Merge changes Id03267c3,Ic6021df6

* changes:
  Provide json output from the version programm and SSH command
  Verbose version output, provide noteDb and index versions
diff --git a/java/com/google/gerrit/server/restapi/change/ChangeRestApiModule.java b/java/com/google/gerrit/server/restapi/change/ChangeRestApiModule.java
index 3e985c2..0f2aa3c 100644
--- a/java/com/google/gerrit/server/restapi/change/ChangeRestApiModule.java
+++ b/java/com/google/gerrit/server/restapi/change/ChangeRestApiModule.java
@@ -92,6 +92,7 @@
     post(ATTENTION_SET_ENTRY_KIND, "delete").to(RemoveFromAttentionSet.class);
     postOnCollection(ATTENTION_SET_ENTRY_KIND).to(AddToAttentionSet.class);
     get(CHANGE_KIND, "hashtags").to(GetHashtags.class);
+    get(CHANGE_KIND, "custom_keyed_values").to(GetCustomKeyedValues.class);
     get(CHANGE_KIND, "comments").to(ListChangeComments.class);
     get(CHANGE_KIND, "robotcomments").to(ListChangeRobotComments.class);
     get(CHANGE_KIND, "drafts").to(ListChangeDrafts.class);
@@ -103,6 +104,7 @@
     delete(CHANGE_KIND).to(DeleteChange.class);
     post(CHANGE_KIND, "abandon").to(Abandon.class);
     post(CHANGE_KIND, "hashtags").to(PostHashtags.class);
+    post(CHANGE_KIND, "custom_keyed_values").to(PostCustomKeyedValues.class);
     post(CHANGE_KIND, "restore").to(Restore.class);
     post(CHANGE_KIND, "revert").to(Revert.class);
     post(CHANGE_KIND, "revert_submission").to(RevertSubmission.class);
diff --git a/javatests/com/google/gerrit/acceptance/rest/binding/ChangesRestApiBindingsIT.java b/javatests/com/google/gerrit/acceptance/rest/binding/ChangesRestApiBindingsIT.java
index 27bd6b9..2df820b 100644
--- a/javatests/com/google/gerrit/acceptance/rest/binding/ChangesRestApiBindingsIT.java
+++ b/javatests/com/google/gerrit/acceptance/rest/binding/ChangesRestApiBindingsIT.java
@@ -60,6 +60,7 @@
           RestCall.delete("/changes/%s/topic"),
           RestCall.get("/changes/%s/in"),
           RestCall.get("/changes/%s/hashtags"),
+          RestCall.get("/changes/%s/custom_keyed_values"),
           RestCall.get("/changes/%s/comments"),
           RestCall.get("/changes/%s/robotcomments"),
           RestCall.get("/changes/%s/drafts"),
diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts
index ff7a528..0e75b84 100644
--- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts
+++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.ts
@@ -142,65 +142,67 @@
     }
   }
 
-  static override styles = [
-    sharedStyles,
-    paperStyles,
-    formStyles,
-    menuPageStyles,
-    css`
-      :host {
-        display: block;
-        margin-bottom: var(--spacing-m);
-      }
-      .header {
-        align-items: baseline;
-        display: flex;
-        justify-content: space-between;
-        margin: var(--spacing-s) var(--spacing-m);
-      }
-      .rules {
-        background: var(--table-header-background-color);
-        border: 1px solid var(--border-color);
-        border-bottom: 0;
-      }
-      .editing .rules {
-        border-bottom: 1px solid var(--border-color);
-      }
-      .title {
-        margin-bottom: var(--spacing-s);
-      }
-      #addRule,
-      #removeBtn {
-        display: none;
-      }
-      .right {
-        display: flex;
-        align-items: center;
-      }
-      .editing #removeBtn {
-        display: block;
-        margin-left: var(--spacing-xl);
-      }
-      .editing #addRule {
-        display: block;
-        padding: var(--spacing-m);
-      }
-      #deletedContainer,
-      .deleted #mainContainer {
-        display: none;
-      }
-      .deleted #deletedContainer {
-        align-items: baseline;
-        border: 1px solid var(--border-color);
-        display: flex;
-        justify-content: space-between;
-        padding: var(--spacing-m);
-      }
-      #mainContainer {
-        display: block;
-      }
-    `,
-  ];
+  static override get styles() {
+    return [
+      sharedStyles,
+      paperStyles,
+      formStyles,
+      menuPageStyles,
+      css`
+        :host {
+          display: block;
+          margin-bottom: var(--spacing-m);
+        }
+        .header {
+          align-items: baseline;
+          display: flex;
+          justify-content: space-between;
+          margin: var(--spacing-s) var(--spacing-m);
+        }
+        .rules {
+          background: var(--table-header-background-color);
+          border: 1px solid var(--border-color);
+          border-bottom: 0;
+        }
+        .editing .rules {
+          border-bottom: 1px solid var(--border-color);
+        }
+        .title {
+          margin-bottom: var(--spacing-s);
+        }
+        #addRule,
+        #removeBtn {
+          display: none;
+        }
+        .right {
+          display: flex;
+          align-items: center;
+        }
+        .editing #removeBtn {
+          display: block;
+          margin-left: var(--spacing-xl);
+        }
+        .editing #addRule {
+          display: block;
+          padding: var(--spacing-m);
+        }
+        #deletedContainer,
+        .deleted #mainContainer {
+          display: none;
+        }
+        .deleted #deletedContainer {
+          align-items: baseline;
+          border: 1px solid var(--border-color);
+          display: flex;
+          justify-content: space-between;
+          padding: var(--spacing-m);
+        }
+        #mainContainer {
+          display: block;
+        }
+      `,
+    ];
+  }
 
   override render() {
     if (!this.section || !this.permission) {
diff --git a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts
index 1cb25ea..8d72a97 100644
--- a/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts
+++ b/polygerrit-ui/app/elements/change/gr-change-metadata/gr-change-metadata.ts
@@ -212,104 +212,106 @@
     this.queryHashtag = (input: string) => this.getHashtagSuggestions(input);
   }
 
-  static override styles = [
-    sharedStyles,
-    fontStyles,
-    changeMetadataStyles,
-    css`
-      :host {
-        display: table;
-      }
-      gr-submit-requirements {
-        --requirements-horizontal-padding: var(--metadata-horizontal-padding);
-      }
-      gr-editable-label {
-        max-width: 9em;
-      }
-      gr-weblink {
-        display: block;
-      }
-      gr-account-chip[disabled],
-      gr-linked-chip[disabled] {
-        opacity: 0;
-        pointer-events: none;
-      }
-      .hashtagChip {
-        padding-bottom: var(--spacing-s);
-      }
-      /* consistent with section .title, .value */
-      .hashtagChip:not(last-of-type) {
-        padding-bottom: var(--spacing-s);
-      }
-      .hashtagChip:last-of-type {
-        display: inline;
-        vertical-align: top;
-      }
-      .parentList.merge {
-        list-style-type: decimal;
-        padding-left: var(--spacing-l);
-      }
-      .parentList gr-commit-info {
-        display: inline-block;
-      }
-      .hideDisplay,
-      #parentNotCurrentMessage {
-        display: none;
-      }
-      .icon {
-        margin: -3px 0;
-      }
-      .icon.help,
-      .icon.notTrusted {
-        color: var(--warning-foreground);
-      }
-      .icon.invalid {
-        color: var(--negative-red-text-color);
-      }
-      .icon.trusted {
-        color: var(--positive-green-text-color);
-      }
-      .parentList.notCurrent.nonMerge #parentNotCurrentMessage {
-        --arrow-color: var(--warning-foreground);
-        display: inline-block;
-      }
-      .oldSeparatedSection {
-        margin-top: var(--spacing-l);
-        padding: var(--spacing-m) 0;
-      }
-      .separatedSection {
-        padding: var(--spacing-m) 0;
-      }
-      .hashtag gr-linked-chip,
-      .topic gr-linked-chip {
-        --linked-chip-text-color: var(--link-color);
-      }
-      gr-reviewer-list {
-        --account-max-length: 100px;
-        max-width: 285px;
-      }
-      .metadata-title {
-        color: var(--deemphasized-text-color);
-        padding-left: var(--metadata-horizontal-padding);
-      }
-      .metadata-header {
-        display: flex;
-        justify-content: space-between;
-        align-items: flex-end;
-        /* The goal is to achieve alignment of the owner account chip and the
+  static override get styles() {
+    return [
+      sharedStyles,
+      fontStyles,
+      changeMetadataStyles,
+      css`
+        :host {
+          display: table;
+        }
+        gr-submit-requirements {
+          --requirements-horizontal-padding: var(--metadata-horizontal-padding);
+        }
+        gr-editable-label {
+          max-width: 9em;
+        }
+        gr-weblink {
+          display: block;
+        }
+        gr-account-chip[disabled],
+        gr-linked-chip[disabled] {
+          opacity: 0;
+          pointer-events: none;
+        }
+        .hashtagChip {
+          padding-bottom: var(--spacing-s);
+        }
+        /* consistent with section .title, .value */
+        .hashtagChip:not(last-of-type) {
+          padding-bottom: var(--spacing-s);
+        }
+        .hashtagChip:last-of-type {
+          display: inline;
+          vertical-align: top;
+        }
+        .parentList.merge {
+          list-style-type: decimal;
+          padding-left: var(--spacing-l);
+        }
+        .parentList gr-commit-info {
+          display: inline-block;
+        }
+        .hideDisplay,
+        #parentNotCurrentMessage {
+          display: none;
+        }
+        .icon {
+          margin: -3px 0;
+        }
+        .icon.help,
+        .icon.notTrusted {
+          color: var(--warning-foreground);
+        }
+        .icon.invalid {
+          color: var(--negative-red-text-color);
+        }
+        .icon.trusted {
+          color: var(--positive-green-text-color);
+        }
+        .parentList.notCurrent.nonMerge #parentNotCurrentMessage {
+          --arrow-color: var(--warning-foreground);
+          display: inline-block;
+        }
+        .oldSeparatedSection {
+          margin-top: var(--spacing-l);
+          padding: var(--spacing-m) 0;
+        }
+        .separatedSection {
+          padding: var(--spacing-m) 0;
+        }
+        .hashtag gr-linked-chip,
+        .topic gr-linked-chip {
+          --linked-chip-text-color: var(--link-color);
+        }
+        gr-reviewer-list {
+          --account-max-length: 100px;
+          max-width: 285px;
+        }
+        .metadata-title {
+          color: var(--deemphasized-text-color);
+          padding-left: var(--metadata-horizontal-padding);
+        }
+        .metadata-header {
+          display: flex;
+          justify-content: space-between;
+          align-items: flex-end;
+          /* The goal is to achieve alignment of the owner account chip and the
          commit message box. Their top border should be on the same line. */
-        margin-bottom: var(--spacing-s);
-      }
-      .show-all-button gr-icon {
-        color: inherit;
-        font-size: 18px;
-      }
-      gr-vote-chip {
-        --gr-vote-chip-width: 14px;
-        --gr-vote-chip-height: 14px;
-      }
-    `,
-  ];
+          margin-bottom: var(--spacing-s);
+        }
+        .show-all-button gr-icon {
+          color: inherit;
+          font-size: 18px;
+        }
+        gr-vote-chip {
+          --gr-vote-chip-width: 14px;
+          --gr-vote-chip-height: 14px;
+        }
+      `,
+    ];
+  }
 
   override render() {
     if (!this.change) return nothing;
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.ts
index 7723327..77a2cf5 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-conflict-dialog/gr-confirm-cherrypick-conflict-dialog.ts
@@ -27,23 +27,25 @@
    * @event cancel
    */
 
-  static override styles = [
-    sharedStyles,
-    css`
-      :host {
-        display: block;
-      }
-      :host([disabled]) {
-        opacity: 0.5;
-        pointer-events: none;
-      }
-      .main {
-        display: flex;
-        flex-direction: column;
-        width: 100%;
-      }
-    `,
-  ];
+  static override get styles() {
+    return [
+      sharedStyles,
+      css`
+        :host {
+          display: block;
+        }
+        :host([disabled]) {
+          opacity: 0.5;
+          pointer-events: none;
+        }
+        .main {
+          display: flex;
+          flex-direction: column;
+          width: 100%;
+        }
+      `,
+    ];
+  }
 
   override render() {
     return html`
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
index 891209e..080eb0c 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-cherrypick-dialog/gr-confirm-cherrypick-dialog.ts
@@ -154,75 +154,77 @@
     }
   }
 
-  static override styles = [
-    sharedStyles,
-    css`
-      :host {
-        display: block;
-      }
-      :host([disabled]) {
-        opacity: 0.5;
-        pointer-events: none;
-      }
-      label {
-        cursor: pointer;
-      }
-      .main {
-        display: flex;
-        flex-direction: column;
-        width: 100%;
-      }
-      .main label,
-      .main input[type='text'] {
-        display: block;
-        width: 100%;
-      }
-      iron-autogrow-textarea {
-        font-family: var(--monospace-font-family);
-        font-size: var(--font-size-mono);
-        line-height: var(--line-height-mono);
-        width: 73ch; /* Add a char to account for the border. */
-      }
-      .cherryPickTopicLayout {
-        display: flex;
-        align-items: center;
-        margin-bottom: var(--spacing-m);
-      }
-      .cherryPickSingleChange,
-      .cherryPickTopic {
-        margin-left: var(--spacing-m);
-      }
-      .cherry-pick-topic-message {
-        margin-bottom: var(--spacing-m);
-      }
-      label[for='messageInput'],
-      label[for='baseInput'] {
-        margin-top: var(--spacing-m);
-      }
-      .title {
-        font-weight: var(--font-weight-bold);
-      }
-      tr > td {
-        padding: var(--spacing-m);
-      }
-      th {
-        color: var(--deemphasized-text-color);
-      }
-      table {
-        border-collapse: collapse;
-      }
-      tr {
-        border-bottom: 1px solid var(--border-color);
-      }
-      .error {
-        color: var(--error-text-color);
-      }
-      .error-message {
-        color: var(--error-text-color);
-        margin: var(--spacing-m) 0 var(--spacing-m) 0;
-      }
-    `,
-  ];
+  static override get styles() {
+    return [
+      sharedStyles,
+      css`
+        :host {
+          display: block;
+        }
+        :host([disabled]) {
+          opacity: 0.5;
+          pointer-events: none;
+        }
+        label {
+          cursor: pointer;
+        }
+        .main {
+          display: flex;
+          flex-direction: column;
+          width: 100%;
+        }
+        .main label,
+        .main input[type='text'] {
+          display: block;
+          width: 100%;
+        }
+        iron-autogrow-textarea {
+          font-family: var(--monospace-font-family);
+          font-size: var(--font-size-mono);
+          line-height: var(--line-height-mono);
+          width: 73ch; /* Add a char to account for the border. */
+        }
+        .cherryPickTopicLayout {
+          display: flex;
+          align-items: center;
+          margin-bottom: var(--spacing-m);
+        }
+        .cherryPickSingleChange,
+        .cherryPickTopic {
+          margin-left: var(--spacing-m);
+        }
+        .cherry-pick-topic-message {
+          margin-bottom: var(--spacing-m);
+        }
+        label[for='messageInput'],
+        label[for='baseInput'] {
+          margin-top: var(--spacing-m);
+        }
+        .title {
+          font-weight: var(--font-weight-bold);
+        }
+        tr > td {
+          padding: var(--spacing-m);
+        }
+        th {
+          color: var(--deemphasized-text-color);
+        }
+        table {
+          border-collapse: collapse;
+        }
+        tr {
+          border-bottom: 1px solid var(--border-color);
+        }
+        .error {
+          color: var(--error-text-color);
+        }
+        .error-message {
+          color: var(--error-text-color);
+          margin: var(--spacing-m) 0 var(--spacing-m) 0;
+        }
+      `,
+    ];
+  }
 
   override render() {
     return html`
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts
index 6ad416e..7bbfd93 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-rebase-dialog/gr-confirm-rebase-dialog.ts
@@ -160,39 +160,41 @@
     }
   }
 
-  static override styles = [
-    sharedStyles,
-    css`
-      :host {
-        display: block;
-        width: 30em;
-      }
-      :host([disabled]) {
-        opacity: 0.5;
-        pointer-events: none;
-      }
-      label {
-        cursor: pointer;
-      }
-      .message {
-        font-style: italic;
-      }
-      .parentRevisionContainer label,
-      .parentRevisionContainer input[type='text'] {
-        display: block;
-        width: 100%;
-      }
-      .rebaseCheckbox {
-        margin-top: var(--spacing-m);
-      }
-      .rebaseOption {
-        margin: var(--spacing-m) 0;
-      }
-      .rebaseOnBehalfMsg {
-        margin-top: var(--spacing-m);
-      }
-    `,
-  ];
+  static override get styles() {
+    return [
+      sharedStyles,
+      css`
+        :host {
+          display: block;
+          width: 30em;
+        }
+        :host([disabled]) {
+          opacity: 0.5;
+          pointer-events: none;
+        }
+        label {
+          cursor: pointer;
+        }
+        .message {
+          font-style: italic;
+        }
+        .parentRevisionContainer label,
+        .parentRevisionContainer input[type='text'] {
+          display: block;
+          width: 100%;
+        }
+        .rebaseCheckbox {
+          margin-top: var(--spacing-m);
+        }
+        .rebaseOption {
+          margin: var(--spacing-m) 0;
+        }
+        .rebaseOnBehalfMsg {
+          margin-top: var(--spacing-m);
+        }
+      `,
+    ];
+  }
 
   override render() {
     return html`
diff --git a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts
index e421c9c..c01d89f 100644
--- a/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-confirm-revert-dialog/gr-confirm-revert-dialog.ts
@@ -66,43 +66,45 @@
 
   private readonly getPluginLoader = resolve(this, pluginLoaderToken);
 
-  static override styles = [
-    sharedStyles,
-    css`
-      :host {
-        display: block;
-      }
-      :host([disabled]) {
-        opacity: 0.5;
-        pointer-events: none;
-      }
-      label {
-        cursor: pointer;
-        display: block;
-        width: 100%;
-      }
-      .revertSubmissionLayout {
-        display: flex;
-        align-items: center;
-      }
-      .label {
-        margin-left: var(--spacing-m);
-      }
-      iron-autogrow-textarea {
-        font-family: var(--monospace-font-family);
-        font-size: var(--font-size-mono);
-        line-height: var(--line-height-mono);
-        width: 73ch; /* Add a char to account for the border. */
-      }
-      .error {
-        color: var(--error-text-color);
-        margin-bottom: var(--spacing-m);
-      }
-      label[for='messageInput'] {
-        margin-top: var(--spacing-m);
-      }
-    `,
-  ];
+  static override get styles() {
+    return [
+      sharedStyles,
+      css`
+        :host {
+          display: block;
+        }
+        :host([disabled]) {
+          opacity: 0.5;
+          pointer-events: none;
+        }
+        label {
+          cursor: pointer;
+          display: block;
+          width: 100%;
+        }
+        .revertSubmissionLayout {
+          display: flex;
+          align-items: center;
+        }
+        .label {
+          margin-left: var(--spacing-m);
+        }
+        iron-autogrow-textarea {
+          font-family: var(--monospace-font-family);
+          font-size: var(--font-size-mono);
+          line-height: var(--line-height-mono);
+          width: 73ch; /* Add a char to account for the border. */
+        }
+        .error {
+          color: var(--error-text-color);
+          margin-bottom: var(--spacing-m);
+        }
+        label[for='messageInput'] {
+          margin-top: var(--spacing-m);
+        }
+      `,
+    ];
+  }
 
   override render() {
     return html`
diff --git a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
index adea275..f6f3706 100644
--- a/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
+++ b/polygerrit-ui/app/elements/change/gr-file-list-header/gr-file-list-header.ts
@@ -139,99 +139,101 @@
     );
   }
 
-  static override styles = [
-    sharedStyles,
-    css`
-      .prefsButton {
-        float: right;
-      }
-      .patchInfoOldPatchSet.patchInfo-header {
-        background-color: var(--emphasis-color);
-      }
-      .patchInfo-header {
-        align-items: center;
-        display: flex;
-        padding: var(--spacing-s) var(--spacing-l);
-      }
-      .patchInfo-left {
-        align-items: baseline;
-        display: flex;
-      }
-      .patchInfoContent {
-        align-items: center;
-        display: flex;
-        flex-wrap: wrap;
-      }
-      .latestPatchContainer a {
-        text-decoration: none;
-      }
-      .mobile {
-        display: none;
-      }
-      .patchInfo-header .container {
-        align-items: center;
-        display: flex;
-      }
-      .downloadContainer,
-      .uploadContainer {
-        margin-right: 16px;
-      }
-      .uploadContainer.hide {
-        display: none;
-      }
-      .rightControls {
-        align-self: flex-end;
-        margin: auto 0 auto auto;
-        align-items: center;
-        display: flex;
-        flex-wrap: wrap;
-        font-weight: var(--font-weight-normal);
-        justify-content: flex-end;
-      }
-      #collapseBtn,
-      .allExpanded #expandBtn,
-      .fileViewActions {
-        display: none;
-      }
-      .someExpanded #expandBtn {
-        margin-right: 8px;
-      }
-      .someExpanded #collapseBtn,
-      .allExpanded #collapseBtn,
-      .openFile .fileViewActions {
-        align-items: center;
-        display: flex;
-      }
-      .rightControls gr-button,
-      gr-patch-range-select {
-        margin: 0 -4px;
-      }
-      .fileViewActions gr-button {
-        margin: 0;
-        --gr-button-padding: 2px 4px;
-      }
-      .flexContainer {
-        align-items: center;
-        display: flex;
-      }
-      .label {
-        font-weight: var(--font-weight-bold);
-        margin-right: 24px;
-      }
-      gr-commit-info,
-      gr-edit-controls {
-        margin-right: -5px;
-      }
-      .fileViewActionsLabel {
-        margin-right: var(--spacing-xs);
-      }
-      @media screen and (max-width: 50em) {
-        .patchInfo-header .desktop {
+  static override get styles() {
+    return [
+      sharedStyles,
+      css`
+        .prefsButton {
+          float: right;
+        }
+        .patchInfoOldPatchSet.patchInfo-header {
+          background-color: var(--emphasis-color);
+        }
+        .patchInfo-header {
+          align-items: center;
+          display: flex;
+          padding: var(--spacing-s) var(--spacing-l);
+        }
+        .patchInfo-left {
+          align-items: baseline;
+          display: flex;
+        }
+        .patchInfoContent {
+          align-items: center;
+          display: flex;
+          flex-wrap: wrap;
+        }
+        .latestPatchContainer a {
+          text-decoration: none;
+        }
+        .mobile {
           display: none;
         }
-      }
-    `,
-  ];
+        .patchInfo-header .container {
+          align-items: center;
+          display: flex;
+        }
+        .downloadContainer,
+        .uploadContainer {
+          margin-right: 16px;
+        }
+        .uploadContainer.hide {
+          display: none;
+        }
+        .rightControls {
+          align-self: flex-end;
+          margin: auto 0 auto auto;
+          align-items: center;
+          display: flex;
+          flex-wrap: wrap;
+          font-weight: var(--font-weight-normal);
+          justify-content: flex-end;
+        }
+        #collapseBtn,
+        .allExpanded #expandBtn,
+        .fileViewActions {
+          display: none;
+        }
+        .someExpanded #expandBtn {
+          margin-right: 8px;
+        }
+        .someExpanded #collapseBtn,
+        .allExpanded #collapseBtn,
+        .openFile .fileViewActions {
+          align-items: center;
+          display: flex;
+        }
+        .rightControls gr-button,
+        gr-patch-range-select {
+          margin: 0 -4px;
+        }
+        .fileViewActions gr-button {
+          margin: 0;
+          --gr-button-padding: 2px 4px;
+        }
+        .flexContainer {
+          align-items: center;
+          display: flex;
+        }
+        .label {
+          font-weight: var(--font-weight-bold);
+          margin-right: 24px;
+        }
+        gr-commit-info,
+        gr-edit-controls {
+          margin-right: -5px;
+        }
+        .fileViewActionsLabel {
+          margin-right: var(--spacing-xs);
+        }
+        @media screen and (max-width: 50em) {
+          .patchInfo-header .desktop {
+            display: none;
+          }
+        }
+      `,
+    ];
+  }
 
   override render() {
     if (!this.change || !this.diffPrefs) {
diff --git a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
index f41236b..a9c472f 100644
--- a/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
+++ b/polygerrit-ui/app/elements/change/gr-reply-dialog/gr-reply-dialog.ts
@@ -354,223 +354,225 @@
 
   private readonly shortcuts = new ShortcutController(this);
 
-  static override styles = [
-    sharedStyles,
-    modalStyles,
-    css`
-      :host {
-        background-color: var(--dialog-background-color);
-        display: block;
-        max-height: 90vh;
-        --label-score-padding-left: var(--spacing-xl);
-      }
-      :host([disabled]) {
-        pointer-events: none;
-      }
-      :host([disabled]) .container {
-        opacity: 0.5;
-      }
-      section {
-        border-top: 1px solid var(--border-color);
-        flex-shrink: 0;
-        padding: var(--spacing-m) var(--spacing-xl);
-        width: 100%;
-      }
-      section.labelsContainer {
-        /* We want the :hover highlight to extend to the border of the dialog. */
-        padding: var(--spacing-m) 0;
-      }
-      .stickyBottom {
-        background-color: var(--dialog-background-color);
-        box-shadow: 0px 0px 8px 0px rgba(60, 64, 67, 0.15);
-        margin-top: var(--spacing-s);
-        bottom: 0;
-        position: sticky;
-        /* @see Issue 8602 */
-        z-index: 1;
-      }
-      .stickyBottom.newReplyDialog {
-        margin-top: unset;
-      }
-      .actions {
-        display: flex;
-        justify-content: space-between;
-      }
-      .actions .right gr-button {
-        margin-left: var(--spacing-l);
-      }
-      .peopleContainer,
-      .labelsContainer {
-        flex-shrink: 0;
-      }
-      .peopleContainer {
-        border-top: none;
-        display: table;
-      }
-      .peopleList {
-        display: flex;
-      }
-      .peopleListLabel {
-        color: var(--deemphasized-text-color);
-        margin-top: var(--spacing-xs);
-        min-width: 6em;
-        padding-right: var(--spacing-m);
-      }
-      gr-account-list {
-        display: flex;
-        flex-wrap: wrap;
-        flex: 1;
-      }
-      #reviewerConfirmationModal {
-        padding: var(--spacing-l);
-        text-align: center;
-      }
-      .reviewerConfirmationButtons {
-        margin-top: var(--spacing-l);
-      }
-      .groupName {
-        font-weight: var(--font-weight-bold);
-      }
-      .groupSize {
-        font-style: italic;
-      }
-      .textareaContainer {
-        min-height: 12em;
-        position: relative;
-      }
-      .newReplyDialog.textareaContainer {
-        min-height: unset;
-      }
-      textareaContainer,
-      gr-endpoint-decorator[name='reply-text'] {
-        display: flex;
-        width: 100%;
-      }
-      gr-endpoint-decorator[name='reply-text'] {
-        flex-direction: column;
-      }
-      #checkingStatusLabel,
-      #notLatestLabel {
-        margin-left: var(--spacing-l);
-      }
-      #checkingStatusLabel {
-        color: var(--deemphasized-text-color);
-        font-style: italic;
-      }
-      #notLatestLabel,
-      #savingLabel {
-        color: var(--error-text-color);
-      }
-      #savingLabel {
-        display: none;
-      }
-      #savingLabel.saving {
-        display: inline;
-      }
-      #pluginMessage {
-        color: var(--deemphasized-text-color);
-        margin-left: var(--spacing-l);
-        margin-bottom: var(--spacing-m);
-      }
-      #pluginMessage:empty {
-        display: none;
-      }
-      .attention .edit-attention-button {
-        vertical-align: top;
-        --gr-button-padding: 0px 4px;
-      }
-      .attention .edit-attention-button gr-icon {
-        color: inherit;
-        /* The line-height:26px hack (see below) requires us to do this.
+  static override get styles() {
+    return [
+      sharedStyles,
+      modalStyles,
+      css`
+        :host {
+          background-color: var(--dialog-background-color);
+          display: block;
+          max-height: 90vh;
+          --label-score-padding-left: var(--spacing-xl);
+        }
+        :host([disabled]) {
+          pointer-events: none;
+        }
+        :host([disabled]) .container {
+          opacity: 0.5;
+        }
+        section {
+          border-top: 1px solid var(--border-color);
+          flex-shrink: 0;
+          padding: var(--spacing-m) var(--spacing-xl);
+          width: 100%;
+        }
+        section.labelsContainer {
+          /* We want the :hover highlight to extend to the border of the dialog. */
+          padding: var(--spacing-m) 0;
+        }
+        .stickyBottom {
+          background-color: var(--dialog-background-color);
+          box-shadow: 0px 0px 8px 0px rgba(60, 64, 67, 0.15);
+          margin-top: var(--spacing-s);
+          bottom: 0;
+          position: sticky;
+          /* @see Issue 8602 */
+          z-index: 1;
+        }
+        .stickyBottom.newReplyDialog {
+          margin-top: unset;
+        }
+        .actions {
+          display: flex;
+          justify-content: space-between;
+        }
+        .actions .right gr-button {
+          margin-left: var(--spacing-l);
+        }
+        .peopleContainer,
+        .labelsContainer {
+          flex-shrink: 0;
+        }
+        .peopleContainer {
+          border-top: none;
+          display: table;
+        }
+        .peopleList {
+          display: flex;
+        }
+        .peopleListLabel {
+          color: var(--deemphasized-text-color);
+          margin-top: var(--spacing-xs);
+          min-width: 6em;
+          padding-right: var(--spacing-m);
+        }
+        gr-account-list {
+          display: flex;
+          flex-wrap: wrap;
+          flex: 1;
+        }
+        #reviewerConfirmationModal {
+          padding: var(--spacing-l);
+          text-align: center;
+        }
+        .reviewerConfirmationButtons {
+          margin-top: var(--spacing-l);
+        }
+        .groupName {
+          font-weight: var(--font-weight-bold);
+        }
+        .groupSize {
+          font-style: italic;
+        }
+        .textareaContainer {
+          min-height: 12em;
+          position: relative;
+        }
+        .newReplyDialog.textareaContainer {
+          min-height: unset;
+        }
+        textareaContainer,
+        gr-endpoint-decorator[name='reply-text'] {
+          display: flex;
+          width: 100%;
+        }
+        gr-endpoint-decorator[name='reply-text'] {
+          flex-direction: column;
+        }
+        #checkingStatusLabel,
+        #notLatestLabel {
+          margin-left: var(--spacing-l);
+        }
+        #checkingStatusLabel {
+          color: var(--deemphasized-text-color);
+          font-style: italic;
+        }
+        #notLatestLabel,
+        #savingLabel {
+          color: var(--error-text-color);
+        }
+        #savingLabel {
+          display: none;
+        }
+        #savingLabel.saving {
+          display: inline;
+        }
+        #pluginMessage {
+          color: var(--deemphasized-text-color);
+          margin-left: var(--spacing-l);
+          margin-bottom: var(--spacing-m);
+        }
+        #pluginMessage:empty {
+          display: none;
+        }
+        .attention .edit-attention-button {
+          vertical-align: top;
+          --gr-button-padding: 0px 4px;
+        }
+        .attention .edit-attention-button gr-icon {
+          color: inherit;
+          /* The line-height:26px hack (see below) requires us to do this.
            Normally the gr-icon would account for a proper positioning
            within the standard line-height:20px context. */
-        top: 5px;
-      }
-      .attention a,
-      .attention-detail a {
-        text-decoration: none;
-      }
-      .attentionSummary {
-        display: flex;
-        justify-content: space-between;
-      }
-      .attentionSummary {
-        /* The account label for selection is misbehaving currently: It consumes
+          top: 5px;
+        }
+        .attention a,
+        .attention-detail a {
+          text-decoration: none;
+        }
+        .attentionSummary {
+          display: flex;
+          justify-content: space-between;
+        }
+        .attentionSummary {
+          /* The account label for selection is misbehaving currently: It consumes
           26px height instead of 20px, which is the default line-height and thus
           the max that can be nicely fit into an inline layout flow. We
           acknowledge that using a fixed 26px value here is a hack and not a
           great solution. */
-        line-height: 26px;
-      }
-      .attentionSummary gr-account-label,
-      .attention-detail gr-account-label {
-        --account-max-length: 120px;
-        display: inline-block;
-        padding: var(--spacing-xs) var(--spacing-m);
-        user-select: none;
-        --label-border-radius: 8px;
-      }
-      .attentionSummary gr-account-label {
-        margin: 0 var(--spacing-xs);
-        line-height: var(--line-height-normal);
-        vertical-align: top;
-      }
-      .attention-detail .peopleListValues {
-        line-height: calc(var(--line-height-normal) + 10px);
-      }
-      .attention-detail gr-account-label {
-        line-height: var(--line-height-normal);
-      }
-      .attentionSummary gr-account-label:focus,
-      .attention-detail gr-account-label:focus {
-        outline: none;
-      }
-      .attentionSummary gr-account-label:hover,
-      .attention-detail gr-account-label:hover {
-        box-shadow: var(--elevation-level-1);
-        cursor: pointer;
-      }
-      .attention-detail .attentionDetailsTitle {
-        display: flex;
-        justify-content: space-between;
-      }
-      .attention-detail .selectUsers {
-        color: var(--deemphasized-text-color);
-        margin-bottom: var(--spacing-m);
-      }
-      .attentionTip {
-        padding: var(--spacing-m);
-        border: 1px solid var(--border-color);
-        border-radius: var(--border-radius);
-        margin-top: var(--spacing-m);
-        background-color: var(--line-item-highlight-color);
-      }
-      .attentionTip div gr-icon {
-        margin-right: var(--spacing-s);
-      }
-      .patchsetLevelContainer {
-        width: 80ch;
-        border-radius: var(--border-radius);
-        box-shadow: var(--elevation-level-2);
-      }
-      .patchsetLevelContainer.resolved {
-        background-color: var(--comment-background-color);
-      }
-      .patchsetLevelContainer.unresolved {
-        background-color: var(--unresolved-comment-background-color);
-      }
-      .privateVisiblityInfo {
-        display: flex;
-        justify-content: center;
-        background-color: var(--info-background);
-        padding: var(--spacing-s) 0;
-      }
-      .privateVisiblityInfo gr-icon {
-        margin-right: var(--spacing-m);
-        color: var(--info-foreground);
-      }
-    `,
-  ];
+          line-height: 26px;
+        }
+        .attentionSummary gr-account-label,
+        .attention-detail gr-account-label {
+          --account-max-length: 120px;
+          display: inline-block;
+          padding: var(--spacing-xs) var(--spacing-m);
+          user-select: none;
+          --label-border-radius: 8px;
+        }
+        .attentionSummary gr-account-label {
+          margin: 0 var(--spacing-xs);
+          line-height: var(--line-height-normal);
+          vertical-align: top;
+        }
+        .attention-detail .peopleListValues {
+          line-height: calc(var(--line-height-normal) + 10px);
+        }
+        .attention-detail gr-account-label {
+          line-height: var(--line-height-normal);
+        }
+        .attentionSummary gr-account-label:focus,
+        .attention-detail gr-account-label:focus {
+          outline: none;
+        }
+        .attentionSummary gr-account-label:hover,
+        .attention-detail gr-account-label:hover {
+          box-shadow: var(--elevation-level-1);
+          cursor: pointer;
+        }
+        .attention-detail .attentionDetailsTitle {
+          display: flex;
+          justify-content: space-between;
+        }
+        .attention-detail .selectUsers {
+          color: var(--deemphasized-text-color);
+          margin-bottom: var(--spacing-m);
+        }
+        .attentionTip {
+          padding: var(--spacing-m);
+          border: 1px solid var(--border-color);
+          border-radius: var(--border-radius);
+          margin-top: var(--spacing-m);
+          background-color: var(--line-item-highlight-color);
+        }
+        .attentionTip div gr-icon {
+          margin-right: var(--spacing-s);
+        }
+        .patchsetLevelContainer {
+          width: 80ch;
+          border-radius: var(--border-radius);
+          box-shadow: var(--elevation-level-2);
+        }
+        .patchsetLevelContainer.resolved {
+          background-color: var(--comment-background-color);
+        }
+        .patchsetLevelContainer.unresolved {
+          background-color: var(--unresolved-comment-background-color);
+        }
+        .privateVisiblityInfo {
+          display: flex;
+          justify-content: center;
+          background-color: var(--info-background);
+          padding: var(--spacing-s) 0;
+        }
+        .privateVisiblityInfo gr-icon {
+          margin-right: var(--spacing-m);
+          color: var(--info-foreground);
+        }
+      `,
+    ];
+  }
 
   constructor() {
     super();
diff --git a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
index 7723c66..02d5124 100644
--- a/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
+++ b/polygerrit-ui/app/elements/diff/gr-apply-fix-dialog/gr-apply-fix-dialog.ts
@@ -149,38 +149,40 @@
     );
   }
 
-  static override styles = [
-    sharedStyles,
-    modalStyles,
-    css`
-      .diffContainer {
-        padding: var(--spacing-l) 0;
-        border-bottom: 1px solid var(--border-color);
-      }
-      .file-name {
-        display: block;
-        padding: var(--spacing-s) var(--spacing-l);
-        background-color: var(--background-color-secondary);
-        border-bottom: 1px solid var(--border-color);
-      }
-      gr-button {
-        margin-left: var(--spacing-m);
-      }
-      .fix-picker {
-        display: flex;
-        align-items: center;
-        margin-right: var(--spacing-l);
-      }
-      .info {
-        background-color: var(--info-background);
-        padding: var(--spacing-l) var(--spacing-xl);
-      }
-      .info gr-icon {
-        color: var(--selected-foreground);
-        margin-right: var(--spacing-xl);
-      }
-    `,
-  ];
+  static override get styles() {
+    return [
+      sharedStyles,
+      modalStyles,
+      css`
+        .diffContainer {
+          padding: var(--spacing-l) 0;
+          border-bottom: 1px solid var(--border-color);
+        }
+        .file-name {
+          display: block;
+          padding: var(--spacing-s) var(--spacing-l);
+          background-color: var(--background-color-secondary);
+          border-bottom: 1px solid var(--border-color);
+        }
+        gr-button {
+          margin-left: var(--spacing-m);
+        }
+        .fix-picker {
+          display: flex;
+          align-items: center;
+          margin-right: var(--spacing-l);
+        }
+        .info {
+          background-color: var(--info-background);
+          padding: var(--spacing-l) var(--spacing-xl);
+        }
+        .info gr-icon {
+          color: var(--selected-foreground);
+          margin-right: var(--spacing-xl);
+        }
+      `,
+    ];
+  }
 
   override render() {
     return html`
diff --git a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.ts b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.ts
index 1d46841..d8c3abe 100644
--- a/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.ts
+++ b/polygerrit-ui/app/elements/diff/gr-diff-mode-selector/gr-diff-mode-selector.ts
@@ -59,21 +59,23 @@
     super.disconnectedCallback();
   }
 
-  static override styles = [
-    sharedStyles,
-    css`
-      :host {
-        /* Used to remove horizontal whitespace between the icons. */
-        display: flex;
-      }
-      gr-button.selected gr-icon {
-        color: var(--link-color);
-      }
-      gr-icon {
-        font-size: 1.3rem;
-      }
-    `,
-  ];
+  static override get styles() {
+    return [
+      sharedStyles,
+      css`
+        :host {
+          /* Used to remove horizontal whitespace between the icons. */
+          display: flex;
+        }
+        gr-button.selected gr-icon {
+          color: var(--link-color);
+        }
+        gr-icon {
+          font-size: 1.3rem;
+        }
+      `,
+    ];
+  }
 
   override render() {
     return html`
diff --git a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts
index 89513e3..747f3eb 100644
--- a/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts
+++ b/polygerrit-ui/app/elements/settings/gr-account-info/gr-account-info.ts
@@ -60,41 +60,43 @@
 
   private readonly restApiService = getAppContext().restApiService;
 
-  static override styles = [
-    sharedStyles,
-    formStyles,
-    css`
-      gr-avatar {
-        height: 120px;
-        width: 120px;
-        margin-right: var(--spacing-xs);
-        vertical-align: -0.25em;
-      }
-      div section.hide {
-        display: none;
-      }
-      gr-hovercard-account-contents {
-        display: block;
-        max-width: 600px;
-        margin-top: var(--spacing-m);
-        background: var(--dialog-background-color);
-        border: 1px solid var(--border-color);
-        border-radius: var(--border-radius);
-        box-shadow: var(--elevation-level-5);
-      }
-      iron-autogrow-textarea {
-        background-color: var(--view-background-color);
-        color: var(--primary-text-color);
-      }
-      .lengthCounter {
-        font-weight: var(--font-weight-normal);
-      }
-      p {
-        max-width: 65ch;
-        margin-bottom: var(--spacing-m);
-      }
-    `,
-  ];
+  static override get styles() {
+    return [
+      sharedStyles,
+      formStyles,
+      css`
+        gr-avatar {
+          height: 120px;
+          width: 120px;
+          margin-right: var(--spacing-xs);
+          vertical-align: -0.25em;
+        }
+        div section.hide {
+          display: none;
+        }
+        gr-hovercard-account-contents {
+          display: block;
+          max-width: 600px;
+          margin-top: var(--spacing-m);
+          background: var(--dialog-background-color);
+          border: 1px solid var(--border-color);
+          border-radius: var(--border-radius);
+          box-shadow: var(--elevation-level-5);
+        }
+        iron-autogrow-textarea {
+          background-color: var(--view-background-color);
+          color: var(--primary-text-color);
+        }
+        .lengthCounter {
+          font-weight: var(--font-weight-normal);
+        }
+        p {
+          max-width: 65ch;
+          margin-bottom: var(--spacing-m);
+        }
+      `,
+    ];
+  }
 
   override render() {
     if (!this.account || this.loading) return nothing;
diff --git a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.ts b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.ts
index 53548f8..568e7c3 100644
--- a/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-change-table-editor/gr-change-table-editor.ts
@@ -36,28 +36,30 @@
 
   private readonly getConfigModel = resolve(this, configModelToken);
 
-  static override styles = [
-    sharedStyles,
-    formStyles,
-    css`
-      #changeCols {
-        width: auto;
-      }
-      #changeCols .visibleHeader {
-        text-align: center;
-      }
-      .checkboxContainer {
-        cursor: pointer;
-        text-align: center;
-      }
-      .checkboxContainer input {
-        cursor: pointer;
-      }
-      .checkboxContainer:hover {
-        outline: 1px solid var(--border-color);
-      }
-    `,
-  ];
+  static override get styles() {
+    return [
+      sharedStyles,
+      formStyles,
+      css`
+        #changeCols {
+          width: auto;
+        }
+        #changeCols .visibleHeader {
+          text-align: center;
+        }
+        .checkboxContainer {
+          cursor: pointer;
+          text-align: center;
+        }
+        .checkboxContainer input {
+          cursor: pointer;
+        }
+        .checkboxContainer:hover {
+          outline: 1px solid var(--border-color);
+        }
+      `,
+    ];
+  }
 
   constructor() {
     super();
diff --git a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.ts b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.ts
index b9f59bf..1c4fd30 100644
--- a/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-email-editor/gr-email-editor.ts
@@ -29,35 +29,37 @@
 
   readonly restApiService = getAppContext().restApiService;
 
-  static override styles = [
-    sharedStyles,
-    formStyles,
-    css`
-      th {
-        color: var(--deemphasized-text-color);
-        text-align: left;
-      }
-      #emailTable .emailColumn {
-        min-width: 32.5em;
-        width: auto;
-      }
-      #emailTable .preferredHeader {
-        text-align: center;
-        width: 6em;
-      }
-      #emailTable .preferredControl {
-        cursor: pointer;
-        height: auto;
-        text-align: center;
-      }
-      #emailTable .preferredControl .preferredRadio {
-        height: auto;
-      }
-      .preferredControl:hover {
-        outline: 1px solid var(--border-color);
-      }
-    `,
-  ];
+  static override get styles() {
+    return [
+      sharedStyles,
+      formStyles,
+      css`
+        th {
+          color: var(--deemphasized-text-color);
+          text-align: left;
+        }
+        #emailTable .emailColumn {
+          min-width: 32.5em;
+          width: auto;
+        }
+        #emailTable .preferredHeader {
+          text-align: center;
+          width: 6em;
+        }
+        #emailTable .preferredControl {
+          cursor: pointer;
+          height: auto;
+          text-align: center;
+        }
+        #emailTable .preferredControl .preferredRadio {
+          height: auto;
+        }
+        .preferredControl:hover {
+          outline: 1px solid var(--border-color);
+        }
+      `,
+    ];
+  }
 
   override render() {
     return html`<div class="gr-form-styles">
diff --git a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.ts b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.ts
index 32b32e2..da1f758 100644
--- a/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-gpg-editor/gr-gpg-editor.ts
@@ -49,34 +49,36 @@
 
   private readonly restApiService = getAppContext().restApiService;
 
-  static override styles = [
-    formStyles,
-    sharedStyles,
-    modalStyles,
-    css`
-      .keyHeader {
-        width: 9em;
-      }
-      .userIdHeader {
-        width: 15em;
-      }
-      #viewKeyModal {
-        padding: var(--spacing-xxl);
-        width: 50em;
-      }
-      .closeButton {
-        bottom: 2em;
-        position: absolute;
-        right: 2em;
-      }
-      #existing {
-        margin-bottom: var(--spacing-l);
-      }
-      iron-autogrow-textarea {
-        background-color: var(--view-background-color);
-      }
-    `,
-  ];
+  static override get styles() {
+    return [
+      formStyles,
+      sharedStyles,
+      modalStyles,
+      css`
+        .keyHeader {
+          width: 9em;
+        }
+        .userIdHeader {
+          width: 15em;
+        }
+        #viewKeyModal {
+          padding: var(--spacing-xxl);
+          width: 50em;
+        }
+        .closeButton {
+          bottom: 2em;
+          position: absolute;
+          right: 2em;
+        }
+        #existing {
+          margin-bottom: var(--spacing-l);
+        }
+        iron-autogrow-textarea {
+          background-color: var(--view-background-color);
+        }
+      `,
+    ];
+  }
 
   override render() {
     return html`
diff --git a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.ts b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.ts
index 7f67ea8..4c8e8da 100644
--- a/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.ts
+++ b/polygerrit-ui/app/elements/settings/gr-identities/gr-identities.ts
@@ -36,37 +36,39 @@
 
   private readonly restApiService = getAppContext().restApiService;
 
-  static override styles = [
-    sharedStyles,
-    formStyles,
-    modalStyles,
-    css`
-      tr th.emailAddressHeader,
-      tr th.identityHeader {
-        width: 15em;
-        padding: 0 10px;
-      }
-      tr td.statusColumn,
-      tr td.emailAddressColumn,
-      tr td.identityColumn {
-        word-break: break-word;
-      }
-      tr td.emailAddressColumn,
-      tr td.identityColumn {
-        padding: 4px 10px;
-        width: 15em;
-      }
-      .deleteButton {
-        float: right;
-      }
-      .deleteButton:not(.show) {
-        display: none;
-      }
-      .space {
-        margin-bottom: var(--spacing-l);
-      }
-    `,
-  ];
+  static override get styles() {
+    return [
+      sharedStyles,
+      formStyles,
+      modalStyles,
+      css`
+        tr th.emailAddressHeader,
+        tr th.identityHeader {
+          width: 15em;
+          padding: 0 10px;
+        }
+        tr td.statusColumn,
+        tr td.emailAddressColumn,
+        tr td.identityColumn {
+          word-break: break-word;
+        }
+        tr td.emailAddressColumn,
+        tr td.identityColumn {
+          padding: 4px 10px;
+          width: 15em;
+        }
+        .deleteButton {
+          float: right;
+        }
+        .deleteButton:not(.show) {
+          display: none;
+        }
+        .space {
+          margin-bottom: var(--spacing-l);
+        }
+      `,
+    ];
+  }
 
   override render() {
     return html`<div class="gr-form-styles">
diff --git a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts
index 9c23857..b00529a 100644
--- a/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts
+++ b/polygerrit-ui/app/elements/settings/gr-menu-editor/gr-menu-editor.ts
@@ -48,31 +48,33 @@
     );
   }
 
-  static override styles = [
-    formStyles,
-    sharedStyles,
-    fontStyles,
-    menuPageStyles,
-    css`
-      .buttonColumn {
-        width: 2em;
-      }
-      .moveUpButton,
-      .moveDownButton {
-        width: 100%;
-      }
-      tbody tr:first-of-type td .moveUpButton,
-      tbody tr:last-of-type td .moveDownButton {
-        display: none;
-      }
-      td.urlCell {
-        word-break: break-word;
-      }
-      .newUrlInput {
-        min-width: 23em;
-      }
-    `,
-  ];
+  static override get styles() {
+    return [
+      formStyles,
+      sharedStyles,
+      fontStyles,
+      menuPageStyles,
+      css`
+        .buttonColumn {
+          width: 2em;
+        }
+        .moveUpButton,
+        .moveDownButton {
+          width: 100%;
+        }
+        tbody tr:first-of-type td .moveUpButton,
+        tbody tr:last-of-type td .moveDownButton {
+          display: none;
+        }
+        td.urlCell {
+          word-break: break-word;
+        }
+        .newUrlInput {
+          min-width: 23em;
+        }
+      `,
+    ];
+  }
 
   override render() {
     const unchanged = deepEqual(this.menuItems, this.originalPrefs.my);
diff --git a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts
index c6c023e..435eb44 100644
--- a/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts
+++ b/polygerrit-ui/app/elements/settings/gr-registration-dialog/gr-registration-dialog.ts
@@ -68,50 +68,52 @@
     }
   }
 
-  static override styles = [
-    sharedStyles,
-    formStyles,
-    css`
-      :host {
-        display: block;
-      }
-      main {
-        max-width: 46em;
-      }
-      :host(.loading) main {
-        display: none;
-      }
-      .loadingMessage {
-        display: none;
-        font-style: italic;
-      }
-      :host(.loading) .loadingMessage {
-        display: block;
-      }
-      hr {
-        margin-top: var(--spacing-l);
-        margin-bottom: var(--spacing-l);
-      }
-      header {
-        border-bottom: 1px solid var(--border-color);
-        font-weight: var(--font-weight-bold);
-        margin-bottom: var(--spacing-l);
-      }
-      .container {
-        padding: var(--spacing-m) var(--spacing-xl);
-      }
-      footer {
-        display: flex;
-        justify-content: flex-end;
-      }
-      footer gr-button {
-        margin-left: var(--spacing-l);
-      }
-      input {
-        width: 20em;
-      }
-    `,
-  ];
+  static override get styles() {
+    return [
+      sharedStyles,
+      formStyles,
+      css`
+        :host {
+          display: block;
+        }
+        main {
+          max-width: 46em;
+        }
+        :host(.loading) main {
+          display: none;
+        }
+        .loadingMessage {
+          display: none;
+          font-style: italic;
+        }
+        :host(.loading) .loadingMessage {
+          display: block;
+        }
+        hr {
+          margin-top: var(--spacing-l);
+          margin-bottom: var(--spacing-l);
+        }
+        header {
+          border-bottom: 1px solid var(--border-color);
+          font-weight: var(--font-weight-bold);
+          margin-bottom: var(--spacing-l);
+        }
+        .container {
+          padding: var(--spacing-m) var(--spacing-xl);
+        }
+        footer {
+          display: flex;
+          justify-content: flex-end;
+        }
+        footer gr-button {
+          margin-left: var(--spacing-l);
+        }
+        input {
+          width: 20em;
+        }
+      `,
+    ];
+  }
 
   override render() {
     return html`<div class="container gr-form-styles">
diff --git a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
index 24a18c9..29203d0 100644
--- a/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
+++ b/polygerrit-ui/app/elements/settings/gr-settings-view/gr-settings-view.ts
@@ -303,43 +303,45 @@
     });
   }
 
-  static override styles = [
-    sharedStyles,
-    paperStyles,
-    fontStyles,
-    formStyles,
-    menuPageStyles,
-    pageNavStyles,
-    css`
-      :host {
-        color: var(--primary-text-color);
-      }
-      h2 {
-        font-family: var(--header-font-family);
-        font-size: var(--font-size-h2);
-        font-weight: var(--font-weight-h2);
-        line-height: var(--line-height-h2);
-      }
-      .newEmailInput {
-        width: 20em;
-      }
-      #email {
-        margin-bottom: var(--spacing-l);
-      }
-      .filters p {
-        margin-bottom: var(--spacing-l);
-      }
-      .queryExample em {
-        color: violet;
-      }
-      .toggle {
-        align-items: center;
-        display: flex;
-        margin-bottom: var(--spacing-l);
-        margin-right: var(--spacing-l);
-      }
-    `,
-  ];
+  static override get styles() {
+    return [
+      sharedStyles,
+      paperStyles,
+      fontStyles,
+      formStyles,
+      menuPageStyles,
+      pageNavStyles,
+      css`
+        :host {
+          color: var(--primary-text-color);
+        }
+        h2 {
+          font-family: var(--header-font-family);
+          font-size: var(--font-size-h2);
+          font-weight: var(--font-weight-h2);
+          line-height: var(--line-height-h2);
+        }
+        .newEmailInput {
+          width: 20em;
+        }
+        #email {
+          margin-bottom: var(--spacing-l);
+        }
+        .filters p {
+          margin-bottom: var(--spacing-l);
+        }
+        .queryExample em {
+          color: violet;
+        }
+        .toggle {
+          align-items: center;
+          display: flex;
+          margin-bottom: var(--spacing-l);
+          margin-right: var(--spacing-l);
+        }
+      `,
+    ];
+  }
 
   override render() {
     const isLoading = this.loading || this.loading === undefined;
diff --git a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts
index 07209db..9045dd6 100644
--- a/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts
+++ b/polygerrit-ui/app/elements/shared/gr-account-list/gr-account-list.ts
@@ -158,32 +158,34 @@
     );
   }
 
-  static override styles = [
-    sharedStyles,
-    css`
-      gr-account-chip {
-        display: inline-block;
-        margin: var(--spacing-xs) var(--spacing-xs) var(--spacing-xs) 0;
-      }
-      gr-account-entry {
-        display: flex;
-        flex: 1;
-        min-width: 10em;
-        margin: var(--spacing-xs) var(--spacing-xs) var(--spacing-xs) 0;
-      }
-      .group {
-        --account-label-suffix: ' (group)';
-      }
-      .newlyAdded {
-        font-style: italic;
-      }
-      .list {
-        align-items: center;
-        display: flex;
-        flex-wrap: wrap;
-      }
-    `,
-  ];
+  static override get styles() {
+    return [
+      sharedStyles,
+      css`
+        gr-account-chip {
+          display: inline-block;
+          margin: var(--spacing-xs) var(--spacing-xs) var(--spacing-xs) 0;
+        }
+        gr-account-entry {
+          display: flex;
+          flex: 1;
+          min-width: 10em;
+          margin: var(--spacing-xs) var(--spacing-xs) var(--spacing-xs) 0;
+        }
+        .group {
+          --account-label-suffix: ' (group)';
+        }
+        .newlyAdded {
+          font-style: italic;
+        }
+        .list {
+          align-items: center;
+          display: flex;
+          flex-wrap: wrap;
+        }
+      `,
+    ];
+  }
 
   override render() {
     return html`<div class="list">
diff --git a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
index fd1311c..210b91c 100644
--- a/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
+++ b/polygerrit-ui/app/elements/shared/gr-autocomplete/gr-autocomplete.ts
@@ -201,59 +201,63 @@
       .inputElement as HTMLInputElement;
   }
 
-  static override styles = [
-    sharedStyles,
-    css`
-      paper-input.borderless {
-        border: none;
-        padding: 0;
-      }
-      paper-input {
-        background-color: var(--view-background-color);
-        color: var(--primary-text-color);
-        border: 1px solid var(--prominent-border-color, var(--border-color));
-        border-radius: var(--border-radius);
-        padding: var(--spacing-s);
-        --paper-input-container_-_padding: 0;
-        --paper-input-container-input_-_font-size: var(--font-size-normal);
-        --paper-input-container-input_-_line-height: var(--line-height-normal);
-        /* This is a hack for not being able to set height:0 on the underline
+  static override get styles() {
+    return [
+      sharedStyles,
+      css`
+        paper-input.borderless {
+          border: none;
+          padding: 0;
+        }
+        paper-input {
+          background-color: var(--view-background-color);
+          color: var(--primary-text-color);
+          border: 1px solid var(--prominent-border-color, var(--border-color));
+          border-radius: var(--border-radius);
+          padding: var(--spacing-s);
+          --paper-input-container_-_padding: 0;
+          --paper-input-container-input_-_font-size: var(--font-size-normal);
+          --paper-input-container-input_-_line-height: var(
+            --line-height-normal
+          );
+          /* This is a hack for not being able to set height:0 on the underline
             of a paper-input 2.2.3 element. All the underline fixes below only
             actually work in 3.x.x, so the height must be adjusted directly as
             a workaround until we are on Polymer 3. */
-        height: var(--line-height-normal);
-        --paper-input-container-underline-height: 0;
-        --paper-input-container-underline-wrapper-height: 0;
-        --paper-input-container-underline-focus-height: 0;
-        --paper-input-container-underline-legacy-height: 0;
-        --paper-input-container-underline_-_height: 0;
-        --paper-input-container-underline_-_display: none;
-        --paper-input-container-underline-focus_-_height: 0;
-        --paper-input-container-underline-focus_-_display: none;
-        --paper-input-container-underline-disabled_-_height: 0;
-        --paper-input-container-underline-disabled_-_display: none;
-        /* Hide label for input. The label is still visible for
+          height: var(--line-height-normal);
+          --paper-input-container-underline-height: 0;
+          --paper-input-container-underline-wrapper-height: 0;
+          --paper-input-container-underline-focus-height: 0;
+          --paper-input-container-underline-legacy-height: 0;
+          --paper-input-container-underline_-_height: 0;
+          --paper-input-container-underline_-_display: none;
+          --paper-input-container-underline-focus_-_height: 0;
+          --paper-input-container-underline-focus_-_display: none;
+          --paper-input-container-underline-disabled_-_height: 0;
+          --paper-input-container-underline-disabled_-_display: none;
+          /* Hide label for input. The label is still visible for
            screen readers. Workaround found at:
            https://github.com/PolymerElements/paper-input/issues/478 */
-        --paper-input-container-label_-_display: none;
-      }
-      paper-input.showBlueFocusBorder:focus {
-        border: 2px solid var(--input-focus-border-color);
-        /*
+          --paper-input-container-label_-_display: none;
+        }
+        paper-input.showBlueFocusBorder:focus {
+          border: 2px solid var(--input-focus-border-color);
+          /*
          * The goal is to have a thicker blue border when focused and a thinner
          * gray border when blurred. To avoid shifting neighboring elements
          * around when the border size changes, a negative margin is added to
          * compensate. box-sizing: border-box; will not work since there is
          * important padding to add around the content.
          */
-        margin: -1px;
-      }
-      paper-input.warnUncommitted {
-        --paper-input-container-input_-_color: var(--error-text-color);
-        --paper-input-container-input_-_font-size: inherit;
-      }
-    `,
-  ];
+          margin: -1px;
+        }
+        paper-input.warnUncommitted {
+          --paper-input-container-input_-_color: var(--error-text-color);
+          --paper-input-container-input_-_font-size: inherit;
+        }
+      `,
+    ];
+  }
 
   override connectedCallback() {
     super.connectedCallback();
diff --git a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
index e880531..405409d 100644
--- a/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
+++ b/polygerrit-ui/app/elements/shared/gr-formatted-text/gr-formatted-text.ts
@@ -56,67 +56,70 @@
    * Note: Do not use sharedStyles or other styles here that should not affect
    * the generated HTML of the markdown.
    */
-  static override styles = [
-    css`
-      a {
-        color: var(--link-color);
-      }
-      p,
-      ul,
-      code,
-      blockquote {
-        margin: 0 0 var(--spacing-m) 0;
-        max-width: var(--gr-formatted-text-prose-max-width, none);
-      }
-      p:last-child,
-      ul:last-child,
-      blockquote:last-child,
-      pre:last-child {
-        margin: 0;
-      }
-      blockquote {
-        border-left: var(--spacing-xxs) solid var(--comment-quote-marker-color);
-        padding: 0 var(--spacing-m);
-      }
-      code {
-        background-color: var(--background-color-secondary);
-        border: var(--spacing-xxs) solid var(--border-color);
-        display: block;
-        font-family: var(--monospace-font-family);
-        font-size: var(--font-size-code);
-        line-height: var(--line-height-mono);
-        margin: var(--spacing-m) 0;
-        padding: var(--spacing-xxs) var(--spacing-s);
-        overflow-x: auto;
-        /* Pre will preserve whitespace and line breaks but not wrap */
-        white-space: pre;
-      }
-      /* Non-multiline code elements need display:inline to shrink and not take
+  static override get styles() {
+    return [
+      css`
+        a {
+          color: var(--link-color);
+        }
+        p,
+        ul,
+        code,
+        blockquote {
+          margin: 0 0 var(--spacing-m) 0;
+          max-width: var(--gr-formatted-text-prose-max-width, none);
+        }
+        p:last-child,
+        ul:last-child,
+        blockquote:last-child,
+        pre:last-child {
+          margin: 0;
+        }
+        blockquote {
+          border-left: var(--spacing-xxs) solid
+            var(--comment-quote-marker-color);
+          padding: 0 var(--spacing-m);
+        }
+        code {
+          background-color: var(--background-color-secondary);
+          border: var(--spacing-xxs) solid var(--border-color);
+          display: block;
+          font-family: var(--monospace-font-family);
+          font-size: var(--font-size-code);
+          line-height: var(--line-height-mono);
+          margin: var(--spacing-m) 0;
+          padding: var(--spacing-xxs) var(--spacing-s);
+          overflow-x: auto;
+          /* Pre will preserve whitespace and line breaks but not wrap */
+          white-space: pre;
+        }
+        /* Non-multiline code elements need display:inline to shrink and not take
          a whole row */
-      :not(pre) > code {
-        display: inline;
-      }
-      li {
-        margin-left: var(--spacing-xl);
-      }
-      gr-account-chip {
-        display: inline;
-      }
-      .plaintext {
-        font: inherit;
-        white-space: var(--linked-text-white-space, pre-wrap);
-        word-wrap: var(--linked-text-word-wrap, break-word);
-      }
-      .markdown-html {
-        /* code overrides white-space to pre, everything else should wrap as
+        :not(pre) > code {
+          display: inline;
+        }
+        li {
+          margin-left: var(--spacing-xl);
+        }
+        gr-account-chip {
+          display: inline;
+        }
+        .plaintext {
+          font: inherit;
+          white-space: var(--linked-text-white-space, pre-wrap);
+          word-wrap: var(--linked-text-word-wrap, break-word);
+        }
+        .markdown-html {
+          /* code overrides white-space to pre, everything else should wrap as
            normal. */
-        white-space: normal;
-        /* prose will automatically wrap but inline <code> blocks won't and we
+          white-space: normal;
+          /* prose will automatically wrap but inline <code> blocks won't and we
            should overflow in that case rather than wrapping or leaking out */
-        overflow-x: auto;
-      }
-    `,
-  ];
+          overflow-x: auto;
+        }
+      `,
+    ];
+  }
 
   constructor() {
     super();
diff --git a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
index 95f1b8a..c29417e 100644
--- a/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
+++ b/polygerrit-ui/app/elements/shared/gr-textarea/gr-textarea.ts
@@ -175,53 +175,55 @@
     }
   }
 
-  static override styles = [
-    sharedStyles,
-    css`
-      :host {
-        display: flex;
-        position: relative;
-      }
-      :host(.monospace) {
-        font-family: var(--monospace-font-family);
-        font-size: var(--font-size-mono);
-        line-height: var(--line-height-mono);
-        font-weight: var(--font-weight-normal);
-      }
-      :host(.code) {
-        font-family: var(--monospace-font-family);
-        font-size: var(--font-size-code);
-        /* usually 16px = 12px + 4px */
-        line-height: calc(var(--font-size-code) + var(--spacing-s));
-        font-weight: var(--font-weight-normal);
-      }
-      #emojiSuggestions {
-        font-family: var(--font-family);
-      }
-      #textarea {
-        background-color: var(--view-background-color);
-        width: 100%;
-      }
-      #hiddenText #emojiSuggestions {
-        visibility: visible;
-        white-space: normal;
-      }
-      iron-autogrow-textarea {
-        position: relative;
-      }
-      #textarea.noBorder {
-        border: none;
-      }
-      #hiddenText {
-        display: block;
-        float: left;
-        position: absolute;
-        visibility: hidden;
-        width: 100%;
-        white-space: pre-wrap;
-      }
-    `,
-  ];
+  static override get styles() {
+    return [
+      sharedStyles,
+      css`
+        :host {
+          display: flex;
+          position: relative;
+        }
+        :host(.monospace) {
+          font-family: var(--monospace-font-family);
+          font-size: var(--font-size-mono);
+          line-height: var(--line-height-mono);
+          font-weight: var(--font-weight-normal);
+        }
+        :host(.code) {
+          font-family: var(--monospace-font-family);
+          font-size: var(--font-size-code);
+          /* usually 16px = 12px + 4px */
+          line-height: calc(var(--font-size-code) + var(--spacing-s));
+          font-weight: var(--font-weight-normal);
+        }
+        #emojiSuggestions {
+          font-family: var(--font-family);
+        }
+        #textarea {
+          background-color: var(--view-background-color);
+          width: 100%;
+        }
+        #hiddenText #emojiSuggestions {
+          visibility: visible;
+          white-space: normal;
+        }
+        iron-autogrow-textarea {
+          position: relative;
+        }
+        #textarea.noBorder {
+          border: none;
+        }
+        #hiddenText {
+          display: block;
+          float: left;
+          position: absolute;
+          visibility: hidden;
+          width: 100%;
+          white-space: pre-wrap;
+        }
+      `,
+    ];
+  }
 
   override render() {
     return html`
diff --git a/polygerrit-ui/app/elements/shared/gr-user-suggestion-fix/gr-user-suggestion-fix.ts b/polygerrit-ui/app/elements/shared/gr-user-suggestion-fix/gr-user-suggestion-fix.ts
index ff068a7..ea67661 100644
--- a/polygerrit-ui/app/elements/shared/gr-user-suggestion-fix/gr-user-suggestion-fix.ts
+++ b/polygerrit-ui/app/elements/shared/gr-user-suggestion-fix/gr-user-suggestion-fix.ts
@@ -25,42 +25,44 @@
 export class GrUserSuggetionFix extends LitElement {
   private readonly flagsService = getAppContext().flagsService;
 
-  static override styles = [
-    css`
-      .header {
-        background-color: var(--background-color-primary);
-        border: 1px solid var(--border-color);
-        padding: var(--spacing-xs) var(--spacing-xl);
-        display: flex;
-        align-items: center;
-        border-top-left-radius: var(--border-radius);
-        border-top-right-radius: var(--border-radius);
-      }
-      .header .title {
-        flex: 1;
-      }
-      .copyButton {
-        margin-right: var(--spacing-l);
-      }
-      code {
-        max-width: var(--gr-formatted-text-prose-max-width, none);
-        background-color: var(--background-color-secondary);
-        border: 1px solid var(--border-color);
-        border-top: 0;
-        display: block;
-        font-family: var(--monospace-font-family);
-        font-size: var(--font-size-code);
-        line-height: var(--line-height-mono);
-        margin-bottom: var(--spacing-m);
-        padding: var(--spacing-xxs) var(--spacing-s);
-        overflow-x: auto;
-        /* Pre will preserve whitespace and line breaks but not wrap */
-        white-space: pre;
-        border-bottom-left-radius: var(--border-radius);
-        border-bottom-right-radius: var(--border-radius);
-      }
-    `,
-  ];
+  static override get styles() {
+    return [
+      css`
+        .header {
+          background-color: var(--background-color-primary);
+          border: 1px solid var(--border-color);
+          padding: var(--spacing-xs) var(--spacing-xl);
+          display: flex;
+          align-items: center;
+          border-top-left-radius: var(--border-radius);
+          border-top-right-radius: var(--border-radius);
+        }
+        .header .title {
+          flex: 1;
+        }
+        .copyButton {
+          margin-right: var(--spacing-l);
+        }
+        code {
+          max-width: var(--gr-formatted-text-prose-max-width, none);
+          background-color: var(--background-color-secondary);
+          border: 1px solid var(--border-color);
+          border-top: 0;
+          display: block;
+          font-family: var(--monospace-font-family);
+          font-size: var(--font-size-code);
+          line-height: var(--line-height-mono);
+          margin-bottom: var(--spacing-m);
+          padding: var(--spacing-xxs) var(--spacing-s);
+          overflow-x: auto;
+          /* Pre will preserve whitespace and line breaks but not wrap */
+          white-space: pre;
+          border-bottom-left-radius: var(--border-radius);
+          border-bottom-right-radius: var(--border-radius);
+        }
+      `,
+    ];
+  }
 
   override render() {
     if (!this.flagsService.isEnabled(KnownExperimentId.SUGGEST_EDIT)) {
diff --git a/polygerrit-ui/app/embed/diff-old/gr-context-controls/gr-context-controls.ts b/polygerrit-ui/app/embed/diff-old/gr-context-controls/gr-context-controls.ts
index 5695f4d..e4afd23 100644
--- a/polygerrit-ui/app/embed/diff-old/gr-context-controls/gr-context-controls.ts
+++ b/polygerrit-ui/app/embed/diff-old/gr-context-controls/gr-context-controls.ts
@@ -99,112 +99,123 @@
     linesToExpand: number;
   }>();
 
-  static override styles = css`
-    :host {
-      display: flex;
-      justify-content: center;
-      flex-direction: column;
-      position: relative;
-    }
+  static override get styles() {
+    return [
+      css`
+        :host {
+          display: flex;
+          justify-content: center;
+          flex-direction: column;
+          position: relative;
+        }
 
-    :host([showConfig='above']) {
-      justify-content: flex-end;
-      margin-top: calc(-1px - var(--line-height-normal) - var(--spacing-s));
-      margin-bottom: var(--gr-context-controls-margin-bottom);
-      height: calc(var(--line-height-normal) + var(--spacing-s));
-      .horizontalFlex {
-        align-items: end;
-      }
-    }
+        :host([showConfig='above']) {
+          justify-content: flex-end;
+          margin-top: calc(-1px - var(--line-height-normal) - var(--spacing-s));
+          margin-bottom: var(--gr-context-controls-margin-bottom);
+          height: calc(var(--line-height-normal) + var(--spacing-s));
+          .horizontalFlex {
+            align-items: end;
+          }
+        }
 
-    :host([showConfig='below']) {
-      justify-content: flex-start;
-      margin-top: 1px;
-      margin-bottom: calc(0px - var(--line-height-normal) - var(--spacing-s));
-      .horizontalFlex {
-        align-items: start;
-      }
-    }
+        :host([showConfig='below']) {
+          justify-content: flex-start;
+          margin-top: 1px;
+          margin-bottom: calc(
+            0px - var(--line-height-normal) - var(--spacing-s)
+          );
+          .horizontalFlex {
+            align-items: start;
+          }
+        }
 
-    :host([showConfig='both']) {
-      margin-top: calc(0px - var(--line-height-normal) - var(--spacing-s));
-      margin-bottom: calc(0px - var(--line-height-normal) - var(--spacing-s));
-      height: calc(
-        2 * var(--line-height-normal) + 2 * var(--spacing-s) +
-          var(--divider-height)
-      );
-      .horizontalFlex {
-        align-items: center;
-      }
-    }
+        :host([showConfig='both']) {
+          margin-top: calc(0px - var(--line-height-normal) - var(--spacing-s));
+          margin-bottom: calc(
+            0px - var(--line-height-normal) - var(--spacing-s)
+          );
+          height: calc(
+            2 * var(--line-height-normal) + 2 * var(--spacing-s) +
+              var(--divider-height)
+          );
+          .horizontalFlex {
+            align-items: center;
+          }
+        }
 
-    .contextControlButton {
-      background-color: var(--default-button-background-color);
-      font: var(--context-control-button-font, inherit);
-    }
+        .contextControlButton {
+          background-color: var(--default-button-background-color);
+          font: var(--context-control-button-font, inherit);
+        }
 
-    paper-button {
-      text-transform: none;
-      align-items: center;
-      background-color: var(--background-color);
-      font-family: inherit;
-      margin: var(--margin, 0);
-      min-width: var(--border, 0);
-      color: var(--diff-context-control-color);
-      border: solid var(--border-color);
-      border-width: 1px;
-      border-radius: var(--border-radius);
-      padding: var(--spacing-s) var(--spacing-l);
-    }
+        paper-button {
+          text-transform: none;
+          align-items: center;
+          background-color: var(--background-color);
+          font-family: inherit;
+          margin: var(--margin, 0);
+          min-width: var(--border, 0);
+          color: var(--diff-context-control-color);
+          border: solid var(--border-color);
+          border-width: 1px;
+          border-radius: var(--border-radius);
+          padding: var(--spacing-s) var(--spacing-l);
+        }
 
-    paper-button:hover {
-      /* same as defined in gr-button */
-      background: rgba(0, 0, 0, 0.12);
-    }
-    paper-button:focus-visible {
-      /* paper-button sets this to 0, thus preventing focus-based styling. */
-      outline-width: 1px;
-    }
+        paper-button:hover {
+          /* same as defined in gr-button */
+          background: rgba(0, 0, 0, 0.12);
+        }
+        paper-button:focus-visible {
+          /* paper-button sets this to 0, thus preventing focus-based styling. */
+          outline-width: 1px;
+        }
 
-    .aboveBelowButtons {
-      display: flex;
-      flex-direction: column;
-      justify-content: center;
-      margin-left: var(--spacing-m);
-      position: relative;
-    }
-    .aboveBelowButtons:first-child {
-      margin-left: 0;
-      /* Places a default background layer behind the "all button" that can have opacity */
-      background-color: var(--default-button-background-color);
-    }
+        .aboveBelowButtons {
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          margin-left: var(--spacing-m);
+          position: relative;
+        }
+        .aboveBelowButtons:first-child {
+          margin-left: 0;
+          /* Places a default background layer behind the "all button" that can have opacity */
+          background-color: var(--default-button-background-color);
+        }
 
-    .horizontalFlex {
-      display: flex;
-      justify-content: center;
-      align-items: var(--gr-context-controls-horizontal-align-items, center);
-    }
+        .horizontalFlex {
+          display: flex;
+          justify-content: center;
+          align-items: var(
+            --gr-context-controls-horizontal-align-items,
+            center
+          );
+        }
 
-    .aboveButton {
-      border-bottom-width: 0;
-      border-bottom-right-radius: 0;
-      border-bottom-left-radius: 0;
-      padding: var(--spacing-xxs) var(--spacing-l);
-    }
-    .belowButton {
-      border-top-width: 0;
-      border-top-left-radius: 0;
-      border-top-right-radius: 0;
-      padding: var(--spacing-xxs) var(--spacing-l);
-      margin-top: calc(var(--divider-height) + 2 * var(--spacing-xxs));
-    }
-    .belowButton:first-child {
-      margin-top: 0;
-    }
-    .breadcrumbTooltip {
-      white-space: nowrap;
-    }
-  `;
+        .aboveButton {
+          border-bottom-width: 0;
+          border-bottom-right-radius: 0;
+          border-bottom-left-radius: 0;
+          padding: var(--spacing-xxs) var(--spacing-l);
+        }
+        .belowButton {
+          border-top-width: 0;
+          border-top-left-radius: 0;
+          border-top-right-radius: 0;
+          padding: var(--spacing-xxs) var(--spacing-l);
+          margin-top: calc(var(--divider-height) + 2 * var(--spacing-xxs));
+        }
+        .belowButton:first-child {
+          margin-top: 0;
+        }
+        .breadcrumbTooltip {
+          white-space: nowrap;
+        }
+      `,
+    ];
+  }
 
   constructor() {
     super();
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff.ts b/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff.ts
index 2aa8096..0da3522 100644
--- a/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff.ts
+++ b/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff.ts
@@ -374,6 +374,7 @@
 
   private renderContainer() {
     const cssClasses = {
+      oldDiff: true,
       diffContainer: true,
       unified: this.viewMode === DiffViewMode.UNIFIED,
       sideBySide: this.viewMode === DiffViewMode.SIDE_BY_SIDE,
diff --git a/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff_test.ts b/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff_test.ts
index 645a64a..af3a492 100644
--- a/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff_test.ts
+++ b/polygerrit-ui/app/embed/diff-old/gr-diff/gr-diff_test.ts
@@ -61,7 +61,7 @@
       assert.shadowDom.equal(
         element,
         /* HTML */ `
-          <div class="diffContainer sideBySide">
+          <div class="diffContainer oldDiff sideBySide">
             <table id="diffTable"></table>
           </div>
         `
@@ -77,7 +77,7 @@
       assert.shadowDom.equal(
         element,
         /* HTML */ `
-          <div class="diffContainer unified">
+          <div class="diffContainer oldDiff unified">
             <table class="selected-right" id="diffTable">
               <colgroup>
                 <col class="blame gr-diff" />
@@ -1343,7 +1343,7 @@
       assert.shadowDom.equal(
         element,
         /* HTML */ `
-          <div class="diffContainer sideBySide">
+          <div class="diffContainer oldDiff sideBySide">
             <table class="selected-right" id="diffTable">
               <colgroup>
                 <col class="blame gr-diff" />
@@ -3141,7 +3141,7 @@
         assert.shadowDom.equal(
           element,
           /* HTML */ `
-            <div class="diffContainer sideBySide">
+            <div class="diffContainer oldDiff sideBySide">
               <gr-diff-section class="left-FILE right-FILE"> </gr-diff-section>
               <gr-diff-row class="left-FILE right-FILE"> </gr-diff-row>
               <table class="selected-right" id="diffTable">
diff --git a/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls.ts b/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls.ts
index 43c8113..b2c0fcb 100644
--- a/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls.ts
+++ b/polygerrit-ui/app/embed/diff/gr-context-controls/gr-context-controls.ts
@@ -99,112 +99,123 @@
     linesToExpand: number;
   }>();
 
-  static override styles = css`
-    :host {
-      display: flex;
-      justify-content: center;
-      flex-direction: column;
-      position: relative;
-    }
+  static override get styles() {
+    return [
+      css`
+        :host {
+          display: flex;
+          justify-content: center;
+          flex-direction: column;
+          position: relative;
+        }
 
-    :host([showConfig='above']) {
-      justify-content: flex-end;
-      margin-top: calc(-1px - var(--line-height-normal) - var(--spacing-s));
-      margin-bottom: var(--gr-context-controls-margin-bottom);
-      height: calc(var(--line-height-normal) + var(--spacing-s));
-      .horizontalFlex {
-        align-items: end;
-      }
-    }
+        :host([showConfig='above']) {
+          justify-content: flex-end;
+          margin-top: calc(-1px - var(--line-height-normal) - var(--spacing-s));
+          margin-bottom: var(--gr-context-controls-margin-bottom);
+          height: calc(var(--line-height-normal) + var(--spacing-s));
+          .horizontalFlex {
+            align-items: end;
+          }
+        }
 
-    :host([showConfig='below']) {
-      justify-content: flex-start;
-      margin-top: 1px;
-      margin-bottom: calc(0px - var(--line-height-normal) - var(--spacing-s));
-      .horizontalFlex {
-        align-items: start;
-      }
-    }
+        :host([showConfig='below']) {
+          justify-content: flex-start;
+          margin-top: 1px;
+          margin-bottom: calc(
+            0px - var(--line-height-normal) - var(--spacing-s)
+          );
+          .horizontalFlex {
+            align-items: start;
+          }
+        }
 
-    :host([showConfig='both']) {
-      margin-top: calc(0px - var(--line-height-normal) - var(--spacing-s));
-      margin-bottom: calc(0px - var(--line-height-normal) - var(--spacing-s));
-      height: calc(
-        2 * var(--line-height-normal) + 2 * var(--spacing-s) +
-          var(--divider-height)
-      );
-      .horizontalFlex {
-        align-items: center;
-      }
-    }
+        :host([showConfig='both']) {
+          margin-top: calc(0px - var(--line-height-normal) - var(--spacing-s));
+          margin-bottom: calc(
+            0px - var(--line-height-normal) - var(--spacing-s)
+          );
+          height: calc(
+            2 * var(--line-height-normal) + 2 * var(--spacing-s) +
+              var(--divider-height)
+          );
+          .horizontalFlex {
+            align-items: center;
+          }
+        }
 
-    .contextControlButton {
-      background-color: var(--default-button-background-color);
-      font: var(--context-control-button-font, inherit);
-    }
+        .contextControlButton {
+          background-color: var(--default-button-background-color);
+          font: var(--context-control-button-font, inherit);
+        }
 
-    paper-button {
-      text-transform: none;
-      align-items: center;
-      background-color: var(--background-color);
-      font-family: inherit;
-      margin: var(--margin, 0);
-      min-width: var(--border, 0);
-      color: var(--diff-context-control-color);
-      border: solid var(--border-color);
-      border-width: 1px;
-      border-radius: var(--border-radius);
-      padding: var(--spacing-s) var(--spacing-l);
-    }
+        paper-button {
+          text-transform: none;
+          align-items: center;
+          background-color: var(--background-color);
+          font-family: inherit;
+          margin: var(--margin, 0);
+          min-width: var(--border, 0);
+          color: var(--diff-context-control-color);
+          border: solid var(--border-color);
+          border-width: 1px;
+          border-radius: var(--border-radius);
+          padding: var(--spacing-s) var(--spacing-l);
+        }
 
-    paper-button:hover {
-      /* same as defined in gr-button */
-      background: rgba(0, 0, 0, 0.12);
-    }
-    paper-button:focus-visible {
-      /* paper-button sets this to 0, thus preventing focus-based styling. */
-      outline-width: 1px;
-    }
+        paper-button:hover {
+          /* same as defined in gr-button */
+          background: rgba(0, 0, 0, 0.12);
+        }
+        paper-button:focus-visible {
+          /* paper-button sets this to 0, thus preventing focus-based styling. */
+          outline-width: 1px;
+        }
 
-    .aboveBelowButtons {
-      display: flex;
-      flex-direction: column;
-      justify-content: center;
-      margin-left: var(--spacing-m);
-      position: relative;
-    }
-    .aboveBelowButtons:first-child {
-      margin-left: 0;
-      /* Places a default background layer behind the "all button" that can have opacity */
-      background-color: var(--default-button-background-color);
-    }
+        .aboveBelowButtons {
+          display: flex;
+          flex-direction: column;
+          justify-content: center;
+          margin-left: var(--spacing-m);
+          position: relative;
+        }
+        .aboveBelowButtons:first-child {
+          margin-left: 0;
+          /* Places a default background layer behind the "all button" that can have opacity */
+          background-color: var(--default-button-background-color);
+        }
 
-    .horizontalFlex {
-      display: flex;
-      justify-content: center;
-      align-items: var(--gr-context-controls-horizontal-align-items, center);
-    }
+        .horizontalFlex {
+          display: flex;
+          justify-content: center;
+          align-items: var(
+            --gr-context-controls-horizontal-align-items,
+            center
+          );
+        }
 
-    .aboveButton {
-      border-bottom-width: 0;
-      border-bottom-right-radius: 0;
-      border-bottom-left-radius: 0;
-      padding: var(--spacing-xxs) var(--spacing-l);
-    }
-    .belowButton {
-      border-top-width: 0;
-      border-top-left-radius: 0;
-      border-top-right-radius: 0;
-      padding: var(--spacing-xxs) var(--spacing-l);
-      margin-top: calc(var(--divider-height) + 2 * var(--spacing-xxs));
-    }
-    .belowButton:first-child {
-      margin-top: 0;
-    }
-    .breadcrumbTooltip {
-      white-space: nowrap;
-    }
-  `;
+        .aboveButton {
+          border-bottom-width: 0;
+          border-bottom-right-radius: 0;
+          border-bottom-left-radius: 0;
+          padding: var(--spacing-xxs) var(--spacing-l);
+        }
+        .belowButton {
+          border-top-width: 0;
+          border-top-left-radius: 0;
+          border-top-right-radius: 0;
+          padding: var(--spacing-xxs) var(--spacing-l);
+          margin-top: calc(var(--divider-height) + 2 * var(--spacing-xxs));
+        }
+        .belowButton:first-child {
+          margin-top: 0;
+        }
+        .breadcrumbTooltip {
+          white-space: nowrap;
+        }
+      `,
+    ];
+  }
 
   constructor() {
     super();
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer.ts
index e9076aa..9478d13 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer.ts
@@ -6,7 +6,10 @@
 import {DiffLayer} from '../../../types/types';
 import {GrDiffLine, Side, TokenHighlightListener} from '../../../api/diff';
 import {assertIsDefined} from '../../../utils/common-util';
-import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
+import {
+  GrAnnotationImpl,
+  getStringLength,
+} from '../gr-diff-highlight/gr-annotation';
 import {debounce, DelayedTask} from '../../../utils/async-util';
 
 import {getLineElByChild, getSideByLineEl} from '../gr-diff/gr-diff-utils';
@@ -147,8 +150,8 @@
       // This is to correctly count surrogate pairs in text and token.
       // If the index calculation becomes a hotspot, we could precompute a code
       // unit to code point index map for text before iterating over the results
-      const index = GrAnnotation.getStringLength(text.slice(0, match.index));
-      const length = GrAnnotation.getStringLength(token);
+      const index = getStringLength(text.slice(0, match.index));
+      const length = getStringLength(token);
 
       atLeastOneTokenMatched = true;
       const highlightTypeClass =
@@ -158,7 +161,7 @@
       // We add the TOKEN_TEXT_PREFIX class so that we can look up the token later easily
       // even if the token element was split up into multiple smaller nodes.
       // All parts of a single token will share a common TOKEN_INDEX_PREFIX class within the line of code.
-      GrAnnotation.annotateElement(
+      GrAnnotationImpl.annotateElement(
         el,
         index,
         length,
@@ -345,7 +348,7 @@
       start_line: line,
       start_column: index + 1, // 1-based inclusive
       end_line: line,
-      end_column: index + GrAnnotation.getStringLength(token), // 1-based inclusive
+      end_column: index + getStringLength(token), // 1-based inclusive
     };
     this.tokenHighlightListener({token, element, side, range});
   }
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer_test.ts b/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer_test.ts
index 5651dcf..8d0050f 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer_test.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-builder/token-highlight-layer_test.ts
@@ -11,7 +11,7 @@
 } from '../../../api/diff';
 import {GrDiffLine} from '../gr-diff/gr-diff-line';
 import {HOVER_DELAY_MS, TokenHighlightLayer} from './token-highlight-layer';
-import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
+import {GrAnnotationImpl} from '../gr-diff-highlight/gr-annotation';
 import {html, render} from 'lit';
 import {_testOnly_allTasks} from '../../../utils/async-util';
 import {queryAndAssert} from '../../../test/test-utils';
@@ -123,10 +123,13 @@
     }
 
     test('annotate adds css token', () => {
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+      const annotateElementStub = sinon.stub(
+        GrAnnotationImpl,
+        'annotateElement'
+      );
       const el = createLine('these are words');
       annotate(el);
-      assert.isTrue(annotateElementStub.calledThrice);
+      assert.equal(annotateElementStub.callCount, 3);
       assertAnnotation(annotateElementStub.args[0], {
         parent: el,
         offset: 0,
@@ -148,7 +151,10 @@
     });
 
     test('annotate adds css tokens w/ emojis', () => {
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+      const annotateElementStub = sinon.stub(
+        GrAnnotationImpl,
+        'annotateElement'
+      );
       const el = createLine('these 💩 are 👨‍👩‍👧‍👦 words');
 
       annotate(el);
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-annotation.ts b/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-annotation.ts
index 5669bcf..bddfcac 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-annotation.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-annotation.ts
@@ -4,6 +4,7 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 import {getSanitizeDOMValue} from '@polymer/polymer/lib/utils/settings';
+import {GrAnnotation} from '../../../api/diff';
 
 // TODO(wyatta): refactor this to be <MARK> rather than <HL>.
 const ANNOTATION_TAG = 'HL';
@@ -11,268 +12,271 @@
 // Astral code point as per https://mathiasbynens.be/notes/javascript-unicode
 const REGEX_ASTRAL_SYMBOL = /[\uD800-\uDBFF][\uDC00-\uDFFF]/;
 
-export const GrAnnotation = {
-  /**
-   * The DOM API textContent.length calculation is broken when the text
-   * contains Unicode. See https://mathiasbynens.be/notes/javascript-unicode .
-   *
-   */
-  getLength(node: Node) {
-    if (node instanceof Comment) return 0;
-    return GrAnnotation.getStringLength(node.textContent || '');
-  },
+/**
+ * The DOM API textContent.length calculation is broken when the text
+ * contains Unicode. See https://mathiasbynens.be/notes/javascript-unicode .
+ */
+export function getLength(node: Node) {
+  if (node instanceof Comment) return 0;
+  return getStringLength(node.textContent || '');
+}
 
-  /**
-   * Returns the number of Unicode code points in the given string
-   *
-   * This is not necessarily the same as the number of visible symbols.
-   * See https://mathiasbynens.be/notes/javascript-unicode for more details.
-   */
-  getStringLength(str: string) {
-    return [...str].length;
-  },
+/**
+ * Returns the number of Unicode code points in the given string
+ *
+ * This is not necessarily the same as the number of visible symbols.
+ * See https://mathiasbynens.be/notes/javascript-unicode for more details.
+ */
+export function getStringLength(str: string) {
+  return [...str].length;
+}
 
-  /**
-   * Annotates the [offset, offset+length) text segment in the parent with the
-   * element definition provided as arguments.
-   *
-   * @param parent the node whose contents will be annotated.
-   * If parent is Text then parent.parentNode must not be null
-   * @param offset the 0-based offset from which the annotation will
-   * start.
-   * @param length of the annotated text.
-   * @param elementSpec the spec to create the
-   * annotating element.
-   */
-  annotateWithElement(
-    parent: Node,
-    offset: number,
-    length: number,
-    elSpec: ElementSpec
+/**
+ * Annotates the [offset, offset+length) text segment in the parent with the
+ * element definition provided as arguments.
+ *
+ * @param parent the node whose contents will be annotated.
+ * If parent is Text then parent.parentNode must not be null
+ * @param offset the 0-based offset from which the annotation will
+ * start.
+ * @param length of the annotated text.
+ * @param elementSpec the spec to create the
+ * annotating element.
+ */
+export function annotateWithElement(
+  parent: Node,
+  offset: number,
+  length: number,
+  elSpec: ElementSpec
+) {
+  const tagName = elSpec.tagName;
+  const attributes = elSpec.attributes || {};
+  let childNodes: Node[];
+
+  if (parent instanceof Element) {
+    childNodes = Array.from(parent.childNodes);
+  } else if (parent instanceof Text) {
+    childNodes = [parent];
+    parent = parent.parentNode!;
+  } else {
+    return;
+  }
+
+  const nestedNodes: Node[] = [];
+  for (let node of childNodes) {
+    const initialNodeLength = getLength(node);
+    // If the current node is completely before the offset.
+    if (offset > 0 && initialNodeLength <= offset) {
+      offset -= initialNodeLength;
+      continue;
+    }
+
+    if (offset > 0) {
+      node = splitNode(node, offset);
+      offset = 0;
+    }
+    if (getLength(node) > length) {
+      splitNode(node, length);
+    }
+    nestedNodes.push(node);
+
+    length -= getLength(node);
+    if (!length) break;
+  }
+
+  const wrapper = document.createElement(tagName);
+  const sanitizer = getSanitizeDOMValue();
+  for (let [name, value] of Object.entries(attributes)) {
+    if (!value) continue;
+    if (sanitizer) {
+      value = sanitizer(value, name, 'attribute', wrapper) as string;
+    }
+    wrapper.setAttribute(name, value);
+  }
+  for (const inner of nestedNodes) {
+    parent.replaceChild(wrapper, inner);
+    wrapper.appendChild(inner);
+  }
+}
+
+/**
+ * Surrounds the element's text at specified range in an ANNOTATION_TAG
+ * element. If the element has child elements, the range is split and
+ * applied as deeply as possible.
+ */
+export function annotateElement(
+  parent: HTMLElement,
+  offset: number,
+  length: number,
+  cssClass: string
+) {
+  const nodes: Array<HTMLElement | Text> = [].slice.apply(parent.childNodes);
+  let nodeLength;
+  let subLength;
+
+  for (const node of nodes) {
+    nodeLength = getLength(node);
+
+    // If the current node is completely before the offset.
+    if (nodeLength <= offset) {
+      offset -= nodeLength;
+      continue;
+    }
+
+    // Sublength is the annotation length for the current node.
+    subLength = Math.min(length, nodeLength - offset);
+
+    if (node instanceof Text) {
+      _annotateText(node, offset, subLength, cssClass);
+    } else if (node instanceof Element) {
+      annotateElement(node, offset, subLength, cssClass);
+    }
+
+    // If there is still more to annotate, then shift the indices, otherwise
+    // work is done, so break the loop.
+    if (subLength < length) {
+      length -= subLength;
+      offset = 0;
+    } else {
+      break;
+    }
+  }
+}
+
+/**
+ * Wraps node in annotation tag with cssClass, replacing the node in DOM.
+ */
+function wrapInHighlight(node: Element | Text, cssClass: string) {
+  let hl;
+  if (!(node instanceof Text) && node.tagName === ANNOTATION_TAG) {
+    hl = node;
+    hl.classList.add(cssClass);
+  } else {
+    hl = document.createElement(ANNOTATION_TAG);
+    hl.className = cssClass;
+    if (node.parentElement) node.parentElement.replaceChild(hl, node);
+    hl.appendChild(node);
+  }
+  return hl;
+}
+
+/**
+ * Splits Text Node and wraps it in hl with cssClass.
+ * Wraps trailing part after split, tailing one if firstPart is true.
+ */
+function splitAndWrapInHighlight(
+  node: Text,
+  offset: number,
+  cssClass: string,
+  firstPart?: boolean
+) {
+  if (
+    (getLength(node) === offset && firstPart) ||
+    (offset === 0 && !firstPart)
   ) {
-    const tagName = elSpec.tagName;
-    const attributes = elSpec.attributes || {};
-    let childNodes: Node[];
+    return wrapInHighlight(node, cssClass);
+  }
+  if (firstPart) {
+    splitNode(node, offset);
+    // Node points to first part of the Text, second one is sibling.
+  } else {
+    // if node is Text then splitNode will return a Text
+    node = splitNode(node, offset) as Text;
+  }
+  return wrapInHighlight(node, cssClass);
+}
 
-    if (parent instanceof Element) {
-      childNodes = Array.from(parent.childNodes);
-    } else if (parent instanceof Text) {
-      childNodes = [parent];
-      parent = parent.parentNode!;
-    } else {
-      return;
+/**
+ * Splits Node at offset.
+ * If Node is Element, it's cloned and the node at offset is split too.
+ */
+function splitNode(element: Node, offset: number) {
+  if (element instanceof Text) {
+    return splitTextNode(element, offset);
+  }
+  const tail = element.cloneNode(false);
+
+  if (element.parentElement)
+    element.parentElement.insertBefore(tail, element.nextSibling);
+  // Skip nodes before offset.
+  let node = element.firstChild;
+  while (node && (getLength(node) <= offset || getLength(node) === 0)) {
+    offset -= getLength(node);
+    node = node.nextSibling;
+  }
+  if (node && getLength(node) > offset) {
+    tail.appendChild(splitNode(node, offset));
+  }
+  while (node && node.nextSibling) {
+    tail.appendChild(node.nextSibling);
+  }
+  return tail;
+}
+
+/**
+ * Node.prototype.splitText Unicode-valid alternative.
+ *
+ * DOM Api for splitText() is broken for Unicode:
+ * https://mathiasbynens.be/notes/javascript-unicode
+ *
+ * @return Trailing Text Node.
+ */
+function splitTextNode(node: Text, offset: number) {
+  if (node.textContent?.match(REGEX_ASTRAL_SYMBOL)) {
+    const head = Array.from(node.textContent);
+    const tail = head.splice(offset);
+    const parent = node.parentNode;
+
+    // Split the content of the original node.
+    node.textContent = head.join('');
+
+    const tailNode = document.createTextNode(tail.join(''));
+    if (parent) {
+      parent.insertBefore(tailNode, node.nextSibling);
     }
+    return tailNode;
+  } else {
+    return node.splitText(offset);
+  }
+}
 
-    const nestedNodes: Node[] = [];
-    for (let node of childNodes) {
-      const initialNodeLength = GrAnnotation.getLength(node);
-      // If the current node is completely before the offset.
-      if (offset > 0 && initialNodeLength <= offset) {
-        offset -= initialNodeLength;
-        continue;
-      }
+function _annotateText(
+  node: Text,
+  offset: number,
+  length: number,
+  cssClass: string
+) {
+  const nodeLength = getLength(node);
 
-      if (offset > 0) {
-        node = GrAnnotation.splitNode(node, offset);
-        offset = 0;
-      }
-      if (GrAnnotation.getLength(node) > length) {
-        GrAnnotation.splitNode(node, length);
-      }
-      nestedNodes.push(node);
+  // There are four cases:
+  //  1) Entire node is highlighted.
+  //  2) Highlight is at the start.
+  //  3) Highlight is at the end.
+  //  4) Highlight is in the middle.
 
-      length -= GrAnnotation.getLength(node);
-      if (!length) break;
-    }
+  if (offset === 0 && nodeLength === length) {
+    // Case 1.
+    wrapInHighlight(node, cssClass);
+  } else if (offset === 0) {
+    // Case 2.
+    splitAndWrapInHighlight(node, length, cssClass, true);
+  } else if (offset + length === nodeLength) {
+    // Case 3
+    splitAndWrapInHighlight(node, offset, cssClass, false);
+  } else {
+    // Case 4
+    splitAndWrapInHighlight(
+      splitTextNode(node, offset),
+      length,
+      cssClass,
+      true
+    );
+  }
+}
 
-    const wrapper = document.createElement(tagName);
-    const sanitizer = getSanitizeDOMValue();
-    for (let [name, value] of Object.entries(attributes)) {
-      if (!value) continue;
-      if (sanitizer) {
-        value = sanitizer(value, name, 'attribute', wrapper) as string;
-      }
-      wrapper.setAttribute(name, value);
-    }
-    for (const inner of nestedNodes) {
-      parent.replaceChild(wrapper, inner);
-      wrapper.appendChild(inner);
-    }
-  },
-
-  /**
-   * Surrounds the element's text at specified range in an ANNOTATION_TAG
-   * element. If the element has child elements, the range is split and
-   * applied as deeply as possible.
-   */
-  annotateElement(
-    parent: HTMLElement,
-    offset: number,
-    length: number,
-    cssClass: string
-  ) {
-    const nodes: Array<HTMLElement | Text> = [].slice.apply(parent.childNodes);
-    let nodeLength;
-    let subLength;
-
-    for (const node of nodes) {
-      nodeLength = GrAnnotation.getLength(node);
-
-      // If the current node is completely before the offset.
-      if (nodeLength <= offset) {
-        offset -= nodeLength;
-        continue;
-      }
-
-      // Sublength is the annotation length for the current node.
-      subLength = Math.min(length, nodeLength - offset);
-
-      if (node instanceof Text) {
-        GrAnnotation._annotateText(node, offset, subLength, cssClass);
-      } else if (node instanceof Element) {
-        GrAnnotation.annotateElement(node, offset, subLength, cssClass);
-      }
-
-      // If there is still more to annotate, then shift the indices, otherwise
-      // work is done, so break the loop.
-      if (subLength < length) {
-        length -= subLength;
-        offset = 0;
-      } else {
-        break;
-      }
-    }
-  },
-
-  /**
-   * Wraps node in annotation tag with cssClass, replacing the node in DOM.
-   */
-  wrapInHighlight(node: Element | Text, cssClass: string) {
-    let hl;
-    if (!(node instanceof Text) && node.tagName === ANNOTATION_TAG) {
-      hl = node;
-      hl.classList.add(cssClass);
-    } else {
-      hl = document.createElement(ANNOTATION_TAG);
-      hl.className = cssClass;
-      if (node.parentElement) node.parentElement.replaceChild(hl, node);
-      hl.appendChild(node);
-    }
-    return hl;
-  },
-
-  /**
-   * Splits Text Node and wraps it in hl with cssClass.
-   * Wraps trailing part after split, tailing one if firstPart is true.
-   */
-  splitAndWrapInHighlight(
-    node: Text,
-    offset: number,
-    cssClass: string,
-    firstPart?: boolean
-  ) {
-    if (
-      (GrAnnotation.getLength(node) === offset && firstPart) ||
-      (offset === 0 && !firstPart)
-    ) {
-      return GrAnnotation.wrapInHighlight(node, cssClass);
-    }
-    if (firstPart) {
-      GrAnnotation.splitNode(node, offset);
-      // Node points to first part of the Text, second one is sibling.
-    } else {
-      // if node is Text then splitNode will return a Text
-      node = GrAnnotation.splitNode(node, offset) as Text;
-    }
-    return GrAnnotation.wrapInHighlight(node, cssClass);
-  },
-
-  /**
-   * Splits Node at offset.
-   * If Node is Element, it's cloned and the node at offset is split too.
-   */
-  splitNode(element: Node, offset: number) {
-    if (element instanceof Text) {
-      return GrAnnotation.splitTextNode(element, offset);
-    }
-    const tail = element.cloneNode(false);
-
-    if (element.parentElement)
-      element.parentElement.insertBefore(tail, element.nextSibling);
-    // Skip nodes before offset.
-    let node = element.firstChild;
-    while (
-      node &&
-      (GrAnnotation.getLength(node) <= offset ||
-        GrAnnotation.getLength(node) === 0)
-    ) {
-      offset -= GrAnnotation.getLength(node);
-      node = node.nextSibling;
-    }
-    if (node && GrAnnotation.getLength(node) > offset) {
-      tail.appendChild(GrAnnotation.splitNode(node, offset));
-    }
-    while (node && node.nextSibling) {
-      tail.appendChild(node.nextSibling);
-    }
-    return tail;
-  },
-
-  /**
-   * Node.prototype.splitText Unicode-valid alternative.
-   *
-   * DOM Api for splitText() is broken for Unicode:
-   * https://mathiasbynens.be/notes/javascript-unicode
-   *
-   * @return Trailing Text Node.
-   */
-  splitTextNode(node: Text, offset: number) {
-    if (node.textContent?.match(REGEX_ASTRAL_SYMBOL)) {
-      const head = Array.from(node.textContent);
-      const tail = head.splice(offset);
-      const parent = node.parentNode;
-
-      // Split the content of the original node.
-      node.textContent = head.join('');
-
-      const tailNode = document.createTextNode(tail.join(''));
-      if (parent) {
-        parent.insertBefore(tailNode, node.nextSibling);
-      }
-      return tailNode;
-    } else {
-      return node.splitText(offset);
-    }
-  },
-
-  _annotateText(node: Text, offset: number, length: number, cssClass: string) {
-    const nodeLength = GrAnnotation.getLength(node);
-
-    // There are four cases:
-    //  1) Entire node is highlighted.
-    //  2) Highlight is at the start.
-    //  3) Highlight is at the end.
-    //  4) Highlight is in the middle.
-
-    if (offset === 0 && nodeLength === length) {
-      // Case 1.
-      GrAnnotation.wrapInHighlight(node, cssClass);
-    } else if (offset === 0) {
-      // Case 2.
-      GrAnnotation.splitAndWrapInHighlight(node, length, cssClass, true);
-    } else if (offset + length === nodeLength) {
-      // Case 3
-      GrAnnotation.splitAndWrapInHighlight(node, offset, cssClass, false);
-    } else {
-      // Case 4
-      GrAnnotation.splitAndWrapInHighlight(
-        GrAnnotation.splitTextNode(node, offset),
-        length,
-        cssClass,
-        true
-      );
-    }
-  },
+export const GrAnnotationImpl: GrAnnotation = {
+  annotateElement,
+  annotateWithElement,
 };
 
 /**
@@ -283,3 +287,8 @@
   tagName: string;
   attributes?: {[attributeName: string]: string | undefined};
 }
+
+export const TEST_ONLY = {
+  _annotateText,
+  splitTextNode,
+};
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-annotation_test.ts b/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-annotation_test.ts
index 3e1ce66..15a6a15 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-annotation_test.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-annotation_test.ts
@@ -4,7 +4,12 @@
  * SPDX-License-Identifier: Apache-2.0
  */
 import '../../../test/common-test-setup';
-import {GrAnnotation} from './gr-annotation';
+import {
+  TEST_ONLY,
+  annotateElement,
+  annotateWithElement,
+  getStringLength,
+} from './gr-annotation';
 import {
   getSanitizeDOMValue,
   setSanitizeDOMValue,
@@ -27,7 +32,7 @@
   });
 
   test('_annotateText length:0 offset:0', () => {
-    GrAnnotation._annotateText(textNode, 0, 0, 'foobar');
+    TEST_ONLY._annotateText(textNode, 0, 0, 'foobar');
 
     assert.equal(parent.textContent, str);
     assert.equal(
@@ -37,7 +42,7 @@
   });
 
   test('_annotateText length:0 offset:1', () => {
-    GrAnnotation._annotateText(textNode, 1, 0, 'foobar');
+    TEST_ONLY._annotateText(textNode, 1, 0, 'foobar');
 
     assert.equal(parent.textContent, str);
     assert.equal(
@@ -47,7 +52,7 @@
   });
 
   test('_annotateText length:0 offset:str.length', () => {
-    GrAnnotation._annotateText(textNode, str.length, 0, 'foobar');
+    TEST_ONLY._annotateText(textNode, str.length, 0, 'foobar');
 
     assert.equal(parent.textContent, str);
     assert.equal(
@@ -57,7 +62,7 @@
   });
 
   test('_annotateText Case 1', () => {
-    GrAnnotation._annotateText(textNode, 0, str.length, 'foobar');
+    TEST_ONLY._annotateText(textNode, 0, str.length, 'foobar');
 
     assert.equal(parent.textContent, str);
     assert.equal(
@@ -67,7 +72,7 @@
   });
 
   test('_annotateText Case 2', () => {
-    GrAnnotation._annotateText(textNode, 0, 12, 'foobar');
+    TEST_ONLY._annotateText(textNode, 0, 12, 'foobar');
 
     assert.equal(parent.textContent, str);
     assert.equal(
@@ -77,7 +82,7 @@
   });
 
   test('_annotateText Case 3', () => {
-    GrAnnotation._annotateText(textNode, 12, str.length - 12, 'foobar');
+    TEST_ONLY._annotateText(textNode, 12, str.length - 12, 'foobar');
 
     assert.equal(parent.textContent, str);
     assert.equal(
@@ -90,7 +95,7 @@
     const index = str.indexOf('dolor');
     const length = 'dolor '.length;
 
-    GrAnnotation._annotateText(textNode, index, length, 'foobar');
+    TEST_ONLY._annotateText(textNode, index, length, 'foobar');
 
     assert.equal(parent.textContent, str);
     assert.equal(
@@ -104,7 +109,7 @@
 
     // Apply the layers successively.
     layers.forEach((layer, i) => {
-      GrAnnotation.annotateElement(
+      annotateElement(
         parent,
         str.indexOf(layer),
         layer.length,
@@ -129,13 +134,13 @@
 
     // Non-unicode path:
     node = document.createTextNode(helloString + asciiString);
-    tail = GrAnnotation.splitTextNode(node, helloString.length);
+    tail = TEST_ONLY.splitTextNode(node, helloString.length);
     assert(node.textContent, helloString);
     assert(tail.textContent, asciiString);
 
     // Unicdoe path:
     node = document.createTextNode(helloString + unicodeString);
-    tail = GrAnnotation.splitTextNode(node, helloString.length);
+    tail = TEST_ONLY.splitTextNode(node, helloString.length);
     assert(node.textContent, helloString);
     assert(tail.textContent, unicodeString);
   });
@@ -166,7 +171,7 @@
       const length = 10;
       const container = document.createElement('div');
       container.textContent = fullText;
-      GrAnnotation.annotateWithElement(container, 1, length, {
+      annotateWithElement(container, 1, length, {
         tagName: 'test-wrapper',
       });
 
@@ -180,8 +185,8 @@
       const length = 10;
       const container = document.createElement('div');
       container.textContent = fullText;
-      GrAnnotation.annotateElement(container, 5, length, 'testclass');
-      GrAnnotation.annotateWithElement(container, 1, length, {
+      annotateElement(container, 5, length, 'testclass');
+      annotateWithElement(container, 1, length, {
         tagName: 'test-wrapper',
       });
 
@@ -201,7 +206,7 @@
       const length = 10;
       const container = document.createElement('div');
       container.textContent = fullText;
-      GrAnnotation.annotateWithElement(container.childNodes[0], 1, length, {
+      annotateWithElement(container.childNodes[0], 1, length, {
         tagName: 'test-wrapper',
       });
 
@@ -216,7 +221,7 @@
       container.appendChild(document.createTextNode('0123456789'));
       container.appendChild(document.createElement('span'));
       container.appendChild(document.createTextNode('0123456789'));
-      GrAnnotation.annotateWithElement(container, 1, 10, {
+      annotateWithElement(container, 1, 10, {
         tagName: 'test-wrapper',
       });
 
@@ -233,7 +238,7 @@
       container.appendChild(document.createComment('comment2'));
       container.appendChild(document.createElement('span'));
       container.appendChild(document.createTextNode('0123456789'));
-      GrAnnotation.annotateWithElement(container, 1, 10, {
+      annotateWithElement(container, 1, 10, {
         tagName: 'test-wrapper',
       });
 
@@ -254,7 +259,7 @@
         'data-foo': 'bar',
         class: 'hello world',
       };
-      GrAnnotation.annotateWithElement(container, 1, length, {
+      annotateWithElement(container, 1, length, {
         tagName: 'test-wrapper',
         attributes,
       });
@@ -291,17 +296,17 @@
 
   suite('getStringLength', () => {
     test('ASCII characters are counted correctly', () => {
-      assert.equal(GrAnnotation.getStringLength('ASCII'), 5);
+      assert.equal(getStringLength('ASCII'), 5);
     });
 
     test('Unicode surrogate pairs count as one symbol', () => {
-      assert.equal(GrAnnotation.getStringLength('Unic💢de'), 7);
-      assert.equal(GrAnnotation.getStringLength('💢💢'), 2);
+      assert.equal(getStringLength('Unic💢de'), 7);
+      assert.equal(getStringLength('💢💢'), 2);
     });
 
     test('Grapheme clusters count as multiple symbols', () => {
-      assert.equal(GrAnnotation.getStringLength('man\u0303ana'), 7); // mañana
-      assert.equal(GrAnnotation.getStringLength('q\u0307\u0323'), 3); // q̣̇
+      assert.equal(getStringLength('man\u0303ana'), 7); // mañana
+      assert.equal(getStringLength('q\u0307\u0323'), 3); // q̣̇
     });
   });
 });
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-diff-highlight.ts b/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-diff-highlight.ts
index 0d9250c..1cdfbc3 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-diff-highlight.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-highlight/gr-diff-highlight.ts
@@ -5,7 +5,7 @@
  */
 import '../../../styles/shared-styles';
 import '../gr-selection-action-box/gr-selection-action-box';
-import {GrAnnotation} from './gr-annotation';
+import {getLength} from './gr-annotation';
 import {normalize} from './gr-range-normalizer';
 import {strToClassName} from '../../../utils/dom-util';
 import {Side} from '../../../constants/constants';
@@ -508,7 +508,7 @@
     if (node instanceof Element && node.classList.contains('content')) {
       return this.getLength(queryAndAssert(node, '.contentText'));
     } else {
-      return GrAnnotation.getLength(node);
+      return getLength(node);
     }
   }
 }
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-image-viewer.ts b/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-image-viewer.ts
index 645de1b..4f05cca 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-image-viewer.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-image-viewer.ts
@@ -150,211 +150,218 @@
   // TODO(hermannloose): Make GrLibLoader a singleton.
   private static readonly libLoader = new GrLibLoader();
 
-  static override styles = css`
-    :host {
-      display: grid;
-      grid-template-rows: 1fr auto;
-      grid-template-columns: 1fr auto;
-      width: 100%;
-      height: 100%;
-      box-sizing: border-box;
-      text-align: initial !important;
-      font-size: var(--font-size-normal);
-      --image-border-width: 2px;
-    }
-    .imageArea {
-      grid-row-start: 1;
-      grid-column-start: 1;
-      box-sizing: border-box;
-      flex-grow: 1;
-      overflow: hidden;
-      display: flex;
-      flex-direction: column;
-      align-items: center;
-      margin: var(--spacing-m);
-      padding: var(--image-border-width);
-      max-height: 100%;
-      position: relative;
-    }
-    #spacer {
-      visibility: hidden;
-    }
-    gr-zoomed-image {
-      border: var(--image-border-width) solid;
-      margin: calc(-1 * var(--image-border-width));
-      box-sizing: content-box;
-      position: absolute;
-      overflow: hidden;
-      cursor: pointer;
-    }
-    gr-zoomed-image.base {
-      border-color: var(--base-image-border-color, rgb(255, 205, 210));
-    }
-    gr-zoomed-image.revision {
-      border-color: var(--revision-image-border-color, rgb(170, 242, 170));
-    }
-    #automatic-blink-button {
-      position: absolute;
-      right: var(--spacing-xl);
-      bottom: var(--spacing-xl);
-      opacity: 0;
-      transition: opacity 200ms ease;
-      --paper-fab-background: var(--primary-button-background-color);
-      --paper-fab-keyboard-focus-background: var(
-        --primary-button-background-color
-      );
-    }
-    #automatic-blink-button.show,
-    #automatic-blink-button:focus-visible {
-      opacity: 1;
-    }
-    .checkerboard {
-      --square-size: var(--checkerboard-square-size, 10px);
-      --square-color: var(--checkerboard-square-color, #808080);
-      background-color: var(--checkerboard-background-color, #aaaaaa);
-      background-image: linear-gradient(
-          45deg,
-          var(--square-color) 25%,
-          transparent 25%
-        ),
-        linear-gradient(-45deg, var(--square-color) 25%, transparent 25%),
-        linear-gradient(45deg, transparent 75%, var(--square-color) 75%),
-        linear-gradient(-45deg, transparent 75%, var(--square-color) 75%);
-      background-size: calc(var(--square-size) * 2) calc(var(--square-size) * 2);
-      background-position: 0 0, 0 var(--square-size),
-        var(--square-size) calc(-1 * var(--square-size)),
-        calc(-1 * var(--square-size)) 0;
-    }
-    .dimensions {
-      grid-row-start: 2;
-      justify-self: center;
-      align-self: center;
-      background: var(--primary-button-background-color);
-      color: var(--primary-button-text-color);
-      font-family: var(--font-family);
-      font-size: var(--font-size-small);
-      line-height: var(--line-height-small);
-      border-radius: var(--border-radius, 4px);
-      margin: var(--spacing-s);
-      padding: var(--spacing-xxs) var(--spacing-s);
-    }
-    .controls {
-      grid-column-start: 2;
-      flex-grow: 0;
-      display: flex;
-      flex-direction: column;
-      align-self: flex-start;
-      margin: var(--spacing-m);
-      padding-bottom: var(--spacing-xl);
-    }
-    paper-button {
-      padding: var(--spacing-m);
-      font: var(--image-diff-button-font);
-      text-transform: var(--image-diff-button-text-transform, uppercase);
-      outline: 1px solid transparent;
-      border: 1px solid var(--primary-button-background-color);
-    }
-    paper-button.unelevated {
-      color: var(--primary-button-text-color);
-      background-color: var(--primary-button-background-color);
-    }
-    paper-button.outlined {
-      color: var(--primary-button-background-color);
-    }
-    #version-switcher {
-      display: flex;
-      align-items: center;
-      margin: var(--spacing-xl) var(--spacing-xl) var(--spacing-m);
-      /* Start a stacking context to contain FAB below. */
-      z-index: 0;
-    }
-    #version-switcher paper-button {
-      flex-grow: 1;
-      margin: 0;
-      /*
+  static override get styles() {
+    return [
+      css`
+        :host {
+          display: grid;
+          grid-template-rows: 1fr auto;
+          grid-template-columns: 1fr auto;
+          width: 100%;
+          height: 100%;
+          box-sizing: border-box;
+          text-align: initial !important;
+          font-size: var(--font-size-normal);
+          --image-border-width: 2px;
+        }
+        .imageArea {
+          grid-row-start: 1;
+          grid-column-start: 1;
+          box-sizing: border-box;
+          flex-grow: 1;
+          overflow: hidden;
+          display: flex;
+          flex-direction: column;
+          align-items: center;
+          margin: var(--spacing-m);
+          padding: var(--image-border-width);
+          max-height: 100%;
+          position: relative;
+        }
+        #spacer {
+          visibility: hidden;
+        }
+        gr-zoomed-image {
+          border: var(--image-border-width) solid;
+          margin: calc(-1 * var(--image-border-width));
+          box-sizing: content-box;
+          position: absolute;
+          overflow: hidden;
+          cursor: pointer;
+        }
+        gr-zoomed-image.base {
+          border-color: var(--base-image-border-color, rgb(255, 205, 210));
+        }
+        gr-zoomed-image.revision {
+          border-color: var(--revision-image-border-color, rgb(170, 242, 170));
+        }
+        #automatic-blink-button {
+          position: absolute;
+          right: var(--spacing-xl);
+          bottom: var(--spacing-xl);
+          opacity: 0;
+          transition: opacity 200ms ease;
+          --paper-fab-background: var(--primary-button-background-color);
+          --paper-fab-keyboard-focus-background: var(
+            --primary-button-background-color
+          );
+        }
+        #automatic-blink-button.show,
+        #automatic-blink-button:focus-visible {
+          opacity: 1;
+        }
+        .checkerboard {
+          --square-size: var(--checkerboard-square-size, 10px);
+          --square-color: var(--checkerboard-square-color, #808080);
+          background-color: var(--checkerboard-background-color, #aaaaaa);
+          background-image: linear-gradient(
+              45deg,
+              var(--square-color) 25%,
+              transparent 25%
+            ),
+            linear-gradient(-45deg, var(--square-color) 25%, transparent 25%),
+            linear-gradient(45deg, transparent 75%, var(--square-color) 75%),
+            linear-gradient(-45deg, transparent 75%, var(--square-color) 75%);
+          background-size: calc(var(--square-size) * 2)
+            calc(var(--square-size) * 2);
+          background-position: 0 0, 0 var(--square-size),
+            var(--square-size) calc(-1 * var(--square-size)),
+            calc(-1 * var(--square-size)) 0;
+        }
+        .dimensions {
+          grid-row-start: 2;
+          justify-self: center;
+          align-self: center;
+          background: var(--primary-button-background-color);
+          color: var(--primary-button-text-color);
+          font-family: var(--font-family);
+          font-size: var(--font-size-small);
+          line-height: var(--line-height-small);
+          border-radius: var(--border-radius, 4px);
+          margin: var(--spacing-s);
+          padding: var(--spacing-xxs) var(--spacing-s);
+        }
+        .controls {
+          grid-column-start: 2;
+          flex-grow: 0;
+          display: flex;
+          flex-direction: column;
+          align-self: flex-start;
+          margin: var(--spacing-m);
+          padding-bottom: var(--spacing-xl);
+        }
+        paper-button {
+          padding: var(--spacing-m);
+          font: var(--image-diff-button-font);
+          text-transform: var(--image-diff-button-text-transform, uppercase);
+          outline: 1px solid transparent;
+          border: 1px solid var(--primary-button-background-color);
+        }
+        paper-button.unelevated {
+          color: var(--primary-button-text-color);
+          background-color: var(--primary-button-background-color);
+        }
+        paper-button.outlined {
+          color: var(--primary-button-background-color);
+        }
+        #version-switcher {
+          display: flex;
+          align-items: center;
+          margin: var(--spacing-xl) var(--spacing-xl) var(--spacing-m);
+          /* Start a stacking context to contain FAB below. */
+          z-index: 0;
+        }
+        #version-switcher paper-button {
+          flex-grow: 1;
+          margin: 0;
+          /*
         The floating action button below overlaps part of the version buttons.
         This min-width ensures the button text still appears somewhat balanced.
         */
-      min-width: 7rem;
-    }
-    #version-switcher paper-fab {
-      /* Round button overlaps Base and Revision buttons. */
-      z-index: 1;
-      margin: 0 -12px;
-      /* Styled as an outlined button. */
-      color: var(--primary-button-background-color);
-      border: 1px solid var(--primary-button-background-color);
-      --paper-fab-background: var(--primary-background-color);
-      --paper-fab-keyboard-focus-background: var(--primary-background-color);
-    }
-    #version-explanation {
-      color: var(--deemphasized-text-color);
-      text-align: center;
-      margin: var(--spacing-xl) var(--spacing-xl) var(--spacing-m);
-    }
-    #highlight-changes {
-      margin: var(--spacing-m) var(--spacing-xl);
-    }
-    gr-overview-image {
-      min-width: 200px;
-      min-height: 150px;
-      margin-top: var(--spacing-m);
-    }
-    #zoom-control {
-      margin: 0 var(--spacing-xl);
-    }
-    paper-item {
-      cursor: pointer;
-    }
-    paper-item:hover {
-      background-color: var(--hover-background-color);
-    }
-    #follow-mouse {
-      margin: var(--spacing-m) var(--spacing-xl);
-    }
-    .color-picker {
-      margin: var(--spacing-m) var(--spacing-xl) 0;
-    }
-    .color-picker .label {
-      margin-bottom: var(--spacing-s);
-    }
-    .color-picker .options {
-      display: flex;
-      /* Ignore selection border for alignment, for visual balance. */
-      margin-left: -3px;
-    }
-    .color-picker-button {
-      border-width: 2px;
-      border-style: solid;
-      border-color: transparent;
-      border-radius: 50%;
-      width: 24px;
-      height: 24px;
-      padding: 1px;
-    }
-    .color-picker-button.selected {
-      border-color: var(--primary-button-background-color);
-    }
-    .color-picker-button:focus-within:not(.selected) {
-      /* Not an actual outline, as those do not follow border-radius. */
-      border-color: var(--outline-color-focus);
-    }
-    .color-picker-button .color {
-      border: 1px solid var(--border-color);
-      border-radius: 50%;
-      width: 100%;
-      height: 100%;
-      box-sizing: border-box;
-    }
-    #source-plus-highlight-container {
-      position: relative;
-    }
-    #source-plus-highlight-container img {
-      position: absolute;
-      top: 0;
-      left: 0;
-    }
-  `;
+          min-width: 7rem;
+        }
+        #version-switcher paper-fab {
+          /* Round button overlaps Base and Revision buttons. */
+          z-index: 1;
+          margin: 0 -12px;
+          /* Styled as an outlined button. */
+          color: var(--primary-button-background-color);
+          border: 1px solid var(--primary-button-background-color);
+          --paper-fab-background: var(--primary-background-color);
+          --paper-fab-keyboard-focus-background: var(
+            --primary-background-color
+          );
+        }
+        #version-explanation {
+          color: var(--deemphasized-text-color);
+          text-align: center;
+          margin: var(--spacing-xl) var(--spacing-xl) var(--spacing-m);
+        }
+        #highlight-changes {
+          margin: var(--spacing-m) var(--spacing-xl);
+        }
+        gr-overview-image {
+          min-width: 200px;
+          min-height: 150px;
+          margin-top: var(--spacing-m);
+        }
+        #zoom-control {
+          margin: 0 var(--spacing-xl);
+        }
+        paper-item {
+          cursor: pointer;
+        }
+        paper-item:hover {
+          background-color: var(--hover-background-color);
+        }
+        #follow-mouse {
+          margin: var(--spacing-m) var(--spacing-xl);
+        }
+        .color-picker {
+          margin: var(--spacing-m) var(--spacing-xl) 0;
+        }
+        .color-picker .label {
+          margin-bottom: var(--spacing-s);
+        }
+        .color-picker .options {
+          display: flex;
+          /* Ignore selection border for alignment, for visual balance. */
+          margin-left: -3px;
+        }
+        .color-picker-button {
+          border-width: 2px;
+          border-style: solid;
+          border-color: transparent;
+          border-radius: 50%;
+          width: 24px;
+          height: 24px;
+          padding: 1px;
+        }
+        .color-picker-button.selected {
+          border-color: var(--primary-button-background-color);
+        }
+        .color-picker-button:focus-within:not(.selected) {
+          /* Not an actual outline, as those do not follow border-radius. */
+          border-color: var(--outline-color-focus);
+        }
+        .color-picker-button .color {
+          border: 1px solid var(--border-color);
+          border-radius: 50%;
+          width: 100%;
+          height: 100%;
+          box-sizing: border-box;
+        }
+        #source-plus-highlight-container {
+          position: relative;
+        }
+        #source-plus-highlight-container img {
+          position: absolute;
+          top: 0;
+          left: 0;
+        }
+      `,
+    ];
+  }
 
   private renderColorPickerButton(color: string, colorPicked: () => void) {
     const selected =
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-overview-image.ts b/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-overview-image.ts
index 21a7cf8..a05b5e2 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-overview-image.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-overview-image.ts
@@ -75,39 +75,43 @@
     }
   );
 
-  static override styles = css`
-    :host {
-      --background-color: var(--overview-image-background-color, #000);
-      --frame-color: var(--overview-image-frame-color, #f00);
-      display: flex;
-    }
-    * {
-      box-sizing: border-box;
-    }
-    ::slotted(*) {
-      display: block;
-    }
-    .content-box {
-      border: 1px solid var(--background-color);
-      background-color: var(--background-color);
-      width: 100%;
-      position: relative;
-    }
-    .content {
-      position: absolute;
-      cursor: pointer;
-    }
-    .content-transform {
-      position: absolute;
-      transform-origin: top left;
-      will-change: transform;
-    }
-    .frame {
-      border: 1px solid var(--frame-color);
-      position: absolute;
-      will-change: transform;
-    }
-  `;
+  static override get styles() {
+    return [
+      css`
+        :host {
+          --background-color: var(--overview-image-background-color, #000);
+          --frame-color: var(--overview-image-frame-color, #f00);
+          display: flex;
+        }
+        * {
+          box-sizing: border-box;
+        }
+        ::slotted(*) {
+          display: block;
+        }
+        .content-box {
+          border: 1px solid var(--background-color);
+          background-color: var(--background-color);
+          width: 100%;
+          position: relative;
+        }
+        .content {
+          position: absolute;
+          cursor: pointer;
+        }
+        .content-transform {
+          position: absolute;
+          transform-origin: top left;
+          will-change: transform;
+        }
+        .frame {
+          border: 1px solid var(--frame-color);
+          position: absolute;
+          will-change: transform;
+        }
+      `,
+    ];
+  }
 
   override render() {
     return html`
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-zoomed-image.ts b/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-zoomed-image.ts
index 7b46c51..3b778b1 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-zoomed-image.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-image-viewer/gr-zoomed-image.ts
@@ -25,25 +25,29 @@
 
   @state() protected imageStyles: StyleInfo = {};
 
-  static override styles = css`
-    :host {
-      display: block;
-    }
-    ::slotted(*) {
-      display: block;
-    }
-    #clip {
-      position: relative;
-      width: 100%;
-      height: 100%;
-      overflow: hidden;
-    }
-    #transform {
-      position: absolute;
-      transform-origin: top left;
-      will-change: transform;
-    }
-  `;
+  static override get styles() {
+    return [
+      css`
+        :host {
+          display: block;
+        }
+        ::slotted(*) {
+          display: block;
+        }
+        #clip {
+          position: relative;
+          width: 100%;
+          height: 100%;
+          overflow: hidden;
+        }
+        #transform {
+          position: absolute;
+          transform-origin: top left;
+          will-change: transform;
+        }
+      `,
+    ];
+  }
 
   override render() {
     return html`
diff --git a/polygerrit-ui/app/embed/diff/gr-diff-processor/gr-diff-processor.ts b/polygerrit-ui/app/embed/diff/gr-diff-processor/gr-diff-processor.ts
index 98c0ab7..5db6db9 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff-processor/gr-diff-processor.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff-processor/gr-diff-processor.ts
@@ -13,7 +13,7 @@
 import {Side} from '../../../constants/constants';
 import {debounce, DelayedTask} from '../../../utils/async-util';
 import {assert} from '../../../utils/common-util';
-import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
+import {getStringLength} from '../gr-diff-highlight/gr-annotation';
 import {GrDiffLineType, LineNumber} from '../../../api/diff';
 import {FULL_CONTEXT, KeyLocations} from '../gr-diff/gr-diff-utils';
 
@@ -633,7 +633,7 @@
     intralineInfos: number[][]
   ): Highlights[] {
     // +1 to account for the \n that is not part of the rows passed here
-    const lineLengths = rows.map(r => GrAnnotation.getStringLength(r) + 1);
+    const lineLengths = rows.map(r => getStringLength(r) + 1);
 
     let rowIndex = 0;
     let idx = 0;
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
index cc49b61..2834f08 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff.ts
@@ -79,7 +79,10 @@
 import {grDiffStyles} from './gr-diff-styles';
 import {getDiffLength} from '../../../utils/diff-util';
 import {GrCoverageLayer} from '../gr-coverage-layer/gr-coverage-layer';
-import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
+import {
+  GrAnnotationImpl,
+  getStringLength,
+} from '../gr-diff-highlight/gr-annotation';
 import {
   GrDiffGroup,
   GrDiffGroupType,
@@ -461,6 +464,7 @@
 
   private renderContainer() {
     const cssClasses = {
+      newDiff: true,
       diffContainer: true,
       unified: this.viewMode === DiffViewMode.UNIFIED,
       sideBySide: this.viewMode === DiffViewMode.SIDE_BY_SIDE,
@@ -1203,10 +1207,10 @@
           // If endIndex isn't present, continue to the end of the line.
           const endIndex =
             highlight.endIndex === undefined
-              ? GrAnnotation.getStringLength(line.text)
+              ? getStringLength(line.text)
               : highlight.endIndex;
 
-          GrAnnotation.annotateElement(
+          GrAnnotationImpl.annotateElement(
             contentEl,
             highlight.startIndex,
             endIndex - highlight.startIndex,
@@ -1254,11 +1258,9 @@
         if (match) {
           // Normalize string positions in case there is unicode before or
           // within the match.
-          const index = GrAnnotation.getStringLength(
-            line.text.substr(0, match.index)
-          );
-          const length = GrAnnotation.getStringLength(match[0]);
-          GrAnnotation.annotateElement(
+          const index = getStringLength(line.text.substr(0, match.index));
+          const length = getStringLength(match[0]);
+          GrAnnotationImpl.annotateElement(
             contentEl,
             index,
             length,
@@ -1459,7 +1461,7 @@
     // Skip forward by the length of the content
     pos += split[i].length;
 
-    GrAnnotation.annotateElement(contentEl, pos, 1, `gr-diff ${className}`);
+    GrAnnotationImpl.annotateElement(contentEl, pos, 1, `gr-diff ${className}`);
 
     pos++;
   }
diff --git a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_test.ts b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_test.ts
index 8806dbf..30f85cc 100644
--- a/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_test.ts
+++ b/polygerrit-ui/app/embed/diff/gr-diff/gr-diff_test.ts
@@ -41,7 +41,10 @@
 import {fixture, html, assert} from '@open-wc/testing';
 import {createDefaultDiffPrefs} from '../../../constants/constants';
 import {GrDiffRow} from '../gr-diff-builder/gr-diff-row';
-import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
+import {
+  GrAnnotationImpl,
+  getStringLength,
+} from '../gr-diff-highlight/gr-annotation';
 import {GrDiffLine} from './gr-diff-line';
 
 const DEFAULT_PREFS = createDefaultDiffPrefs();
@@ -73,7 +76,7 @@
       assert.shadowDom.equal(
         element,
         /* HTML */ `
-          <div class="diffContainer sideBySide">
+          <div class="diffContainer newDiff sideBySide">
             <table id="diffTable">
               <colgroup>
                 <col class="blame gr-diff" />
@@ -99,7 +102,7 @@
       assert.shadowDom.equal(
         element,
         /* HTML */ `
-          <div class="diffContainer unified">
+          <div class="diffContainer newDiff unified">
             <table class="selected-right" id="diffTable">
               <colgroup>
                 <col class="blame gr-diff" />
@@ -1365,7 +1368,7 @@
       assert.shadowDom.equal(
         element,
         /* HTML */ `
-          <div class="diffContainer sideBySide">
+          <div class="diffContainer newDiff sideBySide">
             <table class="selected-right" id="diffTable">
               <colgroup>
                 <col class="blame gr-diff" />
@@ -3157,7 +3160,7 @@
         assert.shadowDom.equal(
           element,
           /* HTML */ `
-            <div class="diffContainer sideBySide">
+            <div class="diffContainer newDiff sideBySide">
               <gr-diff-section class="left-FILE right-FILE"> </gr-diff-section>
               <gr-diff-row class="left-FILE right-FILE"> </gr-diff-row>
               <table class="selected-right" id="diffTable">
@@ -4013,7 +4016,7 @@
         <div>Lorem ipsum dolor sit amet, suspendisse inceptos vehicula</div>
       `);
       str = el.textContent ?? '';
-      annotateElementSpy = sinon.spy(GrAnnotation, 'annotateElement');
+      annotateElementSpy = sinon.spy(GrAnnotationImpl, 'annotateElement');
       layer = element.createIntralineLayer();
     });
 
@@ -4125,7 +4128,7 @@
 
       const str0 = slice(str, 0, 6);
       const str1 = slice(str, 6);
-      const numHighlightedChars = GrAnnotation.getStringLength(str1);
+      const numHighlightedChars = getStringLength(str1);
 
       layer.annotate(el, lineNumberEl, l, Side.LEFT);
 
@@ -4152,7 +4155,10 @@
     test('does nothing with empty line', () => {
       const l = line('');
       const el = document.createElement('div');
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+      const annotateElementStub = sinon.stub(
+        GrAnnotationImpl,
+        'annotateElement'
+      );
 
       layer.annotate(el, lineNumberEl, l, Side.LEFT);
 
@@ -4164,7 +4170,10 @@
       const l = line(str);
       const el = document.createElement('div');
       el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+      const annotateElementStub = sinon.stub(
+        GrAnnotationImpl,
+        'annotateElement'
+      );
 
       layer.annotate(el, lineNumberEl, l, Side.LEFT);
 
@@ -4176,7 +4185,10 @@
       const l = line(str);
       const el = document.createElement('div');
       el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+      const annotateElementStub = sinon.stub(
+        GrAnnotationImpl,
+        'annotateElement'
+      );
 
       layer.annotate(el, lineNumberEl, l, Side.LEFT);
 
@@ -4195,7 +4207,10 @@
       const l = line(str);
       const el = document.createElement('div');
       el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+      const annotateElementStub = sinon.stub(
+        GrAnnotationImpl,
+        'annotateElement'
+      );
 
       layer.annotate(el, lineNumberEl, l, Side.LEFT);
 
@@ -4207,7 +4222,10 @@
       const l = line(str);
       const el = document.createElement('div');
       el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+      const annotateElementStub = sinon.stub(
+        GrAnnotationImpl,
+        'annotateElement'
+      );
 
       layer.annotate(el, lineNumberEl, l, Side.LEFT);
 
@@ -4231,7 +4249,10 @@
       const l = line(str);
       const el = document.createElement('div');
       el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+      const annotateElementStub = sinon.stub(
+        GrAnnotationImpl,
+        'annotateElement'
+      );
 
       layer.annotate(el, lineNumberEl, l, Side.LEFT);
 
@@ -4259,7 +4280,10 @@
     test('does nothing with empty line', () => {
       const l = line('');
       const el = document.createElement('div');
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+      const annotateElementStub = sinon.stub(
+        GrAnnotationImpl,
+        'annotateElement'
+      );
       layer.annotate(el, lineNumberEl, l, Side.LEFT);
       assert.isFalse(annotateElementStub.called);
     });
@@ -4269,7 +4293,10 @@
       const l = line(str);
       const el = document.createElement('div');
       el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+      const annotateElementStub = sinon.stub(
+        GrAnnotationImpl,
+        'annotateElement'
+      );
       layer.annotate(el, lineNumberEl, l, Side.LEFT);
       assert.isFalse(annotateElementStub.called);
     });
@@ -4279,7 +4306,10 @@
       const l = line(str);
       const el = document.createElement('div');
       el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+      const annotateElementStub = sinon.stub(
+        GrAnnotationImpl,
+        'annotateElement'
+      );
       layer.annotate(el, lineNumberEl, l, Side.LEFT);
       assert.isTrue(annotateElementStub.called);
       assert.equal(annotateElementStub.lastCall.args[1], 11);
@@ -4291,7 +4321,10 @@
       const l = line(str);
       const el = document.createElement('div');
       el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+      const annotateElementStub = sinon.stub(
+        GrAnnotationImpl,
+        'annotateElement'
+      );
       layer.annotate(el, lineNumberEl, l, Side.LEFT);
       assert.isTrue(annotateElementStub.called);
       assert.equal(annotateElementStub.lastCall.args[1], 11);
@@ -4303,7 +4336,10 @@
       const l = line(str);
       const el = document.createElement('div');
       el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+      const annotateElementStub = sinon.stub(
+        GrAnnotationImpl,
+        'annotateElement'
+      );
       layer.annotate(el, lineNumberEl, l, Side.LEFT);
       assert.isTrue(annotateElementStub.called);
       assert.equal(annotateElementStub.lastCall.args[1], 11);
@@ -4315,7 +4351,10 @@
       const l = line(str);
       const el = document.createElement('div');
       el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+      const annotateElementStub = sinon.stub(
+        GrAnnotationImpl,
+        'annotateElement'
+      );
       layer.annotate(el, lineNumberEl, l, Side.LEFT);
       assert.isTrue(annotateElementStub.called);
       assert.equal(annotateElementStub.lastCall.args[1], 1);
@@ -4331,7 +4370,10 @@
       const l = line(str);
       const el = document.createElement('div');
       el.textContent = str;
-      const annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+      const annotateElementStub = sinon.stub(
+        GrAnnotationImpl,
+        'annotateElement'
+      );
       layer.annotate(el, lineNumberEl, l, Side.LEFT);
       assert.isFalse(annotateElementStub.called);
     });
diff --git a/polygerrit-ui/app/embed/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.ts b/polygerrit-ui/app/embed/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.ts
index e2837ab..24729ff 100644
--- a/polygerrit-ui/app/embed/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.ts
+++ b/polygerrit-ui/app/embed/diff/gr-ranged-comment-layer/gr-ranged-comment-layer.ts
@@ -3,7 +3,7 @@
  * Copyright 2016 Google LLC
  * SPDX-License-Identifier: Apache-2.0
  */
-import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
+import {GrAnnotationImpl} from '../gr-diff-highlight/gr-annotation';
 import {GrDiffLine} from '../gr-diff/gr-diff-line';
 import {strToClassName} from '../../../utils/dom-util';
 import {Side} from '../../../constants/constants';
@@ -94,7 +94,7 @@
     }
 
     for (const range of ranges) {
-      GrAnnotation.annotateElement(
+      GrAnnotationImpl.annotateElement(
         el,
         range.start,
         range.end - range.start,
diff --git a/polygerrit-ui/app/embed/diff/gr-ranged-comment-layer/gr-ranged-comment-layer_test.ts b/polygerrit-ui/app/embed/diff/gr-ranged-comment-layer/gr-ranged-comment-layer_test.ts
index b90d6f7..5bfd94d 100644
--- a/polygerrit-ui/app/embed/diff/gr-ranged-comment-layer/gr-ranged-comment-layer_test.ts
+++ b/polygerrit-ui/app/embed/diff/gr-ranged-comment-layer/gr-ranged-comment-layer_test.ts
@@ -10,11 +10,11 @@
   CommentRangeLayer,
   GrRangedCommentLayer,
 } from './gr-ranged-comment-layer';
-import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
 import {GrDiffLine} from '../gr-diff/gr-diff-line';
 import {GrDiffLineType, Side} from '../../../api/diff';
 import {SinonStub} from 'sinon';
 import {assert} from '@open-wc/testing';
+import {GrAnnotationImpl} from '../gr-diff-highlight/gr-annotation';
 
 const rangeA: CommentRangeLayer = {
   side: Side.LEFT,
@@ -130,7 +130,7 @@
     }
 
     setup(() => {
-      annotateElementStub = sinon.stub(GrAnnotation, 'annotateElement');
+      annotateElementStub = sinon.stub(GrAnnotationImpl, 'annotateElement');
       el = document.createElement('div');
       el.setAttribute('data-side', Side.LEFT);
       line = new GrDiffLine(GrDiffLineType.BOTH);
diff --git a/polygerrit-ui/app/embed/diff/gr-selection-action-box/gr-selection-action-box.ts b/polygerrit-ui/app/embed/diff/gr-selection-action-box/gr-selection-action-box.ts
index 68aa3b4..756f6fa 100644
--- a/polygerrit-ui/app/embed/diff/gr-selection-action-box/gr-selection-action-box.ts
+++ b/polygerrit-ui/app/embed/diff/gr-selection-action-box/gr-selection-action-box.ts
@@ -40,20 +40,22 @@
     this.addEventListener('mousedown', e => this.handleMouseDown(e));
   }
 
-  static override styles = [
-    sharedStyles,
-    css`
-      :host {
-        cursor: pointer;
-        font-family: var(--font-family);
-        position: absolute;
-        white-space: nowrap;
-      }
-      gr-tooltip[invisible] {
-        visibility: hidden;
-      }
-    `,
-  ];
+  static override get styles() {
+    return [
+      sharedStyles,
+      css`
+        :host {
+          cursor: pointer;
+          font-family: var(--font-family);
+          position: absolute;
+          white-space: nowrap;
+        }
+        gr-tooltip[invisible] {
+          visibility: hidden;
+        }
+      `,
+    ];
+  }
 
   override render() {
     return html`
diff --git a/polygerrit-ui/app/embed/diff/gr-syntax-layer/gr-syntax-layer-worker.ts b/polygerrit-ui/app/embed/diff/gr-syntax-layer/gr-syntax-layer-worker.ts
index baa2ab4..4e166ba 100644
--- a/polygerrit-ui/app/embed/diff/gr-syntax-layer/gr-syntax-layer-worker.ts
+++ b/polygerrit-ui/app/embed/diff/gr-syntax-layer/gr-syntax-layer-worker.ts
@@ -3,7 +3,7 @@
  * Copyright 2022 Google LLC
  * SPDX-License-Identifier: Apache-2.0
  */
-import {GrAnnotation} from '../gr-diff-highlight/gr-annotation';
+import {annotateElement} from '../gr-diff-highlight/gr-annotation';
 import {GrDiffLine} from '../gr-diff/gr-diff-line';
 import {DiffFileMetaInfo, DiffInfo} from '../../../types/diff';
 import {DiffLayer, DiffLayerListener} from '../../../types/types';
@@ -212,7 +212,7 @@
     for (const range of ranges) {
       if (!CLASS_SAFELIST.has(range.className)) continue;
       if (range.length === 0) continue;
-      GrAnnotation.annotateElement(
+      annotateElement(
         el,
         range.start,
         range.length,