From 129319d371c7b570858286664f5e5aaf1fe30595 Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Thu, 10 Aug 2023 17:07:53 -0700 Subject: [PATCH 01/31] get overall impact for all audits --- core/audits/audit.js | 12 +- .../byte-efficiency/uses-long-cache-ttl.js | 2 +- .../audits/metrics/cumulative-layout-shift.js | 5 +- core/audits/metrics/first-contentful-paint.js | 1 + .../metrics/largest-contentful-paint.js | 1 + core/audits/metrics/speed-index.js | 1 + core/audits/metrics/total-blocking-time.js | 1 + .../reports/sample-flow-result.json | 292 +++++++++++++++++- core/test/results/sample_v2.json | 109 ++++++- .../renderer/performance-category-renderer.js | 49 ++- {core/lib => shared}/statistics.js | 0 shared/util.js | 31 ++ tsconfig.json | 1 + types/audit.d.ts | 1 + types/lhr/audit-result.d.ts | 6 + 15 files changed, 481 insertions(+), 31 deletions(-) rename {core/lib => shared}/statistics.js (100%) diff --git a/core/audits/audit.js b/core/audits/audit.js index 281b5f3909f7..5550805af8fe 100644 --- a/core/audits/audit.js +++ b/core/audits/audit.js @@ -6,7 +6,6 @@ import * as LH from '../../types/lh.js'; import {isUnderTest} from '../lib/lh-env.js'; -import * as statistics from '../lib/statistics.js'; import {Util} from '../../shared/util.js'; const DEFAULT_PASS = 'defaultPass'; @@ -105,14 +104,7 @@ class Audit { * @return {number} */ static computeLogNormalScore(controlPoints, value) { - let percentile = statistics.getLogNormalScore(controlPoints, value); - // Add a boost to scores of 90+, linearly ramping from 0 at 0.9 to half a - // point (0.005) at 1. Expands scores in (0.9, 1] to (0.9, 1.005], so more top - // scores will be a perfect 1 after the two-digit `Math.floor()` rounding below. - if (percentile > 0.9) { // getLogNormalScore ensures `percentile` can't exceed 1. - percentile += 0.05 * (percentile - 0.9); - } - return Math.floor(percentile * 100) / 100; + return Util.computeLogNormalScore(controlPoints, value); } /** @@ -411,6 +403,8 @@ class Audit { errorMessage: product.errorMessage, errorStack: product.errorStack, warnings: product.warnings, + scoringOptions: product.scoringOptions, + metricSavings: product.metricSavings, details: product.details, }; diff --git a/core/audits/byte-efficiency/uses-long-cache-ttl.js b/core/audits/byte-efficiency/uses-long-cache-ttl.js index 14397b0220d4..b05ae2b25e3e 100644 --- a/core/audits/byte-efficiency/uses-long-cache-ttl.js +++ b/core/audits/byte-efficiency/uses-long-cache-ttl.js @@ -9,7 +9,7 @@ import parseCacheControl from 'parse-cache-control'; import {Audit} from '../audit.js'; import {NetworkRequest} from '../../lib/network-request.js'; import UrlUtils from '../../lib/url-utils.js'; -import {linearInterpolation} from '../../lib/statistics.js'; +import {linearInterpolation} from '../../../shared/statistics.js'; import * as i18n from '../../lib/i18n/i18n.js'; import {NetworkRecords} from '../../computed/network-records.js'; diff --git a/core/audits/metrics/cumulative-layout-shift.js b/core/audits/metrics/cumulative-layout-shift.js index 3bddd6fe46e7..7edbea2c0ef8 100644 --- a/core/audits/metrics/cumulative-layout-shift.js +++ b/core/audits/metrics/cumulative-layout-shift.js @@ -62,11 +62,14 @@ class CumulativeLayoutShift extends Audit { items: [rest], }; + const scoringOptions = {p10: context.options.p10, median: context.options.median}; + return { score: Audit.computeLogNormalScore( - {p10: context.options.p10, median: context.options.median}, + scoringOptions, cumulativeLayoutShift ), + scoringOptions, numericValue: cumulativeLayoutShift, numericUnit: 'unitless', displayValue: cumulativeLayoutShift.toLocaleString(context.settings.locale), diff --git a/core/audits/metrics/first-contentful-paint.js b/core/audits/metrics/first-contentful-paint.js index 9bbebc449dfe..a5bb444a33a4 100644 --- a/core/audits/metrics/first-contentful-paint.js +++ b/core/audits/metrics/first-contentful-paint.js @@ -74,6 +74,7 @@ class FirstContentfulPaint extends Audit { options.scoring, metricResult.timing ), + scoringOptions: options.scoring, numericValue: metricResult.timing, numericUnit: 'millisecond', displayValue: str_(i18n.UIStrings.seconds, {timeInMs: metricResult.timing}), diff --git a/core/audits/metrics/largest-contentful-paint.js b/core/audits/metrics/largest-contentful-paint.js index 163351a891de..b4fba95ed54f 100644 --- a/core/audits/metrics/largest-contentful-paint.js +++ b/core/audits/metrics/largest-contentful-paint.js @@ -83,6 +83,7 @@ class LargestContentfulPaint extends Audit { options.scoring, metricResult.timing ), + scoringOptions: options.scoring, numericValue: metricResult.timing, numericUnit: 'millisecond', displayValue: str_(i18n.UIStrings.seconds, {timeInMs: metricResult.timing}), diff --git a/core/audits/metrics/speed-index.js b/core/audits/metrics/speed-index.js index e0a5d48ce050..899745aa5615 100644 --- a/core/audits/metrics/speed-index.js +++ b/core/audits/metrics/speed-index.js @@ -77,6 +77,7 @@ class SpeedIndex extends Audit { options.scoring, metricResult.timing ), + scoringOptions: options.scoring, numericValue: metricResult.timing, numericUnit: 'millisecond', displayValue: str_(i18n.UIStrings.seconds, {timeInMs: metricResult.timing}), diff --git a/core/audits/metrics/total-blocking-time.js b/core/audits/metrics/total-blocking-time.js index 7bc2821dc0ec..83edb437dbfc 100644 --- a/core/audits/metrics/total-blocking-time.js +++ b/core/audits/metrics/total-blocking-time.js @@ -107,6 +107,7 @@ class TotalBlockingTime extends Audit { options.scoring, metricResult.timing ), + scoringOptions: options.scoring, numericValue: metricResult.timing, numericUnit: 'millisecond', displayValue: str_(i18n.UIStrings.ms, {timeInMs: metricResult.timing}), diff --git a/core/test/fixtures/user-flows/reports/sample-flow-result.json b/core/test/fixtures/user-flows/reports/sample-flow-result.json index 7891eeb4446c..103ca83806f2 100644 --- a/core/test/fixtures/user-flows/reports/sample-flow-result.json +++ b/core/test/fixtures/user-flows/reports/sample-flow-result.json @@ -38,7 +38,10 @@ "description": "A `` not only optimizes your app for mobile screen sizes, but also prevents [a 300 millisecond delay to user input](https://developer.chrome.com/blog/300ms-tap-delay-gone-away/). [Learn more about using the viewport meta tag](https://developer.chrome.com/docs/lighthouse/pwa/viewport/).", "score": 1, "scoreDisplayMode": "binary", - "warnings": [] + "warnings": [], + "metricSavings": { + "INP": 0 + } }, "first-contentful-paint": { "id": "first-contentful-paint", @@ -48,7 +51,11 @@ "scoreDisplayMode": "numeric", "numericValue": 1372.2951999999998, "numericUnit": "millisecond", - "displayValue": "1.4 s" + "displayValue": "1.4 s", + "scoringOptions": { + "p10": 1800, + "median": 3000 + } }, "largest-contentful-paint": { "id": "largest-contentful-paint", @@ -58,7 +65,11 @@ "scoreDisplayMode": "numeric", "numericValue": 1372.2951999999998, "numericUnit": "millisecond", - "displayValue": "1.4 s" + "displayValue": "1.4 s", + "scoringOptions": { + "p10": 2500, + "median": 4000 + } }, "first-meaningful-paint": { "id": "first-meaningful-paint", @@ -78,7 +89,11 @@ "scoreDisplayMode": "numeric", "numericValue": 1372.2951999999998, "numericUnit": "millisecond", - "displayValue": "1.4 s" + "displayValue": "1.4 s", + "scoringOptions": { + "p10": 3387, + "median": 5800 + } }, "screenshot-thumbnails": { "id": "screenshot-thumbnails", @@ -154,7 +169,11 @@ "scoreDisplayMode": "numeric", "numericValue": 143, "numericUnit": "millisecond", - "displayValue": "140 ms" + "displayValue": "140 ms", + "scoringOptions": { + "p10": 200, + "median": 600 + } }, "max-potential-fid": { "id": "max-potential-fid", @@ -175,6 +194,10 @@ "numericValue": 0.002631263732910156, "numericUnit": "unitless", "displayValue": "0.003", + "scoringOptions": { + "p10": 0.1, + "median": 0.25 + }, "details": { "type": "debugdata", "items": [ @@ -205,6 +228,10 @@ "numericValue": 19.687999999999988, "numericUnit": "millisecond", "displayValue": "Root document took 20 ms", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [ @@ -333,6 +360,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "LCP": 0, + "FCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -618,6 +649,10 @@ "numericUnit": "millisecond", "displayValue": "", "warnings": [], + "metricSavings": { + "LCP": 0, + "FCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -1654,6 +1689,9 @@ "score": null, "scoreDisplayMode": "informative", "displayValue": "5 elements found", + "metricSavings": { + "CLS": 0.002631263732910156 + }, "details": { "type": "table", "headings": [ @@ -1865,6 +1903,9 @@ "description": "Animations which are not composited can be janky and increase CLS. [Learn how to avoid non-composited animations](https://developer.chrome.com/docs/lighthouse/performance/non-composited-animations/)", "score": null, "scoreDisplayMode": "notApplicable", + "metricSavings": { + "CLS": 0 + }, "details": { "type": "table", "headings": [], @@ -1877,6 +1918,9 @@ "description": "Set an explicit width and height on image elements to reduce layout shifts and improve CLS. [Learn how to set image dimensions](https://web.dev/optimize-cls/#images-without-dimensions)", "score": 0, "scoreDisplayMode": "binary", + "metricSavings": { + "CLS": 0 + }, "details": { "type": "table", "headings": [ @@ -1935,6 +1979,9 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -2863,6 +2910,10 @@ "numericUnit": "millisecond", "displayValue": "", "warnings": [], + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -2889,6 +2940,10 @@ "scoreDisplayMode": "numeric", "numericValue": 0, "numericUnit": "millisecond", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -2905,6 +2960,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -2933,6 +2992,10 @@ "numericUnit": "millisecond", "displayValue": "", "warnings": [], + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -2960,6 +3023,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -2987,6 +3054,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -3015,6 +3086,10 @@ "numericUnit": "millisecond", "displayValue": "", "warnings": [], + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -3043,6 +3118,10 @@ "numericUnit": "millisecond", "displayValue": "", "warnings": [], + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -3070,6 +3149,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -3097,6 +3180,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -3124,6 +3211,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -3151,6 +3242,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -3178,6 +3273,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "Potential savings of 0 KiB", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [ @@ -8501,7 +8600,11 @@ "scoreDisplayMode": "numeric", "numericValue": 122.83299999999986, "numericUnit": "millisecond", - "displayValue": "120 ms" + "displayValue": "120 ms", + "scoringOptions": { + "p10": 200, + "median": 600 + } }, "cumulative-layout-shift": { "id": "cumulative-layout-shift", @@ -8512,6 +8615,10 @@ "numericValue": 0.13125, "numericUnit": "unitless", "displayValue": "0.131", + "scoringOptions": { + "p10": 0.1, + "median": 0.25 + }, "details": { "type": "debugdata", "items": [ @@ -9647,6 +9754,9 @@ "score": null, "scoreDisplayMode": "informative", "displayValue": "1 element found", + "metricSavings": { + "CLS": 0.13125 + }, "details": { "type": "table", "headings": [ @@ -9758,6 +9868,9 @@ "description": "Animations which are not composited can be janky and increase CLS. [Learn how to avoid non-composited animations](https://developer.chrome.com/docs/lighthouse/performance/non-composited-animations/)", "score": null, "scoreDisplayMode": "notApplicable", + "metricSavings": { + "CLS": 0 + }, "details": { "type": "table", "headings": [], @@ -9770,6 +9883,9 @@ "description": "Set an explicit width and height on image elements to reduce layout shifts and improve CLS. [Learn how to set image dimensions](https://web.dev/optimize-cls/#images-without-dimensions)", "score": 0, "scoreDisplayMode": "binary", + "metricSavings": { + "CLS": 0 + }, "details": { "type": "table", "headings": [ @@ -10077,6 +10193,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -10105,6 +10225,10 @@ "numericUnit": "millisecond", "displayValue": "", "warnings": [], + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -10132,6 +10256,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -10159,6 +10287,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -10187,6 +10319,10 @@ "numericUnit": "millisecond", "displayValue": "", "warnings": [], + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -10215,6 +10351,10 @@ "numericUnit": "millisecond", "displayValue": "", "warnings": [], + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -10242,6 +10382,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -10269,6 +10413,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -10296,6 +10444,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -10323,6 +10475,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -10350,6 +10506,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -10411,6 +10571,9 @@ "score": 1, "scoreDisplayMode": "numeric", "displayValue": "60 ms spent on event 'keypress'", + "metricSavings": { + "INP": 64 + }, "details": { "type": "list", "items": [ @@ -12435,7 +12598,10 @@ "description": "A `` not only optimizes your app for mobile screen sizes, but also prevents [a 300 millisecond delay to user input](https://developer.chrome.com/blog/300ms-tap-delay-gone-away/). [Learn more about using the viewport meta tag](https://developer.chrome.com/docs/lighthouse/pwa/viewport/).", "score": 1, "scoreDisplayMode": "binary", - "warnings": [] + "warnings": [], + "metricSavings": { + "INP": 0 + } }, "image-aspect-ratio": { "id": "image-aspect-ratio", @@ -12590,6 +12756,9 @@ "description": "Set an explicit width and height on image elements to reduce layout shifts and improve CLS. [Learn how to set image dimensions](https://web.dev/optimize-cls/#images-without-dimensions)", "score": 0, "scoreDisplayMode": "binary", + "metricSavings": { + "CLS": 0 + }, "details": { "type": "table", "headings": [ @@ -17658,7 +17827,10 @@ "description": "A `` not only optimizes your app for mobile screen sizes, but also prevents [a 300 millisecond delay to user input](https://developer.chrome.com/blog/300ms-tap-delay-gone-away/). [Learn more about using the viewport meta tag](https://developer.chrome.com/docs/lighthouse/pwa/viewport/).", "score": 1, "scoreDisplayMode": "binary", - "warnings": [] + "warnings": [], + "metricSavings": { + "INP": 0 + } }, "first-contentful-paint": { "id": "first-contentful-paint", @@ -17668,7 +17840,11 @@ "scoreDisplayMode": "numeric", "numericValue": 866.7026, "numericUnit": "millisecond", - "displayValue": "0.9 s" + "displayValue": "0.9 s", + "scoringOptions": { + "p10": 1800, + "median": 3000 + } }, "largest-contentful-paint": { "id": "largest-contentful-paint", @@ -17678,7 +17854,11 @@ "scoreDisplayMode": "numeric", "numericValue": 1803.0092, "numericUnit": "millisecond", - "displayValue": "1.8 s" + "displayValue": "1.8 s", + "scoringOptions": { + "p10": 2500, + "median": 4000 + } }, "first-meaningful-paint": { "id": "first-meaningful-paint", @@ -17698,7 +17878,11 @@ "scoreDisplayMode": "numeric", "numericValue": 866.7026, "numericUnit": "millisecond", - "displayValue": "0.9 s" + "displayValue": "0.9 s", + "scoringOptions": { + "p10": 3387, + "median": 5800 + } }, "screenshot-thumbnails": { "id": "screenshot-thumbnails", @@ -17774,7 +17958,11 @@ "scoreDisplayMode": "numeric", "numericValue": 13, "numericUnit": "millisecond", - "displayValue": "10 ms" + "displayValue": "10 ms", + "scoringOptions": { + "p10": 200, + "median": 600 + } }, "max-potential-fid": { "id": "max-potential-fid", @@ -17795,6 +17983,10 @@ "numericValue": 0, "numericUnit": "unitless", "displayValue": "0", + "scoringOptions": { + "p10": 0.1, + "median": 0.25 + }, "details": { "type": "debugdata", "items": [ @@ -17825,6 +18017,10 @@ "numericValue": 10.263, "numericUnit": "millisecond", "displayValue": "Root document took 10 ms", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [ @@ -17953,6 +18149,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "LCP": 0, + "FCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -18244,6 +18444,10 @@ "numericUnit": "millisecond", "displayValue": "", "warnings": [], + "metricSavings": { + "LCP": 0, + "FCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -19220,6 +19424,9 @@ "description": "These DOM elements contribute most to the CLS of the page. [Learn how to improve CLS](https://web.dev/optimize-cls/)", "score": null, "scoreDisplayMode": "notApplicable", + "metricSavings": { + "CLS": 0 + }, "details": { "type": "table", "headings": [], @@ -19310,6 +19517,9 @@ "description": "Animations which are not composited can be janky and increase CLS. [Learn how to avoid non-composited animations](https://developer.chrome.com/docs/lighthouse/performance/non-composited-animations/)", "score": null, "scoreDisplayMode": "notApplicable", + "metricSavings": { + "CLS": 0 + }, "details": { "type": "table", "headings": [], @@ -19322,6 +19532,9 @@ "description": "Set an explicit width and height on image elements to reduce layout shifts and improve CLS. [Learn how to set image dimensions](https://web.dev/optimize-cls/#images-without-dimensions)", "score": 0, "scoreDisplayMode": "binary", + "metricSavings": { + "CLS": 0 + }, "details": { "type": "table", "headings": [ @@ -19399,6 +19612,9 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -20344,6 +20560,10 @@ "numericUnit": "millisecond", "displayValue": "", "warnings": [], + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -20370,6 +20590,10 @@ "scoreDisplayMode": "numeric", "numericValue": 0, "numericUnit": "millisecond", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -20386,6 +20610,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -20414,6 +20642,10 @@ "numericUnit": "millisecond", "displayValue": "", "warnings": [], + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -20441,6 +20673,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -20468,6 +20704,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -20496,6 +20736,10 @@ "numericUnit": "millisecond", "displayValue": "Potential savings of 67 KiB", "warnings": [], + "metricSavings": { + "FCP": 0, + "LCP": 330 + }, "details": { "type": "opportunity", "headings": [ @@ -20570,6 +20814,10 @@ "numericUnit": "millisecond", "displayValue": "", "warnings": [], + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -20597,6 +20845,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -20624,6 +20876,10 @@ "numericValue": 300, "numericUnit": "millisecond", "displayValue": "Potential savings of 51 KiB", + "metricSavings": { + "FCP": 0, + "LCP": 300 + }, "details": { "type": "opportunity", "headings": [ @@ -20695,6 +20951,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -20722,6 +20982,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -20749,6 +21013,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [ diff --git a/core/test/results/sample_v2.json b/core/test/results/sample_v2.json index 19e3b0f621e1..83fabfc508ae 100644 --- a/core/test/results/sample_v2.json +++ b/core/test/results/sample_v2.json @@ -52,7 +52,10 @@ "description": "A `` not only optimizes your app for mobile screen sizes, but also prevents [a 300 millisecond delay to user input](https://developer.chrome.com/blog/300ms-tap-delay-gone-away/). [Learn more about using the viewport meta tag](https://developer.chrome.com/docs/lighthouse/pwa/viewport/).", "score": 1, "scoreDisplayMode": "binary", - "warnings": [] + "warnings": [], + "metricSavings": { + "INP": 0 + } }, "first-contentful-paint": { "id": "first-contentful-paint", @@ -62,7 +65,11 @@ "scoreDisplayMode": "numeric", "numericValue": 6843.95, "numericUnit": "millisecond", - "displayValue": "6.8 s" + "displayValue": "6.8 s", + "scoringOptions": { + "p10": 1800, + "median": 3000 + } }, "largest-contentful-paint": { "id": "largest-contentful-paint", @@ -72,7 +79,11 @@ "scoreDisplayMode": "numeric", "numericValue": 13319.961, "numericUnit": "millisecond", - "displayValue": "13.3 s" + "displayValue": "13.3 s", + "scoringOptions": { + "p10": 2500, + "median": 4000 + } }, "first-meaningful-paint": { "id": "first-meaningful-paint", @@ -92,7 +103,11 @@ "scoreDisplayMode": "numeric", "numericValue": 8114, "numericUnit": "millisecond", - "displayValue": "8.1 s" + "displayValue": "8.1 s", + "scoringOptions": { + "p10": 3387, + "median": 5800 + } }, "screenshot-thumbnails": { "id": "screenshot-thumbnails", @@ -168,7 +183,11 @@ "scoreDisplayMode": "numeric", "numericValue": 1220.691999999999, "numericUnit": "millisecond", - "displayValue": "1,220 ms" + "displayValue": "1,220 ms", + "scoringOptions": { + "p10": 200, + "median": 600 + } }, "max-potential-fid": { "id": "max-potential-fid", @@ -189,6 +208,10 @@ "numericValue": 0.13570762803819444, "numericUnit": "unitless", "displayValue": "0.136", + "scoringOptions": { + "p10": 0.1, + "median": 0.25 + }, "details": { "type": "debugdata", "items": [ @@ -308,6 +331,10 @@ "numericValue": 568.468, "numericUnit": "millisecond", "displayValue": "Root document took 570 ms", + "metricSavings": { + "FCP": 468.46799999999996, + "LCP": 468.46799999999996 + }, "details": { "type": "opportunity", "headings": [ @@ -755,6 +782,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "LCP": 0, + "FCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -1139,6 +1170,10 @@ "numericUnit": "millisecond", "displayValue": "", "warnings": [], + "metricSavings": { + "LCP": 0, + "FCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -2392,6 +2427,9 @@ "score": null, "scoreDisplayMode": "informative", "displayValue": "5 elements found", + "metricSavings": { + "CLS": 0.13570762803819444 + }, "details": { "type": "table", "headings": [ @@ -2618,6 +2656,9 @@ "score": null, "scoreDisplayMode": "informative", "displayValue": "1 animated element found", + "metricSavings": { + "CLS": 0 + }, "details": { "type": "table", "headings": [ @@ -2677,6 +2718,9 @@ "description": "Set an explicit width and height on image elements to reduce layout shifts and improve CLS. [Learn how to set image dimensions](https://web.dev/optimize-cls/#images-without-dimensions)", "score": 0, "scoreDisplayMode": "binary", + "metricSavings": { + "CLS": 0 + }, "details": { "type": "table", "headings": [ @@ -2754,6 +2798,9 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [ @@ -4320,6 +4367,10 @@ "numericUnit": "millisecond", "displayValue": "", "warnings": [], + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -4347,6 +4398,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "Potential savings of 0 ms", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [ @@ -4410,6 +4465,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -4438,6 +4497,10 @@ "numericUnit": "millisecond", "displayValue": "Potential savings of 82 KiB", "warnings": [], + "metricSavings": { + "FCP": 0, + "LCP": 300 + }, "details": { "type": "opportunity", "headings": [ @@ -4488,6 +4551,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -4515,6 +4582,10 @@ "numericValue": 750, "numericUnit": "millisecond", "displayValue": "Potential savings of 64 KiB", + "metricSavings": { + "FCP": 0, + "LCP": 450 + }, "details": { "type": "opportunity", "headings": [ @@ -4582,6 +4653,10 @@ "numericUnit": "millisecond", "displayValue": "Potential savings of 76 KiB", "warnings": [], + "metricSavings": { + "FCP": 0, + "LCP": 450 + }, "details": { "type": "opportunity", "headings": [ @@ -4696,6 +4771,10 @@ "numericUnit": "millisecond", "displayValue": "", "warnings": [], + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -4723,6 +4802,10 @@ "numericValue": 2400, "numericUnit": "millisecond", "displayValue": "Potential savings of 143 KiB", + "metricSavings": { + "FCP": 150, + "LCP": 750 + }, "details": { "type": "opportunity", "headings": [ @@ -4777,6 +4860,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -4804,6 +4891,10 @@ "numericValue": 3450, "numericUnit": "millisecond", "displayValue": "Potential savings of 666 KiB", + "metricSavings": { + "FCP": 0, + "LCP": 3300 + }, "details": { "type": "opportunity", "headings": [ @@ -4853,6 +4944,10 @@ "numericValue": 0, "numericUnit": "millisecond", "displayValue": "", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [], @@ -4880,6 +4975,10 @@ "numericValue": 450, "numericUnit": "millisecond", "displayValue": "Potential savings of 26 KiB", + "metricSavings": { + "FCP": 0, + "LCP": 0 + }, "details": { "type": "opportunity", "headings": [ diff --git a/report/renderer/performance-category-renderer.js b/report/renderer/performance-category-renderer.js index b30c1b407929..106cd4baf5a7 100644 --- a/report/renderer/performance-category-renderer.js +++ b/report/renderer/performance-category-renderer.js @@ -20,6 +20,7 @@ import {CategoryRenderer} from './category-renderer.js'; import {ReportUtils} from './report-utils.js'; import {Globals} from './report-globals.js'; +import {Util} from '../../shared/util.js'; export class PerformanceCategoryRenderer extends CategoryRenderer { /** @@ -239,7 +240,7 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { } // Opportunities - const opportunityAudits = category.auditRefs + /* const opportunityAudits = category.auditRefs .filter(audit => this._classifyPerformanceAudit(audit) === 'load-opportunity') .filter(audit => !ReportUtils.showAsPassed(audit.result)) .sort((auditA, auditB) => this._getWastedMs(auditB) - this._getWastedMs(auditA)); @@ -270,17 +271,59 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { groupEl.insertBefore(this._renderOpportunity(item, scale), footerEl)); groupEl.classList.add('lh-audit-group--load-opportunities'); element.append(groupEl); - } + } */ // Diagnostics const diagnosticAudits = category.auditRefs - .filter(audit => this._classifyPerformanceAudit(audit) === 'diagnostic') + // All audits here. + // .filter(audit => this._classifyPerformanceAudit(audit) === 'diagnostic') + .filter(audit => this._classifyPerformanceAudit(audit)) .filter(audit => !ReportUtils.showAsPassed(audit.result)) .sort((a, b) => { const scoreA = a.result.scoreDisplayMode === 'informative' ? 100 : Number(a.result.score); const scoreB = b.result.scoreDisplayMode === 'informative' ? 100 : Number(b.result.score); return scoreA - scoreB; }); + // .sort((a, b) => { + // return + // }); + + // sort by weighted impact - is this individual from each individual metric impact, or all together? + + + diagnosticAudits.forEach(a => { + if (a.result.metricSavings) { + let overallImpact = 0; + for (const [k, savings] of Object.entries(a.result.metricSavings)) { + // Get metric savings for individual audit. + // Don't do anything if we don't have savings for a metric. + if (savings === undefined) continue; + + // Get the metric data. + const mAudit = metricAudits.find(a => a.acronym === k); + if (!mAudit) continue; + if (mAudit.result.score === null) continue; + + const mValue = mAudit.result.numericValue; + if (mValue === undefined) continue; + + const scoringOptions = mAudit.result.scoringOptions; + if (!scoringOptions) continue; + + const newMetricScore = Util.computeLogNormalScore(scoringOptions, mValue - savings); + // only if there's a diff between old & new. + // if (newMetricScore !== mAudit.result.score) { + console.log(a.id, 'New:', newMetricScore, 'Old:', mAudit.result.score); + // This is the impact on the metric. how do you find the impact on the score (how to calculate overall impact score)? + const weightedMetricImpact = (newMetricScore - mAudit.result.score) * mAudit.weight; + overallImpact += weightedMetricImpact; + + console.log('Weighted', k, 'impact: ', weightedMetricImpact); + // } + } + console.log('overall impact: ', overallImpact); + } + }); if (diagnosticAudits.length) { const [groupEl, footerEl] = this.renderAuditGroup(groups['diagnostics']); diff --git a/core/lib/statistics.js b/shared/statistics.js similarity index 100% rename from core/lib/statistics.js rename to shared/statistics.js diff --git a/shared/util.js b/shared/util.js index b23e7fc96b3e..02039ed2e591 100644 --- a/shared/util.js +++ b/shared/util.js @@ -15,6 +15,8 @@ * limitations under the License. */ +import * as statistics from './statistics.js'; + /** @typedef {import('../types/lhr/audit-details').default.SnippetValue} SnippetValue */ const ELLIPSIS = '\u2026'; @@ -373,6 +375,35 @@ class Util { return lines.filter(line => lineNumbersToKeep.has(line.lineNumber)); } + + /** + * Computes a score between 0 and 1 based on the measured `value`. Score is determined by + * considering a log-normal distribution governed by two control points (the 10th + * percentile value and the median value) and represents the percentage of sites that are + * greater than `value`. + * + * Score characteristics: + * - within [0, 1] + * - rounded to two digits + * - value must meet or beat a controlPoint value to meet or exceed its percentile score: + * - value > median will give a score < 0.5; value ≤ median will give a score ≥ 0.5. + * - value > p10 will give a score < 0.9; value ≤ p10 will give a score ≥ 0.9. + * - values < p10 will get a slight boost so a score of 1 is achievable by a + * `value` other than those close to 0. Scores of > ~0.99524 end up rounded to 1. + * @param {{median: number, p10: number}} controlPoints + * @param {number} value + * @return {number} + */ + static computeLogNormalScore(controlPoints, value) { + let percentile = statistics.getLogNormalScore(controlPoints, value); + // Add a boost to scores of 90+, linearly ramping from 0 at 0.9 to half a + // point (0.005) at 1. Expands scores in (0.9, 1] to (0.9, 1.005], so more top + // scores will be a perfect 1 after the two-digit `Math.floor()` rounding below. + if (percentile > 0.9) { // getLogNormalScore ensures `percentile` can't exceed 1. + percentile += 0.05 * (percentile - 0.9); + } + return Math.floor(percentile * 100) / 100; + } } export { diff --git a/tsconfig.json b/tsconfig.json index a4e6f4bc39f7..06a8b2cbe690 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -28,6 +28,7 @@ "core/test/fixtures/traces/lcp-m78.devtools.log.json", "core/audits/byte-efficiency/polyfill-graph-data.json", "shared/localization/locales/en-US.json", + "shared/statistics.js", ], "exclude": [ "build/test/*test-case*.js", diff --git a/types/audit.d.ts b/types/audit.d.ts index 9a83f6337722..2aa13a892fb1 100644 --- a/types/audit.d.ts +++ b/types/audit.d.ts @@ -86,6 +86,7 @@ declare module Audit { runWarnings?: Array; /** [EXPERIMENTAL] Estimates of how much this audit affects various performance metrics. Values will be in the unit of the respective metrics. */ metricSavings?: MetricSavings; + scoringOptions?: ScoreOptions; } /** The Audit.Product type for audits that do not return a `numericValue`. */ diff --git a/types/lhr/audit-result.d.ts b/types/lhr/audit-result.d.ts index 7abe29ec137a..9b4b043d0126 100644 --- a/types/lhr/audit-result.d.ts +++ b/types/lhr/audit-result.d.ts @@ -66,4 +66,10 @@ export interface Result { numericUnit?: string; /** Extra information about the page provided by some types of audits, in one of several possible forms that can be rendered in the HTML report. */ details?: FormattedIcu; + /** Metric savings for and audit */ + metricSavings?: MetricSavings + scoringOptions?: { + p10: number; + median: number; + }; } From 7881ecd875268472bab6205f49d689c03ad5acda Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Fri, 11 Aug 2023 12:17:35 -0700 Subject: [PATCH 02/31] calculate overall impact --- .../renderer/performance-category-renderer.js | 70 ++++++++++++++----- 1 file changed, 52 insertions(+), 18 deletions(-) diff --git a/report/renderer/performance-category-renderer.js b/report/renderer/performance-category-renderer.js index 106cd4baf5a7..732cada26221 100644 --- a/report/renderer/performance-category-renderer.js +++ b/report/renderer/performance-category-renderer.js @@ -172,6 +172,47 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { return 'diagnostic'; } + /** + * @param {LH.ReportResult.AuditRef} audit + * @param {LH.ReportResult.AuditRef[]} metricAudits + * @return {number} + */ + overallImpact(audit, metricAudits) { + if (audit.result.metricSavings) { + let overallImpact = 0; + for (const [k, savings] of Object.entries(audit.result.metricSavings)) { + // Get metric savings for individual audit. + // Don't do anything if we don't have savings for a metric. + if (savings === undefined) continue; + + // Get the metric data. + const mAudit = metricAudits.find(audit => audit.acronym === k); + if (!mAudit) continue; + if (mAudit.result.score === null) continue; + + const mValue = mAudit.result.numericValue; + if (mValue === undefined) continue; + + const scoringOptions = mAudit.result.scoringOptions; + if (!scoringOptions) continue; + + const newMetricScore = Util.computeLogNormalScore(scoringOptions, mValue - savings); + // only if there's a diff between old & new. + if (newMetricScore !== mAudit.result.score) { + // console.log(audit.id, 'New:', newMetricScore, 'Old:', mAudit.result.score); + // This is the impact on the metric. how do you find the impact on the score (how to calculate overall impact score)? + const weightedMetricImpact = (newMetricScore - mAudit.result.score) * mAudit.weight; + overallImpact += weightedMetricImpact; + + // console.log('Weighted', k, 'impact: ', weightedMetricImpact); + } + } + // console.log('overall impact: ', overallImpact); + return overallImpact; + } + return 0; + } + /** * @param {LH.ReportResult.Category} category * @param {Object} groups @@ -276,21 +317,14 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { // Diagnostics const diagnosticAudits = category.auditRefs // All audits here. - // .filter(audit => this._classifyPerformanceAudit(audit) === 'diagnostic') .filter(audit => this._classifyPerformanceAudit(audit)) .filter(audit => !ReportUtils.showAsPassed(audit.result)) .sort((a, b) => { - const scoreA = a.result.scoreDisplayMode === 'informative' ? 100 : Number(a.result.score); - const scoreB = b.result.scoreDisplayMode === 'informative' ? 100 : Number(b.result.score); - return scoreA - scoreB; + // sort by higher impact. + return this.overallImpact(b, metricAudits) - this.overallImpact(a, metricAudits); }); - // .sort((a, b) => { - // return - // }); - - // sort by weighted impact - is this individual from each individual metric impact, or all together? - + // TODO: rm this. just for console logging purposes. diagnosticAudits.forEach(a => { if (a.result.metricSavings) { let overallImpact = 0; @@ -312,16 +346,16 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { const newMetricScore = Util.computeLogNormalScore(scoringOptions, mValue - savings); // only if there's a diff between old & new. - // if (newMetricScore !== mAudit.result.score) { - console.log(a.id, 'New:', newMetricScore, 'Old:', mAudit.result.score); - // This is the impact on the metric. how do you find the impact on the score (how to calculate overall impact score)? - const weightedMetricImpact = (newMetricScore - mAudit.result.score) * mAudit.weight; - overallImpact += weightedMetricImpact; + if (newMetricScore !== mAudit.result.score) { + console.log(a.id, 'New:', newMetricScore, 'Old:', mAudit.result.score); + // This is the impact on the metric. how do you find the impact on the score (how to calculate overall impact score)? + const weightedMetricImpact = (newMetricScore - mAudit.result.score) * mAudit.weight; + overallImpact += weightedMetricImpact; - console.log('Weighted', k, 'impact: ', weightedMetricImpact); - // } + console.log('Weighted', k, 'impact: ', weightedMetricImpact); + } } - console.log('overall impact: ', overallImpact); + console.log(a.id, 'overall impact:', overallImpact); } }); From 2a7ef45c171cf90d42b62be9db7737e3c503ad44 Mon Sep 17 00:00:00 2001 From: Adam Raine Date: Wed, 16 Aug 2023 14:21:34 -0700 Subject: [PATCH 03/31] linear impact + old scoring fallback --- .../renderer/performance-category-renderer.js | 41 ++++++++++++++++--- 1 file changed, 35 insertions(+), 6 deletions(-) diff --git a/report/renderer/performance-category-renderer.js b/report/renderer/performance-category-renderer.js index 732cada26221..73453cc59912 100644 --- a/report/renderer/performance-category-renderer.js +++ b/report/renderer/performance-category-renderer.js @@ -175,11 +175,12 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { /** * @param {LH.ReportResult.AuditRef} audit * @param {LH.ReportResult.AuditRef[]} metricAudits - * @return {number} + * @return {{overallImpact: number, overallLinearImpact: number}} */ overallImpact(audit, metricAudits) { if (audit.result.metricSavings) { let overallImpact = 0; + let overallLinearImpact = 0; for (const [k, savings] of Object.entries(audit.result.metricSavings)) { // Get metric savings for individual audit. // Don't do anything if we don't have savings for a metric. @@ -191,12 +192,15 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { if (mAudit.result.score === null) continue; const mValue = mAudit.result.numericValue; - if (mValue === undefined) continue; + if (!mValue) continue; const scoringOptions = mAudit.result.scoringOptions; if (!scoringOptions) continue; const newMetricScore = Util.computeLogNormalScore(scoringOptions, mValue - savings); + const linearImpact = savings / mValue * mAudit.weight; + overallLinearImpact += linearImpact; + // only if there's a diff between old & new. if (newMetricScore !== mAudit.result.score) { // console.log(audit.id, 'New:', newMetricScore, 'Old:', mAudit.result.score); @@ -208,9 +212,10 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { } } // console.log('overall impact: ', overallImpact); - return overallImpact; + return {overallImpact, overallLinearImpact}; } - return 0; + + return {overallImpact: 0, overallLinearImpact: 0}; } /** @@ -320,8 +325,32 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { .filter(audit => this._classifyPerformanceAudit(audit)) .filter(audit => !ReportUtils.showAsPassed(audit.result)) .sort((a, b) => { - // sort by higher impact. - return this.overallImpact(b, metricAudits) - this.overallImpact(a, metricAudits); + const { + overallImpact: aOverallImpact, + overallLinearImpact: aOverallLinearImpact, + } = this.overallImpact(a, metricAudits); + const { + overallImpact: bOverallImpact, + overallLinearImpact: bOverallLinearImpact, + } = this.overallImpact(b, metricAudits); + + if (a.id === 'unsized-images') { + console.log('######'); + console.log(aOverallImpact, aOverallLinearImpact); + console.log(bOverallImpact, bOverallLinearImpact); + console.log(aOverallImpact === bOverallImpact, bOverallLinearImpact); + } + if (aOverallImpact !== bOverallImpact) return bOverallImpact - aOverallImpact; + if ( + aOverallImpact === 0 && bOverallImpact === 0 && + aOverallLinearImpact !== bOverallLinearImpact + ) { + return bOverallLinearImpact - aOverallLinearImpact; + } + + const scoreA = a.result.scoreDisplayMode === 'informative' ? 100 : Number(a.result.score); + const scoreB = b.result.scoreDisplayMode === 'informative' ? 100 : Number(b.result.score); + return scoreA - scoreB; }); // TODO: rm this. just for console logging purposes. From 4f7b7f46e3d418ddeb5646b5aa03c46710f6e196 Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Wed, 16 Aug 2023 16:56:46 -0700 Subject: [PATCH 04/31] rm color indicators --- report/assets/styles.css | 10 ++++++++-- report/renderer/components.js | 2 +- report/renderer/performance-category-renderer.js | 12 ++++++------ 3 files changed, 15 insertions(+), 9 deletions(-) diff --git a/report/assets/styles.css b/report/assets/styles.css index c3dfe23fea7f..1d4fbf4743a6 100644 --- a/report/assets/styles.css +++ b/report/assets/styles.css @@ -526,6 +526,10 @@ /* Score */ +.lh-audit__score-icon { + opacity: 0; +} + .lh-audit__score-icon { width: var(--score-icon-size); height: var(--score-icon-size); @@ -542,7 +546,8 @@ } .lh-audit--average .lh-audit__display-text { - color: var(--color-average-secondary); + /* color: var(--color-average-secondary); */ + color: gray; } .lh-audit--average .lh-audit__score-icon, .lh-scorescale-range--average::before { @@ -552,7 +557,8 @@ } .lh-audit--fail .lh-audit__display-text { - color: var(--color-fail-secondary); + /* color: var(--color-fail-secondary); */ + color: gray; } .lh-audit--fail .lh-audit__score-icon, .lh-audit--error .lh-audit__score-icon, diff --git a/report/renderer/components.js b/report/renderer/components.js index da47a97287e2..26da5dc837ef 100644 --- a/report/renderer/components.js +++ b/report/renderer/components.js @@ -520,7 +520,7 @@ function createSnippetLineComponent(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 --report-icon-size: var(--score-icon-background-size);\n --report-line-height: 24px;\n --report-line-height-secondary: 20px;\n --report-monospace-font-size: calc(var(--report-font-size) * 0.85);\n --report-text-color-secondary: var(--color-gray-800);\n --report-text-color: var(--color-gray-900);\n --report-content-max-width: calc(60 * var(--report-font-size)); /* defaults to 840px */\n --report-content-min-width: 360px;\n --report-content-max-width-minus-edge-gap: calc(var(--report-content-max-width) - var(--edge-gap-padding) * 2);\n --score-container-padding: 8px;\n --score-icon-background-size: 24px;\n --score-icon-margin-left: 6px;\n --score-icon-margin-right: 14px;\n --score-icon-margin: 0 var(--score-icon-margin-right) 0 var(--score-icon-margin-left);\n --score-icon-size: 12px;\n --score-icon-size-big: 16px;\n --screenshot-overlay-background: rgba(0, 0, 0, 0.3);\n --section-padding-vertical: calc(var(--default-padding) * 6);\n --snippet-background-color: var(--color-gray-50);\n --snippet-color: #0938C2;\n --sparkline-height: 5px;\n --stackpack-padding-horizontal: 10px;\n --sticky-header-background-color: var(--report-background-color);\n --sticky-header-buffer: calc(var(--topbar-height) + var(--sticky-header-height));\n --sticky-header-height: calc(var(--gauge-circle-size-sm) + var(--score-container-padding) * 2);\n --table-group-header-background-color: #EEF1F4;\n --table-group-header-text-color: var(--color-gray-700);\n --table-higlight-background-color: #F5F7FA;\n --tools-icon-color: var(--color-gray-600);\n --topbar-background-color: var(--color-white);\n --topbar-height: 32px;\n --topbar-logo-size: 24px;\n --topbar-padding: 0 8px;\n --toplevel-warning-background-color: hsla(30, 100%, 75%, 10%);\n --toplevel-warning-message-text-color: var(--color-average-secondary);\n --toplevel-warning-padding: 18px;\n --toplevel-warning-text-color: var(--report-text-color);\n\n /* SVGs */\n --plugin-icon-url-dark: url('data:image/svg+xml;utf8,');\n --plugin-icon-url: url('data:image/svg+xml;utf8,');\n\n --pass-icon-url: url('data:image/svg+xml;utf8,check');\n --average-icon-url: url('data:image/svg+xml;utf8,info');\n --fail-icon-url: url('data:image/svg+xml;utf8,warn');\n --error-icon-url: url('data:image/svg+xml;utf8,error');\n\n --pwa-installable-gray-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-gray-url-dark: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url-dark: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-color-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-color-url: url('data:image/svg+xml;utf8,');\n\n --swap-locale-icon-url: url('data:image/svg+xml;utf8,');\n}\n\n@media not print {\n .lh-dark {\n /* Pallete */\n --color-gray-200: var(--color-gray-800);\n --color-gray-300: #616161;\n --color-gray-400: var(--color-gray-600);\n --color-gray-700: var(--color-gray-400);\n --color-gray-50: #757575;\n --color-gray-600: var(--color-gray-500);\n --color-green-700: var(--color-green);\n --color-orange-700: var(--color-orange);\n --color-red-700: var(--color-red);\n --color-teal-600: var(--color-cyan-500);\n\n /* Context-specific colors */\n --color-hover: rgba(0, 0, 0, 0.2);\n --color-informative: var(--color-blue-200);\n\n /* Component variables */\n --env-item-background-color: #393535;\n --link-color: var(--color-blue-200);\n --locale-selector-background-color: var(--color-gray-200);\n --plugin-badge-background-color: var(--color-gray-800);\n --report-background-color: var(--color-gray-900);\n --report-border-color-secondary: var(--color-gray-200);\n --report-text-color-secondary: var(--color-gray-400);\n --report-text-color: var(--color-gray-100);\n --snippet-color: var(--color-cyan-500);\n --topbar-background-color: var(--color-gray);\n --toplevel-warning-background-color: hsl(33deg 14% 18%);\n --toplevel-warning-message-text-color: var(--color-orange-700);\n --toplevel-warning-text-color: var(--color-gray-100);\n --table-group-header-background-color: rgba(186, 196, 206, 0.15);\n --table-group-header-text-color: var(--color-gray-100);\n --table-higlight-background-color: rgba(186, 196, 206, 0.09);\n\n /* SVGs */\n --plugin-icon-url: var(--plugin-icon-url-dark);\n --pwa-installable-gray-url: var(--pwa-installable-gray-url-dark);\n --pwa-optimized-gray-url: var(--pwa-optimized-gray-url-dark);\n }\n}\n\n@media only screen and (max-width: 480px) {\n .lh-vars {\n --audit-group-margin-bottom: 20px;\n --edge-gap-padding: var(--default-padding);\n --env-name-min-width: 120px;\n --gauge-circle-size-big: 96px;\n --gauge-circle-size: 72px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 112px;\n --header-padding: 16px 0 16px 0;\n --image-preview-size: 24px;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-size: 14px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --topbar-height: 28px;\n --topbar-logo-size: 20px;\n }\n\n /* Not enough space to adequately show the relative savings bars. */\n .lh-sparkline {\n display: none;\n }\n}\n\n.lh-vars.lh-devtools {\n --audit-explanation-line-height: 14px;\n --audit-group-margin-bottom: 20px;\n --audit-group-padding-vertical: 12px;\n --audit-padding-vertical: 4px;\n --category-padding: 12px;\n --default-padding: 12px;\n --env-name-min-width: 120px;\n --footer-padding-vertical: 8px;\n --gauge-circle-size-big: 72px;\n --gauge-circle-size: 64px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 97px;\n --header-line-height: 20px;\n --header-padding: 16px 0 16px 0;\n --screenshot-overlay-background: transparent;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-family-monospace: 'Menlo', 'dejavu sans mono', 'Consolas', 'Lucida Console', monospace;\n --report-font-family: '.SFNSDisplay-Regular', 'Helvetica Neue', 'Lucida Grande', sans-serif;\n --report-font-size: 12px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --section-padding-vertical: 8px;\n}\n\n.lh-container:not(.lh-topbar + .lh-container) {\n --topbar-height: 0;\n --sticky-header-height: 0;\n --sticky-header-buffer: 0;\n}\n\n.lh-devtools.lh-root {\n height: 100%;\n}\n.lh-devtools.lh-root img {\n /* Override devtools default 'min-width: 0' so svg without size in a flexbox isn't collapsed. */\n min-width: auto;\n}\n.lh-devtools .lh-container {\n overflow-y: scroll;\n height: calc(100% - var(--topbar-height));\n /** The .lh-container is the scroll parent in DevTools so we exclude the topbar from the sticky header buffer. */\n --sticky-header-buffer: calc(var(--sticky-header-height));\n}\n@media print {\n .lh-devtools .lh-container {\n overflow: unset;\n }\n}\n.lh-devtools .lh-sticky-header {\n /* This is normally the height of the topbar, but we want it to stick to the top of our scroll container .lh-container` */\n top: 0;\n}\n.lh-devtools .lh-element-screenshot__overlay {\n position: absolute;\n}\n\n@keyframes fadeIn {\n 0% { opacity: 0;}\n 100% { opacity: 0.6;}\n}\n\n.lh-root *, .lh-root *::before, .lh-root *::after {\n box-sizing: border-box;\n}\n\n.lh-root {\n font-family: var(--report-font-family);\n font-size: var(--report-font-size);\n margin: 0;\n line-height: var(--report-line-height);\n background: var(--report-background-color);\n color: var(--report-text-color);\n}\n\n.lh-root :focus-visible {\n outline: -webkit-focus-ring-color auto 3px;\n}\n.lh-root summary:focus {\n outline: none;\n box-shadow: 0 0 0 1px hsl(217, 89%, 61%);\n}\n\n.lh-root [hidden] {\n display: none !important;\n}\n\n.lh-root pre {\n margin: 0;\n}\n\n.lh-root pre,\n.lh-root code {\n font-family: var(--report-font-family-monospace);\n}\n\n.lh-root details > summary {\n cursor: pointer;\n}\n\n.lh-hidden {\n display: none !important;\n}\n\n.lh-container {\n /*\n Text wrapping in the report is so much FUN!\n We have a `word-break: break-word;` globally here to prevent a few common scenarios, namely\n long non-breakable text (usually URLs) found in:\n 1. The footer\n 2. .lh-node (outerHTML)\n 3. .lh-code\n\n With that sorted, the next challenge is appropriate column sizing and text wrapping inside our\n .lh-details tables. Even more fun.\n * We don't want table headers (\"Potential Savings (ms)\") to wrap or their column values, but\n we'd be happy for the URL column to wrap if the URLs are particularly long.\n * We want the narrow columns to remain narrow, providing the most column width for URL\n * We don't want the table to extend past 100% width.\n * Long URLs in the URL column can wrap. Util.getURLDisplayName maxes them out at 64 characters,\n but they do not get any overflow:ellipsis treatment.\n */\n word-break: break-word;\n}\n\n.lh-audit-group a,\n.lh-category-header__description a,\n.lh-audit__description a,\n.lh-warnings a,\n.lh-footer a,\n.lh-table-column--link a {\n color: var(--link-color);\n}\n\n.lh-audit__description, .lh-audit__stackpack {\n --inner-audit-padding-right: var(--stackpack-padding-horizontal);\n padding-left: var(--audit-description-padding-left);\n padding-right: var(--inner-audit-padding-right);\n padding-top: 8px;\n padding-bottom: 8px;\n}\n\n.lh-details {\n margin-top: var(--default-padding);\n margin-bottom: var(--default-padding);\n margin-left: var(--audit-description-padding-left);\n /* whatever the .lh-details side margins are */\n width: 100%;\n}\n\n.lh-audit__stackpack {\n display: flex;\n align-items: center;\n}\n\n.lh-audit__stackpack__img {\n max-width: 30px;\n margin-right: var(--default-padding)\n}\n\n/* Report header */\n\n.lh-report-icon {\n display: flex;\n align-items: center;\n padding: 10px 12px;\n cursor: pointer;\n}\n.lh-report-icon[disabled] {\n opacity: 0.3;\n pointer-events: none;\n}\n\n.lh-report-icon::before {\n content: \"\";\n margin: 4px;\n background-repeat: no-repeat;\n width: var(--report-icon-size);\n height: var(--report-icon-size);\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n.lh-report-icon:hover::before {\n opacity: 1;\n}\n.lh-dark .lh-report-icon::before {\n filter: invert(1);\n}\n.lh-report-icon--print::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--copy::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--open::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--download::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--dark::before {\n background-image:url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--treemap::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--date::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--devices::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--world::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--stopwatch::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--networkspeed::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-one::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-many::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--chrome::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--external::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n\n.lh-buttons {\n display: flex;\n flex-wrap: wrap;\n margin: var(--default-padding) 0;\n}\n.lh-button {\n height: 32px;\n border: 1px solid var(--report-border-color-secondary);\n border-radius: 3px;\n color: var(--link-color);\n background-color: var(--report-background-color);\n margin: 5px;\n}\n\n.lh-button:first-of-type {\n margin-left: 0;\n}\n\n/* Node */\n.lh-node__snippet {\n font-family: var(--report-font-family-monospace);\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n line-height: 20px;\n}\n\n/* Score */\n\n.lh-audit__score-icon {\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n margin: var(--score-icon-margin);\n}\n\n.lh-audit--pass .lh-audit__display-text {\n color: var(--color-pass-secondary);\n}\n.lh-audit--pass .lh-audit__score-icon,\n.lh-scorescale-range--pass::before {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-audit__display-text {\n color: var(--color-average-secondary);\n}\n.lh-audit--average .lh-audit__score-icon,\n.lh-scorescale-range--average::before {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-audit--fail .lh-audit__display-text {\n color: var(--color-fail-secondary);\n}\n.lh-audit--fail .lh-audit__score-icon,\n.lh-audit--error .lh-audit__score-icon,\n.lh-scorescale-range--fail::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-audit--error .lh-audit__score-icon,\n.lh-metric--error .lh-metric__icon {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n border: none;\n}\n\n.lh-gauge__wrapper--fail .lh-gauge--error {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n transform: scale(0.5);\n top: var(--score-container-padding);\n}\n\n.lh-audit--manual .lh-audit__display-text,\n.lh-audit--notapplicable .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n.lh-audit--manual .lh-audit__score-icon,\n.lh-audit--notapplicable .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n background: none;\n}\n\n.lh-audit--informative .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n\n.lh-audit--informative .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n}\n\n.lh-audit__description,\n.lh-audit__stackpack {\n color: var(--report-text-color-secondary);\n}\n.lh-audit__adorn {\n border: 1px solid var(--color-gray-500);\n border-radius: 3px;\n margin: 0 3px;\n padding: 0 2px;\n line-height: 1.1;\n display: inline-block;\n font-size: 90%;\n color: var(--report-text-color-secondary);\n}\n\n.lh-category-header__description {\n text-align: center;\n color: var(--color-gray-700);\n margin: 0px auto;\n max-width: 400px;\n}\n\n\n.lh-audit__display-text,\n.lh-load-opportunity__sparkline,\n.lh-chevron-container {\n margin: 0 var(--audit-margin-horizontal);\n}\n.lh-chevron-container {\n margin-right: 0;\n}\n\n.lh-audit__title-and-text {\n flex: 1;\n}\n\n.lh-audit__title-and-text code {\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n}\n\n/* Prepend display text with em dash separator. But not in Opportunities. */\n.lh-audit__display-text:not(:empty):before {\n content: '—';\n margin-right: var(--audit-margin-horizontal);\n}\n.lh-audit-group.lh-audit-group--load-opportunities .lh-audit__display-text:not(:empty):before {\n display: none;\n}\n\n/* Expandable Details (Audit Groups, Audits) */\n.lh-audit__header {\n display: flex;\n align-items: center;\n padding: var(--default-padding);\n}\n\n.lh-audit--load-opportunity .lh-audit__header {\n display: block;\n}\n\n\n.lh-metricfilter {\n display: grid;\n justify-content: end;\n align-items: center;\n grid-auto-flow: column;\n gap: 4px;\n color: var(--color-gray-700);\n}\n\n.lh-metricfilter__radio {\n /*\n * Instead of hiding, position offscreen so it's still accessible to screen readers\n * https://bugs.chromium.org/p/chromium/issues/detail?id=1439785\n */\n position: fixed;\n left: -9999px;\n}\n.lh-metricfilter input[type='radio']:focus-visible + label {\n outline: -webkit-focus-ring-color auto 1px;\n}\n\n.lh-metricfilter__label {\n display: inline-flex;\n padding: 0 4px;\n height: 16px;\n text-decoration: underline;\n align-items: center;\n cursor: pointer;\n font-size: 90%;\n}\n\n.lh-metricfilter__label--active {\n background: var(--color-blue-primary);\n color: var(--color-white);\n border-radius: 3px;\n text-decoration: none;\n}\n/* Give the 'All' choice a more muted display */\n.lh-metricfilter__label--active[for=\"metric-All\"] {\n background-color: var(--color-blue-200) !important;\n color: black !important;\n}\n\n.lh-metricfilter__text {\n margin-right: 8px;\n}\n\n/* If audits are filtered, hide the itemcount for Passed Audits… */\n.lh-category--filtered .lh-audit-group .lh-audit-group__itemcount {\n display: none;\n}\n\n\n.lh-audit__header:hover {\n background-color: var(--color-hover);\n}\n\n/* We want to hide the browser's default arrow marker on summary elements. Admittedly, it's complicated. */\n.lh-root details > summary {\n /* Blink 89+ and Firefox will hide the arrow when display is changed from (new) default of `list-item` to block. https://chromestatus.com/feature/6730096436051968*/\n display: block;\n}\n/* Safari and Blink <=88 require using the -webkit-details-marker selector */\n.lh-root details > summary::-webkit-details-marker {\n display: none;\n}\n\n/* Perf Metric */\n\n.lh-metrics-container {\n display: grid;\n grid-auto-rows: 1fr;\n grid-template-columns: 1fr 1fr;\n grid-column-gap: var(--report-line-height);\n margin-bottom: var(--default-padding);\n}\n\n.lh-metric {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(-n+2) {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-metric__innerwrap {\n display: grid;\n /**\n * Icon -- Metric Name\n * -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 1fr;\n align-items: center;\n padding: var(--default-padding);\n}\n\n.lh-metric__details {\n order: -1;\n}\n\n.lh-metric__title {\n flex: 1;\n}\n\n.lh-calclink {\n padding-left: calc(1ex / 3);\n}\n\n.lh-metric__description {\n display: none;\n grid-column-start: 2;\n grid-column-end: 4;\n color: var(--report-text-color-secondary);\n}\n\n.lh-metric__value {\n font-size: var(--metric-value-font-size);\n margin: calc(var(--default-padding) / 2) 0;\n white-space: nowrap; /* No wrapping between metric value and the icon */\n grid-column-start: 2;\n}\n\n\n@media screen and (max-width: 535px) {\n .lh-metrics-container {\n display: block;\n }\n\n .lh-metric {\n border-bottom: none !important;\n }\n .lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(1) {\n border-bottom: 1px solid var(--report-border-color-secondary) !important;\n }\n\n /* Change the grid to 3 columns for narrow viewport. */\n .lh-metric__innerwrap {\n /**\n * Icon -- Metric Name -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 2fr 1fr;\n }\n .lh-metric__value {\n justify-self: end;\n grid-column-start: unset;\n }\n}\n\n/* No-JS toggle switch */\n/* Keep this selector sync'd w/ `magicSelector` in report-ui-features-test.js */\n .lh-metrics-toggle__input:checked ~ .lh-metrics-container .lh-metric__description {\n display: block;\n}\n\n/* TODO get rid of the SVGS and clean up these some more */\n.lh-metrics-toggle__input {\n opacity: 0;\n position: absolute;\n right: 0;\n top: 0px;\n}\n\n.lh-metrics-toggle__input + div > label > .lh-metrics-toggle__labeltext--hide,\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--show {\n display: none;\n}\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--hide {\n display: inline;\n}\n.lh-metrics-toggle__input:focus + div > label {\n outline: -webkit-focus-ring-color auto 3px;\n}\n\n.lh-metrics-toggle__label {\n cursor: pointer;\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n/* Pushes the metric description toggle button to the right. */\n.lh-audit-group--metrics .lh-audit-group__header {\n display: flex;\n justify-content: space-between;\n}\n\n.lh-metric__icon,\n.lh-scorescale-range::before {\n content: '';\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n display: inline-block;\n margin: var(--score-icon-margin);\n}\n\n.lh-metric--pass .lh-metric__value {\n color: var(--color-pass-secondary);\n}\n.lh-metric--pass .lh-metric__icon {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-metric--average .lh-metric__value {\n color: var(--color-average-secondary);\n}\n.lh-metric--average .lh-metric__icon {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-metric--fail .lh-metric__value {\n color: var(--color-fail-secondary);\n}\n.lh-metric--fail .lh-metric__icon {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-metric--error .lh-metric__value,\n.lh-metric--error .lh-metric__description {\n color: var(--color-fail-secondary);\n}\n\n/* Perf load opportunity */\n\n.lh-load-opportunity__cols {\n display: flex;\n align-items: flex-start;\n}\n\n.lh-load-opportunity__header .lh-load-opportunity__col {\n color: var(--color-gray-600);\n display: unset;\n line-height: calc(2.3 * var(--report-font-size));\n}\n\n.lh-load-opportunity__col {\n display: flex;\n}\n\n.lh-load-opportunity__col--one {\n flex: 5;\n align-items: center;\n margin-right: 2px;\n}\n.lh-load-opportunity__col--two {\n flex: 4;\n text-align: right;\n}\n\n.lh-audit--load-opportunity .lh-audit__display-text {\n text-align: right;\n flex: 0 0 7.5ch;\n}\n\n\n/* Sparkline */\n\n.lh-load-opportunity__sparkline {\n flex: 1;\n margin-top: calc((var(--report-line-height) - var(--sparkline-height)) / 2);\n}\n\n.lh-sparkline {\n height: var(--sparkline-height);\n width: 100%;\n}\n\n.lh-sparkline__bar {\n height: 100%;\n float: right;\n}\n\n.lh-audit--pass .lh-sparkline__bar {\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-sparkline__bar {\n background: var(--color-average);\n}\n\n.lh-audit--fail .lh-sparkline__bar {\n background: var(--color-fail);\n}\n\n/* Filmstrip */\n\n.lh-filmstrip-container {\n /* smaller gap between metrics and filmstrip */\n margin: -8px auto 0 auto;\n}\n\n.lh-filmstrip {\n display: grid;\n justify-content: space-between;\n padding-bottom: var(--default-padding);\n width: 100%;\n grid-template-columns: repeat(auto-fit, 90px);\n}\n\n.lh-filmstrip__frame {\n text-align: right;\n position: relative;\n}\n\n.lh-filmstrip__thumbnail {\n border: 1px solid var(--report-border-color-secondary);\n max-height: 150px;\n max-width: 120px;\n}\n\n/* Audit */\n\n.lh-audit {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n/* Apply border-top to just the first audit. */\n.lh-audit {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n.lh-audit ~ .lh-audit {\n border-top: none;\n}\n\n\n.lh-audit--error .lh-audit__display-text {\n color: var(--color-fail-secondary);\n}\n\n/* Audit Group */\n\n.lh-audit-group {\n margin-bottom: var(--audit-group-margin-bottom);\n position: relative;\n}\n.lh-audit-group--metrics {\n margin-bottom: calc(var(--audit-group-margin-bottom) / 2);\n}\n\n.lh-audit-group__header::before {\n /* By default, groups don't get an icon */\n content: none;\n width: var(--pwa-icon-size);\n height: var(--pwa-icon-size);\n margin: var(--pwa-icon-margin);\n display: inline-block;\n vertical-align: middle;\n}\n\n/* Style the \"over budget\" columns red. */\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(4),\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(5),\n.lh-audit-group--budgets #timing-budget tbody tr td:nth-child(3) {\n color: var(--color-red-700);\n}\n\n/* Align the \"over budget request count\" text to be close to the \"over budget bytes\" column. */\n.lh-audit-group--budgets .lh-table tbody tr td:nth-child(4){\n text-align: right;\n}\n\n.lh-audit-group--budgets .lh-details--budget {\n width: 100%;\n margin: 0 0 var(--default-padding);\n}\n\n.lh-audit-group--pwa-installable .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-installable-gray-url);\n}\n.lh-audit-group--pwa-optimized .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-optimized-gray-url);\n}\n.lh-audit-group--pwa-installable.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-installable-color-url);\n}\n.lh-audit-group--pwa-optimized.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-optimized-color-url);\n}\n\n.lh-audit-group--metrics .lh-audit-group__summary {\n margin-top: 0;\n margin-bottom: 0;\n}\n\n.lh-audit-group__summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.lh-audit-group__header .lh-chevron {\n margin-top: calc((var(--report-line-height) - 5px) / 2);\n}\n\n.lh-audit-group__header {\n letter-spacing: 0.8px;\n padding: var(--default-padding);\n padding-left: 0;\n}\n\n.lh-audit-group__header, .lh-audit-group__summary {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n.lh-audit-group__title {\n text-transform: uppercase;\n font-weight: 500;\n}\n\n.lh-audit-group__itemcount {\n color: var(--color-gray-600);\n}\n\n.lh-audit-group__footer {\n color: var(--color-gray-600);\n display: block;\n margin-top: var(--default-padding);\n}\n\n.lh-details,\n.lh-category-header__description,\n.lh-load-opportunity__header,\n.lh-audit-group__footer {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n}\n\n.lh-audit-explanation {\n margin: var(--audit-padding-vertical) 0 calc(var(--audit-padding-vertical) / 2) var(--audit-margin-horizontal);\n line-height: var(--audit-explanation-line-height);\n display: inline-block;\n}\n\n.lh-audit--fail .lh-audit-explanation {\n color: var(--color-fail-secondary);\n}\n\n/* Report */\n.lh-list > :not(:last-child) {\n margin-bottom: calc(var(--default-padding) * 2);\n}\n\n.lh-header-container {\n display: block;\n margin: 0 auto;\n position: relative;\n word-wrap: break-word;\n}\n\n.lh-header-container .lh-scores-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n\n\n.lh-report {\n min-width: var(--report-content-min-width);\n}\n\n.lh-exception {\n font-size: large;\n}\n\n.lh-code {\n white-space: normal;\n margin-top: 0;\n font-size: var(--report-monospace-font-size);\n}\n\n.lh-warnings {\n --item-margin: calc(var(--report-line-height) / 6);\n color: var(--color-average-secondary);\n margin: var(--audit-padding-vertical) 0;\n padding: var(--default-padding)\n var(--default-padding)\n var(--default-padding)\n calc(var(--audit-description-padding-left));\n background-color: var(--toplevel-warning-background-color);\n}\n.lh-warnings span {\n font-weight: bold;\n}\n\n.lh-warnings--toplevel {\n --item-margin: calc(var(--header-line-height) / 4);\n color: var(--toplevel-warning-text-color);\n margin-left: auto;\n margin-right: auto;\n max-width: var(--report-content-max-width-minus-edge-gap);\n padding: var(--toplevel-warning-padding);\n border-radius: 8px;\n}\n\n.lh-warnings__msg {\n color: var(--toplevel-warning-message-text-color);\n margin: 0;\n}\n\n.lh-warnings ul {\n margin: 0;\n}\n.lh-warnings li {\n margin: var(--item-margin) 0;\n}\n.lh-warnings li:last-of-type {\n margin-bottom: 0;\n}\n\n.lh-scores-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n}\n.lh-scores-header__solo {\n padding: 0;\n border: 0;\n}\n\n/* Gauge */\n\n.lh-gauge__wrapper--pass {\n color: var(--color-pass-secondary);\n fill: var(--color-pass);\n stroke: var(--color-pass);\n}\n\n.lh-gauge__wrapper--average {\n color: var(--color-average-secondary);\n fill: var(--color-average);\n stroke: var(--color-average);\n}\n\n.lh-gauge__wrapper--fail {\n color: var(--color-fail-secondary);\n fill: var(--color-fail);\n stroke: var(--color-fail);\n}\n\n.lh-gauge__wrapper--not-applicable {\n color: var(--color-not-applicable);\n fill: var(--color-not-applicable);\n stroke: var(--color-not-applicable);\n}\n\n.lh-fraction__wrapper .lh-fraction__content::before {\n content: '';\n height: var(--score-icon-size);\n width: var(--score-icon-size);\n margin: var(--score-icon-margin);\n display: inline-block;\n}\n.lh-fraction__wrapper--pass .lh-fraction__content {\n color: var(--color-pass-secondary);\n}\n.lh-fraction__wrapper--pass .lh-fraction__background {\n background-color: var(--color-pass);\n}\n.lh-fraction__wrapper--pass .lh-fraction__content::before {\n background-color: var(--color-pass);\n border-radius: 50%;\n}\n.lh-fraction__wrapper--average .lh-fraction__content {\n color: var(--color-average-secondary);\n}\n.lh-fraction__wrapper--average .lh-fraction__background,\n.lh-fraction__wrapper--average .lh-fraction__content::before {\n background-color: var(--color-average);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content {\n color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__background {\n background-color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n.lh-fraction__wrapper--null .lh-fraction__content {\n color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__background {\n background-color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__content::before {\n border-radius: 50%;\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-700);\n}\n\n.lh-fraction__background {\n position: absolute;\n height: 100%;\n width: 100%;\n border-radius: calc(var(--gauge-circle-size) / 2);\n opacity: 0.1;\n z-index: -1;\n}\n\n.lh-fraction__content-wrapper {\n height: var(--gauge-circle-size);\n display: flex;\n align-items: center;\n}\n\n.lh-fraction__content {\n display: flex;\n position: relative;\n align-items: center;\n justify-content: center;\n font-size: calc(0.3 * var(--gauge-circle-size));\n line-height: calc(0.4 * var(--gauge-circle-size));\n width: max-content;\n min-width: calc(1.5 * var(--gauge-circle-size));\n padding: calc(0.1 * var(--gauge-circle-size)) calc(0.2 * var(--gauge-circle-size));\n --score-icon-size: calc(0.21 * var(--gauge-circle-size));\n --score-icon-margin: 0 calc(0.15 * var(--gauge-circle-size)) 0 0;\n}\n\n.lh-gauge {\n stroke-linecap: round;\n width: var(--gauge-circle-size);\n height: var(--gauge-circle-size);\n}\n\n.lh-category .lh-gauge {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n.lh-gauge-base {\n opacity: 0.1;\n}\n\n.lh-gauge-arc {\n fill: none;\n transform-origin: 50% 50%;\n animation: load-gauge var(--transition-length) ease both;\n animation-delay: 250ms;\n}\n\n.lh-gauge__svg-wrapper {\n position: relative;\n height: var(--gauge-circle-size);\n}\n.lh-category .lh-gauge__svg-wrapper,\n.lh-category .lh-fraction__wrapper {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n/* The plugin badge overlay */\n.lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size);\n height: var(--plugin-badge-size);\n background-color: var(--plugin-badge-background-color);\n background-image: var(--plugin-icon-url);\n background-repeat: no-repeat;\n background-size: var(--plugin-icon-size);\n background-position: 58% 50%;\n content: \"\";\n position: absolute;\n right: -6px;\n bottom: 0px;\n display: block;\n z-index: 100;\n box-shadow: 0 0 4px rgba(0,0,0,.2);\n border-radius: 25%;\n}\n.lh-category .lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size-big);\n height: var(--plugin-badge-size-big);\n}\n\n@keyframes load-gauge {\n from { stroke-dasharray: 0 352; }\n}\n\n.lh-gauge__percentage {\n width: 100%;\n height: var(--gauge-circle-size);\n position: absolute;\n font-family: var(--report-font-family-monospace);\n font-size: calc(var(--gauge-circle-size) * 0.34 + 1.3px);\n line-height: 0;\n text-align: center;\n top: calc(var(--score-container-padding) + var(--gauge-circle-size) / 2);\n}\n\n.lh-category .lh-gauge__percentage {\n --gauge-circle-size: var(--gauge-circle-size-big);\n --gauge-percentage-font-size: var(--gauge-percentage-font-size-big);\n}\n\n.lh-gauge__wrapper,\n.lh-fraction__wrapper {\n position: relative;\n display: flex;\n align-items: center;\n flex-direction: column;\n text-decoration: none;\n padding: var(--score-container-padding);\n\n --transition-length: 1s;\n\n /* Contain the layout style paint & layers during animation*/\n contain: content;\n will-change: opacity; /* Only using for layer promotion */\n}\n\n.lh-gauge__label,\n.lh-fraction__label {\n font-size: var(--gauge-label-font-size);\n font-weight: 500;\n line-height: var(--gauge-label-line-height);\n margin-top: 10px;\n text-align: center;\n color: var(--report-text-color);\n word-break: keep-all;\n}\n\n/* TODO(#8185) use more BEM (.lh-gauge__label--big) instead of relying on descendant selector */\n.lh-category .lh-gauge__label,\n.lh-category .lh-fraction__label {\n --gauge-label-font-size: var(--gauge-label-font-size-big);\n --gauge-label-line-height: var(--gauge-label-line-height-big);\n margin-top: 14px;\n}\n\n.lh-scores-header .lh-gauge__wrapper,\n.lh-scores-header .lh-fraction__wrapper,\n.lh-scores-header .lh-gauge--pwa__wrapper,\n.lh-sticky-header .lh-gauge__wrapper,\n.lh-sticky-header .lh-fraction__wrapper,\n.lh-sticky-header .lh-gauge--pwa__wrapper {\n width: var(--gauge-wrapper-width);\n}\n\n.lh-scorescale {\n display: inline-flex;\n\n gap: calc(var(--default-padding) * 4);\n margin: 16px auto 0 auto;\n font-size: var(--report-font-size-secondary);\n color: var(--color-gray-700);\n\n}\n\n.lh-scorescale-range {\n display: flex;\n align-items: center;\n font-family: var(--report-font-family-monospace);\n white-space: nowrap;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale {\n border: 0;\n display: flex;\n justify-content: center;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale-range {\n font-family: unset;\n font-size: 12px;\n}\n\n.lh-scorescale-wrap {\n display: contents;\n}\n\n/* Hide category score gauages if it's a single category report */\n.lh-header--solo-category .lh-scores-wrapper {\n display: none;\n}\n\n\n.lh-categories {\n width: 100%;\n}\n\n.lh-category {\n padding: var(--category-padding);\n max-width: var(--report-content-max-width);\n margin: 0 auto;\n\n scroll-margin-top: var(--sticky-header-buffer);\n}\n\n.lh-category-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n.lh-category-wrapper:last-of-type {\n border-bottom: 0;\n}\n\n.lh-category-header {\n margin-bottom: var(--section-padding-vertical);\n}\n\n.lh-category-header .lh-score__gauge {\n max-width: 400px;\n width: auto;\n margin: 0px auto;\n}\n\n.lh-category-header__finalscreenshot {\n display: grid;\n grid-template: none / 1fr 1px 1fr;\n justify-items: center;\n align-items: center;\n gap: var(--report-line-height);\n min-height: 288px;\n margin-bottom: var(--default-padding);\n}\n\n.lh-final-ss-image {\n /* constrain the size of the image to not be too large */\n max-height: calc(var(--gauge-circle-size-big) * 2.8);\n max-width: calc(var(--gauge-circle-size-big) * 3.5);\n border: 1px solid var(--color-gray-200);\n padding: 4px;\n border-radius: 3px;\n display: block;\n}\n\n.lh-category-headercol--separator {\n background: var(--color-gray-200);\n width: 1px;\n height: var(--gauge-circle-size-big);\n}\n\n@media screen and (max-width: 780px) {\n .lh-category-header__finalscreenshot {\n grid-template: 1fr 1fr / none\n }\n .lh-category-headercol--separator {\n display: none;\n }\n}\n\n\n/* 964 fits the min-width of the filmstrip */\n@media screen and (max-width: 964px) {\n .lh-report {\n margin-left: 0;\n width: 100%;\n }\n}\n\n@media print {\n body {\n -webkit-print-color-adjust: exact; /* print background colors */\n }\n .lh-container {\n display: block;\n }\n .lh-report {\n margin-left: 0;\n padding-top: 0;\n }\n .lh-categories {\n margin-top: 0;\n }\n}\n\n.lh-table {\n position: relative;\n border-collapse: separate;\n border-spacing: 0;\n /* Can't assign padding to table, so shorten the width instead. */\n width: calc(100% - var(--audit-description-padding-left) - var(--stackpack-padding-horizontal));\n border: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-table thead th {\n position: sticky;\n top: calc(var(--sticky-header-buffer) + 1em);\n z-index: 1;\n background-color: var(--report-background-color);\n border-bottom: 1px solid var(--report-border-color-secondary);\n font-weight: normal;\n color: var(--color-gray-600);\n /* See text-wrapping comment on .lh-container. */\n word-break: normal;\n}\n\n.lh-row--group {\n background-color: var(--table-group-header-background-color);\n}\n\n.lh-row--group td {\n font-weight: bold;\n font-size: 1.05em;\n color: var(--table-group-header-text-color);\n}\n\n.lh-row--group td:first-child {\n font-weight: normal;\n}\n\n.lh-row--group .lh-text {\n color: inherit;\n text-decoration: none;\n display: inline-block;\n}\n\n.lh-row--group a.lh-link:hover {\n text-decoration: underline;\n}\n\n.lh-row--group .lh-audit__adorn {\n text-transform: capitalize;\n font-weight: normal;\n padding: 2px 3px 1px 3px;\n}\n\n.lh-row--group .lh-audit__adorn1p {\n color: var(--link-color);\n border-color: var(--link-color);\n}\n\n.lh-row--group .lh-report-icon--external::before {\n content: \"\";\n background-repeat: no-repeat;\n width: 14px;\n height: 16px;\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n\n.lh-row--group .lh-report-icon--external {\n display: none;\n}\n\n.lh-row--group:hover .lh-report-icon--external {\n display: inline-block;\n}\n\n.lh-dark .lh-report-icon--external::before {\n filter: invert(1);\n}\n\n/** Manages indentation of two-level and three-level nested adjacent rows */\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) td:first-child {\n padding-left: 20px;\n}\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) ~ .lh-sub-item-row td:first-child {\n padding-left: 40px;\n}\n\n.lh-row--even {\n background-color: var(--table-group-header-background-color);\n}\n.lh-row--hidden {\n display: none;\n}\n\n.lh-table th,\n.lh-table td {\n padding: var(--default-padding);\n}\n\n.lh-table tr {\n vertical-align: middle;\n}\n\n.lh-table tr:hover {\n background-color: var(--table-higlight-background-color);\n}\n\n/* Looks unnecessary, but mostly for keeping the s left-aligned */\n.lh-table-column--text,\n.lh-table-column--source-location,\n.lh-table-column--url,\n/* .lh-table-column--thumbnail, */\n/* .lh-table-column--empty,*/\n.lh-table-column--code,\n.lh-table-column--node {\n text-align: left;\n}\n\n.lh-table-column--code {\n min-width: 100px;\n}\n\n.lh-table-column--bytes,\n.lh-table-column--timespanMs,\n.lh-table-column--ms,\n.lh-table-column--numeric {\n text-align: right;\n word-break: normal;\n}\n\n\n\n.lh-table .lh-table-column--thumbnail {\n width: var(--image-preview-size);\n}\n\n.lh-table-column--url {\n min-width: 250px;\n}\n\n.lh-table-column--text {\n min-width: 80px;\n}\n\n/* Keep columns narrow if they follow the URL column */\n/* 12% was determined to be a decent narrow width, but wide enough for column headings */\n.lh-table-column--url + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--ms,\n.lh-table-column--url + .lh-table-column--ms + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--timespanMs {\n width: 12%;\n}\n\n.lh-text__url-host {\n display: inline;\n}\n\n.lh-text__url-host {\n margin-left: calc(var(--report-font-size) / 2);\n opacity: 0.6;\n font-size: 90%\n}\n\n.lh-thumbnail {\n object-fit: cover;\n width: var(--image-preview-size);\n height: var(--image-preview-size);\n display: block;\n}\n\n.lh-unknown pre {\n overflow: scroll;\n border: solid 1px var(--color-gray-200);\n}\n\n.lh-text__url > a {\n color: inherit;\n text-decoration: none;\n}\n\n.lh-text__url > a:hover {\n text-decoration: underline dotted #999;\n}\n\n.lh-sub-item-row {\n margin-left: 20px;\n margin-bottom: 0;\n color: var(--color-gray-700);\n}\n\n.lh-sub-item-row td {\n padding-top: 4px;\n padding-bottom: 4px;\n padding-left: 20px;\n}\n\n/* Chevron\n https://codepen.io/paulirish/pen/LmzEmK\n */\n.lh-chevron {\n --chevron-angle: 42deg;\n /* Edge doesn't support transform: rotate(calc(...)), so we define it here */\n --chevron-angle-right: -42deg;\n width: var(--chevron-size);\n height: var(--chevron-size);\n margin-top: calc((var(--report-line-height) - 12px) / 2);\n}\n\n.lh-chevron__lines {\n transition: transform 0.4s;\n transform: translateY(var(--report-line-height));\n}\n.lh-chevron__line {\n stroke: var(--chevron-line-stroke);\n stroke-width: var(--chevron-size);\n stroke-linecap: square;\n transform-origin: 50%;\n transform: rotate(var(--chevron-angle));\n transition: transform 300ms, stroke 300ms;\n}\n\n.lh-expandable-details .lh-chevron__line-right,\n.lh-expandable-details[open] .lh-chevron__line-left {\n transform: rotate(var(--chevron-angle-right));\n}\n\n.lh-expandable-details[open] .lh-chevron__line-right {\n transform: rotate(var(--chevron-angle));\n}\n\n\n.lh-expandable-details[open] .lh-chevron__lines {\n transform: translateY(calc(var(--chevron-size) * -1));\n}\n\n.lh-expandable-details[open] {\n animation: 300ms openDetails forwards;\n padding-bottom: var(--default-padding);\n}\n\n@keyframes openDetails {\n from {\n outline: 1px solid var(--report-background-color);\n }\n to {\n outline: 1px solid;\n box-shadow: 0 2px 4px rgba(0, 0, 0, .24);\n }\n}\n\n@media screen and (max-width: 780px) {\n /* no black outline if we're not confident the entire table can be displayed within bounds */\n .lh-expandable-details[open] {\n animation: none;\n }\n}\n\n.lh-expandable-details[open] summary, details.lh-clump > summary {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\ndetails.lh-clump[open] > summary {\n border-bottom-width: 0;\n}\n\n\n\ndetails .lh-clump-toggletext--hide,\ndetails[open] .lh-clump-toggletext--show { display: none; }\ndetails[open] .lh-clump-toggletext--hide { display: block;}\n\n\n/* Tooltip */\n.lh-tooltip-boundary {\n position: relative;\n}\n\n.lh-tooltip {\n position: absolute;\n display: none; /* Don't retain these layers when not needed */\n opacity: 0;\n background: #ffffff;\n white-space: pre-line; /* Render newlines in the text */\n min-width: 246px;\n max-width: 275px;\n padding: 15px;\n border-radius: 5px;\n text-align: initial;\n line-height: 1.4;\n}\n/* shrink tooltips to not be cutoff on left edge of narrow viewports\n 45vw is chosen to be ~= width of the left column of metrics\n*/\n@media screen and (max-width: 535px) {\n .lh-tooltip {\n min-width: 45vw;\n padding: 3vw;\n }\n}\n\n.lh-tooltip-boundary:hover .lh-tooltip {\n display: block;\n animation: fadeInTooltip 250ms;\n animation-fill-mode: forwards;\n animation-delay: 850ms;\n bottom: 100%;\n z-index: 1;\n will-change: opacity;\n right: 0;\n pointer-events: none;\n}\n\n.lh-tooltip::before {\n content: \"\";\n border: solid transparent;\n border-bottom-color: #fff;\n border-width: 10px;\n position: absolute;\n bottom: -20px;\n right: 6px;\n transform: rotate(180deg);\n pointer-events: none;\n}\n\n@keyframes fadeInTooltip {\n 0% { opacity: 0; }\n 75% { opacity: 1; }\n 100% { opacity: 1; filter: drop-shadow(1px 0px 1px #aaa) drop-shadow(0px 2px 4px hsla(206, 6%, 25%, 0.15)); pointer-events: auto; }\n}\n\n/* Element screenshot */\n.lh-element-screenshot {\n float: left;\n margin-right: 20px;\n}\n.lh-element-screenshot__content {\n overflow: hidden;\n min-width: 110px;\n display: flex;\n justify-content: center;\n background-color: var(--report-background-color);\n}\n.lh-element-screenshot__image {\n position: relative;\n /* Set by ElementScreenshotRenderer.installFullPageScreenshotCssVariable */\n background-image: var(--element-screenshot-url);\n outline: 2px solid #777;\n background-color: white;\n background-repeat: no-repeat;\n}\n.lh-element-screenshot__mask {\n position: absolute;\n background: #555;\n opacity: 0.8;\n}\n.lh-element-screenshot__element-marker {\n position: absolute;\n outline: 2px solid var(--color-lime-400);\n}\n.lh-element-screenshot__overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 2000; /* .lh-topbar is 1000 */\n background: var(--screenshot-overlay-background);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: zoom-out;\n}\n\n.lh-element-screenshot__overlay .lh-element-screenshot {\n margin-right: 0; /* clearing margin used in thumbnail case */\n outline: 1px solid var(--color-gray-700);\n}\n\n.lh-screenshot-overlay--enabled .lh-element-screenshot {\n cursor: zoom-out;\n}\n.lh-screenshot-overlay--enabled .lh-node .lh-element-screenshot {\n cursor: zoom-in;\n}\n\n\n.lh-meta__items {\n --meta-icon-size: calc(var(--report-icon-size) * 0.667);\n padding: var(--default-padding);\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n background-color: var(--env-item-background-color);\n border-radius: 3px;\n margin: 0 0 var(--default-padding) 0;\n font-size: 12px;\n column-gap: var(--default-padding);\n color: var(--color-gray-700);\n}\n\n.lh-meta__item {\n display: block;\n list-style-type: none;\n position: relative;\n padding: 0 0 0 calc(var(--meta-icon-size) + var(--default-padding) * 2);\n cursor: unset; /* disable pointer cursor from report-icon */\n}\n\n.lh-meta__item.lh-tooltip-boundary {\n text-decoration: dotted underline var(--color-gray-500);\n cursor: help;\n}\n\n.lh-meta__item.lh-report-icon::before {\n position: absolute;\n left: var(--default-padding);\n width: var(--meta-icon-size);\n height: var(--meta-icon-size);\n}\n\n.lh-meta__item.lh-report-icon:hover::before {\n opacity: 0.7;\n}\n\n.lh-meta__item .lh-tooltip {\n color: var(--color-gray-800);\n}\n\n.lh-meta__item .lh-tooltip::before {\n right: auto; /* Set the tooltip arrow to the leftside */\n left: 6px;\n}\n\n/* Change the grid for narrow viewport. */\n@media screen and (max-width: 640px) {\n .lh-meta__items {\n grid-template-columns: 1fr 1fr;\n }\n}\n@media screen and (max-width: 535px) {\n .lh-meta__items {\n display: block;\n }\n}\n\n\n/*# sourceURL=report-styles.css */\n"); + 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 --report-icon-size: var(--score-icon-background-size);\n --report-line-height: 24px;\n --report-line-height-secondary: 20px;\n --report-monospace-font-size: calc(var(--report-font-size) * 0.85);\n --report-text-color-secondary: var(--color-gray-800);\n --report-text-color: var(--color-gray-900);\n --report-content-max-width: calc(60 * var(--report-font-size)); /* defaults to 840px */\n --report-content-min-width: 360px;\n --report-content-max-width-minus-edge-gap: calc(var(--report-content-max-width) - var(--edge-gap-padding) * 2);\n --score-container-padding: 8px;\n --score-icon-background-size: 24px;\n --score-icon-margin-left: 6px;\n --score-icon-margin-right: 14px;\n --score-icon-margin: 0 var(--score-icon-margin-right) 0 var(--score-icon-margin-left);\n --score-icon-size: 12px;\n --score-icon-size-big: 16px;\n --screenshot-overlay-background: rgba(0, 0, 0, 0.3);\n --section-padding-vertical: calc(var(--default-padding) * 6);\n --snippet-background-color: var(--color-gray-50);\n --snippet-color: #0938C2;\n --sparkline-height: 5px;\n --stackpack-padding-horizontal: 10px;\n --sticky-header-background-color: var(--report-background-color);\n --sticky-header-buffer: calc(var(--topbar-height) + var(--sticky-header-height));\n --sticky-header-height: calc(var(--gauge-circle-size-sm) + var(--score-container-padding) * 2);\n --table-group-header-background-color: #EEF1F4;\n --table-group-header-text-color: var(--color-gray-700);\n --table-higlight-background-color: #F5F7FA;\n --tools-icon-color: var(--color-gray-600);\n --topbar-background-color: var(--color-white);\n --topbar-height: 32px;\n --topbar-logo-size: 24px;\n --topbar-padding: 0 8px;\n --toplevel-warning-background-color: hsla(30, 100%, 75%, 10%);\n --toplevel-warning-message-text-color: var(--color-average-secondary);\n --toplevel-warning-padding: 18px;\n --toplevel-warning-text-color: var(--report-text-color);\n\n /* SVGs */\n --plugin-icon-url-dark: url('data:image/svg+xml;utf8,');\n --plugin-icon-url: url('data:image/svg+xml;utf8,');\n\n --pass-icon-url: url('data:image/svg+xml;utf8,check');\n --average-icon-url: url('data:image/svg+xml;utf8,info');\n --fail-icon-url: url('data:image/svg+xml;utf8,warn');\n --error-icon-url: url('data:image/svg+xml;utf8,error');\n\n --pwa-installable-gray-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-gray-url-dark: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url-dark: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-color-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-color-url: url('data:image/svg+xml;utf8,');\n\n --swap-locale-icon-url: url('data:image/svg+xml;utf8,');\n}\n\n@media not print {\n .lh-dark {\n /* Pallete */\n --color-gray-200: var(--color-gray-800);\n --color-gray-300: #616161;\n --color-gray-400: var(--color-gray-600);\n --color-gray-700: var(--color-gray-400);\n --color-gray-50: #757575;\n --color-gray-600: var(--color-gray-500);\n --color-green-700: var(--color-green);\n --color-orange-700: var(--color-orange);\n --color-red-700: var(--color-red);\n --color-teal-600: var(--color-cyan-500);\n\n /* Context-specific colors */\n --color-hover: rgba(0, 0, 0, 0.2);\n --color-informative: var(--color-blue-200);\n\n /* Component variables */\n --env-item-background-color: #393535;\n --link-color: var(--color-blue-200);\n --locale-selector-background-color: var(--color-gray-200);\n --plugin-badge-background-color: var(--color-gray-800);\n --report-background-color: var(--color-gray-900);\n --report-border-color-secondary: var(--color-gray-200);\n --report-text-color-secondary: var(--color-gray-400);\n --report-text-color: var(--color-gray-100);\n --snippet-color: var(--color-cyan-500);\n --topbar-background-color: var(--color-gray);\n --toplevel-warning-background-color: hsl(33deg 14% 18%);\n --toplevel-warning-message-text-color: var(--color-orange-700);\n --toplevel-warning-text-color: var(--color-gray-100);\n --table-group-header-background-color: rgba(186, 196, 206, 0.15);\n --table-group-header-text-color: var(--color-gray-100);\n --table-higlight-background-color: rgba(186, 196, 206, 0.09);\n\n /* SVGs */\n --plugin-icon-url: var(--plugin-icon-url-dark);\n --pwa-installable-gray-url: var(--pwa-installable-gray-url-dark);\n --pwa-optimized-gray-url: var(--pwa-optimized-gray-url-dark);\n }\n}\n\n@media only screen and (max-width: 480px) {\n .lh-vars {\n --audit-group-margin-bottom: 20px;\n --edge-gap-padding: var(--default-padding);\n --env-name-min-width: 120px;\n --gauge-circle-size-big: 96px;\n --gauge-circle-size: 72px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 112px;\n --header-padding: 16px 0 16px 0;\n --image-preview-size: 24px;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-size: 14px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --topbar-height: 28px;\n --topbar-logo-size: 20px;\n }\n\n /* Not enough space to adequately show the relative savings bars. */\n .lh-sparkline {\n display: none;\n }\n}\n\n.lh-vars.lh-devtools {\n --audit-explanation-line-height: 14px;\n --audit-group-margin-bottom: 20px;\n --audit-group-padding-vertical: 12px;\n --audit-padding-vertical: 4px;\n --category-padding: 12px;\n --default-padding: 12px;\n --env-name-min-width: 120px;\n --footer-padding-vertical: 8px;\n --gauge-circle-size-big: 72px;\n --gauge-circle-size: 64px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 97px;\n --header-line-height: 20px;\n --header-padding: 16px 0 16px 0;\n --screenshot-overlay-background: transparent;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-family-monospace: 'Menlo', 'dejavu sans mono', 'Consolas', 'Lucida Console', monospace;\n --report-font-family: '.SFNSDisplay-Regular', 'Helvetica Neue', 'Lucida Grande', sans-serif;\n --report-font-size: 12px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --section-padding-vertical: 8px;\n}\n\n.lh-container:not(.lh-topbar + .lh-container) {\n --topbar-height: 0;\n --sticky-header-height: 0;\n --sticky-header-buffer: 0;\n}\n\n.lh-devtools.lh-root {\n height: 100%;\n}\n.lh-devtools.lh-root img {\n /* Override devtools default 'min-width: 0' so svg without size in a flexbox isn't collapsed. */\n min-width: auto;\n}\n.lh-devtools .lh-container {\n overflow-y: scroll;\n height: calc(100% - var(--topbar-height));\n /** The .lh-container is the scroll parent in DevTools so we exclude the topbar from the sticky header buffer. */\n --sticky-header-buffer: calc(var(--sticky-header-height));\n}\n@media print {\n .lh-devtools .lh-container {\n overflow: unset;\n }\n}\n.lh-devtools .lh-sticky-header {\n /* This is normally the height of the topbar, but we want it to stick to the top of our scroll container .lh-container` */\n top: 0;\n}\n.lh-devtools .lh-element-screenshot__overlay {\n position: absolute;\n}\n\n@keyframes fadeIn {\n 0% { opacity: 0;}\n 100% { opacity: 0.6;}\n}\n\n.lh-root *, .lh-root *::before, .lh-root *::after {\n box-sizing: border-box;\n}\n\n.lh-root {\n font-family: var(--report-font-family);\n font-size: var(--report-font-size);\n margin: 0;\n line-height: var(--report-line-height);\n background: var(--report-background-color);\n color: var(--report-text-color);\n}\n\n.lh-root :focus-visible {\n outline: -webkit-focus-ring-color auto 3px;\n}\n.lh-root summary:focus {\n outline: none;\n box-shadow: 0 0 0 1px hsl(217, 89%, 61%);\n}\n\n.lh-root [hidden] {\n display: none !important;\n}\n\n.lh-root pre {\n margin: 0;\n}\n\n.lh-root pre,\n.lh-root code {\n font-family: var(--report-font-family-monospace);\n}\n\n.lh-root details > summary {\n cursor: pointer;\n}\n\n.lh-hidden {\n display: none !important;\n}\n\n.lh-container {\n /*\n Text wrapping in the report is so much FUN!\n We have a `word-break: break-word;` globally here to prevent a few common scenarios, namely\n long non-breakable text (usually URLs) found in:\n 1. The footer\n 2. .lh-node (outerHTML)\n 3. .lh-code\n\n With that sorted, the next challenge is appropriate column sizing and text wrapping inside our\n .lh-details tables. Even more fun.\n * We don't want table headers (\"Potential Savings (ms)\") to wrap or their column values, but\n we'd be happy for the URL column to wrap if the URLs are particularly long.\n * We want the narrow columns to remain narrow, providing the most column width for URL\n * We don't want the table to extend past 100% width.\n * Long URLs in the URL column can wrap. Util.getURLDisplayName maxes them out at 64 characters,\n but they do not get any overflow:ellipsis treatment.\n */\n word-break: break-word;\n}\n\n.lh-audit-group a,\n.lh-category-header__description a,\n.lh-audit__description a,\n.lh-warnings a,\n.lh-footer a,\n.lh-table-column--link a {\n color: var(--link-color);\n}\n\n.lh-audit__description, .lh-audit__stackpack {\n --inner-audit-padding-right: var(--stackpack-padding-horizontal);\n padding-left: var(--audit-description-padding-left);\n padding-right: var(--inner-audit-padding-right);\n padding-top: 8px;\n padding-bottom: 8px;\n}\n\n.lh-details {\n margin-top: var(--default-padding);\n margin-bottom: var(--default-padding);\n margin-left: var(--audit-description-padding-left);\n /* whatever the .lh-details side margins are */\n width: 100%;\n}\n\n.lh-audit__stackpack {\n display: flex;\n align-items: center;\n}\n\n.lh-audit__stackpack__img {\n max-width: 30px;\n margin-right: var(--default-padding)\n}\n\n/* Report header */\n\n.lh-report-icon {\n display: flex;\n align-items: center;\n padding: 10px 12px;\n cursor: pointer;\n}\n.lh-report-icon[disabled] {\n opacity: 0.3;\n pointer-events: none;\n}\n\n.lh-report-icon::before {\n content: \"\";\n margin: 4px;\n background-repeat: no-repeat;\n width: var(--report-icon-size);\n height: var(--report-icon-size);\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n.lh-report-icon:hover::before {\n opacity: 1;\n}\n.lh-dark .lh-report-icon::before {\n filter: invert(1);\n}\n.lh-report-icon--print::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--copy::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--open::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--download::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--dark::before {\n background-image:url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--treemap::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--date::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--devices::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--world::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--stopwatch::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--networkspeed::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-one::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-many::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--chrome::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--external::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n\n.lh-buttons {\n display: flex;\n flex-wrap: wrap;\n margin: var(--default-padding) 0;\n}\n.lh-button {\n height: 32px;\n border: 1px solid var(--report-border-color-secondary);\n border-radius: 3px;\n color: var(--link-color);\n background-color: var(--report-background-color);\n margin: 5px;\n}\n\n.lh-button:first-of-type {\n margin-left: 0;\n}\n\n/* Node */\n.lh-node__snippet {\n font-family: var(--report-font-family-monospace);\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n line-height: 20px;\n}\n\n/* Score */\n\n.lh-audit__score-icon {\n opacity: 0;\n}\n\n.lh-audit__score-icon {\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n margin: var(--score-icon-margin);\n}\n\n.lh-audit--pass .lh-audit__display-text {\n color: var(--color-pass-secondary);\n}\n.lh-audit--pass .lh-audit__score-icon,\n.lh-scorescale-range--pass::before {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-audit__display-text {\n /* color: var(--color-average-secondary); */\n color: gray;\n}\n.lh-audit--average .lh-audit__score-icon,\n.lh-scorescale-range--average::before {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-audit--fail .lh-audit__display-text {\n /* color: var(--color-fail-secondary); */\n color: gray;\n}\n.lh-audit--fail .lh-audit__score-icon,\n.lh-audit--error .lh-audit__score-icon,\n.lh-scorescale-range--fail::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-audit--error .lh-audit__score-icon,\n.lh-metric--error .lh-metric__icon {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n border: none;\n}\n\n.lh-gauge__wrapper--fail .lh-gauge--error {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n transform: scale(0.5);\n top: var(--score-container-padding);\n}\n\n.lh-audit--manual .lh-audit__display-text,\n.lh-audit--notapplicable .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n.lh-audit--manual .lh-audit__score-icon,\n.lh-audit--notapplicable .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n background: none;\n}\n\n.lh-audit--informative .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n\n.lh-audit--informative .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n}\n\n.lh-audit__description,\n.lh-audit__stackpack {\n color: var(--report-text-color-secondary);\n}\n.lh-audit__adorn {\n border: 1px solid var(--color-gray-500);\n border-radius: 3px;\n margin: 0 3px;\n padding: 0 2px;\n line-height: 1.1;\n display: inline-block;\n font-size: 90%;\n color: var(--report-text-color-secondary);\n}\n\n.lh-category-header__description {\n text-align: center;\n color: var(--color-gray-700);\n margin: 0px auto;\n max-width: 400px;\n}\n\n\n.lh-audit__display-text,\n.lh-load-opportunity__sparkline,\n.lh-chevron-container {\n margin: 0 var(--audit-margin-horizontal);\n}\n.lh-chevron-container {\n margin-right: 0;\n}\n\n.lh-audit__title-and-text {\n flex: 1;\n}\n\n.lh-audit__title-and-text code {\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n}\n\n/* Prepend display text with em dash separator. But not in Opportunities. */\n.lh-audit__display-text:not(:empty):before {\n content: '—';\n margin-right: var(--audit-margin-horizontal);\n}\n.lh-audit-group.lh-audit-group--load-opportunities .lh-audit__display-text:not(:empty):before {\n display: none;\n}\n\n/* Expandable Details (Audit Groups, Audits) */\n.lh-audit__header {\n display: flex;\n align-items: center;\n padding: var(--default-padding);\n}\n\n.lh-audit--load-opportunity .lh-audit__header {\n display: block;\n}\n\n\n.lh-metricfilter {\n display: grid;\n justify-content: end;\n align-items: center;\n grid-auto-flow: column;\n gap: 4px;\n color: var(--color-gray-700);\n}\n\n.lh-metricfilter__radio {\n /*\n * Instead of hiding, position offscreen so it's still accessible to screen readers\n * https://bugs.chromium.org/p/chromium/issues/detail?id=1439785\n */\n position: fixed;\n left: -9999px;\n}\n.lh-metricfilter input[type='radio']:focus-visible + label {\n outline: -webkit-focus-ring-color auto 1px;\n}\n\n.lh-metricfilter__label {\n display: inline-flex;\n padding: 0 4px;\n height: 16px;\n text-decoration: underline;\n align-items: center;\n cursor: pointer;\n font-size: 90%;\n}\n\n.lh-metricfilter__label--active {\n background: var(--color-blue-primary);\n color: var(--color-white);\n border-radius: 3px;\n text-decoration: none;\n}\n/* Give the 'All' choice a more muted display */\n.lh-metricfilter__label--active[for=\"metric-All\"] {\n background-color: var(--color-blue-200) !important;\n color: black !important;\n}\n\n.lh-metricfilter__text {\n margin-right: 8px;\n}\n\n/* If audits are filtered, hide the itemcount for Passed Audits… */\n.lh-category--filtered .lh-audit-group .lh-audit-group__itemcount {\n display: none;\n}\n\n\n.lh-audit__header:hover {\n background-color: var(--color-hover);\n}\n\n/* We want to hide the browser's default arrow marker on summary elements. Admittedly, it's complicated. */\n.lh-root details > summary {\n /* Blink 89+ and Firefox will hide the arrow when display is changed from (new) default of `list-item` to block. https://chromestatus.com/feature/6730096436051968*/\n display: block;\n}\n/* Safari and Blink <=88 require using the -webkit-details-marker selector */\n.lh-root details > summary::-webkit-details-marker {\n display: none;\n}\n\n/* Perf Metric */\n\n.lh-metrics-container {\n display: grid;\n grid-auto-rows: 1fr;\n grid-template-columns: 1fr 1fr;\n grid-column-gap: var(--report-line-height);\n margin-bottom: var(--default-padding);\n}\n\n.lh-metric {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(-n+2) {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-metric__innerwrap {\n display: grid;\n /**\n * Icon -- Metric Name\n * -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 1fr;\n align-items: center;\n padding: var(--default-padding);\n}\n\n.lh-metric__details {\n order: -1;\n}\n\n.lh-metric__title {\n flex: 1;\n}\n\n.lh-calclink {\n padding-left: calc(1ex / 3);\n}\n\n.lh-metric__description {\n display: none;\n grid-column-start: 2;\n grid-column-end: 4;\n color: var(--report-text-color-secondary);\n}\n\n.lh-metric__value {\n font-size: var(--metric-value-font-size);\n margin: calc(var(--default-padding) / 2) 0;\n white-space: nowrap; /* No wrapping between metric value and the icon */\n grid-column-start: 2;\n}\n\n\n@media screen and (max-width: 535px) {\n .lh-metrics-container {\n display: block;\n }\n\n .lh-metric {\n border-bottom: none !important;\n }\n .lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(1) {\n border-bottom: 1px solid var(--report-border-color-secondary) !important;\n }\n\n /* Change the grid to 3 columns for narrow viewport. */\n .lh-metric__innerwrap {\n /**\n * Icon -- Metric Name -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 2fr 1fr;\n }\n .lh-metric__value {\n justify-self: end;\n grid-column-start: unset;\n }\n}\n\n/* No-JS toggle switch */\n/* Keep this selector sync'd w/ `magicSelector` in report-ui-features-test.js */\n .lh-metrics-toggle__input:checked ~ .lh-metrics-container .lh-metric__description {\n display: block;\n}\n\n/* TODO get rid of the SVGS and clean up these some more */\n.lh-metrics-toggle__input {\n opacity: 0;\n position: absolute;\n right: 0;\n top: 0px;\n}\n\n.lh-metrics-toggle__input + div > label > .lh-metrics-toggle__labeltext--hide,\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--show {\n display: none;\n}\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--hide {\n display: inline;\n}\n.lh-metrics-toggle__input:focus + div > label {\n outline: -webkit-focus-ring-color auto 3px;\n}\n\n.lh-metrics-toggle__label {\n cursor: pointer;\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n/* Pushes the metric description toggle button to the right. */\n.lh-audit-group--metrics .lh-audit-group__header {\n display: flex;\n justify-content: space-between;\n}\n\n.lh-metric__icon,\n.lh-scorescale-range::before {\n content: '';\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n display: inline-block;\n margin: var(--score-icon-margin);\n}\n\n.lh-metric--pass .lh-metric__value {\n color: var(--color-pass-secondary);\n}\n.lh-metric--pass .lh-metric__icon {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-metric--average .lh-metric__value {\n color: var(--color-average-secondary);\n}\n.lh-metric--average .lh-metric__icon {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-metric--fail .lh-metric__value {\n color: var(--color-fail-secondary);\n}\n.lh-metric--fail .lh-metric__icon {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-metric--error .lh-metric__value,\n.lh-metric--error .lh-metric__description {\n color: var(--color-fail-secondary);\n}\n\n/* Perf load opportunity */\n\n.lh-load-opportunity__cols {\n display: flex;\n align-items: flex-start;\n}\n\n.lh-load-opportunity__header .lh-load-opportunity__col {\n color: var(--color-gray-600);\n display: unset;\n line-height: calc(2.3 * var(--report-font-size));\n}\n\n.lh-load-opportunity__col {\n display: flex;\n}\n\n.lh-load-opportunity__col--one {\n flex: 5;\n align-items: center;\n margin-right: 2px;\n}\n.lh-load-opportunity__col--two {\n flex: 4;\n text-align: right;\n}\n\n.lh-audit--load-opportunity .lh-audit__display-text {\n text-align: right;\n flex: 0 0 7.5ch;\n}\n\n\n/* Sparkline */\n\n.lh-load-opportunity__sparkline {\n flex: 1;\n margin-top: calc((var(--report-line-height) - var(--sparkline-height)) / 2);\n}\n\n.lh-sparkline {\n height: var(--sparkline-height);\n width: 100%;\n}\n\n.lh-sparkline__bar {\n height: 100%;\n float: right;\n}\n\n.lh-audit--pass .lh-sparkline__bar {\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-sparkline__bar {\n background: var(--color-average);\n}\n\n.lh-audit--fail .lh-sparkline__bar {\n background: var(--color-fail);\n}\n\n/* Filmstrip */\n\n.lh-filmstrip-container {\n /* smaller gap between metrics and filmstrip */\n margin: -8px auto 0 auto;\n}\n\n.lh-filmstrip {\n display: grid;\n justify-content: space-between;\n padding-bottom: var(--default-padding);\n width: 100%;\n grid-template-columns: repeat(auto-fit, 90px);\n}\n\n.lh-filmstrip__frame {\n text-align: right;\n position: relative;\n}\n\n.lh-filmstrip__thumbnail {\n border: 1px solid var(--report-border-color-secondary);\n max-height: 150px;\n max-width: 120px;\n}\n\n/* Audit */\n\n.lh-audit {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n/* Apply border-top to just the first audit. */\n.lh-audit {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n.lh-audit ~ .lh-audit {\n border-top: none;\n}\n\n\n.lh-audit--error .lh-audit__display-text {\n color: var(--color-fail-secondary);\n}\n\n/* Audit Group */\n\n.lh-audit-group {\n margin-bottom: var(--audit-group-margin-bottom);\n position: relative;\n}\n.lh-audit-group--metrics {\n margin-bottom: calc(var(--audit-group-margin-bottom) / 2);\n}\n\n.lh-audit-group__header::before {\n /* By default, groups don't get an icon */\n content: none;\n width: var(--pwa-icon-size);\n height: var(--pwa-icon-size);\n margin: var(--pwa-icon-margin);\n display: inline-block;\n vertical-align: middle;\n}\n\n/* Style the \"over budget\" columns red. */\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(4),\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(5),\n.lh-audit-group--budgets #timing-budget tbody tr td:nth-child(3) {\n color: var(--color-red-700);\n}\n\n/* Align the \"over budget request count\" text to be close to the \"over budget bytes\" column. */\n.lh-audit-group--budgets .lh-table tbody tr td:nth-child(4){\n text-align: right;\n}\n\n.lh-audit-group--budgets .lh-details--budget {\n width: 100%;\n margin: 0 0 var(--default-padding);\n}\n\n.lh-audit-group--pwa-installable .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-installable-gray-url);\n}\n.lh-audit-group--pwa-optimized .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-optimized-gray-url);\n}\n.lh-audit-group--pwa-installable.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-installable-color-url);\n}\n.lh-audit-group--pwa-optimized.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-optimized-color-url);\n}\n\n.lh-audit-group--metrics .lh-audit-group__summary {\n margin-top: 0;\n margin-bottom: 0;\n}\n\n.lh-audit-group__summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.lh-audit-group__header .lh-chevron {\n margin-top: calc((var(--report-line-height) - 5px) / 2);\n}\n\n.lh-audit-group__header {\n letter-spacing: 0.8px;\n padding: var(--default-padding);\n padding-left: 0;\n}\n\n.lh-audit-group__header, .lh-audit-group__summary {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n.lh-audit-group__title {\n text-transform: uppercase;\n font-weight: 500;\n}\n\n.lh-audit-group__itemcount {\n color: var(--color-gray-600);\n}\n\n.lh-audit-group__footer {\n color: var(--color-gray-600);\n display: block;\n margin-top: var(--default-padding);\n}\n\n.lh-details,\n.lh-category-header__description,\n.lh-load-opportunity__header,\n.lh-audit-group__footer {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n}\n\n.lh-audit-explanation {\n margin: var(--audit-padding-vertical) 0 calc(var(--audit-padding-vertical) / 2) var(--audit-margin-horizontal);\n line-height: var(--audit-explanation-line-height);\n display: inline-block;\n}\n\n.lh-audit--fail .lh-audit-explanation {\n color: var(--color-fail-secondary);\n}\n\n/* Report */\n.lh-list > :not(:last-child) {\n margin-bottom: calc(var(--default-padding) * 2);\n}\n\n.lh-header-container {\n display: block;\n margin: 0 auto;\n position: relative;\n word-wrap: break-word;\n}\n\n.lh-header-container .lh-scores-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n\n\n.lh-report {\n min-width: var(--report-content-min-width);\n}\n\n.lh-exception {\n font-size: large;\n}\n\n.lh-code {\n white-space: normal;\n margin-top: 0;\n font-size: var(--report-monospace-font-size);\n}\n\n.lh-warnings {\n --item-margin: calc(var(--report-line-height) / 6);\n color: var(--color-average-secondary);\n margin: var(--audit-padding-vertical) 0;\n padding: var(--default-padding)\n var(--default-padding)\n var(--default-padding)\n calc(var(--audit-description-padding-left));\n background-color: var(--toplevel-warning-background-color);\n}\n.lh-warnings span {\n font-weight: bold;\n}\n\n.lh-warnings--toplevel {\n --item-margin: calc(var(--header-line-height) / 4);\n color: var(--toplevel-warning-text-color);\n margin-left: auto;\n margin-right: auto;\n max-width: var(--report-content-max-width-minus-edge-gap);\n padding: var(--toplevel-warning-padding);\n border-radius: 8px;\n}\n\n.lh-warnings__msg {\n color: var(--toplevel-warning-message-text-color);\n margin: 0;\n}\n\n.lh-warnings ul {\n margin: 0;\n}\n.lh-warnings li {\n margin: var(--item-margin) 0;\n}\n.lh-warnings li:last-of-type {\n margin-bottom: 0;\n}\n\n.lh-scores-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n}\n.lh-scores-header__solo {\n padding: 0;\n border: 0;\n}\n\n/* Gauge */\n\n.lh-gauge__wrapper--pass {\n color: var(--color-pass-secondary);\n fill: var(--color-pass);\n stroke: var(--color-pass);\n}\n\n.lh-gauge__wrapper--average {\n color: var(--color-average-secondary);\n fill: var(--color-average);\n stroke: var(--color-average);\n}\n\n.lh-gauge__wrapper--fail {\n color: var(--color-fail-secondary);\n fill: var(--color-fail);\n stroke: var(--color-fail);\n}\n\n.lh-gauge__wrapper--not-applicable {\n color: var(--color-not-applicable);\n fill: var(--color-not-applicable);\n stroke: var(--color-not-applicable);\n}\n\n.lh-fraction__wrapper .lh-fraction__content::before {\n content: '';\n height: var(--score-icon-size);\n width: var(--score-icon-size);\n margin: var(--score-icon-margin);\n display: inline-block;\n}\n.lh-fraction__wrapper--pass .lh-fraction__content {\n color: var(--color-pass-secondary);\n}\n.lh-fraction__wrapper--pass .lh-fraction__background {\n background-color: var(--color-pass);\n}\n.lh-fraction__wrapper--pass .lh-fraction__content::before {\n background-color: var(--color-pass);\n border-radius: 50%;\n}\n.lh-fraction__wrapper--average .lh-fraction__content {\n color: var(--color-average-secondary);\n}\n.lh-fraction__wrapper--average .lh-fraction__background,\n.lh-fraction__wrapper--average .lh-fraction__content::before {\n background-color: var(--color-average);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content {\n color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__background {\n background-color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n.lh-fraction__wrapper--null .lh-fraction__content {\n color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__background {\n background-color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__content::before {\n border-radius: 50%;\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-700);\n}\n\n.lh-fraction__background {\n position: absolute;\n height: 100%;\n width: 100%;\n border-radius: calc(var(--gauge-circle-size) / 2);\n opacity: 0.1;\n z-index: -1;\n}\n\n.lh-fraction__content-wrapper {\n height: var(--gauge-circle-size);\n display: flex;\n align-items: center;\n}\n\n.lh-fraction__content {\n display: flex;\n position: relative;\n align-items: center;\n justify-content: center;\n font-size: calc(0.3 * var(--gauge-circle-size));\n line-height: calc(0.4 * var(--gauge-circle-size));\n width: max-content;\n min-width: calc(1.5 * var(--gauge-circle-size));\n padding: calc(0.1 * var(--gauge-circle-size)) calc(0.2 * var(--gauge-circle-size));\n --score-icon-size: calc(0.21 * var(--gauge-circle-size));\n --score-icon-margin: 0 calc(0.15 * var(--gauge-circle-size)) 0 0;\n}\n\n.lh-gauge {\n stroke-linecap: round;\n width: var(--gauge-circle-size);\n height: var(--gauge-circle-size);\n}\n\n.lh-category .lh-gauge {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n.lh-gauge-base {\n opacity: 0.1;\n}\n\n.lh-gauge-arc {\n fill: none;\n transform-origin: 50% 50%;\n animation: load-gauge var(--transition-length) ease both;\n animation-delay: 250ms;\n}\n\n.lh-gauge__svg-wrapper {\n position: relative;\n height: var(--gauge-circle-size);\n}\n.lh-category .lh-gauge__svg-wrapper,\n.lh-category .lh-fraction__wrapper {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n/* The plugin badge overlay */\n.lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size);\n height: var(--plugin-badge-size);\n background-color: var(--plugin-badge-background-color);\n background-image: var(--plugin-icon-url);\n background-repeat: no-repeat;\n background-size: var(--plugin-icon-size);\n background-position: 58% 50%;\n content: \"\";\n position: absolute;\n right: -6px;\n bottom: 0px;\n display: block;\n z-index: 100;\n box-shadow: 0 0 4px rgba(0,0,0,.2);\n border-radius: 25%;\n}\n.lh-category .lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size-big);\n height: var(--plugin-badge-size-big);\n}\n\n@keyframes load-gauge {\n from { stroke-dasharray: 0 352; }\n}\n\n.lh-gauge__percentage {\n width: 100%;\n height: var(--gauge-circle-size);\n position: absolute;\n font-family: var(--report-font-family-monospace);\n font-size: calc(var(--gauge-circle-size) * 0.34 + 1.3px);\n line-height: 0;\n text-align: center;\n top: calc(var(--score-container-padding) + var(--gauge-circle-size) / 2);\n}\n\n.lh-category .lh-gauge__percentage {\n --gauge-circle-size: var(--gauge-circle-size-big);\n --gauge-percentage-font-size: var(--gauge-percentage-font-size-big);\n}\n\n.lh-gauge__wrapper,\n.lh-fraction__wrapper {\n position: relative;\n display: flex;\n align-items: center;\n flex-direction: column;\n text-decoration: none;\n padding: var(--score-container-padding);\n\n --transition-length: 1s;\n\n /* Contain the layout style paint & layers during animation*/\n contain: content;\n will-change: opacity; /* Only using for layer promotion */\n}\n\n.lh-gauge__label,\n.lh-fraction__label {\n font-size: var(--gauge-label-font-size);\n font-weight: 500;\n line-height: var(--gauge-label-line-height);\n margin-top: 10px;\n text-align: center;\n color: var(--report-text-color);\n word-break: keep-all;\n}\n\n/* TODO(#8185) use more BEM (.lh-gauge__label--big) instead of relying on descendant selector */\n.lh-category .lh-gauge__label,\n.lh-category .lh-fraction__label {\n --gauge-label-font-size: var(--gauge-label-font-size-big);\n --gauge-label-line-height: var(--gauge-label-line-height-big);\n margin-top: 14px;\n}\n\n.lh-scores-header .lh-gauge__wrapper,\n.lh-scores-header .lh-fraction__wrapper,\n.lh-scores-header .lh-gauge--pwa__wrapper,\n.lh-sticky-header .lh-gauge__wrapper,\n.lh-sticky-header .lh-fraction__wrapper,\n.lh-sticky-header .lh-gauge--pwa__wrapper {\n width: var(--gauge-wrapper-width);\n}\n\n.lh-scorescale {\n display: inline-flex;\n\n gap: calc(var(--default-padding) * 4);\n margin: 16px auto 0 auto;\n font-size: var(--report-font-size-secondary);\n color: var(--color-gray-700);\n\n}\n\n.lh-scorescale-range {\n display: flex;\n align-items: center;\n font-family: var(--report-font-family-monospace);\n white-space: nowrap;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale {\n border: 0;\n display: flex;\n justify-content: center;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale-range {\n font-family: unset;\n font-size: 12px;\n}\n\n.lh-scorescale-wrap {\n display: contents;\n}\n\n/* Hide category score gauages if it's a single category report */\n.lh-header--solo-category .lh-scores-wrapper {\n display: none;\n}\n\n\n.lh-categories {\n width: 100%;\n}\n\n.lh-category {\n padding: var(--category-padding);\n max-width: var(--report-content-max-width);\n margin: 0 auto;\n\n scroll-margin-top: var(--sticky-header-buffer);\n}\n\n.lh-category-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n.lh-category-wrapper:last-of-type {\n border-bottom: 0;\n}\n\n.lh-category-header {\n margin-bottom: var(--section-padding-vertical);\n}\n\n.lh-category-header .lh-score__gauge {\n max-width: 400px;\n width: auto;\n margin: 0px auto;\n}\n\n.lh-category-header__finalscreenshot {\n display: grid;\n grid-template: none / 1fr 1px 1fr;\n justify-items: center;\n align-items: center;\n gap: var(--report-line-height);\n min-height: 288px;\n margin-bottom: var(--default-padding);\n}\n\n.lh-final-ss-image {\n /* constrain the size of the image to not be too large */\n max-height: calc(var(--gauge-circle-size-big) * 2.8);\n max-width: calc(var(--gauge-circle-size-big) * 3.5);\n border: 1px solid var(--color-gray-200);\n padding: 4px;\n border-radius: 3px;\n display: block;\n}\n\n.lh-category-headercol--separator {\n background: var(--color-gray-200);\n width: 1px;\n height: var(--gauge-circle-size-big);\n}\n\n@media screen and (max-width: 780px) {\n .lh-category-header__finalscreenshot {\n grid-template: 1fr 1fr / none\n }\n .lh-category-headercol--separator {\n display: none;\n }\n}\n\n\n/* 964 fits the min-width of the filmstrip */\n@media screen and (max-width: 964px) {\n .lh-report {\n margin-left: 0;\n width: 100%;\n }\n}\n\n@media print {\n body {\n -webkit-print-color-adjust: exact; /* print background colors */\n }\n .lh-container {\n display: block;\n }\n .lh-report {\n margin-left: 0;\n padding-top: 0;\n }\n .lh-categories {\n margin-top: 0;\n }\n}\n\n.lh-table {\n position: relative;\n border-collapse: separate;\n border-spacing: 0;\n /* Can't assign padding to table, so shorten the width instead. */\n width: calc(100% - var(--audit-description-padding-left) - var(--stackpack-padding-horizontal));\n border: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-table thead th {\n position: sticky;\n top: calc(var(--sticky-header-buffer) + 1em);\n z-index: 1;\n background-color: var(--report-background-color);\n border-bottom: 1px solid var(--report-border-color-secondary);\n font-weight: normal;\n color: var(--color-gray-600);\n /* See text-wrapping comment on .lh-container. */\n word-break: normal;\n}\n\n.lh-row--group {\n background-color: var(--table-group-header-background-color);\n}\n\n.lh-row--group td {\n font-weight: bold;\n font-size: 1.05em;\n color: var(--table-group-header-text-color);\n}\n\n.lh-row--group td:first-child {\n font-weight: normal;\n}\n\n.lh-row--group .lh-text {\n color: inherit;\n text-decoration: none;\n display: inline-block;\n}\n\n.lh-row--group a.lh-link:hover {\n text-decoration: underline;\n}\n\n.lh-row--group .lh-audit__adorn {\n text-transform: capitalize;\n font-weight: normal;\n padding: 2px 3px 1px 3px;\n}\n\n.lh-row--group .lh-audit__adorn1p {\n color: var(--link-color);\n border-color: var(--link-color);\n}\n\n.lh-row--group .lh-report-icon--external::before {\n content: \"\";\n background-repeat: no-repeat;\n width: 14px;\n height: 16px;\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n\n.lh-row--group .lh-report-icon--external {\n display: none;\n}\n\n.lh-row--group:hover .lh-report-icon--external {\n display: inline-block;\n}\n\n.lh-dark .lh-report-icon--external::before {\n filter: invert(1);\n}\n\n/** Manages indentation of two-level and three-level nested adjacent rows */\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) td:first-child {\n padding-left: 20px;\n}\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) ~ .lh-sub-item-row td:first-child {\n padding-left: 40px;\n}\n\n.lh-row--even {\n background-color: var(--table-group-header-background-color);\n}\n.lh-row--hidden {\n display: none;\n}\n\n.lh-table th,\n.lh-table td {\n padding: var(--default-padding);\n}\n\n.lh-table tr {\n vertical-align: middle;\n}\n\n.lh-table tr:hover {\n background-color: var(--table-higlight-background-color);\n}\n\n/* Looks unnecessary, but mostly for keeping the s left-aligned */\n.lh-table-column--text,\n.lh-table-column--source-location,\n.lh-table-column--url,\n/* .lh-table-column--thumbnail, */\n/* .lh-table-column--empty,*/\n.lh-table-column--code,\n.lh-table-column--node {\n text-align: left;\n}\n\n.lh-table-column--code {\n min-width: 100px;\n}\n\n.lh-table-column--bytes,\n.lh-table-column--timespanMs,\n.lh-table-column--ms,\n.lh-table-column--numeric {\n text-align: right;\n word-break: normal;\n}\n\n\n\n.lh-table .lh-table-column--thumbnail {\n width: var(--image-preview-size);\n}\n\n.lh-table-column--url {\n min-width: 250px;\n}\n\n.lh-table-column--text {\n min-width: 80px;\n}\n\n/* Keep columns narrow if they follow the URL column */\n/* 12% was determined to be a decent narrow width, but wide enough for column headings */\n.lh-table-column--url + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--ms,\n.lh-table-column--url + .lh-table-column--ms + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--timespanMs {\n width: 12%;\n}\n\n.lh-text__url-host {\n display: inline;\n}\n\n.lh-text__url-host {\n margin-left: calc(var(--report-font-size) / 2);\n opacity: 0.6;\n font-size: 90%\n}\n\n.lh-thumbnail {\n object-fit: cover;\n width: var(--image-preview-size);\n height: var(--image-preview-size);\n display: block;\n}\n\n.lh-unknown pre {\n overflow: scroll;\n border: solid 1px var(--color-gray-200);\n}\n\n.lh-text__url > a {\n color: inherit;\n text-decoration: none;\n}\n\n.lh-text__url > a:hover {\n text-decoration: underline dotted #999;\n}\n\n.lh-sub-item-row {\n margin-left: 20px;\n margin-bottom: 0;\n color: var(--color-gray-700);\n}\n\n.lh-sub-item-row td {\n padding-top: 4px;\n padding-bottom: 4px;\n padding-left: 20px;\n}\n\n/* Chevron\n https://codepen.io/paulirish/pen/LmzEmK\n */\n.lh-chevron {\n --chevron-angle: 42deg;\n /* Edge doesn't support transform: rotate(calc(...)), so we define it here */\n --chevron-angle-right: -42deg;\n width: var(--chevron-size);\n height: var(--chevron-size);\n margin-top: calc((var(--report-line-height) - 12px) / 2);\n}\n\n.lh-chevron__lines {\n transition: transform 0.4s;\n transform: translateY(var(--report-line-height));\n}\n.lh-chevron__line {\n stroke: var(--chevron-line-stroke);\n stroke-width: var(--chevron-size);\n stroke-linecap: square;\n transform-origin: 50%;\n transform: rotate(var(--chevron-angle));\n transition: transform 300ms, stroke 300ms;\n}\n\n.lh-expandable-details .lh-chevron__line-right,\n.lh-expandable-details[open] .lh-chevron__line-left {\n transform: rotate(var(--chevron-angle-right));\n}\n\n.lh-expandable-details[open] .lh-chevron__line-right {\n transform: rotate(var(--chevron-angle));\n}\n\n\n.lh-expandable-details[open] .lh-chevron__lines {\n transform: translateY(calc(var(--chevron-size) * -1));\n}\n\n.lh-expandable-details[open] {\n animation: 300ms openDetails forwards;\n padding-bottom: var(--default-padding);\n}\n\n@keyframes openDetails {\n from {\n outline: 1px solid var(--report-background-color);\n }\n to {\n outline: 1px solid;\n box-shadow: 0 2px 4px rgba(0, 0, 0, .24);\n }\n}\n\n@media screen and (max-width: 780px) {\n /* no black outline if we're not confident the entire table can be displayed within bounds */\n .lh-expandable-details[open] {\n animation: none;\n }\n}\n\n.lh-expandable-details[open] summary, details.lh-clump > summary {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\ndetails.lh-clump[open] > summary {\n border-bottom-width: 0;\n}\n\n\n\ndetails .lh-clump-toggletext--hide,\ndetails[open] .lh-clump-toggletext--show { display: none; }\ndetails[open] .lh-clump-toggletext--hide { display: block;}\n\n\n/* Tooltip */\n.lh-tooltip-boundary {\n position: relative;\n}\n\n.lh-tooltip {\n position: absolute;\n display: none; /* Don't retain these layers when not needed */\n opacity: 0;\n background: #ffffff;\n white-space: pre-line; /* Render newlines in the text */\n min-width: 246px;\n max-width: 275px;\n padding: 15px;\n border-radius: 5px;\n text-align: initial;\n line-height: 1.4;\n}\n/* shrink tooltips to not be cutoff on left edge of narrow viewports\n 45vw is chosen to be ~= width of the left column of metrics\n*/\n@media screen and (max-width: 535px) {\n .lh-tooltip {\n min-width: 45vw;\n padding: 3vw;\n }\n}\n\n.lh-tooltip-boundary:hover .lh-tooltip {\n display: block;\n animation: fadeInTooltip 250ms;\n animation-fill-mode: forwards;\n animation-delay: 850ms;\n bottom: 100%;\n z-index: 1;\n will-change: opacity;\n right: 0;\n pointer-events: none;\n}\n\n.lh-tooltip::before {\n content: \"\";\n border: solid transparent;\n border-bottom-color: #fff;\n border-width: 10px;\n position: absolute;\n bottom: -20px;\n right: 6px;\n transform: rotate(180deg);\n pointer-events: none;\n}\n\n@keyframes fadeInTooltip {\n 0% { opacity: 0; }\n 75% { opacity: 1; }\n 100% { opacity: 1; filter: drop-shadow(1px 0px 1px #aaa) drop-shadow(0px 2px 4px hsla(206, 6%, 25%, 0.15)); pointer-events: auto; }\n}\n\n/* Element screenshot */\n.lh-element-screenshot {\n float: left;\n margin-right: 20px;\n}\n.lh-element-screenshot__content {\n overflow: hidden;\n min-width: 110px;\n display: flex;\n justify-content: center;\n background-color: var(--report-background-color);\n}\n.lh-element-screenshot__image {\n position: relative;\n /* Set by ElementScreenshotRenderer.installFullPageScreenshotCssVariable */\n background-image: var(--element-screenshot-url);\n outline: 2px solid #777;\n background-color: white;\n background-repeat: no-repeat;\n}\n.lh-element-screenshot__mask {\n position: absolute;\n background: #555;\n opacity: 0.8;\n}\n.lh-element-screenshot__element-marker {\n position: absolute;\n outline: 2px solid var(--color-lime-400);\n}\n.lh-element-screenshot__overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 2000; /* .lh-topbar is 1000 */\n background: var(--screenshot-overlay-background);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: zoom-out;\n}\n\n.lh-element-screenshot__overlay .lh-element-screenshot {\n margin-right: 0; /* clearing margin used in thumbnail case */\n outline: 1px solid var(--color-gray-700);\n}\n\n.lh-screenshot-overlay--enabled .lh-element-screenshot {\n cursor: zoom-out;\n}\n.lh-screenshot-overlay--enabled .lh-node .lh-element-screenshot {\n cursor: zoom-in;\n}\n\n\n.lh-meta__items {\n --meta-icon-size: calc(var(--report-icon-size) * 0.667);\n padding: var(--default-padding);\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n background-color: var(--env-item-background-color);\n border-radius: 3px;\n margin: 0 0 var(--default-padding) 0;\n font-size: 12px;\n column-gap: var(--default-padding);\n color: var(--color-gray-700);\n}\n\n.lh-meta__item {\n display: block;\n list-style-type: none;\n position: relative;\n padding: 0 0 0 calc(var(--meta-icon-size) + var(--default-padding) * 2);\n cursor: unset; /* disable pointer cursor from report-icon */\n}\n\n.lh-meta__item.lh-tooltip-boundary {\n text-decoration: dotted underline var(--color-gray-500);\n cursor: help;\n}\n\n.lh-meta__item.lh-report-icon::before {\n position: absolute;\n left: var(--default-padding);\n width: var(--meta-icon-size);\n height: var(--meta-icon-size);\n}\n\n.lh-meta__item.lh-report-icon:hover::before {\n opacity: 0.7;\n}\n\n.lh-meta__item .lh-tooltip {\n color: var(--color-gray-800);\n}\n\n.lh-meta__item .lh-tooltip::before {\n right: auto; /* Set the tooltip arrow to the leftside */\n left: 6px;\n}\n\n/* Change the grid for narrow viewport. */\n@media screen and (max-width: 640px) {\n .lh-meta__items {\n grid-template-columns: 1fr 1fr;\n }\n}\n@media screen and (max-width: 535px) {\n .lh-meta__items {\n display: block;\n }\n}\n\n\n/*# sourceURL=report-styles.css */\n"); el0.append(el1); return el0; } diff --git a/report/renderer/performance-category-renderer.js b/report/renderer/performance-category-renderer.js index 73453cc59912..0701d56402c0 100644 --- a/report/renderer/performance-category-renderer.js +++ b/report/renderer/performance-category-renderer.js @@ -334,12 +334,12 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { overallLinearImpact: bOverallLinearImpact, } = this.overallImpact(b, metricAudits); - if (a.id === 'unsized-images') { - console.log('######'); - console.log(aOverallImpact, aOverallLinearImpact); - console.log(bOverallImpact, bOverallLinearImpact); - console.log(aOverallImpact === bOverallImpact, bOverallLinearImpact); - } + // if (a.id === 'unsized-images') { + // console.log('######'); + // console.log(aOverallImpact, aOverallLinearImpact); + // console.log(bOverallImpact, bOverallLinearImpact); + // console.log(aOverallImpact === bOverallImpact, bOverallLinearImpact); + // } if (aOverallImpact !== bOverallImpact) return bOverallImpact - aOverallImpact; if ( aOverallImpact === 0 && bOverallImpact === 0 && From e1ebbb8d982ee82401e42d9f1cd8ffcc1b107d6d Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Thu, 31 Aug 2023 15:27:18 -0700 Subject: [PATCH 05/31] add simple guidance level sort --- core/audits/audit.js | 1 + report/assets/styles.css | 15 ++++++----- report/renderer/components.js | 2 +- .../renderer/performance-category-renderer.js | 25 ++++++++++++++++--- types/lhr/audit-result.d.ts | 1 + 5 files changed, 34 insertions(+), 10 deletions(-) diff --git a/core/audits/audit.js b/core/audits/audit.js index 5550805af8fe..62dcaa314a57 100644 --- a/core/audits/audit.js +++ b/core/audits/audit.js @@ -407,6 +407,7 @@ class Audit { metricSavings: product.metricSavings, details: product.details, + guidanceLevel: audit.meta.guidanceLevel, }; } diff --git a/report/assets/styles.css b/report/assets/styles.css index 1d4fbf4743a6..4011c628877a 100644 --- a/report/assets/styles.css +++ b/report/assets/styles.css @@ -526,9 +526,10 @@ /* Score */ -.lh-audit__score-icon { +/* to remove color indicators - test */ +/* .lh-audit__score-icon { opacity: 0; -} +} */ .lh-audit__score-icon { width: var(--score-icon-size); @@ -546,8 +547,9 @@ } .lh-audit--average .lh-audit__display-text { - /* color: var(--color-average-secondary); */ - color: gray; + color: var(--color-average-secondary); + /* to remove color indicators - test */ + /* color: gray; */ } .lh-audit--average .lh-audit__score-icon, .lh-scorescale-range--average::before { @@ -557,8 +559,9 @@ } .lh-audit--fail .lh-audit__display-text { - /* color: var(--color-fail-secondary); */ - color: gray; + color: var(--color-fail-secondary); + /* to remove color indicators - test */ + /* color: gray; */ } .lh-audit--fail .lh-audit__score-icon, .lh-audit--error .lh-audit__score-icon, diff --git a/report/renderer/components.js b/report/renderer/components.js index 53dbe6645da8..9d6e7662b262 100644 --- a/report/renderer/components.js +++ b/report/renderer/components.js @@ -520,7 +520,7 @@ function createSnippetLineComponent(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 --report-icon-size: var(--score-icon-background-size);\n --report-line-height: 24px;\n --report-line-height-secondary: 20px;\n --report-monospace-font-size: calc(var(--report-font-size) * 0.85);\n --report-text-color-secondary: var(--color-gray-800);\n --report-text-color: var(--color-gray-900);\n --report-content-max-width: calc(60 * var(--report-font-size)); /* defaults to 840px */\n --report-content-min-width: 360px;\n --report-content-max-width-minus-edge-gap: calc(var(--report-content-max-width) - var(--edge-gap-padding) * 2);\n --score-container-padding: 8px;\n --score-icon-background-size: 24px;\n --score-icon-margin-left: 6px;\n --score-icon-margin-right: 14px;\n --score-icon-margin: 0 var(--score-icon-margin-right) 0 var(--score-icon-margin-left);\n --score-icon-size: 12px;\n --score-icon-size-big: 16px;\n --screenshot-overlay-background: rgba(0, 0, 0, 0.3);\n --section-padding-vertical: calc(var(--default-padding) * 6);\n --snippet-background-color: var(--color-gray-50);\n --snippet-color: #0938C2;\n --sparkline-height: 5px;\n --stackpack-padding-horizontal: 10px;\n --sticky-header-background-color: var(--report-background-color);\n --sticky-header-buffer: calc(var(--topbar-height) + var(--sticky-header-height));\n --sticky-header-height: calc(var(--gauge-circle-size-sm) + var(--score-container-padding) * 2);\n --table-group-header-background-color: #EEF1F4;\n --table-group-header-text-color: var(--color-gray-700);\n --table-higlight-background-color: #F5F7FA;\n --tools-icon-color: var(--color-gray-600);\n --topbar-background-color: var(--color-white);\n --topbar-height: 32px;\n --topbar-logo-size: 24px;\n --topbar-padding: 0 8px;\n --toplevel-warning-background-color: hsla(30, 100%, 75%, 10%);\n --toplevel-warning-message-text-color: var(--color-average-secondary);\n --toplevel-warning-padding: 18px;\n --toplevel-warning-text-color: var(--report-text-color);\n\n /* SVGs */\n --plugin-icon-url-dark: url('data:image/svg+xml;utf8,');\n --plugin-icon-url: url('data:image/svg+xml;utf8,');\n\n --pass-icon-url: url('data:image/svg+xml;utf8,check');\n --average-icon-url: url('data:image/svg+xml;utf8,info');\n --fail-icon-url: url('data:image/svg+xml;utf8,warn');\n --error-icon-url: url('data:image/svg+xml;utf8,error');\n\n --pwa-installable-gray-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-gray-url-dark: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url-dark: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-color-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-color-url: url('data:image/svg+xml;utf8,');\n\n --swap-locale-icon-url: url('data:image/svg+xml;utf8,');\n}\n\n@media not print {\n .lh-dark {\n /* Pallete */\n --color-gray-200: var(--color-gray-800);\n --color-gray-300: #616161;\n --color-gray-400: var(--color-gray-600);\n --color-gray-700: var(--color-gray-400);\n --color-gray-50: #757575;\n --color-gray-600: var(--color-gray-500);\n --color-green-700: var(--color-green);\n --color-orange-700: var(--color-orange);\n --color-red-700: var(--color-red);\n --color-teal-600: var(--color-cyan-500);\n\n /* Context-specific colors */\n --color-hover: rgba(0, 0, 0, 0.2);\n --color-informative: var(--color-blue-200);\n\n /* Component variables */\n --env-item-background-color: #393535;\n --link-color: var(--color-blue-200);\n --locale-selector-background-color: var(--color-gray-200);\n --plugin-badge-background-color: var(--color-gray-800);\n --report-background-color: var(--color-gray-900);\n --report-border-color-secondary: var(--color-gray-200);\n --report-text-color-secondary: var(--color-gray-400);\n --report-text-color: var(--color-gray-100);\n --snippet-color: var(--color-cyan-500);\n --topbar-background-color: var(--color-gray);\n --toplevel-warning-background-color: hsl(33deg 14% 18%);\n --toplevel-warning-message-text-color: var(--color-orange-700);\n --toplevel-warning-text-color: var(--color-gray-100);\n --table-group-header-background-color: rgba(186, 196, 206, 0.15);\n --table-group-header-text-color: var(--color-gray-100);\n --table-higlight-background-color: rgba(186, 196, 206, 0.09);\n\n /* SVGs */\n --plugin-icon-url: var(--plugin-icon-url-dark);\n --pwa-installable-gray-url: var(--pwa-installable-gray-url-dark);\n --pwa-optimized-gray-url: var(--pwa-optimized-gray-url-dark);\n }\n}\n\n@media only screen and (max-width: 480px) {\n .lh-vars {\n --audit-group-margin-bottom: 20px;\n --edge-gap-padding: var(--default-padding);\n --env-name-min-width: 120px;\n --gauge-circle-size-big: 96px;\n --gauge-circle-size: 72px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 112px;\n --header-padding: 16px 0 16px 0;\n --image-preview-size: 24px;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-size: 14px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --topbar-height: 28px;\n --topbar-logo-size: 20px;\n }\n\n /* Not enough space to adequately show the relative savings bars. */\n .lh-sparkline {\n display: none;\n }\n}\n\n.lh-vars.lh-devtools {\n --audit-explanation-line-height: 14px;\n --audit-group-margin-bottom: 20px;\n --audit-group-padding-vertical: 12px;\n --audit-padding-vertical: 4px;\n --category-padding: 12px;\n --default-padding: 12px;\n --env-name-min-width: 120px;\n --footer-padding-vertical: 8px;\n --gauge-circle-size-big: 72px;\n --gauge-circle-size: 64px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 97px;\n --header-line-height: 20px;\n --header-padding: 16px 0 16px 0;\n --screenshot-overlay-background: transparent;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-family-monospace: 'Menlo', 'dejavu sans mono', 'Consolas', 'Lucida Console', monospace;\n --report-font-family: '.SFNSDisplay-Regular', 'Helvetica Neue', 'Lucida Grande', sans-serif;\n --report-font-size: 12px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --section-padding-vertical: 8px;\n}\n\n.lh-container:not(.lh-topbar + .lh-container) {\n --topbar-height: 0;\n --sticky-header-height: 0;\n --sticky-header-buffer: 0;\n}\n\n.lh-devtools.lh-root {\n height: 100%;\n}\n.lh-devtools.lh-root img {\n /* Override devtools default 'min-width: 0' so svg without size in a flexbox isn't collapsed. */\n min-width: auto;\n}\n.lh-devtools .lh-container {\n overflow-y: scroll;\n height: calc(100% - var(--topbar-height));\n /** The .lh-container is the scroll parent in DevTools so we exclude the topbar from the sticky header buffer. */\n --sticky-header-buffer: calc(var(--sticky-header-height));\n}\n@media print {\n .lh-devtools .lh-container {\n overflow: unset;\n }\n}\n.lh-devtools .lh-sticky-header {\n /* This is normally the height of the topbar, but we want it to stick to the top of our scroll container .lh-container` */\n top: 0;\n}\n.lh-devtools .lh-element-screenshot__overlay {\n position: absolute;\n}\n\n@keyframes fadeIn {\n 0% { opacity: 0;}\n 100% { opacity: 0.6;}\n}\n\n.lh-root *, .lh-root *::before, .lh-root *::after {\n box-sizing: border-box;\n}\n\n.lh-root {\n font-family: var(--report-font-family);\n font-size: var(--report-font-size);\n margin: 0;\n line-height: var(--report-line-height);\n background: var(--report-background-color);\n color: var(--report-text-color);\n}\n\n.lh-root :focus-visible {\n outline: -webkit-focus-ring-color auto 3px;\n}\n.lh-root summary:focus {\n outline: none;\n box-shadow: 0 0 0 1px hsl(217, 89%, 61%);\n}\n\n.lh-root [hidden] {\n display: none !important;\n}\n\n.lh-root pre {\n margin: 0;\n}\n\n.lh-root pre,\n.lh-root code {\n font-family: var(--report-font-family-monospace);\n}\n\n.lh-root details > summary {\n cursor: pointer;\n}\n\n.lh-hidden {\n display: none !important;\n}\n\n.lh-container {\n /*\n Text wrapping in the report is so much FUN!\n We have a `word-break: break-word;` globally here to prevent a few common scenarios, namely\n long non-breakable text (usually URLs) found in:\n 1. The footer\n 2. .lh-node (outerHTML)\n 3. .lh-code\n\n With that sorted, the next challenge is appropriate column sizing and text wrapping inside our\n .lh-details tables. Even more fun.\n * We don't want table headers (\"Potential Savings (ms)\") to wrap or their column values, but\n we'd be happy for the URL column to wrap if the URLs are particularly long.\n * We want the narrow columns to remain narrow, providing the most column width for URL\n * We don't want the table to extend past 100% width.\n * Long URLs in the URL column can wrap. Util.getURLDisplayName maxes them out at 64 characters,\n but they do not get any overflow:ellipsis treatment.\n */\n word-break: break-word;\n}\n\n.lh-audit-group a,\n.lh-category-header__description a,\n.lh-audit__description a,\n.lh-warnings a,\n.lh-footer a,\n.lh-table-column--link a {\n color: var(--link-color);\n}\n\n.lh-audit__description, .lh-audit__stackpack {\n --inner-audit-padding-right: var(--stackpack-padding-horizontal);\n padding-left: var(--audit-description-padding-left);\n padding-right: var(--inner-audit-padding-right);\n padding-top: 8px;\n padding-bottom: 8px;\n}\n\n.lh-details {\n margin-top: var(--default-padding);\n margin-bottom: var(--default-padding);\n margin-left: var(--audit-description-padding-left);\n /* whatever the .lh-details side margins are */\n width: 100%;\n}\n\n.lh-audit__stackpack {\n display: flex;\n align-items: center;\n}\n\n.lh-audit__stackpack__img {\n max-width: 30px;\n margin-right: var(--default-padding)\n}\n\n/* Report header */\n\n.lh-report-icon {\n display: flex;\n align-items: center;\n padding: 10px 12px;\n cursor: pointer;\n}\n.lh-report-icon[disabled] {\n opacity: 0.3;\n pointer-events: none;\n}\n\n.lh-report-icon::before {\n content: \"\";\n margin: 4px;\n background-repeat: no-repeat;\n width: var(--report-icon-size);\n height: var(--report-icon-size);\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n.lh-report-icon:hover::before {\n opacity: 1;\n}\n.lh-dark .lh-report-icon::before {\n filter: invert(1);\n}\n.lh-report-icon--print::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--copy::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--open::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--download::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--dark::before {\n background-image:url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--treemap::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--date::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--devices::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--world::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--stopwatch::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--networkspeed::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-one::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-many::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--chrome::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--external::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n\n.lh-buttons {\n display: flex;\n flex-wrap: wrap;\n margin: var(--default-padding) 0;\n}\n.lh-button {\n height: 32px;\n border: 1px solid var(--report-border-color-secondary);\n border-radius: 3px;\n color: var(--link-color);\n background-color: var(--report-background-color);\n margin: 5px;\n}\n\n.lh-button:first-of-type {\n margin-left: 0;\n}\n\n/* Node */\n.lh-node__snippet {\n font-family: var(--report-font-family-monospace);\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n line-height: 20px;\n}\n\n/* Score */\n\n.lh-audit__score-icon {\n opacity: 0;\n}\n\n.lh-audit__score-icon {\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n margin: var(--score-icon-margin);\n}\n\n.lh-audit--pass .lh-audit__display-text {\n color: var(--color-pass-secondary);\n}\n.lh-audit--pass .lh-audit__score-icon,\n.lh-scorescale-range--pass::before {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-audit__display-text {\n /* color: var(--color-average-secondary); */\n color: gray;\n}\n.lh-audit--average .lh-audit__score-icon,\n.lh-scorescale-range--average::before {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-audit--fail .lh-audit__display-text {\n /* color: var(--color-fail-secondary); */\n color: gray;\n}\n.lh-audit--fail .lh-audit__score-icon,\n.lh-audit--error .lh-audit__score-icon,\n.lh-scorescale-range--fail::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-audit--error .lh-audit__score-icon,\n.lh-metric--error .lh-metric__icon {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n border: none;\n}\n\n.lh-gauge__wrapper--fail .lh-gauge--error {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n transform: scale(0.5);\n top: var(--score-container-padding);\n}\n\n.lh-audit--manual .lh-audit__display-text,\n.lh-audit--notapplicable .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n.lh-audit--manual .lh-audit__score-icon,\n.lh-audit--notapplicable .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n background: none;\n}\n\n.lh-audit--informative .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n\n.lh-audit--informative .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n}\n\n.lh-audit__description,\n.lh-audit__stackpack {\n color: var(--report-text-color-secondary);\n}\n.lh-audit__adorn {\n border: 1px solid var(--color-gray-500);\n border-radius: 3px;\n margin: 0 3px;\n padding: 0 2px;\n line-height: 1.1;\n display: inline-block;\n font-size: 90%;\n color: var(--report-text-color-secondary);\n}\n\n.lh-category-header__description {\n text-align: center;\n color: var(--color-gray-700);\n margin: 0px auto;\n max-width: 400px;\n}\n\n\n.lh-audit__display-text,\n.lh-load-opportunity__sparkline,\n.lh-chevron-container {\n margin: 0 var(--audit-margin-horizontal);\n}\n.lh-chevron-container {\n margin-right: 0;\n}\n\n.lh-audit__title-and-text {\n flex: 1;\n}\n\n.lh-audit__title-and-text code {\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n}\n\n/* Prepend display text with em dash separator. But not in Opportunities. */\n.lh-audit__display-text:not(:empty):before {\n content: '—';\n margin-right: var(--audit-margin-horizontal);\n}\n.lh-audit-group.lh-audit-group--load-opportunities .lh-audit__display-text:not(:empty):before {\n display: none;\n}\n\n/* Expandable Details (Audit Groups, Audits) */\n.lh-audit__header {\n display: flex;\n align-items: center;\n padding: var(--default-padding);\n}\n\n.lh-audit--load-opportunity .lh-audit__header {\n display: block;\n}\n\n\n.lh-metricfilter {\n display: grid;\n justify-content: end;\n align-items: center;\n grid-auto-flow: column;\n gap: 4px;\n color: var(--color-gray-700);\n}\n\n.lh-metricfilter__radio {\n /*\n * Instead of hiding, position offscreen so it's still accessible to screen readers\n * https://bugs.chromium.org/p/chromium/issues/detail?id=1439785\n */\n position: fixed;\n left: -9999px;\n}\n.lh-metricfilter input[type='radio']:focus-visible + label {\n outline: -webkit-focus-ring-color auto 1px;\n}\n\n.lh-metricfilter__label {\n display: inline-flex;\n padding: 0 4px;\n height: 16px;\n text-decoration: underline;\n align-items: center;\n cursor: pointer;\n font-size: 90%;\n}\n\n.lh-metricfilter__label--active {\n background: var(--color-blue-primary);\n color: var(--color-white);\n border-radius: 3px;\n text-decoration: none;\n}\n/* Give the 'All' choice a more muted display */\n.lh-metricfilter__label--active[for=\"metric-All\"] {\n background-color: var(--color-blue-200) !important;\n color: black !important;\n}\n\n.lh-metricfilter__text {\n margin-right: 8px;\n}\n\n/* If audits are filtered, hide the itemcount for Passed Audits… */\n.lh-category--filtered .lh-audit-group .lh-audit-group__itemcount {\n display: none;\n}\n\n\n.lh-audit__header:hover {\n background-color: var(--color-hover);\n}\n\n/* We want to hide the browser's default arrow marker on summary elements. Admittedly, it's complicated. */\n.lh-root details > summary {\n /* Blink 89+ and Firefox will hide the arrow when display is changed from (new) default of `list-item` to block. https://chromestatus.com/feature/6730096436051968*/\n display: block;\n}\n/* Safari and Blink <=88 require using the -webkit-details-marker selector */\n.lh-root details > summary::-webkit-details-marker {\n display: none;\n}\n\n/* Perf Metric */\n\n.lh-metrics-container {\n display: grid;\n grid-auto-rows: 1fr;\n grid-template-columns: 1fr 1fr;\n grid-column-gap: var(--report-line-height);\n margin-bottom: var(--default-padding);\n}\n\n.lh-metric {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(-n+2) {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-metric__innerwrap {\n display: grid;\n /**\n * Icon -- Metric Name\n * -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 1fr;\n align-items: center;\n padding: var(--default-padding);\n}\n\n.lh-metric__details {\n order: -1;\n}\n\n.lh-metric__title {\n flex: 1;\n}\n\n.lh-calclink {\n padding-left: calc(1ex / 3);\n}\n\n.lh-metric__description {\n display: none;\n grid-column-start: 2;\n grid-column-end: 4;\n color: var(--report-text-color-secondary);\n}\n\n.lh-metric__value {\n font-size: var(--metric-value-font-size);\n margin: calc(var(--default-padding) / 2) 0;\n white-space: nowrap; /* No wrapping between metric value and the icon */\n grid-column-start: 2;\n}\n\n\n@media screen and (max-width: 535px) {\n .lh-metrics-container {\n display: block;\n }\n\n .lh-metric {\n border-bottom: none !important;\n }\n .lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(1) {\n border-bottom: 1px solid var(--report-border-color-secondary) !important;\n }\n\n /* Change the grid to 3 columns for narrow viewport. */\n .lh-metric__innerwrap {\n /**\n * Icon -- Metric Name -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 2fr 1fr;\n }\n .lh-metric__value {\n justify-self: end;\n grid-column-start: unset;\n }\n}\n\n/* No-JS toggle switch */\n/* Keep this selector sync'd w/ `magicSelector` in report-ui-features-test.js */\n .lh-metrics-toggle__input:checked ~ .lh-metrics-container .lh-metric__description {\n display: block;\n}\n\n/* TODO get rid of the SVGS and clean up these some more */\n.lh-metrics-toggle__input {\n opacity: 0;\n position: absolute;\n right: 0;\n top: 0px;\n}\n\n.lh-metrics-toggle__input + div > label > .lh-metrics-toggle__labeltext--hide,\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--show {\n display: none;\n}\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--hide {\n display: inline;\n}\n.lh-metrics-toggle__input:focus + div > label {\n outline: -webkit-focus-ring-color auto 3px;\n}\n\n.lh-metrics-toggle__label {\n cursor: pointer;\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n/* Pushes the metric description toggle button to the right. */\n.lh-audit-group--metrics .lh-audit-group__header {\n display: flex;\n justify-content: space-between;\n}\n\n.lh-metric__icon,\n.lh-scorescale-range::before {\n content: '';\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n display: inline-block;\n margin: var(--score-icon-margin);\n}\n\n.lh-metric--pass .lh-metric__value {\n color: var(--color-pass-secondary);\n}\n.lh-metric--pass .lh-metric__icon {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-metric--average .lh-metric__value {\n color: var(--color-average-secondary);\n}\n.lh-metric--average .lh-metric__icon {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-metric--fail .lh-metric__value {\n color: var(--color-fail-secondary);\n}\n.lh-metric--fail .lh-metric__icon {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-metric--error .lh-metric__value,\n.lh-metric--error .lh-metric__description {\n color: var(--color-fail-secondary);\n}\n\n/* Perf load opportunity */\n\n.lh-load-opportunity__cols {\n display: flex;\n align-items: flex-start;\n}\n\n.lh-load-opportunity__header .lh-load-opportunity__col {\n color: var(--color-gray-600);\n display: unset;\n line-height: calc(2.3 * var(--report-font-size));\n}\n\n.lh-load-opportunity__col {\n display: flex;\n}\n\n.lh-load-opportunity__col--one {\n flex: 5;\n align-items: center;\n margin-right: 2px;\n}\n.lh-load-opportunity__col--two {\n flex: 4;\n text-align: right;\n}\n\n.lh-audit--load-opportunity .lh-audit__display-text {\n text-align: right;\n flex: 0 0 7.5ch;\n}\n\n\n/* Sparkline */\n\n.lh-load-opportunity__sparkline {\n flex: 1;\n margin-top: calc((var(--report-line-height) - var(--sparkline-height)) / 2);\n}\n\n.lh-sparkline {\n height: var(--sparkline-height);\n width: 100%;\n}\n\n.lh-sparkline__bar {\n height: 100%;\n float: right;\n}\n\n.lh-audit--pass .lh-sparkline__bar {\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-sparkline__bar {\n background: var(--color-average);\n}\n\n.lh-audit--fail .lh-sparkline__bar {\n background: var(--color-fail);\n}\n\n/* Filmstrip */\n\n.lh-filmstrip-container {\n /* smaller gap between metrics and filmstrip */\n margin: -8px auto 0 auto;\n}\n\n.lh-filmstrip {\n display: grid;\n justify-content: space-between;\n padding-bottom: var(--default-padding);\n width: 100%;\n grid-template-columns: repeat(auto-fit, 90px);\n}\n\n.lh-filmstrip__frame {\n text-align: right;\n position: relative;\n}\n\n.lh-filmstrip__thumbnail {\n border: 1px solid var(--report-border-color-secondary);\n max-height: 150px;\n max-width: 120px;\n}\n\n/* Audit */\n\n.lh-audit {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n/* Apply border-top to just the first audit. */\n.lh-audit {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n.lh-audit ~ .lh-audit {\n border-top: none;\n}\n\n\n.lh-audit--error .lh-audit__display-text {\n color: var(--color-fail-secondary);\n}\n\n/* Audit Group */\n\n.lh-audit-group {\n margin-bottom: var(--audit-group-margin-bottom);\n position: relative;\n}\n.lh-audit-group--metrics {\n margin-bottom: calc(var(--audit-group-margin-bottom) / 2);\n}\n\n.lh-audit-group__header::before {\n /* By default, groups don't get an icon */\n content: none;\n width: var(--pwa-icon-size);\n height: var(--pwa-icon-size);\n margin: var(--pwa-icon-margin);\n display: inline-block;\n vertical-align: middle;\n}\n\n/* Style the \"over budget\" columns red. */\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(4),\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(5),\n.lh-audit-group--budgets #timing-budget tbody tr td:nth-child(3) {\n color: var(--color-red-700);\n}\n\n/* Align the \"over budget request count\" text to be close to the \"over budget bytes\" column. */\n.lh-audit-group--budgets .lh-table tbody tr td:nth-child(4){\n text-align: right;\n}\n\n.lh-audit-group--budgets .lh-details--budget {\n width: 100%;\n margin: 0 0 var(--default-padding);\n}\n\n.lh-audit-group--pwa-installable .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-installable-gray-url);\n}\n.lh-audit-group--pwa-optimized .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-optimized-gray-url);\n}\n.lh-audit-group--pwa-installable.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-installable-color-url);\n}\n.lh-audit-group--pwa-optimized.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-optimized-color-url);\n}\n\n.lh-audit-group--metrics .lh-audit-group__summary {\n margin-top: 0;\n margin-bottom: 0;\n}\n\n.lh-audit-group__summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.lh-audit-group__header .lh-chevron {\n margin-top: calc((var(--report-line-height) - 5px) / 2);\n}\n\n.lh-audit-group__header {\n letter-spacing: 0.8px;\n padding: var(--default-padding);\n padding-left: 0;\n}\n\n.lh-audit-group__header, .lh-audit-group__summary {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n.lh-audit-group__title {\n text-transform: uppercase;\n font-weight: 500;\n}\n\n.lh-audit-group__itemcount {\n color: var(--color-gray-600);\n}\n\n.lh-audit-group__footer {\n color: var(--color-gray-600);\n display: block;\n margin-top: var(--default-padding);\n}\n\n.lh-details,\n.lh-category-header__description,\n.lh-load-opportunity__header,\n.lh-audit-group__footer {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n}\n\n.lh-audit-explanation {\n margin: var(--audit-padding-vertical) 0 calc(var(--audit-padding-vertical) / 2) var(--audit-margin-horizontal);\n line-height: var(--audit-explanation-line-height);\n display: inline-block;\n}\n\n.lh-audit--fail .lh-audit-explanation {\n color: var(--color-fail-secondary);\n}\n\n/* Report */\n.lh-list > :not(:last-child) {\n margin-bottom: calc(var(--default-padding) * 2);\n}\n\n.lh-header-container {\n display: block;\n margin: 0 auto;\n position: relative;\n word-wrap: break-word;\n}\n\n.lh-header-container .lh-scores-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n\n\n.lh-report {\n min-width: var(--report-content-min-width);\n}\n\n.lh-exception {\n font-size: large;\n}\n\n.lh-code {\n white-space: normal;\n margin-top: 0;\n font-size: var(--report-monospace-font-size);\n}\n\n.lh-warnings {\n --item-margin: calc(var(--report-line-height) / 6);\n color: var(--color-average-secondary);\n margin: var(--audit-padding-vertical) 0;\n padding: var(--default-padding)\n var(--default-padding)\n var(--default-padding)\n calc(var(--audit-description-padding-left));\n background-color: var(--toplevel-warning-background-color);\n}\n.lh-warnings span {\n font-weight: bold;\n}\n\n.lh-warnings--toplevel {\n --item-margin: calc(var(--header-line-height) / 4);\n color: var(--toplevel-warning-text-color);\n margin-left: auto;\n margin-right: auto;\n max-width: var(--report-content-max-width-minus-edge-gap);\n padding: var(--toplevel-warning-padding);\n border-radius: 8px;\n}\n\n.lh-warnings__msg {\n color: var(--toplevel-warning-message-text-color);\n margin: 0;\n}\n\n.lh-warnings ul {\n margin: 0;\n}\n.lh-warnings li {\n margin: var(--item-margin) 0;\n}\n.lh-warnings li:last-of-type {\n margin-bottom: 0;\n}\n\n.lh-scores-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n}\n.lh-scores-header__solo {\n padding: 0;\n border: 0;\n}\n\n/* Gauge */\n\n.lh-gauge__wrapper--pass {\n color: var(--color-pass-secondary);\n fill: var(--color-pass);\n stroke: var(--color-pass);\n}\n\n.lh-gauge__wrapper--average {\n color: var(--color-average-secondary);\n fill: var(--color-average);\n stroke: var(--color-average);\n}\n\n.lh-gauge__wrapper--fail {\n color: var(--color-fail-secondary);\n fill: var(--color-fail);\n stroke: var(--color-fail);\n}\n\n.lh-gauge__wrapper--not-applicable {\n color: var(--color-not-applicable);\n fill: var(--color-not-applicable);\n stroke: var(--color-not-applicable);\n}\n\n.lh-fraction__wrapper .lh-fraction__content::before {\n content: '';\n height: var(--score-icon-size);\n width: var(--score-icon-size);\n margin: var(--score-icon-margin);\n display: inline-block;\n}\n.lh-fraction__wrapper--pass .lh-fraction__content {\n color: var(--color-pass-secondary);\n}\n.lh-fraction__wrapper--pass .lh-fraction__background {\n background-color: var(--color-pass);\n}\n.lh-fraction__wrapper--pass .lh-fraction__content::before {\n background-color: var(--color-pass);\n border-radius: 50%;\n}\n.lh-fraction__wrapper--average .lh-fraction__content {\n color: var(--color-average-secondary);\n}\n.lh-fraction__wrapper--average .lh-fraction__background,\n.lh-fraction__wrapper--average .lh-fraction__content::before {\n background-color: var(--color-average);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content {\n color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__background {\n background-color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n.lh-fraction__wrapper--null .lh-fraction__content {\n color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__background {\n background-color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__content::before {\n border-radius: 50%;\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-700);\n}\n\n.lh-fraction__background {\n position: absolute;\n height: 100%;\n width: 100%;\n border-radius: calc(var(--gauge-circle-size) / 2);\n opacity: 0.1;\n z-index: -1;\n}\n\n.lh-fraction__content-wrapper {\n height: var(--gauge-circle-size);\n display: flex;\n align-items: center;\n}\n\n.lh-fraction__content {\n display: flex;\n position: relative;\n align-items: center;\n justify-content: center;\n font-size: calc(0.3 * var(--gauge-circle-size));\n line-height: calc(0.4 * var(--gauge-circle-size));\n width: max-content;\n min-width: calc(1.5 * var(--gauge-circle-size));\n padding: calc(0.1 * var(--gauge-circle-size)) calc(0.2 * var(--gauge-circle-size));\n --score-icon-size: calc(0.21 * var(--gauge-circle-size));\n --score-icon-margin: 0 calc(0.15 * var(--gauge-circle-size)) 0 0;\n}\n\n.lh-gauge {\n stroke-linecap: round;\n width: var(--gauge-circle-size);\n height: var(--gauge-circle-size);\n}\n\n.lh-category .lh-gauge {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n.lh-gauge-base {\n opacity: 0.1;\n}\n\n.lh-gauge-arc {\n fill: none;\n transform-origin: 50% 50%;\n animation: load-gauge var(--transition-length) ease both;\n animation-delay: 250ms;\n}\n\n.lh-gauge__svg-wrapper {\n position: relative;\n height: var(--gauge-circle-size);\n}\n.lh-category .lh-gauge__svg-wrapper,\n.lh-category .lh-fraction__wrapper {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n/* The plugin badge overlay */\n.lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size);\n height: var(--plugin-badge-size);\n background-color: var(--plugin-badge-background-color);\n background-image: var(--plugin-icon-url);\n background-repeat: no-repeat;\n background-size: var(--plugin-icon-size);\n background-position: 58% 50%;\n content: \"\";\n position: absolute;\n right: -6px;\n bottom: 0px;\n display: block;\n z-index: 100;\n box-shadow: 0 0 4px rgba(0,0,0,.2);\n border-radius: 25%;\n}\n.lh-category .lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size-big);\n height: var(--plugin-badge-size-big);\n}\n\n@keyframes load-gauge {\n from { stroke-dasharray: 0 352; }\n}\n\n.lh-gauge__percentage {\n width: 100%;\n height: var(--gauge-circle-size);\n position: absolute;\n font-family: var(--report-font-family-monospace);\n font-size: calc(var(--gauge-circle-size) * 0.34 + 1.3px);\n line-height: 0;\n text-align: center;\n top: calc(var(--score-container-padding) + var(--gauge-circle-size) / 2);\n}\n\n.lh-category .lh-gauge__percentage {\n --gauge-circle-size: var(--gauge-circle-size-big);\n --gauge-percentage-font-size: var(--gauge-percentage-font-size-big);\n}\n\n.lh-gauge__wrapper,\n.lh-fraction__wrapper {\n position: relative;\n display: flex;\n align-items: center;\n flex-direction: column;\n text-decoration: none;\n padding: var(--score-container-padding);\n\n --transition-length: 1s;\n\n /* Contain the layout style paint & layers during animation*/\n contain: content;\n will-change: opacity; /* Only using for layer promotion */\n}\n\n.lh-gauge__label,\n.lh-fraction__label {\n font-size: var(--gauge-label-font-size);\n font-weight: 500;\n line-height: var(--gauge-label-line-height);\n margin-top: 10px;\n text-align: center;\n color: var(--report-text-color);\n word-break: keep-all;\n}\n\n/* TODO(#8185) use more BEM (.lh-gauge__label--big) instead of relying on descendant selector */\n.lh-category .lh-gauge__label,\n.lh-category .lh-fraction__label {\n --gauge-label-font-size: var(--gauge-label-font-size-big);\n --gauge-label-line-height: var(--gauge-label-line-height-big);\n margin-top: 14px;\n}\n\n.lh-scores-header .lh-gauge__wrapper,\n.lh-scores-header .lh-fraction__wrapper,\n.lh-scores-header .lh-gauge--pwa__wrapper,\n.lh-sticky-header .lh-gauge__wrapper,\n.lh-sticky-header .lh-fraction__wrapper,\n.lh-sticky-header .lh-gauge--pwa__wrapper {\n width: var(--gauge-wrapper-width);\n}\n\n.lh-scorescale {\n display: inline-flex;\n\n gap: calc(var(--default-padding) * 4);\n margin: 16px auto 0 auto;\n font-size: var(--report-font-size-secondary);\n color: var(--color-gray-700);\n\n}\n\n.lh-scorescale-range {\n display: flex;\n align-items: center;\n font-family: var(--report-font-family-monospace);\n white-space: nowrap;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale {\n border: 0;\n display: flex;\n justify-content: center;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale-range {\n font-family: unset;\n font-size: 12px;\n}\n\n.lh-scorescale-wrap {\n display: contents;\n}\n\n/* Hide category score gauages if it's a single category report */\n.lh-header--solo-category .lh-scores-wrapper {\n display: none;\n}\n\n\n.lh-categories {\n width: 100%;\n}\n\n.lh-category {\n padding: var(--category-padding);\n max-width: var(--report-content-max-width);\n margin: 0 auto;\n\n scroll-margin-top: var(--sticky-header-buffer);\n}\n\n.lh-category-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n.lh-category-wrapper:last-of-type {\n border-bottom: 0;\n}\n\n.lh-category-header {\n margin-bottom: var(--section-padding-vertical);\n}\n\n.lh-category-header .lh-score__gauge {\n max-width: 400px;\n width: auto;\n margin: 0px auto;\n}\n\n.lh-category-header__finalscreenshot {\n display: grid;\n grid-template: none / 1fr 1px 1fr;\n justify-items: center;\n align-items: center;\n gap: var(--report-line-height);\n min-height: 288px;\n margin-bottom: var(--default-padding);\n}\n\n.lh-final-ss-image {\n /* constrain the size of the image to not be too large */\n max-height: calc(var(--gauge-circle-size-big) * 2.8);\n max-width: calc(var(--gauge-circle-size-big) * 3.5);\n border: 1px solid var(--color-gray-200);\n padding: 4px;\n border-radius: 3px;\n display: block;\n}\n\n.lh-category-headercol--separator {\n background: var(--color-gray-200);\n width: 1px;\n height: var(--gauge-circle-size-big);\n}\n\n@media screen and (max-width: 780px) {\n .lh-category-header__finalscreenshot {\n grid-template: 1fr 1fr / none\n }\n .lh-category-headercol--separator {\n display: none;\n }\n}\n\n\n/* 964 fits the min-width of the filmstrip */\n@media screen and (max-width: 964px) {\n .lh-report {\n margin-left: 0;\n width: 100%;\n }\n}\n\n@media print {\n body {\n -webkit-print-color-adjust: exact; /* print background colors */\n }\n .lh-container {\n display: block;\n }\n .lh-report {\n margin-left: 0;\n padding-top: 0;\n }\n .lh-categories {\n margin-top: 0;\n }\n}\n\n.lh-table {\n position: relative;\n border-collapse: separate;\n border-spacing: 0;\n /* Can't assign padding to table, so shorten the width instead. */\n width: calc(100% - var(--audit-description-padding-left) - var(--stackpack-padding-horizontal));\n border: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-table thead th {\n position: sticky;\n top: calc(var(--sticky-header-buffer) + 1em);\n z-index: 1;\n background-color: var(--report-background-color);\n border-bottom: 1px solid var(--report-border-color-secondary);\n font-weight: normal;\n color: var(--color-gray-600);\n /* See text-wrapping comment on .lh-container. */\n word-break: normal;\n}\n\n.lh-row--group {\n background-color: var(--table-group-header-background-color);\n}\n\n.lh-row--group td {\n font-weight: bold;\n font-size: 1.05em;\n color: var(--table-group-header-text-color);\n}\n\n.lh-row--group td:first-child {\n font-weight: normal;\n}\n\n.lh-row--group .lh-text {\n color: inherit;\n text-decoration: none;\n display: inline-block;\n}\n\n.lh-row--group a.lh-link:hover {\n text-decoration: underline;\n}\n\n.lh-row--group .lh-audit__adorn {\n text-transform: capitalize;\n font-weight: normal;\n padding: 2px 3px 1px 3px;\n}\n\n.lh-row--group .lh-audit__adorn1p {\n color: var(--link-color);\n border-color: var(--link-color);\n}\n\n.lh-row--group .lh-report-icon--external::before {\n content: \"\";\n background-repeat: no-repeat;\n width: 14px;\n height: 16px;\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n\n.lh-row--group .lh-report-icon--external {\n display: none;\n}\n\n.lh-row--group:hover .lh-report-icon--external {\n display: inline-block;\n}\n\n.lh-dark .lh-report-icon--external::before {\n filter: invert(1);\n}\n\n/** Manages indentation of two-level and three-level nested adjacent rows */\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) td:first-child {\n padding-left: 20px;\n}\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) ~ .lh-sub-item-row td:first-child {\n padding-left: 40px;\n}\n\n.lh-row--even {\n background-color: var(--table-group-header-background-color);\n}\n.lh-row--hidden {\n display: none;\n}\n\n.lh-table th,\n.lh-table td {\n padding: var(--default-padding);\n}\n\n.lh-table tr {\n vertical-align: middle;\n}\n\n.lh-table tr:hover {\n background-color: var(--table-higlight-background-color);\n}\n\n/* Looks unnecessary, but mostly for keeping the s left-aligned */\n.lh-table-column--text,\n.lh-table-column--source-location,\n.lh-table-column--url,\n/* .lh-table-column--thumbnail, */\n/* .lh-table-column--empty,*/\n.lh-table-column--code,\n.lh-table-column--node {\n text-align: left;\n}\n\n.lh-table-column--code {\n min-width: 100px;\n}\n\n.lh-table-column--bytes,\n.lh-table-column--timespanMs,\n.lh-table-column--ms,\n.lh-table-column--numeric {\n text-align: right;\n word-break: normal;\n}\n\n\n\n.lh-table .lh-table-column--thumbnail {\n width: var(--image-preview-size);\n}\n\n.lh-table-column--url {\n min-width: 250px;\n}\n\n.lh-table-column--text {\n min-width: 80px;\n}\n\n/* Keep columns narrow if they follow the URL column */\n/* 12% was determined to be a decent narrow width, but wide enough for column headings */\n.lh-table-column--url + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--ms,\n.lh-table-column--url + .lh-table-column--ms + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--timespanMs {\n width: 12%;\n}\n\n.lh-text__url-host {\n display: inline;\n}\n\n.lh-text__url-host {\n margin-left: calc(var(--report-font-size) / 2);\n opacity: 0.6;\n font-size: 90%\n}\n\n.lh-thumbnail {\n object-fit: cover;\n width: var(--image-preview-size);\n height: var(--image-preview-size);\n display: block;\n}\n\n.lh-unknown pre {\n overflow: scroll;\n border: solid 1px var(--color-gray-200);\n}\n\n.lh-text__url > a {\n color: inherit;\n text-decoration: none;\n}\n\n.lh-text__url > a:hover {\n text-decoration: underline dotted #999;\n}\n\n.lh-sub-item-row {\n margin-left: 20px;\n margin-bottom: 0;\n color: var(--color-gray-700);\n}\n\n.lh-sub-item-row td {\n padding-top: 4px;\n padding-bottom: 4px;\n padding-left: 20px;\n}\n\n/* Chevron\n https://codepen.io/paulirish/pen/LmzEmK\n */\n.lh-chevron {\n --chevron-angle: 42deg;\n /* Edge doesn't support transform: rotate(calc(...)), so we define it here */\n --chevron-angle-right: -42deg;\n width: var(--chevron-size);\n height: var(--chevron-size);\n margin-top: calc((var(--report-line-height) - 12px) / 2);\n}\n\n.lh-chevron__lines {\n transition: transform 0.4s;\n transform: translateY(var(--report-line-height));\n}\n.lh-chevron__line {\n stroke: var(--chevron-line-stroke);\n stroke-width: var(--chevron-size);\n stroke-linecap: square;\n transform-origin: 50%;\n transform: rotate(var(--chevron-angle));\n transition: transform 300ms, stroke 300ms;\n}\n\n.lh-expandable-details .lh-chevron__line-right,\n.lh-expandable-details[open] .lh-chevron__line-left {\n transform: rotate(var(--chevron-angle-right));\n}\n\n.lh-expandable-details[open] .lh-chevron__line-right {\n transform: rotate(var(--chevron-angle));\n}\n\n\n.lh-expandable-details[open] .lh-chevron__lines {\n transform: translateY(calc(var(--chevron-size) * -1));\n}\n\n.lh-expandable-details[open] {\n animation: 300ms openDetails forwards;\n padding-bottom: var(--default-padding);\n}\n\n@keyframes openDetails {\n from {\n outline: 1px solid var(--report-background-color);\n }\n to {\n outline: 1px solid;\n box-shadow: 0 2px 4px rgba(0, 0, 0, .24);\n }\n}\n\n@media screen and (max-width: 780px) {\n /* no black outline if we're not confident the entire table can be displayed within bounds */\n .lh-expandable-details[open] {\n animation: none;\n }\n}\n\n.lh-expandable-details[open] summary, details.lh-clump > summary {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\ndetails.lh-clump[open] > summary {\n border-bottom-width: 0;\n}\n\n\n\ndetails .lh-clump-toggletext--hide,\ndetails[open] .lh-clump-toggletext--show { display: none; }\ndetails[open] .lh-clump-toggletext--hide { display: block;}\n\n\n/* Tooltip */\n.lh-tooltip-boundary {\n position: relative;\n}\n\n.lh-tooltip {\n position: absolute;\n display: none; /* Don't retain these layers when not needed */\n opacity: 0;\n background: #ffffff;\n white-space: pre-line; /* Render newlines in the text */\n min-width: 246px;\n max-width: 275px;\n padding: 15px;\n border-radius: 5px;\n text-align: initial;\n line-height: 1.4;\n}\n/* shrink tooltips to not be cutoff on left edge of narrow viewports\n 45vw is chosen to be ~= width of the left column of metrics\n*/\n@media screen and (max-width: 535px) {\n .lh-tooltip {\n min-width: 45vw;\n padding: 3vw;\n }\n}\n\n.lh-tooltip-boundary:hover .lh-tooltip {\n display: block;\n animation: fadeInTooltip 250ms;\n animation-fill-mode: forwards;\n animation-delay: 850ms;\n bottom: 100%;\n z-index: 1;\n will-change: opacity;\n right: 0;\n pointer-events: none;\n}\n\n.lh-tooltip::before {\n content: \"\";\n border: solid transparent;\n border-bottom-color: #fff;\n border-width: 10px;\n position: absolute;\n bottom: -20px;\n right: 6px;\n transform: rotate(180deg);\n pointer-events: none;\n}\n\n@keyframes fadeInTooltip {\n 0% { opacity: 0; }\n 75% { opacity: 1; }\n 100% { opacity: 1; filter: drop-shadow(1px 0px 1px #aaa) drop-shadow(0px 2px 4px hsla(206, 6%, 25%, 0.15)); pointer-events: auto; }\n}\n\n/* Element screenshot */\n.lh-element-screenshot {\n float: left;\n margin-right: 20px;\n}\n.lh-element-screenshot__content {\n overflow: hidden;\n min-width: 110px;\n display: flex;\n justify-content: center;\n background-color: var(--report-background-color);\n}\n.lh-element-screenshot__image {\n position: relative;\n /* Set by ElementScreenshotRenderer.installFullPageScreenshotCssVariable */\n background-image: var(--element-screenshot-url);\n outline: 2px solid #777;\n background-color: white;\n background-repeat: no-repeat;\n}\n.lh-element-screenshot__mask {\n position: absolute;\n background: #555;\n opacity: 0.8;\n}\n.lh-element-screenshot__element-marker {\n position: absolute;\n outline: 2px solid var(--color-lime-400);\n}\n.lh-element-screenshot__overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 2000; /* .lh-topbar is 1000 */\n background: var(--screenshot-overlay-background);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: zoom-out;\n}\n\n.lh-element-screenshot__overlay .lh-element-screenshot {\n margin-right: 0; /* clearing margin used in thumbnail case */\n outline: 1px solid var(--color-gray-700);\n}\n\n.lh-screenshot-overlay--enabled .lh-element-screenshot {\n cursor: zoom-out;\n}\n.lh-screenshot-overlay--enabled .lh-node .lh-element-screenshot {\n cursor: zoom-in;\n}\n\n\n.lh-meta__items {\n --meta-icon-size: calc(var(--report-icon-size) * 0.667);\n padding: var(--default-padding);\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n background-color: var(--env-item-background-color);\n border-radius: 3px;\n margin: 0 0 var(--default-padding) 0;\n font-size: 12px;\n column-gap: var(--default-padding);\n color: var(--color-gray-700);\n}\n\n.lh-meta__item {\n display: block;\n list-style-type: none;\n position: relative;\n padding: 0 0 0 calc(var(--meta-icon-size) + var(--default-padding) * 2);\n cursor: unset; /* disable pointer cursor from report-icon */\n}\n\n.lh-meta__item.lh-tooltip-boundary {\n text-decoration: dotted underline var(--color-gray-500);\n cursor: help;\n}\n\n.lh-meta__item.lh-report-icon::before {\n position: absolute;\n left: var(--default-padding);\n width: var(--meta-icon-size);\n height: var(--meta-icon-size);\n}\n\n.lh-meta__item.lh-report-icon:hover::before {\n opacity: 0.7;\n}\n\n.lh-meta__item .lh-tooltip {\n color: var(--color-gray-800);\n}\n\n.lh-meta__item .lh-tooltip::before {\n right: auto; /* Set the tooltip arrow to the leftside */\n left: 6px;\n}\n\n/* Change the grid for narrow viewport. */\n@media screen and (max-width: 640px) {\n .lh-meta__items {\n grid-template-columns: 1fr 1fr;\n }\n}\n@media screen and (max-width: 535px) {\n .lh-meta__items {\n display: block;\n }\n}\n\n\n/*# sourceURL=report-styles.css */\n"); + 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 --report-icon-size: var(--score-icon-background-size);\n --report-line-height: 24px;\n --report-line-height-secondary: 20px;\n --report-monospace-font-size: calc(var(--report-font-size) * 0.85);\n --report-text-color-secondary: var(--color-gray-800);\n --report-text-color: var(--color-gray-900);\n --report-content-max-width: calc(60 * var(--report-font-size)); /* defaults to 840px */\n --report-content-min-width: 360px;\n --report-content-max-width-minus-edge-gap: calc(var(--report-content-max-width) - var(--edge-gap-padding) * 2);\n --score-container-padding: 8px;\n --score-icon-background-size: 24px;\n --score-icon-margin-left: 6px;\n --score-icon-margin-right: 14px;\n --score-icon-margin: 0 var(--score-icon-margin-right) 0 var(--score-icon-margin-left);\n --score-icon-size: 12px;\n --score-icon-size-big: 16px;\n --screenshot-overlay-background: rgba(0, 0, 0, 0.3);\n --section-padding-vertical: calc(var(--default-padding) * 6);\n --snippet-background-color: var(--color-gray-50);\n --snippet-color: #0938C2;\n --sparkline-height: 5px;\n --stackpack-padding-horizontal: 10px;\n --sticky-header-background-color: var(--report-background-color);\n --sticky-header-buffer: calc(var(--topbar-height) + var(--sticky-header-height));\n --sticky-header-height: calc(var(--gauge-circle-size-sm) + var(--score-container-padding) * 2);\n --table-group-header-background-color: #EEF1F4;\n --table-group-header-text-color: var(--color-gray-700);\n --table-higlight-background-color: #F5F7FA;\n --tools-icon-color: var(--color-gray-600);\n --topbar-background-color: var(--color-white);\n --topbar-height: 32px;\n --topbar-logo-size: 24px;\n --topbar-padding: 0 8px;\n --toplevel-warning-background-color: hsla(30, 100%, 75%, 10%);\n --toplevel-warning-message-text-color: var(--color-average-secondary);\n --toplevel-warning-padding: 18px;\n --toplevel-warning-text-color: var(--report-text-color);\n\n /* SVGs */\n --plugin-icon-url-dark: url('data:image/svg+xml;utf8,');\n --plugin-icon-url: url('data:image/svg+xml;utf8,');\n\n --pass-icon-url: url('data:image/svg+xml;utf8,check');\n --average-icon-url: url('data:image/svg+xml;utf8,info');\n --fail-icon-url: url('data:image/svg+xml;utf8,warn');\n --error-icon-url: url('data:image/svg+xml;utf8,error');\n\n --pwa-installable-gray-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-gray-url-dark: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url-dark: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-color-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-color-url: url('data:image/svg+xml;utf8,');\n\n --swap-locale-icon-url: url('data:image/svg+xml;utf8,');\n}\n\n@media not print {\n .lh-dark {\n /* Pallete */\n --color-gray-200: var(--color-gray-800);\n --color-gray-300: #616161;\n --color-gray-400: var(--color-gray-600);\n --color-gray-700: var(--color-gray-400);\n --color-gray-50: #757575;\n --color-gray-600: var(--color-gray-500);\n --color-green-700: var(--color-green);\n --color-orange-700: var(--color-orange);\n --color-red-700: var(--color-red);\n --color-teal-600: var(--color-cyan-500);\n\n /* Context-specific colors */\n --color-hover: rgba(0, 0, 0, 0.2);\n --color-informative: var(--color-blue-200);\n\n /* Component variables */\n --env-item-background-color: #393535;\n --link-color: var(--color-blue-200);\n --locale-selector-background-color: var(--color-gray-200);\n --plugin-badge-background-color: var(--color-gray-800);\n --report-background-color: var(--color-gray-900);\n --report-border-color-secondary: var(--color-gray-200);\n --report-text-color-secondary: var(--color-gray-400);\n --report-text-color: var(--color-gray-100);\n --snippet-color: var(--color-cyan-500);\n --topbar-background-color: var(--color-gray);\n --toplevel-warning-background-color: hsl(33deg 14% 18%);\n --toplevel-warning-message-text-color: var(--color-orange-700);\n --toplevel-warning-text-color: var(--color-gray-100);\n --table-group-header-background-color: rgba(186, 196, 206, 0.15);\n --table-group-header-text-color: var(--color-gray-100);\n --table-higlight-background-color: rgba(186, 196, 206, 0.09);\n\n /* SVGs */\n --plugin-icon-url: var(--plugin-icon-url-dark);\n --pwa-installable-gray-url: var(--pwa-installable-gray-url-dark);\n --pwa-optimized-gray-url: var(--pwa-optimized-gray-url-dark);\n }\n}\n\n@media only screen and (max-width: 480px) {\n .lh-vars {\n --audit-group-margin-bottom: 20px;\n --edge-gap-padding: var(--default-padding);\n --env-name-min-width: 120px;\n --gauge-circle-size-big: 96px;\n --gauge-circle-size: 72px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 112px;\n --header-padding: 16px 0 16px 0;\n --image-preview-size: 24px;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-size: 14px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --topbar-height: 28px;\n --topbar-logo-size: 20px;\n }\n\n /* Not enough space to adequately show the relative savings bars. */\n .lh-sparkline {\n display: none;\n }\n}\n\n.lh-vars.lh-devtools {\n --audit-explanation-line-height: 14px;\n --audit-group-margin-bottom: 20px;\n --audit-group-padding-vertical: 12px;\n --audit-padding-vertical: 4px;\n --category-padding: 12px;\n --default-padding: 12px;\n --env-name-min-width: 120px;\n --footer-padding-vertical: 8px;\n --gauge-circle-size-big: 72px;\n --gauge-circle-size: 64px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 97px;\n --header-line-height: 20px;\n --header-padding: 16px 0 16px 0;\n --screenshot-overlay-background: transparent;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-family-monospace: 'Menlo', 'dejavu sans mono', 'Consolas', 'Lucida Console', monospace;\n --report-font-family: '.SFNSDisplay-Regular', 'Helvetica Neue', 'Lucida Grande', sans-serif;\n --report-font-size: 12px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --section-padding-vertical: 8px;\n}\n\n.lh-container:not(.lh-topbar + .lh-container) {\n --topbar-height: 0;\n --sticky-header-height: 0;\n --sticky-header-buffer: 0;\n}\n\n.lh-devtools.lh-root {\n height: 100%;\n}\n.lh-devtools.lh-root img {\n /* Override devtools default 'min-width: 0' so svg without size in a flexbox isn't collapsed. */\n min-width: auto;\n}\n.lh-devtools .lh-container {\n overflow-y: scroll;\n height: calc(100% - var(--topbar-height));\n /** The .lh-container is the scroll parent in DevTools so we exclude the topbar from the sticky header buffer. */\n --sticky-header-buffer: calc(var(--sticky-header-height));\n}\n@media print {\n .lh-devtools .lh-container {\n overflow: unset;\n }\n}\n.lh-devtools .lh-sticky-header {\n /* This is normally the height of the topbar, but we want it to stick to the top of our scroll container .lh-container` */\n top: 0;\n}\n.lh-devtools .lh-element-screenshot__overlay {\n position: absolute;\n}\n\n@keyframes fadeIn {\n 0% { opacity: 0;}\n 100% { opacity: 0.6;}\n}\n\n.lh-root *, .lh-root *::before, .lh-root *::after {\n box-sizing: border-box;\n}\n\n.lh-root {\n font-family: var(--report-font-family);\n font-size: var(--report-font-size);\n margin: 0;\n line-height: var(--report-line-height);\n background: var(--report-background-color);\n color: var(--report-text-color);\n}\n\n.lh-root :focus-visible {\n outline: -webkit-focus-ring-color auto 3px;\n}\n.lh-root summary:focus {\n outline: none;\n box-shadow: 0 0 0 1px hsl(217, 89%, 61%);\n}\n\n.lh-root [hidden] {\n display: none !important;\n}\n\n.lh-root pre {\n margin: 0;\n}\n\n.lh-root pre,\n.lh-root code {\n font-family: var(--report-font-family-monospace);\n}\n\n.lh-root details > summary {\n cursor: pointer;\n}\n\n.lh-hidden {\n display: none !important;\n}\n\n.lh-container {\n /*\n Text wrapping in the report is so much FUN!\n We have a `word-break: break-word;` globally here to prevent a few common scenarios, namely\n long non-breakable text (usually URLs) found in:\n 1. The footer\n 2. .lh-node (outerHTML)\n 3. .lh-code\n\n With that sorted, the next challenge is appropriate column sizing and text wrapping inside our\n .lh-details tables. Even more fun.\n * We don't want table headers (\"Potential Savings (ms)\") to wrap or their column values, but\n we'd be happy for the URL column to wrap if the URLs are particularly long.\n * We want the narrow columns to remain narrow, providing the most column width for URL\n * We don't want the table to extend past 100% width.\n * Long URLs in the URL column can wrap. Util.getURLDisplayName maxes them out at 64 characters,\n but they do not get any overflow:ellipsis treatment.\n */\n word-break: break-word;\n}\n\n.lh-audit-group a,\n.lh-category-header__description a,\n.lh-audit__description a,\n.lh-warnings a,\n.lh-footer a,\n.lh-table-column--link a {\n color: var(--link-color);\n}\n\n.lh-audit__description, .lh-audit__stackpack {\n --inner-audit-padding-right: var(--stackpack-padding-horizontal);\n padding-left: var(--audit-description-padding-left);\n padding-right: var(--inner-audit-padding-right);\n padding-top: 8px;\n padding-bottom: 8px;\n}\n\n.lh-details {\n margin-top: var(--default-padding);\n margin-bottom: var(--default-padding);\n margin-left: var(--audit-description-padding-left);\n /* whatever the .lh-details side margins are */\n width: 100%;\n}\n\n.lh-audit__stackpack {\n display: flex;\n align-items: center;\n}\n\n.lh-audit__stackpack__img {\n max-width: 30px;\n margin-right: var(--default-padding)\n}\n\n/* Report header */\n\n.lh-report-icon {\n display: flex;\n align-items: center;\n padding: 10px 12px;\n cursor: pointer;\n}\n.lh-report-icon[disabled] {\n opacity: 0.3;\n pointer-events: none;\n}\n\n.lh-report-icon::before {\n content: \"\";\n margin: 4px;\n background-repeat: no-repeat;\n width: var(--report-icon-size);\n height: var(--report-icon-size);\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n.lh-report-icon:hover::before {\n opacity: 1;\n}\n.lh-dark .lh-report-icon::before {\n filter: invert(1);\n}\n.lh-report-icon--print::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--copy::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--open::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--download::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--dark::before {\n background-image:url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--treemap::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--date::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--devices::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--world::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--stopwatch::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--networkspeed::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-one::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-many::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--chrome::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--external::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n\n.lh-buttons {\n display: flex;\n flex-wrap: wrap;\n margin: var(--default-padding) 0;\n}\n.lh-button {\n height: 32px;\n border: 1px solid var(--report-border-color-secondary);\n border-radius: 3px;\n color: var(--link-color);\n background-color: var(--report-background-color);\n margin: 5px;\n}\n\n.lh-button:first-of-type {\n margin-left: 0;\n}\n\n/* Node */\n.lh-node__snippet {\n font-family: var(--report-font-family-monospace);\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n line-height: 20px;\n}\n\n/* Score */\n\n/* to remove color indicators - test */\n/* .lh-audit__score-icon {\n opacity: 0;\n} */\n\n.lh-audit__score-icon {\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n margin: var(--score-icon-margin);\n}\n\n.lh-audit--pass .lh-audit__display-text {\n color: var(--color-pass-secondary);\n}\n.lh-audit--pass .lh-audit__score-icon,\n.lh-scorescale-range--pass::before {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-audit__display-text {\n color: var(--color-average-secondary);\n /* to remove color indicators - test */\n /* color: gray; */\n}\n.lh-audit--average .lh-audit__score-icon,\n.lh-scorescale-range--average::before {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-audit--fail .lh-audit__display-text {\n color: var(--color-fail-secondary);\n /* to remove color indicators - test */\n /* color: gray; */\n}\n.lh-audit--fail .lh-audit__score-icon,\n.lh-audit--error .lh-audit__score-icon,\n.lh-scorescale-range--fail::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-audit--error .lh-audit__score-icon,\n.lh-metric--error .lh-metric__icon {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n border: none;\n}\n\n.lh-gauge__wrapper--fail .lh-gauge--error {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n transform: scale(0.5);\n top: var(--score-container-padding);\n}\n\n.lh-audit--manual .lh-audit__display-text,\n.lh-audit--notapplicable .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n.lh-audit--manual .lh-audit__score-icon,\n.lh-audit--notapplicable .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n background: none;\n}\n\n.lh-audit--informative .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n\n.lh-audit--informative .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n}\n\n.lh-audit__description,\n.lh-audit__stackpack {\n color: var(--report-text-color-secondary);\n}\n.lh-audit__adorn {\n border: 1px solid var(--color-gray-500);\n border-radius: 3px;\n margin: 0 3px;\n padding: 0 2px;\n line-height: 1.1;\n display: inline-block;\n font-size: 90%;\n color: var(--report-text-color-secondary);\n}\n\n.lh-category-header__description {\n text-align: center;\n color: var(--color-gray-700);\n margin: 0px auto;\n max-width: 400px;\n}\n\n\n.lh-audit__display-text,\n.lh-load-opportunity__sparkline,\n.lh-chevron-container {\n margin: 0 var(--audit-margin-horizontal);\n}\n.lh-chevron-container {\n margin-right: 0;\n}\n\n.lh-audit__title-and-text {\n flex: 1;\n}\n\n.lh-audit__title-and-text code {\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n}\n\n/* Prepend display text with em dash separator. But not in Opportunities. */\n.lh-audit__display-text:not(:empty):before {\n content: '—';\n margin-right: var(--audit-margin-horizontal);\n}\n.lh-audit-group.lh-audit-group--load-opportunities .lh-audit__display-text:not(:empty):before {\n display: none;\n}\n\n/* Expandable Details (Audit Groups, Audits) */\n.lh-audit__header {\n display: flex;\n align-items: center;\n padding: var(--default-padding);\n}\n\n.lh-audit--load-opportunity .lh-audit__header {\n display: block;\n}\n\n\n.lh-metricfilter {\n display: grid;\n justify-content: end;\n align-items: center;\n grid-auto-flow: column;\n gap: 4px;\n color: var(--color-gray-700);\n}\n\n.lh-metricfilter__radio {\n /*\n * Instead of hiding, position offscreen so it's still accessible to screen readers\n * https://bugs.chromium.org/p/chromium/issues/detail?id=1439785\n */\n position: fixed;\n left: -9999px;\n}\n.lh-metricfilter input[type='radio']:focus-visible + label {\n outline: -webkit-focus-ring-color auto 1px;\n}\n\n.lh-metricfilter__label {\n display: inline-flex;\n padding: 0 4px;\n height: 16px;\n text-decoration: underline;\n align-items: center;\n cursor: pointer;\n font-size: 90%;\n}\n\n.lh-metricfilter__label--active {\n background: var(--color-blue-primary);\n color: var(--color-white);\n border-radius: 3px;\n text-decoration: none;\n}\n/* Give the 'All' choice a more muted display */\n.lh-metricfilter__label--active[for=\"metric-All\"] {\n background-color: var(--color-blue-200) !important;\n color: black !important;\n}\n\n.lh-metricfilter__text {\n margin-right: 8px;\n}\n\n/* If audits are filtered, hide the itemcount for Passed Audits… */\n.lh-category--filtered .lh-audit-group .lh-audit-group__itemcount {\n display: none;\n}\n\n\n.lh-audit__header:hover {\n background-color: var(--color-hover);\n}\n\n/* We want to hide the browser's default arrow marker on summary elements. Admittedly, it's complicated. */\n.lh-root details > summary {\n /* Blink 89+ and Firefox will hide the arrow when display is changed from (new) default of `list-item` to block. https://chromestatus.com/feature/6730096436051968*/\n display: block;\n}\n/* Safari and Blink <=88 require using the -webkit-details-marker selector */\n.lh-root details > summary::-webkit-details-marker {\n display: none;\n}\n\n/* Perf Metric */\n\n.lh-metrics-container {\n display: grid;\n grid-auto-rows: 1fr;\n grid-template-columns: 1fr 1fr;\n grid-column-gap: var(--report-line-height);\n margin-bottom: var(--default-padding);\n}\n\n.lh-metric {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(-n+2) {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-metric__innerwrap {\n display: grid;\n /**\n * Icon -- Metric Name\n * -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 1fr;\n align-items: center;\n padding: var(--default-padding);\n}\n\n.lh-metric__details {\n order: -1;\n}\n\n.lh-metric__title {\n flex: 1;\n}\n\n.lh-calclink {\n padding-left: calc(1ex / 3);\n}\n\n.lh-metric__description {\n display: none;\n grid-column-start: 2;\n grid-column-end: 4;\n color: var(--report-text-color-secondary);\n}\n\n.lh-metric__value {\n font-size: var(--metric-value-font-size);\n margin: calc(var(--default-padding) / 2) 0;\n white-space: nowrap; /* No wrapping between metric value and the icon */\n grid-column-start: 2;\n}\n\n\n@media screen and (max-width: 535px) {\n .lh-metrics-container {\n display: block;\n }\n\n .lh-metric {\n border-bottom: none !important;\n }\n .lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(1) {\n border-bottom: 1px solid var(--report-border-color-secondary) !important;\n }\n\n /* Change the grid to 3 columns for narrow viewport. */\n .lh-metric__innerwrap {\n /**\n * Icon -- Metric Name -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 2fr 1fr;\n }\n .lh-metric__value {\n justify-self: end;\n grid-column-start: unset;\n }\n}\n\n/* No-JS toggle switch */\n/* Keep this selector sync'd w/ `magicSelector` in report-ui-features-test.js */\n .lh-metrics-toggle__input:checked ~ .lh-metrics-container .lh-metric__description {\n display: block;\n}\n\n/* TODO get rid of the SVGS and clean up these some more */\n.lh-metrics-toggle__input {\n opacity: 0;\n position: absolute;\n right: 0;\n top: 0px;\n}\n\n.lh-metrics-toggle__input + div > label > .lh-metrics-toggle__labeltext--hide,\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--show {\n display: none;\n}\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--hide {\n display: inline;\n}\n.lh-metrics-toggle__input:focus + div > label {\n outline: -webkit-focus-ring-color auto 3px;\n}\n\n.lh-metrics-toggle__label {\n cursor: pointer;\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n/* Pushes the metric description toggle button to the right. */\n.lh-audit-group--metrics .lh-audit-group__header {\n display: flex;\n justify-content: space-between;\n}\n\n.lh-metric__icon,\n.lh-scorescale-range::before {\n content: '';\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n display: inline-block;\n margin: var(--score-icon-margin);\n}\n\n.lh-metric--pass .lh-metric__value {\n color: var(--color-pass-secondary);\n}\n.lh-metric--pass .lh-metric__icon {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-metric--average .lh-metric__value {\n color: var(--color-average-secondary);\n}\n.lh-metric--average .lh-metric__icon {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-metric--fail .lh-metric__value {\n color: var(--color-fail-secondary);\n}\n.lh-metric--fail .lh-metric__icon {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-metric--error .lh-metric__value,\n.lh-metric--error .lh-metric__description {\n color: var(--color-fail-secondary);\n}\n\n/* Perf load opportunity */\n\n.lh-load-opportunity__cols {\n display: flex;\n align-items: flex-start;\n}\n\n.lh-load-opportunity__header .lh-load-opportunity__col {\n color: var(--color-gray-600);\n display: unset;\n line-height: calc(2.3 * var(--report-font-size));\n}\n\n.lh-load-opportunity__col {\n display: flex;\n}\n\n.lh-load-opportunity__col--one {\n flex: 5;\n align-items: center;\n margin-right: 2px;\n}\n.lh-load-opportunity__col--two {\n flex: 4;\n text-align: right;\n}\n\n.lh-audit--load-opportunity .lh-audit__display-text {\n text-align: right;\n flex: 0 0 7.5ch;\n}\n\n\n/* Sparkline */\n\n.lh-load-opportunity__sparkline {\n flex: 1;\n margin-top: calc((var(--report-line-height) - var(--sparkline-height)) / 2);\n}\n\n.lh-sparkline {\n height: var(--sparkline-height);\n width: 100%;\n}\n\n.lh-sparkline__bar {\n height: 100%;\n float: right;\n}\n\n.lh-audit--pass .lh-sparkline__bar {\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-sparkline__bar {\n background: var(--color-average);\n}\n\n.lh-audit--fail .lh-sparkline__bar {\n background: var(--color-fail);\n}\n\n/* Filmstrip */\n\n.lh-filmstrip-container {\n /* smaller gap between metrics and filmstrip */\n margin: -8px auto 0 auto;\n}\n\n.lh-filmstrip {\n display: grid;\n justify-content: space-between;\n padding-bottom: var(--default-padding);\n width: 100%;\n grid-template-columns: repeat(auto-fit, 90px);\n}\n\n.lh-filmstrip__frame {\n text-align: right;\n position: relative;\n}\n\n.lh-filmstrip__thumbnail {\n border: 1px solid var(--report-border-color-secondary);\n max-height: 150px;\n max-width: 120px;\n}\n\n/* Audit */\n\n.lh-audit {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n/* Apply border-top to just the first audit. */\n.lh-audit {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n.lh-audit ~ .lh-audit {\n border-top: none;\n}\n\n\n.lh-audit--error .lh-audit__display-text {\n color: var(--color-fail-secondary);\n}\n\n/* Audit Group */\n\n.lh-audit-group {\n margin-bottom: var(--audit-group-margin-bottom);\n position: relative;\n}\n.lh-audit-group--metrics {\n margin-bottom: calc(var(--audit-group-margin-bottom) / 2);\n}\n\n.lh-audit-group__header::before {\n /* By default, groups don't get an icon */\n content: none;\n width: var(--pwa-icon-size);\n height: var(--pwa-icon-size);\n margin: var(--pwa-icon-margin);\n display: inline-block;\n vertical-align: middle;\n}\n\n/* Style the \"over budget\" columns red. */\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(4),\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(5),\n.lh-audit-group--budgets #timing-budget tbody tr td:nth-child(3) {\n color: var(--color-red-700);\n}\n\n/* Align the \"over budget request count\" text to be close to the \"over budget bytes\" column. */\n.lh-audit-group--budgets .lh-table tbody tr td:nth-child(4){\n text-align: right;\n}\n\n.lh-audit-group--budgets .lh-details--budget {\n width: 100%;\n margin: 0 0 var(--default-padding);\n}\n\n.lh-audit-group--pwa-installable .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-installable-gray-url);\n}\n.lh-audit-group--pwa-optimized .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-optimized-gray-url);\n}\n.lh-audit-group--pwa-installable.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-installable-color-url);\n}\n.lh-audit-group--pwa-optimized.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-optimized-color-url);\n}\n\n.lh-audit-group--metrics .lh-audit-group__summary {\n margin-top: 0;\n margin-bottom: 0;\n}\n\n.lh-audit-group__summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.lh-audit-group__header .lh-chevron {\n margin-top: calc((var(--report-line-height) - 5px) / 2);\n}\n\n.lh-audit-group__header {\n letter-spacing: 0.8px;\n padding: var(--default-padding);\n padding-left: 0;\n}\n\n.lh-audit-group__header, .lh-audit-group__summary {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n.lh-audit-group__title {\n text-transform: uppercase;\n font-weight: 500;\n}\n\n.lh-audit-group__itemcount {\n color: var(--color-gray-600);\n}\n\n.lh-audit-group__footer {\n color: var(--color-gray-600);\n display: block;\n margin-top: var(--default-padding);\n}\n\n.lh-details,\n.lh-category-header__description,\n.lh-load-opportunity__header,\n.lh-audit-group__footer {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n}\n\n.lh-audit-explanation {\n margin: var(--audit-padding-vertical) 0 calc(var(--audit-padding-vertical) / 2) var(--audit-margin-horizontal);\n line-height: var(--audit-explanation-line-height);\n display: inline-block;\n}\n\n.lh-audit--fail .lh-audit-explanation {\n color: var(--color-fail-secondary);\n}\n\n/* Report */\n.lh-list > :not(:last-child) {\n margin-bottom: calc(var(--default-padding) * 2);\n}\n\n.lh-header-container {\n display: block;\n margin: 0 auto;\n position: relative;\n word-wrap: break-word;\n}\n\n.lh-header-container .lh-scores-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n\n\n.lh-report {\n min-width: var(--report-content-min-width);\n}\n\n.lh-exception {\n font-size: large;\n}\n\n.lh-code {\n white-space: normal;\n margin-top: 0;\n font-size: var(--report-monospace-font-size);\n}\n\n.lh-warnings {\n --item-margin: calc(var(--report-line-height) / 6);\n color: var(--color-average-secondary);\n margin: var(--audit-padding-vertical) 0;\n padding: var(--default-padding)\n var(--default-padding)\n var(--default-padding)\n calc(var(--audit-description-padding-left));\n background-color: var(--toplevel-warning-background-color);\n}\n.lh-warnings span {\n font-weight: bold;\n}\n\n.lh-warnings--toplevel {\n --item-margin: calc(var(--header-line-height) / 4);\n color: var(--toplevel-warning-text-color);\n margin-left: auto;\n margin-right: auto;\n max-width: var(--report-content-max-width-minus-edge-gap);\n padding: var(--toplevel-warning-padding);\n border-radius: 8px;\n}\n\n.lh-warnings__msg {\n color: var(--toplevel-warning-message-text-color);\n margin: 0;\n}\n\n.lh-warnings ul {\n margin: 0;\n}\n.lh-warnings li {\n margin: var(--item-margin) 0;\n}\n.lh-warnings li:last-of-type {\n margin-bottom: 0;\n}\n\n.lh-scores-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n}\n.lh-scores-header__solo {\n padding: 0;\n border: 0;\n}\n\n/* Gauge */\n\n.lh-gauge__wrapper--pass {\n color: var(--color-pass-secondary);\n fill: var(--color-pass);\n stroke: var(--color-pass);\n}\n\n.lh-gauge__wrapper--average {\n color: var(--color-average-secondary);\n fill: var(--color-average);\n stroke: var(--color-average);\n}\n\n.lh-gauge__wrapper--fail {\n color: var(--color-fail-secondary);\n fill: var(--color-fail);\n stroke: var(--color-fail);\n}\n\n.lh-gauge__wrapper--not-applicable {\n color: var(--color-not-applicable);\n fill: var(--color-not-applicable);\n stroke: var(--color-not-applicable);\n}\n\n.lh-fraction__wrapper .lh-fraction__content::before {\n content: '';\n height: var(--score-icon-size);\n width: var(--score-icon-size);\n margin: var(--score-icon-margin);\n display: inline-block;\n}\n.lh-fraction__wrapper--pass .lh-fraction__content {\n color: var(--color-pass-secondary);\n}\n.lh-fraction__wrapper--pass .lh-fraction__background {\n background-color: var(--color-pass);\n}\n.lh-fraction__wrapper--pass .lh-fraction__content::before {\n background-color: var(--color-pass);\n border-radius: 50%;\n}\n.lh-fraction__wrapper--average .lh-fraction__content {\n color: var(--color-average-secondary);\n}\n.lh-fraction__wrapper--average .lh-fraction__background,\n.lh-fraction__wrapper--average .lh-fraction__content::before {\n background-color: var(--color-average);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content {\n color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__background {\n background-color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n.lh-fraction__wrapper--null .lh-fraction__content {\n color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__background {\n background-color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__content::before {\n border-radius: 50%;\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-700);\n}\n\n.lh-fraction__background {\n position: absolute;\n height: 100%;\n width: 100%;\n border-radius: calc(var(--gauge-circle-size) / 2);\n opacity: 0.1;\n z-index: -1;\n}\n\n.lh-fraction__content-wrapper {\n height: var(--gauge-circle-size);\n display: flex;\n align-items: center;\n}\n\n.lh-fraction__content {\n display: flex;\n position: relative;\n align-items: center;\n justify-content: center;\n font-size: calc(0.3 * var(--gauge-circle-size));\n line-height: calc(0.4 * var(--gauge-circle-size));\n width: max-content;\n min-width: calc(1.5 * var(--gauge-circle-size));\n padding: calc(0.1 * var(--gauge-circle-size)) calc(0.2 * var(--gauge-circle-size));\n --score-icon-size: calc(0.21 * var(--gauge-circle-size));\n --score-icon-margin: 0 calc(0.15 * var(--gauge-circle-size)) 0 0;\n}\n\n.lh-gauge {\n stroke-linecap: round;\n width: var(--gauge-circle-size);\n height: var(--gauge-circle-size);\n}\n\n.lh-category .lh-gauge {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n.lh-gauge-base {\n opacity: 0.1;\n}\n\n.lh-gauge-arc {\n fill: none;\n transform-origin: 50% 50%;\n animation: load-gauge var(--transition-length) ease both;\n animation-delay: 250ms;\n}\n\n.lh-gauge__svg-wrapper {\n position: relative;\n height: var(--gauge-circle-size);\n}\n.lh-category .lh-gauge__svg-wrapper,\n.lh-category .lh-fraction__wrapper {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n/* The plugin badge overlay */\n.lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size);\n height: var(--plugin-badge-size);\n background-color: var(--plugin-badge-background-color);\n background-image: var(--plugin-icon-url);\n background-repeat: no-repeat;\n background-size: var(--plugin-icon-size);\n background-position: 58% 50%;\n content: \"\";\n position: absolute;\n right: -6px;\n bottom: 0px;\n display: block;\n z-index: 100;\n box-shadow: 0 0 4px rgba(0,0,0,.2);\n border-radius: 25%;\n}\n.lh-category .lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size-big);\n height: var(--plugin-badge-size-big);\n}\n\n@keyframes load-gauge {\n from { stroke-dasharray: 0 352; }\n}\n\n.lh-gauge__percentage {\n width: 100%;\n height: var(--gauge-circle-size);\n position: absolute;\n font-family: var(--report-font-family-monospace);\n font-size: calc(var(--gauge-circle-size) * 0.34 + 1.3px);\n line-height: 0;\n text-align: center;\n top: calc(var(--score-container-padding) + var(--gauge-circle-size) / 2);\n}\n\n.lh-category .lh-gauge__percentage {\n --gauge-circle-size: var(--gauge-circle-size-big);\n --gauge-percentage-font-size: var(--gauge-percentage-font-size-big);\n}\n\n.lh-gauge__wrapper,\n.lh-fraction__wrapper {\n position: relative;\n display: flex;\n align-items: center;\n flex-direction: column;\n text-decoration: none;\n padding: var(--score-container-padding);\n\n --transition-length: 1s;\n\n /* Contain the layout style paint & layers during animation*/\n contain: content;\n will-change: opacity; /* Only using for layer promotion */\n}\n\n.lh-gauge__label,\n.lh-fraction__label {\n font-size: var(--gauge-label-font-size);\n font-weight: 500;\n line-height: var(--gauge-label-line-height);\n margin-top: 10px;\n text-align: center;\n color: var(--report-text-color);\n word-break: keep-all;\n}\n\n/* TODO(#8185) use more BEM (.lh-gauge__label--big) instead of relying on descendant selector */\n.lh-category .lh-gauge__label,\n.lh-category .lh-fraction__label {\n --gauge-label-font-size: var(--gauge-label-font-size-big);\n --gauge-label-line-height: var(--gauge-label-line-height-big);\n margin-top: 14px;\n}\n\n.lh-scores-header .lh-gauge__wrapper,\n.lh-scores-header .lh-fraction__wrapper,\n.lh-scores-header .lh-gauge--pwa__wrapper,\n.lh-sticky-header .lh-gauge__wrapper,\n.lh-sticky-header .lh-fraction__wrapper,\n.lh-sticky-header .lh-gauge--pwa__wrapper {\n width: var(--gauge-wrapper-width);\n}\n\n.lh-scorescale {\n display: inline-flex;\n\n gap: calc(var(--default-padding) * 4);\n margin: 16px auto 0 auto;\n font-size: var(--report-font-size-secondary);\n color: var(--color-gray-700);\n\n}\n\n.lh-scorescale-range {\n display: flex;\n align-items: center;\n font-family: var(--report-font-family-monospace);\n white-space: nowrap;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale {\n border: 0;\n display: flex;\n justify-content: center;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale-range {\n font-family: unset;\n font-size: 12px;\n}\n\n.lh-scorescale-wrap {\n display: contents;\n}\n\n/* Hide category score gauages if it's a single category report */\n.lh-header--solo-category .lh-scores-wrapper {\n display: none;\n}\n\n\n.lh-categories {\n width: 100%;\n}\n\n.lh-category {\n padding: var(--category-padding);\n max-width: var(--report-content-max-width);\n margin: 0 auto;\n\n scroll-margin-top: var(--sticky-header-buffer);\n}\n\n.lh-category-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n.lh-category-wrapper:last-of-type {\n border-bottom: 0;\n}\n\n.lh-category-header {\n margin-bottom: var(--section-padding-vertical);\n}\n\n.lh-category-header .lh-score__gauge {\n max-width: 400px;\n width: auto;\n margin: 0px auto;\n}\n\n.lh-category-header__finalscreenshot {\n display: grid;\n grid-template: none / 1fr 1px 1fr;\n justify-items: center;\n align-items: center;\n gap: var(--report-line-height);\n min-height: 288px;\n margin-bottom: var(--default-padding);\n}\n\n.lh-final-ss-image {\n /* constrain the size of the image to not be too large */\n max-height: calc(var(--gauge-circle-size-big) * 2.8);\n max-width: calc(var(--gauge-circle-size-big) * 3.5);\n border: 1px solid var(--color-gray-200);\n padding: 4px;\n border-radius: 3px;\n display: block;\n}\n\n.lh-category-headercol--separator {\n background: var(--color-gray-200);\n width: 1px;\n height: var(--gauge-circle-size-big);\n}\n\n@media screen and (max-width: 780px) {\n .lh-category-header__finalscreenshot {\n grid-template: 1fr 1fr / none\n }\n .lh-category-headercol--separator {\n display: none;\n }\n}\n\n\n/* 964 fits the min-width of the filmstrip */\n@media screen and (max-width: 964px) {\n .lh-report {\n margin-left: 0;\n width: 100%;\n }\n}\n\n@media print {\n body {\n -webkit-print-color-adjust: exact; /* print background colors */\n }\n .lh-container {\n display: block;\n }\n .lh-report {\n margin-left: 0;\n padding-top: 0;\n }\n .lh-categories {\n margin-top: 0;\n }\n}\n\n.lh-table {\n position: relative;\n border-collapse: separate;\n border-spacing: 0;\n /* Can't assign padding to table, so shorten the width instead. */\n width: calc(100% - var(--audit-description-padding-left) - var(--stackpack-padding-horizontal));\n border: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-table thead th {\n position: sticky;\n top: calc(var(--sticky-header-buffer) + 1em);\n z-index: 1;\n background-color: var(--report-background-color);\n border-bottom: 1px solid var(--report-border-color-secondary);\n font-weight: normal;\n color: var(--color-gray-600);\n /* See text-wrapping comment on .lh-container. */\n word-break: normal;\n}\n\n.lh-row--group {\n background-color: var(--table-group-header-background-color);\n}\n\n.lh-row--group td {\n font-weight: bold;\n font-size: 1.05em;\n color: var(--table-group-header-text-color);\n}\n\n.lh-row--group td:first-child {\n font-weight: normal;\n}\n\n.lh-row--group .lh-text {\n color: inherit;\n text-decoration: none;\n display: inline-block;\n}\n\n.lh-row--group a.lh-link:hover {\n text-decoration: underline;\n}\n\n.lh-row--group .lh-audit__adorn {\n text-transform: capitalize;\n font-weight: normal;\n padding: 2px 3px 1px 3px;\n}\n\n.lh-row--group .lh-audit__adorn1p {\n color: var(--link-color);\n border-color: var(--link-color);\n}\n\n.lh-row--group .lh-report-icon--external::before {\n content: \"\";\n background-repeat: no-repeat;\n width: 14px;\n height: 16px;\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n\n.lh-row--group .lh-report-icon--external {\n display: none;\n}\n\n.lh-row--group:hover .lh-report-icon--external {\n display: inline-block;\n}\n\n.lh-dark .lh-report-icon--external::before {\n filter: invert(1);\n}\n\n/** Manages indentation of two-level and three-level nested adjacent rows */\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) td:first-child {\n padding-left: 20px;\n}\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) ~ .lh-sub-item-row td:first-child {\n padding-left: 40px;\n}\n\n.lh-row--even {\n background-color: var(--table-group-header-background-color);\n}\n.lh-row--hidden {\n display: none;\n}\n\n.lh-table th,\n.lh-table td {\n padding: var(--default-padding);\n}\n\n.lh-table tr {\n vertical-align: middle;\n}\n\n.lh-table tr:hover {\n background-color: var(--table-higlight-background-color);\n}\n\n/* Looks unnecessary, but mostly for keeping the s left-aligned */\n.lh-table-column--text,\n.lh-table-column--source-location,\n.lh-table-column--url,\n/* .lh-table-column--thumbnail, */\n/* .lh-table-column--empty,*/\n.lh-table-column--code,\n.lh-table-column--node {\n text-align: left;\n}\n\n.lh-table-column--code {\n min-width: 100px;\n}\n\n.lh-table-column--bytes,\n.lh-table-column--timespanMs,\n.lh-table-column--ms,\n.lh-table-column--numeric {\n text-align: right;\n word-break: normal;\n}\n\n\n\n.lh-table .lh-table-column--thumbnail {\n width: var(--image-preview-size);\n}\n\n.lh-table-column--url {\n min-width: 250px;\n}\n\n.lh-table-column--text {\n min-width: 80px;\n}\n\n/* Keep columns narrow if they follow the URL column */\n/* 12% was determined to be a decent narrow width, but wide enough for column headings */\n.lh-table-column--url + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--ms,\n.lh-table-column--url + .lh-table-column--ms + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--timespanMs {\n width: 12%;\n}\n\n.lh-text__url-host {\n display: inline;\n}\n\n.lh-text__url-host {\n margin-left: calc(var(--report-font-size) / 2);\n opacity: 0.6;\n font-size: 90%\n}\n\n.lh-thumbnail {\n object-fit: cover;\n width: var(--image-preview-size);\n height: var(--image-preview-size);\n display: block;\n}\n\n.lh-unknown pre {\n overflow: scroll;\n border: solid 1px var(--color-gray-200);\n}\n\n.lh-text__url > a {\n color: inherit;\n text-decoration: none;\n}\n\n.lh-text__url > a:hover {\n text-decoration: underline dotted #999;\n}\n\n.lh-sub-item-row {\n margin-left: 20px;\n margin-bottom: 0;\n color: var(--color-gray-700);\n}\n\n.lh-sub-item-row td {\n padding-top: 4px;\n padding-bottom: 4px;\n padding-left: 20px;\n}\n\n/* Chevron\n https://codepen.io/paulirish/pen/LmzEmK\n */\n.lh-chevron {\n --chevron-angle: 42deg;\n /* Edge doesn't support transform: rotate(calc(...)), so we define it here */\n --chevron-angle-right: -42deg;\n width: var(--chevron-size);\n height: var(--chevron-size);\n margin-top: calc((var(--report-line-height) - 12px) / 2);\n}\n\n.lh-chevron__lines {\n transition: transform 0.4s;\n transform: translateY(var(--report-line-height));\n}\n.lh-chevron__line {\n stroke: var(--chevron-line-stroke);\n stroke-width: var(--chevron-size);\n stroke-linecap: square;\n transform-origin: 50%;\n transform: rotate(var(--chevron-angle));\n transition: transform 300ms, stroke 300ms;\n}\n\n.lh-expandable-details .lh-chevron__line-right,\n.lh-expandable-details[open] .lh-chevron__line-left {\n transform: rotate(var(--chevron-angle-right));\n}\n\n.lh-expandable-details[open] .lh-chevron__line-right {\n transform: rotate(var(--chevron-angle));\n}\n\n\n.lh-expandable-details[open] .lh-chevron__lines {\n transform: translateY(calc(var(--chevron-size) * -1));\n}\n\n.lh-expandable-details[open] {\n animation: 300ms openDetails forwards;\n padding-bottom: var(--default-padding);\n}\n\n@keyframes openDetails {\n from {\n outline: 1px solid var(--report-background-color);\n }\n to {\n outline: 1px solid;\n box-shadow: 0 2px 4px rgba(0, 0, 0, .24);\n }\n}\n\n@media screen and (max-width: 780px) {\n /* no black outline if we're not confident the entire table can be displayed within bounds */\n .lh-expandable-details[open] {\n animation: none;\n }\n}\n\n.lh-expandable-details[open] summary, details.lh-clump > summary {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\ndetails.lh-clump[open] > summary {\n border-bottom-width: 0;\n}\n\n\n\ndetails .lh-clump-toggletext--hide,\ndetails[open] .lh-clump-toggletext--show { display: none; }\ndetails[open] .lh-clump-toggletext--hide { display: block;}\n\n\n/* Tooltip */\n.lh-tooltip-boundary {\n position: relative;\n}\n\n.lh-tooltip {\n position: absolute;\n display: none; /* Don't retain these layers when not needed */\n opacity: 0;\n background: #ffffff;\n white-space: pre-line; /* Render newlines in the text */\n min-width: 246px;\n max-width: 275px;\n padding: 15px;\n border-radius: 5px;\n text-align: initial;\n line-height: 1.4;\n}\n/* shrink tooltips to not be cutoff on left edge of narrow viewports\n 45vw is chosen to be ~= width of the left column of metrics\n*/\n@media screen and (max-width: 535px) {\n .lh-tooltip {\n min-width: 45vw;\n padding: 3vw;\n }\n}\n\n.lh-tooltip-boundary:hover .lh-tooltip {\n display: block;\n animation: fadeInTooltip 250ms;\n animation-fill-mode: forwards;\n animation-delay: 850ms;\n bottom: 100%;\n z-index: 1;\n will-change: opacity;\n right: 0;\n pointer-events: none;\n}\n\n.lh-tooltip::before {\n content: \"\";\n border: solid transparent;\n border-bottom-color: #fff;\n border-width: 10px;\n position: absolute;\n bottom: -20px;\n right: 6px;\n transform: rotate(180deg);\n pointer-events: none;\n}\n\n@keyframes fadeInTooltip {\n 0% { opacity: 0; }\n 75% { opacity: 1; }\n 100% { opacity: 1; filter: drop-shadow(1px 0px 1px #aaa) drop-shadow(0px 2px 4px hsla(206, 6%, 25%, 0.15)); pointer-events: auto; }\n}\n\n/* Element screenshot */\n.lh-element-screenshot {\n float: left;\n margin-right: 20px;\n}\n.lh-element-screenshot__content {\n overflow: hidden;\n min-width: 110px;\n display: flex;\n justify-content: center;\n background-color: var(--report-background-color);\n}\n.lh-element-screenshot__image {\n position: relative;\n /* Set by ElementScreenshotRenderer.installFullPageScreenshotCssVariable */\n background-image: var(--element-screenshot-url);\n outline: 2px solid #777;\n background-color: white;\n background-repeat: no-repeat;\n}\n.lh-element-screenshot__mask {\n position: absolute;\n background: #555;\n opacity: 0.8;\n}\n.lh-element-screenshot__element-marker {\n position: absolute;\n outline: 2px solid var(--color-lime-400);\n}\n.lh-element-screenshot__overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 2000; /* .lh-topbar is 1000 */\n background: var(--screenshot-overlay-background);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: zoom-out;\n}\n\n.lh-element-screenshot__overlay .lh-element-screenshot {\n margin-right: 0; /* clearing margin used in thumbnail case */\n outline: 1px solid var(--color-gray-700);\n}\n\n.lh-screenshot-overlay--enabled .lh-element-screenshot {\n cursor: zoom-out;\n}\n.lh-screenshot-overlay--enabled .lh-node .lh-element-screenshot {\n cursor: zoom-in;\n}\n\n\n.lh-meta__items {\n --meta-icon-size: calc(var(--report-icon-size) * 0.667);\n padding: var(--default-padding);\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n background-color: var(--env-item-background-color);\n border-radius: 3px;\n margin: 0 0 var(--default-padding) 0;\n font-size: 12px;\n column-gap: var(--default-padding);\n color: var(--color-gray-700);\n}\n\n.lh-meta__item {\n display: block;\n list-style-type: none;\n position: relative;\n padding: 0 0 0 calc(var(--meta-icon-size) + var(--default-padding) * 2);\n cursor: unset; /* disable pointer cursor from report-icon */\n}\n\n.lh-meta__item.lh-tooltip-boundary {\n text-decoration: dotted underline var(--color-gray-500);\n cursor: help;\n}\n\n.lh-meta__item.lh-report-icon::before {\n position: absolute;\n left: var(--default-padding);\n width: var(--meta-icon-size);\n height: var(--meta-icon-size);\n}\n\n.lh-meta__item.lh-report-icon:hover::before {\n opacity: 0.7;\n}\n\n.lh-meta__item .lh-tooltip {\n color: var(--color-gray-800);\n}\n\n.lh-meta__item .lh-tooltip::before {\n right: auto; /* Set the tooltip arrow to the leftside */\n left: 6px;\n}\n\n/* Change the grid for narrow viewport. */\n@media screen and (max-width: 640px) {\n .lh-meta__items {\n grid-template-columns: 1fr 1fr;\n }\n}\n@media screen and (max-width: 535px) {\n .lh-meta__items {\n display: block;\n }\n}\n\n\n/*# sourceURL=report-styles.css */\n"); el0.append(el1); return el0; } diff --git a/report/renderer/performance-category-renderer.js b/report/renderer/performance-category-renderer.js index 0701d56402c0..ef69993b5e18 100644 --- a/report/renderer/performance-category-renderer.js +++ b/report/renderer/performance-category-renderer.js @@ -218,6 +218,17 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { return {overallImpact: 0, overallLinearImpact: 0}; } + /** + * @param {number} impact + * @param {number | undefined} guidanceLevel + * @return {number} + */ + rank(impact, guidanceLevel) { + const glKnob = 1; + const impactKnob = 1; + return guidanceLevel ? (guidanceLevel ** glKnob) * (impact ** impactKnob) : impact; + } + /** * @param {LH.ReportResult.Category} category * @param {Object} groups @@ -340,16 +351,23 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { // console.log(bOverallImpact, bOverallLinearImpact); // console.log(aOverallImpact === bOverallImpact, bOverallLinearImpact); // } - if (aOverallImpact !== bOverallImpact) return bOverallImpact - aOverallImpact; + // higher impact is first. + // LH.Audit() + const aRank = this.rank(aOverallImpact, a.result.guidanceLevel); + const bRank = this.rank(bOverallImpact, b.result.guidanceLevel); + + if (aOverallImpact !== bOverallImpact) return bRank - aRank; if ( aOverallImpact === 0 && bOverallImpact === 0 && aOverallLinearImpact !== bOverallLinearImpact ) { - return bOverallLinearImpact - aOverallLinearImpact; + // If there's no impact, just use Guidance Level. + return this.rank(1, b.result.guidanceLevel) - this.rank(1, a.result.guidanceLevel); } const scoreA = a.result.scoreDisplayMode === 'informative' ? 100 : Number(a.result.score); const scoreB = b.result.scoreDisplayMode === 'informative' ? 100 : Number(b.result.score); + console.log('sorting', a.id, 'by score...'); return scoreA - scoreB; }); @@ -384,7 +402,8 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { console.log('Weighted', k, 'impact: ', weightedMetricImpact); } } - console.log(a.id, 'overall impact:', overallImpact); + const gl = a.result.guidanceLevel ? a.result.guidanceLevel : 0; + console.log(a.id, 'overall impact:', overallImpact, 'guidance level:', gl); } }); diff --git a/types/lhr/audit-result.d.ts b/types/lhr/audit-result.d.ts index 9b4b043d0126..e6c0e751e01f 100644 --- a/types/lhr/audit-result.d.ts +++ b/types/lhr/audit-result.d.ts @@ -72,4 +72,5 @@ export interface Result { p10: number; median: number; }; + guidanceLevel?: number; } From 6a642add45da429b14332e9341eecff78425fd41 Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Thu, 31 Aug 2023 16:04:12 -0700 Subject: [PATCH 06/31] add gl to impact, rm dependency on score --- .../renderer/performance-category-renderer.js | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/report/renderer/performance-category-renderer.js b/report/renderer/performance-category-renderer.js index ef69993b5e18..8e14a21fe3ca 100644 --- a/report/renderer/performance-category-renderer.js +++ b/report/renderer/performance-category-renderer.js @@ -361,49 +361,56 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { aOverallImpact === 0 && bOverallImpact === 0 && aOverallLinearImpact !== bOverallLinearImpact ) { - // If there's no impact, just use Guidance Level. - return this.rank(1, b.result.guidanceLevel) - this.rank(1, a.result.guidanceLevel); + // try sorting by linear impact + gl. + return this.rank(bOverallLinearImpact, b.result.guidanceLevel) - + this.rank(aOverallLinearImpact, a.result.guidanceLevel); } - const scoreA = a.result.scoreDisplayMode === 'informative' ? 100 : Number(a.result.score); - const scoreB = b.result.scoreDisplayMode === 'informative' ? 100 : Number(b.result.score); - console.log('sorting', a.id, 'by score...'); - return scoreA - scoreB; + // If there's no impact at all, just use Guidance Level. + // const scoreA = a.result.scoreDisplayMode === 'informative' ? 100 : Number(a.result.score); + // const scoreB = b.result.scoreDisplayMode === 'informative' ? 100 : Number(b.result.score); + // console.log('sorting', a.id, 'by score...'); + // return scoreA - scoreB; + return this.rank(1, b.result.guidanceLevel) - + this.rank(1, a.result.guidanceLevel); }); + console.log('in order audits:', diagnosticAudits); // TODO: rm this. just for console logging purposes. diagnosticAudits.forEach(a => { if (a.result.metricSavings) { let overallImpact = 0; + let overallLinearImpact = 0; for (const [k, savings] of Object.entries(a.result.metricSavings)) { // Get metric savings for individual audit. // Don't do anything if we don't have savings for a metric. if (savings === undefined) continue; // Get the metric data. - const mAudit = metricAudits.find(a => a.acronym === k); + const mAudit = metricAudits.find(audit => audit.acronym === k); if (!mAudit) continue; if (mAudit.result.score === null) continue; const mValue = mAudit.result.numericValue; - if (mValue === undefined) continue; + if (!mValue) continue; const scoringOptions = mAudit.result.scoringOptions; if (!scoringOptions) continue; - const newMetricScore = Util.computeLogNormalScore(scoringOptions, mValue - savings); + const linearImpact = savings / mValue * mAudit.weight; + overallLinearImpact += linearImpact; + // only if there's a diff between old & new. - if (newMetricScore !== mAudit.result.score) { - console.log(a.id, 'New:', newMetricScore, 'Old:', mAudit.result.score); - // This is the impact on the metric. how do you find the impact on the score (how to calculate overall impact score)? - const weightedMetricImpact = (newMetricScore - mAudit.result.score) * mAudit.weight; - overallImpact += weightedMetricImpact; + // if (newMetricScore !== mAudit.result.score) { + // console.log(audit.id, 'New:', newMetricScore, 'Old:', mAudit.result.score); + const newMetricScore = Util.computeLogNormalScore(scoringOptions, mValue - savings); + const weightedMetricImpact = (newMetricScore - mAudit.result.score) * mAudit.weight; + overallImpact += weightedMetricImpact; - console.log('Weighted', k, 'impact: ', weightedMetricImpact); - } + // eslint-disable-next-line max-len + console.log(a.id, 'impact: ', overallImpact, 'linear impact:', overallLinearImpact, 'guidance level:', a.result.guidanceLevel); + // } } - const gl = a.result.guidanceLevel ? a.result.guidanceLevel : 0; - console.log(a.id, 'overall impact:', overallImpact, 'guidance level:', gl); } }); From 9838c9c6b36bd6fe8ec59b114448248b118f3ab6 Mon Sep 17 00:00:00 2001 From: Adam Raine Date: Fri, 1 Sep 2023 14:12:04 -0700 Subject: [PATCH 07/31] fall back to old sort --- .../renderer/performance-category-renderer.js | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/report/renderer/performance-category-renderer.js b/report/renderer/performance-category-renderer.js index 8e14a21fe3ca..881a54c40c98 100644 --- a/report/renderer/performance-category-renderer.js +++ b/report/renderer/performance-category-renderer.js @@ -220,13 +220,13 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { /** * @param {number} impact - * @param {number | undefined} guidanceLevel + * @param {number} guidanceLevel * @return {number} */ rank(impact, guidanceLevel) { const glKnob = 1; const impactKnob = 1; - return guidanceLevel ? (guidanceLevel ** glKnob) * (impact ** impactKnob) : impact; + return (guidanceLevel ** glKnob) * (impact ** impactKnob); } /** @@ -345,6 +345,9 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { overallLinearImpact: bOverallLinearImpact, } = this.overallImpact(b, metricAudits); + const aGuidanceLevel = a.result.guidanceLevel || 1; + const bGuidanceLevel = b.result.guidanceLevel || 1; + // if (a.id === 'unsized-images') { // console.log('######'); // console.log(aOverallImpact, aOverallLinearImpact); @@ -353,26 +356,25 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { // } // higher impact is first. // LH.Audit() - const aRank = this.rank(aOverallImpact, a.result.guidanceLevel); - const bRank = this.rank(bOverallImpact, b.result.guidanceLevel); - + const aRank = this.rank(aOverallImpact, aGuidanceLevel); + const bRank = this.rank(bOverallImpact, bGuidanceLevel); if (aOverallImpact !== bOverallImpact) return bRank - aRank; + if ( aOverallImpact === 0 && bOverallImpact === 0 && aOverallLinearImpact !== bOverallLinearImpact ) { // try sorting by linear impact + gl. - return this.rank(bOverallLinearImpact, b.result.guidanceLevel) - - this.rank(aOverallLinearImpact, a.result.guidanceLevel); + return this.rank(bOverallLinearImpact, bGuidanceLevel) - + this.rank(aOverallLinearImpact, bGuidanceLevel); } + if (aGuidanceLevel !== bGuidanceLevel) return bGuidanceLevel - aGuidanceLevel; + // If there's no impact at all, just use Guidance Level. - // const scoreA = a.result.scoreDisplayMode === 'informative' ? 100 : Number(a.result.score); - // const scoreB = b.result.scoreDisplayMode === 'informative' ? 100 : Number(b.result.score); - // console.log('sorting', a.id, 'by score...'); - // return scoreA - scoreB; - return this.rank(1, b.result.guidanceLevel) - - this.rank(1, a.result.guidanceLevel); + const scoreA = a.result.scoreDisplayMode === 'informative' ? 100 : Number(a.result.score); + const scoreB = b.result.scoreDisplayMode === 'informative' ? 100 : Number(b.result.score); + return scoreA - scoreB; }); console.log('in order audits:', diagnosticAudits); From be2455b94c1f890d17af8affa55bc87731896266 Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Wed, 6 Sep 2023 14:27:09 -0700 Subject: [PATCH 08/31] remove guidance level from main sort --- .../renderer/performance-category-renderer.js | 114 +----------------- 1 file changed, 5 insertions(+), 109 deletions(-) diff --git a/report/renderer/performance-category-renderer.js b/report/renderer/performance-category-renderer.js index 881a54c40c98..afdcded20ba7 100644 --- a/report/renderer/performance-category-renderer.js +++ b/report/renderer/performance-category-renderer.js @@ -201,34 +201,15 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { const linearImpact = savings / mValue * mAudit.weight; overallLinearImpact += linearImpact; - // only if there's a diff between old & new. - if (newMetricScore !== mAudit.result.score) { - // console.log(audit.id, 'New:', newMetricScore, 'Old:', mAudit.result.score); - // This is the impact on the metric. how do you find the impact on the score (how to calculate overall impact score)? - const weightedMetricImpact = (newMetricScore - mAudit.result.score) * mAudit.weight; - overallImpact += weightedMetricImpact; - - // console.log('Weighted', k, 'impact: ', weightedMetricImpact); - } + const weightedMetricImpact = (newMetricScore - mAudit.result.score) * mAudit.weight; + overallImpact += weightedMetricImpact; } - // console.log('overall impact: ', overallImpact); return {overallImpact, overallLinearImpact}; } return {overallImpact: 0, overallLinearImpact: 0}; } - /** - * @param {number} impact - * @param {number} guidanceLevel - * @return {number} - */ - rank(impact, guidanceLevel) { - const glKnob = 1; - const impactKnob = 1; - return (guidanceLevel ** glKnob) * (impact ** impactKnob); - } - /** * @param {LH.ReportResult.Category} category * @param {Object} groups @@ -296,46 +277,13 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { filmstripEl && timelineEl.append(filmstripEl); } - // Opportunities - /* const opportunityAudits = category.auditRefs - .filter(audit => this._classifyPerformanceAudit(audit) === 'load-opportunity') - .filter(audit => !ReportUtils.showAsPassed(audit.result)) - .sort((auditA, auditB) => this._getWastedMs(auditB) - this._getWastedMs(auditA)); - - const filterableMetrics = metricAudits.filter(a => !!a.relevantAudits); - // TODO: only add if there are opportunities & diagnostics rendered. - if (filterableMetrics.length) { - this.renderMetricAuditFilter(filterableMetrics, element); - } - - if (opportunityAudits.length) { - // Scale the sparklines relative to savings, minimum 2s to not overstate small savings - const minimumScale = 2000; - const wastedMsValues = opportunityAudits.map(audit => this._getWastedMs(audit)); - const maxWaste = Math.max(...wastedMsValues); - const scale = Math.max(Math.ceil(maxWaste / 1000) * 1000, minimumScale); - const [groupEl, footerEl] = this.renderAuditGroup(groups['load-opportunities']); - const tmpl = this.dom.createComponent('opportunityHeader'); - - this.dom.find('.lh-load-opportunity__col--one', tmpl).textContent = - strings.opportunityResourceColumnLabel; - this.dom.find('.lh-load-opportunity__col--two', tmpl).textContent = - strings.opportunitySavingsColumnLabel; - - const headerEl = this.dom.find('.lh-load-opportunity__header', tmpl); - groupEl.insertBefore(headerEl, footerEl); - opportunityAudits.forEach(item => - groupEl.insertBefore(this._renderOpportunity(item, scale), footerEl)); - groupEl.classList.add('lh-audit-group--load-opportunities'); - element.append(groupEl); - } */ - // Diagnostics const diagnosticAudits = category.auditRefs // All audits here. .filter(audit => this._classifyPerformanceAudit(audit)) .filter(audit => !ReportUtils.showAsPassed(audit.result)) .sort((a, b) => { + // Sort by impact. const { overallImpact: aOverallImpact, overallLinearImpact: aOverallLinearImpact, @@ -348,74 +296,22 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { const aGuidanceLevel = a.result.guidanceLevel || 1; const bGuidanceLevel = b.result.guidanceLevel || 1; - // if (a.id === 'unsized-images') { - // console.log('######'); - // console.log(aOverallImpact, aOverallLinearImpact); - // console.log(bOverallImpact, bOverallLinearImpact); - // console.log(aOverallImpact === bOverallImpact, bOverallLinearImpact); - // } - // higher impact is first. - // LH.Audit() - const aRank = this.rank(aOverallImpact, aGuidanceLevel); - const bRank = this.rank(bOverallImpact, bGuidanceLevel); - if (aOverallImpact !== bOverallImpact) return bRank - aRank; + if (aOverallImpact !== bOverallImpact) return bOverallImpact - aOverallImpact; if ( aOverallImpact === 0 && bOverallImpact === 0 && aOverallLinearImpact !== bOverallLinearImpact ) { - // try sorting by linear impact + gl. - return this.rank(bOverallLinearImpact, bGuidanceLevel) - - this.rank(aOverallLinearImpact, bGuidanceLevel); + return bOverallLinearImpact - aOverallLinearImpact; } if (aGuidanceLevel !== bGuidanceLevel) return bGuidanceLevel - aGuidanceLevel; - // If there's no impact at all, just use Guidance Level. const scoreA = a.result.scoreDisplayMode === 'informative' ? 100 : Number(a.result.score); const scoreB = b.result.scoreDisplayMode === 'informative' ? 100 : Number(b.result.score); return scoreA - scoreB; }); - console.log('in order audits:', diagnosticAudits); - // TODO: rm this. just for console logging purposes. - diagnosticAudits.forEach(a => { - if (a.result.metricSavings) { - let overallImpact = 0; - let overallLinearImpact = 0; - for (const [k, savings] of Object.entries(a.result.metricSavings)) { - // Get metric savings for individual audit. - // Don't do anything if we don't have savings for a metric. - if (savings === undefined) continue; - - // Get the metric data. - const mAudit = metricAudits.find(audit => audit.acronym === k); - if (!mAudit) continue; - if (mAudit.result.score === null) continue; - - const mValue = mAudit.result.numericValue; - if (!mValue) continue; - - const scoringOptions = mAudit.result.scoringOptions; - if (!scoringOptions) continue; - - const linearImpact = savings / mValue * mAudit.weight; - overallLinearImpact += linearImpact; - - // only if there's a diff between old & new. - // if (newMetricScore !== mAudit.result.score) { - // console.log(audit.id, 'New:', newMetricScore, 'Old:', mAudit.result.score); - const newMetricScore = Util.computeLogNormalScore(scoringOptions, mValue - savings); - const weightedMetricImpact = (newMetricScore - mAudit.result.score) * mAudit.weight; - overallImpact += weightedMetricImpact; - - // eslint-disable-next-line max-len - console.log(a.id, 'impact: ', overallImpact, 'linear impact:', overallLinearImpact, 'guidance level:', a.result.guidanceLevel); - // } - } - } - }); - if (diagnosticAudits.length) { const [groupEl, footerEl] = this.renderAuditGroup(groups['diagnostics']); diagnosticAudits.forEach(item => groupEl.insertBefore(this.renderAudit(item), footerEl)); From 212be08a0269e4b61c9cd3f8514e4b85ec4623e0 Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Fri, 8 Sep 2023 16:09:56 -0700 Subject: [PATCH 09/31] add metrics filter back --- report/renderer/performance-category-renderer.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/report/renderer/performance-category-renderer.js b/report/renderer/performance-category-renderer.js index afdcded20ba7..f829e0484e9c 100644 --- a/report/renderer/performance-category-renderer.js +++ b/report/renderer/performance-category-renderer.js @@ -183,7 +183,6 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { let overallLinearImpact = 0; for (const [k, savings] of Object.entries(audit.result.metricSavings)) { // Get metric savings for individual audit. - // Don't do anything if we don't have savings for a metric. if (savings === undefined) continue; // Get the metric data. @@ -277,6 +276,12 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { filmstripEl && timelineEl.append(filmstripEl); } + const filterableMetrics = metricAudits.filter(a => !!a.relevantAudits); + // TODO: only add if there are opportunities & diagnostics rendered. + if (filterableMetrics.length) { + this.renderMetricAuditFilter(filterableMetrics, element); + } + // Diagnostics const diagnosticAudits = category.auditRefs // All audits here. From 5f0f5f797f24af36bf8949d97e46f3c94ccbc38c Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Fri, 8 Sep 2023 16:20:29 -0700 Subject: [PATCH 10/31] sample json --- .../reports/sample-flow-result.json | 349 ++++++++++++------ core/test/results/sample_v2.json | 136 +++++-- 2 files changed, 341 insertions(+), 144 deletions(-) diff --git a/core/test/fixtures/user-flows/reports/sample-flow-result.json b/core/test/fixtures/user-flows/reports/sample-flow-result.json index 3ae678ddf526..cb3fc4bfd008 100644 --- a/core/test/fixtures/user-flows/reports/sample-flow-result.json +++ b/core/test/fixtures/user-flows/reports/sample-flow-result.json @@ -41,7 +41,8 @@ "warnings": [], "metricSavings": { "INP": 0 - } + }, + "guidanceLevel": 3 }, "first-contentful-paint": { "id": "first-contentful-paint", @@ -253,7 +254,8 @@ } ], "overallSavingsMs": 0 - } + }, + "guidanceLevel": 1 }, "interactive": { "id": "interactive", @@ -322,7 +324,8 @@ "timingType": "Mark" } ] - } + }, + "guidanceLevel": 2 }, "critical-request-chains": { "id": "critical-request-chains", @@ -349,7 +352,8 @@ "length": 1, "transferSize": 3558 } - } + }, + "guidanceLevel": 1 }, "redirects": { "id": "redirects", @@ -369,7 +373,8 @@ "headings": [], "items": [], "overallSavingsMs": 0 - } + }, + "guidanceLevel": 2 }, "installable-manifest": { "id": "installable-manifest", @@ -560,7 +565,8 @@ "sortedBy": [ "duration" ] - } + }, + "guidanceLevel": 1 }, "bootup-time": { "id": "bootup-time", @@ -624,7 +630,8 @@ "sortedBy": [ "total" ] - } + }, + "guidanceLevel": 1 }, "uses-rel-preload": { "id": "uses-rel-preload", @@ -637,7 +644,8 @@ "headings": [], "items": [], "overallSavingsMs": 0 - } + }, + "guidanceLevel": 3 }, "uses-rel-preconnect": { "id": "uses-rel-preconnect", @@ -661,7 +669,8 @@ "sortedBy": [ "wastedMs" ] - } + }, + "guidanceLevel": 3 }, "font-display": { "id": "font-display", @@ -674,7 +683,8 @@ "type": "table", "headings": [], "items": [] - } + }, + "guidanceLevel": 3 }, "diagnostics": { "id": "diagnostics", @@ -1406,6 +1416,9 @@ "score": 1, "scoreDisplayMode": "binary", "displayValue": "Third-party code blocked the main thread for 0 ms", + "metricSavings": { + "TBT": 0 + }, "details": { "type": "table", "headings": [ @@ -1470,14 +1483,19 @@ "wastedMs": 0 }, "isEntityGrouped": true - } + }, + "guidanceLevel": 1 }, "third-party-facades": { "id": "third-party-facades", "title": "Lazy load third-party resources with facades", "description": "Some third-party embeds can be lazy loaded. Consider replacing them with a facade until they are required. [Learn how to defer third-parties with a facade](https://developer.chrome.com/docs/lighthouse/performance/third-party-facades/).", "score": null, - "scoreDisplayMode": "notApplicable" + "scoreDisplayMode": "notApplicable", + "metricSavings": { + "TBT": 0 + }, + "guidanceLevel": 3 }, "largest-contentful-paint-element": { "id": "largest-contentful-paint-element", @@ -1486,6 +1504,9 @@ "score": null, "scoreDisplayMode": "informative", "displayValue": "1,370 ms", + "metricSavings": { + "LCP": 0 + }, "details": { "type": "list", "items": [ @@ -1562,7 +1583,8 @@ ] } ] - } + }, + "guidanceLevel": 1 }, "lcp-lazy-loaded": { "id": "lcp-lazy-loaded", @@ -1570,6 +1592,9 @@ "description": "Above-the-fold images that are lazily loaded render later in the page lifecycle, which can delay the largest contentful paint. [Learn more about optimal lazy loading](https://web.dev/lcp-lazy-loading/).", "score": 1, "scoreDisplayMode": "binary", + "metricSavings": { + "LCP": 0 + }, "details": { "type": "table", "headings": [ @@ -1599,7 +1624,8 @@ } } ] - } + }, + "guidanceLevel": 3 }, "layout-shift-elements": { "id": "layout-shift-elements", @@ -1723,7 +1749,8 @@ "score": 0.00036762719987422577 } ] - } + }, + "guidanceLevel": 2 }, "long-tasks": { "id": "long-tasks", @@ -1807,7 +1834,8 @@ } ] } - } + }, + "guidanceLevel": 1 }, "no-unload-listeners": { "id": "no-unload-listeners", @@ -1829,7 +1857,8 @@ "type": "table", "headings": [], "items": [] - } + }, + "guidanceLevel": 2 }, "unsized-images": { "id": "unsized-images", @@ -1875,7 +1904,8 @@ } } ] - } + }, + "guidanceLevel": 3 }, "valid-source-maps": { "id": "valid-source-maps", @@ -1923,7 +1953,8 @@ ], "pathLength": 2 } - } + }, + "guidanceLevel": 3 }, "csp-xss": { "id": "csp-xss", @@ -2747,7 +2778,8 @@ "type": "table", "headings": [], "items": [] - } + }, + "guidanceLevel": 3 }, "total-byte-weight": { "id": "total-byte-weight", @@ -2817,7 +2849,8 @@ "sortedBy": [ "totalBytes" ] - } + }, + "guidanceLevel": 1 }, "offscreen-images": { "id": "offscreen-images", @@ -2849,7 +2882,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "render-blocking-resources": { "id": "render-blocking-resources", @@ -2868,7 +2902,8 @@ "headings": [], "items": [], "overallSavingsMs": 0 - } + }, + "guidanceLevel": 2 }, "unminified-css": { "id": "unminified-css", @@ -2899,7 +2934,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 3 }, "unminified-javascript": { "id": "unminified-javascript", @@ -2931,7 +2967,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 3 }, "unused-css-rules": { "id": "unused-css-rules", @@ -2962,7 +2999,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "unused-javascript": { "id": "unused-javascript", @@ -2993,7 +3031,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "modern-image-formats": { "id": "modern-image-formats", @@ -3025,7 +3064,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 3 }, "uses-optimized-images": { "id": "uses-optimized-images", @@ -3057,7 +3097,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "uses-text-compression": { "id": "uses-text-compression", @@ -3088,7 +3129,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 3 }, "uses-responsive-images": { "id": "uses-responsive-images", @@ -3119,7 +3161,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "efficient-animated-content": { "id": "efficient-animated-content", @@ -3150,7 +3193,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 3 }, "duplicated-javascript": { "id": "duplicated-javascript", @@ -3181,7 +3225,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "legacy-javascript": { "id": "legacy-javascript", @@ -3256,7 +3301,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "doctype": { "id": "doctype", @@ -3281,6 +3327,9 @@ "numericValue": 70, "numericUnit": "element", "displayValue": "70 elements", + "metricSavings": { + "TBT": 0 + }, "details": { "type": "table", "headings": [ @@ -3358,7 +3407,8 @@ } } ] - } + }, + "guidanceLevel": 1 }, "geolocation-on-start": { "id": "geolocation-on-start", @@ -3394,7 +3444,8 @@ "type": "table", "headings": [], "items": [] - } + }, + "guidanceLevel": 2 }, "js-libraries": { "id": "js-libraries", @@ -3481,7 +3532,8 @@ "type": "table", "headings": [], "items": [] - } + }, + "guidanceLevel": 3 }, "meta-description": { "id": "meta-description", @@ -3653,7 +3705,8 @@ "title": "Page didn't prevent back/forward cache restoration", "description": "Many navigations are performed by going back to a previous page, or forwards again. The back/forward cache (bfcache) can speed up these return navigations. [Learn more about the bfcache](https://developer.chrome.com/docs/lighthouse/performance/bf-cache/)", "score": 1, - "scoreDisplayMode": "binary" + "scoreDisplayMode": "binary", + "guidanceLevel": 2 } }, "configSettings": { @@ -8578,7 +8631,8 @@ "timingType": "Mark" } ] - } + }, + "guidanceLevel": 2 }, "image-aspect-ratio": { "id": "image-aspect-ratio", @@ -8810,7 +8864,8 @@ "sortedBy": [ "duration" ] - } + }, + "guidanceLevel": 1 }, "bootup-time": { "id": "bootup-time", @@ -8874,7 +8929,8 @@ "sortedBy": [ "total" ] - } + }, + "guidanceLevel": 1 }, "network-requests": { "id": "network-requests", @@ -9472,6 +9528,9 @@ "score": 1, "scoreDisplayMode": "binary", "displayValue": "Third-party code blocked the main thread for 0 ms", + "metricSavings": { + "TBT": 0 + }, "details": { "type": "table", "headings": [ @@ -9529,7 +9588,8 @@ "wastedMs": 0 }, "isEntityGrouped": true - } + }, + "guidanceLevel": 1 }, "layout-shift-elements": { "id": "layout-shift-elements", @@ -9577,7 +9637,8 @@ "score": 0.13125 } ] - } + }, + "guidanceLevel": 2 }, "long-tasks": { "id": "long-tasks", @@ -9637,7 +9698,8 @@ } ] } - } + }, + "guidanceLevel": 1 }, "no-unload-listeners": { "id": "no-unload-listeners", @@ -9659,7 +9721,8 @@ "type": "table", "headings": [], "items": [] - } + }, + "guidanceLevel": 2 }, "unsized-images": { "id": "unsized-images", @@ -9705,7 +9768,8 @@ } } ] - } + }, + "guidanceLevel": 3 }, "valid-source-maps": { "id": "valid-source-maps", @@ -9896,7 +9960,8 @@ "skipSumming": [ "cacheLifetimeMs" ] - } + }, + "guidanceLevel": 3 }, "total-byte-weight": { "id": "total-byte-weight", @@ -9966,7 +10031,8 @@ "sortedBy": [ "totalBytes" ] - } + }, + "guidanceLevel": 1 }, "unminified-css": { "id": "unminified-css", @@ -9997,7 +10063,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 3 }, "unminified-javascript": { "id": "unminified-javascript", @@ -10029,7 +10096,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 3 }, "unused-css-rules": { "id": "unused-css-rules", @@ -10060,7 +10128,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "unused-javascript": { "id": "unused-javascript", @@ -10091,7 +10160,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "modern-image-formats": { "id": "modern-image-formats", @@ -10123,7 +10193,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 3 }, "uses-optimized-images": { "id": "uses-optimized-images", @@ -10155,7 +10226,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "uses-text-compression": { "id": "uses-text-compression", @@ -10186,7 +10258,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 3 }, "uses-responsive-images": { "id": "uses-responsive-images", @@ -10217,7 +10290,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "efficient-animated-content": { "id": "efficient-animated-content", @@ -10248,7 +10322,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 3 }, "duplicated-javascript": { "id": "duplicated-javascript", @@ -10279,7 +10354,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "legacy-javascript": { "id": "legacy-javascript", @@ -10310,7 +10386,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "inspector-issues": { "id": "inspector-issues", @@ -10334,7 +10411,8 @@ "type": "table", "headings": [], "items": [] - } + }, + "guidanceLevel": 2 }, "uses-passive-event-listeners": { "id": "uses-passive-event-listeners", @@ -10346,7 +10424,8 @@ "type": "table", "headings": [], "items": [] - } + }, + "guidanceLevel": 3 }, "work-during-interaction": { "id": "work-during-interaction", @@ -10539,14 +10618,16 @@ } } ] - } + }, + "guidanceLevel": 1 }, "bf-cache": { "id": "bf-cache", "title": "Page didn't prevent back/forward cache restoration", "description": "Many navigations are performed by going back to a previous page, or forwards again. The back/forward cache (bfcache) can speed up these return navigations. [Learn more about the bfcache](https://developer.chrome.com/docs/lighthouse/performance/bf-cache/)", "score": 1, - "scoreDisplayMode": "binary" + "scoreDisplayMode": "binary", + "guidanceLevel": 2 } }, "configSettings": { @@ -12326,7 +12407,8 @@ "warnings": [], "metricSavings": { "INP": 0 - } + }, + "guidanceLevel": 3 }, "image-aspect-ratio": { "id": "image-aspect-ratio", @@ -12519,7 +12601,8 @@ } } ] - } + }, + "guidanceLevel": 3 }, "accesskeys": { "id": "accesskeys", @@ -14327,7 +14410,8 @@ "actualDimensions": "1000x450" } ] - } + }, + "guidanceLevel": 2 }, "doctype": { "id": "doctype", @@ -14345,6 +14429,7 @@ "numericValue": 361, "numericUnit": "element", "displayValue": "361 elements", + "metricSavings": {}, "details": { "type": "table", "headings": [ @@ -14422,7 +14507,8 @@ } } ] - } + }, + "guidanceLevel": 1 }, "js-libraries": { "id": "js-libraries", @@ -17555,7 +17641,8 @@ "warnings": [], "metricSavings": { "INP": 0 - } + }, + "guidanceLevel": 3 }, "first-contentful-paint": { "id": "first-contentful-paint", @@ -17767,7 +17854,8 @@ } ], "overallSavingsMs": 0 - } + }, + "guidanceLevel": 1 }, "interactive": { "id": "interactive", @@ -17836,7 +17924,8 @@ "timingType": "Mark" } ] - } + }, + "guidanceLevel": 2 }, "critical-request-chains": { "id": "critical-request-chains", @@ -17863,7 +17952,8 @@ "length": 1, "transferSize": 3596 } - } + }, + "guidanceLevel": 1 }, "redirects": { "id": "redirects", @@ -17883,7 +17973,8 @@ "headings": [], "items": [], "overallSavingsMs": 0 - } + }, + "guidanceLevel": 2 }, "installable-manifest": { "id": "installable-manifest", @@ -18074,7 +18165,8 @@ "sortedBy": [ "duration" ] - } + }, + "guidanceLevel": 1 }, "bootup-time": { "id": "bootup-time", @@ -18144,7 +18236,8 @@ "sortedBy": [ "total" ] - } + }, + "guidanceLevel": 1 }, "uses-rel-preload": { "id": "uses-rel-preload", @@ -18157,7 +18250,8 @@ "headings": [], "items": [], "overallSavingsMs": 0 - } + }, + "guidanceLevel": 3 }, "uses-rel-preconnect": { "id": "uses-rel-preconnect", @@ -18181,7 +18275,8 @@ "sortedBy": [ "wastedMs" ] - } + }, + "guidanceLevel": 3 }, "font-display": { "id": "font-display", @@ -18194,7 +18289,8 @@ "type": "table", "headings": [], "items": [] - } + }, + "guidanceLevel": 3 }, "diagnostics": { "id": "diagnostics", @@ -18884,6 +18980,9 @@ "score": 1, "scoreDisplayMode": "binary", "displayValue": "Third-party code blocked the main thread for 0 ms", + "metricSavings": { + "TBT": 0 + }, "details": { "type": "table", "headings": [ @@ -18929,14 +19028,19 @@ } ], "isEntityGrouped": true - } + }, + "guidanceLevel": 1 }, "third-party-facades": { "id": "third-party-facades", "title": "Lazy load third-party resources with facades", "description": "Some third-party embeds can be lazy loaded. Consider replacing them with a facade until they are required. [Learn how to defer third-parties with a facade](https://developer.chrome.com/docs/lighthouse/performance/third-party-facades/).", "score": null, - "scoreDisplayMode": "notApplicable" + "scoreDisplayMode": "notApplicable", + "metricSavings": { + "TBT": 0 + }, + "guidanceLevel": 3 }, "largest-contentful-paint-element": { "id": "largest-contentful-paint-element", @@ -18945,6 +19049,9 @@ "score": null, "scoreDisplayMode": "informative", "displayValue": "1,800 ms", + "metricSavings": { + "LCP": 0 + }, "details": { "type": "list", "items": [ @@ -19021,7 +19128,8 @@ ] } ] - } + }, + "guidanceLevel": 1 }, "lcp-lazy-loaded": { "id": "lcp-lazy-loaded", @@ -19029,6 +19137,9 @@ "description": "Above-the-fold images that are lazily loaded render later in the page lifecycle, which can delay the largest contentful paint. [Learn more about optimal lazy loading](https://web.dev/lcp-lazy-loading/).", "score": 1, "scoreDisplayMode": "binary", + "metricSavings": { + "LCP": 0 + }, "details": { "type": "table", "headings": [ @@ -19058,7 +19169,8 @@ } } ] - } + }, + "guidanceLevel": 3 }, "layout-shift-elements": { "id": "layout-shift-elements", @@ -19073,7 +19185,8 @@ "type": "table", "headings": [], "items": [] - } + }, + "guidanceLevel": 2 }, "long-tasks": { "id": "long-tasks", @@ -19144,7 +19257,8 @@ } ] } - } + }, + "guidanceLevel": 1 }, "no-unload-listeners": { "id": "no-unload-listeners", @@ -19166,7 +19280,8 @@ "type": "table", "headings": [], "items": [] - } + }, + "guidanceLevel": 2 }, "unsized-images": { "id": "unsized-images", @@ -19231,7 +19346,8 @@ } } ] - } + }, + "guidanceLevel": 3 }, "valid-source-maps": { "id": "valid-source-maps", @@ -19279,7 +19395,8 @@ ], "pathLength": 2 } - } + }, + "guidanceLevel": 3 }, "csp-xss": { "id": "csp-xss", @@ -20140,7 +20257,8 @@ "type": "table", "headings": [], "items": [] - } + }, + "guidanceLevel": 3 }, "total-byte-weight": { "id": "total-byte-weight", @@ -20190,7 +20308,8 @@ "sortedBy": [ "totalBytes" ] - } + }, + "guidanceLevel": 1 }, "offscreen-images": { "id": "offscreen-images", @@ -20222,7 +20341,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "render-blocking-resources": { "id": "render-blocking-resources", @@ -20241,7 +20361,8 @@ "headings": [], "items": [], "overallSavingsMs": 0 - } + }, + "guidanceLevel": 2 }, "unminified-css": { "id": "unminified-css", @@ -20272,7 +20393,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 3 }, "unminified-javascript": { "id": "unminified-javascript", @@ -20304,7 +20426,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 3 }, "unused-css-rules": { "id": "unused-css-rules", @@ -20335,7 +20458,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "unused-javascript": { "id": "unused-javascript", @@ -20366,7 +20490,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "modern-image-formats": { "id": "modern-image-formats", @@ -20444,7 +20569,8 @@ "LCP": 330 } } - } + }, + "guidanceLevel": 3 }, "uses-optimized-images": { "id": "uses-optimized-images", @@ -20476,7 +20602,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "uses-text-compression": { "id": "uses-text-compression", @@ -20507,7 +20634,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 3 }, "uses-responsive-images": { "id": "uses-responsive-images", @@ -20582,7 +20710,8 @@ "LCP": 300 } } - } + }, + "guidanceLevel": 2 }, "efficient-animated-content": { "id": "efficient-animated-content", @@ -20613,7 +20742,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 3 }, "duplicated-javascript": { "id": "duplicated-javascript", @@ -20644,7 +20774,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "legacy-javascript": { "id": "legacy-javascript", @@ -20719,7 +20850,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "doctype": { "id": "doctype", @@ -20744,6 +20876,9 @@ "numericValue": 81, "numericUnit": "element", "displayValue": "81 elements", + "metricSavings": { + "TBT": 0 + }, "details": { "type": "table", "headings": [ @@ -20821,7 +20956,8 @@ } } ] - } + }, + "guidanceLevel": 1 }, "geolocation-on-start": { "id": "geolocation-on-start", @@ -20857,7 +20993,8 @@ "type": "table", "headings": [], "items": [] - } + }, + "guidanceLevel": 2 }, "js-libraries": { "id": "js-libraries", @@ -20944,7 +21081,8 @@ "type": "table", "headings": [], "items": [] - } + }, + "guidanceLevel": 3 }, "meta-description": { "id": "meta-description", @@ -21173,7 +21311,8 @@ "title": "Page didn't prevent back/forward cache restoration", "description": "Many navigations are performed by going back to a previous page, or forwards again. The back/forward cache (bfcache) can speed up these return navigations. [Learn more about the bfcache](https://developer.chrome.com/docs/lighthouse/performance/bf-cache/)", "score": 1, - "scoreDisplayMode": "binary" + "scoreDisplayMode": "binary", + "guidanceLevel": 2 } }, "configSettings": { diff --git a/core/test/results/sample_v2.json b/core/test/results/sample_v2.json index e757799710e7..e18904e1c3dd 100644 --- a/core/test/results/sample_v2.json +++ b/core/test/results/sample_v2.json @@ -55,7 +55,8 @@ "warnings": [], "metricSavings": { "INP": 0 - } + }, + "guidanceLevel": 3 }, "first-contentful-paint": { "id": "first-contentful-paint", @@ -356,7 +357,8 @@ } ], "overallSavingsMs": 468.46799999999996 - } + }, + "guidanceLevel": 1 }, "interactive": { "id": "interactive", @@ -634,7 +636,8 @@ "timingType": "Mark" } ] - } + }, + "guidanceLevel": 2 }, "critical-request-chains": { "id": "critical-request-chains", @@ -771,7 +774,8 @@ "length": 2, "transferSize": 903 } - } + }, + "guidanceLevel": 1 }, "redirects": { "id": "redirects", @@ -791,7 +795,8 @@ "headings": [], "items": [], "overallSavingsMs": 0 - } + }, + "guidanceLevel": 2 }, "installable-manifest": { "id": "installable-manifest", @@ -1081,7 +1086,8 @@ "sortedBy": [ "duration" ] - } + }, + "guidanceLevel": 1 }, "bootup-time": { "id": "bootup-time", @@ -1145,7 +1151,8 @@ "sortedBy": [ "total" ] - } + }, + "guidanceLevel": 1 }, "uses-rel-preload": { "id": "uses-rel-preload", @@ -1158,7 +1165,8 @@ "headings": [], "items": [], "overallSavingsMs": 0 - } + }, + "guidanceLevel": 3 }, "uses-rel-preconnect": { "id": "uses-rel-preconnect", @@ -1182,7 +1190,8 @@ "sortedBy": [ "wastedMs" ] - } + }, + "guidanceLevel": 3 }, "font-display": { "id": "font-display", @@ -1195,7 +1204,8 @@ "type": "table", "headings": [], "items": [] - } + }, + "guidanceLevel": 3 }, "diagnostics": { "id": "diagnostics", @@ -2180,6 +2190,9 @@ "score": 1, "scoreDisplayMode": "binary", "displayValue": "Third-party code blocked the main thread for 0 ms", + "metricSavings": { + "TBT": 23.424291876693196 + }, "details": { "type": "table", "headings": [ @@ -2237,14 +2250,19 @@ "wastedMs": 0 }, "isEntityGrouped": true - } + }, + "guidanceLevel": 1 }, "third-party-facades": { "id": "third-party-facades", "title": "Lazy load third-party resources with facades", "description": "Some third-party embeds can be lazy loaded. Consider replacing them with a facade until they are required. [Learn how to defer third-parties with a facade](https://developer.chrome.com/docs/lighthouse/performance/third-party-facades/).", "score": null, - "scoreDisplayMode": "notApplicable" + "scoreDisplayMode": "notApplicable", + "metricSavings": { + "TBT": 0 + }, + "guidanceLevel": 3 }, "largest-contentful-paint-element": { "id": "largest-contentful-paint-element", @@ -2253,6 +2271,9 @@ "score": null, "scoreDisplayMode": "informative", "displayValue": "13,320 ms", + "metricSavings": { + "LCP": 10819.961 + }, "details": { "type": "list", "items": [ @@ -2329,14 +2350,19 @@ ] } ] - } + }, + "guidanceLevel": 1 }, "lcp-lazy-loaded": { "id": "lcp-lazy-loaded", "title": "Largest Contentful Paint image was not lazily loaded", "description": "Above-the-fold images that are lazily loaded render later in the page lifecycle, which can delay the largest contentful paint. [Learn more about optimal lazy loading](https://web.dev/lcp-lazy-loading/).", "score": null, - "scoreDisplayMode": "notApplicable" + "scoreDisplayMode": "notApplicable", + "metricSavings": { + "LCP": 0 + }, + "guidanceLevel": 3 }, "layout-shift-elements": { "id": "layout-shift-elements", @@ -2460,7 +2486,8 @@ "score": 0.004071364067636093 } ] - } + }, + "guidanceLevel": 2 }, "long-tasks": { "id": "long-tasks", @@ -2537,7 +2564,8 @@ } ] } - } + }, + "guidanceLevel": 1 }, "no-unload-listeners": { "id": "no-unload-listeners", @@ -2628,7 +2656,8 @@ } } ] - } + }, + "guidanceLevel": 2 }, "unsized-images": { "id": "unsized-images", @@ -2693,7 +2722,8 @@ } } ] - } + }, + "guidanceLevel": 3 }, "valid-source-maps": { "id": "valid-source-maps", @@ -2786,7 +2816,8 @@ ], "pathLength": 4 } - } + }, + "guidanceLevel": 3 }, "csp-xss": { "id": "csp-xss", @@ -4203,7 +4234,8 @@ "skipSumming": [ "cacheLifetimeMs" ] - } + }, + "guidanceLevel": 3 }, "total-byte-weight": { "id": "total-byte-weight", @@ -4273,7 +4305,8 @@ "sortedBy": [ "totalBytes" ] - } + }, + "guidanceLevel": 1 }, "offscreen-images": { "id": "offscreen-images", @@ -4305,7 +4338,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "render-blocking-resources": { "id": "render-blocking-resources", @@ -4372,7 +4406,8 @@ } ], "overallSavingsMs": 0 - } + }, + "guidanceLevel": 2 }, "unminified-css": { "id": "unminified-css", @@ -4403,7 +4438,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 3 }, "unminified-javascript": { "id": "unminified-javascript", @@ -4458,7 +4494,8 @@ "LCP": 300 } } - } + }, + "guidanceLevel": 3 }, "unused-css-rules": { "id": "unused-css-rules", @@ -4489,7 +4526,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "unused-javascript": { "id": "unused-javascript", @@ -4559,7 +4597,8 @@ "LCP": 450 } } - } + }, + "guidanceLevel": 2 }, "modern-image-formats": { "id": "modern-image-formats", @@ -4677,7 +4716,8 @@ "LCP": 450 } } - } + }, + "guidanceLevel": 3 }, "uses-optimized-images": { "id": "uses-optimized-images", @@ -4709,7 +4749,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "uses-text-compression": { "id": "uses-text-compression", @@ -4767,7 +4808,8 @@ "LCP": 750 } } - } + }, + "guidanceLevel": 3 }, "uses-responsive-images": { "id": "uses-responsive-images", @@ -4798,7 +4840,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "efficient-animated-content": { "id": "efficient-animated-content", @@ -4851,7 +4894,8 @@ "LCP": 3300 } } - } + }, + "guidanceLevel": 3 }, "duplicated-javascript": { "id": "duplicated-javascript", @@ -4882,7 +4926,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "legacy-javascript": { "id": "legacy-javascript", @@ -4967,7 +5012,8 @@ "LCP": 0 } } - } + }, + "guidanceLevel": 2 }, "doctype": { "id": "doctype", @@ -4992,6 +5038,9 @@ "numericValue": 153, "numericUnit": "element", "displayValue": "153 elements", + "metricSavings": { + "TBT": 1 + }, "details": { "type": "table", "headings": [ @@ -5069,7 +5118,8 @@ } } ] - } + }, + "guidanceLevel": 1 }, "geolocation-on-start": { "id": "geolocation-on-start", @@ -5164,7 +5214,8 @@ } } ] - } + }, + "guidanceLevel": 2 }, "js-libraries": { "id": "js-libraries", @@ -5306,12 +5357,17 @@ "scoreDisplayMode": "numeric", "numericValue": 0, "numericUnit": "millisecond", + "metricSavings": { + "LCP": 0, + "FCP": 0 + }, "details": { "type": "opportunity", "headings": [], "items": [], "overallSavingsMs": 0 - } + }, + "guidanceLevel": 3 }, "uses-passive-event-listeners": { "id": "uses-passive-event-listeners", @@ -5339,7 +5395,8 @@ } } ] - } + }, + "guidanceLevel": 3 }, "meta-description": { "id": "meta-description", @@ -5647,7 +5704,8 @@ "protocolReason": "BrowsingInstanceNotSwapped" } ] - } + }, + "guidanceLevel": 2 } }, "configSettings": { From 74d1cb9b39a8a04c66b2672a2de7b911dd7d04bc Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Wed, 20 Sep 2023 14:29:29 -0700 Subject: [PATCH 11/31] fix --- core/test/lib/statistics-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/test/lib/statistics-test.js b/core/test/lib/statistics-test.js index e676e0e1b465..f8bf571d3f23 100644 --- a/core/test/lib/statistics-test.js +++ b/core/test/lib/statistics-test.js @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as statistics from '../../lib/statistics.js'; +import * as statistics from '../../../shared/statistics.js'; describe('statistics', () => { describe('#getLogNormalScore', () => { From be716afdd01cb81408d24ca89756a2b4ffc4810f Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Thu, 21 Sep 2023 10:34:07 -0700 Subject: [PATCH 12/31] update proto --- proto/lighthouse-result.proto | 36 +++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/proto/lighthouse-result.proto b/proto/lighthouse-result.proto index d9080282df11..6f5dc7c2af2e 100644 --- a/proto/lighthouse-result.proto +++ b/proto/lighthouse-result.proto @@ -382,6 +382,42 @@ message AuditResult { // Stacktrace of error, if any occurred while processing the audit. string errorStack = 13; + + // Message containing the audit's MetricSavings. + message MetricSavings { + // Optional numeric value representing the audit's savings for the LCP metric. + optional google.protobuf.DoubleValue LCP = 1; + + // Optional numeric value representing the audit's savings for the FCP metric. + optional google.protobuf.DoubleValue FCP = 2; + + // Optional numeric value representing the audit's savings for the CLS metric. + optional google.protobuf.DoubleValue CLS = 3; + + // Optional numeric value representing the audit's savings for the TBT metric. + optional google.protobuf.DoubleValue TBT = 4; + + // Optional numeric value representing the audit's savings for the INP metric. + optional google.protobuf.DoubleValue INP = 5; + } + + // The audit's MetricSavings. + MetricSavings metricSavings = 14; + + // Message containing ScoringOptions. + message ScoringOptions { + // Scoring option's p10. + google.protobuf.DoubleValue p10 = 1; + + // Scoring option's median. + google.protobuf.DoubleValue median = 2; + } + + // The audit's ScoringOption. + ScoringOptions scoringOptions = 15; + + // An audit's guidance level. + google.protobuf.DoubleValue guidanceLevel = 16; } // Message containing the i18n data for the LHR - Version 1 From c2521ad4d89430feb74f391eec29ae1cae3bdc2a Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Thu, 21 Sep 2023 15:39:50 -0700 Subject: [PATCH 13/31] add tests --- .../performance-category-renderer-test.js | 164 ++++++++++++++++++ 1 file changed, 164 insertions(+) diff --git a/report/test/renderer/performance-category-renderer-test.js b/report/test/renderer/performance-category-renderer-test.js index 5177360340da..2f6d30ca4b7b 100644 --- a/report/test/renderer/performance-category-renderer-test.js +++ b/report/test/renderer/performance-category-renderer-test.js @@ -437,4 +437,168 @@ Array [ }); }); }); + + describe('prioritize audits by metricSavings', () => { + let metricAudits; + let defaultAuditRef; + let fakeCategory; + + before(() => { + metricAudits = category.auditRefs.filter(audit => audit.group === 'metrics'); + defaultAuditRef = { + title: '', + description: '', + scoreDisplayMode: 'numeric', + warnings: [], + }; + fakeCategory = { + id: 'performance', + title: 'Performance', + score: 0.5, + supportedModes: category.supportedModes, + }; + }); + + it('audits in order of most impact metric savings first', () => { + fakeCategory = { + id: 'performance', + title: 'Performance', + score: 0.5, + supportedModes: category.supportedModes, + }; + + fakeCategory.auditRefs = [{ + id: 'audit-1', + result: { + id: 'audit-1', + metricSavings: {'LCP': 50, 'FCP': 5}, + score: 0, + ...defaultAuditRef, + }, + }, { + id: 'audit-2', + result: { + id: 'audit-2', + score: 0.5, + ...defaultAuditRef, + }, + }, { + id: 'audit-3', + result: { + id: 'audit-3', + score: 0, + metricSavings: {'LCP': 50, 'FCP': 15}, + ...defaultAuditRef, + }, + }, { + id: 'audit-4', + result: { + id: 'audit-4', + score: 0, + metricSavings: {'FCP': 15}, + ...defaultAuditRef, + }, + }, + ...metricAudits]; + + const categoryDOM = renderer.render(fakeCategory, sampleResults.categoryGroups); + const diagnosticSection = categoryDOM.querySelector( + '.lh-category > .lh-audit-group.lh-audit-group--diagnostics'); + const diagnosticElementIds = [...diagnosticSection.querySelectorAll('.lh-audit')]; + expect(diagnosticElementIds.map(el => el.id)).toEqual(['audit-3', 'audit-1', 'audit-4', 'audit-2']); // eslint-disable-line max-len + }); + + it('audits sorted with guidance level', () => { + fakeCategory.auditRefs = [{ + id: 'audit-1', + result: { + id: 'audit-1', + metricSavings: {'LCP': 50, 'FCP': 5}, + score: 0, + ...defaultAuditRef, + }, + }, { + id: 'audit-2', + result: { + id: 'audit-2', + score: 0.5, + guidanceLevel: 3, + ...defaultAuditRef, + }, + }, { + id: 'audit-3', + result: { + id: 'audit-3', + score: 0, + metricSavings: {'LCP': 50, 'FCP': 5}, + guidanceLevel: 3, + ...defaultAuditRef, + }, + }, { + id: 'audit-4', + result: { + id: 'audit-4', + score: 0.5, + guidanceLevel: 2, + ...defaultAuditRef, + }, + }, { + id: 'audit-5', + result: { + id: 'audit-5', + score: 0.5, + ...defaultAuditRef, + }, + }, + ...metricAudits]; + + const categoryDOM = renderer.render(fakeCategory, sampleResults.categoryGroups); + const diagnosticSection = categoryDOM.querySelector( + '.lh-category > .lh-audit-group.lh-audit-group--diagnostics'); + const diagnosticElementIds = [...diagnosticSection.querySelectorAll('.lh-audit')]; + expect(diagnosticElementIds.map(el => el.id)).toEqual(['audit-3', 'audit-1', 'audit-2', 'audit-4', 'audit-5']); // eslint-disable-line max-len + }); + + it('audits without impact and guidance level sorted', () => { + fakeCategory.auditRefs = [{ + id: 'audit-1', + result: { + id: 'audit-1', + metricSavings: {'LCP': 50, 'FCP': 5}, + score: 0, + ...defaultAuditRef, + }, + }, { + id: 'audit-2', + result: { + id: 'audit-2', + score: 0, + weight: 10, + ...defaultAuditRef, + }, + }, { + id: 'audit-3', + result: { + id: 'audit-3', + score: 0, + guidanceLevel: 2, + ...defaultAuditRef, + }, + }, { + id: 'audit-4', + result: { + id: 'audit-4', + score: 0.5, + ...defaultAuditRef, + }, + }, + ...metricAudits]; + + const categoryDOM = renderer.render(fakeCategory, sampleResults.categoryGroups); + const diagnosticSection = categoryDOM.querySelector( + '.lh-category > .lh-audit-group.lh-audit-group--diagnostics'); + const diagnosticElementIds = [...diagnosticSection.querySelectorAll('.lh-audit')]; + expect(diagnosticElementIds.map(el => el.id)).toEqual(['audit-1', 'audit-3', 'audit-2', 'audit-4']); // eslint-disable-line max-len + }); + }); }); From 8b1fd6520ae9a6b22b0cb3edd99c60ea097b7387 Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Thu, 21 Sep 2023 18:35:29 -0700 Subject: [PATCH 14/31] nit --- report/renderer/components.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/report/renderer/components.js b/report/renderer/components.js index 9d6e7662b262..e0f6c0254629 100644 --- a/report/renderer/components.js +++ b/report/renderer/components.js @@ -520,7 +520,7 @@ function createSnippetLineComponent(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 --report-icon-size: var(--score-icon-background-size);\n --report-line-height: 24px;\n --report-line-height-secondary: 20px;\n --report-monospace-font-size: calc(var(--report-font-size) * 0.85);\n --report-text-color-secondary: var(--color-gray-800);\n --report-text-color: var(--color-gray-900);\n --report-content-max-width: calc(60 * var(--report-font-size)); /* defaults to 840px */\n --report-content-min-width: 360px;\n --report-content-max-width-minus-edge-gap: calc(var(--report-content-max-width) - var(--edge-gap-padding) * 2);\n --score-container-padding: 8px;\n --score-icon-background-size: 24px;\n --score-icon-margin-left: 6px;\n --score-icon-margin-right: 14px;\n --score-icon-margin: 0 var(--score-icon-margin-right) 0 var(--score-icon-margin-left);\n --score-icon-size: 12px;\n --score-icon-size-big: 16px;\n --screenshot-overlay-background: rgba(0, 0, 0, 0.3);\n --section-padding-vertical: calc(var(--default-padding) * 6);\n --snippet-background-color: var(--color-gray-50);\n --snippet-color: #0938C2;\n --sparkline-height: 5px;\n --stackpack-padding-horizontal: 10px;\n --sticky-header-background-color: var(--report-background-color);\n --sticky-header-buffer: calc(var(--topbar-height) + var(--sticky-header-height));\n --sticky-header-height: calc(var(--gauge-circle-size-sm) + var(--score-container-padding) * 2);\n --table-group-header-background-color: #EEF1F4;\n --table-group-header-text-color: var(--color-gray-700);\n --table-higlight-background-color: #F5F7FA;\n --tools-icon-color: var(--color-gray-600);\n --topbar-background-color: var(--color-white);\n --topbar-height: 32px;\n --topbar-logo-size: 24px;\n --topbar-padding: 0 8px;\n --toplevel-warning-background-color: hsla(30, 100%, 75%, 10%);\n --toplevel-warning-message-text-color: var(--color-average-secondary);\n --toplevel-warning-padding: 18px;\n --toplevel-warning-text-color: var(--report-text-color);\n\n /* SVGs */\n --plugin-icon-url-dark: url('data:image/svg+xml;utf8,');\n --plugin-icon-url: url('data:image/svg+xml;utf8,');\n\n --pass-icon-url: url('data:image/svg+xml;utf8,check');\n --average-icon-url: url('data:image/svg+xml;utf8,info');\n --fail-icon-url: url('data:image/svg+xml;utf8,warn');\n --error-icon-url: url('data:image/svg+xml;utf8,error');\n\n --pwa-installable-gray-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-gray-url-dark: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url-dark: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-color-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-color-url: url('data:image/svg+xml;utf8,');\n\n --swap-locale-icon-url: url('data:image/svg+xml;utf8,');\n}\n\n@media not print {\n .lh-dark {\n /* Pallete */\n --color-gray-200: var(--color-gray-800);\n --color-gray-300: #616161;\n --color-gray-400: var(--color-gray-600);\n --color-gray-700: var(--color-gray-400);\n --color-gray-50: #757575;\n --color-gray-600: var(--color-gray-500);\n --color-green-700: var(--color-green);\n --color-orange-700: var(--color-orange);\n --color-red-700: var(--color-red);\n --color-teal-600: var(--color-cyan-500);\n\n /* Context-specific colors */\n --color-hover: rgba(0, 0, 0, 0.2);\n --color-informative: var(--color-blue-200);\n\n /* Component variables */\n --env-item-background-color: #393535;\n --link-color: var(--color-blue-200);\n --locale-selector-background-color: var(--color-gray-200);\n --plugin-badge-background-color: var(--color-gray-800);\n --report-background-color: var(--color-gray-900);\n --report-border-color-secondary: var(--color-gray-200);\n --report-text-color-secondary: var(--color-gray-400);\n --report-text-color: var(--color-gray-100);\n --snippet-color: var(--color-cyan-500);\n --topbar-background-color: var(--color-gray);\n --toplevel-warning-background-color: hsl(33deg 14% 18%);\n --toplevel-warning-message-text-color: var(--color-orange-700);\n --toplevel-warning-text-color: var(--color-gray-100);\n --table-group-header-background-color: rgba(186, 196, 206, 0.15);\n --table-group-header-text-color: var(--color-gray-100);\n --table-higlight-background-color: rgba(186, 196, 206, 0.09);\n\n /* SVGs */\n --plugin-icon-url: var(--plugin-icon-url-dark);\n --pwa-installable-gray-url: var(--pwa-installable-gray-url-dark);\n --pwa-optimized-gray-url: var(--pwa-optimized-gray-url-dark);\n }\n}\n\n@media only screen and (max-width: 480px) {\n .lh-vars {\n --audit-group-margin-bottom: 20px;\n --edge-gap-padding: var(--default-padding);\n --env-name-min-width: 120px;\n --gauge-circle-size-big: 96px;\n --gauge-circle-size: 72px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 112px;\n --header-padding: 16px 0 16px 0;\n --image-preview-size: 24px;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-size: 14px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --topbar-height: 28px;\n --topbar-logo-size: 20px;\n }\n\n /* Not enough space to adequately show the relative savings bars. */\n .lh-sparkline {\n display: none;\n }\n}\n\n.lh-vars.lh-devtools {\n --audit-explanation-line-height: 14px;\n --audit-group-margin-bottom: 20px;\n --audit-group-padding-vertical: 12px;\n --audit-padding-vertical: 4px;\n --category-padding: 12px;\n --default-padding: 12px;\n --env-name-min-width: 120px;\n --footer-padding-vertical: 8px;\n --gauge-circle-size-big: 72px;\n --gauge-circle-size: 64px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 97px;\n --header-line-height: 20px;\n --header-padding: 16px 0 16px 0;\n --screenshot-overlay-background: transparent;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-family-monospace: 'Menlo', 'dejavu sans mono', 'Consolas', 'Lucida Console', monospace;\n --report-font-family: '.SFNSDisplay-Regular', 'Helvetica Neue', 'Lucida Grande', sans-serif;\n --report-font-size: 12px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --section-padding-vertical: 8px;\n}\n\n.lh-container:not(.lh-topbar + .lh-container) {\n --topbar-height: 0;\n --sticky-header-height: 0;\n --sticky-header-buffer: 0;\n}\n\n.lh-devtools.lh-root {\n height: 100%;\n}\n.lh-devtools.lh-root img {\n /* Override devtools default 'min-width: 0' so svg without size in a flexbox isn't collapsed. */\n min-width: auto;\n}\n.lh-devtools .lh-container {\n overflow-y: scroll;\n height: calc(100% - var(--topbar-height));\n /** The .lh-container is the scroll parent in DevTools so we exclude the topbar from the sticky header buffer. */\n --sticky-header-buffer: calc(var(--sticky-header-height));\n}\n@media print {\n .lh-devtools .lh-container {\n overflow: unset;\n }\n}\n.lh-devtools .lh-sticky-header {\n /* This is normally the height of the topbar, but we want it to stick to the top of our scroll container .lh-container` */\n top: 0;\n}\n.lh-devtools .lh-element-screenshot__overlay {\n position: absolute;\n}\n\n@keyframes fadeIn {\n 0% { opacity: 0;}\n 100% { opacity: 0.6;}\n}\n\n.lh-root *, .lh-root *::before, .lh-root *::after {\n box-sizing: border-box;\n}\n\n.lh-root {\n font-family: var(--report-font-family);\n font-size: var(--report-font-size);\n margin: 0;\n line-height: var(--report-line-height);\n background: var(--report-background-color);\n color: var(--report-text-color);\n}\n\n.lh-root :focus-visible {\n outline: -webkit-focus-ring-color auto 3px;\n}\n.lh-root summary:focus {\n outline: none;\n box-shadow: 0 0 0 1px hsl(217, 89%, 61%);\n}\n\n.lh-root [hidden] {\n display: none !important;\n}\n\n.lh-root pre {\n margin: 0;\n}\n\n.lh-root pre,\n.lh-root code {\n font-family: var(--report-font-family-monospace);\n}\n\n.lh-root details > summary {\n cursor: pointer;\n}\n\n.lh-hidden {\n display: none !important;\n}\n\n.lh-container {\n /*\n Text wrapping in the report is so much FUN!\n We have a `word-break: break-word;` globally here to prevent a few common scenarios, namely\n long non-breakable text (usually URLs) found in:\n 1. The footer\n 2. .lh-node (outerHTML)\n 3. .lh-code\n\n With that sorted, the next challenge is appropriate column sizing and text wrapping inside our\n .lh-details tables. Even more fun.\n * We don't want table headers (\"Potential Savings (ms)\") to wrap or their column values, but\n we'd be happy for the URL column to wrap if the URLs are particularly long.\n * We want the narrow columns to remain narrow, providing the most column width for URL\n * We don't want the table to extend past 100% width.\n * Long URLs in the URL column can wrap. Util.getURLDisplayName maxes them out at 64 characters,\n but they do not get any overflow:ellipsis treatment.\n */\n word-break: break-word;\n}\n\n.lh-audit-group a,\n.lh-category-header__description a,\n.lh-audit__description a,\n.lh-warnings a,\n.lh-footer a,\n.lh-table-column--link a {\n color: var(--link-color);\n}\n\n.lh-audit__description, .lh-audit__stackpack {\n --inner-audit-padding-right: var(--stackpack-padding-horizontal);\n padding-left: var(--audit-description-padding-left);\n padding-right: var(--inner-audit-padding-right);\n padding-top: 8px;\n padding-bottom: 8px;\n}\n\n.lh-details {\n margin-top: var(--default-padding);\n margin-bottom: var(--default-padding);\n margin-left: var(--audit-description-padding-left);\n /* whatever the .lh-details side margins are */\n width: 100%;\n}\n\n.lh-audit__stackpack {\n display: flex;\n align-items: center;\n}\n\n.lh-audit__stackpack__img {\n max-width: 30px;\n margin-right: var(--default-padding)\n}\n\n/* Report header */\n\n.lh-report-icon {\n display: flex;\n align-items: center;\n padding: 10px 12px;\n cursor: pointer;\n}\n.lh-report-icon[disabled] {\n opacity: 0.3;\n pointer-events: none;\n}\n\n.lh-report-icon::before {\n content: \"\";\n margin: 4px;\n background-repeat: no-repeat;\n width: var(--report-icon-size);\n height: var(--report-icon-size);\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n.lh-report-icon:hover::before {\n opacity: 1;\n}\n.lh-dark .lh-report-icon::before {\n filter: invert(1);\n}\n.lh-report-icon--print::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--copy::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--open::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--download::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--dark::before {\n background-image:url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--treemap::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--date::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--devices::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--world::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--stopwatch::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--networkspeed::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-one::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-many::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--chrome::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--external::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n\n.lh-buttons {\n display: flex;\n flex-wrap: wrap;\n margin: var(--default-padding) 0;\n}\n.lh-button {\n height: 32px;\n border: 1px solid var(--report-border-color-secondary);\n border-radius: 3px;\n color: var(--link-color);\n background-color: var(--report-background-color);\n margin: 5px;\n}\n\n.lh-button:first-of-type {\n margin-left: 0;\n}\n\n/* Node */\n.lh-node__snippet {\n font-family: var(--report-font-family-monospace);\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n line-height: 20px;\n}\n\n/* Score */\n\n/* to remove color indicators - test */\n/* .lh-audit__score-icon {\n opacity: 0;\n} */\n\n.lh-audit__score-icon {\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n margin: var(--score-icon-margin);\n}\n\n.lh-audit--pass .lh-audit__display-text {\n color: var(--color-pass-secondary);\n}\n.lh-audit--pass .lh-audit__score-icon,\n.lh-scorescale-range--pass::before {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-audit__display-text {\n color: var(--color-average-secondary);\n /* to remove color indicators - test */\n /* color: gray; */\n}\n.lh-audit--average .lh-audit__score-icon,\n.lh-scorescale-range--average::before {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-audit--fail .lh-audit__display-text {\n color: var(--color-fail-secondary);\n /* to remove color indicators - test */\n /* color: gray; */\n}\n.lh-audit--fail .lh-audit__score-icon,\n.lh-audit--error .lh-audit__score-icon,\n.lh-scorescale-range--fail::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-audit--error .lh-audit__score-icon,\n.lh-metric--error .lh-metric__icon {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n border: none;\n}\n\n.lh-gauge__wrapper--fail .lh-gauge--error {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n transform: scale(0.5);\n top: var(--score-container-padding);\n}\n\n.lh-audit--manual .lh-audit__display-text,\n.lh-audit--notapplicable .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n.lh-audit--manual .lh-audit__score-icon,\n.lh-audit--notapplicable .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n background: none;\n}\n\n.lh-audit--informative .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n\n.lh-audit--informative .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n}\n\n.lh-audit__description,\n.lh-audit__stackpack {\n color: var(--report-text-color-secondary);\n}\n.lh-audit__adorn {\n border: 1px solid var(--color-gray-500);\n border-radius: 3px;\n margin: 0 3px;\n padding: 0 2px;\n line-height: 1.1;\n display: inline-block;\n font-size: 90%;\n color: var(--report-text-color-secondary);\n}\n\n.lh-category-header__description {\n text-align: center;\n color: var(--color-gray-700);\n margin: 0px auto;\n max-width: 400px;\n}\n\n\n.lh-audit__display-text,\n.lh-load-opportunity__sparkline,\n.lh-chevron-container {\n margin: 0 var(--audit-margin-horizontal);\n}\n.lh-chevron-container {\n margin-right: 0;\n}\n\n.lh-audit__title-and-text {\n flex: 1;\n}\n\n.lh-audit__title-and-text code {\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n}\n\n/* Prepend display text with em dash separator. But not in Opportunities. */\n.lh-audit__display-text:not(:empty):before {\n content: '—';\n margin-right: var(--audit-margin-horizontal);\n}\n.lh-audit-group.lh-audit-group--load-opportunities .lh-audit__display-text:not(:empty):before {\n display: none;\n}\n\n/* Expandable Details (Audit Groups, Audits) */\n.lh-audit__header {\n display: flex;\n align-items: center;\n padding: var(--default-padding);\n}\n\n.lh-audit--load-opportunity .lh-audit__header {\n display: block;\n}\n\n\n.lh-metricfilter {\n display: grid;\n justify-content: end;\n align-items: center;\n grid-auto-flow: column;\n gap: 4px;\n color: var(--color-gray-700);\n}\n\n.lh-metricfilter__radio {\n /*\n * Instead of hiding, position offscreen so it's still accessible to screen readers\n * https://bugs.chromium.org/p/chromium/issues/detail?id=1439785\n */\n position: fixed;\n left: -9999px;\n}\n.lh-metricfilter input[type='radio']:focus-visible + label {\n outline: -webkit-focus-ring-color auto 1px;\n}\n\n.lh-metricfilter__label {\n display: inline-flex;\n padding: 0 4px;\n height: 16px;\n text-decoration: underline;\n align-items: center;\n cursor: pointer;\n font-size: 90%;\n}\n\n.lh-metricfilter__label--active {\n background: var(--color-blue-primary);\n color: var(--color-white);\n border-radius: 3px;\n text-decoration: none;\n}\n/* Give the 'All' choice a more muted display */\n.lh-metricfilter__label--active[for=\"metric-All\"] {\n background-color: var(--color-blue-200) !important;\n color: black !important;\n}\n\n.lh-metricfilter__text {\n margin-right: 8px;\n}\n\n/* If audits are filtered, hide the itemcount for Passed Audits… */\n.lh-category--filtered .lh-audit-group .lh-audit-group__itemcount {\n display: none;\n}\n\n\n.lh-audit__header:hover {\n background-color: var(--color-hover);\n}\n\n/* We want to hide the browser's default arrow marker on summary elements. Admittedly, it's complicated. */\n.lh-root details > summary {\n /* Blink 89+ and Firefox will hide the arrow when display is changed from (new) default of `list-item` to block. https://chromestatus.com/feature/6730096436051968*/\n display: block;\n}\n/* Safari and Blink <=88 require using the -webkit-details-marker selector */\n.lh-root details > summary::-webkit-details-marker {\n display: none;\n}\n\n/* Perf Metric */\n\n.lh-metrics-container {\n display: grid;\n grid-auto-rows: 1fr;\n grid-template-columns: 1fr 1fr;\n grid-column-gap: var(--report-line-height);\n margin-bottom: var(--default-padding);\n}\n\n.lh-metric {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(-n+2) {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-metric__innerwrap {\n display: grid;\n /**\n * Icon -- Metric Name\n * -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 1fr;\n align-items: center;\n padding: var(--default-padding);\n}\n\n.lh-metric__details {\n order: -1;\n}\n\n.lh-metric__title {\n flex: 1;\n}\n\n.lh-calclink {\n padding-left: calc(1ex / 3);\n}\n\n.lh-metric__description {\n display: none;\n grid-column-start: 2;\n grid-column-end: 4;\n color: var(--report-text-color-secondary);\n}\n\n.lh-metric__value {\n font-size: var(--metric-value-font-size);\n margin: calc(var(--default-padding) / 2) 0;\n white-space: nowrap; /* No wrapping between metric value and the icon */\n grid-column-start: 2;\n}\n\n\n@media screen and (max-width: 535px) {\n .lh-metrics-container {\n display: block;\n }\n\n .lh-metric {\n border-bottom: none !important;\n }\n .lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(1) {\n border-bottom: 1px solid var(--report-border-color-secondary) !important;\n }\n\n /* Change the grid to 3 columns for narrow viewport. */\n .lh-metric__innerwrap {\n /**\n * Icon -- Metric Name -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 2fr 1fr;\n }\n .lh-metric__value {\n justify-self: end;\n grid-column-start: unset;\n }\n}\n\n/* No-JS toggle switch */\n/* Keep this selector sync'd w/ `magicSelector` in report-ui-features-test.js */\n .lh-metrics-toggle__input:checked ~ .lh-metrics-container .lh-metric__description {\n display: block;\n}\n\n/* TODO get rid of the SVGS and clean up these some more */\n.lh-metrics-toggle__input {\n opacity: 0;\n position: absolute;\n right: 0;\n top: 0px;\n}\n\n.lh-metrics-toggle__input + div > label > .lh-metrics-toggle__labeltext--hide,\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--show {\n display: none;\n}\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--hide {\n display: inline;\n}\n.lh-metrics-toggle__input:focus + div > label {\n outline: -webkit-focus-ring-color auto 3px;\n}\n\n.lh-metrics-toggle__label {\n cursor: pointer;\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n/* Pushes the metric description toggle button to the right. */\n.lh-audit-group--metrics .lh-audit-group__header {\n display: flex;\n justify-content: space-between;\n}\n\n.lh-metric__icon,\n.lh-scorescale-range::before {\n content: '';\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n display: inline-block;\n margin: var(--score-icon-margin);\n}\n\n.lh-metric--pass .lh-metric__value {\n color: var(--color-pass-secondary);\n}\n.lh-metric--pass .lh-metric__icon {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-metric--average .lh-metric__value {\n color: var(--color-average-secondary);\n}\n.lh-metric--average .lh-metric__icon {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-metric--fail .lh-metric__value {\n color: var(--color-fail-secondary);\n}\n.lh-metric--fail .lh-metric__icon {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-metric--error .lh-metric__value,\n.lh-metric--error .lh-metric__description {\n color: var(--color-fail-secondary);\n}\n\n/* Perf load opportunity */\n\n.lh-load-opportunity__cols {\n display: flex;\n align-items: flex-start;\n}\n\n.lh-load-opportunity__header .lh-load-opportunity__col {\n color: var(--color-gray-600);\n display: unset;\n line-height: calc(2.3 * var(--report-font-size));\n}\n\n.lh-load-opportunity__col {\n display: flex;\n}\n\n.lh-load-opportunity__col--one {\n flex: 5;\n align-items: center;\n margin-right: 2px;\n}\n.lh-load-opportunity__col--two {\n flex: 4;\n text-align: right;\n}\n\n.lh-audit--load-opportunity .lh-audit__display-text {\n text-align: right;\n flex: 0 0 7.5ch;\n}\n\n\n/* Sparkline */\n\n.lh-load-opportunity__sparkline {\n flex: 1;\n margin-top: calc((var(--report-line-height) - var(--sparkline-height)) / 2);\n}\n\n.lh-sparkline {\n height: var(--sparkline-height);\n width: 100%;\n}\n\n.lh-sparkline__bar {\n height: 100%;\n float: right;\n}\n\n.lh-audit--pass .lh-sparkline__bar {\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-sparkline__bar {\n background: var(--color-average);\n}\n\n.lh-audit--fail .lh-sparkline__bar {\n background: var(--color-fail);\n}\n\n/* Filmstrip */\n\n.lh-filmstrip-container {\n /* smaller gap between metrics and filmstrip */\n margin: -8px auto 0 auto;\n}\n\n.lh-filmstrip {\n display: grid;\n justify-content: space-between;\n padding-bottom: var(--default-padding);\n width: 100%;\n grid-template-columns: repeat(auto-fit, 90px);\n}\n\n.lh-filmstrip__frame {\n text-align: right;\n position: relative;\n}\n\n.lh-filmstrip__thumbnail {\n border: 1px solid var(--report-border-color-secondary);\n max-height: 150px;\n max-width: 120px;\n}\n\n/* Audit */\n\n.lh-audit {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n/* Apply border-top to just the first audit. */\n.lh-audit {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n.lh-audit ~ .lh-audit {\n border-top: none;\n}\n\n\n.lh-audit--error .lh-audit__display-text {\n color: var(--color-fail-secondary);\n}\n\n/* Audit Group */\n\n.lh-audit-group {\n margin-bottom: var(--audit-group-margin-bottom);\n position: relative;\n}\n.lh-audit-group--metrics {\n margin-bottom: calc(var(--audit-group-margin-bottom) / 2);\n}\n\n.lh-audit-group__header::before {\n /* By default, groups don't get an icon */\n content: none;\n width: var(--pwa-icon-size);\n height: var(--pwa-icon-size);\n margin: var(--pwa-icon-margin);\n display: inline-block;\n vertical-align: middle;\n}\n\n/* Style the \"over budget\" columns red. */\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(4),\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(5),\n.lh-audit-group--budgets #timing-budget tbody tr td:nth-child(3) {\n color: var(--color-red-700);\n}\n\n/* Align the \"over budget request count\" text to be close to the \"over budget bytes\" column. */\n.lh-audit-group--budgets .lh-table tbody tr td:nth-child(4){\n text-align: right;\n}\n\n.lh-audit-group--budgets .lh-details--budget {\n width: 100%;\n margin: 0 0 var(--default-padding);\n}\n\n.lh-audit-group--pwa-installable .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-installable-gray-url);\n}\n.lh-audit-group--pwa-optimized .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-optimized-gray-url);\n}\n.lh-audit-group--pwa-installable.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-installable-color-url);\n}\n.lh-audit-group--pwa-optimized.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-optimized-color-url);\n}\n\n.lh-audit-group--metrics .lh-audit-group__summary {\n margin-top: 0;\n margin-bottom: 0;\n}\n\n.lh-audit-group__summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.lh-audit-group__header .lh-chevron {\n margin-top: calc((var(--report-line-height) - 5px) / 2);\n}\n\n.lh-audit-group__header {\n letter-spacing: 0.8px;\n padding: var(--default-padding);\n padding-left: 0;\n}\n\n.lh-audit-group__header, .lh-audit-group__summary {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n.lh-audit-group__title {\n text-transform: uppercase;\n font-weight: 500;\n}\n\n.lh-audit-group__itemcount {\n color: var(--color-gray-600);\n}\n\n.lh-audit-group__footer {\n color: var(--color-gray-600);\n display: block;\n margin-top: var(--default-padding);\n}\n\n.lh-details,\n.lh-category-header__description,\n.lh-load-opportunity__header,\n.lh-audit-group__footer {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n}\n\n.lh-audit-explanation {\n margin: var(--audit-padding-vertical) 0 calc(var(--audit-padding-vertical) / 2) var(--audit-margin-horizontal);\n line-height: var(--audit-explanation-line-height);\n display: inline-block;\n}\n\n.lh-audit--fail .lh-audit-explanation {\n color: var(--color-fail-secondary);\n}\n\n/* Report */\n.lh-list > :not(:last-child) {\n margin-bottom: calc(var(--default-padding) * 2);\n}\n\n.lh-header-container {\n display: block;\n margin: 0 auto;\n position: relative;\n word-wrap: break-word;\n}\n\n.lh-header-container .lh-scores-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n\n\n.lh-report {\n min-width: var(--report-content-min-width);\n}\n\n.lh-exception {\n font-size: large;\n}\n\n.lh-code {\n white-space: normal;\n margin-top: 0;\n font-size: var(--report-monospace-font-size);\n}\n\n.lh-warnings {\n --item-margin: calc(var(--report-line-height) / 6);\n color: var(--color-average-secondary);\n margin: var(--audit-padding-vertical) 0;\n padding: var(--default-padding)\n var(--default-padding)\n var(--default-padding)\n calc(var(--audit-description-padding-left));\n background-color: var(--toplevel-warning-background-color);\n}\n.lh-warnings span {\n font-weight: bold;\n}\n\n.lh-warnings--toplevel {\n --item-margin: calc(var(--header-line-height) / 4);\n color: var(--toplevel-warning-text-color);\n margin-left: auto;\n margin-right: auto;\n max-width: var(--report-content-max-width-minus-edge-gap);\n padding: var(--toplevel-warning-padding);\n border-radius: 8px;\n}\n\n.lh-warnings__msg {\n color: var(--toplevel-warning-message-text-color);\n margin: 0;\n}\n\n.lh-warnings ul {\n margin: 0;\n}\n.lh-warnings li {\n margin: var(--item-margin) 0;\n}\n.lh-warnings li:last-of-type {\n margin-bottom: 0;\n}\n\n.lh-scores-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n}\n.lh-scores-header__solo {\n padding: 0;\n border: 0;\n}\n\n/* Gauge */\n\n.lh-gauge__wrapper--pass {\n color: var(--color-pass-secondary);\n fill: var(--color-pass);\n stroke: var(--color-pass);\n}\n\n.lh-gauge__wrapper--average {\n color: var(--color-average-secondary);\n fill: var(--color-average);\n stroke: var(--color-average);\n}\n\n.lh-gauge__wrapper--fail {\n color: var(--color-fail-secondary);\n fill: var(--color-fail);\n stroke: var(--color-fail);\n}\n\n.lh-gauge__wrapper--not-applicable {\n color: var(--color-not-applicable);\n fill: var(--color-not-applicable);\n stroke: var(--color-not-applicable);\n}\n\n.lh-fraction__wrapper .lh-fraction__content::before {\n content: '';\n height: var(--score-icon-size);\n width: var(--score-icon-size);\n margin: var(--score-icon-margin);\n display: inline-block;\n}\n.lh-fraction__wrapper--pass .lh-fraction__content {\n color: var(--color-pass-secondary);\n}\n.lh-fraction__wrapper--pass .lh-fraction__background {\n background-color: var(--color-pass);\n}\n.lh-fraction__wrapper--pass .lh-fraction__content::before {\n background-color: var(--color-pass);\n border-radius: 50%;\n}\n.lh-fraction__wrapper--average .lh-fraction__content {\n color: var(--color-average-secondary);\n}\n.lh-fraction__wrapper--average .lh-fraction__background,\n.lh-fraction__wrapper--average .lh-fraction__content::before {\n background-color: var(--color-average);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content {\n color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__background {\n background-color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n.lh-fraction__wrapper--null .lh-fraction__content {\n color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__background {\n background-color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__content::before {\n border-radius: 50%;\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-700);\n}\n\n.lh-fraction__background {\n position: absolute;\n height: 100%;\n width: 100%;\n border-radius: calc(var(--gauge-circle-size) / 2);\n opacity: 0.1;\n z-index: -1;\n}\n\n.lh-fraction__content-wrapper {\n height: var(--gauge-circle-size);\n display: flex;\n align-items: center;\n}\n\n.lh-fraction__content {\n display: flex;\n position: relative;\n align-items: center;\n justify-content: center;\n font-size: calc(0.3 * var(--gauge-circle-size));\n line-height: calc(0.4 * var(--gauge-circle-size));\n width: max-content;\n min-width: calc(1.5 * var(--gauge-circle-size));\n padding: calc(0.1 * var(--gauge-circle-size)) calc(0.2 * var(--gauge-circle-size));\n --score-icon-size: calc(0.21 * var(--gauge-circle-size));\n --score-icon-margin: 0 calc(0.15 * var(--gauge-circle-size)) 0 0;\n}\n\n.lh-gauge {\n stroke-linecap: round;\n width: var(--gauge-circle-size);\n height: var(--gauge-circle-size);\n}\n\n.lh-category .lh-gauge {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n.lh-gauge-base {\n opacity: 0.1;\n}\n\n.lh-gauge-arc {\n fill: none;\n transform-origin: 50% 50%;\n animation: load-gauge var(--transition-length) ease both;\n animation-delay: 250ms;\n}\n\n.lh-gauge__svg-wrapper {\n position: relative;\n height: var(--gauge-circle-size);\n}\n.lh-category .lh-gauge__svg-wrapper,\n.lh-category .lh-fraction__wrapper {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n/* The plugin badge overlay */\n.lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size);\n height: var(--plugin-badge-size);\n background-color: var(--plugin-badge-background-color);\n background-image: var(--plugin-icon-url);\n background-repeat: no-repeat;\n background-size: var(--plugin-icon-size);\n background-position: 58% 50%;\n content: \"\";\n position: absolute;\n right: -6px;\n bottom: 0px;\n display: block;\n z-index: 100;\n box-shadow: 0 0 4px rgba(0,0,0,.2);\n border-radius: 25%;\n}\n.lh-category .lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size-big);\n height: var(--plugin-badge-size-big);\n}\n\n@keyframes load-gauge {\n from { stroke-dasharray: 0 352; }\n}\n\n.lh-gauge__percentage {\n width: 100%;\n height: var(--gauge-circle-size);\n position: absolute;\n font-family: var(--report-font-family-monospace);\n font-size: calc(var(--gauge-circle-size) * 0.34 + 1.3px);\n line-height: 0;\n text-align: center;\n top: calc(var(--score-container-padding) + var(--gauge-circle-size) / 2);\n}\n\n.lh-category .lh-gauge__percentage {\n --gauge-circle-size: var(--gauge-circle-size-big);\n --gauge-percentage-font-size: var(--gauge-percentage-font-size-big);\n}\n\n.lh-gauge__wrapper,\n.lh-fraction__wrapper {\n position: relative;\n display: flex;\n align-items: center;\n flex-direction: column;\n text-decoration: none;\n padding: var(--score-container-padding);\n\n --transition-length: 1s;\n\n /* Contain the layout style paint & layers during animation*/\n contain: content;\n will-change: opacity; /* Only using for layer promotion */\n}\n\n.lh-gauge__label,\n.lh-fraction__label {\n font-size: var(--gauge-label-font-size);\n font-weight: 500;\n line-height: var(--gauge-label-line-height);\n margin-top: 10px;\n text-align: center;\n color: var(--report-text-color);\n word-break: keep-all;\n}\n\n/* TODO(#8185) use more BEM (.lh-gauge__label--big) instead of relying on descendant selector */\n.lh-category .lh-gauge__label,\n.lh-category .lh-fraction__label {\n --gauge-label-font-size: var(--gauge-label-font-size-big);\n --gauge-label-line-height: var(--gauge-label-line-height-big);\n margin-top: 14px;\n}\n\n.lh-scores-header .lh-gauge__wrapper,\n.lh-scores-header .lh-fraction__wrapper,\n.lh-scores-header .lh-gauge--pwa__wrapper,\n.lh-sticky-header .lh-gauge__wrapper,\n.lh-sticky-header .lh-fraction__wrapper,\n.lh-sticky-header .lh-gauge--pwa__wrapper {\n width: var(--gauge-wrapper-width);\n}\n\n.lh-scorescale {\n display: inline-flex;\n\n gap: calc(var(--default-padding) * 4);\n margin: 16px auto 0 auto;\n font-size: var(--report-font-size-secondary);\n color: var(--color-gray-700);\n\n}\n\n.lh-scorescale-range {\n display: flex;\n align-items: center;\n font-family: var(--report-font-family-monospace);\n white-space: nowrap;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale {\n border: 0;\n display: flex;\n justify-content: center;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale-range {\n font-family: unset;\n font-size: 12px;\n}\n\n.lh-scorescale-wrap {\n display: contents;\n}\n\n/* Hide category score gauages if it's a single category report */\n.lh-header--solo-category .lh-scores-wrapper {\n display: none;\n}\n\n\n.lh-categories {\n width: 100%;\n}\n\n.lh-category {\n padding: var(--category-padding);\n max-width: var(--report-content-max-width);\n margin: 0 auto;\n\n scroll-margin-top: var(--sticky-header-buffer);\n}\n\n.lh-category-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n.lh-category-wrapper:last-of-type {\n border-bottom: 0;\n}\n\n.lh-category-header {\n margin-bottom: var(--section-padding-vertical);\n}\n\n.lh-category-header .lh-score__gauge {\n max-width: 400px;\n width: auto;\n margin: 0px auto;\n}\n\n.lh-category-header__finalscreenshot {\n display: grid;\n grid-template: none / 1fr 1px 1fr;\n justify-items: center;\n align-items: center;\n gap: var(--report-line-height);\n min-height: 288px;\n margin-bottom: var(--default-padding);\n}\n\n.lh-final-ss-image {\n /* constrain the size of the image to not be too large */\n max-height: calc(var(--gauge-circle-size-big) * 2.8);\n max-width: calc(var(--gauge-circle-size-big) * 3.5);\n border: 1px solid var(--color-gray-200);\n padding: 4px;\n border-radius: 3px;\n display: block;\n}\n\n.lh-category-headercol--separator {\n background: var(--color-gray-200);\n width: 1px;\n height: var(--gauge-circle-size-big);\n}\n\n@media screen and (max-width: 780px) {\n .lh-category-header__finalscreenshot {\n grid-template: 1fr 1fr / none\n }\n .lh-category-headercol--separator {\n display: none;\n }\n}\n\n\n/* 964 fits the min-width of the filmstrip */\n@media screen and (max-width: 964px) {\n .lh-report {\n margin-left: 0;\n width: 100%;\n }\n}\n\n@media print {\n body {\n -webkit-print-color-adjust: exact; /* print background colors */\n }\n .lh-container {\n display: block;\n }\n .lh-report {\n margin-left: 0;\n padding-top: 0;\n }\n .lh-categories {\n margin-top: 0;\n }\n}\n\n.lh-table {\n position: relative;\n border-collapse: separate;\n border-spacing: 0;\n /* Can't assign padding to table, so shorten the width instead. */\n width: calc(100% - var(--audit-description-padding-left) - var(--stackpack-padding-horizontal));\n border: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-table thead th {\n position: sticky;\n top: calc(var(--sticky-header-buffer) + 1em);\n z-index: 1;\n background-color: var(--report-background-color);\n border-bottom: 1px solid var(--report-border-color-secondary);\n font-weight: normal;\n color: var(--color-gray-600);\n /* See text-wrapping comment on .lh-container. */\n word-break: normal;\n}\n\n.lh-row--group {\n background-color: var(--table-group-header-background-color);\n}\n\n.lh-row--group td {\n font-weight: bold;\n font-size: 1.05em;\n color: var(--table-group-header-text-color);\n}\n\n.lh-row--group td:first-child {\n font-weight: normal;\n}\n\n.lh-row--group .lh-text {\n color: inherit;\n text-decoration: none;\n display: inline-block;\n}\n\n.lh-row--group a.lh-link:hover {\n text-decoration: underline;\n}\n\n.lh-row--group .lh-audit__adorn {\n text-transform: capitalize;\n font-weight: normal;\n padding: 2px 3px 1px 3px;\n}\n\n.lh-row--group .lh-audit__adorn1p {\n color: var(--link-color);\n border-color: var(--link-color);\n}\n\n.lh-row--group .lh-report-icon--external::before {\n content: \"\";\n background-repeat: no-repeat;\n width: 14px;\n height: 16px;\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n\n.lh-row--group .lh-report-icon--external {\n display: none;\n}\n\n.lh-row--group:hover .lh-report-icon--external {\n display: inline-block;\n}\n\n.lh-dark .lh-report-icon--external::before {\n filter: invert(1);\n}\n\n/** Manages indentation of two-level and three-level nested adjacent rows */\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) td:first-child {\n padding-left: 20px;\n}\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) ~ .lh-sub-item-row td:first-child {\n padding-left: 40px;\n}\n\n.lh-row--even {\n background-color: var(--table-group-header-background-color);\n}\n.lh-row--hidden {\n display: none;\n}\n\n.lh-table th,\n.lh-table td {\n padding: var(--default-padding);\n}\n\n.lh-table tr {\n vertical-align: middle;\n}\n\n.lh-table tr:hover {\n background-color: var(--table-higlight-background-color);\n}\n\n/* Looks unnecessary, but mostly for keeping the s left-aligned */\n.lh-table-column--text,\n.lh-table-column--source-location,\n.lh-table-column--url,\n/* .lh-table-column--thumbnail, */\n/* .lh-table-column--empty,*/\n.lh-table-column--code,\n.lh-table-column--node {\n text-align: left;\n}\n\n.lh-table-column--code {\n min-width: 100px;\n}\n\n.lh-table-column--bytes,\n.lh-table-column--timespanMs,\n.lh-table-column--ms,\n.lh-table-column--numeric {\n text-align: right;\n word-break: normal;\n}\n\n\n\n.lh-table .lh-table-column--thumbnail {\n width: var(--image-preview-size);\n}\n\n.lh-table-column--url {\n min-width: 250px;\n}\n\n.lh-table-column--text {\n min-width: 80px;\n}\n\n/* Keep columns narrow if they follow the URL column */\n/* 12% was determined to be a decent narrow width, but wide enough for column headings */\n.lh-table-column--url + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--ms,\n.lh-table-column--url + .lh-table-column--ms + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--timespanMs {\n width: 12%;\n}\n\n.lh-text__url-host {\n display: inline;\n}\n\n.lh-text__url-host {\n margin-left: calc(var(--report-font-size) / 2);\n opacity: 0.6;\n font-size: 90%\n}\n\n.lh-thumbnail {\n object-fit: cover;\n width: var(--image-preview-size);\n height: var(--image-preview-size);\n display: block;\n}\n\n.lh-unknown pre {\n overflow: scroll;\n border: solid 1px var(--color-gray-200);\n}\n\n.lh-text__url > a {\n color: inherit;\n text-decoration: none;\n}\n\n.lh-text__url > a:hover {\n text-decoration: underline dotted #999;\n}\n\n.lh-sub-item-row {\n margin-left: 20px;\n margin-bottom: 0;\n color: var(--color-gray-700);\n}\n\n.lh-sub-item-row td {\n padding-top: 4px;\n padding-bottom: 4px;\n padding-left: 20px;\n}\n\n/* Chevron\n https://codepen.io/paulirish/pen/LmzEmK\n */\n.lh-chevron {\n --chevron-angle: 42deg;\n /* Edge doesn't support transform: rotate(calc(...)), so we define it here */\n --chevron-angle-right: -42deg;\n width: var(--chevron-size);\n height: var(--chevron-size);\n margin-top: calc((var(--report-line-height) - 12px) / 2);\n}\n\n.lh-chevron__lines {\n transition: transform 0.4s;\n transform: translateY(var(--report-line-height));\n}\n.lh-chevron__line {\n stroke: var(--chevron-line-stroke);\n stroke-width: var(--chevron-size);\n stroke-linecap: square;\n transform-origin: 50%;\n transform: rotate(var(--chevron-angle));\n transition: transform 300ms, stroke 300ms;\n}\n\n.lh-expandable-details .lh-chevron__line-right,\n.lh-expandable-details[open] .lh-chevron__line-left {\n transform: rotate(var(--chevron-angle-right));\n}\n\n.lh-expandable-details[open] .lh-chevron__line-right {\n transform: rotate(var(--chevron-angle));\n}\n\n\n.lh-expandable-details[open] .lh-chevron__lines {\n transform: translateY(calc(var(--chevron-size) * -1));\n}\n\n.lh-expandable-details[open] {\n animation: 300ms openDetails forwards;\n padding-bottom: var(--default-padding);\n}\n\n@keyframes openDetails {\n from {\n outline: 1px solid var(--report-background-color);\n }\n to {\n outline: 1px solid;\n box-shadow: 0 2px 4px rgba(0, 0, 0, .24);\n }\n}\n\n@media screen and (max-width: 780px) {\n /* no black outline if we're not confident the entire table can be displayed within bounds */\n .lh-expandable-details[open] {\n animation: none;\n }\n}\n\n.lh-expandable-details[open] summary, details.lh-clump > summary {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\ndetails.lh-clump[open] > summary {\n border-bottom-width: 0;\n}\n\n\n\ndetails .lh-clump-toggletext--hide,\ndetails[open] .lh-clump-toggletext--show { display: none; }\ndetails[open] .lh-clump-toggletext--hide { display: block;}\n\n\n/* Tooltip */\n.lh-tooltip-boundary {\n position: relative;\n}\n\n.lh-tooltip {\n position: absolute;\n display: none; /* Don't retain these layers when not needed */\n opacity: 0;\n background: #ffffff;\n white-space: pre-line; /* Render newlines in the text */\n min-width: 246px;\n max-width: 275px;\n padding: 15px;\n border-radius: 5px;\n text-align: initial;\n line-height: 1.4;\n}\n/* shrink tooltips to not be cutoff on left edge of narrow viewports\n 45vw is chosen to be ~= width of the left column of metrics\n*/\n@media screen and (max-width: 535px) {\n .lh-tooltip {\n min-width: 45vw;\n padding: 3vw;\n }\n}\n\n.lh-tooltip-boundary:hover .lh-tooltip {\n display: block;\n animation: fadeInTooltip 250ms;\n animation-fill-mode: forwards;\n animation-delay: 850ms;\n bottom: 100%;\n z-index: 1;\n will-change: opacity;\n right: 0;\n pointer-events: none;\n}\n\n.lh-tooltip::before {\n content: \"\";\n border: solid transparent;\n border-bottom-color: #fff;\n border-width: 10px;\n position: absolute;\n bottom: -20px;\n right: 6px;\n transform: rotate(180deg);\n pointer-events: none;\n}\n\n@keyframes fadeInTooltip {\n 0% { opacity: 0; }\n 75% { opacity: 1; }\n 100% { opacity: 1; filter: drop-shadow(1px 0px 1px #aaa) drop-shadow(0px 2px 4px hsla(206, 6%, 25%, 0.15)); pointer-events: auto; }\n}\n\n/* Element screenshot */\n.lh-element-screenshot {\n float: left;\n margin-right: 20px;\n}\n.lh-element-screenshot__content {\n overflow: hidden;\n min-width: 110px;\n display: flex;\n justify-content: center;\n background-color: var(--report-background-color);\n}\n.lh-element-screenshot__image {\n position: relative;\n /* Set by ElementScreenshotRenderer.installFullPageScreenshotCssVariable */\n background-image: var(--element-screenshot-url);\n outline: 2px solid #777;\n background-color: white;\n background-repeat: no-repeat;\n}\n.lh-element-screenshot__mask {\n position: absolute;\n background: #555;\n opacity: 0.8;\n}\n.lh-element-screenshot__element-marker {\n position: absolute;\n outline: 2px solid var(--color-lime-400);\n}\n.lh-element-screenshot__overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 2000; /* .lh-topbar is 1000 */\n background: var(--screenshot-overlay-background);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: zoom-out;\n}\n\n.lh-element-screenshot__overlay .lh-element-screenshot {\n margin-right: 0; /* clearing margin used in thumbnail case */\n outline: 1px solid var(--color-gray-700);\n}\n\n.lh-screenshot-overlay--enabled .lh-element-screenshot {\n cursor: zoom-out;\n}\n.lh-screenshot-overlay--enabled .lh-node .lh-element-screenshot {\n cursor: zoom-in;\n}\n\n\n.lh-meta__items {\n --meta-icon-size: calc(var(--report-icon-size) * 0.667);\n padding: var(--default-padding);\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n background-color: var(--env-item-background-color);\n border-radius: 3px;\n margin: 0 0 var(--default-padding) 0;\n font-size: 12px;\n column-gap: var(--default-padding);\n color: var(--color-gray-700);\n}\n\n.lh-meta__item {\n display: block;\n list-style-type: none;\n position: relative;\n padding: 0 0 0 calc(var(--meta-icon-size) + var(--default-padding) * 2);\n cursor: unset; /* disable pointer cursor from report-icon */\n}\n\n.lh-meta__item.lh-tooltip-boundary {\n text-decoration: dotted underline var(--color-gray-500);\n cursor: help;\n}\n\n.lh-meta__item.lh-report-icon::before {\n position: absolute;\n left: var(--default-padding);\n width: var(--meta-icon-size);\n height: var(--meta-icon-size);\n}\n\n.lh-meta__item.lh-report-icon:hover::before {\n opacity: 0.7;\n}\n\n.lh-meta__item .lh-tooltip {\n color: var(--color-gray-800);\n}\n\n.lh-meta__item .lh-tooltip::before {\n right: auto; /* Set the tooltip arrow to the leftside */\n left: 6px;\n}\n\n/* Change the grid for narrow viewport. */\n@media screen and (max-width: 640px) {\n .lh-meta__items {\n grid-template-columns: 1fr 1fr;\n }\n}\n@media screen and (max-width: 535px) {\n .lh-meta__items {\n display: block;\n }\n}\n\n\n/*# sourceURL=report-styles.css */\n"); + el1.append("/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: Apache-2.0\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 --report-icon-size: var(--score-icon-background-size);\n --report-line-height: 24px;\n --report-line-height-secondary: 20px;\n --report-monospace-font-size: calc(var(--report-font-size) * 0.85);\n --report-text-color-secondary: var(--color-gray-800);\n --report-text-color: var(--color-gray-900);\n --report-content-max-width: calc(60 * var(--report-font-size)); /* defaults to 840px */\n --report-content-min-width: 360px;\n --report-content-max-width-minus-edge-gap: calc(var(--report-content-max-width) - var(--edge-gap-padding) * 2);\n --score-container-padding: 8px;\n --score-icon-background-size: 24px;\n --score-icon-margin-left: 6px;\n --score-icon-margin-right: 14px;\n --score-icon-margin: 0 var(--score-icon-margin-right) 0 var(--score-icon-margin-left);\n --score-icon-size: 12px;\n --score-icon-size-big: 16px;\n --screenshot-overlay-background: rgba(0, 0, 0, 0.3);\n --section-padding-vertical: calc(var(--default-padding) * 6);\n --snippet-background-color: var(--color-gray-50);\n --snippet-color: #0938C2;\n --sparkline-height: 5px;\n --stackpack-padding-horizontal: 10px;\n --sticky-header-background-color: var(--report-background-color);\n --sticky-header-buffer: calc(var(--topbar-height) + var(--sticky-header-height));\n --sticky-header-height: calc(var(--gauge-circle-size-sm) + var(--score-container-padding) * 2);\n --table-group-header-background-color: #EEF1F4;\n --table-group-header-text-color: var(--color-gray-700);\n --table-higlight-background-color: #F5F7FA;\n --tools-icon-color: var(--color-gray-600);\n --topbar-background-color: var(--color-white);\n --topbar-height: 32px;\n --topbar-logo-size: 24px;\n --topbar-padding: 0 8px;\n --toplevel-warning-background-color: hsla(30, 100%, 75%, 10%);\n --toplevel-warning-message-text-color: var(--color-average-secondary);\n --toplevel-warning-padding: 18px;\n --toplevel-warning-text-color: var(--report-text-color);\n\n /* SVGs */\n --plugin-icon-url-dark: url('data:image/svg+xml;utf8,');\n --plugin-icon-url: url('data:image/svg+xml;utf8,');\n\n --pass-icon-url: url('data:image/svg+xml;utf8,check');\n --average-icon-url: url('data:image/svg+xml;utf8,info');\n --fail-icon-url: url('data:image/svg+xml;utf8,warn');\n --error-icon-url: url('data:image/svg+xml;utf8,error');\n\n --pwa-installable-gray-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-gray-url-dark: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url-dark: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-color-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-color-url: url('data:image/svg+xml;utf8,');\n\n --swap-locale-icon-url: url('data:image/svg+xml;utf8,');\n}\n\n@media not print {\n .lh-dark {\n /* Pallete */\n --color-gray-200: var(--color-gray-800);\n --color-gray-300: #616161;\n --color-gray-400: var(--color-gray-600);\n --color-gray-700: var(--color-gray-400);\n --color-gray-50: #757575;\n --color-gray-600: var(--color-gray-500);\n --color-green-700: var(--color-green);\n --color-orange-700: var(--color-orange);\n --color-red-700: var(--color-red);\n --color-teal-600: var(--color-cyan-500);\n\n /* Context-specific colors */\n --color-hover: rgba(0, 0, 0, 0.2);\n --color-informative: var(--color-blue-200);\n\n /* Component variables */\n --env-item-background-color: #393535;\n --link-color: var(--color-blue-200);\n --locale-selector-background-color: var(--color-gray-200);\n --plugin-badge-background-color: var(--color-gray-800);\n --report-background-color: var(--color-gray-900);\n --report-border-color-secondary: var(--color-gray-200);\n --report-text-color-secondary: var(--color-gray-400);\n --report-text-color: var(--color-gray-100);\n --snippet-color: var(--color-cyan-500);\n --topbar-background-color: var(--color-gray);\n --toplevel-warning-background-color: hsl(33deg 14% 18%);\n --toplevel-warning-message-text-color: var(--color-orange-700);\n --toplevel-warning-text-color: var(--color-gray-100);\n --table-group-header-background-color: rgba(186, 196, 206, 0.15);\n --table-group-header-text-color: var(--color-gray-100);\n --table-higlight-background-color: rgba(186, 196, 206, 0.09);\n\n /* SVGs */\n --plugin-icon-url: var(--plugin-icon-url-dark);\n --pwa-installable-gray-url: var(--pwa-installable-gray-url-dark);\n --pwa-optimized-gray-url: var(--pwa-optimized-gray-url-dark);\n }\n}\n\n@media only screen and (max-width: 480px) {\n .lh-vars {\n --audit-group-margin-bottom: 20px;\n --edge-gap-padding: var(--default-padding);\n --env-name-min-width: 120px;\n --gauge-circle-size-big: 96px;\n --gauge-circle-size: 72px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 112px;\n --header-padding: 16px 0 16px 0;\n --image-preview-size: 24px;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-size: 14px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --topbar-height: 28px;\n --topbar-logo-size: 20px;\n }\n\n /* Not enough space to adequately show the relative savings bars. */\n .lh-sparkline {\n display: none;\n }\n}\n\n.lh-vars.lh-devtools {\n --audit-explanation-line-height: 14px;\n --audit-group-margin-bottom: 20px;\n --audit-group-padding-vertical: 12px;\n --audit-padding-vertical: 4px;\n --category-padding: 12px;\n --default-padding: 12px;\n --env-name-min-width: 120px;\n --footer-padding-vertical: 8px;\n --gauge-circle-size-big: 72px;\n --gauge-circle-size: 64px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 97px;\n --header-line-height: 20px;\n --header-padding: 16px 0 16px 0;\n --screenshot-overlay-background: transparent;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-family-monospace: 'Menlo', 'dejavu sans mono', 'Consolas', 'Lucida Console', monospace;\n --report-font-family: '.SFNSDisplay-Regular', 'Helvetica Neue', 'Lucida Grande', sans-serif;\n --report-font-size: 12px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --section-padding-vertical: 8px;\n}\n\n.lh-container:not(.lh-topbar + .lh-container) {\n --topbar-height: 0;\n --sticky-header-height: 0;\n --sticky-header-buffer: 0;\n}\n\n.lh-devtools.lh-root {\n height: 100%;\n}\n.lh-devtools.lh-root img {\n /* Override devtools default 'min-width: 0' so svg without size in a flexbox isn't collapsed. */\n min-width: auto;\n}\n.lh-devtools .lh-container {\n overflow-y: scroll;\n height: calc(100% - var(--topbar-height));\n /** The .lh-container is the scroll parent in DevTools so we exclude the topbar from the sticky header buffer. */\n --sticky-header-buffer: calc(var(--sticky-header-height));\n}\n@media print {\n .lh-devtools .lh-container {\n overflow: unset;\n }\n}\n.lh-devtools .lh-sticky-header {\n /* This is normally the height of the topbar, but we want it to stick to the top of our scroll container .lh-container` */\n top: 0;\n}\n.lh-devtools .lh-element-screenshot__overlay {\n position: absolute;\n}\n\n@keyframes fadeIn {\n 0% { opacity: 0;}\n 100% { opacity: 0.6;}\n}\n\n.lh-root *, .lh-root *::before, .lh-root *::after {\n box-sizing: border-box;\n}\n\n.lh-root {\n font-family: var(--report-font-family);\n font-size: var(--report-font-size);\n margin: 0;\n line-height: var(--report-line-height);\n background: var(--report-background-color);\n color: var(--report-text-color);\n}\n\n.lh-root :focus-visible {\n outline: -webkit-focus-ring-color auto 3px;\n}\n.lh-root summary:focus {\n outline: none;\n box-shadow: 0 0 0 1px hsl(217, 89%, 61%);\n}\n\n.lh-root [hidden] {\n display: none !important;\n}\n\n.lh-root pre {\n margin: 0;\n}\n\n.lh-root pre,\n.lh-root code {\n font-family: var(--report-font-family-monospace);\n}\n\n.lh-root details > summary {\n cursor: pointer;\n}\n\n.lh-hidden {\n display: none !important;\n}\n\n.lh-container {\n /*\n Text wrapping in the report is so much FUN!\n We have a `word-break: break-word;` globally here to prevent a few common scenarios, namely\n long non-breakable text (usually URLs) found in:\n 1. The footer\n 2. .lh-node (outerHTML)\n 3. .lh-code\n\n With that sorted, the next challenge is appropriate column sizing and text wrapping inside our\n .lh-details tables. Even more fun.\n * We don't want table headers (\"Potential Savings (ms)\") to wrap or their column values, but\n we'd be happy for the URL column to wrap if the URLs are particularly long.\n * We want the narrow columns to remain narrow, providing the most column width for URL\n * We don't want the table to extend past 100% width.\n * Long URLs in the URL column can wrap. Util.getURLDisplayName maxes them out at 64 characters,\n but they do not get any overflow:ellipsis treatment.\n */\n word-break: break-word;\n}\n\n.lh-audit-group a,\n.lh-category-header__description a,\n.lh-audit__description a,\n.lh-warnings a,\n.lh-footer a,\n.lh-table-column--link a {\n color: var(--link-color);\n}\n\n.lh-audit__description, .lh-audit__stackpack {\n --inner-audit-padding-right: var(--stackpack-padding-horizontal);\n padding-left: var(--audit-description-padding-left);\n padding-right: var(--inner-audit-padding-right);\n padding-top: 8px;\n padding-bottom: 8px;\n}\n\n.lh-details {\n margin-top: var(--default-padding);\n margin-bottom: var(--default-padding);\n margin-left: var(--audit-description-padding-left);\n /* whatever the .lh-details side margins are */\n width: 100%;\n}\n\n.lh-audit__stackpack {\n display: flex;\n align-items: center;\n}\n\n.lh-audit__stackpack__img {\n max-width: 30px;\n margin-right: var(--default-padding)\n}\n\n/* Report header */\n\n.lh-report-icon {\n display: flex;\n align-items: center;\n padding: 10px 12px;\n cursor: pointer;\n}\n.lh-report-icon[disabled] {\n opacity: 0.3;\n pointer-events: none;\n}\n\n.lh-report-icon::before {\n content: \"\";\n margin: 4px;\n background-repeat: no-repeat;\n width: var(--report-icon-size);\n height: var(--report-icon-size);\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n.lh-report-icon:hover::before {\n opacity: 1;\n}\n.lh-dark .lh-report-icon::before {\n filter: invert(1);\n}\n.lh-report-icon--print::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--copy::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--open::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--download::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--dark::before {\n background-image:url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--treemap::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--date::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--devices::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--world::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--stopwatch::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--networkspeed::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-one::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-many::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--chrome::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--external::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n\n.lh-buttons {\n display: flex;\n flex-wrap: wrap;\n margin: var(--default-padding) 0;\n}\n.lh-button {\n height: 32px;\n border: 1px solid var(--report-border-color-secondary);\n border-radius: 3px;\n color: var(--link-color);\n background-color: var(--report-background-color);\n margin: 5px;\n}\n\n.lh-button:first-of-type {\n margin-left: 0;\n}\n\n/* Node */\n.lh-node__snippet {\n font-family: var(--report-font-family-monospace);\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n line-height: 20px;\n}\n\n/* Score */\n\n/* to remove color indicators - test */\n/* .lh-audit__score-icon {\n opacity: 0;\n} */\n\n.lh-audit__score-icon {\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n margin: var(--score-icon-margin);\n}\n\n.lh-audit--pass .lh-audit__display-text {\n color: var(--color-pass-secondary);\n}\n.lh-audit--pass .lh-audit__score-icon,\n.lh-scorescale-range--pass::before {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-audit__display-text {\n color: var(--color-average-secondary);\n /* to remove color indicators - test */\n /* color: gray; */\n}\n.lh-audit--average .lh-audit__score-icon,\n.lh-scorescale-range--average::before {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-audit--fail .lh-audit__display-text {\n color: var(--color-fail-secondary);\n /* to remove color indicators - test */\n /* color: gray; */\n}\n.lh-audit--fail .lh-audit__score-icon,\n.lh-audit--error .lh-audit__score-icon,\n.lh-scorescale-range--fail::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-audit--error .lh-audit__score-icon,\n.lh-metric--error .lh-metric__icon {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n border: none;\n}\n\n.lh-gauge__wrapper--fail .lh-gauge--error {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n transform: scale(0.5);\n top: var(--score-container-padding);\n}\n\n.lh-audit--manual .lh-audit__display-text,\n.lh-audit--notapplicable .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n.lh-audit--manual .lh-audit__score-icon,\n.lh-audit--notapplicable .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n background: none;\n}\n\n.lh-audit--informative .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n\n.lh-audit--informative .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n}\n\n.lh-audit__description,\n.lh-audit__stackpack {\n color: var(--report-text-color-secondary);\n}\n.lh-audit__adorn {\n border: 1px solid var(--color-gray-500);\n border-radius: 3px;\n margin: 0 3px;\n padding: 0 2px;\n line-height: 1.1;\n display: inline-block;\n font-size: 90%;\n color: var(--report-text-color-secondary);\n}\n\n.lh-category-header__description {\n text-align: center;\n color: var(--color-gray-700);\n margin: 0px auto;\n max-width: 400px;\n}\n\n\n.lh-audit__display-text,\n.lh-load-opportunity__sparkline,\n.lh-chevron-container {\n margin: 0 var(--audit-margin-horizontal);\n}\n.lh-chevron-container {\n margin-right: 0;\n}\n\n.lh-audit__title-and-text {\n flex: 1;\n}\n\n.lh-audit__title-and-text code {\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n}\n\n/* Prepend display text with em dash separator. But not in Opportunities. */\n.lh-audit__display-text:not(:empty):before {\n content: '—';\n margin-right: var(--audit-margin-horizontal);\n}\n.lh-audit-group.lh-audit-group--load-opportunities .lh-audit__display-text:not(:empty):before {\n display: none;\n}\n\n/* Expandable Details (Audit Groups, Audits) */\n.lh-audit__header {\n display: flex;\n align-items: center;\n padding: var(--default-padding);\n}\n\n.lh-audit--load-opportunity .lh-audit__header {\n display: block;\n}\n\n\n.lh-metricfilter {\n display: grid;\n justify-content: end;\n align-items: center;\n grid-auto-flow: column;\n gap: 4px;\n color: var(--color-gray-700);\n}\n\n.lh-metricfilter__radio {\n /*\n * Instead of hiding, position offscreen so it's still accessible to screen readers\n * https://bugs.chromium.org/p/chromium/issues/detail?id=1439785\n */\n position: fixed;\n left: -9999px;\n}\n.lh-metricfilter input[type='radio']:focus-visible + label {\n outline: -webkit-focus-ring-color auto 1px;\n}\n\n.lh-metricfilter__label {\n display: inline-flex;\n padding: 0 4px;\n height: 16px;\n text-decoration: underline;\n align-items: center;\n cursor: pointer;\n font-size: 90%;\n}\n\n.lh-metricfilter__label--active {\n background: var(--color-blue-primary);\n color: var(--color-white);\n border-radius: 3px;\n text-decoration: none;\n}\n/* Give the 'All' choice a more muted display */\n.lh-metricfilter__label--active[for=\"metric-All\"] {\n background-color: var(--color-blue-200) !important;\n color: black !important;\n}\n\n.lh-metricfilter__text {\n margin-right: 8px;\n}\n\n/* If audits are filtered, hide the itemcount for Passed Audits… */\n.lh-category--filtered .lh-audit-group .lh-audit-group__itemcount {\n display: none;\n}\n\n\n.lh-audit__header:hover {\n background-color: var(--color-hover);\n}\n\n/* We want to hide the browser's default arrow marker on summary elements. Admittedly, it's complicated. */\n.lh-root details > summary {\n /* Blink 89+ and Firefox will hide the arrow when display is changed from (new) default of `list-item` to block. https://chromestatus.com/feature/6730096436051968*/\n display: block;\n}\n/* Safari and Blink <=88 require using the -webkit-details-marker selector */\n.lh-root details > summary::-webkit-details-marker {\n display: none;\n}\n\n/* Perf Metric */\n\n.lh-metrics-container {\n display: grid;\n grid-auto-rows: 1fr;\n grid-template-columns: 1fr 1fr;\n grid-column-gap: var(--report-line-height);\n margin-bottom: var(--default-padding);\n}\n\n.lh-metric {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(-n+2) {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-metric__innerwrap {\n display: grid;\n /**\n * Icon -- Metric Name\n * -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 1fr;\n align-items: center;\n padding: var(--default-padding);\n}\n\n.lh-metric__details {\n order: -1;\n}\n\n.lh-metric__title {\n flex: 1;\n}\n\n.lh-calclink {\n padding-left: calc(1ex / 3);\n}\n\n.lh-metric__description {\n display: none;\n grid-column-start: 2;\n grid-column-end: 4;\n color: var(--report-text-color-secondary);\n}\n\n.lh-metric__value {\n font-size: var(--metric-value-font-size);\n margin: calc(var(--default-padding) / 2) 0;\n white-space: nowrap; /* No wrapping between metric value and the icon */\n grid-column-start: 2;\n}\n\n\n@media screen and (max-width: 535px) {\n .lh-metrics-container {\n display: block;\n }\n\n .lh-metric {\n border-bottom: none !important;\n }\n .lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(1) {\n border-bottom: 1px solid var(--report-border-color-secondary) !important;\n }\n\n /* Change the grid to 3 columns for narrow viewport. */\n .lh-metric__innerwrap {\n /**\n * Icon -- Metric Name -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 2fr 1fr;\n }\n .lh-metric__value {\n justify-self: end;\n grid-column-start: unset;\n }\n}\n\n/* No-JS toggle switch */\n/* Keep this selector sync'd w/ `magicSelector` in report-ui-features-test.js */\n .lh-metrics-toggle__input:checked ~ .lh-metrics-container .lh-metric__description {\n display: block;\n}\n\n/* TODO get rid of the SVGS and clean up these some more */\n.lh-metrics-toggle__input {\n opacity: 0;\n position: absolute;\n right: 0;\n top: 0px;\n}\n\n.lh-metrics-toggle__input + div > label > .lh-metrics-toggle__labeltext--hide,\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--show {\n display: none;\n}\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--hide {\n display: inline;\n}\n.lh-metrics-toggle__input:focus + div > label {\n outline: -webkit-focus-ring-color auto 3px;\n}\n\n.lh-metrics-toggle__label {\n cursor: pointer;\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n/* Pushes the metric description toggle button to the right. */\n.lh-audit-group--metrics .lh-audit-group__header {\n display: flex;\n justify-content: space-between;\n}\n\n.lh-metric__icon,\n.lh-scorescale-range::before {\n content: '';\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n display: inline-block;\n margin: var(--score-icon-margin);\n}\n\n.lh-metric--pass .lh-metric__value {\n color: var(--color-pass-secondary);\n}\n.lh-metric--pass .lh-metric__icon {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-metric--average .lh-metric__value {\n color: var(--color-average-secondary);\n}\n.lh-metric--average .lh-metric__icon {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-metric--fail .lh-metric__value {\n color: var(--color-fail-secondary);\n}\n.lh-metric--fail .lh-metric__icon {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-metric--error .lh-metric__value,\n.lh-metric--error .lh-metric__description {\n color: var(--color-fail-secondary);\n}\n\n/* Perf load opportunity */\n\n.lh-load-opportunity__cols {\n display: flex;\n align-items: flex-start;\n}\n\n.lh-load-opportunity__header .lh-load-opportunity__col {\n color: var(--color-gray-600);\n display: unset;\n line-height: calc(2.3 * var(--report-font-size));\n}\n\n.lh-load-opportunity__col {\n display: flex;\n}\n\n.lh-load-opportunity__col--one {\n flex: 5;\n align-items: center;\n margin-right: 2px;\n}\n.lh-load-opportunity__col--two {\n flex: 4;\n text-align: right;\n}\n\n.lh-audit--load-opportunity .lh-audit__display-text {\n text-align: right;\n flex: 0 0 7.5ch;\n}\n\n\n/* Sparkline */\n\n.lh-load-opportunity__sparkline {\n flex: 1;\n margin-top: calc((var(--report-line-height) - var(--sparkline-height)) / 2);\n}\n\n.lh-sparkline {\n height: var(--sparkline-height);\n width: 100%;\n}\n\n.lh-sparkline__bar {\n height: 100%;\n float: right;\n}\n\n.lh-audit--pass .lh-sparkline__bar {\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-sparkline__bar {\n background: var(--color-average);\n}\n\n.lh-audit--fail .lh-sparkline__bar {\n background: var(--color-fail);\n}\n\n/* Filmstrip */\n\n.lh-filmstrip-container {\n /* smaller gap between metrics and filmstrip */\n margin: -8px auto 0 auto;\n}\n\n.lh-filmstrip {\n display: grid;\n justify-content: space-between;\n padding-bottom: var(--default-padding);\n width: 100%;\n grid-template-columns: repeat(auto-fit, 90px);\n}\n\n.lh-filmstrip__frame {\n text-align: right;\n position: relative;\n}\n\n.lh-filmstrip__thumbnail {\n border: 1px solid var(--report-border-color-secondary);\n max-height: 150px;\n max-width: 120px;\n}\n\n/* Audit */\n\n.lh-audit {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n/* Apply border-top to just the first audit. */\n.lh-audit {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n.lh-audit ~ .lh-audit {\n border-top: none;\n}\n\n\n.lh-audit--error .lh-audit__display-text {\n color: var(--color-fail-secondary);\n}\n\n/* Audit Group */\n\n.lh-audit-group {\n margin-bottom: var(--audit-group-margin-bottom);\n position: relative;\n}\n.lh-audit-group--metrics {\n margin-bottom: calc(var(--audit-group-margin-bottom) / 2);\n}\n\n.lh-audit-group__header::before {\n /* By default, groups don't get an icon */\n content: none;\n width: var(--pwa-icon-size);\n height: var(--pwa-icon-size);\n margin: var(--pwa-icon-margin);\n display: inline-block;\n vertical-align: middle;\n}\n\n/* Style the \"over budget\" columns red. */\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(4),\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(5),\n.lh-audit-group--budgets #timing-budget tbody tr td:nth-child(3) {\n color: var(--color-red-700);\n}\n\n/* Align the \"over budget request count\" text to be close to the \"over budget bytes\" column. */\n.lh-audit-group--budgets .lh-table tbody tr td:nth-child(4){\n text-align: right;\n}\n\n.lh-audit-group--budgets .lh-details--budget {\n width: 100%;\n margin: 0 0 var(--default-padding);\n}\n\n.lh-audit-group--pwa-installable .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-installable-gray-url);\n}\n.lh-audit-group--pwa-optimized .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-optimized-gray-url);\n}\n.lh-audit-group--pwa-installable.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-installable-color-url);\n}\n.lh-audit-group--pwa-optimized.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-optimized-color-url);\n}\n\n.lh-audit-group--metrics .lh-audit-group__summary {\n margin-top: 0;\n margin-bottom: 0;\n}\n\n.lh-audit-group__summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.lh-audit-group__header .lh-chevron {\n margin-top: calc((var(--report-line-height) - 5px) / 2);\n}\n\n.lh-audit-group__header {\n letter-spacing: 0.8px;\n padding: var(--default-padding);\n padding-left: 0;\n}\n\n.lh-audit-group__header, .lh-audit-group__summary {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n.lh-audit-group__title {\n text-transform: uppercase;\n font-weight: 500;\n}\n\n.lh-audit-group__itemcount {\n color: var(--color-gray-600);\n}\n\n.lh-audit-group__footer {\n color: var(--color-gray-600);\n display: block;\n margin-top: var(--default-padding);\n}\n\n.lh-details,\n.lh-category-header__description,\n.lh-load-opportunity__header,\n.lh-audit-group__footer {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n}\n\n.lh-audit-explanation {\n margin: var(--audit-padding-vertical) 0 calc(var(--audit-padding-vertical) / 2) var(--audit-margin-horizontal);\n line-height: var(--audit-explanation-line-height);\n display: inline-block;\n}\n\n.lh-audit--fail .lh-audit-explanation {\n color: var(--color-fail-secondary);\n}\n\n/* Report */\n.lh-list > :not(:last-child) {\n margin-bottom: calc(var(--default-padding) * 2);\n}\n\n.lh-header-container {\n display: block;\n margin: 0 auto;\n position: relative;\n word-wrap: break-word;\n}\n\n.lh-header-container .lh-scores-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n\n\n.lh-report {\n min-width: var(--report-content-min-width);\n}\n\n.lh-exception {\n font-size: large;\n}\n\n.lh-code {\n white-space: normal;\n margin-top: 0;\n font-size: var(--report-monospace-font-size);\n}\n\n.lh-warnings {\n --item-margin: calc(var(--report-line-height) / 6);\n color: var(--color-average-secondary);\n margin: var(--audit-padding-vertical) 0;\n padding: var(--default-padding)\n var(--default-padding)\n var(--default-padding)\n calc(var(--audit-description-padding-left));\n background-color: var(--toplevel-warning-background-color);\n}\n.lh-warnings span {\n font-weight: bold;\n}\n\n.lh-warnings--toplevel {\n --item-margin: calc(var(--header-line-height) / 4);\n color: var(--toplevel-warning-text-color);\n margin-left: auto;\n margin-right: auto;\n max-width: var(--report-content-max-width-minus-edge-gap);\n padding: var(--toplevel-warning-padding);\n border-radius: 8px;\n}\n\n.lh-warnings__msg {\n color: var(--toplevel-warning-message-text-color);\n margin: 0;\n}\n\n.lh-warnings ul {\n margin: 0;\n}\n.lh-warnings li {\n margin: var(--item-margin) 0;\n}\n.lh-warnings li:last-of-type {\n margin-bottom: 0;\n}\n\n.lh-scores-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n}\n.lh-scores-header__solo {\n padding: 0;\n border: 0;\n}\n\n/* Gauge */\n\n.lh-gauge__wrapper--pass {\n color: var(--color-pass-secondary);\n fill: var(--color-pass);\n stroke: var(--color-pass);\n}\n\n.lh-gauge__wrapper--average {\n color: var(--color-average-secondary);\n fill: var(--color-average);\n stroke: var(--color-average);\n}\n\n.lh-gauge__wrapper--fail {\n color: var(--color-fail-secondary);\n fill: var(--color-fail);\n stroke: var(--color-fail);\n}\n\n.lh-gauge__wrapper--not-applicable {\n color: var(--color-not-applicable);\n fill: var(--color-not-applicable);\n stroke: var(--color-not-applicable);\n}\n\n.lh-fraction__wrapper .lh-fraction__content::before {\n content: '';\n height: var(--score-icon-size);\n width: var(--score-icon-size);\n margin: var(--score-icon-margin);\n display: inline-block;\n}\n.lh-fraction__wrapper--pass .lh-fraction__content {\n color: var(--color-pass-secondary);\n}\n.lh-fraction__wrapper--pass .lh-fraction__background {\n background-color: var(--color-pass);\n}\n.lh-fraction__wrapper--pass .lh-fraction__content::before {\n background-color: var(--color-pass);\n border-radius: 50%;\n}\n.lh-fraction__wrapper--average .lh-fraction__content {\n color: var(--color-average-secondary);\n}\n.lh-fraction__wrapper--average .lh-fraction__background,\n.lh-fraction__wrapper--average .lh-fraction__content::before {\n background-color: var(--color-average);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content {\n color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__background {\n background-color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n.lh-fraction__wrapper--null .lh-fraction__content {\n color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__background {\n background-color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__content::before {\n border-radius: 50%;\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-700);\n}\n\n.lh-fraction__background {\n position: absolute;\n height: 100%;\n width: 100%;\n border-radius: calc(var(--gauge-circle-size) / 2);\n opacity: 0.1;\n z-index: -1;\n}\n\n.lh-fraction__content-wrapper {\n height: var(--gauge-circle-size);\n display: flex;\n align-items: center;\n}\n\n.lh-fraction__content {\n display: flex;\n position: relative;\n align-items: center;\n justify-content: center;\n font-size: calc(0.3 * var(--gauge-circle-size));\n line-height: calc(0.4 * var(--gauge-circle-size));\n width: max-content;\n min-width: calc(1.5 * var(--gauge-circle-size));\n padding: calc(0.1 * var(--gauge-circle-size)) calc(0.2 * var(--gauge-circle-size));\n --score-icon-size: calc(0.21 * var(--gauge-circle-size));\n --score-icon-margin: 0 calc(0.15 * var(--gauge-circle-size)) 0 0;\n}\n\n.lh-gauge {\n stroke-linecap: round;\n width: var(--gauge-circle-size);\n height: var(--gauge-circle-size);\n}\n\n.lh-category .lh-gauge {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n.lh-gauge-base {\n opacity: 0.1;\n}\n\n.lh-gauge-arc {\n fill: none;\n transform-origin: 50% 50%;\n animation: load-gauge var(--transition-length) ease both;\n animation-delay: 250ms;\n}\n\n.lh-gauge__svg-wrapper {\n position: relative;\n height: var(--gauge-circle-size);\n}\n.lh-category .lh-gauge__svg-wrapper,\n.lh-category .lh-fraction__wrapper {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n/* The plugin badge overlay */\n.lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size);\n height: var(--plugin-badge-size);\n background-color: var(--plugin-badge-background-color);\n background-image: var(--plugin-icon-url);\n background-repeat: no-repeat;\n background-size: var(--plugin-icon-size);\n background-position: 58% 50%;\n content: \"\";\n position: absolute;\n right: -6px;\n bottom: 0px;\n display: block;\n z-index: 100;\n box-shadow: 0 0 4px rgba(0,0,0,.2);\n border-radius: 25%;\n}\n.lh-category .lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size-big);\n height: var(--plugin-badge-size-big);\n}\n\n@keyframes load-gauge {\n from { stroke-dasharray: 0 352; }\n}\n\n.lh-gauge__percentage {\n width: 100%;\n height: var(--gauge-circle-size);\n position: absolute;\n font-family: var(--report-font-family-monospace);\n font-size: calc(var(--gauge-circle-size) * 0.34 + 1.3px);\n line-height: 0;\n text-align: center;\n top: calc(var(--score-container-padding) + var(--gauge-circle-size) / 2);\n}\n\n.lh-category .lh-gauge__percentage {\n --gauge-circle-size: var(--gauge-circle-size-big);\n --gauge-percentage-font-size: var(--gauge-percentage-font-size-big);\n}\n\n.lh-gauge__wrapper,\n.lh-fraction__wrapper {\n position: relative;\n display: flex;\n align-items: center;\n flex-direction: column;\n text-decoration: none;\n padding: var(--score-container-padding);\n\n --transition-length: 1s;\n\n /* Contain the layout style paint & layers during animation*/\n contain: content;\n will-change: opacity; /* Only using for layer promotion */\n}\n\n.lh-gauge__label,\n.lh-fraction__label {\n font-size: var(--gauge-label-font-size);\n font-weight: 500;\n line-height: var(--gauge-label-line-height);\n margin-top: 10px;\n text-align: center;\n color: var(--report-text-color);\n word-break: keep-all;\n}\n\n/* TODO(#8185) use more BEM (.lh-gauge__label--big) instead of relying on descendant selector */\n.lh-category .lh-gauge__label,\n.lh-category .lh-fraction__label {\n --gauge-label-font-size: var(--gauge-label-font-size-big);\n --gauge-label-line-height: var(--gauge-label-line-height-big);\n margin-top: 14px;\n}\n\n.lh-scores-header .lh-gauge__wrapper,\n.lh-scores-header .lh-fraction__wrapper,\n.lh-scores-header .lh-gauge--pwa__wrapper,\n.lh-sticky-header .lh-gauge__wrapper,\n.lh-sticky-header .lh-fraction__wrapper,\n.lh-sticky-header .lh-gauge--pwa__wrapper {\n width: var(--gauge-wrapper-width);\n}\n\n.lh-scorescale {\n display: inline-flex;\n\n gap: calc(var(--default-padding) * 4);\n margin: 16px auto 0 auto;\n font-size: var(--report-font-size-secondary);\n color: var(--color-gray-700);\n\n}\n\n.lh-scorescale-range {\n display: flex;\n align-items: center;\n font-family: var(--report-font-family-monospace);\n white-space: nowrap;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale {\n border: 0;\n display: flex;\n justify-content: center;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale-range {\n font-family: unset;\n font-size: 12px;\n}\n\n.lh-scorescale-wrap {\n display: contents;\n}\n\n/* Hide category score gauages if it's a single category report */\n.lh-header--solo-category .lh-scores-wrapper {\n display: none;\n}\n\n\n.lh-categories {\n width: 100%;\n}\n\n.lh-category {\n padding: var(--category-padding);\n max-width: var(--report-content-max-width);\n margin: 0 auto;\n\n scroll-margin-top: var(--sticky-header-buffer);\n}\n\n.lh-category-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n.lh-category-wrapper:last-of-type {\n border-bottom: 0;\n}\n\n.lh-category-header {\n margin-bottom: var(--section-padding-vertical);\n}\n\n.lh-category-header .lh-score__gauge {\n max-width: 400px;\n width: auto;\n margin: 0px auto;\n}\n\n.lh-category-header__finalscreenshot {\n display: grid;\n grid-template: none / 1fr 1px 1fr;\n justify-items: center;\n align-items: center;\n gap: var(--report-line-height);\n min-height: 288px;\n margin-bottom: var(--default-padding);\n}\n\n.lh-final-ss-image {\n /* constrain the size of the image to not be too large */\n max-height: calc(var(--gauge-circle-size-big) * 2.8);\n max-width: calc(var(--gauge-circle-size-big) * 3.5);\n border: 1px solid var(--color-gray-200);\n padding: 4px;\n border-radius: 3px;\n display: block;\n}\n\n.lh-category-headercol--separator {\n background: var(--color-gray-200);\n width: 1px;\n height: var(--gauge-circle-size-big);\n}\n\n@media screen and (max-width: 780px) {\n .lh-category-header__finalscreenshot {\n grid-template: 1fr 1fr / none\n }\n .lh-category-headercol--separator {\n display: none;\n }\n}\n\n\n/* 964 fits the min-width of the filmstrip */\n@media screen and (max-width: 964px) {\n .lh-report {\n margin-left: 0;\n width: 100%;\n }\n}\n\n@media print {\n body {\n -webkit-print-color-adjust: exact; /* print background colors */\n }\n .lh-container {\n display: block;\n }\n .lh-report {\n margin-left: 0;\n padding-top: 0;\n }\n .lh-categories {\n margin-top: 0;\n }\n}\n\n.lh-table {\n position: relative;\n border-collapse: separate;\n border-spacing: 0;\n /* Can't assign padding to table, so shorten the width instead. */\n width: calc(100% - var(--audit-description-padding-left) - var(--stackpack-padding-horizontal));\n border: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-table thead th {\n position: sticky;\n top: calc(var(--sticky-header-buffer) + 1em);\n z-index: 1;\n background-color: var(--report-background-color);\n border-bottom: 1px solid var(--report-border-color-secondary);\n font-weight: normal;\n color: var(--color-gray-600);\n /* See text-wrapping comment on .lh-container. */\n word-break: normal;\n}\n\n.lh-row--group {\n background-color: var(--table-group-header-background-color);\n}\n\n.lh-row--group td {\n font-weight: bold;\n font-size: 1.05em;\n color: var(--table-group-header-text-color);\n}\n\n.lh-row--group td:first-child {\n font-weight: normal;\n}\n\n.lh-row--group .lh-text {\n color: inherit;\n text-decoration: none;\n display: inline-block;\n}\n\n.lh-row--group a.lh-link:hover {\n text-decoration: underline;\n}\n\n.lh-row--group .lh-audit__adorn {\n text-transform: capitalize;\n font-weight: normal;\n padding: 2px 3px 1px 3px;\n}\n\n.lh-row--group .lh-audit__adorn1p {\n color: var(--link-color);\n border-color: var(--link-color);\n}\n\n.lh-row--group .lh-report-icon--external::before {\n content: \"\";\n background-repeat: no-repeat;\n width: 14px;\n height: 16px;\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n\n.lh-row--group .lh-report-icon--external {\n display: none;\n}\n\n.lh-row--group:hover .lh-report-icon--external {\n display: inline-block;\n}\n\n.lh-dark .lh-report-icon--external::before {\n filter: invert(1);\n}\n\n/** Manages indentation of two-level and three-level nested adjacent rows */\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) td:first-child {\n padding-left: 20px;\n}\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) ~ .lh-sub-item-row td:first-child {\n padding-left: 40px;\n}\n\n.lh-row--even {\n background-color: var(--table-group-header-background-color);\n}\n.lh-row--hidden {\n display: none;\n}\n\n.lh-table th,\n.lh-table td {\n padding: var(--default-padding);\n}\n\n.lh-table tr {\n vertical-align: middle;\n}\n\n.lh-table tr:hover {\n background-color: var(--table-higlight-background-color);\n}\n\n/* Looks unnecessary, but mostly for keeping the s left-aligned */\n.lh-table-column--text,\n.lh-table-column--source-location,\n.lh-table-column--url,\n/* .lh-table-column--thumbnail, */\n/* .lh-table-column--empty,*/\n.lh-table-column--code,\n.lh-table-column--node {\n text-align: left;\n}\n\n.lh-table-column--code {\n min-width: 100px;\n}\n\n.lh-table-column--bytes,\n.lh-table-column--timespanMs,\n.lh-table-column--ms,\n.lh-table-column--numeric {\n text-align: right;\n word-break: normal;\n}\n\n\n\n.lh-table .lh-table-column--thumbnail {\n width: var(--image-preview-size);\n}\n\n.lh-table-column--url {\n min-width: 250px;\n}\n\n.lh-table-column--text {\n min-width: 80px;\n}\n\n/* Keep columns narrow if they follow the URL column */\n/* 12% was determined to be a decent narrow width, but wide enough for column headings */\n.lh-table-column--url + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--ms,\n.lh-table-column--url + .lh-table-column--ms + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--timespanMs {\n width: 12%;\n}\n\n.lh-text__url-host {\n display: inline;\n}\n\n.lh-text__url-host {\n margin-left: calc(var(--report-font-size) / 2);\n opacity: 0.6;\n font-size: 90%\n}\n\n.lh-thumbnail {\n object-fit: cover;\n width: var(--image-preview-size);\n height: var(--image-preview-size);\n display: block;\n}\n\n.lh-unknown pre {\n overflow: scroll;\n border: solid 1px var(--color-gray-200);\n}\n\n.lh-text__url > a {\n color: inherit;\n text-decoration: none;\n}\n\n.lh-text__url > a:hover {\n text-decoration: underline dotted #999;\n}\n\n.lh-sub-item-row {\n margin-left: 20px;\n margin-bottom: 0;\n color: var(--color-gray-700);\n}\n\n.lh-sub-item-row td {\n padding-top: 4px;\n padding-bottom: 4px;\n padding-left: 20px;\n}\n\n/* Chevron\n https://codepen.io/paulirish/pen/LmzEmK\n */\n.lh-chevron {\n --chevron-angle: 42deg;\n /* Edge doesn't support transform: rotate(calc(...)), so we define it here */\n --chevron-angle-right: -42deg;\n width: var(--chevron-size);\n height: var(--chevron-size);\n margin-top: calc((var(--report-line-height) - 12px) / 2);\n}\n\n.lh-chevron__lines {\n transition: transform 0.4s;\n transform: translateY(var(--report-line-height));\n}\n.lh-chevron__line {\n stroke: var(--chevron-line-stroke);\n stroke-width: var(--chevron-size);\n stroke-linecap: square;\n transform-origin: 50%;\n transform: rotate(var(--chevron-angle));\n transition: transform 300ms, stroke 300ms;\n}\n\n.lh-expandable-details .lh-chevron__line-right,\n.lh-expandable-details[open] .lh-chevron__line-left {\n transform: rotate(var(--chevron-angle-right));\n}\n\n.lh-expandable-details[open] .lh-chevron__line-right {\n transform: rotate(var(--chevron-angle));\n}\n\n\n.lh-expandable-details[open] .lh-chevron__lines {\n transform: translateY(calc(var(--chevron-size) * -1));\n}\n\n.lh-expandable-details[open] {\n animation: 300ms openDetails forwards;\n padding-bottom: var(--default-padding);\n}\n\n@keyframes openDetails {\n from {\n outline: 1px solid var(--report-background-color);\n }\n to {\n outline: 1px solid;\n box-shadow: 0 2px 4px rgba(0, 0, 0, .24);\n }\n}\n\n@media screen and (max-width: 780px) {\n /* no black outline if we're not confident the entire table can be displayed within bounds */\n .lh-expandable-details[open] {\n animation: none;\n }\n}\n\n.lh-expandable-details[open] summary, details.lh-clump > summary {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\ndetails.lh-clump[open] > summary {\n border-bottom-width: 0;\n}\n\n\n\ndetails .lh-clump-toggletext--hide,\ndetails[open] .lh-clump-toggletext--show { display: none; }\ndetails[open] .lh-clump-toggletext--hide { display: block;}\n\n\n/* Tooltip */\n.lh-tooltip-boundary {\n position: relative;\n}\n\n.lh-tooltip {\n position: absolute;\n display: none; /* Don't retain these layers when not needed */\n opacity: 0;\n background: #ffffff;\n white-space: pre-line; /* Render newlines in the text */\n min-width: 246px;\n max-width: 275px;\n padding: 15px;\n border-radius: 5px;\n text-align: initial;\n line-height: 1.4;\n}\n/* shrink tooltips to not be cutoff on left edge of narrow viewports\n 45vw is chosen to be ~= width of the left column of metrics\n*/\n@media screen and (max-width: 535px) {\n .lh-tooltip {\n min-width: 45vw;\n padding: 3vw;\n }\n}\n\n.lh-tooltip-boundary:hover .lh-tooltip {\n display: block;\n animation: fadeInTooltip 250ms;\n animation-fill-mode: forwards;\n animation-delay: 850ms;\n bottom: 100%;\n z-index: 1;\n will-change: opacity;\n right: 0;\n pointer-events: none;\n}\n\n.lh-tooltip::before {\n content: \"\";\n border: solid transparent;\n border-bottom-color: #fff;\n border-width: 10px;\n position: absolute;\n bottom: -20px;\n right: 6px;\n transform: rotate(180deg);\n pointer-events: none;\n}\n\n@keyframes fadeInTooltip {\n 0% { opacity: 0; }\n 75% { opacity: 1; }\n 100% { opacity: 1; filter: drop-shadow(1px 0px 1px #aaa) drop-shadow(0px 2px 4px hsla(206, 6%, 25%, 0.15)); pointer-events: auto; }\n}\n\n/* Element screenshot */\n.lh-element-screenshot {\n float: left;\n margin-right: 20px;\n}\n.lh-element-screenshot__content {\n overflow: hidden;\n min-width: 110px;\n display: flex;\n justify-content: center;\n background-color: var(--report-background-color);\n}\n.lh-element-screenshot__image {\n position: relative;\n /* Set by ElementScreenshotRenderer.installFullPageScreenshotCssVariable */\n background-image: var(--element-screenshot-url);\n outline: 2px solid #777;\n background-color: white;\n background-repeat: no-repeat;\n}\n.lh-element-screenshot__mask {\n position: absolute;\n background: #555;\n opacity: 0.8;\n}\n.lh-element-screenshot__element-marker {\n position: absolute;\n outline: 2px solid var(--color-lime-400);\n}\n.lh-element-screenshot__overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 2000; /* .lh-topbar is 1000 */\n background: var(--screenshot-overlay-background);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: zoom-out;\n}\n\n.lh-element-screenshot__overlay .lh-element-screenshot {\n margin-right: 0; /* clearing margin used in thumbnail case */\n outline: 1px solid var(--color-gray-700);\n}\n\n.lh-screenshot-overlay--enabled .lh-element-screenshot {\n cursor: zoom-out;\n}\n.lh-screenshot-overlay--enabled .lh-node .lh-element-screenshot {\n cursor: zoom-in;\n}\n\n\n.lh-meta__items {\n --meta-icon-size: calc(var(--report-icon-size) * 0.667);\n padding: var(--default-padding);\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n background-color: var(--env-item-background-color);\n border-radius: 3px;\n margin: 0 0 var(--default-padding) 0;\n font-size: 12px;\n column-gap: var(--default-padding);\n color: var(--color-gray-700);\n}\n\n.lh-meta__item {\n display: block;\n list-style-type: none;\n position: relative;\n padding: 0 0 0 calc(var(--meta-icon-size) + var(--default-padding) * 2);\n cursor: unset; /* disable pointer cursor from report-icon */\n}\n\n.lh-meta__item.lh-tooltip-boundary {\n text-decoration: dotted underline var(--color-gray-500);\n cursor: help;\n}\n\n.lh-meta__item.lh-report-icon::before {\n position: absolute;\n left: var(--default-padding);\n width: var(--meta-icon-size);\n height: var(--meta-icon-size);\n}\n\n.lh-meta__item.lh-report-icon:hover::before {\n opacity: 0.7;\n}\n\n.lh-meta__item .lh-tooltip {\n color: var(--color-gray-800);\n}\n\n.lh-meta__item .lh-tooltip::before {\n right: auto; /* Set the tooltip arrow to the leftside */\n left: 6px;\n}\n\n/* Change the grid for narrow viewport. */\n@media screen and (max-width: 640px) {\n .lh-meta__items {\n grid-template-columns: 1fr 1fr;\n }\n}\n@media screen and (max-width: 535px) {\n .lh-meta__items {\n display: block;\n }\n}\n\n\n/*# sourceURL=report-styles.css */\n"); el0.append(el1); return el0; } From c1d75f860caf1d375bea415d63fbdc5d64a21a4f Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Thu, 21 Sep 2023 18:40:16 -0700 Subject: [PATCH 15/31] nit --- report/renderer/components.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/report/renderer/components.js b/report/renderer/components.js index 3e9da212182b..28305435855d 100644 --- a/report/renderer/components.js +++ b/report/renderer/components.js @@ -520,7 +520,7 @@ function createSnippetLineComponent(dom) { function createStylesComponent(dom) { const el0 = dom.createFragment(); const el1 = dom.createElement("style"); - el1.append("/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: Apache-2.0\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 --report-icon-size: var(--score-icon-background-size);\n --report-line-height: 24px;\n --report-line-height-secondary: 20px;\n --report-monospace-font-size: calc(var(--report-font-size) * 0.85);\n --report-text-color-secondary: var(--color-gray-800);\n --report-text-color: var(--color-gray-900);\n --report-content-max-width: calc(60 * var(--report-font-size)); /* defaults to 840px */\n --report-content-min-width: 360px;\n --report-content-max-width-minus-edge-gap: calc(var(--report-content-max-width) - var(--edge-gap-padding) * 2);\n --score-container-padding: 8px;\n --score-icon-background-size: 24px;\n --score-icon-margin-left: 6px;\n --score-icon-margin-right: 14px;\n --score-icon-margin: 0 var(--score-icon-margin-right) 0 var(--score-icon-margin-left);\n --score-icon-size: 12px;\n --score-icon-size-big: 16px;\n --screenshot-overlay-background: rgba(0, 0, 0, 0.3);\n --section-padding-vertical: calc(var(--default-padding) * 6);\n --snippet-background-color: var(--color-gray-50);\n --snippet-color: #0938C2;\n --sparkline-height: 5px;\n --stackpack-padding-horizontal: 10px;\n --sticky-header-background-color: var(--report-background-color);\n --sticky-header-buffer: calc(var(--topbar-height) + var(--sticky-header-height));\n --sticky-header-height: calc(var(--gauge-circle-size-sm) + var(--score-container-padding) * 2);\n --table-group-header-background-color: #EEF1F4;\n --table-group-header-text-color: var(--color-gray-700);\n --table-higlight-background-color: #F5F7FA;\n --tools-icon-color: var(--color-gray-600);\n --topbar-background-color: var(--color-white);\n --topbar-height: 32px;\n --topbar-logo-size: 24px;\n --topbar-padding: 0 8px;\n --toplevel-warning-background-color: hsla(30, 100%, 75%, 10%);\n --toplevel-warning-message-text-color: var(--color-average-secondary);\n --toplevel-warning-padding: 18px;\n --toplevel-warning-text-color: var(--report-text-color);\n\n /* SVGs */\n --plugin-icon-url-dark: url('data:image/svg+xml;utf8,');\n --plugin-icon-url: url('data:image/svg+xml;utf8,');\n\n --pass-icon-url: url('data:image/svg+xml;utf8,check');\n --average-icon-url: url('data:image/svg+xml;utf8,info');\n --fail-icon-url: url('data:image/svg+xml;utf8,warn');\n --error-icon-url: url('data:image/svg+xml;utf8,error');\n\n --pwa-installable-gray-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-gray-url-dark: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url-dark: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-color-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-color-url: url('data:image/svg+xml;utf8,');\n\n --swap-locale-icon-url: url('data:image/svg+xml;utf8,');\n}\n\n@media not print {\n .lh-dark {\n /* Pallete */\n --color-gray-200: var(--color-gray-800);\n --color-gray-300: #616161;\n --color-gray-400: var(--color-gray-600);\n --color-gray-700: var(--color-gray-400);\n --color-gray-50: #757575;\n --color-gray-600: var(--color-gray-500);\n --color-green-700: var(--color-green);\n --color-orange-700: var(--color-orange);\n --color-red-700: var(--color-red);\n --color-teal-600: var(--color-cyan-500);\n\n /* Context-specific colors */\n --color-hover: rgba(0, 0, 0, 0.2);\n --color-informative: var(--color-blue-200);\n\n /* Component variables */\n --env-item-background-color: #393535;\n --link-color: var(--color-blue-200);\n --locale-selector-background-color: var(--color-gray-200);\n --plugin-badge-background-color: var(--color-gray-800);\n --report-background-color: var(--color-gray-900);\n --report-border-color-secondary: var(--color-gray-200);\n --report-text-color-secondary: var(--color-gray-400);\n --report-text-color: var(--color-gray-100);\n --snippet-color: var(--color-cyan-500);\n --topbar-background-color: var(--color-gray);\n --toplevel-warning-background-color: hsl(33deg 14% 18%);\n --toplevel-warning-message-text-color: var(--color-orange-700);\n --toplevel-warning-text-color: var(--color-gray-100);\n --table-group-header-background-color: rgba(186, 196, 206, 0.15);\n --table-group-header-text-color: var(--color-gray-100);\n --table-higlight-background-color: rgba(186, 196, 206, 0.09);\n\n /* SVGs */\n --plugin-icon-url: var(--plugin-icon-url-dark);\n --pwa-installable-gray-url: var(--pwa-installable-gray-url-dark);\n --pwa-optimized-gray-url: var(--pwa-optimized-gray-url-dark);\n }\n}\n\n@media only screen and (max-width: 480px) {\n .lh-vars {\n --audit-group-margin-bottom: 20px;\n --edge-gap-padding: var(--default-padding);\n --env-name-min-width: 120px;\n --gauge-circle-size-big: 96px;\n --gauge-circle-size: 72px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 112px;\n --header-padding: 16px 0 16px 0;\n --image-preview-size: 24px;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-size: 14px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --topbar-height: 28px;\n --topbar-logo-size: 20px;\n }\n\n /* Not enough space to adequately show the relative savings bars. */\n .lh-sparkline {\n display: none;\n }\n}\n\n.lh-vars.lh-devtools {\n --audit-explanation-line-height: 14px;\n --audit-group-margin-bottom: 20px;\n --audit-group-padding-vertical: 12px;\n --audit-padding-vertical: 4px;\n --category-padding: 12px;\n --default-padding: 12px;\n --env-name-min-width: 120px;\n --footer-padding-vertical: 8px;\n --gauge-circle-size-big: 72px;\n --gauge-circle-size: 64px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 97px;\n --header-line-height: 20px;\n --header-padding: 16px 0 16px 0;\n --screenshot-overlay-background: transparent;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-family-monospace: 'Menlo', 'dejavu sans mono', 'Consolas', 'Lucida Console', monospace;\n --report-font-family: '.SFNSDisplay-Regular', 'Helvetica Neue', 'Lucida Grande', sans-serif;\n --report-font-size: 12px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --section-padding-vertical: 8px;\n}\n\n.lh-container:not(.lh-topbar + .lh-container) {\n --topbar-height: 0;\n --sticky-header-height: 0;\n --sticky-header-buffer: 0;\n}\n\n.lh-devtools.lh-root {\n height: 100%;\n}\n.lh-devtools.lh-root img {\n /* Override devtools default 'min-width: 0' so svg without size in a flexbox isn't collapsed. */\n min-width: auto;\n}\n.lh-devtools .lh-container {\n overflow-y: scroll;\n height: calc(100% - var(--topbar-height));\n /** The .lh-container is the scroll parent in DevTools so we exclude the topbar from the sticky header buffer. */\n --sticky-header-buffer: calc(var(--sticky-header-height));\n}\n@media print {\n .lh-devtools .lh-container {\n overflow: unset;\n }\n}\n.lh-devtools .lh-sticky-header {\n /* This is normally the height of the topbar, but we want it to stick to the top of our scroll container .lh-container` */\n top: 0;\n}\n.lh-devtools .lh-element-screenshot__overlay {\n position: absolute;\n}\n\n@keyframes fadeIn {\n 0% { opacity: 0;}\n 100% { opacity: 0.6;}\n}\n\n.lh-root *, .lh-root *::before, .lh-root *::after {\n box-sizing: border-box;\n}\n\n.lh-root {\n font-family: var(--report-font-family);\n font-size: var(--report-font-size);\n margin: 0;\n line-height: var(--report-line-height);\n background: var(--report-background-color);\n color: var(--report-text-color);\n}\n\n.lh-root :focus-visible {\n outline: -webkit-focus-ring-color auto 3px;\n}\n.lh-root summary:focus {\n outline: none;\n box-shadow: 0 0 0 1px hsl(217, 89%, 61%);\n}\n\n.lh-root [hidden] {\n display: none !important;\n}\n\n.lh-root pre {\n margin: 0;\n}\n\n.lh-root pre,\n.lh-root code {\n font-family: var(--report-font-family-monospace);\n}\n\n.lh-root details > summary {\n cursor: pointer;\n}\n\n.lh-hidden {\n display: none !important;\n}\n\n.lh-container {\n /*\n Text wrapping in the report is so much FUN!\n We have a `word-break: break-word;` globally here to prevent a few common scenarios, namely\n long non-breakable text (usually URLs) found in:\n 1. The footer\n 2. .lh-node (outerHTML)\n 3. .lh-code\n\n With that sorted, the next challenge is appropriate column sizing and text wrapping inside our\n .lh-details tables. Even more fun.\n * We don't want table headers (\"Potential Savings (ms)\") to wrap or their column values, but\n we'd be happy for the URL column to wrap if the URLs are particularly long.\n * We want the narrow columns to remain narrow, providing the most column width for URL\n * We don't want the table to extend past 100% width.\n * Long URLs in the URL column can wrap. Util.getURLDisplayName maxes them out at 64 characters,\n but they do not get any overflow:ellipsis treatment.\n */\n word-break: break-word;\n}\n\n.lh-audit-group a,\n.lh-category-header__description a,\n.lh-audit__description a,\n.lh-warnings a,\n.lh-footer a,\n.lh-table-column--link a {\n color: var(--link-color);\n}\n\n.lh-audit__description, .lh-audit__stackpack {\n --inner-audit-padding-right: var(--stackpack-padding-horizontal);\n padding-left: var(--audit-description-padding-left);\n padding-right: var(--inner-audit-padding-right);\n padding-top: 8px;\n padding-bottom: 8px;\n}\n\n.lh-details {\n margin-top: var(--default-padding);\n margin-bottom: var(--default-padding);\n margin-left: var(--audit-description-padding-left);\n /* whatever the .lh-details side margins are */\n width: 100%;\n}\n\n.lh-audit__stackpack {\n display: flex;\n align-items: center;\n}\n\n.lh-audit__stackpack__img {\n max-width: 30px;\n margin-right: var(--default-padding)\n}\n\n/* Report header */\n\n.lh-report-icon {\n display: flex;\n align-items: center;\n padding: 10px 12px;\n cursor: pointer;\n}\n.lh-report-icon[disabled] {\n opacity: 0.3;\n pointer-events: none;\n}\n\n.lh-report-icon::before {\n content: \"\";\n margin: 4px;\n background-repeat: no-repeat;\n width: var(--report-icon-size);\n height: var(--report-icon-size);\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n.lh-report-icon:hover::before {\n opacity: 1;\n}\n.lh-dark .lh-report-icon::before {\n filter: invert(1);\n}\n.lh-report-icon--print::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--copy::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--open::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--download::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--dark::before {\n background-image:url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--treemap::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--date::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--devices::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--world::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--stopwatch::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--networkspeed::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-one::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-many::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--chrome::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--external::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n\n.lh-buttons {\n display: flex;\n flex-wrap: wrap;\n margin: var(--default-padding) 0;\n}\n.lh-button {\n height: 32px;\n border: 1px solid var(--report-border-color-secondary);\n border-radius: 3px;\n color: var(--link-color);\n background-color: var(--report-background-color);\n margin: 5px;\n}\n\n.lh-button:first-of-type {\n margin-left: 0;\n}\n\n/* Node */\n.lh-node__snippet {\n font-family: var(--report-font-family-monospace);\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n line-height: 20px;\n}\n\n/* Score */\n\n.lh-audit__score-icon {\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n margin: var(--score-icon-margin);\n}\n\n.lh-audit--pass .lh-audit__display-text {\n color: var(--color-pass-secondary);\n}\n.lh-audit--pass .lh-audit__score-icon,\n.lh-scorescale-range--pass::before {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-audit__display-text {\n color: var(--color-average-secondary);\n}\n.lh-audit--average .lh-audit__score-icon,\n.lh-scorescale-range--average::before {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-audit--fail .lh-audit__display-text {\n color: var(--color-fail-secondary);\n}\n.lh-audit--fail .lh-audit__score-icon,\n.lh-audit--error .lh-audit__score-icon,\n.lh-scorescale-range--fail::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-audit--error .lh-audit__score-icon,\n.lh-metric--error .lh-metric__icon {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n border: none;\n}\n\n.lh-gauge__wrapper--fail .lh-gauge--error {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n transform: scale(0.5);\n top: var(--score-container-padding);\n}\n\n.lh-audit--manual .lh-audit__display-text,\n.lh-audit--notapplicable .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n.lh-audit--manual .lh-audit__score-icon,\n.lh-audit--notapplicable .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n background: none;\n}\n\n.lh-audit--informative .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n\n.lh-audit--informative .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n}\n\n.lh-audit__description,\n.lh-audit__stackpack {\n color: var(--report-text-color-secondary);\n}\n.lh-audit__adorn {\n border: 1px solid var(--color-gray-500);\n border-radius: 3px;\n margin: 0 3px;\n padding: 0 2px;\n line-height: 1.1;\n display: inline-block;\n font-size: 90%;\n color: var(--report-text-color-secondary);\n}\n\n.lh-category-header__description {\n text-align: center;\n color: var(--color-gray-700);\n margin: 0px auto;\n max-width: 400px;\n}\n\n\n.lh-audit__display-text,\n.lh-load-opportunity__sparkline,\n.lh-chevron-container {\n margin: 0 var(--audit-margin-horizontal);\n}\n.lh-chevron-container {\n margin-right: 0;\n}\n\n.lh-audit__title-and-text {\n flex: 1;\n}\n\n.lh-audit__title-and-text code {\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n}\n\n/* Prepend display text with em dash separator. But not in Opportunities. */\n.lh-audit__display-text:not(:empty):before {\n content: '—';\n margin-right: var(--audit-margin-horizontal);\n}\n.lh-audit-group.lh-audit-group--load-opportunities .lh-audit__display-text:not(:empty):before {\n display: none;\n}\n\n/* Expandable Details (Audit Groups, Audits) */\n.lh-audit__header {\n display: flex;\n align-items: center;\n padding: var(--default-padding);\n}\n\n.lh-audit--load-opportunity .lh-audit__header {\n display: block;\n}\n\n\n.lh-metricfilter {\n display: grid;\n justify-content: end;\n align-items: center;\n grid-auto-flow: column;\n gap: 4px;\n color: var(--color-gray-700);\n}\n\n.lh-metricfilter__radio {\n /*\n * Instead of hiding, position offscreen so it's still accessible to screen readers\n * https://bugs.chromium.org/p/chromium/issues/detail?id=1439785\n */\n position: fixed;\n left: -9999px;\n}\n.lh-metricfilter input[type='radio']:focus-visible + label {\n outline: -webkit-focus-ring-color auto 1px;\n}\n\n.lh-metricfilter__label {\n display: inline-flex;\n padding: 0 4px;\n height: 16px;\n text-decoration: underline;\n align-items: center;\n cursor: pointer;\n font-size: 90%;\n}\n\n.lh-metricfilter__label--active {\n background: var(--color-blue-primary);\n color: var(--color-white);\n border-radius: 3px;\n text-decoration: none;\n}\n/* Give the 'All' choice a more muted display */\n.lh-metricfilter__label--active[for=\"metric-All\"] {\n background-color: var(--color-blue-200) !important;\n color: black !important;\n}\n\n.lh-metricfilter__text {\n margin-right: 8px;\n}\n\n/* If audits are filtered, hide the itemcount for Passed Audits… */\n.lh-category--filtered .lh-audit-group .lh-audit-group__itemcount {\n display: none;\n}\n\n\n.lh-audit__header:hover {\n background-color: var(--color-hover);\n}\n\n/* We want to hide the browser's default arrow marker on summary elements. Admittedly, it's complicated. */\n.lh-root details > summary {\n /* Blink 89+ and Firefox will hide the arrow when display is changed from (new) default of `list-item` to block. https://chromestatus.com/feature/6730096436051968*/\n display: block;\n}\n/* Safari and Blink <=88 require using the -webkit-details-marker selector */\n.lh-root details > summary::-webkit-details-marker {\n display: none;\n}\n\n/* Perf Metric */\n\n.lh-metrics-container {\n display: grid;\n grid-auto-rows: 1fr;\n grid-template-columns: 1fr 1fr;\n grid-column-gap: var(--report-line-height);\n margin-bottom: var(--default-padding);\n}\n\n.lh-metric {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(-n+2) {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-metric__innerwrap {\n display: grid;\n /**\n * Icon -- Metric Name\n * -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 1fr;\n align-items: center;\n padding: var(--default-padding);\n}\n\n.lh-metric__details {\n order: -1;\n}\n\n.lh-metric__title {\n flex: 1;\n}\n\n.lh-calclink {\n padding-left: calc(1ex / 3);\n}\n\n.lh-metric__description {\n display: none;\n grid-column-start: 2;\n grid-column-end: 4;\n color: var(--report-text-color-secondary);\n}\n\n.lh-metric__value {\n font-size: var(--metric-value-font-size);\n margin: calc(var(--default-padding) / 2) 0;\n white-space: nowrap; /* No wrapping between metric value and the icon */\n grid-column-start: 2;\n}\n\n\n@media screen and (max-width: 535px) {\n .lh-metrics-container {\n display: block;\n }\n\n .lh-metric {\n border-bottom: none !important;\n }\n .lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(1) {\n border-bottom: 1px solid var(--report-border-color-secondary) !important;\n }\n\n /* Change the grid to 3 columns for narrow viewport. */\n .lh-metric__innerwrap {\n /**\n * Icon -- Metric Name -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 2fr 1fr;\n }\n .lh-metric__value {\n justify-self: end;\n grid-column-start: unset;\n }\n}\n\n/* No-JS toggle switch */\n/* Keep this selector sync'd w/ `magicSelector` in report-ui-features-test.js */\n .lh-metrics-toggle__input:checked ~ .lh-metrics-container .lh-metric__description {\n display: block;\n}\n\n/* TODO get rid of the SVGS and clean up these some more */\n.lh-metrics-toggle__input {\n opacity: 0;\n position: absolute;\n right: 0;\n top: 0px;\n}\n\n.lh-metrics-toggle__input + div > label > .lh-metrics-toggle__labeltext--hide,\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--show {\n display: none;\n}\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--hide {\n display: inline;\n}\n.lh-metrics-toggle__input:focus + div > label {\n outline: -webkit-focus-ring-color auto 3px;\n}\n\n.lh-metrics-toggle__label {\n cursor: pointer;\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n/* Pushes the metric description toggle button to the right. */\n.lh-audit-group--metrics .lh-audit-group__header {\n display: flex;\n justify-content: space-between;\n}\n\n.lh-metric__icon,\n.lh-scorescale-range::before {\n content: '';\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n display: inline-block;\n margin: var(--score-icon-margin);\n}\n\n.lh-metric--pass .lh-metric__value {\n color: var(--color-pass-secondary);\n}\n.lh-metric--pass .lh-metric__icon {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-metric--average .lh-metric__value {\n color: var(--color-average-secondary);\n}\n.lh-metric--average .lh-metric__icon {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-metric--fail .lh-metric__value {\n color: var(--color-fail-secondary);\n}\n.lh-metric--fail .lh-metric__icon {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-metric--error .lh-metric__value,\n.lh-metric--error .lh-metric__description {\n color: var(--color-fail-secondary);\n}\n\n/* Perf load opportunity */\n\n.lh-load-opportunity__cols {\n display: flex;\n align-items: flex-start;\n}\n\n.lh-load-opportunity__header .lh-load-opportunity__col {\n color: var(--color-gray-600);\n display: unset;\n line-height: calc(2.3 * var(--report-font-size));\n}\n\n.lh-load-opportunity__col {\n display: flex;\n}\n\n.lh-load-opportunity__col--one {\n flex: 5;\n align-items: center;\n margin-right: 2px;\n}\n.lh-load-opportunity__col--two {\n flex: 4;\n text-align: right;\n}\n\n.lh-audit--load-opportunity .lh-audit__display-text {\n text-align: right;\n flex: 0 0 7.5ch;\n}\n\n\n/* Sparkline */\n\n.lh-load-opportunity__sparkline {\n flex: 1;\n margin-top: calc((var(--report-line-height) - var(--sparkline-height)) / 2);\n}\n\n.lh-sparkline {\n height: var(--sparkline-height);\n width: 100%;\n}\n\n.lh-sparkline__bar {\n height: 100%;\n float: right;\n}\n\n.lh-audit--pass .lh-sparkline__bar {\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-sparkline__bar {\n background: var(--color-average);\n}\n\n.lh-audit--fail .lh-sparkline__bar {\n background: var(--color-fail);\n}\n\n/* Filmstrip */\n\n.lh-filmstrip-container {\n /* smaller gap between metrics and filmstrip */\n margin: -8px auto 0 auto;\n}\n\n.lh-filmstrip {\n display: grid;\n justify-content: space-between;\n padding-bottom: var(--default-padding);\n width: 100%;\n grid-template-columns: repeat(auto-fit, 90px);\n}\n\n.lh-filmstrip__frame {\n text-align: right;\n position: relative;\n}\n\n.lh-filmstrip__thumbnail {\n border: 1px solid var(--report-border-color-secondary);\n max-height: 150px;\n max-width: 120px;\n}\n\n/* Audit */\n\n.lh-audit {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n/* Apply border-top to just the first audit. */\n.lh-audit {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n.lh-audit ~ .lh-audit {\n border-top: none;\n}\n\n\n.lh-audit--error .lh-audit__display-text {\n color: var(--color-fail-secondary);\n}\n\n/* Audit Group */\n\n.lh-audit-group {\n margin-bottom: var(--audit-group-margin-bottom);\n position: relative;\n}\n.lh-audit-group--metrics {\n margin-bottom: calc(var(--audit-group-margin-bottom) / 2);\n}\n\n.lh-audit-group__header::before {\n /* By default, groups don't get an icon */\n content: none;\n width: var(--pwa-icon-size);\n height: var(--pwa-icon-size);\n margin: var(--pwa-icon-margin);\n display: inline-block;\n vertical-align: middle;\n}\n\n/* Style the \"over budget\" columns red. */\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(4),\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(5),\n.lh-audit-group--budgets #timing-budget tbody tr td:nth-child(3) {\n color: var(--color-red-700);\n}\n\n/* Align the \"over budget request count\" text to be close to the \"over budget bytes\" column. */\n.lh-audit-group--budgets .lh-table tbody tr td:nth-child(4){\n text-align: right;\n}\n\n.lh-audit-group--budgets .lh-details--budget {\n width: 100%;\n margin: 0 0 var(--default-padding);\n}\n\n.lh-audit-group--pwa-installable .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-installable-gray-url);\n}\n.lh-audit-group--pwa-optimized .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-optimized-gray-url);\n}\n.lh-audit-group--pwa-installable.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-installable-color-url);\n}\n.lh-audit-group--pwa-optimized.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-optimized-color-url);\n}\n\n.lh-audit-group--metrics .lh-audit-group__summary {\n margin-top: 0;\n margin-bottom: 0;\n}\n\n.lh-audit-group__summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.lh-audit-group__header .lh-chevron {\n margin-top: calc((var(--report-line-height) - 5px) / 2);\n}\n\n.lh-audit-group__header {\n letter-spacing: 0.8px;\n padding: var(--default-padding);\n padding-left: 0;\n}\n\n.lh-audit-group__header, .lh-audit-group__summary {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n.lh-audit-group__title {\n text-transform: uppercase;\n font-weight: 500;\n}\n\n.lh-audit-group__itemcount {\n color: var(--color-gray-600);\n}\n\n.lh-audit-group__footer {\n color: var(--color-gray-600);\n display: block;\n margin-top: var(--default-padding);\n}\n\n.lh-details,\n.lh-category-header__description,\n.lh-load-opportunity__header,\n.lh-audit-group__footer {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n}\n\n.lh-audit-explanation {\n margin: var(--audit-padding-vertical) 0 calc(var(--audit-padding-vertical) / 2) var(--audit-margin-horizontal);\n line-height: var(--audit-explanation-line-height);\n display: inline-block;\n}\n\n.lh-audit--fail .lh-audit-explanation {\n color: var(--color-fail-secondary);\n}\n\n/* Report */\n.lh-list > :not(:last-child) {\n margin-bottom: calc(var(--default-padding) * 2);\n}\n\n.lh-header-container {\n display: block;\n margin: 0 auto;\n position: relative;\n word-wrap: break-word;\n}\n\n.lh-header-container .lh-scores-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n\n\n.lh-report {\n min-width: var(--report-content-min-width);\n}\n\n.lh-exception {\n font-size: large;\n}\n\n.lh-code {\n white-space: normal;\n margin-top: 0;\n font-size: var(--report-monospace-font-size);\n}\n\n.lh-warnings {\n --item-margin: calc(var(--report-line-height) / 6);\n color: var(--color-average-secondary);\n margin: var(--audit-padding-vertical) 0;\n padding: var(--default-padding)\n var(--default-padding)\n var(--default-padding)\n calc(var(--audit-description-padding-left));\n background-color: var(--toplevel-warning-background-color);\n}\n.lh-warnings span {\n font-weight: bold;\n}\n\n.lh-warnings--toplevel {\n --item-margin: calc(var(--header-line-height) / 4);\n color: var(--toplevel-warning-text-color);\n margin-left: auto;\n margin-right: auto;\n max-width: var(--report-content-max-width-minus-edge-gap);\n padding: var(--toplevel-warning-padding);\n border-radius: 8px;\n}\n\n.lh-warnings__msg {\n color: var(--toplevel-warning-message-text-color);\n margin: 0;\n}\n\n.lh-warnings ul {\n margin: 0;\n}\n.lh-warnings li {\n margin: var(--item-margin) 0;\n}\n.lh-warnings li:last-of-type {\n margin-bottom: 0;\n}\n\n.lh-scores-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n}\n.lh-scores-header__solo {\n padding: 0;\n border: 0;\n}\n\n/* Gauge */\n\n.lh-gauge__wrapper--pass {\n color: var(--color-pass-secondary);\n fill: var(--color-pass);\n stroke: var(--color-pass);\n}\n\n.lh-gauge__wrapper--average {\n color: var(--color-average-secondary);\n fill: var(--color-average);\n stroke: var(--color-average);\n}\n\n.lh-gauge__wrapper--fail {\n color: var(--color-fail-secondary);\n fill: var(--color-fail);\n stroke: var(--color-fail);\n}\n\n.lh-gauge__wrapper--not-applicable {\n color: var(--color-not-applicable);\n fill: var(--color-not-applicable);\n stroke: var(--color-not-applicable);\n}\n\n.lh-fraction__wrapper .lh-fraction__content::before {\n content: '';\n height: var(--score-icon-size);\n width: var(--score-icon-size);\n margin: var(--score-icon-margin);\n display: inline-block;\n}\n.lh-fraction__wrapper--pass .lh-fraction__content {\n color: var(--color-pass-secondary);\n}\n.lh-fraction__wrapper--pass .lh-fraction__background {\n background-color: var(--color-pass);\n}\n.lh-fraction__wrapper--pass .lh-fraction__content::before {\n background-color: var(--color-pass);\n border-radius: 50%;\n}\n.lh-fraction__wrapper--average .lh-fraction__content {\n color: var(--color-average-secondary);\n}\n.lh-fraction__wrapper--average .lh-fraction__background,\n.lh-fraction__wrapper--average .lh-fraction__content::before {\n background-color: var(--color-average);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content {\n color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__background {\n background-color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n.lh-fraction__wrapper--null .lh-fraction__content {\n color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__background {\n background-color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__content::before {\n border-radius: 50%;\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-700);\n}\n\n.lh-fraction__background {\n position: absolute;\n height: 100%;\n width: 100%;\n border-radius: calc(var(--gauge-circle-size) / 2);\n opacity: 0.1;\n z-index: -1;\n}\n\n.lh-fraction__content-wrapper {\n height: var(--gauge-circle-size);\n display: flex;\n align-items: center;\n}\n\n.lh-fraction__content {\n display: flex;\n position: relative;\n align-items: center;\n justify-content: center;\n font-size: calc(0.3 * var(--gauge-circle-size));\n line-height: calc(0.4 * var(--gauge-circle-size));\n width: max-content;\n min-width: calc(1.5 * var(--gauge-circle-size));\n padding: calc(0.1 * var(--gauge-circle-size)) calc(0.2 * var(--gauge-circle-size));\n --score-icon-size: calc(0.21 * var(--gauge-circle-size));\n --score-icon-margin: 0 calc(0.15 * var(--gauge-circle-size)) 0 0;\n}\n\n.lh-gauge {\n stroke-linecap: round;\n width: var(--gauge-circle-size);\n height: var(--gauge-circle-size);\n}\n\n.lh-category .lh-gauge {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n.lh-gauge-base {\n opacity: 0.1;\n}\n\n.lh-gauge-arc {\n fill: none;\n transform-origin: 50% 50%;\n animation: load-gauge var(--transition-length) ease both;\n animation-delay: 250ms;\n}\n\n.lh-gauge__svg-wrapper {\n position: relative;\n height: var(--gauge-circle-size);\n}\n.lh-category .lh-gauge__svg-wrapper,\n.lh-category .lh-fraction__wrapper {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n/* The plugin badge overlay */\n.lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size);\n height: var(--plugin-badge-size);\n background-color: var(--plugin-badge-background-color);\n background-image: var(--plugin-icon-url);\n background-repeat: no-repeat;\n background-size: var(--plugin-icon-size);\n background-position: 58% 50%;\n content: \"\";\n position: absolute;\n right: -6px;\n bottom: 0px;\n display: block;\n z-index: 100;\n box-shadow: 0 0 4px rgba(0,0,0,.2);\n border-radius: 25%;\n}\n.lh-category .lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size-big);\n height: var(--plugin-badge-size-big);\n}\n\n@keyframes load-gauge {\n from { stroke-dasharray: 0 352; }\n}\n\n.lh-gauge__percentage {\n width: 100%;\n height: var(--gauge-circle-size);\n line-height: var(--gauge-circle-size);\n position: absolute;\n font-family: var(--report-font-family-monospace);\n font-size: calc(var(--gauge-circle-size) * 0.34 + 1.3px);\n text-align: center;\n top: var(--score-container-padding);\n}\n\n.lh-category .lh-gauge__percentage {\n --gauge-circle-size: var(--gauge-circle-size-big);\n --gauge-percentage-font-size: var(--gauge-percentage-font-size-big);\n}\n\n.lh-gauge__wrapper,\n.lh-fraction__wrapper {\n position: relative;\n display: flex;\n align-items: center;\n flex-direction: column;\n text-decoration: none;\n padding: var(--score-container-padding);\n\n --transition-length: 1s;\n\n /* Contain the layout style paint & layers during animation*/\n contain: content;\n will-change: opacity; /* Only using for layer promotion */\n}\n\n.lh-gauge__label,\n.lh-fraction__label {\n font-size: var(--gauge-label-font-size);\n font-weight: 500;\n line-height: var(--gauge-label-line-height);\n margin-top: 10px;\n text-align: center;\n color: var(--report-text-color);\n word-break: keep-all;\n}\n\n/* TODO(#8185) use more BEM (.lh-gauge__label--big) instead of relying on descendant selector */\n.lh-category .lh-gauge__label,\n.lh-category .lh-fraction__label {\n --gauge-label-font-size: var(--gauge-label-font-size-big);\n --gauge-label-line-height: var(--gauge-label-line-height-big);\n margin-top: 14px;\n}\n\n.lh-scores-header .lh-gauge__wrapper,\n.lh-scores-header .lh-fraction__wrapper,\n.lh-scores-header .lh-gauge--pwa__wrapper,\n.lh-sticky-header .lh-gauge__wrapper,\n.lh-sticky-header .lh-fraction__wrapper,\n.lh-sticky-header .lh-gauge--pwa__wrapper {\n width: var(--gauge-wrapper-width);\n}\n\n.lh-scorescale {\n display: inline-flex;\n\n gap: calc(var(--default-padding) * 4);\n margin: 16px auto 0 auto;\n font-size: var(--report-font-size-secondary);\n color: var(--color-gray-700);\n\n}\n\n.lh-scorescale-range {\n display: flex;\n align-items: center;\n font-family: var(--report-font-family-monospace);\n white-space: nowrap;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale {\n border: 0;\n display: flex;\n justify-content: center;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale-range {\n font-family: unset;\n font-size: 12px;\n}\n\n.lh-scorescale-wrap {\n display: contents;\n}\n\n/* Hide category score gauages if it's a single category report */\n.lh-header--solo-category .lh-scores-wrapper {\n display: none;\n}\n\n\n.lh-categories {\n width: 100%;\n}\n\n.lh-category {\n padding: var(--category-padding);\n max-width: var(--report-content-max-width);\n margin: 0 auto;\n\n scroll-margin-top: var(--sticky-header-buffer);\n}\n\n.lh-category-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n.lh-category-wrapper:last-of-type {\n border-bottom: 0;\n}\n\n.lh-category-header {\n margin-bottom: var(--section-padding-vertical);\n}\n\n.lh-category-header .lh-score__gauge {\n max-width: 400px;\n width: auto;\n margin: 0px auto;\n}\n\n.lh-category-header__finalscreenshot {\n display: grid;\n grid-template: none / 1fr 1px 1fr;\n justify-items: center;\n align-items: center;\n gap: var(--report-line-height);\n min-height: 288px;\n margin-bottom: var(--default-padding);\n}\n\n.lh-final-ss-image {\n /* constrain the size of the image to not be too large */\n max-height: calc(var(--gauge-circle-size-big) * 2.8);\n max-width: calc(var(--gauge-circle-size-big) * 3.5);\n border: 1px solid var(--color-gray-200);\n padding: 4px;\n border-radius: 3px;\n display: block;\n}\n\n.lh-category-headercol--separator {\n background: var(--color-gray-200);\n width: 1px;\n height: var(--gauge-circle-size-big);\n}\n\n@media screen and (max-width: 780px) {\n .lh-category-header__finalscreenshot {\n grid-template: 1fr 1fr / none\n }\n .lh-category-headercol--separator {\n display: none;\n }\n}\n\n\n/* 964 fits the min-width of the filmstrip */\n@media screen and (max-width: 964px) {\n .lh-report {\n margin-left: 0;\n width: 100%;\n }\n}\n\n@media print {\n body {\n -webkit-print-color-adjust: exact; /* print background colors */\n }\n .lh-container {\n display: block;\n }\n .lh-report {\n margin-left: 0;\n padding-top: 0;\n }\n .lh-categories {\n margin-top: 0;\n }\n}\n\n.lh-table {\n position: relative;\n border-collapse: separate;\n border-spacing: 0;\n /* Can't assign padding to table, so shorten the width instead. */\n width: calc(100% - var(--audit-description-padding-left) - var(--stackpack-padding-horizontal));\n border: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-table thead th {\n position: sticky;\n top: calc(var(--sticky-header-buffer) + 1em);\n z-index: 1;\n background-color: var(--report-background-color);\n border-bottom: 1px solid var(--report-border-color-secondary);\n font-weight: normal;\n color: var(--color-gray-600);\n /* See text-wrapping comment on .lh-container. */\n word-break: normal;\n}\n\n.lh-row--group {\n background-color: var(--table-group-header-background-color);\n}\n\n.lh-row--group td {\n font-weight: bold;\n font-size: 1.05em;\n color: var(--table-group-header-text-color);\n}\n\n.lh-row--group td:first-child {\n font-weight: normal;\n}\n\n.lh-row--group .lh-text {\n color: inherit;\n text-decoration: none;\n display: inline-block;\n}\n\n.lh-row--group a.lh-link:hover {\n text-decoration: underline;\n}\n\n.lh-row--group .lh-audit__adorn {\n text-transform: capitalize;\n font-weight: normal;\n padding: 2px 3px 1px 3px;\n}\n\n.lh-row--group .lh-audit__adorn1p {\n color: var(--link-color);\n border-color: var(--link-color);\n}\n\n.lh-row--group .lh-report-icon--external::before {\n content: \"\";\n background-repeat: no-repeat;\n width: 14px;\n height: 16px;\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n\n.lh-row--group .lh-report-icon--external {\n display: none;\n}\n\n.lh-row--group:hover .lh-report-icon--external {\n display: inline-block;\n}\n\n.lh-dark .lh-report-icon--external::before {\n filter: invert(1);\n}\n\n/** Manages indentation of two-level and three-level nested adjacent rows */\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) td:first-child {\n padding-left: 20px;\n}\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) ~ .lh-sub-item-row td:first-child {\n padding-left: 40px;\n}\n\n.lh-row--even {\n background-color: var(--table-group-header-background-color);\n}\n.lh-row--hidden {\n display: none;\n}\n\n.lh-table th,\n.lh-table td {\n padding: var(--default-padding);\n}\n\n.lh-table tr {\n vertical-align: middle;\n}\n\n.lh-table tr:hover {\n background-color: var(--table-higlight-background-color);\n}\n\n/* Looks unnecessary, but mostly for keeping the s left-aligned */\n.lh-table-column--text,\n.lh-table-column--source-location,\n.lh-table-column--url,\n/* .lh-table-column--thumbnail, */\n/* .lh-table-column--empty,*/\n.lh-table-column--code,\n.lh-table-column--node {\n text-align: left;\n}\n\n.lh-table-column--code {\n min-width: 100px;\n}\n\n.lh-table-column--bytes,\n.lh-table-column--timespanMs,\n.lh-table-column--ms,\n.lh-table-column--numeric {\n text-align: right;\n word-break: normal;\n}\n\n\n\n.lh-table .lh-table-column--thumbnail {\n width: var(--image-preview-size);\n}\n\n.lh-table-column--url {\n min-width: 250px;\n}\n\n.lh-table-column--text {\n min-width: 80px;\n}\n\n/* Keep columns narrow if they follow the URL column */\n/* 12% was determined to be a decent narrow width, but wide enough for column headings */\n.lh-table-column--url + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--ms,\n.lh-table-column--url + .lh-table-column--ms + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--timespanMs {\n width: 12%;\n}\n\n.lh-text__url-host {\n display: inline;\n}\n\n.lh-text__url-host {\n margin-left: calc(var(--report-font-size) / 2);\n opacity: 0.6;\n font-size: 90%\n}\n\n.lh-thumbnail {\n object-fit: cover;\n width: var(--image-preview-size);\n height: var(--image-preview-size);\n display: block;\n}\n\n.lh-unknown pre {\n overflow: scroll;\n border: solid 1px var(--color-gray-200);\n}\n\n.lh-text__url > a {\n color: inherit;\n text-decoration: none;\n}\n\n.lh-text__url > a:hover {\n text-decoration: underline dotted #999;\n}\n\n.lh-sub-item-row {\n margin-left: 20px;\n margin-bottom: 0;\n color: var(--color-gray-700);\n}\n\n.lh-sub-item-row td {\n padding-top: 4px;\n padding-bottom: 4px;\n padding-left: 20px;\n}\n\n/* Chevron\n https://codepen.io/paulirish/pen/LmzEmK\n */\n.lh-chevron {\n --chevron-angle: 42deg;\n /* Edge doesn't support transform: rotate(calc(...)), so we define it here */\n --chevron-angle-right: -42deg;\n width: var(--chevron-size);\n height: var(--chevron-size);\n margin-top: calc((var(--report-line-height) - 12px) / 2);\n}\n\n.lh-chevron__lines {\n transition: transform 0.4s;\n transform: translateY(var(--report-line-height));\n}\n.lh-chevron__line {\n stroke: var(--chevron-line-stroke);\n stroke-width: var(--chevron-size);\n stroke-linecap: square;\n transform-origin: 50%;\n transform: rotate(var(--chevron-angle));\n transition: transform 300ms, stroke 300ms;\n}\n\n.lh-expandable-details .lh-chevron__line-right,\n.lh-expandable-details[open] .lh-chevron__line-left {\n transform: rotate(var(--chevron-angle-right));\n}\n\n.lh-expandable-details[open] .lh-chevron__line-right {\n transform: rotate(var(--chevron-angle));\n}\n\n\n.lh-expandable-details[open] .lh-chevron__lines {\n transform: translateY(calc(var(--chevron-size) * -1));\n}\n\n.lh-expandable-details[open] {\n animation: 300ms openDetails forwards;\n padding-bottom: var(--default-padding);\n}\n\n@keyframes openDetails {\n from {\n outline: 1px solid var(--report-background-color);\n }\n to {\n outline: 1px solid;\n box-shadow: 0 2px 4px rgba(0, 0, 0, .24);\n }\n}\n\n@media screen and (max-width: 780px) {\n /* no black outline if we're not confident the entire table can be displayed within bounds */\n .lh-expandable-details[open] {\n animation: none;\n }\n}\n\n.lh-expandable-details[open] summary, details.lh-clump > summary {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\ndetails.lh-clump[open] > summary {\n border-bottom-width: 0;\n}\n\n\n\ndetails .lh-clump-toggletext--hide,\ndetails[open] .lh-clump-toggletext--show { display: none; }\ndetails[open] .lh-clump-toggletext--hide { display: block;}\n\n\n/* Tooltip */\n.lh-tooltip-boundary {\n position: relative;\n}\n\n.lh-tooltip {\n position: absolute;\n display: none; /* Don't retain these layers when not needed */\n opacity: 0;\n background: #ffffff;\n white-space: pre-line; /* Render newlines in the text */\n min-width: 246px;\n max-width: 275px;\n padding: 15px;\n border-radius: 5px;\n text-align: initial;\n line-height: 1.4;\n}\n/* shrink tooltips to not be cutoff on left edge of narrow viewports\n 45vw is chosen to be ~= width of the left column of metrics\n*/\n@media screen and (max-width: 535px) {\n .lh-tooltip {\n min-width: 45vw;\n padding: 3vw;\n }\n}\n\n.lh-tooltip-boundary:hover .lh-tooltip {\n display: block;\n animation: fadeInTooltip 250ms;\n animation-fill-mode: forwards;\n animation-delay: 850ms;\n bottom: 100%;\n z-index: 1;\n will-change: opacity;\n right: 0;\n pointer-events: none;\n}\n\n.lh-tooltip::before {\n content: \"\";\n border: solid transparent;\n border-bottom-color: #fff;\n border-width: 10px;\n position: absolute;\n bottom: -20px;\n right: 6px;\n transform: rotate(180deg);\n pointer-events: none;\n}\n\n@keyframes fadeInTooltip {\n 0% { opacity: 0; }\n 75% { opacity: 1; }\n 100% { opacity: 1; filter: drop-shadow(1px 0px 1px #aaa) drop-shadow(0px 2px 4px hsla(206, 6%, 25%, 0.15)); pointer-events: auto; }\n}\n\n/* Element screenshot */\n.lh-element-screenshot {\n float: left;\n margin-right: 20px;\n}\n.lh-element-screenshot__content {\n overflow: hidden;\n min-width: 110px;\n display: flex;\n justify-content: center;\n background-color: var(--report-background-color);\n}\n.lh-element-screenshot__image {\n position: relative;\n /* Set by ElementScreenshotRenderer.installFullPageScreenshotCssVariable */\n background-image: var(--element-screenshot-url);\n outline: 2px solid #777;\n background-color: white;\n background-repeat: no-repeat;\n}\n.lh-element-screenshot__mask {\n position: absolute;\n background: #555;\n opacity: 0.8;\n}\n.lh-element-screenshot__element-marker {\n position: absolute;\n outline: 2px solid var(--color-lime-400);\n}\n.lh-element-screenshot__overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 2000; /* .lh-topbar is 1000 */\n background: var(--screenshot-overlay-background);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: zoom-out;\n}\n\n.lh-element-screenshot__overlay .lh-element-screenshot {\n margin-right: 0; /* clearing margin used in thumbnail case */\n outline: 1px solid var(--color-gray-700);\n}\n\n.lh-screenshot-overlay--enabled .lh-element-screenshot {\n cursor: zoom-out;\n}\n.lh-screenshot-overlay--enabled .lh-node .lh-element-screenshot {\n cursor: zoom-in;\n}\n\n\n.lh-meta__items {\n --meta-icon-size: calc(var(--report-icon-size) * 0.667);\n padding: var(--default-padding);\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n background-color: var(--env-item-background-color);\n border-radius: 3px;\n margin: 0 0 var(--default-padding) 0;\n font-size: 12px;\n column-gap: var(--default-padding);\n color: var(--color-gray-700);\n}\n\n.lh-meta__item {\n display: block;\n list-style-type: none;\n position: relative;\n padding: 0 0 0 calc(var(--meta-icon-size) + var(--default-padding) * 2);\n cursor: unset; /* disable pointer cursor from report-icon */\n}\n\n.lh-meta__item.lh-tooltip-boundary {\n text-decoration: dotted underline var(--color-gray-500);\n cursor: help;\n}\n\n.lh-meta__item.lh-report-icon::before {\n position: absolute;\n left: var(--default-padding);\n width: var(--meta-icon-size);\n height: var(--meta-icon-size);\n}\n\n.lh-meta__item.lh-report-icon:hover::before {\n opacity: 0.7;\n}\n\n.lh-meta__item .lh-tooltip {\n color: var(--color-gray-800);\n}\n\n.lh-meta__item .lh-tooltip::before {\n right: auto; /* Set the tooltip arrow to the leftside */\n left: 6px;\n}\n\n/* Change the grid for narrow viewport. */\n@media screen and (max-width: 640px) {\n .lh-meta__items {\n grid-template-columns: 1fr 1fr;\n }\n}\n@media screen and (max-width: 535px) {\n .lh-meta__items {\n display: block;\n }\n}\n\n\n/*# sourceURL=report-styles.css */\n"); + el1.append("/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: Apache-2.0\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 --report-icon-size: var(--score-icon-background-size);\n --report-line-height: 24px;\n --report-line-height-secondary: 20px;\n --report-monospace-font-size: calc(var(--report-font-size) * 0.85);\n --report-text-color-secondary: var(--color-gray-800);\n --report-text-color: var(--color-gray-900);\n --report-content-max-width: calc(60 * var(--report-font-size)); /* defaults to 840px */\n --report-content-min-width: 360px;\n --report-content-max-width-minus-edge-gap: calc(var(--report-content-max-width) - var(--edge-gap-padding) * 2);\n --score-container-padding: 8px;\n --score-icon-background-size: 24px;\n --score-icon-margin-left: 6px;\n --score-icon-margin-right: 14px;\n --score-icon-margin: 0 var(--score-icon-margin-right) 0 var(--score-icon-margin-left);\n --score-icon-size: 12px;\n --score-icon-size-big: 16px;\n --screenshot-overlay-background: rgba(0, 0, 0, 0.3);\n --section-padding-vertical: calc(var(--default-padding) * 6);\n --snippet-background-color: var(--color-gray-50);\n --snippet-color: #0938C2;\n --sparkline-height: 5px;\n --stackpack-padding-horizontal: 10px;\n --sticky-header-background-color: var(--report-background-color);\n --sticky-header-buffer: calc(var(--topbar-height) + var(--sticky-header-height));\n --sticky-header-height: calc(var(--gauge-circle-size-sm) + var(--score-container-padding) * 2);\n --table-group-header-background-color: #EEF1F4;\n --table-group-header-text-color: var(--color-gray-700);\n --table-higlight-background-color: #F5F7FA;\n --tools-icon-color: var(--color-gray-600);\n --topbar-background-color: var(--color-white);\n --topbar-height: 32px;\n --topbar-logo-size: 24px;\n --topbar-padding: 0 8px;\n --toplevel-warning-background-color: hsla(30, 100%, 75%, 10%);\n --toplevel-warning-message-text-color: var(--color-average-secondary);\n --toplevel-warning-padding: 18px;\n --toplevel-warning-text-color: var(--report-text-color);\n\n /* SVGs */\n --plugin-icon-url-dark: url('data:image/svg+xml;utf8,');\n --plugin-icon-url: url('data:image/svg+xml;utf8,');\n\n --pass-icon-url: url('data:image/svg+xml;utf8,check');\n --average-icon-url: url('data:image/svg+xml;utf8,info');\n --fail-icon-url: url('data:image/svg+xml;utf8,warn');\n --error-icon-url: url('data:image/svg+xml;utf8,error');\n\n --pwa-installable-gray-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-gray-url-dark: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url-dark: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-color-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-color-url: url('data:image/svg+xml;utf8,');\n\n --swap-locale-icon-url: url('data:image/svg+xml;utf8,');\n}\n\n@media not print {\n .lh-dark {\n /* Pallete */\n --color-gray-200: var(--color-gray-800);\n --color-gray-300: #616161;\n --color-gray-400: var(--color-gray-600);\n --color-gray-700: var(--color-gray-400);\n --color-gray-50: #757575;\n --color-gray-600: var(--color-gray-500);\n --color-green-700: var(--color-green);\n --color-orange-700: var(--color-orange);\n --color-red-700: var(--color-red);\n --color-teal-600: var(--color-cyan-500);\n\n /* Context-specific colors */\n --color-hover: rgba(0, 0, 0, 0.2);\n --color-informative: var(--color-blue-200);\n\n /* Component variables */\n --env-item-background-color: #393535;\n --link-color: var(--color-blue-200);\n --locale-selector-background-color: var(--color-gray-200);\n --plugin-badge-background-color: var(--color-gray-800);\n --report-background-color: var(--color-gray-900);\n --report-border-color-secondary: var(--color-gray-200);\n --report-text-color-secondary: var(--color-gray-400);\n --report-text-color: var(--color-gray-100);\n --snippet-color: var(--color-cyan-500);\n --topbar-background-color: var(--color-gray);\n --toplevel-warning-background-color: hsl(33deg 14% 18%);\n --toplevel-warning-message-text-color: var(--color-orange-700);\n --toplevel-warning-text-color: var(--color-gray-100);\n --table-group-header-background-color: rgba(186, 196, 206, 0.15);\n --table-group-header-text-color: var(--color-gray-100);\n --table-higlight-background-color: rgba(186, 196, 206, 0.09);\n\n /* SVGs */\n --plugin-icon-url: var(--plugin-icon-url-dark);\n --pwa-installable-gray-url: var(--pwa-installable-gray-url-dark);\n --pwa-optimized-gray-url: var(--pwa-optimized-gray-url-dark);\n }\n}\n\n@media only screen and (max-width: 480px) {\n .lh-vars {\n --audit-group-margin-bottom: 20px;\n --edge-gap-padding: var(--default-padding);\n --env-name-min-width: 120px;\n --gauge-circle-size-big: 96px;\n --gauge-circle-size: 72px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 112px;\n --header-padding: 16px 0 16px 0;\n --image-preview-size: 24px;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-size: 14px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --topbar-height: 28px;\n --topbar-logo-size: 20px;\n }\n\n /* Not enough space to adequately show the relative savings bars. */\n .lh-sparkline {\n display: none;\n }\n}\n\n.lh-vars.lh-devtools {\n --audit-explanation-line-height: 14px;\n --audit-group-margin-bottom: 20px;\n --audit-group-padding-vertical: 12px;\n --audit-padding-vertical: 4px;\n --category-padding: 12px;\n --default-padding: 12px;\n --env-name-min-width: 120px;\n --footer-padding-vertical: 8px;\n --gauge-circle-size-big: 72px;\n --gauge-circle-size: 64px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 97px;\n --header-line-height: 20px;\n --header-padding: 16px 0 16px 0;\n --screenshot-overlay-background: transparent;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-family-monospace: 'Menlo', 'dejavu sans mono', 'Consolas', 'Lucida Console', monospace;\n --report-font-family: '.SFNSDisplay-Regular', 'Helvetica Neue', 'Lucida Grande', sans-serif;\n --report-font-size: 12px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --section-padding-vertical: 8px;\n}\n\n.lh-container:not(.lh-topbar + .lh-container) {\n --topbar-height: 0;\n --sticky-header-height: 0;\n --sticky-header-buffer: 0;\n}\n\n.lh-devtools.lh-root {\n height: 100%;\n}\n.lh-devtools.lh-root img {\n /* Override devtools default 'min-width: 0' so svg without size in a flexbox isn't collapsed. */\n min-width: auto;\n}\n.lh-devtools .lh-container {\n overflow-y: scroll;\n height: calc(100% - var(--topbar-height));\n /** The .lh-container is the scroll parent in DevTools so we exclude the topbar from the sticky header buffer. */\n --sticky-header-buffer: calc(var(--sticky-header-height));\n}\n@media print {\n .lh-devtools .lh-container {\n overflow: unset;\n }\n}\n.lh-devtools .lh-sticky-header {\n /* This is normally the height of the topbar, but we want it to stick to the top of our scroll container .lh-container` */\n top: 0;\n}\n.lh-devtools .lh-element-screenshot__overlay {\n position: absolute;\n}\n\n@keyframes fadeIn {\n 0% { opacity: 0;}\n 100% { opacity: 0.6;}\n}\n\n.lh-root *, .lh-root *::before, .lh-root *::after {\n box-sizing: border-box;\n}\n\n.lh-root {\n font-family: var(--report-font-family);\n font-size: var(--report-font-size);\n margin: 0;\n line-height: var(--report-line-height);\n background: var(--report-background-color);\n color: var(--report-text-color);\n}\n\n.lh-root :focus-visible {\n outline: -webkit-focus-ring-color auto 3px;\n}\n.lh-root summary:focus {\n outline: none;\n box-shadow: 0 0 0 1px hsl(217, 89%, 61%);\n}\n\n.lh-root [hidden] {\n display: none !important;\n}\n\n.lh-root pre {\n margin: 0;\n}\n\n.lh-root pre,\n.lh-root code {\n font-family: var(--report-font-family-monospace);\n}\n\n.lh-root details > summary {\n cursor: pointer;\n}\n\n.lh-hidden {\n display: none !important;\n}\n\n.lh-container {\n /*\n Text wrapping in the report is so much FUN!\n We have a `word-break: break-word;` globally here to prevent a few common scenarios, namely\n long non-breakable text (usually URLs) found in:\n 1. The footer\n 2. .lh-node (outerHTML)\n 3. .lh-code\n\n With that sorted, the next challenge is appropriate column sizing and text wrapping inside our\n .lh-details tables. Even more fun.\n * We don't want table headers (\"Potential Savings (ms)\") to wrap or their column values, but\n we'd be happy for the URL column to wrap if the URLs are particularly long.\n * We want the narrow columns to remain narrow, providing the most column width for URL\n * We don't want the table to extend past 100% width.\n * Long URLs in the URL column can wrap. Util.getURLDisplayName maxes them out at 64 characters,\n but they do not get any overflow:ellipsis treatment.\n */\n word-break: break-word;\n}\n\n.lh-audit-group a,\n.lh-category-header__description a,\n.lh-audit__description a,\n.lh-warnings a,\n.lh-footer a,\n.lh-table-column--link a {\n color: var(--link-color);\n}\n\n.lh-audit__description, .lh-audit__stackpack {\n --inner-audit-padding-right: var(--stackpack-padding-horizontal);\n padding-left: var(--audit-description-padding-left);\n padding-right: var(--inner-audit-padding-right);\n padding-top: 8px;\n padding-bottom: 8px;\n}\n\n.lh-details {\n margin-top: var(--default-padding);\n margin-bottom: var(--default-padding);\n margin-left: var(--audit-description-padding-left);\n /* whatever the .lh-details side margins are */\n width: 100%;\n}\n\n.lh-audit__stackpack {\n display: flex;\n align-items: center;\n}\n\n.lh-audit__stackpack__img {\n max-width: 30px;\n margin-right: var(--default-padding)\n}\n\n/* Report header */\n\n.lh-report-icon {\n display: flex;\n align-items: center;\n padding: 10px 12px;\n cursor: pointer;\n}\n.lh-report-icon[disabled] {\n opacity: 0.3;\n pointer-events: none;\n}\n\n.lh-report-icon::before {\n content: \"\";\n margin: 4px;\n background-repeat: no-repeat;\n width: var(--report-icon-size);\n height: var(--report-icon-size);\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n.lh-report-icon:hover::before {\n opacity: 1;\n}\n.lh-dark .lh-report-icon::before {\n filter: invert(1);\n}\n.lh-report-icon--print::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--copy::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--open::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--download::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--dark::before {\n background-image:url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--treemap::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--date::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--devices::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--world::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--stopwatch::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--networkspeed::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-one::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-many::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--chrome::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--external::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n\n.lh-buttons {\n display: flex;\n flex-wrap: wrap;\n margin: var(--default-padding) 0;\n}\n.lh-button {\n height: 32px;\n border: 1px solid var(--report-border-color-secondary);\n border-radius: 3px;\n color: var(--link-color);\n background-color: var(--report-background-color);\n margin: 5px;\n}\n\n.lh-button:first-of-type {\n margin-left: 0;\n}\n\n/* Node */\n.lh-node__snippet {\n font-family: var(--report-font-family-monospace);\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n line-height: 20px;\n}\n\n/* Score */\n\n/* to remove color indicators - test */\n/* .lh-audit__score-icon {\n opacity: 0;\n} */\n\n.lh-audit__score-icon {\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n margin: var(--score-icon-margin);\n}\n\n.lh-audit--pass .lh-audit__display-text {\n color: var(--color-pass-secondary);\n}\n.lh-audit--pass .lh-audit__score-icon,\n.lh-scorescale-range--pass::before {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-audit__display-text {\n color: var(--color-average-secondary);\n /* to remove color indicators - test */\n /* color: gray; */\n}\n.lh-audit--average .lh-audit__score-icon,\n.lh-scorescale-range--average::before {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-audit--fail .lh-audit__display-text {\n color: var(--color-fail-secondary);\n /* to remove color indicators - test */\n /* color: gray; */\n}\n.lh-audit--fail .lh-audit__score-icon,\n.lh-audit--error .lh-audit__score-icon,\n.lh-scorescale-range--fail::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-audit--error .lh-audit__score-icon,\n.lh-metric--error .lh-metric__icon {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n border: none;\n}\n\n.lh-gauge__wrapper--fail .lh-gauge--error {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n transform: scale(0.5);\n top: var(--score-container-padding);\n}\n\n.lh-audit--manual .lh-audit__display-text,\n.lh-audit--notapplicable .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n.lh-audit--manual .lh-audit__score-icon,\n.lh-audit--notapplicable .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n background: none;\n}\n\n.lh-audit--informative .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n\n.lh-audit--informative .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n}\n\n.lh-audit__description,\n.lh-audit__stackpack {\n color: var(--report-text-color-secondary);\n}\n.lh-audit__adorn {\n border: 1px solid var(--color-gray-500);\n border-radius: 3px;\n margin: 0 3px;\n padding: 0 2px;\n line-height: 1.1;\n display: inline-block;\n font-size: 90%;\n color: var(--report-text-color-secondary);\n}\n\n.lh-category-header__description {\n text-align: center;\n color: var(--color-gray-700);\n margin: 0px auto;\n max-width: 400px;\n}\n\n\n.lh-audit__display-text,\n.lh-load-opportunity__sparkline,\n.lh-chevron-container {\n margin: 0 var(--audit-margin-horizontal);\n}\n.lh-chevron-container {\n margin-right: 0;\n}\n\n.lh-audit__title-and-text {\n flex: 1;\n}\n\n.lh-audit__title-and-text code {\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n}\n\n/* Prepend display text with em dash separator. But not in Opportunities. */\n.lh-audit__display-text:not(:empty):before {\n content: '—';\n margin-right: var(--audit-margin-horizontal);\n}\n.lh-audit-group.lh-audit-group--load-opportunities .lh-audit__display-text:not(:empty):before {\n display: none;\n}\n\n/* Expandable Details (Audit Groups, Audits) */\n.lh-audit__header {\n display: flex;\n align-items: center;\n padding: var(--default-padding);\n}\n\n.lh-audit--load-opportunity .lh-audit__header {\n display: block;\n}\n\n\n.lh-metricfilter {\n display: grid;\n justify-content: end;\n align-items: center;\n grid-auto-flow: column;\n gap: 4px;\n color: var(--color-gray-700);\n}\n\n.lh-metricfilter__radio {\n /*\n * Instead of hiding, position offscreen so it's still accessible to screen readers\n * https://bugs.chromium.org/p/chromium/issues/detail?id=1439785\n */\n position: fixed;\n left: -9999px;\n}\n.lh-metricfilter input[type='radio']:focus-visible + label {\n outline: -webkit-focus-ring-color auto 1px;\n}\n\n.lh-metricfilter__label {\n display: inline-flex;\n padding: 0 4px;\n height: 16px;\n text-decoration: underline;\n align-items: center;\n cursor: pointer;\n font-size: 90%;\n}\n\n.lh-metricfilter__label--active {\n background: var(--color-blue-primary);\n color: var(--color-white);\n border-radius: 3px;\n text-decoration: none;\n}\n/* Give the 'All' choice a more muted display */\n.lh-metricfilter__label--active[for=\"metric-All\"] {\n background-color: var(--color-blue-200) !important;\n color: black !important;\n}\n\n.lh-metricfilter__text {\n margin-right: 8px;\n}\n\n/* If audits are filtered, hide the itemcount for Passed Audits… */\n.lh-category--filtered .lh-audit-group .lh-audit-group__itemcount {\n display: none;\n}\n\n\n.lh-audit__header:hover {\n background-color: var(--color-hover);\n}\n\n/* We want to hide the browser's default arrow marker on summary elements. Admittedly, it's complicated. */\n.lh-root details > summary {\n /* Blink 89+ and Firefox will hide the arrow when display is changed from (new) default of `list-item` to block. https://chromestatus.com/feature/6730096436051968*/\n display: block;\n}\n/* Safari and Blink <=88 require using the -webkit-details-marker selector */\n.lh-root details > summary::-webkit-details-marker {\n display: none;\n}\n\n/* Perf Metric */\n\n.lh-metrics-container {\n display: grid;\n grid-auto-rows: 1fr;\n grid-template-columns: 1fr 1fr;\n grid-column-gap: var(--report-line-height);\n margin-bottom: var(--default-padding);\n}\n\n.lh-metric {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(-n+2) {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-metric__innerwrap {\n display: grid;\n /**\n * Icon -- Metric Name\n * -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 1fr;\n align-items: center;\n padding: var(--default-padding);\n}\n\n.lh-metric__details {\n order: -1;\n}\n\n.lh-metric__title {\n flex: 1;\n}\n\n.lh-calclink {\n padding-left: calc(1ex / 3);\n}\n\n.lh-metric__description {\n display: none;\n grid-column-start: 2;\n grid-column-end: 4;\n color: var(--report-text-color-secondary);\n}\n\n.lh-metric__value {\n font-size: var(--metric-value-font-size);\n margin: calc(var(--default-padding) / 2) 0;\n white-space: nowrap; /* No wrapping between metric value and the icon */\n grid-column-start: 2;\n}\n\n\n@media screen and (max-width: 535px) {\n .lh-metrics-container {\n display: block;\n }\n\n .lh-metric {\n border-bottom: none !important;\n }\n .lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(1) {\n border-bottom: 1px solid var(--report-border-color-secondary) !important;\n }\n\n /* Change the grid to 3 columns for narrow viewport. */\n .lh-metric__innerwrap {\n /**\n * Icon -- Metric Name -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 2fr 1fr;\n }\n .lh-metric__value {\n justify-self: end;\n grid-column-start: unset;\n }\n}\n\n/* No-JS toggle switch */\n/* Keep this selector sync'd w/ `magicSelector` in report-ui-features-test.js */\n .lh-metrics-toggle__input:checked ~ .lh-metrics-container .lh-metric__description {\n display: block;\n}\n\n/* TODO get rid of the SVGS and clean up these some more */\n.lh-metrics-toggle__input {\n opacity: 0;\n position: absolute;\n right: 0;\n top: 0px;\n}\n\n.lh-metrics-toggle__input + div > label > .lh-metrics-toggle__labeltext--hide,\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--show {\n display: none;\n}\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--hide {\n display: inline;\n}\n.lh-metrics-toggle__input:focus + div > label {\n outline: -webkit-focus-ring-color auto 3px;\n}\n\n.lh-metrics-toggle__label {\n cursor: pointer;\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n/* Pushes the metric description toggle button to the right. */\n.lh-audit-group--metrics .lh-audit-group__header {\n display: flex;\n justify-content: space-between;\n}\n\n.lh-metric__icon,\n.lh-scorescale-range::before {\n content: '';\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n display: inline-block;\n margin: var(--score-icon-margin);\n}\n\n.lh-metric--pass .lh-metric__value {\n color: var(--color-pass-secondary);\n}\n.lh-metric--pass .lh-metric__icon {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-metric--average .lh-metric__value {\n color: var(--color-average-secondary);\n}\n.lh-metric--average .lh-metric__icon {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-metric--fail .lh-metric__value {\n color: var(--color-fail-secondary);\n}\n.lh-metric--fail .lh-metric__icon {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-metric--error .lh-metric__value,\n.lh-metric--error .lh-metric__description {\n color: var(--color-fail-secondary);\n}\n\n/* Perf load opportunity */\n\n.lh-load-opportunity__cols {\n display: flex;\n align-items: flex-start;\n}\n\n.lh-load-opportunity__header .lh-load-opportunity__col {\n color: var(--color-gray-600);\n display: unset;\n line-height: calc(2.3 * var(--report-font-size));\n}\n\n.lh-load-opportunity__col {\n display: flex;\n}\n\n.lh-load-opportunity__col--one {\n flex: 5;\n align-items: center;\n margin-right: 2px;\n}\n.lh-load-opportunity__col--two {\n flex: 4;\n text-align: right;\n}\n\n.lh-audit--load-opportunity .lh-audit__display-text {\n text-align: right;\n flex: 0 0 7.5ch;\n}\n\n\n/* Sparkline */\n\n.lh-load-opportunity__sparkline {\n flex: 1;\n margin-top: calc((var(--report-line-height) - var(--sparkline-height)) / 2);\n}\n\n.lh-sparkline {\n height: var(--sparkline-height);\n width: 100%;\n}\n\n.lh-sparkline__bar {\n height: 100%;\n float: right;\n}\n\n.lh-audit--pass .lh-sparkline__bar {\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-sparkline__bar {\n background: var(--color-average);\n}\n\n.lh-audit--fail .lh-sparkline__bar {\n background: var(--color-fail);\n}\n\n/* Filmstrip */\n\n.lh-filmstrip-container {\n /* smaller gap between metrics and filmstrip */\n margin: -8px auto 0 auto;\n}\n\n.lh-filmstrip {\n display: grid;\n justify-content: space-between;\n padding-bottom: var(--default-padding);\n width: 100%;\n grid-template-columns: repeat(auto-fit, 90px);\n}\n\n.lh-filmstrip__frame {\n text-align: right;\n position: relative;\n}\n\n.lh-filmstrip__thumbnail {\n border: 1px solid var(--report-border-color-secondary);\n max-height: 150px;\n max-width: 120px;\n}\n\n/* Audit */\n\n.lh-audit {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n/* Apply border-top to just the first audit. */\n.lh-audit {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n.lh-audit ~ .lh-audit {\n border-top: none;\n}\n\n\n.lh-audit--error .lh-audit__display-text {\n color: var(--color-fail-secondary);\n}\n\n/* Audit Group */\n\n.lh-audit-group {\n margin-bottom: var(--audit-group-margin-bottom);\n position: relative;\n}\n.lh-audit-group--metrics {\n margin-bottom: calc(var(--audit-group-margin-bottom) / 2);\n}\n\n.lh-audit-group__header::before {\n /* By default, groups don't get an icon */\n content: none;\n width: var(--pwa-icon-size);\n height: var(--pwa-icon-size);\n margin: var(--pwa-icon-margin);\n display: inline-block;\n vertical-align: middle;\n}\n\n/* Style the \"over budget\" columns red. */\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(4),\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(5),\n.lh-audit-group--budgets #timing-budget tbody tr td:nth-child(3) {\n color: var(--color-red-700);\n}\n\n/* Align the \"over budget request count\" text to be close to the \"over budget bytes\" column. */\n.lh-audit-group--budgets .lh-table tbody tr td:nth-child(4){\n text-align: right;\n}\n\n.lh-audit-group--budgets .lh-details--budget {\n width: 100%;\n margin: 0 0 var(--default-padding);\n}\n\n.lh-audit-group--pwa-installable .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-installable-gray-url);\n}\n.lh-audit-group--pwa-optimized .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-optimized-gray-url);\n}\n.lh-audit-group--pwa-installable.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-installable-color-url);\n}\n.lh-audit-group--pwa-optimized.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-optimized-color-url);\n}\n\n.lh-audit-group--metrics .lh-audit-group__summary {\n margin-top: 0;\n margin-bottom: 0;\n}\n\n.lh-audit-group__summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.lh-audit-group__header .lh-chevron {\n margin-top: calc((var(--report-line-height) - 5px) / 2);\n}\n\n.lh-audit-group__header {\n letter-spacing: 0.8px;\n padding: var(--default-padding);\n padding-left: 0;\n}\n\n.lh-audit-group__header, .lh-audit-group__summary {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n.lh-audit-group__title {\n text-transform: uppercase;\n font-weight: 500;\n}\n\n.lh-audit-group__itemcount {\n color: var(--color-gray-600);\n}\n\n.lh-audit-group__footer {\n color: var(--color-gray-600);\n display: block;\n margin-top: var(--default-padding);\n}\n\n.lh-details,\n.lh-category-header__description,\n.lh-load-opportunity__header,\n.lh-audit-group__footer {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n}\n\n.lh-audit-explanation {\n margin: var(--audit-padding-vertical) 0 calc(var(--audit-padding-vertical) / 2) var(--audit-margin-horizontal);\n line-height: var(--audit-explanation-line-height);\n display: inline-block;\n}\n\n.lh-audit--fail .lh-audit-explanation {\n color: var(--color-fail-secondary);\n}\n\n/* Report */\n.lh-list > :not(:last-child) {\n margin-bottom: calc(var(--default-padding) * 2);\n}\n\n.lh-header-container {\n display: block;\n margin: 0 auto;\n position: relative;\n word-wrap: break-word;\n}\n\n.lh-header-container .lh-scores-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n\n\n.lh-report {\n min-width: var(--report-content-min-width);\n}\n\n.lh-exception {\n font-size: large;\n}\n\n.lh-code {\n white-space: normal;\n margin-top: 0;\n font-size: var(--report-monospace-font-size);\n}\n\n.lh-warnings {\n --item-margin: calc(var(--report-line-height) / 6);\n color: var(--color-average-secondary);\n margin: var(--audit-padding-vertical) 0;\n padding: var(--default-padding)\n var(--default-padding)\n var(--default-padding)\n calc(var(--audit-description-padding-left));\n background-color: var(--toplevel-warning-background-color);\n}\n.lh-warnings span {\n font-weight: bold;\n}\n\n.lh-warnings--toplevel {\n --item-margin: calc(var(--header-line-height) / 4);\n color: var(--toplevel-warning-text-color);\n margin-left: auto;\n margin-right: auto;\n max-width: var(--report-content-max-width-minus-edge-gap);\n padding: var(--toplevel-warning-padding);\n border-radius: 8px;\n}\n\n.lh-warnings__msg {\n color: var(--toplevel-warning-message-text-color);\n margin: 0;\n}\n\n.lh-warnings ul {\n margin: 0;\n}\n.lh-warnings li {\n margin: var(--item-margin) 0;\n}\n.lh-warnings li:last-of-type {\n margin-bottom: 0;\n}\n\n.lh-scores-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n}\n.lh-scores-header__solo {\n padding: 0;\n border: 0;\n}\n\n/* Gauge */\n\n.lh-gauge__wrapper--pass {\n color: var(--color-pass-secondary);\n fill: var(--color-pass);\n stroke: var(--color-pass);\n}\n\n.lh-gauge__wrapper--average {\n color: var(--color-average-secondary);\n fill: var(--color-average);\n stroke: var(--color-average);\n}\n\n.lh-gauge__wrapper--fail {\n color: var(--color-fail-secondary);\n fill: var(--color-fail);\n stroke: var(--color-fail);\n}\n\n.lh-gauge__wrapper--not-applicable {\n color: var(--color-not-applicable);\n fill: var(--color-not-applicable);\n stroke: var(--color-not-applicable);\n}\n\n.lh-fraction__wrapper .lh-fraction__content::before {\n content: '';\n height: var(--score-icon-size);\n width: var(--score-icon-size);\n margin: var(--score-icon-margin);\n display: inline-block;\n}\n.lh-fraction__wrapper--pass .lh-fraction__content {\n color: var(--color-pass-secondary);\n}\n.lh-fraction__wrapper--pass .lh-fraction__background {\n background-color: var(--color-pass);\n}\n.lh-fraction__wrapper--pass .lh-fraction__content::before {\n background-color: var(--color-pass);\n border-radius: 50%;\n}\n.lh-fraction__wrapper--average .lh-fraction__content {\n color: var(--color-average-secondary);\n}\n.lh-fraction__wrapper--average .lh-fraction__background,\n.lh-fraction__wrapper--average .lh-fraction__content::before {\n background-color: var(--color-average);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content {\n color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__background {\n background-color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n.lh-fraction__wrapper--null .lh-fraction__content {\n color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__background {\n background-color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__content::before {\n border-radius: 50%;\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-700);\n}\n\n.lh-fraction__background {\n position: absolute;\n height: 100%;\n width: 100%;\n border-radius: calc(var(--gauge-circle-size) / 2);\n opacity: 0.1;\n z-index: -1;\n}\n\n.lh-fraction__content-wrapper {\n height: var(--gauge-circle-size);\n display: flex;\n align-items: center;\n}\n\n.lh-fraction__content {\n display: flex;\n position: relative;\n align-items: center;\n justify-content: center;\n font-size: calc(0.3 * var(--gauge-circle-size));\n line-height: calc(0.4 * var(--gauge-circle-size));\n width: max-content;\n min-width: calc(1.5 * var(--gauge-circle-size));\n padding: calc(0.1 * var(--gauge-circle-size)) calc(0.2 * var(--gauge-circle-size));\n --score-icon-size: calc(0.21 * var(--gauge-circle-size));\n --score-icon-margin: 0 calc(0.15 * var(--gauge-circle-size)) 0 0;\n}\n\n.lh-gauge {\n stroke-linecap: round;\n width: var(--gauge-circle-size);\n height: var(--gauge-circle-size);\n}\n\n.lh-category .lh-gauge {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n.lh-gauge-base {\n opacity: 0.1;\n}\n\n.lh-gauge-arc {\n fill: none;\n transform-origin: 50% 50%;\n animation: load-gauge var(--transition-length) ease both;\n animation-delay: 250ms;\n}\n\n.lh-gauge__svg-wrapper {\n position: relative;\n height: var(--gauge-circle-size);\n}\n.lh-category .lh-gauge__svg-wrapper,\n.lh-category .lh-fraction__wrapper {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n/* The plugin badge overlay */\n.lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size);\n height: var(--plugin-badge-size);\n background-color: var(--plugin-badge-background-color);\n background-image: var(--plugin-icon-url);\n background-repeat: no-repeat;\n background-size: var(--plugin-icon-size);\n background-position: 58% 50%;\n content: \"\";\n position: absolute;\n right: -6px;\n bottom: 0px;\n display: block;\n z-index: 100;\n box-shadow: 0 0 4px rgba(0,0,0,.2);\n border-radius: 25%;\n}\n.lh-category .lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size-big);\n height: var(--plugin-badge-size-big);\n}\n\n@keyframes load-gauge {\n from { stroke-dasharray: 0 352; }\n}\n\n.lh-gauge__percentage {\n width: 100%;\n height: var(--gauge-circle-size);\n line-height: var(--gauge-circle-size);\n position: absolute;\n font-family: var(--report-font-family-monospace);\n font-size: calc(var(--gauge-circle-size) * 0.34 + 1.3px);\n text-align: center;\n top: var(--score-container-padding);\n}\n\n.lh-category .lh-gauge__percentage {\n --gauge-circle-size: var(--gauge-circle-size-big);\n --gauge-percentage-font-size: var(--gauge-percentage-font-size-big);\n}\n\n.lh-gauge__wrapper,\n.lh-fraction__wrapper {\n position: relative;\n display: flex;\n align-items: center;\n flex-direction: column;\n text-decoration: none;\n padding: var(--score-container-padding);\n\n --transition-length: 1s;\n\n /* Contain the layout style paint & layers during animation*/\n contain: content;\n will-change: opacity; /* Only using for layer promotion */\n}\n\n.lh-gauge__label,\n.lh-fraction__label {\n font-size: var(--gauge-label-font-size);\n font-weight: 500;\n line-height: var(--gauge-label-line-height);\n margin-top: 10px;\n text-align: center;\n color: var(--report-text-color);\n word-break: keep-all;\n}\n\n/* TODO(#8185) use more BEM (.lh-gauge__label--big) instead of relying on descendant selector */\n.lh-category .lh-gauge__label,\n.lh-category .lh-fraction__label {\n --gauge-label-font-size: var(--gauge-label-font-size-big);\n --gauge-label-line-height: var(--gauge-label-line-height-big);\n margin-top: 14px;\n}\n\n.lh-scores-header .lh-gauge__wrapper,\n.lh-scores-header .lh-fraction__wrapper,\n.lh-scores-header .lh-gauge--pwa__wrapper,\n.lh-sticky-header .lh-gauge__wrapper,\n.lh-sticky-header .lh-fraction__wrapper,\n.lh-sticky-header .lh-gauge--pwa__wrapper {\n width: var(--gauge-wrapper-width);\n}\n\n.lh-scorescale {\n display: inline-flex;\n\n gap: calc(var(--default-padding) * 4);\n margin: 16px auto 0 auto;\n font-size: var(--report-font-size-secondary);\n color: var(--color-gray-700);\n\n}\n\n.lh-scorescale-range {\n display: flex;\n align-items: center;\n font-family: var(--report-font-family-monospace);\n white-space: nowrap;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale {\n border: 0;\n display: flex;\n justify-content: center;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale-range {\n font-family: unset;\n font-size: 12px;\n}\n\n.lh-scorescale-wrap {\n display: contents;\n}\n\n/* Hide category score gauages if it's a single category report */\n.lh-header--solo-category .lh-scores-wrapper {\n display: none;\n}\n\n\n.lh-categories {\n width: 100%;\n}\n\n.lh-category {\n padding: var(--category-padding);\n max-width: var(--report-content-max-width);\n margin: 0 auto;\n\n scroll-margin-top: var(--sticky-header-buffer);\n}\n\n.lh-category-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n.lh-category-wrapper:last-of-type {\n border-bottom: 0;\n}\n\n.lh-category-header {\n margin-bottom: var(--section-padding-vertical);\n}\n\n.lh-category-header .lh-score__gauge {\n max-width: 400px;\n width: auto;\n margin: 0px auto;\n}\n\n.lh-category-header__finalscreenshot {\n display: grid;\n grid-template: none / 1fr 1px 1fr;\n justify-items: center;\n align-items: center;\n gap: var(--report-line-height);\n min-height: 288px;\n margin-bottom: var(--default-padding);\n}\n\n.lh-final-ss-image {\n /* constrain the size of the image to not be too large */\n max-height: calc(var(--gauge-circle-size-big) * 2.8);\n max-width: calc(var(--gauge-circle-size-big) * 3.5);\n border: 1px solid var(--color-gray-200);\n padding: 4px;\n border-radius: 3px;\n display: block;\n}\n\n.lh-category-headercol--separator {\n background: var(--color-gray-200);\n width: 1px;\n height: var(--gauge-circle-size-big);\n}\n\n@media screen and (max-width: 780px) {\n .lh-category-header__finalscreenshot {\n grid-template: 1fr 1fr / none\n }\n .lh-category-headercol--separator {\n display: none;\n }\n}\n\n\n/* 964 fits the min-width of the filmstrip */\n@media screen and (max-width: 964px) {\n .lh-report {\n margin-left: 0;\n width: 100%;\n }\n}\n\n@media print {\n body {\n -webkit-print-color-adjust: exact; /* print background colors */\n }\n .lh-container {\n display: block;\n }\n .lh-report {\n margin-left: 0;\n padding-top: 0;\n }\n .lh-categories {\n margin-top: 0;\n }\n}\n\n.lh-table {\n position: relative;\n border-collapse: separate;\n border-spacing: 0;\n /* Can't assign padding to table, so shorten the width instead. */\n width: calc(100% - var(--audit-description-padding-left) - var(--stackpack-padding-horizontal));\n border: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-table thead th {\n position: sticky;\n top: calc(var(--sticky-header-buffer) + 1em);\n z-index: 1;\n background-color: var(--report-background-color);\n border-bottom: 1px solid var(--report-border-color-secondary);\n font-weight: normal;\n color: var(--color-gray-600);\n /* See text-wrapping comment on .lh-container. */\n word-break: normal;\n}\n\n.lh-row--group {\n background-color: var(--table-group-header-background-color);\n}\n\n.lh-row--group td {\n font-weight: bold;\n font-size: 1.05em;\n color: var(--table-group-header-text-color);\n}\n\n.lh-row--group td:first-child {\n font-weight: normal;\n}\n\n.lh-row--group .lh-text {\n color: inherit;\n text-decoration: none;\n display: inline-block;\n}\n\n.lh-row--group a.lh-link:hover {\n text-decoration: underline;\n}\n\n.lh-row--group .lh-audit__adorn {\n text-transform: capitalize;\n font-weight: normal;\n padding: 2px 3px 1px 3px;\n}\n\n.lh-row--group .lh-audit__adorn1p {\n color: var(--link-color);\n border-color: var(--link-color);\n}\n\n.lh-row--group .lh-report-icon--external::before {\n content: \"\";\n background-repeat: no-repeat;\n width: 14px;\n height: 16px;\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n\n.lh-row--group .lh-report-icon--external {\n display: none;\n}\n\n.lh-row--group:hover .lh-report-icon--external {\n display: inline-block;\n}\n\n.lh-dark .lh-report-icon--external::before {\n filter: invert(1);\n}\n\n/** Manages indentation of two-level and three-level nested adjacent rows */\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) td:first-child {\n padding-left: 20px;\n}\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) ~ .lh-sub-item-row td:first-child {\n padding-left: 40px;\n}\n\n.lh-row--even {\n background-color: var(--table-group-header-background-color);\n}\n.lh-row--hidden {\n display: none;\n}\n\n.lh-table th,\n.lh-table td {\n padding: var(--default-padding);\n}\n\n.lh-table tr {\n vertical-align: middle;\n}\n\n.lh-table tr:hover {\n background-color: var(--table-higlight-background-color);\n}\n\n/* Looks unnecessary, but mostly for keeping the s left-aligned */\n.lh-table-column--text,\n.lh-table-column--source-location,\n.lh-table-column--url,\n/* .lh-table-column--thumbnail, */\n/* .lh-table-column--empty,*/\n.lh-table-column--code,\n.lh-table-column--node {\n text-align: left;\n}\n\n.lh-table-column--code {\n min-width: 100px;\n}\n\n.lh-table-column--bytes,\n.lh-table-column--timespanMs,\n.lh-table-column--ms,\n.lh-table-column--numeric {\n text-align: right;\n word-break: normal;\n}\n\n\n\n.lh-table .lh-table-column--thumbnail {\n width: var(--image-preview-size);\n}\n\n.lh-table-column--url {\n min-width: 250px;\n}\n\n.lh-table-column--text {\n min-width: 80px;\n}\n\n/* Keep columns narrow if they follow the URL column */\n/* 12% was determined to be a decent narrow width, but wide enough for column headings */\n.lh-table-column--url + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--ms,\n.lh-table-column--url + .lh-table-column--ms + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--timespanMs {\n width: 12%;\n}\n\n.lh-text__url-host {\n display: inline;\n}\n\n.lh-text__url-host {\n margin-left: calc(var(--report-font-size) / 2);\n opacity: 0.6;\n font-size: 90%\n}\n\n.lh-thumbnail {\n object-fit: cover;\n width: var(--image-preview-size);\n height: var(--image-preview-size);\n display: block;\n}\n\n.lh-unknown pre {\n overflow: scroll;\n border: solid 1px var(--color-gray-200);\n}\n\n.lh-text__url > a {\n color: inherit;\n text-decoration: none;\n}\n\n.lh-text__url > a:hover {\n text-decoration: underline dotted #999;\n}\n\n.lh-sub-item-row {\n margin-left: 20px;\n margin-bottom: 0;\n color: var(--color-gray-700);\n}\n\n.lh-sub-item-row td {\n padding-top: 4px;\n padding-bottom: 4px;\n padding-left: 20px;\n}\n\n/* Chevron\n https://codepen.io/paulirish/pen/LmzEmK\n */\n.lh-chevron {\n --chevron-angle: 42deg;\n /* Edge doesn't support transform: rotate(calc(...)), so we define it here */\n --chevron-angle-right: -42deg;\n width: var(--chevron-size);\n height: var(--chevron-size);\n margin-top: calc((var(--report-line-height) - 12px) / 2);\n}\n\n.lh-chevron__lines {\n transition: transform 0.4s;\n transform: translateY(var(--report-line-height));\n}\n.lh-chevron__line {\n stroke: var(--chevron-line-stroke);\n stroke-width: var(--chevron-size);\n stroke-linecap: square;\n transform-origin: 50%;\n transform: rotate(var(--chevron-angle));\n transition: transform 300ms, stroke 300ms;\n}\n\n.lh-expandable-details .lh-chevron__line-right,\n.lh-expandable-details[open] .lh-chevron__line-left {\n transform: rotate(var(--chevron-angle-right));\n}\n\n.lh-expandable-details[open] .lh-chevron__line-right {\n transform: rotate(var(--chevron-angle));\n}\n\n\n.lh-expandable-details[open] .lh-chevron__lines {\n transform: translateY(calc(var(--chevron-size) * -1));\n}\n\n.lh-expandable-details[open] {\n animation: 300ms openDetails forwards;\n padding-bottom: var(--default-padding);\n}\n\n@keyframes openDetails {\n from {\n outline: 1px solid var(--report-background-color);\n }\n to {\n outline: 1px solid;\n box-shadow: 0 2px 4px rgba(0, 0, 0, .24);\n }\n}\n\n@media screen and (max-width: 780px) {\n /* no black outline if we're not confident the entire table can be displayed within bounds */\n .lh-expandable-details[open] {\n animation: none;\n }\n}\n\n.lh-expandable-details[open] summary, details.lh-clump > summary {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\ndetails.lh-clump[open] > summary {\n border-bottom-width: 0;\n}\n\n\n\ndetails .lh-clump-toggletext--hide,\ndetails[open] .lh-clump-toggletext--show { display: none; }\ndetails[open] .lh-clump-toggletext--hide { display: block;}\n\n\n/* Tooltip */\n.lh-tooltip-boundary {\n position: relative;\n}\n\n.lh-tooltip {\n position: absolute;\n display: none; /* Don't retain these layers when not needed */\n opacity: 0;\n background: #ffffff;\n white-space: pre-line; /* Render newlines in the text */\n min-width: 246px;\n max-width: 275px;\n padding: 15px;\n border-radius: 5px;\n text-align: initial;\n line-height: 1.4;\n}\n/* shrink tooltips to not be cutoff on left edge of narrow viewports\n 45vw is chosen to be ~= width of the left column of metrics\n*/\n@media screen and (max-width: 535px) {\n .lh-tooltip {\n min-width: 45vw;\n padding: 3vw;\n }\n}\n\n.lh-tooltip-boundary:hover .lh-tooltip {\n display: block;\n animation: fadeInTooltip 250ms;\n animation-fill-mode: forwards;\n animation-delay: 850ms;\n bottom: 100%;\n z-index: 1;\n will-change: opacity;\n right: 0;\n pointer-events: none;\n}\n\n.lh-tooltip::before {\n content: \"\";\n border: solid transparent;\n border-bottom-color: #fff;\n border-width: 10px;\n position: absolute;\n bottom: -20px;\n right: 6px;\n transform: rotate(180deg);\n pointer-events: none;\n}\n\n@keyframes fadeInTooltip {\n 0% { opacity: 0; }\n 75% { opacity: 1; }\n 100% { opacity: 1; filter: drop-shadow(1px 0px 1px #aaa) drop-shadow(0px 2px 4px hsla(206, 6%, 25%, 0.15)); pointer-events: auto; }\n}\n\n/* Element screenshot */\n.lh-element-screenshot {\n float: left;\n margin-right: 20px;\n}\n.lh-element-screenshot__content {\n overflow: hidden;\n min-width: 110px;\n display: flex;\n justify-content: center;\n background-color: var(--report-background-color);\n}\n.lh-element-screenshot__image {\n position: relative;\n /* Set by ElementScreenshotRenderer.installFullPageScreenshotCssVariable */\n background-image: var(--element-screenshot-url);\n outline: 2px solid #777;\n background-color: white;\n background-repeat: no-repeat;\n}\n.lh-element-screenshot__mask {\n position: absolute;\n background: #555;\n opacity: 0.8;\n}\n.lh-element-screenshot__element-marker {\n position: absolute;\n outline: 2px solid var(--color-lime-400);\n}\n.lh-element-screenshot__overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 2000; /* .lh-topbar is 1000 */\n background: var(--screenshot-overlay-background);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: zoom-out;\n}\n\n.lh-element-screenshot__overlay .lh-element-screenshot {\n margin-right: 0; /* clearing margin used in thumbnail case */\n outline: 1px solid var(--color-gray-700);\n}\n\n.lh-screenshot-overlay--enabled .lh-element-screenshot {\n cursor: zoom-out;\n}\n.lh-screenshot-overlay--enabled .lh-node .lh-element-screenshot {\n cursor: zoom-in;\n}\n\n\n.lh-meta__items {\n --meta-icon-size: calc(var(--report-icon-size) * 0.667);\n padding: var(--default-padding);\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n background-color: var(--env-item-background-color);\n border-radius: 3px;\n margin: 0 0 var(--default-padding) 0;\n font-size: 12px;\n column-gap: var(--default-padding);\n color: var(--color-gray-700);\n}\n\n.lh-meta__item {\n display: block;\n list-style-type: none;\n position: relative;\n padding: 0 0 0 calc(var(--meta-icon-size) + var(--default-padding) * 2);\n cursor: unset; /* disable pointer cursor from report-icon */\n}\n\n.lh-meta__item.lh-tooltip-boundary {\n text-decoration: dotted underline var(--color-gray-500);\n cursor: help;\n}\n\n.lh-meta__item.lh-report-icon::before {\n position: absolute;\n left: var(--default-padding);\n width: var(--meta-icon-size);\n height: var(--meta-icon-size);\n}\n\n.lh-meta__item.lh-report-icon:hover::before {\n opacity: 0.7;\n}\n\n.lh-meta__item .lh-tooltip {\n color: var(--color-gray-800);\n}\n\n.lh-meta__item .lh-tooltip::before {\n right: auto; /* Set the tooltip arrow to the leftside */\n left: 6px;\n}\n\n/* Change the grid for narrow viewport. */\n@media screen and (max-width: 640px) {\n .lh-meta__items {\n grid-template-columns: 1fr 1fr;\n }\n}\n@media screen and (max-width: 535px) {\n .lh-meta__items {\n display: block;\n }\n}\n\n\n/*# sourceURL=report-styles.css */\n"); el0.append(el1); return el0; } From b658d37542950abf3694f8612451171e7f05d006 Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Thu, 21 Sep 2023 18:53:41 -0700 Subject: [PATCH 16/31] nit --- .../user-flows/reports/sample-flow-result.json | 18 ++++++++++++++++++ core/test/results/sample_v2.json | 6 ++++++ 2 files changed, 24 insertions(+) diff --git a/core/test/fixtures/user-flows/reports/sample-flow-result.json b/core/test/fixtures/user-flows/reports/sample-flow-result.json index fd472d6c28ca..43ab24ddef6d 100644 --- a/core/test/fixtures/user-flows/reports/sample-flow-result.json +++ b/core/test/fixtures/user-flows/reports/sample-flow-result.json @@ -515,6 +515,9 @@ "numericValue": 959.4240000000008, "numericUnit": "millisecond", "displayValue": "1.0 s", + "metricSavings": { + "TBT": 143 + }, "details": { "type": "table", "headings": [ @@ -577,6 +580,9 @@ "numericValue": 288.41200000000015, "numericUnit": "millisecond", "displayValue": "0.3 s", + "metricSavings": { + "TBT": 142.50196940171634 + }, "details": { "type": "table", "headings": [ @@ -8809,6 +8815,9 @@ "numericValue": 867.7709999999973, "numericUnit": "millisecond", "displayValue": "0.9 s", + "metricSavings": { + "TBT": 122.83299999999986 + }, "details": { "type": "table", "headings": [ @@ -8876,6 +8885,9 @@ "numericValue": 352.6489999999996, "numericUnit": "millisecond", "displayValue": "0.4 s", + "metricSavings": { + "TBT": 106.76186411159928 + }, "details": { "type": "table", "headings": [ @@ -18115,6 +18127,9 @@ "numericValue": 454.39200000000045, "numericUnit": "millisecond", "displayValue": "0.5 s", + "metricSavings": { + "TBT": 13 + }, "details": { "type": "table", "headings": [ @@ -18177,6 +18192,9 @@ "numericValue": 169.10399999999998, "numericUnit": "millisecond", "displayValue": "0.2 s", + "metricSavings": { + "TBT": 25.85177364864864 + }, "details": { "type": "table", "headings": [ diff --git a/core/test/results/sample_v2.json b/core/test/results/sample_v2.json index bbdc3a9af297..01dac7b23c55 100644 --- a/core/test/results/sample_v2.json +++ b/core/test/results/sample_v2.json @@ -1036,6 +1036,9 @@ "numericValue": 2240.732999999998, "numericUnit": "millisecond", "displayValue": "2.2 s", + "metricSavings": { + "TBT": 1220.691999999999 + }, "details": { "type": "table", "headings": [ @@ -1098,6 +1101,9 @@ "numericValue": 1324.3129999999999, "numericUnit": "millisecond", "displayValue": "1.3 s", + "metricSavings": { + "TBT": 1209.4020894768312 + }, "details": { "type": "table", "headings": [ From 6a56412f925368e2dfb534ebd964391dc9566cbb Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Mon, 25 Sep 2023 19:14:00 -0700 Subject: [PATCH 17/31] fix perf render tests --- .../performance-category-renderer-test.js | 95 +------------------ 1 file changed, 2 insertions(+), 93 deletions(-) diff --git a/report/test/renderer/performance-category-renderer-test.js b/report/test/renderer/performance-category-renderer-test.js index 2f6d30ca4b7b..360e105e3f48 100644 --- a/report/test/renderer/performance-category-renderer-test.js +++ b/report/test/renderer/performance-category-renderer-test.js @@ -59,7 +59,7 @@ describe('PerfCategoryRenderer', () => { it('renders the sections', () => { const categoryDOM = renderer.render(category, sampleResults.categoryGroups); const sections = categoryDOM.querySelectorAll('.lh-category > .lh-audit-group'); - assert.equal(sections.length, 5); + assert.equal(sections.length, 4); }); it('renders the metrics', () => { @@ -111,7 +111,7 @@ describe('PerfCategoryRenderer', () => { const sections = categoryDOM.querySelectorAll('.lh-category > .lh-audit-group'); const metricSection = categoryDOM.querySelector('.lh-audit-group--metrics'); assert.ok(!metricSection); - assert.equal(sections.length, 4); + assert.equal(sections.length, 3); }); it('renders the metrics variance disclaimer as markdown', () => { @@ -150,96 +150,6 @@ describe('PerfCategoryRenderer', () => { expect(matchingElements).toHaveLength(0); }); - it('renders an audit as an opportunity if overallSavingMs is present', () => { - // Make a non-opportunity into an opportunity. - const cloneCategory = JSON.parse(JSON.stringify(category)); - const crcAudit = cloneCategory.auditRefs.find(a => a.id === 'critical-request-chains'); - expect(crcAudit.result.details.overallSavingsMs).toBe(undefined); - crcAudit.result.details.overallSavingsMs = 5555; - crcAudit.result.details.score = 0.5; - - const categoryDOM = renderer.render(cloneCategory, sampleResults.categoryGroups); - - const crcElem = categoryDOM.querySelector('.lh-audit-group--load-opportunities #critical-request-chains.lh-audit--load-opportunity'); // eslint-disable-line max-len - - const crcSparklineBarElem = crcElem.querySelector('.lh-sparkline__bar'); - expect(crcSparklineBarElem).toBeTruthy(); - - const crcWastedElem = crcElem.querySelector('.lh-audit__display-text'); - expect(crcWastedElem.textContent).toBe('5.56s'); - expect(crcWastedElem.title).toMatch(/\d+ chains found/); - - const crcDetailsElem = crcElem.querySelector('.lh-crc-container.lh-details'); - expect(crcDetailsElem.textContent).toMatch('Maximum critical path latency'); - }); - - it('renders the failing performance opportunities', () => { - const categoryDOM = renderer.render(category, sampleResults.categoryGroups); - - const oppAudits = category.auditRefs.filter(audit => - audit.result.details && - audit.result.details.overallSavingsMs !== undefined && - !ReportUtils.showAsPassed(audit.result)); - const oppElements = [...categoryDOM.querySelectorAll('.lh-audit--load-opportunity')]; - expect(oppElements.map(e => e.id).sort()).toEqual(oppAudits.map(a => a.id).sort()); - expect(oppElements.length).toBeGreaterThan(0); - expect(oppElements.length).toMatchInlineSnapshot('6'); - - const oppElement = oppElements[0]; - const oppSparklineBarElement = oppElement.querySelector('.lh-sparkline__bar'); - const oppSparklineElement = oppElement.querySelector('.lh-load-opportunity__sparkline'); - const oppTitleElement = oppElement.querySelector('.lh-audit__title'); - const oppWastedElement = oppElement.querySelector('.lh-audit__display-text'); - assert.ok(oppTitleElement.textContent, 'did not render title'); - assert.ok(oppSparklineBarElement.style.width, 'did not set sparkline width'); - assert.ok(oppWastedElement.textContent, 'did not render stats'); - assert.ok(oppSparklineElement.title, 'did not set tooltip on sparkline'); - }); - - it('renders performance opportunities with an errorMessage', () => { - const auditWithError = { - score: 0, - result: { - score: null, scoreDisplayMode: 'error', errorMessage: 'Yikes!!', title: 'Bug #2', - description: '', - details: { - overallSavingsMs: 0, - items: [], - type: 'opportunity', - }, - }, - }; - - const fakeCategory = Object.assign({}, category, {auditRefs: [auditWithError]}); - const categoryDOM = renderer.render(fakeCategory, sampleResults.categoryGroups); - const tooltipEl = categoryDOM.querySelector('.lh-audit--load-opportunity .lh-tooltip--error'); - assert.ok(tooltipEl, 'did not render error message'); - assert.ok(/Yikes!!/.test(tooltipEl.textContent)); - }); - - it('renders performance opportunities\' explanation', () => { - const auditWithExplanation = { - score: 0, - result: { - score: 0, scoreDisplayMode: 'numeric', - numericValue: 100, explanation: 'Yikes!!', title: 'Bug #2', description: '', - details: { - overallSavingsMs: 0, - items: [], - type: 'opportunity', - }, - }, - }; - - const fakeCategory = Object.assign({}, category, {auditRefs: [auditWithExplanation]}); - const categoryDOM = renderer.render(fakeCategory, sampleResults.categoryGroups); - - const selector = '.lh-audit--load-opportunity .lh-audit-explanation'; - const tooltipEl = categoryDOM.querySelector(selector); - assert.ok(tooltipEl, 'did not render explanation text'); - assert.ok(/Yikes!!/.test(tooltipEl.textContent)); - }); - it('renders the failing diagnostics', () => { const categoryDOM = renderer.render(category, sampleResults.categoryGroups); const diagnosticSection = categoryDOM.querySelector( @@ -247,7 +157,6 @@ describe('PerfCategoryRenderer', () => { const diagnosticAuditIds = category.auditRefs.filter(audit => { return !audit.group && - !(audit.result.details?.overallSavingsMs !== undefined) && !ReportUtils.showAsPassed(audit.result); }).map(audit => audit.id).sort(); assert.ok(diagnosticAuditIds.length > 0); From 3e2af6cb48053f98119b5e764367fdea9c6a3943 Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Mon, 25 Sep 2023 19:31:47 -0700 Subject: [PATCH 18/31] move statistics --- {core/test/lib => shared/test}/statistics-test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename {core/test/lib => shared/test}/statistics-test.js (98%) diff --git a/core/test/lib/statistics-test.js b/shared/test/statistics-test.js similarity index 98% rename from core/test/lib/statistics-test.js rename to shared/test/statistics-test.js index f8bf571d3f23..4d1b23fcc8e6 100644 --- a/core/test/lib/statistics-test.js +++ b/shared/test/statistics-test.js @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ -import * as statistics from '../../../shared/statistics.js'; +import * as statistics from '../statistics.js'; describe('statistics', () => { describe('#getLogNormalScore', () => { From d49ee447d8f4f946d7ecc87e8637812030fe4718 Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Tue, 26 Sep 2023 11:25:19 -0700 Subject: [PATCH 19/31] test fixie --- .../smokehouse/__snapshots__/report-assert-test.js.snap | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/cli/test/smokehouse/__snapshots__/report-assert-test.js.snap b/cli/test/smokehouse/__snapshots__/report-assert-test.js.snap index 1dc0c6c3d68a..3910339b0299 100644 --- a/cli/test/smokehouse/__snapshots__/report-assert-test.js.snap +++ b/cli/test/smokehouse/__snapshots__/report-assert-test.js.snap @@ -20,6 +20,10 @@ exports[`getAssertionReport works (multiple failing) 1`] = ` \\"numericValue\\": 0.13570762803819444, \\"numericUnit\\": \\"unitless\\", \\"displayValue\\": \\"0.136\\", + \\"scoringOptions\\": { + \\"p10\\": 0.1, + \\"median\\": 0.25 + }, \\"details\\": { \\"type\\": \\"debugdata\\", \\"items\\": [ @@ -46,6 +50,10 @@ exports[`getAssertionReport works (trivial failing) 1`] = ` \\"numericValue\\": 0.13570762803819444, \\"numericUnit\\": \\"unitless\\", \\"displayValue\\": \\"0.136\\", + \\"scoringOptions\\": { + \\"p10\\": 0.1, + \\"median\\": 0.25 + }, \\"details\\": { \\"type\\": \\"debugdata\\", \\"items\\": [ From ae40a9b9d797eeefc4c38aec982373e5f0f194f7 Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Tue, 26 Sep 2023 13:33:57 -0700 Subject: [PATCH 20/31] fixes --- report/assets/styles.css | 58 +--------- .../renderer/performance-category-renderer.js | 107 ++++++------------ tsconfig.json | 1 - types/audit.d.ts | 1 + types/lhr/audit-result.d.ts | 2 + 5 files changed, 37 insertions(+), 132 deletions(-) diff --git a/report/assets/styles.css b/report/assets/styles.css index 744e45504eed..c6e6b29d2f82 100644 --- a/report/assets/styles.css +++ b/report/assets/styles.css @@ -515,11 +515,6 @@ /* Score */ -/* to remove color indicators - test */ -/* .lh-audit__score-icon { - opacity: 0; -} */ - .lh-audit__score-icon { width: var(--score-icon-size); height: var(--score-icon-size); @@ -537,8 +532,6 @@ .lh-audit--average .lh-audit__display-text { color: var(--color-average-secondary); - /* to remove color indicators - test */ - /* color: gray; */ } .lh-audit--average .lh-audit__score-icon, .lh-scorescale-range--average::before { @@ -549,8 +542,6 @@ .lh-audit--fail .lh-audit__display-text { color: var(--color-fail-secondary); - /* to remove color indicators - test */ - /* color: gray; */ } .lh-audit--fail .lh-audit__score-icon, .lh-audit--error .lh-audit__score-icon, @@ -620,7 +611,6 @@ .lh-audit__display-text, -.lh-load-opportunity__sparkline, .lh-chevron-container { margin: 0 var(--audit-margin-horizontal); } @@ -637,14 +627,11 @@ font-size: var(--report-monospace-font-size); } -/* Prepend display text with em dash separator. But not in Opportunities. */ +/* Prepend display text with em dash separator. */ .lh-audit__display-text:not(:empty):before { content: '—'; margin-right: var(--audit-margin-horizontal); } -.lh-audit-group.lh-audit-group--load-opportunities .lh-audit__display-text:not(:empty):before { - display: none; -} /* Expandable Details (Audit Groups, Audits) */ .lh-audit__header { @@ -653,10 +640,6 @@ padding: var(--default-padding); } -.lh-audit--load-opportunity .lh-audit__header { - display: block; -} - .lh-metricfilter { display: grid; @@ -884,46 +867,8 @@ color: var(--color-fail-secondary); } -/* Perf load opportunity */ - -.lh-load-opportunity__cols { - display: flex; - align-items: flex-start; -} - -.lh-load-opportunity__header .lh-load-opportunity__col { - color: var(--color-gray-600); - display: unset; - line-height: calc(2.3 * var(--report-font-size)); -} - -.lh-load-opportunity__col { - display: flex; -} - -.lh-load-opportunity__col--one { - flex: 5; - align-items: center; - margin-right: 2px; -} -.lh-load-opportunity__col--two { - flex: 4; - text-align: right; -} - -.lh-audit--load-opportunity .lh-audit__display-text { - text-align: right; - flex: 0 0 7.5ch; -} - - /* Sparkline */ -.lh-load-opportunity__sparkline { - flex: 1; - margin-top: calc((var(--report-line-height) - var(--sparkline-height)) / 2); -} - .lh-sparkline { height: var(--sparkline-height); width: 100%; @@ -1087,7 +1032,6 @@ .lh-details, .lh-category-header__description, -.lh-load-opportunity__header, .lh-audit-group__footer { font-size: var(--report-font-size-secondary); line-height: var(--report-line-height-secondary); diff --git a/report/renderer/performance-category-renderer.js b/report/renderer/performance-category-renderer.js index 5d1b444a94c1..dc4b509047b2 100644 --- a/report/renderer/performance-category-renderer.js +++ b/report/renderer/performance-category-renderer.js @@ -44,42 +44,6 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { return element; } - /** - * @param {LH.ReportResult.AuditRef} audit - * @param {number} scale - * @return {!Element} - */ - _renderOpportunity(audit, scale) { - const oppTmpl = this.dom.createComponent('opportunity'); - const element = this.populateAuditValues(audit, oppTmpl); - element.id = audit.result.id; - - if (!audit.result.details || audit.result.scoreDisplayMode === 'error') { - return element; - } - const details = audit.result.details; - if (details.overallSavingsMs === undefined) { - return element; - } - - // Overwrite the displayValue with opportunity's wastedMs - // TODO: normalize this to one tagName. - const displayEl = - this.dom.find('span.lh-audit__display-text, div.lh-audit__display-text', element); - const sparklineWidthPct = `${details.overallSavingsMs / scale * 100}%`; - this.dom.find('div.lh-sparkline__bar', element).style.width = sparklineWidthPct; - displayEl.textContent = Globals.i18n.formatSeconds(details.overallSavingsMs, 0.01); - - // Set [title] tooltips - if (audit.result.displayValue) { - const displayValue = audit.result.displayValue; - this.dom.find('div.lh-load-opportunity__sparkline', element).title = displayValue; - displayEl.title = displayValue; - } - - return element; - } - /** * Get an audit's wastedMs to sort the opportunity by, and scale the sparkline width * Opportunities with an error won't have a details object, so MIN_VALUE is returned to keep any @@ -147,18 +111,13 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { } /** - * For performance, audits with no group should be a diagnostic or opportunity. - * The audit details type will determine which of the two groups an audit is in. + * For performance, audits without. * * @param {LH.ReportResult.AuditRef} audit - * @return {'load-opportunity'|'diagnostic'|null} + * @return {boolean} */ - _classifyPerformanceAudit(audit) { - if (audit.group) return null; - if (audit.result.details?.overallSavingsMs !== undefined) { - return 'load-opportunity'; - } - return 'diagnostic'; + _isPerformanceInsight(audit) { + return !audit.group; } /** @@ -167,35 +126,35 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { * @return {{overallImpact: number, overallLinearImpact: number}} */ overallImpact(audit, metricAudits) { - if (audit.result.metricSavings) { - let overallImpact = 0; - let overallLinearImpact = 0; - for (const [k, savings] of Object.entries(audit.result.metricSavings)) { - // Get metric savings for individual audit. - if (savings === undefined) continue; - - // Get the metric data. - const mAudit = metricAudits.find(audit => audit.acronym === k); - if (!mAudit) continue; - if (mAudit.result.score === null) continue; - - const mValue = mAudit.result.numericValue; - if (!mValue) continue; - - const scoringOptions = mAudit.result.scoringOptions; - if (!scoringOptions) continue; - - const newMetricScore = Util.computeLogNormalScore(scoringOptions, mValue - savings); - const linearImpact = savings / mValue * mAudit.weight; - overallLinearImpact += linearImpact; - - const weightedMetricImpact = (newMetricScore - mAudit.result.score) * mAudit.weight; - overallImpact += weightedMetricImpact; - } - return {overallImpact, overallLinearImpact}; + if (!audit.result.metricSavings) { + return {overallImpact: 0, overallLinearImpact: 0}; } - return {overallImpact: 0, overallLinearImpact: 0}; + let overallImpact = 0; + let overallLinearImpact = 0; + for (const [k, savings] of Object.entries(audit.result.metricSavings)) { + // Get metric savings for individual audit. + if (savings === undefined) continue; + + // Get the metric data. + const mAudit = metricAudits.find(audit => audit.acronym === k); + if (!mAudit) continue; + if (mAudit.result.score === null) continue; + + const mValue = mAudit.result.numericValue; + if (!mValue) continue; + + const scoringOptions = mAudit.result.scoringOptions; + if (!scoringOptions) continue; + + const newMetricScore = Util.computeLogNormalScore(scoringOptions, mValue - savings); + const linearImpact = savings / mValue * mAudit.weight; + overallLinearImpact += linearImpact; + + const weightedMetricImpact = (newMetricScore - mAudit.result.score) * mAudit.weight; + overallImpact += weightedMetricImpact; + } + return {overallImpact, overallLinearImpact}; } /** @@ -274,7 +233,7 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { // Diagnostics const diagnosticAudits = category.auditRefs // All audits here. - .filter(audit => this._classifyPerformanceAudit(audit)) + .filter(audit => this._isPerformanceInsight(audit)) .filter(audit => !ReportUtils.showAsPassed(audit.result)) .sort((a, b) => { // Sort by impact. @@ -316,7 +275,7 @@ export class PerformanceCategoryRenderer extends CategoryRenderer { // Passed audits const passedAudits = category.auditRefs .filter(audit => - this._classifyPerformanceAudit(audit) && ReportUtils.showAsPassed(audit.result)); + this._isPerformanceInsight(audit) && ReportUtils.showAsPassed(audit.result)); if (!passedAudits.length) return element; diff --git a/tsconfig.json b/tsconfig.json index 1528c8ff8d82..10432cbc6ab5 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -26,7 +26,6 @@ "core/test/fixtures/traces/lcp-m78.devtools.log.json", "core/audits/byte-efficiency/polyfill-graph-data.json", "shared/localization/locales/en-US.json", - "shared/statistics.js", ], "exclude": [ "build/test/*test-case*.js", diff --git a/types/audit.d.ts b/types/audit.d.ts index 901a77d3919b..47003f72c406 100644 --- a/types/audit.d.ts +++ b/types/audit.d.ts @@ -88,6 +88,7 @@ declare module Audit { runWarnings?: Array; /** [EXPERIMENTAL] Estimates of how much this audit affects various performance metrics. Values will be in the unit of the respective metrics. */ metricSavings?: MetricSavings; + /** Score details including p10 and median for calculating an audit's log-normal score. */ scoringOptions?: ScoreOptions; } diff --git a/types/lhr/audit-result.d.ts b/types/lhr/audit-result.d.ts index c40cc299193b..ebf5a2f64851 100644 --- a/types/lhr/audit-result.d.ts +++ b/types/lhr/audit-result.d.ts @@ -68,9 +68,11 @@ export interface Result { details?: FormattedIcu; /** Metric savings for and audit */ metricSavings?: MetricSavings + /** Score details including p10 and median for calculating an audit's log-normal score. */ scoringOptions?: { p10: number; median: number; }; + /** A number indicating how much guidance Lighthouse provides to solve the problem in this audit on a 1-3 scale. Higher means more guidance. */ guidanceLevel?: number; } From 3266cf3f93a6c63a6dd23462382b5b83eabfe009 Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Tue, 26 Sep 2023 13:44:25 -0700 Subject: [PATCH 21/31] nit fixie --- report/renderer/components.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/report/renderer/components.js b/report/renderer/components.js index 28305435855d..89a6600ad2af 100644 --- a/report/renderer/components.js +++ b/report/renderer/components.js @@ -520,7 +520,7 @@ function createSnippetLineComponent(dom) { function createStylesComponent(dom) { const el0 = dom.createFragment(); const el1 = dom.createElement("style"); - el1.append("/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: Apache-2.0\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 --report-icon-size: var(--score-icon-background-size);\n --report-line-height: 24px;\n --report-line-height-secondary: 20px;\n --report-monospace-font-size: calc(var(--report-font-size) * 0.85);\n --report-text-color-secondary: var(--color-gray-800);\n --report-text-color: var(--color-gray-900);\n --report-content-max-width: calc(60 * var(--report-font-size)); /* defaults to 840px */\n --report-content-min-width: 360px;\n --report-content-max-width-minus-edge-gap: calc(var(--report-content-max-width) - var(--edge-gap-padding) * 2);\n --score-container-padding: 8px;\n --score-icon-background-size: 24px;\n --score-icon-margin-left: 6px;\n --score-icon-margin-right: 14px;\n --score-icon-margin: 0 var(--score-icon-margin-right) 0 var(--score-icon-margin-left);\n --score-icon-size: 12px;\n --score-icon-size-big: 16px;\n --screenshot-overlay-background: rgba(0, 0, 0, 0.3);\n --section-padding-vertical: calc(var(--default-padding) * 6);\n --snippet-background-color: var(--color-gray-50);\n --snippet-color: #0938C2;\n --sparkline-height: 5px;\n --stackpack-padding-horizontal: 10px;\n --sticky-header-background-color: var(--report-background-color);\n --sticky-header-buffer: calc(var(--topbar-height) + var(--sticky-header-height));\n --sticky-header-height: calc(var(--gauge-circle-size-sm) + var(--score-container-padding) * 2);\n --table-group-header-background-color: #EEF1F4;\n --table-group-header-text-color: var(--color-gray-700);\n --table-higlight-background-color: #F5F7FA;\n --tools-icon-color: var(--color-gray-600);\n --topbar-background-color: var(--color-white);\n --topbar-height: 32px;\n --topbar-logo-size: 24px;\n --topbar-padding: 0 8px;\n --toplevel-warning-background-color: hsla(30, 100%, 75%, 10%);\n --toplevel-warning-message-text-color: var(--color-average-secondary);\n --toplevel-warning-padding: 18px;\n --toplevel-warning-text-color: var(--report-text-color);\n\n /* SVGs */\n --plugin-icon-url-dark: url('data:image/svg+xml;utf8,');\n --plugin-icon-url: url('data:image/svg+xml;utf8,');\n\n --pass-icon-url: url('data:image/svg+xml;utf8,check');\n --average-icon-url: url('data:image/svg+xml;utf8,info');\n --fail-icon-url: url('data:image/svg+xml;utf8,warn');\n --error-icon-url: url('data:image/svg+xml;utf8,error');\n\n --pwa-installable-gray-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-gray-url-dark: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url-dark: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-color-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-color-url: url('data:image/svg+xml;utf8,');\n\n --swap-locale-icon-url: url('data:image/svg+xml;utf8,');\n}\n\n@media not print {\n .lh-dark {\n /* Pallete */\n --color-gray-200: var(--color-gray-800);\n --color-gray-300: #616161;\n --color-gray-400: var(--color-gray-600);\n --color-gray-700: var(--color-gray-400);\n --color-gray-50: #757575;\n --color-gray-600: var(--color-gray-500);\n --color-green-700: var(--color-green);\n --color-orange-700: var(--color-orange);\n --color-red-700: var(--color-red);\n --color-teal-600: var(--color-cyan-500);\n\n /* Context-specific colors */\n --color-hover: rgba(0, 0, 0, 0.2);\n --color-informative: var(--color-blue-200);\n\n /* Component variables */\n --env-item-background-color: #393535;\n --link-color: var(--color-blue-200);\n --locale-selector-background-color: var(--color-gray-200);\n --plugin-badge-background-color: var(--color-gray-800);\n --report-background-color: var(--color-gray-900);\n --report-border-color-secondary: var(--color-gray-200);\n --report-text-color-secondary: var(--color-gray-400);\n --report-text-color: var(--color-gray-100);\n --snippet-color: var(--color-cyan-500);\n --topbar-background-color: var(--color-gray);\n --toplevel-warning-background-color: hsl(33deg 14% 18%);\n --toplevel-warning-message-text-color: var(--color-orange-700);\n --toplevel-warning-text-color: var(--color-gray-100);\n --table-group-header-background-color: rgba(186, 196, 206, 0.15);\n --table-group-header-text-color: var(--color-gray-100);\n --table-higlight-background-color: rgba(186, 196, 206, 0.09);\n\n /* SVGs */\n --plugin-icon-url: var(--plugin-icon-url-dark);\n --pwa-installable-gray-url: var(--pwa-installable-gray-url-dark);\n --pwa-optimized-gray-url: var(--pwa-optimized-gray-url-dark);\n }\n}\n\n@media only screen and (max-width: 480px) {\n .lh-vars {\n --audit-group-margin-bottom: 20px;\n --edge-gap-padding: var(--default-padding);\n --env-name-min-width: 120px;\n --gauge-circle-size-big: 96px;\n --gauge-circle-size: 72px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 112px;\n --header-padding: 16px 0 16px 0;\n --image-preview-size: 24px;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-size: 14px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --topbar-height: 28px;\n --topbar-logo-size: 20px;\n }\n\n /* Not enough space to adequately show the relative savings bars. */\n .lh-sparkline {\n display: none;\n }\n}\n\n.lh-vars.lh-devtools {\n --audit-explanation-line-height: 14px;\n --audit-group-margin-bottom: 20px;\n --audit-group-padding-vertical: 12px;\n --audit-padding-vertical: 4px;\n --category-padding: 12px;\n --default-padding: 12px;\n --env-name-min-width: 120px;\n --footer-padding-vertical: 8px;\n --gauge-circle-size-big: 72px;\n --gauge-circle-size: 64px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 97px;\n --header-line-height: 20px;\n --header-padding: 16px 0 16px 0;\n --screenshot-overlay-background: transparent;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-family-monospace: 'Menlo', 'dejavu sans mono', 'Consolas', 'Lucida Console', monospace;\n --report-font-family: '.SFNSDisplay-Regular', 'Helvetica Neue', 'Lucida Grande', sans-serif;\n --report-font-size: 12px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --section-padding-vertical: 8px;\n}\n\n.lh-container:not(.lh-topbar + .lh-container) {\n --topbar-height: 0;\n --sticky-header-height: 0;\n --sticky-header-buffer: 0;\n}\n\n.lh-devtools.lh-root {\n height: 100%;\n}\n.lh-devtools.lh-root img {\n /* Override devtools default 'min-width: 0' so svg without size in a flexbox isn't collapsed. */\n min-width: auto;\n}\n.lh-devtools .lh-container {\n overflow-y: scroll;\n height: calc(100% - var(--topbar-height));\n /** The .lh-container is the scroll parent in DevTools so we exclude the topbar from the sticky header buffer. */\n --sticky-header-buffer: calc(var(--sticky-header-height));\n}\n@media print {\n .lh-devtools .lh-container {\n overflow: unset;\n }\n}\n.lh-devtools .lh-sticky-header {\n /* This is normally the height of the topbar, but we want it to stick to the top of our scroll container .lh-container` */\n top: 0;\n}\n.lh-devtools .lh-element-screenshot__overlay {\n position: absolute;\n}\n\n@keyframes fadeIn {\n 0% { opacity: 0;}\n 100% { opacity: 0.6;}\n}\n\n.lh-root *, .lh-root *::before, .lh-root *::after {\n box-sizing: border-box;\n}\n\n.lh-root {\n font-family: var(--report-font-family);\n font-size: var(--report-font-size);\n margin: 0;\n line-height: var(--report-line-height);\n background: var(--report-background-color);\n color: var(--report-text-color);\n}\n\n.lh-root :focus-visible {\n outline: -webkit-focus-ring-color auto 3px;\n}\n.lh-root summary:focus {\n outline: none;\n box-shadow: 0 0 0 1px hsl(217, 89%, 61%);\n}\n\n.lh-root [hidden] {\n display: none !important;\n}\n\n.lh-root pre {\n margin: 0;\n}\n\n.lh-root pre,\n.lh-root code {\n font-family: var(--report-font-family-monospace);\n}\n\n.lh-root details > summary {\n cursor: pointer;\n}\n\n.lh-hidden {\n display: none !important;\n}\n\n.lh-container {\n /*\n Text wrapping in the report is so much FUN!\n We have a `word-break: break-word;` globally here to prevent a few common scenarios, namely\n long non-breakable text (usually URLs) found in:\n 1. The footer\n 2. .lh-node (outerHTML)\n 3. .lh-code\n\n With that sorted, the next challenge is appropriate column sizing and text wrapping inside our\n .lh-details tables. Even more fun.\n * We don't want table headers (\"Potential Savings (ms)\") to wrap or their column values, but\n we'd be happy for the URL column to wrap if the URLs are particularly long.\n * We want the narrow columns to remain narrow, providing the most column width for URL\n * We don't want the table to extend past 100% width.\n * Long URLs in the URL column can wrap. Util.getURLDisplayName maxes them out at 64 characters,\n but they do not get any overflow:ellipsis treatment.\n */\n word-break: break-word;\n}\n\n.lh-audit-group a,\n.lh-category-header__description a,\n.lh-audit__description a,\n.lh-warnings a,\n.lh-footer a,\n.lh-table-column--link a {\n color: var(--link-color);\n}\n\n.lh-audit__description, .lh-audit__stackpack {\n --inner-audit-padding-right: var(--stackpack-padding-horizontal);\n padding-left: var(--audit-description-padding-left);\n padding-right: var(--inner-audit-padding-right);\n padding-top: 8px;\n padding-bottom: 8px;\n}\n\n.lh-details {\n margin-top: var(--default-padding);\n margin-bottom: var(--default-padding);\n margin-left: var(--audit-description-padding-left);\n /* whatever the .lh-details side margins are */\n width: 100%;\n}\n\n.lh-audit__stackpack {\n display: flex;\n align-items: center;\n}\n\n.lh-audit__stackpack__img {\n max-width: 30px;\n margin-right: var(--default-padding)\n}\n\n/* Report header */\n\n.lh-report-icon {\n display: flex;\n align-items: center;\n padding: 10px 12px;\n cursor: pointer;\n}\n.lh-report-icon[disabled] {\n opacity: 0.3;\n pointer-events: none;\n}\n\n.lh-report-icon::before {\n content: \"\";\n margin: 4px;\n background-repeat: no-repeat;\n width: var(--report-icon-size);\n height: var(--report-icon-size);\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n.lh-report-icon:hover::before {\n opacity: 1;\n}\n.lh-dark .lh-report-icon::before {\n filter: invert(1);\n}\n.lh-report-icon--print::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--copy::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--open::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--download::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--dark::before {\n background-image:url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--treemap::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--date::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--devices::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--world::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--stopwatch::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--networkspeed::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-one::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-many::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--chrome::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--external::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n\n.lh-buttons {\n display: flex;\n flex-wrap: wrap;\n margin: var(--default-padding) 0;\n}\n.lh-button {\n height: 32px;\n border: 1px solid var(--report-border-color-secondary);\n border-radius: 3px;\n color: var(--link-color);\n background-color: var(--report-background-color);\n margin: 5px;\n}\n\n.lh-button:first-of-type {\n margin-left: 0;\n}\n\n/* Node */\n.lh-node__snippet {\n font-family: var(--report-font-family-monospace);\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n line-height: 20px;\n}\n\n/* Score */\n\n/* to remove color indicators - test */\n/* .lh-audit__score-icon {\n opacity: 0;\n} */\n\n.lh-audit__score-icon {\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n margin: var(--score-icon-margin);\n}\n\n.lh-audit--pass .lh-audit__display-text {\n color: var(--color-pass-secondary);\n}\n.lh-audit--pass .lh-audit__score-icon,\n.lh-scorescale-range--pass::before {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-audit__display-text {\n color: var(--color-average-secondary);\n /* to remove color indicators - test */\n /* color: gray; */\n}\n.lh-audit--average .lh-audit__score-icon,\n.lh-scorescale-range--average::before {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-audit--fail .lh-audit__display-text {\n color: var(--color-fail-secondary);\n /* to remove color indicators - test */\n /* color: gray; */\n}\n.lh-audit--fail .lh-audit__score-icon,\n.lh-audit--error .lh-audit__score-icon,\n.lh-scorescale-range--fail::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-audit--error .lh-audit__score-icon,\n.lh-metric--error .lh-metric__icon {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n border: none;\n}\n\n.lh-gauge__wrapper--fail .lh-gauge--error {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n transform: scale(0.5);\n top: var(--score-container-padding);\n}\n\n.lh-audit--manual .lh-audit__display-text,\n.lh-audit--notapplicable .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n.lh-audit--manual .lh-audit__score-icon,\n.lh-audit--notapplicable .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n background: none;\n}\n\n.lh-audit--informative .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n\n.lh-audit--informative .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n}\n\n.lh-audit__description,\n.lh-audit__stackpack {\n color: var(--report-text-color-secondary);\n}\n.lh-audit__adorn {\n border: 1px solid var(--color-gray-500);\n border-radius: 3px;\n margin: 0 3px;\n padding: 0 2px;\n line-height: 1.1;\n display: inline-block;\n font-size: 90%;\n color: var(--report-text-color-secondary);\n}\n\n.lh-category-header__description {\n text-align: center;\n color: var(--color-gray-700);\n margin: 0px auto;\n max-width: 400px;\n}\n\n\n.lh-audit__display-text,\n.lh-load-opportunity__sparkline,\n.lh-chevron-container {\n margin: 0 var(--audit-margin-horizontal);\n}\n.lh-chevron-container {\n margin-right: 0;\n}\n\n.lh-audit__title-and-text {\n flex: 1;\n}\n\n.lh-audit__title-and-text code {\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n}\n\n/* Prepend display text with em dash separator. But not in Opportunities. */\n.lh-audit__display-text:not(:empty):before {\n content: '—';\n margin-right: var(--audit-margin-horizontal);\n}\n.lh-audit-group.lh-audit-group--load-opportunities .lh-audit__display-text:not(:empty):before {\n display: none;\n}\n\n/* Expandable Details (Audit Groups, Audits) */\n.lh-audit__header {\n display: flex;\n align-items: center;\n padding: var(--default-padding);\n}\n\n.lh-audit--load-opportunity .lh-audit__header {\n display: block;\n}\n\n\n.lh-metricfilter {\n display: grid;\n justify-content: end;\n align-items: center;\n grid-auto-flow: column;\n gap: 4px;\n color: var(--color-gray-700);\n}\n\n.lh-metricfilter__radio {\n /*\n * Instead of hiding, position offscreen so it's still accessible to screen readers\n * https://bugs.chromium.org/p/chromium/issues/detail?id=1439785\n */\n position: fixed;\n left: -9999px;\n}\n.lh-metricfilter input[type='radio']:focus-visible + label {\n outline: -webkit-focus-ring-color auto 1px;\n}\n\n.lh-metricfilter__label {\n display: inline-flex;\n padding: 0 4px;\n height: 16px;\n text-decoration: underline;\n align-items: center;\n cursor: pointer;\n font-size: 90%;\n}\n\n.lh-metricfilter__label--active {\n background: var(--color-blue-primary);\n color: var(--color-white);\n border-radius: 3px;\n text-decoration: none;\n}\n/* Give the 'All' choice a more muted display */\n.lh-metricfilter__label--active[for=\"metric-All\"] {\n background-color: var(--color-blue-200) !important;\n color: black !important;\n}\n\n.lh-metricfilter__text {\n margin-right: 8px;\n}\n\n/* If audits are filtered, hide the itemcount for Passed Audits… */\n.lh-category--filtered .lh-audit-group .lh-audit-group__itemcount {\n display: none;\n}\n\n\n.lh-audit__header:hover {\n background-color: var(--color-hover);\n}\n\n/* We want to hide the browser's default arrow marker on summary elements. Admittedly, it's complicated. */\n.lh-root details > summary {\n /* Blink 89+ and Firefox will hide the arrow when display is changed from (new) default of `list-item` to block. https://chromestatus.com/feature/6730096436051968*/\n display: block;\n}\n/* Safari and Blink <=88 require using the -webkit-details-marker selector */\n.lh-root details > summary::-webkit-details-marker {\n display: none;\n}\n\n/* Perf Metric */\n\n.lh-metrics-container {\n display: grid;\n grid-auto-rows: 1fr;\n grid-template-columns: 1fr 1fr;\n grid-column-gap: var(--report-line-height);\n margin-bottom: var(--default-padding);\n}\n\n.lh-metric {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(-n+2) {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-metric__innerwrap {\n display: grid;\n /**\n * Icon -- Metric Name\n * -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 1fr;\n align-items: center;\n padding: var(--default-padding);\n}\n\n.lh-metric__details {\n order: -1;\n}\n\n.lh-metric__title {\n flex: 1;\n}\n\n.lh-calclink {\n padding-left: calc(1ex / 3);\n}\n\n.lh-metric__description {\n display: none;\n grid-column-start: 2;\n grid-column-end: 4;\n color: var(--report-text-color-secondary);\n}\n\n.lh-metric__value {\n font-size: var(--metric-value-font-size);\n margin: calc(var(--default-padding) / 2) 0;\n white-space: nowrap; /* No wrapping between metric value and the icon */\n grid-column-start: 2;\n}\n\n\n@media screen and (max-width: 535px) {\n .lh-metrics-container {\n display: block;\n }\n\n .lh-metric {\n border-bottom: none !important;\n }\n .lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(1) {\n border-bottom: 1px solid var(--report-border-color-secondary) !important;\n }\n\n /* Change the grid to 3 columns for narrow viewport. */\n .lh-metric__innerwrap {\n /**\n * Icon -- Metric Name -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 2fr 1fr;\n }\n .lh-metric__value {\n justify-self: end;\n grid-column-start: unset;\n }\n}\n\n/* No-JS toggle switch */\n/* Keep this selector sync'd w/ `magicSelector` in report-ui-features-test.js */\n .lh-metrics-toggle__input:checked ~ .lh-metrics-container .lh-metric__description {\n display: block;\n}\n\n/* TODO get rid of the SVGS and clean up these some more */\n.lh-metrics-toggle__input {\n opacity: 0;\n position: absolute;\n right: 0;\n top: 0px;\n}\n\n.lh-metrics-toggle__input + div > label > .lh-metrics-toggle__labeltext--hide,\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--show {\n display: none;\n}\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--hide {\n display: inline;\n}\n.lh-metrics-toggle__input:focus + div > label {\n outline: -webkit-focus-ring-color auto 3px;\n}\n\n.lh-metrics-toggle__label {\n cursor: pointer;\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n/* Pushes the metric description toggle button to the right. */\n.lh-audit-group--metrics .lh-audit-group__header {\n display: flex;\n justify-content: space-between;\n}\n\n.lh-metric__icon,\n.lh-scorescale-range::before {\n content: '';\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n display: inline-block;\n margin: var(--score-icon-margin);\n}\n\n.lh-metric--pass .lh-metric__value {\n color: var(--color-pass-secondary);\n}\n.lh-metric--pass .lh-metric__icon {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-metric--average .lh-metric__value {\n color: var(--color-average-secondary);\n}\n.lh-metric--average .lh-metric__icon {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-metric--fail .lh-metric__value {\n color: var(--color-fail-secondary);\n}\n.lh-metric--fail .lh-metric__icon {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-metric--error .lh-metric__value,\n.lh-metric--error .lh-metric__description {\n color: var(--color-fail-secondary);\n}\n\n/* Perf load opportunity */\n\n.lh-load-opportunity__cols {\n display: flex;\n align-items: flex-start;\n}\n\n.lh-load-opportunity__header .lh-load-opportunity__col {\n color: var(--color-gray-600);\n display: unset;\n line-height: calc(2.3 * var(--report-font-size));\n}\n\n.lh-load-opportunity__col {\n display: flex;\n}\n\n.lh-load-opportunity__col--one {\n flex: 5;\n align-items: center;\n margin-right: 2px;\n}\n.lh-load-opportunity__col--two {\n flex: 4;\n text-align: right;\n}\n\n.lh-audit--load-opportunity .lh-audit__display-text {\n text-align: right;\n flex: 0 0 7.5ch;\n}\n\n\n/* Sparkline */\n\n.lh-load-opportunity__sparkline {\n flex: 1;\n margin-top: calc((var(--report-line-height) - var(--sparkline-height)) / 2);\n}\n\n.lh-sparkline {\n height: var(--sparkline-height);\n width: 100%;\n}\n\n.lh-sparkline__bar {\n height: 100%;\n float: right;\n}\n\n.lh-audit--pass .lh-sparkline__bar {\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-sparkline__bar {\n background: var(--color-average);\n}\n\n.lh-audit--fail .lh-sparkline__bar {\n background: var(--color-fail);\n}\n\n/* Filmstrip */\n\n.lh-filmstrip-container {\n /* smaller gap between metrics and filmstrip */\n margin: -8px auto 0 auto;\n}\n\n.lh-filmstrip {\n display: grid;\n justify-content: space-between;\n padding-bottom: var(--default-padding);\n width: 100%;\n grid-template-columns: repeat(auto-fit, 90px);\n}\n\n.lh-filmstrip__frame {\n text-align: right;\n position: relative;\n}\n\n.lh-filmstrip__thumbnail {\n border: 1px solid var(--report-border-color-secondary);\n max-height: 150px;\n max-width: 120px;\n}\n\n/* Audit */\n\n.lh-audit {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n/* Apply border-top to just the first audit. */\n.lh-audit {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n.lh-audit ~ .lh-audit {\n border-top: none;\n}\n\n\n.lh-audit--error .lh-audit__display-text {\n color: var(--color-fail-secondary);\n}\n\n/* Audit Group */\n\n.lh-audit-group {\n margin-bottom: var(--audit-group-margin-bottom);\n position: relative;\n}\n.lh-audit-group--metrics {\n margin-bottom: calc(var(--audit-group-margin-bottom) / 2);\n}\n\n.lh-audit-group__header::before {\n /* By default, groups don't get an icon */\n content: none;\n width: var(--pwa-icon-size);\n height: var(--pwa-icon-size);\n margin: var(--pwa-icon-margin);\n display: inline-block;\n vertical-align: middle;\n}\n\n/* Style the \"over budget\" columns red. */\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(4),\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(5),\n.lh-audit-group--budgets #timing-budget tbody tr td:nth-child(3) {\n color: var(--color-red-700);\n}\n\n/* Align the \"over budget request count\" text to be close to the \"over budget bytes\" column. */\n.lh-audit-group--budgets .lh-table tbody tr td:nth-child(4){\n text-align: right;\n}\n\n.lh-audit-group--budgets .lh-details--budget {\n width: 100%;\n margin: 0 0 var(--default-padding);\n}\n\n.lh-audit-group--pwa-installable .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-installable-gray-url);\n}\n.lh-audit-group--pwa-optimized .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-optimized-gray-url);\n}\n.lh-audit-group--pwa-installable.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-installable-color-url);\n}\n.lh-audit-group--pwa-optimized.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-optimized-color-url);\n}\n\n.lh-audit-group--metrics .lh-audit-group__summary {\n margin-top: 0;\n margin-bottom: 0;\n}\n\n.lh-audit-group__summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.lh-audit-group__header .lh-chevron {\n margin-top: calc((var(--report-line-height) - 5px) / 2);\n}\n\n.lh-audit-group__header {\n letter-spacing: 0.8px;\n padding: var(--default-padding);\n padding-left: 0;\n}\n\n.lh-audit-group__header, .lh-audit-group__summary {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n.lh-audit-group__title {\n text-transform: uppercase;\n font-weight: 500;\n}\n\n.lh-audit-group__itemcount {\n color: var(--color-gray-600);\n}\n\n.lh-audit-group__footer {\n color: var(--color-gray-600);\n display: block;\n margin-top: var(--default-padding);\n}\n\n.lh-details,\n.lh-category-header__description,\n.lh-load-opportunity__header,\n.lh-audit-group__footer {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n}\n\n.lh-audit-explanation {\n margin: var(--audit-padding-vertical) 0 calc(var(--audit-padding-vertical) / 2) var(--audit-margin-horizontal);\n line-height: var(--audit-explanation-line-height);\n display: inline-block;\n}\n\n.lh-audit--fail .lh-audit-explanation {\n color: var(--color-fail-secondary);\n}\n\n/* Report */\n.lh-list > :not(:last-child) {\n margin-bottom: calc(var(--default-padding) * 2);\n}\n\n.lh-header-container {\n display: block;\n margin: 0 auto;\n position: relative;\n word-wrap: break-word;\n}\n\n.lh-header-container .lh-scores-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n\n\n.lh-report {\n min-width: var(--report-content-min-width);\n}\n\n.lh-exception {\n font-size: large;\n}\n\n.lh-code {\n white-space: normal;\n margin-top: 0;\n font-size: var(--report-monospace-font-size);\n}\n\n.lh-warnings {\n --item-margin: calc(var(--report-line-height) / 6);\n color: var(--color-average-secondary);\n margin: var(--audit-padding-vertical) 0;\n padding: var(--default-padding)\n var(--default-padding)\n var(--default-padding)\n calc(var(--audit-description-padding-left));\n background-color: var(--toplevel-warning-background-color);\n}\n.lh-warnings span {\n font-weight: bold;\n}\n\n.lh-warnings--toplevel {\n --item-margin: calc(var(--header-line-height) / 4);\n color: var(--toplevel-warning-text-color);\n margin-left: auto;\n margin-right: auto;\n max-width: var(--report-content-max-width-minus-edge-gap);\n padding: var(--toplevel-warning-padding);\n border-radius: 8px;\n}\n\n.lh-warnings__msg {\n color: var(--toplevel-warning-message-text-color);\n margin: 0;\n}\n\n.lh-warnings ul {\n margin: 0;\n}\n.lh-warnings li {\n margin: var(--item-margin) 0;\n}\n.lh-warnings li:last-of-type {\n margin-bottom: 0;\n}\n\n.lh-scores-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n}\n.lh-scores-header__solo {\n padding: 0;\n border: 0;\n}\n\n/* Gauge */\n\n.lh-gauge__wrapper--pass {\n color: var(--color-pass-secondary);\n fill: var(--color-pass);\n stroke: var(--color-pass);\n}\n\n.lh-gauge__wrapper--average {\n color: var(--color-average-secondary);\n fill: var(--color-average);\n stroke: var(--color-average);\n}\n\n.lh-gauge__wrapper--fail {\n color: var(--color-fail-secondary);\n fill: var(--color-fail);\n stroke: var(--color-fail);\n}\n\n.lh-gauge__wrapper--not-applicable {\n color: var(--color-not-applicable);\n fill: var(--color-not-applicable);\n stroke: var(--color-not-applicable);\n}\n\n.lh-fraction__wrapper .lh-fraction__content::before {\n content: '';\n height: var(--score-icon-size);\n width: var(--score-icon-size);\n margin: var(--score-icon-margin);\n display: inline-block;\n}\n.lh-fraction__wrapper--pass .lh-fraction__content {\n color: var(--color-pass-secondary);\n}\n.lh-fraction__wrapper--pass .lh-fraction__background {\n background-color: var(--color-pass);\n}\n.lh-fraction__wrapper--pass .lh-fraction__content::before {\n background-color: var(--color-pass);\n border-radius: 50%;\n}\n.lh-fraction__wrapper--average .lh-fraction__content {\n color: var(--color-average-secondary);\n}\n.lh-fraction__wrapper--average .lh-fraction__background,\n.lh-fraction__wrapper--average .lh-fraction__content::before {\n background-color: var(--color-average);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content {\n color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__background {\n background-color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n.lh-fraction__wrapper--null .lh-fraction__content {\n color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__background {\n background-color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__content::before {\n border-radius: 50%;\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-700);\n}\n\n.lh-fraction__background {\n position: absolute;\n height: 100%;\n width: 100%;\n border-radius: calc(var(--gauge-circle-size) / 2);\n opacity: 0.1;\n z-index: -1;\n}\n\n.lh-fraction__content-wrapper {\n height: var(--gauge-circle-size);\n display: flex;\n align-items: center;\n}\n\n.lh-fraction__content {\n display: flex;\n position: relative;\n align-items: center;\n justify-content: center;\n font-size: calc(0.3 * var(--gauge-circle-size));\n line-height: calc(0.4 * var(--gauge-circle-size));\n width: max-content;\n min-width: calc(1.5 * var(--gauge-circle-size));\n padding: calc(0.1 * var(--gauge-circle-size)) calc(0.2 * var(--gauge-circle-size));\n --score-icon-size: calc(0.21 * var(--gauge-circle-size));\n --score-icon-margin: 0 calc(0.15 * var(--gauge-circle-size)) 0 0;\n}\n\n.lh-gauge {\n stroke-linecap: round;\n width: var(--gauge-circle-size);\n height: var(--gauge-circle-size);\n}\n\n.lh-category .lh-gauge {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n.lh-gauge-base {\n opacity: 0.1;\n}\n\n.lh-gauge-arc {\n fill: none;\n transform-origin: 50% 50%;\n animation: load-gauge var(--transition-length) ease both;\n animation-delay: 250ms;\n}\n\n.lh-gauge__svg-wrapper {\n position: relative;\n height: var(--gauge-circle-size);\n}\n.lh-category .lh-gauge__svg-wrapper,\n.lh-category .lh-fraction__wrapper {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n/* The plugin badge overlay */\n.lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size);\n height: var(--plugin-badge-size);\n background-color: var(--plugin-badge-background-color);\n background-image: var(--plugin-icon-url);\n background-repeat: no-repeat;\n background-size: var(--plugin-icon-size);\n background-position: 58% 50%;\n content: \"\";\n position: absolute;\n right: -6px;\n bottom: 0px;\n display: block;\n z-index: 100;\n box-shadow: 0 0 4px rgba(0,0,0,.2);\n border-radius: 25%;\n}\n.lh-category .lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size-big);\n height: var(--plugin-badge-size-big);\n}\n\n@keyframes load-gauge {\n from { stroke-dasharray: 0 352; }\n}\n\n.lh-gauge__percentage {\n width: 100%;\n height: var(--gauge-circle-size);\n line-height: var(--gauge-circle-size);\n position: absolute;\n font-family: var(--report-font-family-monospace);\n font-size: calc(var(--gauge-circle-size) * 0.34 + 1.3px);\n text-align: center;\n top: var(--score-container-padding);\n}\n\n.lh-category .lh-gauge__percentage {\n --gauge-circle-size: var(--gauge-circle-size-big);\n --gauge-percentage-font-size: var(--gauge-percentage-font-size-big);\n}\n\n.lh-gauge__wrapper,\n.lh-fraction__wrapper {\n position: relative;\n display: flex;\n align-items: center;\n flex-direction: column;\n text-decoration: none;\n padding: var(--score-container-padding);\n\n --transition-length: 1s;\n\n /* Contain the layout style paint & layers during animation*/\n contain: content;\n will-change: opacity; /* Only using for layer promotion */\n}\n\n.lh-gauge__label,\n.lh-fraction__label {\n font-size: var(--gauge-label-font-size);\n font-weight: 500;\n line-height: var(--gauge-label-line-height);\n margin-top: 10px;\n text-align: center;\n color: var(--report-text-color);\n word-break: keep-all;\n}\n\n/* TODO(#8185) use more BEM (.lh-gauge__label--big) instead of relying on descendant selector */\n.lh-category .lh-gauge__label,\n.lh-category .lh-fraction__label {\n --gauge-label-font-size: var(--gauge-label-font-size-big);\n --gauge-label-line-height: var(--gauge-label-line-height-big);\n margin-top: 14px;\n}\n\n.lh-scores-header .lh-gauge__wrapper,\n.lh-scores-header .lh-fraction__wrapper,\n.lh-scores-header .lh-gauge--pwa__wrapper,\n.lh-sticky-header .lh-gauge__wrapper,\n.lh-sticky-header .lh-fraction__wrapper,\n.lh-sticky-header .lh-gauge--pwa__wrapper {\n width: var(--gauge-wrapper-width);\n}\n\n.lh-scorescale {\n display: inline-flex;\n\n gap: calc(var(--default-padding) * 4);\n margin: 16px auto 0 auto;\n font-size: var(--report-font-size-secondary);\n color: var(--color-gray-700);\n\n}\n\n.lh-scorescale-range {\n display: flex;\n align-items: center;\n font-family: var(--report-font-family-monospace);\n white-space: nowrap;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale {\n border: 0;\n display: flex;\n justify-content: center;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale-range {\n font-family: unset;\n font-size: 12px;\n}\n\n.lh-scorescale-wrap {\n display: contents;\n}\n\n/* Hide category score gauages if it's a single category report */\n.lh-header--solo-category .lh-scores-wrapper {\n display: none;\n}\n\n\n.lh-categories {\n width: 100%;\n}\n\n.lh-category {\n padding: var(--category-padding);\n max-width: var(--report-content-max-width);\n margin: 0 auto;\n\n scroll-margin-top: var(--sticky-header-buffer);\n}\n\n.lh-category-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n.lh-category-wrapper:last-of-type {\n border-bottom: 0;\n}\n\n.lh-category-header {\n margin-bottom: var(--section-padding-vertical);\n}\n\n.lh-category-header .lh-score__gauge {\n max-width: 400px;\n width: auto;\n margin: 0px auto;\n}\n\n.lh-category-header__finalscreenshot {\n display: grid;\n grid-template: none / 1fr 1px 1fr;\n justify-items: center;\n align-items: center;\n gap: var(--report-line-height);\n min-height: 288px;\n margin-bottom: var(--default-padding);\n}\n\n.lh-final-ss-image {\n /* constrain the size of the image to not be too large */\n max-height: calc(var(--gauge-circle-size-big) * 2.8);\n max-width: calc(var(--gauge-circle-size-big) * 3.5);\n border: 1px solid var(--color-gray-200);\n padding: 4px;\n border-radius: 3px;\n display: block;\n}\n\n.lh-category-headercol--separator {\n background: var(--color-gray-200);\n width: 1px;\n height: var(--gauge-circle-size-big);\n}\n\n@media screen and (max-width: 780px) {\n .lh-category-header__finalscreenshot {\n grid-template: 1fr 1fr / none\n }\n .lh-category-headercol--separator {\n display: none;\n }\n}\n\n\n/* 964 fits the min-width of the filmstrip */\n@media screen and (max-width: 964px) {\n .lh-report {\n margin-left: 0;\n width: 100%;\n }\n}\n\n@media print {\n body {\n -webkit-print-color-adjust: exact; /* print background colors */\n }\n .lh-container {\n display: block;\n }\n .lh-report {\n margin-left: 0;\n padding-top: 0;\n }\n .lh-categories {\n margin-top: 0;\n }\n}\n\n.lh-table {\n position: relative;\n border-collapse: separate;\n border-spacing: 0;\n /* Can't assign padding to table, so shorten the width instead. */\n width: calc(100% - var(--audit-description-padding-left) - var(--stackpack-padding-horizontal));\n border: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-table thead th {\n position: sticky;\n top: calc(var(--sticky-header-buffer) + 1em);\n z-index: 1;\n background-color: var(--report-background-color);\n border-bottom: 1px solid var(--report-border-color-secondary);\n font-weight: normal;\n color: var(--color-gray-600);\n /* See text-wrapping comment on .lh-container. */\n word-break: normal;\n}\n\n.lh-row--group {\n background-color: var(--table-group-header-background-color);\n}\n\n.lh-row--group td {\n font-weight: bold;\n font-size: 1.05em;\n color: var(--table-group-header-text-color);\n}\n\n.lh-row--group td:first-child {\n font-weight: normal;\n}\n\n.lh-row--group .lh-text {\n color: inherit;\n text-decoration: none;\n display: inline-block;\n}\n\n.lh-row--group a.lh-link:hover {\n text-decoration: underline;\n}\n\n.lh-row--group .lh-audit__adorn {\n text-transform: capitalize;\n font-weight: normal;\n padding: 2px 3px 1px 3px;\n}\n\n.lh-row--group .lh-audit__adorn1p {\n color: var(--link-color);\n border-color: var(--link-color);\n}\n\n.lh-row--group .lh-report-icon--external::before {\n content: \"\";\n background-repeat: no-repeat;\n width: 14px;\n height: 16px;\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n\n.lh-row--group .lh-report-icon--external {\n display: none;\n}\n\n.lh-row--group:hover .lh-report-icon--external {\n display: inline-block;\n}\n\n.lh-dark .lh-report-icon--external::before {\n filter: invert(1);\n}\n\n/** Manages indentation of two-level and three-level nested adjacent rows */\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) td:first-child {\n padding-left: 20px;\n}\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) ~ .lh-sub-item-row td:first-child {\n padding-left: 40px;\n}\n\n.lh-row--even {\n background-color: var(--table-group-header-background-color);\n}\n.lh-row--hidden {\n display: none;\n}\n\n.lh-table th,\n.lh-table td {\n padding: var(--default-padding);\n}\n\n.lh-table tr {\n vertical-align: middle;\n}\n\n.lh-table tr:hover {\n background-color: var(--table-higlight-background-color);\n}\n\n/* Looks unnecessary, but mostly for keeping the s left-aligned */\n.lh-table-column--text,\n.lh-table-column--source-location,\n.lh-table-column--url,\n/* .lh-table-column--thumbnail, */\n/* .lh-table-column--empty,*/\n.lh-table-column--code,\n.lh-table-column--node {\n text-align: left;\n}\n\n.lh-table-column--code {\n min-width: 100px;\n}\n\n.lh-table-column--bytes,\n.lh-table-column--timespanMs,\n.lh-table-column--ms,\n.lh-table-column--numeric {\n text-align: right;\n word-break: normal;\n}\n\n\n\n.lh-table .lh-table-column--thumbnail {\n width: var(--image-preview-size);\n}\n\n.lh-table-column--url {\n min-width: 250px;\n}\n\n.lh-table-column--text {\n min-width: 80px;\n}\n\n/* Keep columns narrow if they follow the URL column */\n/* 12% was determined to be a decent narrow width, but wide enough for column headings */\n.lh-table-column--url + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--ms,\n.lh-table-column--url + .lh-table-column--ms + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--timespanMs {\n width: 12%;\n}\n\n.lh-text__url-host {\n display: inline;\n}\n\n.lh-text__url-host {\n margin-left: calc(var(--report-font-size) / 2);\n opacity: 0.6;\n font-size: 90%\n}\n\n.lh-thumbnail {\n object-fit: cover;\n width: var(--image-preview-size);\n height: var(--image-preview-size);\n display: block;\n}\n\n.lh-unknown pre {\n overflow: scroll;\n border: solid 1px var(--color-gray-200);\n}\n\n.lh-text__url > a {\n color: inherit;\n text-decoration: none;\n}\n\n.lh-text__url > a:hover {\n text-decoration: underline dotted #999;\n}\n\n.lh-sub-item-row {\n margin-left: 20px;\n margin-bottom: 0;\n color: var(--color-gray-700);\n}\n\n.lh-sub-item-row td {\n padding-top: 4px;\n padding-bottom: 4px;\n padding-left: 20px;\n}\n\n/* Chevron\n https://codepen.io/paulirish/pen/LmzEmK\n */\n.lh-chevron {\n --chevron-angle: 42deg;\n /* Edge doesn't support transform: rotate(calc(...)), so we define it here */\n --chevron-angle-right: -42deg;\n width: var(--chevron-size);\n height: var(--chevron-size);\n margin-top: calc((var(--report-line-height) - 12px) / 2);\n}\n\n.lh-chevron__lines {\n transition: transform 0.4s;\n transform: translateY(var(--report-line-height));\n}\n.lh-chevron__line {\n stroke: var(--chevron-line-stroke);\n stroke-width: var(--chevron-size);\n stroke-linecap: square;\n transform-origin: 50%;\n transform: rotate(var(--chevron-angle));\n transition: transform 300ms, stroke 300ms;\n}\n\n.lh-expandable-details .lh-chevron__line-right,\n.lh-expandable-details[open] .lh-chevron__line-left {\n transform: rotate(var(--chevron-angle-right));\n}\n\n.lh-expandable-details[open] .lh-chevron__line-right {\n transform: rotate(var(--chevron-angle));\n}\n\n\n.lh-expandable-details[open] .lh-chevron__lines {\n transform: translateY(calc(var(--chevron-size) * -1));\n}\n\n.lh-expandable-details[open] {\n animation: 300ms openDetails forwards;\n padding-bottom: var(--default-padding);\n}\n\n@keyframes openDetails {\n from {\n outline: 1px solid var(--report-background-color);\n }\n to {\n outline: 1px solid;\n box-shadow: 0 2px 4px rgba(0, 0, 0, .24);\n }\n}\n\n@media screen and (max-width: 780px) {\n /* no black outline if we're not confident the entire table can be displayed within bounds */\n .lh-expandable-details[open] {\n animation: none;\n }\n}\n\n.lh-expandable-details[open] summary, details.lh-clump > summary {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\ndetails.lh-clump[open] > summary {\n border-bottom-width: 0;\n}\n\n\n\ndetails .lh-clump-toggletext--hide,\ndetails[open] .lh-clump-toggletext--show { display: none; }\ndetails[open] .lh-clump-toggletext--hide { display: block;}\n\n\n/* Tooltip */\n.lh-tooltip-boundary {\n position: relative;\n}\n\n.lh-tooltip {\n position: absolute;\n display: none; /* Don't retain these layers when not needed */\n opacity: 0;\n background: #ffffff;\n white-space: pre-line; /* Render newlines in the text */\n min-width: 246px;\n max-width: 275px;\n padding: 15px;\n border-radius: 5px;\n text-align: initial;\n line-height: 1.4;\n}\n/* shrink tooltips to not be cutoff on left edge of narrow viewports\n 45vw is chosen to be ~= width of the left column of metrics\n*/\n@media screen and (max-width: 535px) {\n .lh-tooltip {\n min-width: 45vw;\n padding: 3vw;\n }\n}\n\n.lh-tooltip-boundary:hover .lh-tooltip {\n display: block;\n animation: fadeInTooltip 250ms;\n animation-fill-mode: forwards;\n animation-delay: 850ms;\n bottom: 100%;\n z-index: 1;\n will-change: opacity;\n right: 0;\n pointer-events: none;\n}\n\n.lh-tooltip::before {\n content: \"\";\n border: solid transparent;\n border-bottom-color: #fff;\n border-width: 10px;\n position: absolute;\n bottom: -20px;\n right: 6px;\n transform: rotate(180deg);\n pointer-events: none;\n}\n\n@keyframes fadeInTooltip {\n 0% { opacity: 0; }\n 75% { opacity: 1; }\n 100% { opacity: 1; filter: drop-shadow(1px 0px 1px #aaa) drop-shadow(0px 2px 4px hsla(206, 6%, 25%, 0.15)); pointer-events: auto; }\n}\n\n/* Element screenshot */\n.lh-element-screenshot {\n float: left;\n margin-right: 20px;\n}\n.lh-element-screenshot__content {\n overflow: hidden;\n min-width: 110px;\n display: flex;\n justify-content: center;\n background-color: var(--report-background-color);\n}\n.lh-element-screenshot__image {\n position: relative;\n /* Set by ElementScreenshotRenderer.installFullPageScreenshotCssVariable */\n background-image: var(--element-screenshot-url);\n outline: 2px solid #777;\n background-color: white;\n background-repeat: no-repeat;\n}\n.lh-element-screenshot__mask {\n position: absolute;\n background: #555;\n opacity: 0.8;\n}\n.lh-element-screenshot__element-marker {\n position: absolute;\n outline: 2px solid var(--color-lime-400);\n}\n.lh-element-screenshot__overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 2000; /* .lh-topbar is 1000 */\n background: var(--screenshot-overlay-background);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: zoom-out;\n}\n\n.lh-element-screenshot__overlay .lh-element-screenshot {\n margin-right: 0; /* clearing margin used in thumbnail case */\n outline: 1px solid var(--color-gray-700);\n}\n\n.lh-screenshot-overlay--enabled .lh-element-screenshot {\n cursor: zoom-out;\n}\n.lh-screenshot-overlay--enabled .lh-node .lh-element-screenshot {\n cursor: zoom-in;\n}\n\n\n.lh-meta__items {\n --meta-icon-size: calc(var(--report-icon-size) * 0.667);\n padding: var(--default-padding);\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n background-color: var(--env-item-background-color);\n border-radius: 3px;\n margin: 0 0 var(--default-padding) 0;\n font-size: 12px;\n column-gap: var(--default-padding);\n color: var(--color-gray-700);\n}\n\n.lh-meta__item {\n display: block;\n list-style-type: none;\n position: relative;\n padding: 0 0 0 calc(var(--meta-icon-size) + var(--default-padding) * 2);\n cursor: unset; /* disable pointer cursor from report-icon */\n}\n\n.lh-meta__item.lh-tooltip-boundary {\n text-decoration: dotted underline var(--color-gray-500);\n cursor: help;\n}\n\n.lh-meta__item.lh-report-icon::before {\n position: absolute;\n left: var(--default-padding);\n width: var(--meta-icon-size);\n height: var(--meta-icon-size);\n}\n\n.lh-meta__item.lh-report-icon:hover::before {\n opacity: 0.7;\n}\n\n.lh-meta__item .lh-tooltip {\n color: var(--color-gray-800);\n}\n\n.lh-meta__item .lh-tooltip::before {\n right: auto; /* Set the tooltip arrow to the leftside */\n left: 6px;\n}\n\n/* Change the grid for narrow viewport. */\n@media screen and (max-width: 640px) {\n .lh-meta__items {\n grid-template-columns: 1fr 1fr;\n }\n}\n@media screen and (max-width: 535px) {\n .lh-meta__items {\n display: block;\n }\n}\n\n\n/*# sourceURL=report-styles.css */\n"); + el1.append("/**\n * @license\n * Copyright 2017 Google LLC\n * SPDX-License-Identifier: Apache-2.0\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 --report-icon-size: var(--score-icon-background-size);\n --report-line-height: 24px;\n --report-line-height-secondary: 20px;\n --report-monospace-font-size: calc(var(--report-font-size) * 0.85);\n --report-text-color-secondary: var(--color-gray-800);\n --report-text-color: var(--color-gray-900);\n --report-content-max-width: calc(60 * var(--report-font-size)); /* defaults to 840px */\n --report-content-min-width: 360px;\n --report-content-max-width-minus-edge-gap: calc(var(--report-content-max-width) - var(--edge-gap-padding) * 2);\n --score-container-padding: 8px;\n --score-icon-background-size: 24px;\n --score-icon-margin-left: 6px;\n --score-icon-margin-right: 14px;\n --score-icon-margin: 0 var(--score-icon-margin-right) 0 var(--score-icon-margin-left);\n --score-icon-size: 12px;\n --score-icon-size-big: 16px;\n --screenshot-overlay-background: rgba(0, 0, 0, 0.3);\n --section-padding-vertical: calc(var(--default-padding) * 6);\n --snippet-background-color: var(--color-gray-50);\n --snippet-color: #0938C2;\n --sparkline-height: 5px;\n --stackpack-padding-horizontal: 10px;\n --sticky-header-background-color: var(--report-background-color);\n --sticky-header-buffer: calc(var(--topbar-height) + var(--sticky-header-height));\n --sticky-header-height: calc(var(--gauge-circle-size-sm) + var(--score-container-padding) * 2);\n --table-group-header-background-color: #EEF1F4;\n --table-group-header-text-color: var(--color-gray-700);\n --table-higlight-background-color: #F5F7FA;\n --tools-icon-color: var(--color-gray-600);\n --topbar-background-color: var(--color-white);\n --topbar-height: 32px;\n --topbar-logo-size: 24px;\n --topbar-padding: 0 8px;\n --toplevel-warning-background-color: hsla(30, 100%, 75%, 10%);\n --toplevel-warning-message-text-color: var(--color-average-secondary);\n --toplevel-warning-padding: 18px;\n --toplevel-warning-text-color: var(--report-text-color);\n\n /* SVGs */\n --plugin-icon-url-dark: url('data:image/svg+xml;utf8,');\n --plugin-icon-url: url('data:image/svg+xml;utf8,');\n\n --pass-icon-url: url('data:image/svg+xml;utf8,check');\n --average-icon-url: url('data:image/svg+xml;utf8,info');\n --fail-icon-url: url('data:image/svg+xml;utf8,warn');\n --error-icon-url: url('data:image/svg+xml;utf8,error');\n\n --pwa-installable-gray-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-gray-url-dark: url('data:image/svg+xml;utf8,');\n --pwa-optimized-gray-url-dark: url('data:image/svg+xml;utf8,');\n\n --pwa-installable-color-url: url('data:image/svg+xml;utf8,');\n --pwa-optimized-color-url: url('data:image/svg+xml;utf8,');\n\n --swap-locale-icon-url: url('data:image/svg+xml;utf8,');\n}\n\n@media not print {\n .lh-dark {\n /* Pallete */\n --color-gray-200: var(--color-gray-800);\n --color-gray-300: #616161;\n --color-gray-400: var(--color-gray-600);\n --color-gray-700: var(--color-gray-400);\n --color-gray-50: #757575;\n --color-gray-600: var(--color-gray-500);\n --color-green-700: var(--color-green);\n --color-orange-700: var(--color-orange);\n --color-red-700: var(--color-red);\n --color-teal-600: var(--color-cyan-500);\n\n /* Context-specific colors */\n --color-hover: rgba(0, 0, 0, 0.2);\n --color-informative: var(--color-blue-200);\n\n /* Component variables */\n --env-item-background-color: #393535;\n --link-color: var(--color-blue-200);\n --locale-selector-background-color: var(--color-gray-200);\n --plugin-badge-background-color: var(--color-gray-800);\n --report-background-color: var(--color-gray-900);\n --report-border-color-secondary: var(--color-gray-200);\n --report-text-color-secondary: var(--color-gray-400);\n --report-text-color: var(--color-gray-100);\n --snippet-color: var(--color-cyan-500);\n --topbar-background-color: var(--color-gray);\n --toplevel-warning-background-color: hsl(33deg 14% 18%);\n --toplevel-warning-message-text-color: var(--color-orange-700);\n --toplevel-warning-text-color: var(--color-gray-100);\n --table-group-header-background-color: rgba(186, 196, 206, 0.15);\n --table-group-header-text-color: var(--color-gray-100);\n --table-higlight-background-color: rgba(186, 196, 206, 0.09);\n\n /* SVGs */\n --plugin-icon-url: var(--plugin-icon-url-dark);\n --pwa-installable-gray-url: var(--pwa-installable-gray-url-dark);\n --pwa-optimized-gray-url: var(--pwa-optimized-gray-url-dark);\n }\n}\n\n@media only screen and (max-width: 480px) {\n .lh-vars {\n --audit-group-margin-bottom: 20px;\n --edge-gap-padding: var(--default-padding);\n --env-name-min-width: 120px;\n --gauge-circle-size-big: 96px;\n --gauge-circle-size: 72px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 112px;\n --header-padding: 16px 0 16px 0;\n --image-preview-size: 24px;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-size: 14px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --topbar-height: 28px;\n --topbar-logo-size: 20px;\n }\n\n /* Not enough space to adequately show the relative savings bars. */\n .lh-sparkline {\n display: none;\n }\n}\n\n.lh-vars.lh-devtools {\n --audit-explanation-line-height: 14px;\n --audit-group-margin-bottom: 20px;\n --audit-group-padding-vertical: 12px;\n --audit-padding-vertical: 4px;\n --category-padding: 12px;\n --default-padding: 12px;\n --env-name-min-width: 120px;\n --footer-padding-vertical: 8px;\n --gauge-circle-size-big: 72px;\n --gauge-circle-size: 64px;\n --gauge-label-font-size-big: 22px;\n --gauge-label-font-size: 14px;\n --gauge-label-line-height-big: 26px;\n --gauge-label-line-height: 20px;\n --gauge-percentage-font-size-big: 34px;\n --gauge-percentage-font-size: 26px;\n --gauge-wrapper-width: 97px;\n --header-line-height: 20px;\n --header-padding: 16px 0 16px 0;\n --screenshot-overlay-background: transparent;\n --plugin-icon-size: 75%;\n --pwa-icon-margin: 0 7px 0 -3px;\n --report-font-family-monospace: 'Menlo', 'dejavu sans mono', 'Consolas', 'Lucida Console', monospace;\n --report-font-family: '.SFNSDisplay-Regular', 'Helvetica Neue', 'Lucida Grande', sans-serif;\n --report-font-size: 12px;\n --report-line-height: 20px;\n --score-icon-margin-left: 2px;\n --score-icon-size: 10px;\n --section-padding-vertical: 8px;\n}\n\n.lh-container:not(.lh-topbar + .lh-container) {\n --topbar-height: 0;\n --sticky-header-height: 0;\n --sticky-header-buffer: 0;\n}\n\n.lh-devtools.lh-root {\n height: 100%;\n}\n.lh-devtools.lh-root img {\n /* Override devtools default 'min-width: 0' so svg without size in a flexbox isn't collapsed. */\n min-width: auto;\n}\n.lh-devtools .lh-container {\n overflow-y: scroll;\n height: calc(100% - var(--topbar-height));\n /** The .lh-container is the scroll parent in DevTools so we exclude the topbar from the sticky header buffer. */\n --sticky-header-buffer: calc(var(--sticky-header-height));\n}\n@media print {\n .lh-devtools .lh-container {\n overflow: unset;\n }\n}\n.lh-devtools .lh-sticky-header {\n /* This is normally the height of the topbar, but we want it to stick to the top of our scroll container .lh-container` */\n top: 0;\n}\n.lh-devtools .lh-element-screenshot__overlay {\n position: absolute;\n}\n\n@keyframes fadeIn {\n 0% { opacity: 0;}\n 100% { opacity: 0.6;}\n}\n\n.lh-root *, .lh-root *::before, .lh-root *::after {\n box-sizing: border-box;\n}\n\n.lh-root {\n font-family: var(--report-font-family);\n font-size: var(--report-font-size);\n margin: 0;\n line-height: var(--report-line-height);\n background: var(--report-background-color);\n color: var(--report-text-color);\n}\n\n.lh-root :focus-visible {\n outline: -webkit-focus-ring-color auto 3px;\n}\n.lh-root summary:focus {\n outline: none;\n box-shadow: 0 0 0 1px hsl(217, 89%, 61%);\n}\n\n.lh-root [hidden] {\n display: none !important;\n}\n\n.lh-root pre {\n margin: 0;\n}\n\n.lh-root pre,\n.lh-root code {\n font-family: var(--report-font-family-monospace);\n}\n\n.lh-root details > summary {\n cursor: pointer;\n}\n\n.lh-hidden {\n display: none !important;\n}\n\n.lh-container {\n /*\n Text wrapping in the report is so much FUN!\n We have a `word-break: break-word;` globally here to prevent a few common scenarios, namely\n long non-breakable text (usually URLs) found in:\n 1. The footer\n 2. .lh-node (outerHTML)\n 3. .lh-code\n\n With that sorted, the next challenge is appropriate column sizing and text wrapping inside our\n .lh-details tables. Even more fun.\n * We don't want table headers (\"Potential Savings (ms)\") to wrap or their column values, but\n we'd be happy for the URL column to wrap if the URLs are particularly long.\n * We want the narrow columns to remain narrow, providing the most column width for URL\n * We don't want the table to extend past 100% width.\n * Long URLs in the URL column can wrap. Util.getURLDisplayName maxes them out at 64 characters,\n but they do not get any overflow:ellipsis treatment.\n */\n word-break: break-word;\n}\n\n.lh-audit-group a,\n.lh-category-header__description a,\n.lh-audit__description a,\n.lh-warnings a,\n.lh-footer a,\n.lh-table-column--link a {\n color: var(--link-color);\n}\n\n.lh-audit__description, .lh-audit__stackpack {\n --inner-audit-padding-right: var(--stackpack-padding-horizontal);\n padding-left: var(--audit-description-padding-left);\n padding-right: var(--inner-audit-padding-right);\n padding-top: 8px;\n padding-bottom: 8px;\n}\n\n.lh-details {\n margin-top: var(--default-padding);\n margin-bottom: var(--default-padding);\n margin-left: var(--audit-description-padding-left);\n /* whatever the .lh-details side margins are */\n width: 100%;\n}\n\n.lh-audit__stackpack {\n display: flex;\n align-items: center;\n}\n\n.lh-audit__stackpack__img {\n max-width: 30px;\n margin-right: var(--default-padding)\n}\n\n/* Report header */\n\n.lh-report-icon {\n display: flex;\n align-items: center;\n padding: 10px 12px;\n cursor: pointer;\n}\n.lh-report-icon[disabled] {\n opacity: 0.3;\n pointer-events: none;\n}\n\n.lh-report-icon::before {\n content: \"\";\n margin: 4px;\n background-repeat: no-repeat;\n width: var(--report-icon-size);\n height: var(--report-icon-size);\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n.lh-report-icon:hover::before {\n opacity: 1;\n}\n.lh-dark .lh-report-icon::before {\n filter: invert(1);\n}\n.lh-report-icon--print::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--copy::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--open::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--download::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--dark::before {\n background-image:url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--treemap::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--date::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--devices::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--world::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--stopwatch::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--networkspeed::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-one::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--samples-many::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--chrome::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n.lh-report-icon--external::before {\n background-image: url('data:image/svg+xml;utf8,');\n}\n\n.lh-buttons {\n display: flex;\n flex-wrap: wrap;\n margin: var(--default-padding) 0;\n}\n.lh-button {\n height: 32px;\n border: 1px solid var(--report-border-color-secondary);\n border-radius: 3px;\n color: var(--link-color);\n background-color: var(--report-background-color);\n margin: 5px;\n}\n\n.lh-button:first-of-type {\n margin-left: 0;\n}\n\n/* Node */\n.lh-node__snippet {\n font-family: var(--report-font-family-monospace);\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n line-height: 20px;\n}\n\n/* Score */\n\n.lh-audit__score-icon {\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n margin: var(--score-icon-margin);\n}\n\n.lh-audit--pass .lh-audit__display-text {\n color: var(--color-pass-secondary);\n}\n.lh-audit--pass .lh-audit__score-icon,\n.lh-scorescale-range--pass::before {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-audit__display-text {\n color: var(--color-average-secondary);\n}\n.lh-audit--average .lh-audit__score-icon,\n.lh-scorescale-range--average::before {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-audit--fail .lh-audit__display-text {\n color: var(--color-fail-secondary);\n}\n.lh-audit--fail .lh-audit__score-icon,\n.lh-audit--error .lh-audit__score-icon,\n.lh-scorescale-range--fail::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-audit--error .lh-audit__score-icon,\n.lh-metric--error .lh-metric__icon {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n border: none;\n}\n\n.lh-gauge__wrapper--fail .lh-gauge--error {\n background-image: var(--error-icon-url);\n background-repeat: no-repeat;\n background-position: center;\n transform: scale(0.5);\n top: var(--score-container-padding);\n}\n\n.lh-audit--manual .lh-audit__display-text,\n.lh-audit--notapplicable .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n.lh-audit--manual .lh-audit__score-icon,\n.lh-audit--notapplicable .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n background: none;\n}\n\n.lh-audit--informative .lh-audit__display-text {\n color: var(--color-gray-600);\n}\n\n.lh-audit--informative .lh-audit__score-icon {\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-400);\n border-radius: 100%;\n}\n\n.lh-audit__description,\n.lh-audit__stackpack {\n color: var(--report-text-color-secondary);\n}\n.lh-audit__adorn {\n border: 1px solid var(--color-gray-500);\n border-radius: 3px;\n margin: 0 3px;\n padding: 0 2px;\n line-height: 1.1;\n display: inline-block;\n font-size: 90%;\n color: var(--report-text-color-secondary);\n}\n\n.lh-category-header__description {\n text-align: center;\n color: var(--color-gray-700);\n margin: 0px auto;\n max-width: 400px;\n}\n\n\n.lh-audit__display-text,\n.lh-chevron-container {\n margin: 0 var(--audit-margin-horizontal);\n}\n.lh-chevron-container {\n margin-right: 0;\n}\n\n.lh-audit__title-and-text {\n flex: 1;\n}\n\n.lh-audit__title-and-text code {\n color: var(--snippet-color);\n font-size: var(--report-monospace-font-size);\n}\n\n/* Prepend display text with em dash separator. */\n.lh-audit__display-text:not(:empty):before {\n content: '—';\n margin-right: var(--audit-margin-horizontal);\n}\n\n/* Expandable Details (Audit Groups, Audits) */\n.lh-audit__header {\n display: flex;\n align-items: center;\n padding: var(--default-padding);\n}\n\n\n.lh-metricfilter {\n display: grid;\n justify-content: end;\n align-items: center;\n grid-auto-flow: column;\n gap: 4px;\n color: var(--color-gray-700);\n}\n\n.lh-metricfilter__radio {\n /*\n * Instead of hiding, position offscreen so it's still accessible to screen readers\n * https://bugs.chromium.org/p/chromium/issues/detail?id=1439785\n */\n position: fixed;\n left: -9999px;\n}\n.lh-metricfilter input[type='radio']:focus-visible + label {\n outline: -webkit-focus-ring-color auto 1px;\n}\n\n.lh-metricfilter__label {\n display: inline-flex;\n padding: 0 4px;\n height: 16px;\n text-decoration: underline;\n align-items: center;\n cursor: pointer;\n font-size: 90%;\n}\n\n.lh-metricfilter__label--active {\n background: var(--color-blue-primary);\n color: var(--color-white);\n border-radius: 3px;\n text-decoration: none;\n}\n/* Give the 'All' choice a more muted display */\n.lh-metricfilter__label--active[for=\"metric-All\"] {\n background-color: var(--color-blue-200) !important;\n color: black !important;\n}\n\n.lh-metricfilter__text {\n margin-right: 8px;\n}\n\n/* If audits are filtered, hide the itemcount for Passed Audits… */\n.lh-category--filtered .lh-audit-group .lh-audit-group__itemcount {\n display: none;\n}\n\n\n.lh-audit__header:hover {\n background-color: var(--color-hover);\n}\n\n/* We want to hide the browser's default arrow marker on summary elements. Admittedly, it's complicated. */\n.lh-root details > summary {\n /* Blink 89+ and Firefox will hide the arrow when display is changed from (new) default of `list-item` to block. https://chromestatus.com/feature/6730096436051968*/\n display: block;\n}\n/* Safari and Blink <=88 require using the -webkit-details-marker selector */\n.lh-root details > summary::-webkit-details-marker {\n display: none;\n}\n\n/* Perf Metric */\n\n.lh-metrics-container {\n display: grid;\n grid-auto-rows: 1fr;\n grid-template-columns: 1fr 1fr;\n grid-column-gap: var(--report-line-height);\n margin-bottom: var(--default-padding);\n}\n\n.lh-metric {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(-n+2) {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-metric__innerwrap {\n display: grid;\n /**\n * Icon -- Metric Name\n * -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 1fr;\n align-items: center;\n padding: var(--default-padding);\n}\n\n.lh-metric__details {\n order: -1;\n}\n\n.lh-metric__title {\n flex: 1;\n}\n\n.lh-calclink {\n padding-left: calc(1ex / 3);\n}\n\n.lh-metric__description {\n display: none;\n grid-column-start: 2;\n grid-column-end: 4;\n color: var(--report-text-color-secondary);\n}\n\n.lh-metric__value {\n font-size: var(--metric-value-font-size);\n margin: calc(var(--default-padding) / 2) 0;\n white-space: nowrap; /* No wrapping between metric value and the icon */\n grid-column-start: 2;\n}\n\n\n@media screen and (max-width: 535px) {\n .lh-metrics-container {\n display: block;\n }\n\n .lh-metric {\n border-bottom: none !important;\n }\n .lh-category:not(.lh--hoisted-meta) .lh-metric:nth-last-child(1) {\n border-bottom: 1px solid var(--report-border-color-secondary) !important;\n }\n\n /* Change the grid to 3 columns for narrow viewport. */\n .lh-metric__innerwrap {\n /**\n * Icon -- Metric Name -- Metric Value\n */\n grid-template-columns: calc(var(--score-icon-size) + var(--score-icon-margin-left) + var(--score-icon-margin-right)) 2fr 1fr;\n }\n .lh-metric__value {\n justify-self: end;\n grid-column-start: unset;\n }\n}\n\n/* No-JS toggle switch */\n/* Keep this selector sync'd w/ `magicSelector` in report-ui-features-test.js */\n .lh-metrics-toggle__input:checked ~ .lh-metrics-container .lh-metric__description {\n display: block;\n}\n\n/* TODO get rid of the SVGS and clean up these some more */\n.lh-metrics-toggle__input {\n opacity: 0;\n position: absolute;\n right: 0;\n top: 0px;\n}\n\n.lh-metrics-toggle__input + div > label > .lh-metrics-toggle__labeltext--hide,\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--show {\n display: none;\n}\n.lh-metrics-toggle__input:checked + div > label > .lh-metrics-toggle__labeltext--hide {\n display: inline;\n}\n.lh-metrics-toggle__input:focus + div > label {\n outline: -webkit-focus-ring-color auto 3px;\n}\n\n.lh-metrics-toggle__label {\n cursor: pointer;\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n/* Pushes the metric description toggle button to the right. */\n.lh-audit-group--metrics .lh-audit-group__header {\n display: flex;\n justify-content: space-between;\n}\n\n.lh-metric__icon,\n.lh-scorescale-range::before {\n content: '';\n width: var(--score-icon-size);\n height: var(--score-icon-size);\n display: inline-block;\n margin: var(--score-icon-margin);\n}\n\n.lh-metric--pass .lh-metric__value {\n color: var(--color-pass-secondary);\n}\n.lh-metric--pass .lh-metric__icon {\n border-radius: 100%;\n background: var(--color-pass);\n}\n\n.lh-metric--average .lh-metric__value {\n color: var(--color-average-secondary);\n}\n.lh-metric--average .lh-metric__icon {\n background: var(--color-average);\n width: var(--icon-square-size);\n height: var(--icon-square-size);\n}\n\n.lh-metric--fail .lh-metric__value {\n color: var(--color-fail-secondary);\n}\n.lh-metric--fail .lh-metric__icon {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n\n.lh-metric--error .lh-metric__value,\n.lh-metric--error .lh-metric__description {\n color: var(--color-fail-secondary);\n}\n\n/* Sparkline */\n\n.lh-sparkline {\n height: var(--sparkline-height);\n width: 100%;\n}\n\n.lh-sparkline__bar {\n height: 100%;\n float: right;\n}\n\n.lh-audit--pass .lh-sparkline__bar {\n background: var(--color-pass);\n}\n\n.lh-audit--average .lh-sparkline__bar {\n background: var(--color-average);\n}\n\n.lh-audit--fail .lh-sparkline__bar {\n background: var(--color-fail);\n}\n\n/* Filmstrip */\n\n.lh-filmstrip-container {\n /* smaller gap between metrics and filmstrip */\n margin: -8px auto 0 auto;\n}\n\n.lh-filmstrip {\n display: grid;\n justify-content: space-between;\n padding-bottom: var(--default-padding);\n width: 100%;\n grid-template-columns: repeat(auto-fit, 90px);\n}\n\n.lh-filmstrip__frame {\n text-align: right;\n position: relative;\n}\n\n.lh-filmstrip__thumbnail {\n border: 1px solid var(--report-border-color-secondary);\n max-height: 150px;\n max-width: 120px;\n}\n\n/* Audit */\n\n.lh-audit {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\n\n/* Apply border-top to just the first audit. */\n.lh-audit {\n border-top: 1px solid var(--report-border-color-secondary);\n}\n.lh-audit ~ .lh-audit {\n border-top: none;\n}\n\n\n.lh-audit--error .lh-audit__display-text {\n color: var(--color-fail-secondary);\n}\n\n/* Audit Group */\n\n.lh-audit-group {\n margin-bottom: var(--audit-group-margin-bottom);\n position: relative;\n}\n.lh-audit-group--metrics {\n margin-bottom: calc(var(--audit-group-margin-bottom) / 2);\n}\n\n.lh-audit-group__header::before {\n /* By default, groups don't get an icon */\n content: none;\n width: var(--pwa-icon-size);\n height: var(--pwa-icon-size);\n margin: var(--pwa-icon-margin);\n display: inline-block;\n vertical-align: middle;\n}\n\n/* Style the \"over budget\" columns red. */\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(4),\n.lh-audit-group--budgets #performance-budget tbody tr td:nth-child(5),\n.lh-audit-group--budgets #timing-budget tbody tr td:nth-child(3) {\n color: var(--color-red-700);\n}\n\n/* Align the \"over budget request count\" text to be close to the \"over budget bytes\" column. */\n.lh-audit-group--budgets .lh-table tbody tr td:nth-child(4){\n text-align: right;\n}\n\n.lh-audit-group--budgets .lh-details--budget {\n width: 100%;\n margin: 0 0 var(--default-padding);\n}\n\n.lh-audit-group--pwa-installable .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-installable-gray-url);\n}\n.lh-audit-group--pwa-optimized .lh-audit-group__header::before {\n content: '';\n background-image: var(--pwa-optimized-gray-url);\n}\n.lh-audit-group--pwa-installable.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-installable-color-url);\n}\n.lh-audit-group--pwa-optimized.lh-badged .lh-audit-group__header::before {\n background-image: var(--pwa-optimized-color-url);\n}\n\n.lh-audit-group--metrics .lh-audit-group__summary {\n margin-top: 0;\n margin-bottom: 0;\n}\n\n.lh-audit-group__summary {\n display: flex;\n justify-content: space-between;\n align-items: center;\n}\n\n.lh-audit-group__header .lh-chevron {\n margin-top: calc((var(--report-line-height) - 5px) / 2);\n}\n\n.lh-audit-group__header {\n letter-spacing: 0.8px;\n padding: var(--default-padding);\n padding-left: 0;\n}\n\n.lh-audit-group__header, .lh-audit-group__summary {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n color: var(--color-gray-700);\n}\n\n.lh-audit-group__title {\n text-transform: uppercase;\n font-weight: 500;\n}\n\n.lh-audit-group__itemcount {\n color: var(--color-gray-600);\n}\n\n.lh-audit-group__footer {\n color: var(--color-gray-600);\n display: block;\n margin-top: var(--default-padding);\n}\n\n.lh-details,\n.lh-category-header__description,\n.lh-audit-group__footer {\n font-size: var(--report-font-size-secondary);\n line-height: var(--report-line-height-secondary);\n}\n\n.lh-audit-explanation {\n margin: var(--audit-padding-vertical) 0 calc(var(--audit-padding-vertical) / 2) var(--audit-margin-horizontal);\n line-height: var(--audit-explanation-line-height);\n display: inline-block;\n}\n\n.lh-audit--fail .lh-audit-explanation {\n color: var(--color-fail-secondary);\n}\n\n/* Report */\n.lh-list > :not(:last-child) {\n margin-bottom: calc(var(--default-padding) * 2);\n}\n\n.lh-header-container {\n display: block;\n margin: 0 auto;\n position: relative;\n word-wrap: break-word;\n}\n\n.lh-header-container .lh-scores-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n\n\n.lh-report {\n min-width: var(--report-content-min-width);\n}\n\n.lh-exception {\n font-size: large;\n}\n\n.lh-code {\n white-space: normal;\n margin-top: 0;\n font-size: var(--report-monospace-font-size);\n}\n\n.lh-warnings {\n --item-margin: calc(var(--report-line-height) / 6);\n color: var(--color-average-secondary);\n margin: var(--audit-padding-vertical) 0;\n padding: var(--default-padding)\n var(--default-padding)\n var(--default-padding)\n calc(var(--audit-description-padding-left));\n background-color: var(--toplevel-warning-background-color);\n}\n.lh-warnings span {\n font-weight: bold;\n}\n\n.lh-warnings--toplevel {\n --item-margin: calc(var(--header-line-height) / 4);\n color: var(--toplevel-warning-text-color);\n margin-left: auto;\n margin-right: auto;\n max-width: var(--report-content-max-width-minus-edge-gap);\n padding: var(--toplevel-warning-padding);\n border-radius: 8px;\n}\n\n.lh-warnings__msg {\n color: var(--toplevel-warning-message-text-color);\n margin: 0;\n}\n\n.lh-warnings ul {\n margin: 0;\n}\n.lh-warnings li {\n margin: var(--item-margin) 0;\n}\n.lh-warnings li:last-of-type {\n margin-bottom: 0;\n}\n\n.lh-scores-header {\n display: flex;\n flex-wrap: wrap;\n justify-content: center;\n}\n.lh-scores-header__solo {\n padding: 0;\n border: 0;\n}\n\n/* Gauge */\n\n.lh-gauge__wrapper--pass {\n color: var(--color-pass-secondary);\n fill: var(--color-pass);\n stroke: var(--color-pass);\n}\n\n.lh-gauge__wrapper--average {\n color: var(--color-average-secondary);\n fill: var(--color-average);\n stroke: var(--color-average);\n}\n\n.lh-gauge__wrapper--fail {\n color: var(--color-fail-secondary);\n fill: var(--color-fail);\n stroke: var(--color-fail);\n}\n\n.lh-gauge__wrapper--not-applicable {\n color: var(--color-not-applicable);\n fill: var(--color-not-applicable);\n stroke: var(--color-not-applicable);\n}\n\n.lh-fraction__wrapper .lh-fraction__content::before {\n content: '';\n height: var(--score-icon-size);\n width: var(--score-icon-size);\n margin: var(--score-icon-margin);\n display: inline-block;\n}\n.lh-fraction__wrapper--pass .lh-fraction__content {\n color: var(--color-pass-secondary);\n}\n.lh-fraction__wrapper--pass .lh-fraction__background {\n background-color: var(--color-pass);\n}\n.lh-fraction__wrapper--pass .lh-fraction__content::before {\n background-color: var(--color-pass);\n border-radius: 50%;\n}\n.lh-fraction__wrapper--average .lh-fraction__content {\n color: var(--color-average-secondary);\n}\n.lh-fraction__wrapper--average .lh-fraction__background,\n.lh-fraction__wrapper--average .lh-fraction__content::before {\n background-color: var(--color-average);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content {\n color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__background {\n background-color: var(--color-fail);\n}\n.lh-fraction__wrapper--fail .lh-fraction__content::before {\n border-left: calc(var(--score-icon-size) / 2) solid transparent;\n border-right: calc(var(--score-icon-size) / 2) solid transparent;\n border-bottom: var(--score-icon-size) solid var(--color-fail);\n}\n.lh-fraction__wrapper--null .lh-fraction__content {\n color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__background {\n background-color: var(--color-gray-700);\n}\n.lh-fraction__wrapper--null .lh-fraction__content::before {\n border-radius: 50%;\n border: calc(0.2 * var(--score-icon-size)) solid var(--color-gray-700);\n}\n\n.lh-fraction__background {\n position: absolute;\n height: 100%;\n width: 100%;\n border-radius: calc(var(--gauge-circle-size) / 2);\n opacity: 0.1;\n z-index: -1;\n}\n\n.lh-fraction__content-wrapper {\n height: var(--gauge-circle-size);\n display: flex;\n align-items: center;\n}\n\n.lh-fraction__content {\n display: flex;\n position: relative;\n align-items: center;\n justify-content: center;\n font-size: calc(0.3 * var(--gauge-circle-size));\n line-height: calc(0.4 * var(--gauge-circle-size));\n width: max-content;\n min-width: calc(1.5 * var(--gauge-circle-size));\n padding: calc(0.1 * var(--gauge-circle-size)) calc(0.2 * var(--gauge-circle-size));\n --score-icon-size: calc(0.21 * var(--gauge-circle-size));\n --score-icon-margin: 0 calc(0.15 * var(--gauge-circle-size)) 0 0;\n}\n\n.lh-gauge {\n stroke-linecap: round;\n width: var(--gauge-circle-size);\n height: var(--gauge-circle-size);\n}\n\n.lh-category .lh-gauge {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n.lh-gauge-base {\n opacity: 0.1;\n}\n\n.lh-gauge-arc {\n fill: none;\n transform-origin: 50% 50%;\n animation: load-gauge var(--transition-length) ease both;\n animation-delay: 250ms;\n}\n\n.lh-gauge__svg-wrapper {\n position: relative;\n height: var(--gauge-circle-size);\n}\n.lh-category .lh-gauge__svg-wrapper,\n.lh-category .lh-fraction__wrapper {\n --gauge-circle-size: var(--gauge-circle-size-big);\n}\n\n/* The plugin badge overlay */\n.lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size);\n height: var(--plugin-badge-size);\n background-color: var(--plugin-badge-background-color);\n background-image: var(--plugin-icon-url);\n background-repeat: no-repeat;\n background-size: var(--plugin-icon-size);\n background-position: 58% 50%;\n content: \"\";\n position: absolute;\n right: -6px;\n bottom: 0px;\n display: block;\n z-index: 100;\n box-shadow: 0 0 4px rgba(0,0,0,.2);\n border-radius: 25%;\n}\n.lh-category .lh-gauge__wrapper--plugin .lh-gauge__svg-wrapper::before {\n width: var(--plugin-badge-size-big);\n height: var(--plugin-badge-size-big);\n}\n\n@keyframes load-gauge {\n from { stroke-dasharray: 0 352; }\n}\n\n.lh-gauge__percentage {\n width: 100%;\n height: var(--gauge-circle-size);\n line-height: var(--gauge-circle-size);\n position: absolute;\n font-family: var(--report-font-family-monospace);\n font-size: calc(var(--gauge-circle-size) * 0.34 + 1.3px);\n text-align: center;\n top: var(--score-container-padding);\n}\n\n.lh-category .lh-gauge__percentage {\n --gauge-circle-size: var(--gauge-circle-size-big);\n --gauge-percentage-font-size: var(--gauge-percentage-font-size-big);\n}\n\n.lh-gauge__wrapper,\n.lh-fraction__wrapper {\n position: relative;\n display: flex;\n align-items: center;\n flex-direction: column;\n text-decoration: none;\n padding: var(--score-container-padding);\n\n --transition-length: 1s;\n\n /* Contain the layout style paint & layers during animation*/\n contain: content;\n will-change: opacity; /* Only using for layer promotion */\n}\n\n.lh-gauge__label,\n.lh-fraction__label {\n font-size: var(--gauge-label-font-size);\n font-weight: 500;\n line-height: var(--gauge-label-line-height);\n margin-top: 10px;\n text-align: center;\n color: var(--report-text-color);\n word-break: keep-all;\n}\n\n/* TODO(#8185) use more BEM (.lh-gauge__label--big) instead of relying on descendant selector */\n.lh-category .lh-gauge__label,\n.lh-category .lh-fraction__label {\n --gauge-label-font-size: var(--gauge-label-font-size-big);\n --gauge-label-line-height: var(--gauge-label-line-height-big);\n margin-top: 14px;\n}\n\n.lh-scores-header .lh-gauge__wrapper,\n.lh-scores-header .lh-fraction__wrapper,\n.lh-scores-header .lh-gauge--pwa__wrapper,\n.lh-sticky-header .lh-gauge__wrapper,\n.lh-sticky-header .lh-fraction__wrapper,\n.lh-sticky-header .lh-gauge--pwa__wrapper {\n width: var(--gauge-wrapper-width);\n}\n\n.lh-scorescale {\n display: inline-flex;\n\n gap: calc(var(--default-padding) * 4);\n margin: 16px auto 0 auto;\n font-size: var(--report-font-size-secondary);\n color: var(--color-gray-700);\n\n}\n\n.lh-scorescale-range {\n display: flex;\n align-items: center;\n font-family: var(--report-font-family-monospace);\n white-space: nowrap;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale {\n border: 0;\n display: flex;\n justify-content: center;\n}\n\n.lh-category-header__finalscreenshot .lh-scorescale-range {\n font-family: unset;\n font-size: 12px;\n}\n\n.lh-scorescale-wrap {\n display: contents;\n}\n\n/* Hide category score gauages if it's a single category report */\n.lh-header--solo-category .lh-scores-wrapper {\n display: none;\n}\n\n\n.lh-categories {\n width: 100%;\n}\n\n.lh-category {\n padding: var(--category-padding);\n max-width: var(--report-content-max-width);\n margin: 0 auto;\n\n scroll-margin-top: var(--sticky-header-buffer);\n}\n\n.lh-category-wrapper {\n border-bottom: 1px solid var(--color-gray-200);\n}\n.lh-category-wrapper:last-of-type {\n border-bottom: 0;\n}\n\n.lh-category-header {\n margin-bottom: var(--section-padding-vertical);\n}\n\n.lh-category-header .lh-score__gauge {\n max-width: 400px;\n width: auto;\n margin: 0px auto;\n}\n\n.lh-category-header__finalscreenshot {\n display: grid;\n grid-template: none / 1fr 1px 1fr;\n justify-items: center;\n align-items: center;\n gap: var(--report-line-height);\n min-height: 288px;\n margin-bottom: var(--default-padding);\n}\n\n.lh-final-ss-image {\n /* constrain the size of the image to not be too large */\n max-height: calc(var(--gauge-circle-size-big) * 2.8);\n max-width: calc(var(--gauge-circle-size-big) * 3.5);\n border: 1px solid var(--color-gray-200);\n padding: 4px;\n border-radius: 3px;\n display: block;\n}\n\n.lh-category-headercol--separator {\n background: var(--color-gray-200);\n width: 1px;\n height: var(--gauge-circle-size-big);\n}\n\n@media screen and (max-width: 780px) {\n .lh-category-header__finalscreenshot {\n grid-template: 1fr 1fr / none\n }\n .lh-category-headercol--separator {\n display: none;\n }\n}\n\n\n/* 964 fits the min-width of the filmstrip */\n@media screen and (max-width: 964px) {\n .lh-report {\n margin-left: 0;\n width: 100%;\n }\n}\n\n@media print {\n body {\n -webkit-print-color-adjust: exact; /* print background colors */\n }\n .lh-container {\n display: block;\n }\n .lh-report {\n margin-left: 0;\n padding-top: 0;\n }\n .lh-categories {\n margin-top: 0;\n }\n}\n\n.lh-table {\n position: relative;\n border-collapse: separate;\n border-spacing: 0;\n /* Can't assign padding to table, so shorten the width instead. */\n width: calc(100% - var(--audit-description-padding-left) - var(--stackpack-padding-horizontal));\n border: 1px solid var(--report-border-color-secondary);\n}\n\n.lh-table thead th {\n position: sticky;\n top: calc(var(--sticky-header-buffer) + 1em);\n z-index: 1;\n background-color: var(--report-background-color);\n border-bottom: 1px solid var(--report-border-color-secondary);\n font-weight: normal;\n color: var(--color-gray-600);\n /* See text-wrapping comment on .lh-container. */\n word-break: normal;\n}\n\n.lh-row--group {\n background-color: var(--table-group-header-background-color);\n}\n\n.lh-row--group td {\n font-weight: bold;\n font-size: 1.05em;\n color: var(--table-group-header-text-color);\n}\n\n.lh-row--group td:first-child {\n font-weight: normal;\n}\n\n.lh-row--group .lh-text {\n color: inherit;\n text-decoration: none;\n display: inline-block;\n}\n\n.lh-row--group a.lh-link:hover {\n text-decoration: underline;\n}\n\n.lh-row--group .lh-audit__adorn {\n text-transform: capitalize;\n font-weight: normal;\n padding: 2px 3px 1px 3px;\n}\n\n.lh-row--group .lh-audit__adorn1p {\n color: var(--link-color);\n border-color: var(--link-color);\n}\n\n.lh-row--group .lh-report-icon--external::before {\n content: \"\";\n background-repeat: no-repeat;\n width: 14px;\n height: 16px;\n opacity: 0.7;\n display: inline-block;\n vertical-align: middle;\n}\n\n.lh-row--group .lh-report-icon--external {\n display: none;\n}\n\n.lh-row--group:hover .lh-report-icon--external {\n display: inline-block;\n}\n\n.lh-dark .lh-report-icon--external::before {\n filter: invert(1);\n}\n\n/** Manages indentation of two-level and three-level nested adjacent rows */\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) td:first-child {\n padding-left: 20px;\n}\n\n.lh-row--group ~ [data-entity]:not(.lh-row--group) ~ .lh-sub-item-row td:first-child {\n padding-left: 40px;\n}\n\n.lh-row--even {\n background-color: var(--table-group-header-background-color);\n}\n.lh-row--hidden {\n display: none;\n}\n\n.lh-table th,\n.lh-table td {\n padding: var(--default-padding);\n}\n\n.lh-table tr {\n vertical-align: middle;\n}\n\n.lh-table tr:hover {\n background-color: var(--table-higlight-background-color);\n}\n\n/* Looks unnecessary, but mostly for keeping the s left-aligned */\n.lh-table-column--text,\n.lh-table-column--source-location,\n.lh-table-column--url,\n/* .lh-table-column--thumbnail, */\n/* .lh-table-column--empty,*/\n.lh-table-column--code,\n.lh-table-column--node {\n text-align: left;\n}\n\n.lh-table-column--code {\n min-width: 100px;\n}\n\n.lh-table-column--bytes,\n.lh-table-column--timespanMs,\n.lh-table-column--ms,\n.lh-table-column--numeric {\n text-align: right;\n word-break: normal;\n}\n\n\n\n.lh-table .lh-table-column--thumbnail {\n width: var(--image-preview-size);\n}\n\n.lh-table-column--url {\n min-width: 250px;\n}\n\n.lh-table-column--text {\n min-width: 80px;\n}\n\n/* Keep columns narrow if they follow the URL column */\n/* 12% was determined to be a decent narrow width, but wide enough for column headings */\n.lh-table-column--url + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--ms,\n.lh-table-column--url + .lh-table-column--ms + th.lh-table-column--bytes,\n.lh-table-column--url + .lh-table-column--bytes + th.lh-table-column--timespanMs {\n width: 12%;\n}\n\n.lh-text__url-host {\n display: inline;\n}\n\n.lh-text__url-host {\n margin-left: calc(var(--report-font-size) / 2);\n opacity: 0.6;\n font-size: 90%\n}\n\n.lh-thumbnail {\n object-fit: cover;\n width: var(--image-preview-size);\n height: var(--image-preview-size);\n display: block;\n}\n\n.lh-unknown pre {\n overflow: scroll;\n border: solid 1px var(--color-gray-200);\n}\n\n.lh-text__url > a {\n color: inherit;\n text-decoration: none;\n}\n\n.lh-text__url > a:hover {\n text-decoration: underline dotted #999;\n}\n\n.lh-sub-item-row {\n margin-left: 20px;\n margin-bottom: 0;\n color: var(--color-gray-700);\n}\n\n.lh-sub-item-row td {\n padding-top: 4px;\n padding-bottom: 4px;\n padding-left: 20px;\n}\n\n/* Chevron\n https://codepen.io/paulirish/pen/LmzEmK\n */\n.lh-chevron {\n --chevron-angle: 42deg;\n /* Edge doesn't support transform: rotate(calc(...)), so we define it here */\n --chevron-angle-right: -42deg;\n width: var(--chevron-size);\n height: var(--chevron-size);\n margin-top: calc((var(--report-line-height) - 12px) / 2);\n}\n\n.lh-chevron__lines {\n transition: transform 0.4s;\n transform: translateY(var(--report-line-height));\n}\n.lh-chevron__line {\n stroke: var(--chevron-line-stroke);\n stroke-width: var(--chevron-size);\n stroke-linecap: square;\n transform-origin: 50%;\n transform: rotate(var(--chevron-angle));\n transition: transform 300ms, stroke 300ms;\n}\n\n.lh-expandable-details .lh-chevron__line-right,\n.lh-expandable-details[open] .lh-chevron__line-left {\n transform: rotate(var(--chevron-angle-right));\n}\n\n.lh-expandable-details[open] .lh-chevron__line-right {\n transform: rotate(var(--chevron-angle));\n}\n\n\n.lh-expandable-details[open] .lh-chevron__lines {\n transform: translateY(calc(var(--chevron-size) * -1));\n}\n\n.lh-expandable-details[open] {\n animation: 300ms openDetails forwards;\n padding-bottom: var(--default-padding);\n}\n\n@keyframes openDetails {\n from {\n outline: 1px solid var(--report-background-color);\n }\n to {\n outline: 1px solid;\n box-shadow: 0 2px 4px rgba(0, 0, 0, .24);\n }\n}\n\n@media screen and (max-width: 780px) {\n /* no black outline if we're not confident the entire table can be displayed within bounds */\n .lh-expandable-details[open] {\n animation: none;\n }\n}\n\n.lh-expandable-details[open] summary, details.lh-clump > summary {\n border-bottom: 1px solid var(--report-border-color-secondary);\n}\ndetails.lh-clump[open] > summary {\n border-bottom-width: 0;\n}\n\n\n\ndetails .lh-clump-toggletext--hide,\ndetails[open] .lh-clump-toggletext--show { display: none; }\ndetails[open] .lh-clump-toggletext--hide { display: block;}\n\n\n/* Tooltip */\n.lh-tooltip-boundary {\n position: relative;\n}\n\n.lh-tooltip {\n position: absolute;\n display: none; /* Don't retain these layers when not needed */\n opacity: 0;\n background: #ffffff;\n white-space: pre-line; /* Render newlines in the text */\n min-width: 246px;\n max-width: 275px;\n padding: 15px;\n border-radius: 5px;\n text-align: initial;\n line-height: 1.4;\n}\n/* shrink tooltips to not be cutoff on left edge of narrow viewports\n 45vw is chosen to be ~= width of the left column of metrics\n*/\n@media screen and (max-width: 535px) {\n .lh-tooltip {\n min-width: 45vw;\n padding: 3vw;\n }\n}\n\n.lh-tooltip-boundary:hover .lh-tooltip {\n display: block;\n animation: fadeInTooltip 250ms;\n animation-fill-mode: forwards;\n animation-delay: 850ms;\n bottom: 100%;\n z-index: 1;\n will-change: opacity;\n right: 0;\n pointer-events: none;\n}\n\n.lh-tooltip::before {\n content: \"\";\n border: solid transparent;\n border-bottom-color: #fff;\n border-width: 10px;\n position: absolute;\n bottom: -20px;\n right: 6px;\n transform: rotate(180deg);\n pointer-events: none;\n}\n\n@keyframes fadeInTooltip {\n 0% { opacity: 0; }\n 75% { opacity: 1; }\n 100% { opacity: 1; filter: drop-shadow(1px 0px 1px #aaa) drop-shadow(0px 2px 4px hsla(206, 6%, 25%, 0.15)); pointer-events: auto; }\n}\n\n/* Element screenshot */\n.lh-element-screenshot {\n float: left;\n margin-right: 20px;\n}\n.lh-element-screenshot__content {\n overflow: hidden;\n min-width: 110px;\n display: flex;\n justify-content: center;\n background-color: var(--report-background-color);\n}\n.lh-element-screenshot__image {\n position: relative;\n /* Set by ElementScreenshotRenderer.installFullPageScreenshotCssVariable */\n background-image: var(--element-screenshot-url);\n outline: 2px solid #777;\n background-color: white;\n background-repeat: no-repeat;\n}\n.lh-element-screenshot__mask {\n position: absolute;\n background: #555;\n opacity: 0.8;\n}\n.lh-element-screenshot__element-marker {\n position: absolute;\n outline: 2px solid var(--color-lime-400);\n}\n.lh-element-screenshot__overlay {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n bottom: 0;\n z-index: 2000; /* .lh-topbar is 1000 */\n background: var(--screenshot-overlay-background);\n display: flex;\n align-items: center;\n justify-content: center;\n cursor: zoom-out;\n}\n\n.lh-element-screenshot__overlay .lh-element-screenshot {\n margin-right: 0; /* clearing margin used in thumbnail case */\n outline: 1px solid var(--color-gray-700);\n}\n\n.lh-screenshot-overlay--enabled .lh-element-screenshot {\n cursor: zoom-out;\n}\n.lh-screenshot-overlay--enabled .lh-node .lh-element-screenshot {\n cursor: zoom-in;\n}\n\n\n.lh-meta__items {\n --meta-icon-size: calc(var(--report-icon-size) * 0.667);\n padding: var(--default-padding);\n display: grid;\n grid-template-columns: 1fr 1fr 1fr;\n background-color: var(--env-item-background-color);\n border-radius: 3px;\n margin: 0 0 var(--default-padding) 0;\n font-size: 12px;\n column-gap: var(--default-padding);\n color: var(--color-gray-700);\n}\n\n.lh-meta__item {\n display: block;\n list-style-type: none;\n position: relative;\n padding: 0 0 0 calc(var(--meta-icon-size) + var(--default-padding) * 2);\n cursor: unset; /* disable pointer cursor from report-icon */\n}\n\n.lh-meta__item.lh-tooltip-boundary {\n text-decoration: dotted underline var(--color-gray-500);\n cursor: help;\n}\n\n.lh-meta__item.lh-report-icon::before {\n position: absolute;\n left: var(--default-padding);\n width: var(--meta-icon-size);\n height: var(--meta-icon-size);\n}\n\n.lh-meta__item.lh-report-icon:hover::before {\n opacity: 0.7;\n}\n\n.lh-meta__item .lh-tooltip {\n color: var(--color-gray-800);\n}\n\n.lh-meta__item .lh-tooltip::before {\n right: auto; /* Set the tooltip arrow to the leftside */\n left: 6px;\n}\n\n/* Change the grid for narrow viewport. */\n@media screen and (max-width: 640px) {\n .lh-meta__items {\n grid-template-columns: 1fr 1fr;\n }\n}\n@media screen and (max-width: 535px) {\n .lh-meta__items {\n display: block;\n }\n}\n\n\n/*# sourceURL=report-styles.css */\n"); el0.append(el1); return el0; } From ce877bd8079507231b2cc4a1fd96fad92131939a Mon Sep 17 00:00:00 2001 From: Adriana Ixba Date: Tue, 26 Sep 2023 14:41:39 -0700 Subject: [PATCH 22/31] cleanups --- report/assets/styles.css | 30 ----------- report/assets/templates.html | 35 ------------- report/renderer/components.js | 51 +------------------ .../renderer/performance-category-renderer.js | 22 +------- types/audit.d.ts | 2 +- 5 files changed, 3 insertions(+), 137 deletions(-) diff --git a/report/assets/styles.css b/report/assets/styles.css index c6e6b29d2f82..27680e1f9eff 100644 --- a/report/assets/styles.css +++ b/report/assets/styles.css @@ -131,7 +131,6 @@ --section-padding-vertical: calc(var(--default-padding) * 6); --snippet-background-color: var(--color-gray-50); --snippet-color: #0938C2; - --sparkline-height: 5px; --stackpack-padding-horizontal: 10px; --sticky-header-background-color: var(--report-background-color); --sticky-header-buffer: calc(var(--topbar-height) + var(--sticky-header-height)); @@ -238,11 +237,6 @@ --topbar-height: 28px; --topbar-logo-size: 20px; } - - /* Not enough space to adequately show the relative savings bars. */ - .lh-sparkline { - display: none; - } } .lh-vars.lh-devtools { @@ -867,30 +861,6 @@ color: var(--color-fail-secondary); } -/* Sparkline */ - -.lh-sparkline { - height: var(--sparkline-height); - width: 100%; -} - -.lh-sparkline__bar { - height: 100%; - float: right; -} - -.lh-audit--pass .lh-sparkline__bar { - background: var(--color-pass); -} - -.lh-audit--average .lh-sparkline__bar { - background: var(--color-average); -} - -.lh-audit--fail .lh-sparkline__bar { - background: var(--color-fail); -} - /* Filmstrip */ .lh-filmstrip-container { diff --git a/report/assets/templates.html b/report/assets/templates.html index 12f2c77202e2..6a52c8f3b097 100644 --- a/report/assets/templates.html +++ b/report/assets/templates.html @@ -94,41 +94,6 @@ - - - - - -