_renderReport(report) {
    Globals.apply({
      providedStrings: report.i18n.rendererFormattedStrings,
      i18n: new I18nFormatter(report.configSettings.locale),
      reportJson: report,
    });

    const detailsRenderer = new DetailsRenderer(this._dom, {
      fullPageScreenshot: report.fullPageScreenshot ?? undefined,
      entities: report.entities,
    });

    const categoryRenderer = new CategoryRenderer(this._dom, detailsRenderer);

    /** @type {Record<string, CategoryRenderer>} */
    const specificCategoryRenderers = {
      performance: new PerformanceCategoryRenderer(this._dom, detailsRenderer),
    };

    const headerContainer = this._dom.createElement('div');
    headerContainer.append(this._renderReportHeader());

    const reportContainer = this._dom.createElement('div', 'lh-container');
    const reportSection = this._dom.createElement('div', 'lh-report');
    reportSection.append(this._renderReportWarnings(report));

    let scoreHeader;
    const isSoloCategory = Object.keys(report.categories).length === 1;
    if (!isSoloCategory) {
      scoreHeader = this._dom.createElement('div', 'lh-scores-header');
    } else {
      headerContainer.classList.add('lh-header--solo-category');
    }

    const scoreScale = this._dom.createElement('div');
    scoreScale.classList.add('lh-scorescale-wrap');
    scoreScale.append(this._dom.createComponent('scorescale'));
    if (scoreHeader) {
      const scoresContainer = this._dom.find('.lh-scores-container', headerContainer);
      scoreHeader.append(
        ...this._renderScoreGauges(report, categoryRenderer, specificCategoryRenderers));
      scoresContainer.append(scoreHeader, scoreScale);

      const stickyHeader = this._dom.createElement('div', 'lh-sticky-header');
      stickyHeader.append(
        ...this._renderScoreGauges(report, categoryRenderer, specificCategoryRenderers));
      reportContainer.append(stickyHeader);
    }

    const categories = this._dom.createElement('div', 'lh-categories');
    reportSection.append(categories);
    const categoryOptions = {gatherMode: report.gatherMode};
    for (const category of Object.values(report.categories)) {
      const renderer = specificCategoryRenderers[category.id] || categoryRenderer;
      // .lh-category-wrapper is full-width and provides horizontal rules between categories.
      // .lh-category within has the max-width: var(--report-content-max-width);
      const wrapper = renderer.dom.createChildOf(categories, 'div', 'lh-category-wrapper');
      wrapper.append(renderer.render(
        category,
        report.categoryGroups,
        categoryOptions
      ));
    }

    categoryRenderer.injectFinalScreenshot(categories, report.audits, scoreScale);

    const reportFragment = this._dom.createFragment();
    if (!this._opts.omitGlobalStyles) {
      reportFragment.append(this._dom.createComponent('styles'));
    }

    if (!this._opts.omitTopbar) {
      reportFragment.append(this._renderReportTopbar(report));
    }

    reportFragment.append(reportContainer);
    reportSection.append(this._renderReportFooter(report));
    reportContainer.append(headerContainer, reportSection);

    if (report.fullPageScreenshot) {
      ElementScreenshotRenderer.installFullPageScreenshot(
        this._dom.rootEl, report.fullPageScreenshot.screenshot);
    }

    return reportFragment;
  }
@param {LH.ReportResult} report
@return {!DocumentFragment}