content/static,devtools,internal: update header to spec

This change implements the latest designs for the site header,
adds a new fixed header to details pages, and updates to the
latest Closure Compiler Docker image tag to support an API used
by the new fixed header implementation (ResizeObserver).

The global header is no longer sticky, but on the details page
a hybrid header that shows a combination of the header content
and details tabs is displayed when the inline tab list goes out
of view.

Both the inline and fixed tab lists are responsive in that the
elements are pushed to an overflow container when they can no
longer fit on screen. A native <select> tag is used for this to
avoid implementing a popup menu (perhaps that can be done in a
future change).

The mechanism used to copy the current path to the clipboard has
also been updated to avoid hacks that didn’t play well with
screen readers. This method does not work on iOS, but a message
is displayed to the user in that case.

Fixes golang/go#37110

Change-Id: I2b8b73d7e85c122992b106e9b89d7e207be9f099
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/245400
Run-TryBot: Andrew Bonventre <andybons@golang.org>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Jamal Carvalho <jamal@golang.org>
diff --git a/content/static/css/sidenav.css b/content/static/css/sidenav.css
index f305b99..71ef5cd 100644
--- a/content/static/css/sidenav.css
+++ b/content/static/css/sidenav.css
@@ -23,8 +23,9 @@
   height: 3rem;
   margin: 0 -1rem;
   position: sticky;
-  top: 4rem; /* The site header height on mobile */
+  top: var(--header-height);
   transition: box-shadow 0.2s linear;
+  z-index: 1000;
 }
 .DocNavMobile--withShadow {
   box-shadow: 0 0.1875rem 0.1875rem rgba(0, 0, 0, 0.2);
@@ -106,13 +107,13 @@
   }
   .DocNav {
     display: block;
-    max-height: calc(100vh - 6.511rem); /* 6.511rem is the site header height */
+    max-height: calc(100vh - var(--header-height));
     overflow-x: hidden;
     overflow-y: scroll;
     padding-top: 1rem;
     padding-left: 0.25rem;
     position: sticky;
-    top: 6.511rem;
+    top: var(--header-height);
   }
   .DocNavMobile {
     display: none;
diff --git a/content/static/css/stylesheet.css b/content/static/css/stylesheet.css
index 42a49b6..f01cee9 100644
--- a/content/static/css/stylesheet.css
+++ b/content/static/css/stylesheet.css
@@ -27,6 +27,8 @@
   --slate: #253443; /* Footer background. */
   --white: #fff;
   --yellow: #fddd00;
+
+  --header-height: 3.5rem;
 }
 
 *,
@@ -34,8 +36,14 @@
 :after {
   box-sizing: border-box;
 }
-html {
+html,
+body {
+  /**
+   * Prevent jitter when focusing within fixed elements on iOS.
+   */
+  -webkit-overflow-scrolling: touch;
   height: 100%;
+  overflow: auto;
 }
 body {
   color: var(--gray-1);
@@ -167,7 +175,7 @@
   }
 }
 
-/* TODO: Remove deprecated Homepage styles after "new-hompage" launch */
+/* TODO: Remove deprecated Homepage styles after "new-homepage" launch */
 .SearchForm[aria-expanded='false'] .AutoComplete-list,
 .Header-searchForm[aria-expanded='false'] .AutoComplete-list {
   display: none;
@@ -251,18 +259,11 @@
   max-width: 75.75rem;
 }
 .Site-header {
-  background: var(--white);
-  border-bottom: 0.0625rem solid var(--gray-8);
-  -webkit-position: sticky;
-  position: sticky;
-  top: 0;
+  background: var(--turq-dark);
+  box-shadow: 0 0.0625rem 0.125rem rgba(171, 171, 171, 0.3);
   width: 100%;
   z-index: 1;
 }
-.Site-header--dark {
-  background: var(--turq-dark);
-  border: none;
-}
 :target::before {
   content: ' ';
   display: block;
@@ -271,64 +272,62 @@
   pointer-events: none;
   visibility: hidden;
 }
-@media only screen and (min-width: 52rem) {
-  :target::before {
-    height: calc(5.125rem + 2.5rem);
-    margin-top: calc(-5.125rem - 2.5rem); /* Account for added height of banner. */
-  }
-}
 .Header-logoLink {
   margin-right: auto;
 }
 .Header-nav {
+  align-items: center;
   display: flex;
-  justify-content: flex-end;
+  height: var(--header-height);
+  justify-content: space-between;
 }
 .Header-logo {
   display: block;
   height: 2rem;
-  margin: 1rem;
+  margin: 0 2.25rem 0 1rem;
   width: 5.125rem;
 }
-.Header-menuItem {
-  display: none;
-}
 .Header-menu {
   display: flex;
   list-style: none;
-  margin: 0 0 0 1.4rem;
+  height: 100%;
+  margin: 0;
   padding: 0;
 }
+.Header-menuItem {
+  display: none;
+}
 @media only screen and (min-width: 57.7rem) {
   .Header {
     padding: 0 1.5rem;
   }
+  .Header-logo {
+    margin-left: 1.4rem;
+  }
   .Header-menuItem {
     display: inline-flex;
     flex: none;
   }
   .Header-menu {
     justify-content: flex-end;
+    margin-left: 1.4rem;
   }
   .Header-navOpen {
     display: none;
   }
   .Header-logo {
-    margin: 1rem 1rem 1rem 0;
+    margin-left: 0;
   }
 }
-.Site-header--dark .Header-menuItem a:link,
-.Site-header--dark .Header-menuItem a:visited {
-  color: var(--white);
-}
 .Header-menuItem a:link,
 .Header-menuItem a:visited {
-  border-bottom: 3px solid transparent;
-  border-top: 3px solid transparent; /* To ensure the text remains centered. */
-  color: var(--gray-2);
-  display: inline-block;
-  margin: 0 15px;
-  padding: 20px 15px;
+  align-items: center;
+  border-bottom: 0.1875rem solid transparent;
+  border-top: 0.1875rem solid transparent; /* To ensure the text remains centered. */
+  color: var(--white);
+  display: inline-flex;
+  margin: 0 0.3125rem;
+  padding: 0 0.9375rem;
   text-align: center;
   text-decoration: none;
   width: 100%;
@@ -340,46 +339,32 @@
 }
 .Header-menuItem a:hover {
   border-top-color: var(--pink);
-  color: var(--gray-2);
 }
 .Header-navOpen {
-  background: no-repeat center/2rem url('/static/img/menu-24px.svg');
+  background: no-repeat center/2rem url('/static/img/menu-24px-white.svg');
   border: none;
   height: 2.5rem;
   margin: auto 1rem;
   width: 2.5rem;
 }
-.Site-header--dark .Header-navOpen {
-  background: no-repeat center/2rem url('/static/img/menu-24px-white.svg');
-}
-.Header-searchForm-container {
-  position: relative;
-  display: inline-flex;
-  margin: 0.6rem auto 0 1.4rem;
-  flex: 1;
-}
-.Experiment-autoComplete .Header-searchForm {
-  background-color: white;
-}
 .Header-searchForm {
-  border: 0.0625rem solid var(--gray-8);
-  border-radius: 1.4rem;
-  position: absolute;
-  left: 0;
-  right: 0;
+  align-items: center;
+  background-color: transparent;
+  border: 0.0625rem solid transparent;
+  border-radius: 0.25rem;
+  display: flex;
   font-size: 1rem;
-  padding: 0.5rem 0.5rem 0.5rem 1rem;
-  min-height: 2.863125rem;
+  height: 2rem;
+  position: relative;
+  width: 2.25rem;
 }
-.Site-header--dark .Experiment-autoComplete input[type='text'].Header-searchFormInput {
-  color: initial;
-}
-.Site-header--dark .Experiment-autoComplete input[type='text'].Header-searchFormInput::placeholder {
-  color: initial;
-}
-.Site-header--dark input[type='text'].Header-searchFormInput,
-.Site-header--dark input[type='text'].Header-searchFormInput::placeholder {
-  color: var(--white);
+.Header-searchForm:focus-within {
+  background-color: var(--white);
+  border-color: var(--gray-8);
+  flex: 1;
+  left: 1rem;
+  position: absolute;
+  width: calc(100% - 5.25rem);
 }
 .Header-searchFormInput {
   background-color: transparent;
@@ -387,8 +372,21 @@
   box-sizing: border-box;
   flex: 1;
   font: inherit;
+  height: 100%;
   outline: none;
-  width: 1rem;
+  position: absolute;
+  width: 100%;
+}
+.Header-searchFormInput::placeholder {
+  color: transparent;
+}
+.Header-searchForm:focus-within .Header-searchFormInput {
+  height: auto;
+  position: relative;
+  width: auto;
+}
+.Header-searchForm:focus-within .Header-searchFormInput::placeholder {
+  color: var(--gray-4);
 }
 .Header-searchFormSubmit {
   background-color: transparent;
@@ -400,11 +398,35 @@
 .Header-searchFormSubmitIcon {
   box-sizing: border-box;
   cursor: pointer;
-  fill: var(--turq-med);
-  width: 23px;
-}
-.Site-header--dark .Header-searchFormSubmitIcon {
   fill: var(--white);
+  width: 1.4375rem;
+}
+.Header-searchForm:focus-within .Header-searchFormSubmitIcon {
+  fill: var(--gray-4);
+}
+@media only screen and (min-width: 26.875rem) {
+  .Header-searchForm {
+    background-color: var(--white);
+    border-color: var(--gray-8);
+    flex: 1;
+    width: auto;
+  }
+  .Header-searchForm:focus-within {
+    left: 0;
+    position: relative;
+    width: auto;
+  }
+  .Header-searchFormSubmitIcon {
+    fill: var(--gray-4);
+  }
+  .Header-searchFormInput {
+    height: auto;
+    position: relative;
+    width: auto;
+  }
+  .Header-searchFormInput::placeholder {
+    color: var(--gray-4);
+  }
 }
 .NavigationDrawer {
   background: var(--white);
@@ -473,6 +495,12 @@
 .DetailsHeader {
   margin-top: 0.75rem;
 }
+.DetailsHeader-breadcrumb {
+  align-items: center;
+  display: flex;
+  flex-wrap: wrap;
+  word-break: break-word;
+}
 .DetailsHeader-main {
   margin-top: 0.25rem;
 }
@@ -520,16 +548,7 @@
 }
 .DetailsHeader-breadcrumbDivider {
   color: var(--gray-3);
-}
-.DetailsHeader-pathInput {
-  /*
-   * An input element that can be selected so its contents can be
-   * copied to the clipboard. We can't use a hidden element, so
-   * put this visible one very far off the screen.
-   */
-  left: -50vw;
-  position: absolute;
-  top: 62rem;
+  margin: 0 0.3rem;
 }
 
 .Error-gopher,
@@ -762,75 +781,304 @@
   margin: 0 auto;
   max-width: 60em;
 }
-.DetailsNav {
-  margin: 0 -1rem 0 -1rem;
-  overflow-x: scroll;
-  overflow-y: hidden;
-  mask-image: linear-gradient(
-    90deg,
-    transparent,
-    #000 1.25rem,
-    #000 calc(100% - 1.25rem),
-    transparent
-  );
-  padding: 0 1rem;
-  -ms-overflow-style: -ms-autohiding-scrollbar;
-  -webkit-mask-image: linear-gradient(
-    90deg,
-    transparent,
-    #000 1.25rem,
-    #000 calc(100% - 1.25rem),
-    transparent
-  );
-  -webkit-overflow-scrolling: touch;
-}
-@media only screen and (min-width: 43.75rem) {
-  .DetailsNav {
-    overflow-x: hidden;
-  }
-}
 
-.DetailsNav-list {
-  list-style: none;
-  margin: 0;
-  padding: 0;
-  white-space: nowrap;
-  border-bottom: 0.0625rem solid var(--gray-8);
+.CopyToClipboardButton {
+  background-color: transparent;
+  border: none;
+  cursor: pointer;
+  height: 1.5rem;
+  margin: 0 0.5rem;
+  position: relative;
+  width: 1.5rem;
 }
-.DetailsNav::-webkit-scrollbar {
+.CopyToClipboardButton:not([data-tooltip])::before,
+.CopyToClipboardButton:not([data-tooltip])::after,
+.CopyToClipboardButton[data-tooltip='']::before,
+.CopyToClipboardButton[data-tooltip='']::after {
   display: none;
 }
-.DetailsNav-tab {
+.CopyToClipboardButton::before {
+  background-color: rgba(0, 0, 0, 0.75);
+  border-radius: 3px;
+  color: var(--white);
+  content: attr(data-tooltip);
+  display: block;
+  font-size: 0.9em;
+  left: calc(100% + 0.125rem);
+  position: absolute;
+  padding: 0.25rem 0.3rem;
+  text-transform: uppercase;
+  top: 2px;
+  white-space: nowrap;
+  z-index: 1000;
+}
+.CopyToClipboardButton::after {
+  border-bottom: 0.25rem solid transparent;
+  border-left: 0;
+  border-right: 0.25rem solid rgba(0, 0, 0, 0.75);
+  border-top: 0.25rem solid transparent;
+  content: '';
+  display: block;
+  position: absolute;
+  right: -0.125rem;
+  top: 9px;
+  z-index: 1000;
+}
+.CopyToClipboardButton:hover {
+  background-color: var(--gray-9);
+}
+.CopyToClipboardButton:active {
+  background-color: var(--gray-8);
+}
+.CopyToClipboardButton-image {
+  display: block;
+  height: 0.9375rem;
+  width: 0.8125rem;
+}
+
+.DetailsNav {
+  align-items: center;
+  border-bottom: 0.0625rem solid var(--gray-8);
+  display: flex;
+  flex-wrap: nowrap;
+  justify-content: space-between;
+  min-width: 0;
+  position: relative;
+}
+.DetailsNav [aria-hidden='true'] {
+  display: none;
+}
+.DetailsNav [role='tablist'] {
+  white-space: nowrap;
+}
+.DetailsNav [role='tab'] {
   color: var(--gray-2);
   display: inline-block;
 }
-.DetailsNav-tab + .DetailsNav-tab {
+.DetailsNav [role='tab'] + [role='tab'] {
   margin-left: 1rem;
 }
-.DetailsNav-tab.selected {
-  border-bottom: 2px solid var(--turq-med);
-  color: var(--gray-1);
-  font-weight: bold;
-}
-.DetailsNav-tab:hover {
-  border-bottom: 2px solid var(--purple);
-}
-.DetailsNav-tabDisabled,
-.DetailsNav-tabDisabled:hover {
+.DetailsNav [role='tab'][aria-disabled='true'],
+.DetailsNav [role='tab'][aria-disabled='true']:hover {
   border-bottom: 2px solid var(--white);
   color: var(--gray-5);
 }
-.DetailsNav-link,
-.DetailsNav-link:link,
-.DetailsNav-link:visited {
+.DetailsNav [role='tab'],
+.DetailsNav [role='tab']:link,
+.DetailsNav [role='tab']:visited {
+  border-bottom: 2px solid transparent;
   display: inline-block;
   color: inherit;
   padding: 0.625rem 0.5rem;
 }
-.DetailsNav-link,
-.DetailsNav-link:hover {
+.DetailsNav [role='tab']:hover {
+  border-bottom-color: var(--purple);
   text-decoration: none;
 }
+.DetailsNav [role='tab'][aria-selected='true'] {
+  border-bottom: 2px solid var(--turq-med);
+  color: var(--gray-1);
+  font-weight: bold;
+}
+.DetailsNav [role='tab'][aria-hidden='true'] {
+  display: none;
+}
+.DetailsNav-overflowContainer {
+  display: none;
+  height: 1.5rem;
+  position: absolute;
+  right: 0;
+  top: 0.4375rem;
+  width: 1.5rem;
+}
+.DetailsNav.is-overflowing .DetailsNav-overflowContainer {
+  display: block;
+}
+.DetailsNav-overflowImage {
+  fill: var(--gray-3);
+  height: 100%;
+  left: 0;
+  position: absolute;
+  top: 0;
+  width: 100%;
+}
+.DetailsNav-overflowSelect {
+  -webkit-appearance: none;
+  -moz-appearance: none;
+  appearance: none;
+  background: transparent;
+  border: 0;
+  color: transparent;
+  cursor: pointer;
+  font-size: 1rem;
+  height: 100%;
+  left: 0;
+  position: absolute;
+  top: 0;
+  width: 100%;
+}
+/**
+ * Firefox allows for styling of option and optgroup tags.
+ * Ensure they don’t inherit the clear styling of their parent.
+ */
+.DetailsNav-overflowSelect option {
+  color: var(--gray-1);
+}
+
+.DetailsNavFixed {
+  background-color: var(--gray-10);
+  border-bottom: 1px solid var(--gray-8);
+  height: var(--header-height);
+  position: fixed;
+  top: 0;
+  left: 0;
+  transition: transform 100ms linear;
+  width: 100%;
+  z-index: 1000;
+}
+.DetailsNavFixed[aria-hidden='true'] {
+  transform: translateY(calc(var(--header-height) * -1));
+}
+.DetailsNavFixed [aria-hidden='true'] {
+  display: none;
+}
+.DetailsNavFixed-container {
+  align-items: center;
+  display: flex;
+  height: 100%;
+  margin: 0 auto;
+  max-width: 75.75rem;
+  padding: 0 0.5rem;
+  position: relative;
+}
+.DetailsNavFixed-logoLink {
+  margin-right: 1rem;
+}
+.DetailsNavFixed-logo {
+  display: block;
+  height: 1.695625;
+  width: 4.5rem;
+}
+.DetailsNavFixed-moduleInfo {
+  align-items: baseline;
+  display: flex;
+  flex-wrap: nowrap;
+  margin-right: 3rem;
+  min-width: 0;
+}
+.DetailsNavFixed-title {
+  font: 600 1.125rem/1.5 'Work Sans', arial, sans-serif;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  white-space: nowrap;
+}
+.DetailsNavFixed .CopyToClipboardButton {
+  top: 0.1875rem;
+}
+.DetailsNavFixed-pathInput {
+  left: -100vw;
+  position: absolute;
+  top: -100vh;
+}
+.DetailsNavFixed-version {
+  color: var(--gray-2);
+  font-size: 0.6875rem;
+  position: relative;
+  text-transform: uppercase;
+}
+@media only screen and (min-width: 37.5rem) {
+  .DetailsNavFixed-container {
+    padding: 0 0.5rem;
+  }
+  .DetailsNavFixed-logo {
+    height: 1.9541rem;
+    width: 5.1875rem;
+  }
+  .DetailsNavFixed-title {
+    font-size: 1.5rem;
+  }
+  .DetailsNavFixed .CopyToClipboardButton {
+    top: 0.0625rem;
+  }
+  .DetailsNavFixed-version {
+    top: -0.125rem;
+  }
+}
+.DetailsNavFixed-overflowingTabList {
+  display: flex;
+  flex: 1;
+  height: 100%;
+  min-width: 0;
+  position: relative;
+}
+.DetailsNavFixed [role='tablist'] {
+  display: flex;
+  flex: 1;
+  height: 100%;
+  justify-content: flex-end;
+  margin: 0;
+  padding: 0;
+}
+.DetailsNavFixed [role='tab'] + [role='tab'] {
+  margin-left: 1rem;
+}
+.DetailsNavFixed [role='tab'] {
+  border-bottom: 0.25rem solid transparent;
+  display: block;
+  height: 100%;
+  padding: 1.3125rem 0.5rem 0 0.5rem;
+  white-space: nowrap;
+}
+.DetailsNavFixed [role='tab']:hover {
+  border-bottom-color: var(--purple);
+  text-decoration: none;
+}
+.DetailsNavFixed [role='tab'][aria-selected='true'] {
+  border-bottom-color: var(--turq-dark);
+}
+.DetailsNavFixed [role='tab'][aria-hidden='true'] {
+  display: none;
+}
+.DetailsNavFixed-overflowContainer {
+  display: none;
+  height: 1.5rem;
+  position: absolute;
+  right: 0.0625rem;
+  top: 1.125rem;
+  width: 1.5rem;
+}
+.DetailsNavFixed-overflowingTabList.is-overflowing {
+  padding-right: 1.5rem;
+}
+.DetailsNavFixed-overflowingTabList.is-overflowing .DetailsNavFixed-overflowContainer {
+  display: block;
+}
+.DetailsNavFixed-overflowImage {
+  fill: var(--gray-3);
+  height: 100%;
+  left: 0;
+  position: absolute;
+  top: 0;
+  width: 100%;
+}
+.DetailsNavFixed-overflowSelect {
+  -webkit-appearance: none;
+  -moz-appearance: none;
+  appearance: none;
+  background: transparent;
+  border: 0;
+  color: transparent;
+  cursor: pointer;
+  font-size: 1rem;
+  height: 100%;
+  left: 0;
+  position: absolute;
+  top: 0;
+  width: 100%;
+}
+.DetailsNavFixed-overflowSelect option {
+  color: var(--gray-1);
+}
 
 .Container {
   color: var(--gray-1);
diff --git a/content/static/html/helpers/_search_bar.tmpl b/content/static/html/helpers/_search_bar.tmpl
index dd7a6cc..68679a5 100644
--- a/content/static/html/helpers/_search_bar.tmpl
+++ b/content/static/html/helpers/_search_bar.tmpl
@@ -34,30 +34,21 @@
 {{end}}
 
 {{define "header_search"}}
-  <div class="Header-searchForm-container{{if (.Experiments.IsActive "autocomplete")}} Experiment-autoComplete{{end}}">
-    <form class="Header-searchForm" action="/search" role="search" id="AutoComplete-parent" aria-owns="AutoComplete-list">
-      <div class="SearchForm-firstRow">
-        <input class="Header-searchFormInput js-autoComplete"
-          id="AutoComplete"
-          role="textbox"
-          aria-controls="AutoComplete-list"
-          aria-autocomplete="list"
-          aria-label="Search for a package"
-          type="text"
-          name="q"
-          size="1"
-          placeholder="Search for a package"
-          autocapitalize="off"
-          autocomplete="off"
-          autocorrect="off"
-          spellcheck="false"
-          title="Search for a package"
-          value="{{.Query}}"
-          {{block "search_additional_attrs" .}}{{end}}>
-        <button class="Header-searchFormSubmit" aria-label="Search for a package">
-          <svg class="Header-searchFormSubmitIcon" focusable="false" viewBox="0 0 24 24" aria-hidden="true" role="presentation"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path><path fill="none" d="M0 0h24v24H0z"></path></svg>
-        </button>
-      </div>
-    </form>
-  </div>
+  <form class="Header-searchForm" action="/search" role="search">
+    <button class="Header-searchFormSubmit" aria-label="Search for a package">
+      <svg class="Header-searchFormSubmitIcon" focusable="false" viewBox="0 0 24 24" aria-hidden="true" role="presentation"><path d="M15.5 14h-.79l-.28-.27C15.41 12.59 16 11.11 16 9.5 16 5.91 13.09 3 9.5 3S3 5.91 3 9.5 5.91 16 9.5 16c1.61 0 3.09-.59 4.23-1.57l.27.28v.79l5 4.99L20.49 19l-4.99-5zm-6 0C7.01 14 5 11.99 5 9.5S7.01 5 9.5 5 14 7.01 14 9.5 11.99 14 9.5 14z"></path><path fill="none" d="M0 0h24v24H0z"></path></svg>
+    </button>
+    <input class="Header-searchFormInput"
+      aria-label="Search for a package"
+      type="text"
+      name="q"
+      placeholder="Search for a package"
+      autocapitalize="off"
+      autocomplete="off"
+      autocorrect="off"
+      spellcheck="false"
+      title="Search for a package"
+      value="{{.Query}}"
+      {{block "search_additional_attrs" .}}{{end}}>
+  </form>
 {{end}}
diff --git a/content/static/html/pages/details.tmpl b/content/static/html/pages/details.tmpl
index 096ce0f..b3d7cf9 100644
--- a/content/static/html/pages/details.tmpl
+++ b/content/static/html/pages/details.tmpl
@@ -17,27 +17,12 @@
       {{end}}
       <span class="DetailsHeader-breadcrumbCurrent">{{.Current}}</span>
       {{if .CopyData}}
-        <button class="ImageButton js-detailsHeaderCopyPath" aria-label="Copy path to clipboard">
-          <!-- Inline the svg for the "copy" icon because when it was in a separate file
-               referenced by an img tag, it was loaded asynchronously and the page
-               jittered when it was finally loaded and its height was known. -->
-          <svg fill="#00add8" width="13px" height="15px" viewBox="0 0 13 15" version="1.1"
-               xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
-            <!-- Generator: Sketch 58 (84663) - https://sketch.com -->
-            <title>Copy path to clipboard</title>
-            <desc>Created with Sketch.</desc>
-            <g id="Symbols" stroke="none" stroke-width="1" fill-rule="evenodd">
-                <g id="go/header-package" transform="translate(-359.000000, -12.000000)">
-                    <path d="M367,12 L361,12 C359.896,12 359,12.896 359,14 L359,22 C359,23.104 359.896,24 361,24 L361,22 L361,14 L367,14 L369,14 C369,12.896 368.104,12 367,12 L367,12 Z M370,15 L364,15 C362.896,15 362,15.896 362,17 L362,25 C362,26.104 362.896,27 364,27 L370,27 C371.104,27 372,26.104 372,25 L372,17 C372,15.896 371.104,15 370,15 L370,15 Z M364,25 L370,25 L370,17 L364,17 L364,25 Z" id="ic_copy"></path>
-                </g>
-            </g>
-          </svg>
+        <button class="CopyToClipboardButton js-copyToClipboard"
+            title="Copy path to clipboard"
+            aria-label="Copy path to clipboard"
+            data-to-copy="{{.CopyData}}">
+          <img class="CopyToClipboardButton-image" src="/static/img/copy-click.svg" alt="">
         </button>
-        <!--  We need this input element to copy to the clipboard.
-              Consider using the Clipboard API instead (see
-              https://github.com/golang/go/issues/38162#issuecomment-645362803). -->
-        <input class="DetailsHeader-pathInput js-detailsHeaderPathInput" role="presentation" tabindex="-1"
-               value="{{.CopyData}}">
       {{end}}
     {{end}}
     </div>
@@ -45,10 +30,10 @@
       <h1 class="DetailsHeader-title">{{.Title}}</h1>
       <div class="DetailsHeader-version">{{$header.DisplayVersion}}</div>
 
-      {{- $ppath := "" -}}
-      {{- if ne $pageType "mod" -}}
-         {{- $ppath = $header.Path -}}
-      {{- end}}
+      {{$ppath := ""}}
+      {{if ne $pageType "mod"}}
+         {{$ppath = $header.Path}}
+      {{end}}
       <!-- Do not reformat the data attributes of the following div: the server uses a regexp to extract them. -->
       <div class="DetailsHeader-badge $$GODISCOVERY_LATESTCLASS$$"
            data-version="{{$header.LinkVersion}}" data-mpath="{{$header.ModulePath}}" data-ppath="{{$ppath}}" data-pagetype="{{$pageType}}">
@@ -62,12 +47,12 @@
       <span class="DetailsHeader-infoLabelDivider">|</span>
       <span class="DetailsHeader-infoLabelTitle">{{pluralize (len $header.Licenses) "License"}}: </span>
       <span data-test-id="DetailsHeader-infoLabelLicense">
-        {{range $i, $e := $header.Licenses -}}{{if $i}}, {{end}}
+        {{range $i, $e := $header.Licenses}}{{if $i}}, {{end}}
           <a href="{{$header.URL}}?tab=licenses#{{.Anchor}}">{{$e.Type}}</a>
-        {{- else -}}
+        {{else}}
           <span>None detected</span>
           <a href="/license-policy" class="Disclaimer-link"><em>not legal advice</em></a>
-        {{- end}}
+        {{end}}
       </span>
       {{if or (eq $pageType "pkg") (eq $pageType "dir")}}
         <span class="DetailsHeader-infoLabelDivider">|</span>
@@ -83,35 +68,93 @@
     </div>
   </header>
 
-  <nav class="DetailsNav js-modulesNav">
-    <ul class="DetailsNav-list" role="tablist">
+  <nav class="DetailsNav js-fixedHeaderSentinel js-overflowingTabList">
+    <div role="tablist">
       {{range .Tabs}}
-        <li class="{{if .Disabled}}DetailsNav-tabDisabled {{end}}DetailsNav-tab{{if eq .Name $.Settings.Name}} selected{{end}}" role="presentation">
-          {{if .Disabled}}
-            <a class="DetailsNav-link"
-               role="tab"
-               aria-selected="false">
-          {{else if eq .Name $.Settings.Name}}
-            <a class="DetailsNav-link"
-               role="tab"
-               aria-selected="true">
+        <a role="tab" href="{{$header.URL}}?tab={{.Name}}"
+          {{if .Disabled}}aria-disabled="true"{{end}}
+          {{if eq .Name $.Settings.Name}}
+            aria-selected="true"
           {{else}}
-            <a class="DetailsNav-link"
-               href="{{$header.URL}}?tab={{.Name}}"
-               role="tab"
-               aria-selected="false">
+            aria-selected="false"
           {{end}}
-          {{.DisplayName}}
-          </a>
-        </li>
+        >{{.DisplayName}}</a>
       {{end}}
-    </ul>
+    </div>
+    <div class="DetailsNav-overflowContainer">
+      <svg class="DetailsNav-overflowImage" xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24">
+        <path d="M0 0h24v24H0z" fill="none"/>
+        <path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>
+      </svg>
+      <select class="DetailsNav-overflowSelect" aria-label="More">
+        {{range .Tabs}}
+          <option
+            value="{{$header.URL}}?tab={{.Name}}"
+            {{if .Disabled}}disabled{{end}}
+            {{if eq .Name $.Settings.Name}}selected{{end}}
+          >{{.DisplayName}}</option>
+        {{end}}
+      </select>
+    </div>
   </nav>
 
+  <div class="DetailsNavFixed js-fixedHeader" aria-hidden="true">
+    <div class="DetailsNavFixed-container">
+      <a href="https://go.dev/" class="DetailsNavFixed-logoLink">
+        <img class="DetailsNavFixed-logo" src="/static/img/go-logo-blue.svg" alt="Go">
+      </a>
+      <div class="DetailsNavFixed-moduleInfo">
+        <span class="DetailsNavFixed-title">
+          {{.Title}}
+        </span>
+        {{with .Breadcrumb}}
+          {{if .CopyData}}
+            <button class="CopyToClipboardButton js-copyToClipboard"
+                title="Copy path to clipboard"
+                aria-label="Copy path to clipboard"
+                data-to-copy="{{.CopyData}}">
+              <img class="CopyToClipboardButton-image" src="/static/img/copy-click.svg" alt="">
+            </button>
+          {{end}}
+        {{end}}
+        <div class="DetailsNavFixed-version">{{$header.DisplayVersion}}</div>
+      </div>
+      <div class="DetailsNavFixed-overflowingTabList js-overflowingTabList">
+        <div role="tablist">
+          {{range .Tabs}}
+            <a role="tab" href="{{$header.URL}}?tab={{.Name}}"
+              {{if .Disabled}}aria-disabled="true"{{end}}
+              {{if eq .Name $.Settings.Name}}
+                aria-selected="true"
+              {{else}}
+                aria-selected="false"
+              {{end}}
+            >{{.DisplayName}}</a>
+          {{end}}
+        </div>
+        <div class="DetailsNavFixed-overflowContainer">
+          <svg class="DetailsNavFixed-overflowImage" xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 0 24 24" width="24">
+            <path d="M0 0h24v24H0z" fill="none"/>
+            <path d="M12 8c1.1 0 2-.9 2-2s-.9-2-2-2-2 .9-2 2 .9 2 2 2zm0 2c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2zm0 6c-1.1 0-2 .9-2 2s.9 2 2 2 2-.9 2-2-.9-2-2-2z"/>
+          </svg>
+          <select class="DetailsNavFixed-overflowSelect" aria-label="More">
+            {{range .Tabs}}
+              <option
+                value="{{$header.URL}}?tab={{.Name}}"
+                {{if .Disabled}}disabled{{end}}
+                {{if eq .Name $.Settings.Name}}selected{{end}}
+              >{{.DisplayName}}</option>
+            {{end}}
+          </select>
+        </div>
+      </div>
+    </div>
+  </div>
+
   <div class="DetailsContent">
-    {{if .CanShowDetails -}}
+    {{if .CanShowDetails}}
       {{template "details_content" .Details}}
-    {{- else}}
+    {{else}}
       <h2>“{{.Settings.DisplayName}}” not displayed due to license restrictions.</h2>
       See our <a href="/license-policy">license policy</a>.
     {{end}}
@@ -120,29 +163,8 @@
 {{end}}
 
 {{define "post_content"}}
-
-<!-- inputEl.blur() below prevents a jump to the focused element in some browsers.
-     Do not add comments to the script below: they are stripped by html/template
-     (https://golang.org/issue/28628), which messes up the CSP hash.
--->     
-<script>
-const navEl = document.querySelector('.js-modulesNav');
-const selectedEl = navEl.querySelector(`[aria-selected='true']`);
-if (selectedEl.offsetLeft + selectedEl.offsetWidth > navEl.offsetWidth) {
-  navEl.scrollLeft = selectedEl.offsetLeft;
-}
-
-const copyButton = document.querySelector('.js-detailsHeaderCopyPath');
-if (copyButton) {
-  copyButton.addEventListener('click', e => {
-    e.preventDefault();
-    const inputEl = document.querySelector('.js-detailsHeaderPathInput');
-    inputEl.select();
-    document.execCommand('copy');
-    inputEl.blur();
-  });
-}
-</script>
-
-{{block "details_post_content" .}}{{end}}
+  <script>
+    loadScript('/static/js/details.min.js');
+  </script>
+  {{block "details_post_content" .}}{{end}}
 {{end}}
diff --git a/content/static/js/badge.min.js b/content/static/js/badge.min.js
index b360943..d75d226 100644
--- a/content/static/js/badge.min.js
+++ b/content/static/js/badge.min.js
@@ -4,5 +4,6 @@
  Use of this source code is governed by a BSD-style
  license that can be found in the LICENSE file.
 */
-var snippetEls=document.querySelectorAll(".js-toolsCopySnippet");snippetEls.forEach(function(a){a.addEventListener("click",function(a){a.preventDefault();a.currentTarget.select();document.execCommand("copy")})});var pathEl=document.querySelector(".js-toolsPathInput"),htmlEl=document.querySelector('input[name="html"].js-toolsCopySnippet'),markdownEl=document.querySelector('input[name="markdown"].js-toolsCopySnippet'),badgeEl=document.querySelector(".js-badgeExampleButton");
-pathEl&&htmlEl&&markdownEl&&badgeEl&&pathEl.addEventListener("input",function(a){var c=window.location.origin,b=c+"/"+a.target.value;a=c+"/badge/"+a.target.value;htmlEl.value='<a href="'+b+'"><img src="'+a+'" alt="PkgGoDev"></a>';markdownEl.value="[![PkgGoDev]("+a+")]("+b+")";badgeEl.href=b});
+var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.createTemplateTagFirstArg=function(a){return a.raw=a};$jscomp.createTemplateTagFirstArgWithRaw=function(a,b){a.raw=b;return a};var snippetEls=document.querySelectorAll(".js-toolsCopySnippet");snippetEls.forEach(function(a){a.addEventListener("click",function(b){b.preventDefault();b.currentTarget.select();document.execCommand("copy")})});
+var pathEl=document.querySelector(".js-toolsPathInput"),htmlEl=document.querySelector('input[name="html"].js-toolsCopySnippet'),markdownEl=document.querySelector('input[name="markdown"].js-toolsCopySnippet'),badgeEl=document.querySelector(".js-badgeExampleButton");
+pathEl&&htmlEl&&markdownEl&&badgeEl&&pathEl.addEventListener("input",function(a){var b=window.location.origin,c=b+"/"+a.target.value;a=b+"/badge/"+a.target.value;htmlEl.value='<a href="'+c+'"><img src="'+a+'" alt="PkgGoDev"></a>';markdownEl.value="[![PkgGoDev]("+a+")]("+c+")";badgeEl.href=c});
diff --git a/content/static/js/base.min.js b/content/static/js/base.min.js
index 6705be6..e7afef1 100644
--- a/content/static/js/base.min.js
+++ b/content/static/js/base.min.js
@@ -4,5 +4,5 @@
  Use of this source code is governed by a BSD-style
  license that can be found in the LICENSE file.
 */
-(function(){var b=document.querySelector(".js-header"),c=document.querySelectorAll(".js-headerMenuButton");c.forEach(function(d){d.addEventListener("click",function(a){a.preventDefault();b.classList.toggle("is-active");d.setAttribute("aria-expanded",b.classList.contains("is-active"))})});var a=document.querySelector(".js-scrim");a&&a.hasOwnProperty("addEventListener")&&a.addEventListener("click",function(a){a.preventDefault();b.classList.remove("is-active");c.forEach(function(a){a.setAttribute("aria-expanded",
-b.classList.contains("is-active"))})})})();(function(){window.dataLayer=window.dataLayer||[];window.dataLayer.push({"gtm.start":(new Date).getTime(),event:"gtm.js"})})();
+(function(){var a=document.querySelector(".js-header"),e=document.querySelectorAll(".js-headerMenuButton");e.forEach(function(b){b.addEventListener("click",function(c){c.preventDefault();a.classList.toggle("is-active");b.setAttribute("aria-expanded",a.classList.contains("is-active"))})});var d=document.querySelector(".js-scrim");d&&d.hasOwnProperty("addEventListener")&&d.addEventListener("click",function(b){b.preventDefault();a.classList.remove("is-active");e.forEach(function(c){c.setAttribute("aria-expanded",
+a.classList.contains("is-active"))})})})();(function(){window.dataLayer=window.dataLayer||[];window.dataLayer.push({"gtm.start":(new Date).getTime(),event:"gtm.js"})})();
diff --git a/content/static/js/clipboard.js b/content/static/js/clipboard.js
new file mode 100644
index 0000000..c9b7e35
--- /dev/null
+++ b/content/static/js/clipboard.js
@@ -0,0 +1,69 @@
+/**
+ * @license
+ * Copyright 2019-2020 The Go Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ */
+
+/**
+ * This class decorates an element to copy arbitrary data attached via a data-
+ * attribute to the clipboard.
+ */
+class CopyToClipboardController {
+  /**
+   * The element that will trigger copying text to the clipboard. The text is
+   * expected to be within its data-to-copy attribute.
+   * @param {!Element} el
+   */
+  constructor(el) {
+    /**
+     * @type {!Element}
+     * @private
+     */
+    this._el = el;
+
+    /**
+     * The data to be copied to the clipboard.
+     * @type {string}
+     * @private
+     */
+    this._data = el.dataset['toCopy'];
+
+    el.addEventListener('click', e => this.handleCopyClick(/** @type {!Event} */ (e)));
+  }
+
+  /**
+   * Handles when the primary element is clicked.
+   * @param {!Event} e
+   * @private
+   */
+  handleCopyClick(e) {
+    e.preventDefault();
+    const TOOLTIP_SHOW_DURATION_MS = 1000;
+
+    // This API is not available on iOS.
+    if (!navigator.clipboard) {
+      this.showTooltipText('Unable to copy', TOOLTIP_SHOW_DURATION_MS);
+      return;
+    }
+    navigator.clipboard
+      .writeText(this._data)
+      .then(() => {
+        this.showTooltipText('Copied!', TOOLTIP_SHOW_DURATION_MS);
+      })
+      .catch(() => {
+        this.showTooltipText('Unable to copy', TOOLTIP_SHOW_DURATION_MS);
+      });
+  }
+
+  /**
+   * Shows the given text in a tooltip for a specified amount of time, in milliseconds.
+   * @param {string} text
+   * @param {number} durationMs
+   * @private
+   */
+  showTooltipText(text, durationMs) {
+    this._el.setAttribute('data-tooltip', text);
+    setTimeout(() => this._el.setAttribute('data-tooltip', ''), durationMs);
+  }
+}
diff --git a/content/static/js/completion.min.js b/content/static/js/completion.min.js
index b6b93ff..cc88efd 100644
--- a/content/static/js/completion.min.js
+++ b/content/static/js/completion.min.js
@@ -4,37 +4,41 @@
  Use of this source code is governed by a BSD-style
  license that can be found in the LICENSE file.
 */
-var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.arrayIteratorImpl=function(a){var b=0;return function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}}};$jscomp.arrayIterator=function(a){return{next:$jscomp.arrayIteratorImpl(a)}};$jscomp.makeIterator=function(a){var b="undefined"!=typeof Symbol&&Symbol.iterator&&a[Symbol.iterator];return b?b.call(a):$jscomp.arrayIterator(a)};
-$jscomp.getGlobal=function(a){a=["object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global,a];for(var b=0;b<a.length;++b){var d=a[b];if(d&&d.Math==Math)return d}return globalThis};$jscomp.global=$jscomp.getGlobal(this);$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.SIMPLE_FROUND_POLYFILL=!1;
-$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,d){a!=Array.prototype&&a!=Object.prototype&&(a[b]=d.value)};$jscomp.polyfill=function(a,b,d,e){if(b){d=$jscomp.global;a=a.split(".");for(e=0;e<a.length-1;e++){var c=a[e];c in d||(d[c]={});d=d[c]}a=a[a.length-1];e=d[a];b=b(e);b!=e&&null!=b&&$jscomp.defineProperty(d,a,{configurable:!0,writable:!0,value:b})}};$jscomp.FORCE_POLYFILL_PROMISE=!1;
-$jscomp.polyfill("Promise",function(a){function b(){this.batch_=null}function d(a){return a instanceof c?a:new c(function(b,g){b(a)})}if(a&&!$jscomp.FORCE_POLYFILL_PROMISE)return a;b.prototype.asyncExecute=function(a){if(null==this.batch_){this.batch_=[];var b=this;this.asyncExecuteFunction(function(){b.executeBatch_()})}this.batch_.push(a)};var e=$jscomp.global.setTimeout;b.prototype.asyncExecuteFunction=function(a){e(a,0)};b.prototype.executeBatch_=function(){for(;this.batch_&&this.batch_.length;){var a=
-this.batch_;this.batch_=[];for(var b=0;b<a.length;++b){var c=a[b];a[b]=null;try{c()}catch(k){this.asyncThrow_(k)}}}this.batch_=null};b.prototype.asyncThrow_=function(a){this.asyncExecuteFunction(function(){throw a;})};var c=function(a){this.state_=0;this.result_=void 0;this.onSettledCallbacks_=[];var b=this.createResolveAndReject_();try{a(b.resolve,b.reject)}catch(h){b.reject(h)}};c.prototype.createResolveAndReject_=function(){function a(a){return function(g){c||(c=!0,a.call(b,g))}}var b=this,c=!1;
-return{resolve:a(this.resolveTo_),reject:a(this.reject_)}};c.prototype.resolveTo_=function(a){if(a===this)this.reject_(new TypeError("A Promise cannot resolve to itself"));else if(a instanceof c)this.settleSameAsPromise_(a);else{a:switch(typeof a){case "object":var b=null!=a;break a;case "function":b=!0;break a;default:b=!1}b?this.resolveToNonPromiseObj_(a):this.fulfill_(a)}};c.prototype.resolveToNonPromiseObj_=function(a){var b=void 0;try{b=a.then}catch(h){this.reject_(h);return}"function"==typeof b?
-this.settleSameAsThenable_(b,a):this.fulfill_(a)};c.prototype.reject_=function(a){this.settle_(2,a)};c.prototype.fulfill_=function(a){this.settle_(1,a)};c.prototype.settle_=function(a,b){if(0!=this.state_)throw Error("Cannot settle("+a+", "+b+"): Promise already settled in state"+this.state_);this.state_=a;this.result_=b;this.executeOnSettledCallbacks_()};c.prototype.executeOnSettledCallbacks_=function(){if(null!=this.onSettledCallbacks_){for(var a=0;a<this.onSettledCallbacks_.length;++a)f.asyncExecute(this.onSettledCallbacks_[a]);
-this.onSettledCallbacks_=null}};var f=new b;c.prototype.settleSameAsPromise_=function(a){var b=this.createResolveAndReject_();a.callWhenSettled_(b.resolve,b.reject)};c.prototype.settleSameAsThenable_=function(a,b){var c=this.createResolveAndReject_();try{a.call(b,c.resolve,c.reject)}catch(k){c.reject(k)}};c.prototype.then=function(a,b){function d(a,b){return"function"==typeof a?function(b){try{g(a(b))}catch(q){e(q)}}:b}var g,e,f=new c(function(a,b){g=a;e=b});this.callWhenSettled_(d(a,g),d(b,e));return f};
-c.prototype.catch=function(a){return this.then(void 0,a)};c.prototype.callWhenSettled_=function(a,b){function c(){switch(d.state_){case 1:a(d.result_);break;case 2:b(d.result_);break;default:throw Error("Unexpected state: "+d.state_);}}var d=this;null==this.onSettledCallbacks_?f.asyncExecute(c):this.onSettledCallbacks_.push(c)};c.resolve=d;c.reject=function(a){return new c(function(b,c){c(a)})};c.race=function(a){return new c(function(b,c){for(var e=$jscomp.makeIterator(a),g=e.next();!g.done;g=e.next())d(g.value).callWhenSettled_(b,
-c)})};c.all=function(a){var b=$jscomp.makeIterator(a),e=b.next();return e.done?d([]):new c(function(a,c){function g(b){return function(c){f[b]=c;l--;0==l&&a(f)}}var f=[],l=0;do f.push(void 0),l++,d(e.value).callWhenSettled_(g(f.length-1),c),e=b.next();while(!e.done)})};return c},"es6","es3");$jscomp.SYMBOL_PREFIX="jscomp_symbol_";$jscomp.initSymbol=function(){$jscomp.initSymbol=function(){};$jscomp.global.Symbol||($jscomp.global.Symbol=$jscomp.Symbol)};
-$jscomp.SymbolClass=function(a,b){this.$jscomp$symbol$id_=a;$jscomp.defineProperty(this,"description",{configurable:!0,writable:!0,value:b})};$jscomp.SymbolClass.prototype.toString=function(){return this.$jscomp$symbol$id_};$jscomp.Symbol=function(){function a(d){if(this instanceof a)throw new TypeError("Symbol is not a constructor");return new $jscomp.SymbolClass($jscomp.SYMBOL_PREFIX+(d||"")+"_"+b++,d)}var b=0;return a}();
-$jscomp.initSymbolIterator=function(){$jscomp.initSymbol();var a=$jscomp.global.Symbol.iterator;a||(a=$jscomp.global.Symbol.iterator=$jscomp.global.Symbol("Symbol.iterator"));"function"!=typeof Array.prototype[a]&&$jscomp.defineProperty(Array.prototype,a,{configurable:!0,writable:!0,value:function(){return $jscomp.iteratorPrototype($jscomp.arrayIteratorImpl(this))}});$jscomp.initSymbolIterator=function(){}};
-$jscomp.initSymbolAsyncIterator=function(){$jscomp.initSymbol();var a=$jscomp.global.Symbol.asyncIterator;a||(a=$jscomp.global.Symbol.asyncIterator=$jscomp.global.Symbol("Symbol.asyncIterator"));$jscomp.initSymbolAsyncIterator=function(){}};$jscomp.iteratorPrototype=function(a){$jscomp.initSymbolIterator();a={next:a};a[$jscomp.global.Symbol.iterator]=function(){return this};return a};$jscomp.underscoreProtoCanBeSet=function(){var a={a:!0},b={};try{return b.__proto__=a,b.a}catch(d){}return!1};
-$jscomp.setPrototypeOf="function"==typeof Object.setPrototypeOf?Object.setPrototypeOf:$jscomp.underscoreProtoCanBeSet()?function(a,b){a.__proto__=b;if(a.__proto__!==b)throw new TypeError(a+" is not extensible");return a}:null;$jscomp.generator={};$jscomp.generator.ensureIteratorResultIsObject_=function(a){if(!(a instanceof Object))throw new TypeError("Iterator result "+a+" is not an object");};
-$jscomp.generator.Context=function(){this.isRunning_=!1;this.yieldAllIterator_=null;this.yieldResult=void 0;this.nextAddress=1;this.finallyAddress_=this.catchAddress_=0;this.finallyContexts_=this.abruptCompletion_=null};$jscomp.generator.Context.prototype.start_=function(){if(this.isRunning_)throw new TypeError("Generator is already running");this.isRunning_=!0};$jscomp.generator.Context.prototype.stop_=function(){this.isRunning_=!1};
-$jscomp.generator.Context.prototype.jumpToErrorHandler_=function(){this.nextAddress=this.catchAddress_||this.finallyAddress_};$jscomp.generator.Context.prototype.next_=function(a){this.yieldResult=a};$jscomp.generator.Context.prototype.throw_=function(a){this.abruptCompletion_={exception:a,isException:!0};this.jumpToErrorHandler_()};$jscomp.generator.Context.prototype.return=function(a){this.abruptCompletion_={return:a};this.nextAddress=this.finallyAddress_};
-$jscomp.generator.Context.prototype.jumpThroughFinallyBlocks=function(a){this.abruptCompletion_={jumpTo:a};this.nextAddress=this.finallyAddress_};$jscomp.generator.Context.prototype.yield=function(a,b){this.nextAddress=b;return{value:a}};$jscomp.generator.Context.prototype.yieldAll=function(a,b){a=$jscomp.makeIterator(a);var d=a.next();$jscomp.generator.ensureIteratorResultIsObject_(d);if(d.done)this.yieldResult=d.value,this.nextAddress=b;else return this.yieldAllIterator_=a,this.yield(d.value,b)};
-$jscomp.generator.Context.prototype.jumpTo=function(a){this.nextAddress=a};$jscomp.generator.Context.prototype.jumpToEnd=function(){this.nextAddress=0};$jscomp.generator.Context.prototype.setCatchFinallyBlocks=function(a,b){this.catchAddress_=a;void 0!=b&&(this.finallyAddress_=b)};$jscomp.generator.Context.prototype.setFinallyBlock=function(a){this.catchAddress_=0;this.finallyAddress_=a||0};$jscomp.generator.Context.prototype.leaveTryBlock=function(a,b){this.nextAddress=a;this.catchAddress_=b||0};
-$jscomp.generator.Context.prototype.enterCatchBlock=function(a){this.catchAddress_=a||0;a=this.abruptCompletion_.exception;this.abruptCompletion_=null;return a};$jscomp.generator.Context.prototype.enterFinallyBlock=function(a,b,d){d?this.finallyContexts_[d]=this.abruptCompletion_:this.finallyContexts_=[this.abruptCompletion_];this.catchAddress_=a||0;this.finallyAddress_=b||0};
+var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.createTemplateTagFirstArg=function(a){return a.raw=a};$jscomp.createTemplateTagFirstArgWithRaw=function(a,b){a.raw=b;return a};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.SIMPLE_FROUND_POLYFILL=!1;$jscomp.ISOLATE_POLYFILLS=!1;
+$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,e){if(a==Array.prototype||a==Object.prototype)return a;a[b]=e.value;return a};$jscomp.getGlobal=function(a){a=["object"==typeof globalThis&&globalThis,a,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var b=0;b<a.length;++b){var e=a[b];if(e&&e.Math==Math)return e}throw Error("Cannot find global object");};$jscomp.global=$jscomp.getGlobal(this);
+$jscomp.IS_SYMBOL_NATIVE="function"===typeof Symbol&&"symbol"===typeof Symbol("x");$jscomp.TRUST_ES6_POLYFILLS=!$jscomp.ISOLATE_POLYFILLS||$jscomp.IS_SYMBOL_NATIVE;$jscomp.polyfills={};$jscomp.propertyToPolyfillSymbol={};$jscomp.POLYFILL_PREFIX="$jscp$";var $jscomp$lookupPolyfilledValue=function(a,b){var e=$jscomp.propertyToPolyfillSymbol[b];if(null==e)return a[b];e=a[e];return void 0!==e?e:a[b]};
+$jscomp.polyfill=function(a,b,e,f){b&&($jscomp.ISOLATE_POLYFILLS?$jscomp.polyfillIsolated(a,b,e,f):$jscomp.polyfillUnisolated(a,b,e,f))};$jscomp.polyfillUnisolated=function(a,b,e,f){e=$jscomp.global;a=a.split(".");for(f=0;f<a.length-1;f++){var d=a[f];if(!(d in e))return;e=e[d]}a=a[a.length-1];f=e[a];b=b(f);b!=f&&null!=b&&$jscomp.defineProperty(e,a,{configurable:!0,writable:!0,value:b})};
+$jscomp.polyfillIsolated=function(a,b,e,f){var d=a.split(".");a=1===d.length;f=d[0];f=!a&&f in $jscomp.polyfills?$jscomp.polyfills:$jscomp.global;for(var k=0;k<d.length-1;k++){var c=d[k];if(!(c in f))return;f=f[c]}d=d[d.length-1];e=$jscomp.IS_SYMBOL_NATIVE&&"es6"===e?f[d]:null;b=b(e);null!=b&&(a?$jscomp.defineProperty($jscomp.polyfills,d,{configurable:!0,writable:!0,value:b}):b!==e&&($jscomp.propertyToPolyfillSymbol[d]=$jscomp.IS_SYMBOL_NATIVE?$jscomp.global.Symbol(d):$jscomp.POLYFILL_PREFIX+d,d=
+$jscomp.propertyToPolyfillSymbol[d],$jscomp.defineProperty(f,d,{configurable:!0,writable:!0,value:b})))};$jscomp.underscoreProtoCanBeSet=function(){var a={a:!0},b={};try{return b.__proto__=a,b.a}catch(e){}return!1};$jscomp.setPrototypeOf=$jscomp.TRUST_ES6_POLYFILLS&&"function"==typeof Object.setPrototypeOf?Object.setPrototypeOf:$jscomp.underscoreProtoCanBeSet()?function(a,b){a.__proto__=b;if(a.__proto__!==b)throw new TypeError(a+" is not extensible");return a}:null;
+$jscomp.arrayIteratorImpl=function(a){var b=0;return function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}}};$jscomp.arrayIterator=function(a){return{next:$jscomp.arrayIteratorImpl(a)}};$jscomp.makeIterator=function(a){var b="undefined"!=typeof Symbol&&Symbol.iterator&&a[Symbol.iterator];return b?b.call(a):$jscomp.arrayIterator(a)};$jscomp.generator={};
+$jscomp.generator.ensureIteratorResultIsObject_=function(a){if(!(a instanceof Object))throw new TypeError("Iterator result "+a+" is not an object");};$jscomp.generator.Context=function(){this.isRunning_=!1;this.yieldAllIterator_=null;this.yieldResult=void 0;this.nextAddress=1;this.finallyAddress_=this.catchAddress_=0;this.finallyContexts_=this.abruptCompletion_=null};
+$jscomp.generator.Context.prototype.start_=function(){if(this.isRunning_)throw new TypeError("Generator is already running");this.isRunning_=!0};$jscomp.generator.Context.prototype.stop_=function(){this.isRunning_=!1};$jscomp.generator.Context.prototype.jumpToErrorHandler_=function(){this.nextAddress=this.catchAddress_||this.finallyAddress_};$jscomp.generator.Context.prototype.next_=function(a){this.yieldResult=a};
+$jscomp.generator.Context.prototype.throw_=function(a){this.abruptCompletion_={exception:a,isException:!0};this.jumpToErrorHandler_()};$jscomp.generator.Context.prototype.return=function(a){this.abruptCompletion_={return:a};this.nextAddress=this.finallyAddress_};$jscomp.generator.Context.prototype.jumpThroughFinallyBlocks=function(a){this.abruptCompletion_={jumpTo:a};this.nextAddress=this.finallyAddress_};$jscomp.generator.Context.prototype.yield=function(a,b){this.nextAddress=b;return{value:a}};
+$jscomp.generator.Context.prototype.yieldAll=function(a,b){a=$jscomp.makeIterator(a);var e=a.next();$jscomp.generator.ensureIteratorResultIsObject_(e);if(e.done)this.yieldResult=e.value,this.nextAddress=b;else return this.yieldAllIterator_=a,this.yield(e.value,b)};$jscomp.generator.Context.prototype.jumpTo=function(a){this.nextAddress=a};$jscomp.generator.Context.prototype.jumpToEnd=function(){this.nextAddress=0};
+$jscomp.generator.Context.prototype.setCatchFinallyBlocks=function(a,b){this.catchAddress_=a;void 0!=b&&(this.finallyAddress_=b)};$jscomp.generator.Context.prototype.setFinallyBlock=function(a){this.catchAddress_=0;this.finallyAddress_=a||0};$jscomp.generator.Context.prototype.leaveTryBlock=function(a,b){this.nextAddress=a;this.catchAddress_=b||0};
+$jscomp.generator.Context.prototype.enterCatchBlock=function(a){this.catchAddress_=a||0;a=this.abruptCompletion_.exception;this.abruptCompletion_=null;return a};$jscomp.generator.Context.prototype.enterFinallyBlock=function(a,b,e){e?this.finallyContexts_[e]=this.abruptCompletion_:this.finallyContexts_=[this.abruptCompletion_];this.catchAddress_=a||0;this.finallyAddress_=b||0};
 $jscomp.generator.Context.prototype.leaveFinallyBlock=function(a,b){b=this.finallyContexts_.splice(b||0)[0];if(b=this.abruptCompletion_=this.abruptCompletion_||b){if(b.isException)return this.jumpToErrorHandler_();void 0!=b.jumpTo&&this.finallyAddress_<b.jumpTo?(this.nextAddress=b.jumpTo,this.abruptCompletion_=null):this.nextAddress=this.finallyAddress_}else this.nextAddress=a};$jscomp.generator.Context.prototype.forIn=function(a){return new $jscomp.generator.Context.PropertyIterator(a)};
 $jscomp.generator.Context.PropertyIterator=function(a){this.object_=a;this.properties_=[];for(var b in a)this.properties_.push(b);this.properties_.reverse()};$jscomp.generator.Context.PropertyIterator.prototype.getNext=function(){for(;0<this.properties_.length;){var a=this.properties_.pop();if(a in this.object_)return a}return null};$jscomp.generator.Engine_=function(a){this.context_=new $jscomp.generator.Context;this.program_=a};
 $jscomp.generator.Engine_.prototype.next_=function(a){this.context_.start_();if(this.context_.yieldAllIterator_)return this.yieldAllStep_(this.context_.yieldAllIterator_.next,a,this.context_.next_);this.context_.next_(a);return this.nextStep_()};
-$jscomp.generator.Engine_.prototype.return_=function(a){this.context_.start_();var b=this.context_.yieldAllIterator_;if(b)return this.yieldAllStep_("return"in b?b["return"]:function(a){return{value:a,done:!0}},a,this.context_.return);this.context_.return(a);return this.nextStep_()};
+$jscomp.generator.Engine_.prototype.return_=function(a){this.context_.start_();var b=this.context_.yieldAllIterator_;if(b)return this.yieldAllStep_("return"in b?b["return"]:function(e){return{value:e,done:!0}},a,this.context_.return);this.context_.return(a);return this.nextStep_()};
 $jscomp.generator.Engine_.prototype.throw_=function(a){this.context_.start_();if(this.context_.yieldAllIterator_)return this.yieldAllStep_(this.context_.yieldAllIterator_["throw"],a,this.context_.next_);this.context_.throw_(a);return this.nextStep_()};
-$jscomp.generator.Engine_.prototype.yieldAllStep_=function(a,b,d){try{var e=a.call(this.context_.yieldAllIterator_,b);$jscomp.generator.ensureIteratorResultIsObject_(e);if(!e.done)return this.context_.stop_(),e;var c=e.value}catch(f){return this.context_.yieldAllIterator_=null,this.context_.throw_(f),this.nextStep_()}this.context_.yieldAllIterator_=null;d.call(this.context_,c);return this.nextStep_()};
+$jscomp.generator.Engine_.prototype.yieldAllStep_=function(a,b,e){try{var f=a.call(this.context_.yieldAllIterator_,b);$jscomp.generator.ensureIteratorResultIsObject_(f);if(!f.done)return this.context_.stop_(),f;var d=f.value}catch(k){return this.context_.yieldAllIterator_=null,this.context_.throw_(k),this.nextStep_()}this.context_.yieldAllIterator_=null;e.call(this.context_,d);return this.nextStep_()};
 $jscomp.generator.Engine_.prototype.nextStep_=function(){for(;this.context_.nextAddress;)try{var a=this.program_(this.context_);if(a)return this.context_.stop_(),{value:a.value,done:!1}}catch(b){this.context_.yieldResult=void 0,this.context_.throw_(b)}this.context_.stop_();if(this.context_.abruptCompletion_){a=this.context_.abruptCompletion_;this.context_.abruptCompletion_=null;if(a.isException)throw a.exception;return{value:a.return,done:!0}}return{value:void 0,done:!0}};
-$jscomp.generator.Generator_=function(a){this.next=function(b){return a.next_(b)};this.throw=function(b){return a.throw_(b)};this.return=function(b){return a.return_(b)};$jscomp.initSymbolIterator();this[Symbol.iterator]=function(){return this}};$jscomp.generator.createGenerator=function(a,b){b=new $jscomp.generator.Generator_(new $jscomp.generator.Engine_(b));$jscomp.setPrototypeOf&&$jscomp.setPrototypeOf(b,a.prototype);return b};
-$jscomp.asyncExecutePromiseGenerator=function(a){function b(b){return a.next(b)}function d(b){return a.throw(b)}return new Promise(function(e,c){function f(a){a.done?e(a.value):Promise.resolve(a.value).then(b,d).then(f,c)}f(a.next())})};$jscomp.asyncExecutePromiseGeneratorFunction=function(a){return $jscomp.asyncExecutePromiseGenerator(a())};$jscomp.asyncExecutePromiseGeneratorProgram=function(a){return $jscomp.asyncExecutePromiseGenerator(new $jscomp.generator.Generator_(new $jscomp.generator.Engine_(a)))};
-$jscomp.polyfill("globalThis",function(a){return a||$jscomp.global},"es_next","es3");$jscomp.polyfill("Array.from",function(a){return a?a:function(a,d,e){d=null!=d?d:function(a){return a};var b=[],f="undefined"!=typeof Symbol&&Symbol.iterator&&a[Symbol.iterator];if("function"==typeof f){a=f.call(a);for(var g=0;!(f=a.next()).done;)b.push(d.call(e,f.value,g++))}else for(f=a.length,g=0;g<f;g++)b.push(d.call(e,a[g],g));return b}},"es6","es3");
-$jscomp.findInternal=function(a,b,d){a instanceof String&&(a=String(a));for(var e=a.length,c=0;c<e;c++){var f=a[c];if(b.call(d,f,c,a))return{i:c,v:f}}return{i:-1,v:void 0}};$jscomp.polyfill("Array.prototype.findIndex",function(a){return a?a:function(a,d){return $jscomp.findInternal(this,a,d).i}},"es6","es3");$jscomp.polyfill("Array.prototype.find",function(a){return a?a:function(a,d){return $jscomp.findInternal(this,a,d).v}},"es6","es3");
-document.addEventListener("DOMContentLoaded",function(){var a=document.querySelector("#AutoComplete"),b=document.querySelector("#AutoComplete-parent"),d=function(){b.setAttribute("aria-expanded",!1);a.removeAttribute("aria-activedescendant")},e=function(){b.setAttribute("aria-expanded",!0)};a.addEventListener("blur",d);a.addEventListener("focus",e);new autoComplete({data:{src:function(){var b,d;return $jscomp.asyncExecutePromiseGeneratorProgram(function(c){return 1==c.nextAddress?(b=a.value,c.yield(fetch("/autocomplete?q="+
-b),2)):3!=c.nextAddress?(d=c.yieldResult,c.yield(d.json(),3)):c.return(c.yieldResult)})},key:["PackagePath"],cache:!1},threshold:1,debounce:100,resultsList:{render:!0,container:function(a){a.setAttribute("id","AutoComplete-list");a.classList.add("AutoComplete-list");a.setAttribute("role","listbox")},destination:document.querySelector("#AutoComplete-parent"),position:"beforeend",element:"ul",navigation:function(a,b,g,p,h){var c=Array.from(g.childNodes),f=void 0,n=function(a){f&&f.removeAttribute("aria-selected");
-f=a;f.setAttribute("aria-selected","true");a=c.findIndex(function(a){return a===f});b.setAttribute("aria-activedescendant","AutoComplete-item-"+a)},m=function(a,c){p({event:a,query:b.value,matches:h.matches,results:h.list.map(function(a){return a.value}),selection:h.list.find(function(a){return a.index===Number(c.getAttribute("data-id"))})});d()};b.onkeydown=function(a){if(0<c.length)switch(a.keyCode){case 38:e();var g=c[c.length-1];f&&f.previousSibling&&(g=f.previousSibling);n(g);a.preventDefault();
-break;case 40:e();g=c[0];f&&f.nextSibling&&(g=f.nextSibling);n(g);a.preventDefault();break;case 13:f&&(a.preventDefault(),m(a,f));break;case 27:d();b.value="";break;default:e()}};c.forEach(function(a,b){a.setAttribute("id","AutoComplete-item-"+b);a.onmousedown=function(a){m(a,a.currentTarget);a.preventDefault()}})}},highlight:!0,selector:"#AutoComplete",onSelection:function(a){a.selection.value.PackagePath&&(window.location.href="/"+a.selection.value.PackagePath)}})});
+$jscomp.generator.Generator_=function(a){this.next=function(b){return a.next_(b)};this.throw=function(b){return a.throw_(b)};this.return=function(b){return a.return_(b)};this[Symbol.iterator]=function(){return this}};$jscomp.generator.createGenerator=function(a,b){b=new $jscomp.generator.Generator_(new $jscomp.generator.Engine_(b));$jscomp.setPrototypeOf&&a.prototype&&$jscomp.setPrototypeOf(b,a.prototype);return b};
+$jscomp.asyncExecutePromiseGenerator=function(a){function b(f){return a.next(f)}function e(f){return a.throw(f)}return new Promise(function(f,d){function k(c){c.done?f(c.value):Promise.resolve(c.value).then(b,e).then(k,d)}k(a.next())})};$jscomp.asyncExecutePromiseGeneratorFunction=function(a){return $jscomp.asyncExecutePromiseGenerator(a())};$jscomp.asyncExecutePromiseGeneratorProgram=function(a){return $jscomp.asyncExecutePromiseGenerator(new $jscomp.generator.Generator_(new $jscomp.generator.Engine_(a)))};
+$jscomp.initSymbol=function(){};$jscomp.polyfill("Symbol",function(a){if(a)return a;var b=function(d,k){this.$jscomp$symbol$id_=d;$jscomp.defineProperty(this,"description",{configurable:!0,writable:!0,value:k})};b.prototype.toString=function(){return this.$jscomp$symbol$id_};var e=0,f=function(d){if(this instanceof f)throw new TypeError("Symbol is not a constructor");return new b("jscomp_symbol_"+(d||"")+"_"+e++,d)};return f},"es6","es3");$jscomp.initSymbolIterator=function(){};
+$jscomp.polyfill("Symbol.iterator",function(a){if(a)return a;a=Symbol("Symbol.iterator");for(var b="Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array".split(" "),e=0;e<b.length;e++){var f=$jscomp.global[b[e]];"function"===typeof f&&"function"!=typeof f.prototype[a]&&$jscomp.defineProperty(f.prototype,a,{configurable:!0,writable:!0,value:function(){return $jscomp.iteratorPrototype($jscomp.arrayIteratorImpl(this))}})}return a},"es6",
+"es3");$jscomp.initSymbolAsyncIterator=function(){};$jscomp.iteratorPrototype=function(a){a={next:a};a[Symbol.iterator]=function(){return this};return a};$jscomp.FORCE_POLYFILL_PROMISE=!1;
+$jscomp.polyfill("Promise",function(a){function b(){this.batch_=null}function e(c){return c instanceof d?c:new d(function(g,h){g(c)})}if(a&&!$jscomp.FORCE_POLYFILL_PROMISE)return a;b.prototype.asyncExecute=function(c){if(null==this.batch_){this.batch_=[];var g=this;this.asyncExecuteFunction(function(){g.executeBatch_()})}this.batch_.push(c)};var f=$jscomp.global.setTimeout;b.prototype.asyncExecuteFunction=function(c){f(c,0)};b.prototype.executeBatch_=function(){for(;this.batch_&&this.batch_.length;){var c=
+this.batch_;this.batch_=[];for(var g=0;g<c.length;++g){var h=c[g];c[g]=null;try{h()}catch(l){this.asyncThrow_(l)}}}this.batch_=null};b.prototype.asyncThrow_=function(c){this.asyncExecuteFunction(function(){throw c;})};var d=function(c){this.state_=0;this.result_=void 0;this.onSettledCallbacks_=[];var g=this.createResolveAndReject_();try{c(g.resolve,g.reject)}catch(h){g.reject(h)}};d.prototype.createResolveAndReject_=function(){function c(l){return function(m){h||(h=!0,l.call(g,m))}}var g=this,h=!1;
+return{resolve:c(this.resolveTo_),reject:c(this.reject_)}};d.prototype.resolveTo_=function(c){if(c===this)this.reject_(new TypeError("A Promise cannot resolve to itself"));else if(c instanceof d)this.settleSameAsPromise_(c);else{a:switch(typeof c){case "object":var g=null!=c;break a;case "function":g=!0;break a;default:g=!1}g?this.resolveToNonPromiseObj_(c):this.fulfill_(c)}};d.prototype.resolveToNonPromiseObj_=function(c){var g=void 0;try{g=c.then}catch(h){this.reject_(h);return}"function"==typeof g?
+this.settleSameAsThenable_(g,c):this.fulfill_(c)};d.prototype.reject_=function(c){this.settle_(2,c)};d.prototype.fulfill_=function(c){this.settle_(1,c)};d.prototype.settle_=function(c,g){if(0!=this.state_)throw Error("Cannot settle("+c+", "+g+"): Promise already settled in state"+this.state_);this.state_=c;this.result_=g;this.executeOnSettledCallbacks_()};d.prototype.executeOnSettledCallbacks_=function(){if(null!=this.onSettledCallbacks_){for(var c=0;c<this.onSettledCallbacks_.length;++c)k.asyncExecute(this.onSettledCallbacks_[c]);
+this.onSettledCallbacks_=null}};var k=new b;d.prototype.settleSameAsPromise_=function(c){var g=this.createResolveAndReject_();c.callWhenSettled_(g.resolve,g.reject)};d.prototype.settleSameAsThenable_=function(c,g){var h=this.createResolveAndReject_();try{c.call(g,h.resolve,h.reject)}catch(l){h.reject(l)}};d.prototype.then=function(c,g){function h(q,n){return"function"==typeof q?function(p){try{l(q(p))}catch(r){m(r)}}:n}var l,m,t=new d(function(q,n){l=q;m=n});this.callWhenSettled_(h(c,l),h(g,m));return t};
+d.prototype.catch=function(c){return this.then(void 0,c)};d.prototype.callWhenSettled_=function(c,g){function h(){switch(l.state_){case 1:c(l.result_);break;case 2:g(l.result_);break;default:throw Error("Unexpected state: "+l.state_);}}var l=this;null==this.onSettledCallbacks_?k.asyncExecute(h):this.onSettledCallbacks_.push(h)};d.resolve=e;d.reject=function(c){return new d(function(g,h){h(c)})};d.race=function(c){return new d(function(g,h){for(var l=$jscomp.makeIterator(c),m=l.next();!m.done;m=l.next())e(m.value).callWhenSettled_(g,
+h)})};d.all=function(c){var g=$jscomp.makeIterator(c),h=g.next();return h.done?e([]):new d(function(l,m){function t(p){return function(r){q[p]=r;n--;0==n&&l(q)}}var q=[],n=0;do q.push(void 0),n++,e(h.value).callWhenSettled_(t(q.length-1),m),h=g.next();while(!h.done)})};return d},"es6","es3");
+$jscomp.polyfill("Array.from",function(a){return a?a:function(b,e,f){e=null!=e?e:function(g){return g};var d=[],k="undefined"!=typeof Symbol&&Symbol.iterator&&b[Symbol.iterator];if("function"==typeof k){b=k.call(b);for(var c=0;!(k=b.next()).done;)d.push(e.call(f,k.value,c++))}else for(k=b.length,c=0;c<k;c++)d.push(e.call(f,b[c],c));return d}},"es6","es3");
+$jscomp.findInternal=function(a,b,e){a instanceof String&&(a=String(a));for(var f=a.length,d=0;d<f;d++){var k=a[d];if(b.call(e,k,d,a))return{i:d,v:k}}return{i:-1,v:void 0}};$jscomp.polyfill("Array.prototype.findIndex",function(a){return a?a:function(b,e){return $jscomp.findInternal(this,b,e).i}},"es6","es3");$jscomp.polyfill("Array.prototype.find",function(a){return a?a:function(b,e){return $jscomp.findInternal(this,b,e).v}},"es6","es3");
+document.addEventListener("DOMContentLoaded",function(){var a=document.querySelector("#AutoComplete"),b=document.querySelector("#AutoComplete-parent"),e=function(){b.setAttribute("aria-expanded",!1);a.removeAttribute("aria-activedescendant")},f=function(){b.setAttribute("aria-expanded",!0)};a.addEventListener("blur",e);a.addEventListener("focus",f);new autoComplete({data:{src:function(){var d,k;return $jscomp.asyncExecutePromiseGeneratorProgram(function(c){return 1==c.nextAddress?(d=a.value,c.yield(fetch("/autocomplete?q="+
+d),2)):3!=c.nextAddress?(k=c.yieldResult,c.yield(k.json(),3)):c.return(c.yieldResult)})},key:["PackagePath"],cache:!1},threshold:1,debounce:100,resultsList:{render:!0,container:function(d){d.setAttribute("id","AutoComplete-list");d.classList.add("AutoComplete-list");d.setAttribute("role","listbox")},destination:document.querySelector("#AutoComplete-parent"),position:"beforeend",element:"ul",navigation:function(d,k,c,g,h){var l=Array.from(c.childNodes),m=void 0,t=function(n){m&&m.removeAttribute("aria-selected");
+m=n;m.setAttribute("aria-selected","true");n=l.findIndex(function(p){return p===m});k.setAttribute("aria-activedescendant","AutoComplete-item-"+n)},q=function(n,p){g({event:n,query:k.value,matches:h.matches,results:h.list.map(function(r){return r.value}),selection:h.list.find(function(r){return r.index===Number(p.getAttribute("data-id"))})});e()};k.onkeydown=function(n){if(0<l.length)switch(n.keyCode){case 38:f();var p=l[l.length-1];m&&m.previousSibling&&(p=m.previousSibling);t(p);n.preventDefault();
+break;case 40:f();p=l[0];m&&m.nextSibling&&(p=m.nextSibling);t(p);n.preventDefault();break;case 13:m&&(n.preventDefault(),q(n,m));break;case 27:e();k.value="";break;default:f()}};l.forEach(function(n,p){n.setAttribute("id","AutoComplete-item-"+p);n.onmousedown=function(r){q(r,r.currentTarget);r.preventDefault()}})}},highlight:!0,selector:"#AutoComplete",onSelection:function(d){d.selection.value.PackagePath&&(window.location.href="/"+d.selection.value.PackagePath)}})});
diff --git a/content/static/js/details.js b/content/static/js/details.js
new file mode 100644
index 0000000..9b39298
--- /dev/null
+++ b/content/static/js/details.js
@@ -0,0 +1,17 @@
+/**
+ * @license
+ * Copyright 2019-2020 The Go Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ */
+
+new FixedHeaderController(
+  document.querySelector('.js-fixedHeaderSentinel'),
+  document.querySelector('.js-fixedHeader')
+);
+document
+  .querySelectorAll('.js-overflowingTabList')
+  .forEach(el => new OverflowingTabListController(el));
+document.querySelectorAll('.js-copyToClipboard').forEach(el => {
+  new CopyToClipboardController(el);
+});
diff --git a/content/static/js/details.min.js b/content/static/js/details.min.js
new file mode 100644
index 0000000..f2a0dc3
--- /dev/null
+++ b/content/static/js/details.min.js
@@ -0,0 +1,15 @@
+/*
+
+ Copyright 2019-2020 The Go Authors. All rights reserved.
+ Use of this source code is governed by a BSD-style
+ license that can be found in the LICENSE file.
+*/
+var k="function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){if(a==Array.prototype||a==Object.prototype)return a;a[b]=c.value;return a};function l(a){a=["object"==typeof globalThis&&globalThis,a,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var b=0;b<a.length;++b){var c=a[b];if(c&&c.Math==Math)return c}throw Error("Cannot find global object");}var n=l(this);
+function p(a,b){if(b)a:{var c=n;a=a.split(".");for(var d=0;d<a.length-1;d++){var e=a[d];if(!(e in c))break a;c=c[e]}a=a[a.length-1];d=c[a];b=b(d);b!=d&&null!=b&&k(c,a,{configurable:!0,writable:!0,value:b})}}
+p("Array.from",function(a){return a?a:function(b,c,d){c=null!=c?c:function(h){return h};var e=[],f="undefined"!=typeof Symbol&&Symbol.iterator&&b[Symbol.iterator];if("function"==typeof f){b=f.call(b);for(var g=0;!(f=b.next()).done;)e.push(c.call(d,f.value,g++))}else for(f=b.length,g=0;g<f;g++)e.push(c.call(d,b[g],g));return e}});p("Object.is",function(a){return a?a:function(b,c){return b===c?0!==b||1/b===1/c:b!==b&&c!==c}});
+p("Array.prototype.includes",function(a){return a?a:function(b,c){var d=this;d instanceof String&&(d=String(d));var e=d.length;c=c||0;for(0>c&&(c=Math.max(c+e,0));c<e;c++){var f=d[c];if(f===b||Object.is(f,b))return!0}return!1}});
+p("String.prototype.includes",function(a){return a?a:function(b,c){if(null==this)throw new TypeError("The 'this' value for String.prototype.includes must not be null or undefined");if(b instanceof RegExp)throw new TypeError("First argument to String.prototype.includes must not be a regular expression");return-1!==this.indexOf(b,c||0)}});function q(a){var b=this;this.a=a;this.b=a.dataset.toCopy;a.addEventListener("click",function(c){return r(b,c)})}
+function r(a,b){b.preventDefault();navigator.clipboard?navigator.clipboard.writeText(a.b).then(function(){t(a,"Copied!")}).catch(function(){t(a,"Unable to copy")}):t(a,"Unable to copy")}function t(a,b){a.a.setAttribute("data-tooltip",b);setTimeout(function(){return a.a.setAttribute("data-tooltip","")},1E3)}function u(a,b){b.forEach(function(c){a.b.setAttribute("aria-hidden",c.isIntersecting)})}
+function v(a){var b=this;if(!a)throw Error("Must provide an element.");this.a=a;a=this.a.querySelector("select");if(!a)throw Error("Element must contain a <select> element.");this.b=a;this.c=[];if(window.ResizeObserver){var c=0;this.c=Array.from(this.a.querySelectorAll("[role='tab']")).map(function(d,e){0===e&&(c=d.offsetLeft);return d.offsetLeft+d.offsetWidth-c});(new ResizeObserver(function(d){return w(b,d)})).observe(this.a);this.b.addEventListener("change",function(d){window.location.href=d.target.value})}else this.a.style.overflowX=
+"scroll"}function w(a,b){b.forEach(function(c){var d=c.target.getBoundingClientRect(),e=[];a.a.querySelectorAll("[role='tab']").forEach(function(f,g){var h=a.c[g],m=d.width;a.a.classList.contains("is-overflowing")&&(m-=40);h=h>m;f.setAttribute("aria-hidden",h);h&&e.push(g)});a.a.classList.toggle("is-overflowing",0!==e.length);a.b.querySelectorAll("option").forEach(function(f,g){f.disabled=!e.includes(g)})})}
+new function(){var a=document.querySelector(".js-fixedHeaderSentinel"),b=document.querySelector(".js-fixedHeader"),c=this;if(!a||!b)throw Error("Must provide sentinel and fixed elements to constructor.");this.a=a;this.b=b;this.c=new IntersectionObserver(function(d){return u(c,d)},{threshold:1});this.c.observe(this.a)};document.querySelectorAll(".js-overflowingTabList").forEach(function(a){return new v(a)});document.querySelectorAll(".js-copyToClipboard").forEach(function(a){new q(a)});
diff --git a/content/static/js/fetch.min.js b/content/static/js/fetch.min.js
index 079eff3..8f70514 100644
--- a/content/static/js/fetch.min.js
+++ b/content/static/js/fetch.min.js
@@ -4,34 +4,37 @@
  Use of this source code is governed by a BSD-style
  license that can be found in the LICENSE file.
 */
-var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.arrayIteratorImpl=function(a){var b=0;return function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}}};$jscomp.arrayIterator=function(a){return{next:$jscomp.arrayIteratorImpl(a)}};$jscomp.makeIterator=function(a){var b="undefined"!=typeof Symbol&&Symbol.iterator&&a[Symbol.iterator];return b?b.call(a):$jscomp.arrayIterator(a)};
-$jscomp.getGlobal=function(a){a=["object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global,a];for(var b=0;b<a.length;++b){var c=a[b];if(c&&c.Math==Math)return c}return globalThis};$jscomp.global=$jscomp.getGlobal(this);$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.SIMPLE_FROUND_POLYFILL=!1;
-$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,c){a!=Array.prototype&&a!=Object.prototype&&(a[b]=c.value)};$jscomp.polyfill=function(a,b,c,d){if(b){c=$jscomp.global;a=a.split(".");for(d=0;d<a.length-1;d++){var e=a[d];e in c||(c[e]={});c=c[e]}a=a[a.length-1];d=c[a];b=b(d);b!=d&&null!=b&&$jscomp.defineProperty(c,a,{configurable:!0,writable:!0,value:b})}};$jscomp.FORCE_POLYFILL_PROMISE=!1;
-$jscomp.polyfill("Promise",function(a){function b(){this.batch_=null}function c(a){return a instanceof e?a:new e(function(b,f){b(a)})}if(a&&!$jscomp.FORCE_POLYFILL_PROMISE)return a;b.prototype.asyncExecute=function(a){if(null==this.batch_){this.batch_=[];var b=this;this.asyncExecuteFunction(function(){b.executeBatch_()})}this.batch_.push(a)};var d=$jscomp.global.setTimeout;b.prototype.asyncExecuteFunction=function(a){d(a,0)};b.prototype.executeBatch_=function(){for(;this.batch_&&this.batch_.length;){var a=
-this.batch_;this.batch_=[];for(var b=0;b<a.length;++b){var c=a[b];a[b]=null;try{c()}catch(k){this.asyncThrow_(k)}}}this.batch_=null};b.prototype.asyncThrow_=function(a){this.asyncExecuteFunction(function(){throw a;})};var e=function(a){this.state_=0;this.result_=void 0;this.onSettledCallbacks_=[];var b=this.createResolveAndReject_();try{a(b.resolve,b.reject)}catch(h){b.reject(h)}};e.prototype.createResolveAndReject_=function(){function a(a){return function(f){c||(c=!0,a.call(b,f))}}var b=this,c=!1;
-return{resolve:a(this.resolveTo_),reject:a(this.reject_)}};e.prototype.resolveTo_=function(a){if(a===this)this.reject_(new TypeError("A Promise cannot resolve to itself"));else if(a instanceof e)this.settleSameAsPromise_(a);else{a:switch(typeof a){case "object":var b=null!=a;break a;case "function":b=!0;break a;default:b=!1}b?this.resolveToNonPromiseObj_(a):this.fulfill_(a)}};e.prototype.resolveToNonPromiseObj_=function(a){var b=void 0;try{b=a.then}catch(h){this.reject_(h);return}"function"==typeof b?
-this.settleSameAsThenable_(b,a):this.fulfill_(a)};e.prototype.reject_=function(a){this.settle_(2,a)};e.prototype.fulfill_=function(a){this.settle_(1,a)};e.prototype.settle_=function(a,b){if(0!=this.state_)throw Error("Cannot settle("+a+", "+b+"): Promise already settled in state"+this.state_);this.state_=a;this.result_=b;this.executeOnSettledCallbacks_()};e.prototype.executeOnSettledCallbacks_=function(){if(null!=this.onSettledCallbacks_){for(var a=0;a<this.onSettledCallbacks_.length;++a)g.asyncExecute(this.onSettledCallbacks_[a]);
-this.onSettledCallbacks_=null}};var g=new b;e.prototype.settleSameAsPromise_=function(a){var b=this.createResolveAndReject_();a.callWhenSettled_(b.resolve,b.reject)};e.prototype.settleSameAsThenable_=function(a,b){var c=this.createResolveAndReject_();try{a.call(b,c.resolve,c.reject)}catch(k){c.reject(k)}};e.prototype.then=function(a,b){function c(a,b){return"function"==typeof a?function(b){try{d(a(b))}catch(m){f(m)}}:b}var d,f,l=new e(function(a,b){d=a;f=b});this.callWhenSettled_(c(a,d),c(b,f));return l};
-e.prototype.catch=function(a){return this.then(void 0,a)};e.prototype.callWhenSettled_=function(a,b){function c(){switch(d.state_){case 1:a(d.result_);break;case 2:b(d.result_);break;default:throw Error("Unexpected state: "+d.state_);}}var d=this;null==this.onSettledCallbacks_?g.asyncExecute(c):this.onSettledCallbacks_.push(c)};e.resolve=c;e.reject=function(a){return new e(function(b,c){c(a)})};e.race=function(a){return new e(function(b,d){for(var e=$jscomp.makeIterator(a),f=e.next();!f.done;f=e.next())c(f.value).callWhenSettled_(b,
-d)})};e.all=function(a){var b=$jscomp.makeIterator(a),d=b.next();return d.done?c([]):new e(function(a,e){function f(b){return function(c){g[b]=c;h--;0==h&&a(g)}}var g=[],h=0;do g.push(void 0),h++,c(d.value).callWhenSettled_(f(g.length-1),e),d=b.next();while(!d.done)})};return e},"es6","es3");$jscomp.SYMBOL_PREFIX="jscomp_symbol_";$jscomp.initSymbol=function(){$jscomp.initSymbol=function(){};$jscomp.global.Symbol||($jscomp.global.Symbol=$jscomp.Symbol)};
-$jscomp.SymbolClass=function(a,b){this.$jscomp$symbol$id_=a;$jscomp.defineProperty(this,"description",{configurable:!0,writable:!0,value:b})};$jscomp.SymbolClass.prototype.toString=function(){return this.$jscomp$symbol$id_};$jscomp.Symbol=function(){function a(c){if(this instanceof a)throw new TypeError("Symbol is not a constructor");return new $jscomp.SymbolClass($jscomp.SYMBOL_PREFIX+(c||"")+"_"+b++,c)}var b=0;return a}();
-$jscomp.initSymbolIterator=function(){$jscomp.initSymbol();var a=$jscomp.global.Symbol.iterator;a||(a=$jscomp.global.Symbol.iterator=$jscomp.global.Symbol("Symbol.iterator"));"function"!=typeof Array.prototype[a]&&$jscomp.defineProperty(Array.prototype,a,{configurable:!0,writable:!0,value:function(){return $jscomp.iteratorPrototype($jscomp.arrayIteratorImpl(this))}});$jscomp.initSymbolIterator=function(){}};
-$jscomp.initSymbolAsyncIterator=function(){$jscomp.initSymbol();var a=$jscomp.global.Symbol.asyncIterator;a||(a=$jscomp.global.Symbol.asyncIterator=$jscomp.global.Symbol("Symbol.asyncIterator"));$jscomp.initSymbolAsyncIterator=function(){}};$jscomp.iteratorPrototype=function(a){$jscomp.initSymbolIterator();a={next:a};a[$jscomp.global.Symbol.iterator]=function(){return this};return a};$jscomp.underscoreProtoCanBeSet=function(){var a={a:!0},b={};try{return b.__proto__=a,b.a}catch(c){}return!1};
-$jscomp.setPrototypeOf="function"==typeof Object.setPrototypeOf?Object.setPrototypeOf:$jscomp.underscoreProtoCanBeSet()?function(a,b){a.__proto__=b;if(a.__proto__!==b)throw new TypeError(a+" is not extensible");return a}:null;$jscomp.generator={};$jscomp.generator.ensureIteratorResultIsObject_=function(a){if(!(a instanceof Object))throw new TypeError("Iterator result "+a+" is not an object");};
-$jscomp.generator.Context=function(){this.isRunning_=!1;this.yieldAllIterator_=null;this.yieldResult=void 0;this.nextAddress=1;this.finallyAddress_=this.catchAddress_=0;this.finallyContexts_=this.abruptCompletion_=null};$jscomp.generator.Context.prototype.start_=function(){if(this.isRunning_)throw new TypeError("Generator is already running");this.isRunning_=!0};$jscomp.generator.Context.prototype.stop_=function(){this.isRunning_=!1};
-$jscomp.generator.Context.prototype.jumpToErrorHandler_=function(){this.nextAddress=this.catchAddress_||this.finallyAddress_};$jscomp.generator.Context.prototype.next_=function(a){this.yieldResult=a};$jscomp.generator.Context.prototype.throw_=function(a){this.abruptCompletion_={exception:a,isException:!0};this.jumpToErrorHandler_()};$jscomp.generator.Context.prototype.return=function(a){this.abruptCompletion_={return:a};this.nextAddress=this.finallyAddress_};
-$jscomp.generator.Context.prototype.jumpThroughFinallyBlocks=function(a){this.abruptCompletion_={jumpTo:a};this.nextAddress=this.finallyAddress_};$jscomp.generator.Context.prototype.yield=function(a,b){this.nextAddress=b;return{value:a}};$jscomp.generator.Context.prototype.yieldAll=function(a,b){a=$jscomp.makeIterator(a);var c=a.next();$jscomp.generator.ensureIteratorResultIsObject_(c);if(c.done)this.yieldResult=c.value,this.nextAddress=b;else return this.yieldAllIterator_=a,this.yield(c.value,b)};
-$jscomp.generator.Context.prototype.jumpTo=function(a){this.nextAddress=a};$jscomp.generator.Context.prototype.jumpToEnd=function(){this.nextAddress=0};$jscomp.generator.Context.prototype.setCatchFinallyBlocks=function(a,b){this.catchAddress_=a;void 0!=b&&(this.finallyAddress_=b)};$jscomp.generator.Context.prototype.setFinallyBlock=function(a){this.catchAddress_=0;this.finallyAddress_=a||0};$jscomp.generator.Context.prototype.leaveTryBlock=function(a,b){this.nextAddress=a;this.catchAddress_=b||0};
-$jscomp.generator.Context.prototype.enterCatchBlock=function(a){this.catchAddress_=a||0;a=this.abruptCompletion_.exception;this.abruptCompletion_=null;return a};$jscomp.generator.Context.prototype.enterFinallyBlock=function(a,b,c){c?this.finallyContexts_[c]=this.abruptCompletion_:this.finallyContexts_=[this.abruptCompletion_];this.catchAddress_=a||0;this.finallyAddress_=b||0};
+var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.createTemplateTagFirstArg=function(a){return a.raw=a};$jscomp.createTemplateTagFirstArgWithRaw=function(a,b){a.raw=b;return a};$jscomp.ASSUME_ES5=!1;$jscomp.ASSUME_NO_NATIVE_MAP=!1;$jscomp.ASSUME_NO_NATIVE_SET=!1;$jscomp.SIMPLE_FROUND_POLYFILL=!1;$jscomp.ISOLATE_POLYFILLS=!1;
+$jscomp.defineProperty=$jscomp.ASSUME_ES5||"function"==typeof Object.defineProperties?Object.defineProperty:function(a,b,d){if(a==Array.prototype||a==Object.prototype)return a;a[b]=d.value;return a};$jscomp.getGlobal=function(a){a=["object"==typeof globalThis&&globalThis,a,"object"==typeof window&&window,"object"==typeof self&&self,"object"==typeof global&&global];for(var b=0;b<a.length;++b){var d=a[b];if(d&&d.Math==Math)return d}throw Error("Cannot find global object");};$jscomp.global=$jscomp.getGlobal(this);
+$jscomp.IS_SYMBOL_NATIVE="function"===typeof Symbol&&"symbol"===typeof Symbol("x");$jscomp.TRUST_ES6_POLYFILLS=!$jscomp.ISOLATE_POLYFILLS||$jscomp.IS_SYMBOL_NATIVE;$jscomp.polyfills={};$jscomp.propertyToPolyfillSymbol={};$jscomp.POLYFILL_PREFIX="$jscp$";var $jscomp$lookupPolyfilledValue=function(a,b){var d=$jscomp.propertyToPolyfillSymbol[b];if(null==d)return a[b];d=a[d];return void 0!==d?d:a[b]};
+$jscomp.polyfill=function(a,b,d,f){b&&($jscomp.ISOLATE_POLYFILLS?$jscomp.polyfillIsolated(a,b,d,f):$jscomp.polyfillUnisolated(a,b,d,f))};$jscomp.polyfillUnisolated=function(a,b,d,f){d=$jscomp.global;a=a.split(".");for(f=0;f<a.length-1;f++){var e=a[f];if(!(e in d))return;d=d[e]}a=a[a.length-1];f=d[a];b=b(f);b!=f&&null!=b&&$jscomp.defineProperty(d,a,{configurable:!0,writable:!0,value:b})};
+$jscomp.polyfillIsolated=function(a,b,d,f){var e=a.split(".");a=1===e.length;f=e[0];f=!a&&f in $jscomp.polyfills?$jscomp.polyfills:$jscomp.global;for(var l=0;l<e.length-1;l++){var c=e[l];if(!(c in f))return;f=f[c]}e=e[e.length-1];d=$jscomp.IS_SYMBOL_NATIVE&&"es6"===d?f[e]:null;b=b(d);null!=b&&(a?$jscomp.defineProperty($jscomp.polyfills,e,{configurable:!0,writable:!0,value:b}):b!==d&&($jscomp.propertyToPolyfillSymbol[e]=$jscomp.IS_SYMBOL_NATIVE?$jscomp.global.Symbol(e):$jscomp.POLYFILL_PREFIX+e,e=
+$jscomp.propertyToPolyfillSymbol[e],$jscomp.defineProperty(f,e,{configurable:!0,writable:!0,value:b})))};$jscomp.underscoreProtoCanBeSet=function(){var a={a:!0},b={};try{return b.__proto__=a,b.a}catch(d){}return!1};$jscomp.setPrototypeOf=$jscomp.TRUST_ES6_POLYFILLS&&"function"==typeof Object.setPrototypeOf?Object.setPrototypeOf:$jscomp.underscoreProtoCanBeSet()?function(a,b){a.__proto__=b;if(a.__proto__!==b)throw new TypeError(a+" is not extensible");return a}:null;
+$jscomp.arrayIteratorImpl=function(a){var b=0;return function(){return b<a.length?{done:!1,value:a[b++]}:{done:!0}}};$jscomp.arrayIterator=function(a){return{next:$jscomp.arrayIteratorImpl(a)}};$jscomp.makeIterator=function(a){var b="undefined"!=typeof Symbol&&Symbol.iterator&&a[Symbol.iterator];return b?b.call(a):$jscomp.arrayIterator(a)};$jscomp.generator={};
+$jscomp.generator.ensureIteratorResultIsObject_=function(a){if(!(a instanceof Object))throw new TypeError("Iterator result "+a+" is not an object");};$jscomp.generator.Context=function(){this.isRunning_=!1;this.yieldAllIterator_=null;this.yieldResult=void 0;this.nextAddress=1;this.finallyAddress_=this.catchAddress_=0;this.finallyContexts_=this.abruptCompletion_=null};
+$jscomp.generator.Context.prototype.start_=function(){if(this.isRunning_)throw new TypeError("Generator is already running");this.isRunning_=!0};$jscomp.generator.Context.prototype.stop_=function(){this.isRunning_=!1};$jscomp.generator.Context.prototype.jumpToErrorHandler_=function(){this.nextAddress=this.catchAddress_||this.finallyAddress_};$jscomp.generator.Context.prototype.next_=function(a){this.yieldResult=a};
+$jscomp.generator.Context.prototype.throw_=function(a){this.abruptCompletion_={exception:a,isException:!0};this.jumpToErrorHandler_()};$jscomp.generator.Context.prototype.return=function(a){this.abruptCompletion_={return:a};this.nextAddress=this.finallyAddress_};$jscomp.generator.Context.prototype.jumpThroughFinallyBlocks=function(a){this.abruptCompletion_={jumpTo:a};this.nextAddress=this.finallyAddress_};$jscomp.generator.Context.prototype.yield=function(a,b){this.nextAddress=b;return{value:a}};
+$jscomp.generator.Context.prototype.yieldAll=function(a,b){a=$jscomp.makeIterator(a);var d=a.next();$jscomp.generator.ensureIteratorResultIsObject_(d);if(d.done)this.yieldResult=d.value,this.nextAddress=b;else return this.yieldAllIterator_=a,this.yield(d.value,b)};$jscomp.generator.Context.prototype.jumpTo=function(a){this.nextAddress=a};$jscomp.generator.Context.prototype.jumpToEnd=function(){this.nextAddress=0};
+$jscomp.generator.Context.prototype.setCatchFinallyBlocks=function(a,b){this.catchAddress_=a;void 0!=b&&(this.finallyAddress_=b)};$jscomp.generator.Context.prototype.setFinallyBlock=function(a){this.catchAddress_=0;this.finallyAddress_=a||0};$jscomp.generator.Context.prototype.leaveTryBlock=function(a,b){this.nextAddress=a;this.catchAddress_=b||0};
+$jscomp.generator.Context.prototype.enterCatchBlock=function(a){this.catchAddress_=a||0;a=this.abruptCompletion_.exception;this.abruptCompletion_=null;return a};$jscomp.generator.Context.prototype.enterFinallyBlock=function(a,b,d){d?this.finallyContexts_[d]=this.abruptCompletion_:this.finallyContexts_=[this.abruptCompletion_];this.catchAddress_=a||0;this.finallyAddress_=b||0};
 $jscomp.generator.Context.prototype.leaveFinallyBlock=function(a,b){b=this.finallyContexts_.splice(b||0)[0];if(b=this.abruptCompletion_=this.abruptCompletion_||b){if(b.isException)return this.jumpToErrorHandler_();void 0!=b.jumpTo&&this.finallyAddress_<b.jumpTo?(this.nextAddress=b.jumpTo,this.abruptCompletion_=null):this.nextAddress=this.finallyAddress_}else this.nextAddress=a};$jscomp.generator.Context.prototype.forIn=function(a){return new $jscomp.generator.Context.PropertyIterator(a)};
 $jscomp.generator.Context.PropertyIterator=function(a){this.object_=a;this.properties_=[];for(var b in a)this.properties_.push(b);this.properties_.reverse()};$jscomp.generator.Context.PropertyIterator.prototype.getNext=function(){for(;0<this.properties_.length;){var a=this.properties_.pop();if(a in this.object_)return a}return null};$jscomp.generator.Engine_=function(a){this.context_=new $jscomp.generator.Context;this.program_=a};
 $jscomp.generator.Engine_.prototype.next_=function(a){this.context_.start_();if(this.context_.yieldAllIterator_)return this.yieldAllStep_(this.context_.yieldAllIterator_.next,a,this.context_.next_);this.context_.next_(a);return this.nextStep_()};
-$jscomp.generator.Engine_.prototype.return_=function(a){this.context_.start_();var b=this.context_.yieldAllIterator_;if(b)return this.yieldAllStep_("return"in b?b["return"]:function(a){return{value:a,done:!0}},a,this.context_.return);this.context_.return(a);return this.nextStep_()};
+$jscomp.generator.Engine_.prototype.return_=function(a){this.context_.start_();var b=this.context_.yieldAllIterator_;if(b)return this.yieldAllStep_("return"in b?b["return"]:function(d){return{value:d,done:!0}},a,this.context_.return);this.context_.return(a);return this.nextStep_()};
 $jscomp.generator.Engine_.prototype.throw_=function(a){this.context_.start_();if(this.context_.yieldAllIterator_)return this.yieldAllStep_(this.context_.yieldAllIterator_["throw"],a,this.context_.next_);this.context_.throw_(a);return this.nextStep_()};
-$jscomp.generator.Engine_.prototype.yieldAllStep_=function(a,b,c){try{var d=a.call(this.context_.yieldAllIterator_,b);$jscomp.generator.ensureIteratorResultIsObject_(d);if(!d.done)return this.context_.stop_(),d;var e=d.value}catch(g){return this.context_.yieldAllIterator_=null,this.context_.throw_(g),this.nextStep_()}this.context_.yieldAllIterator_=null;c.call(this.context_,e);return this.nextStep_()};
+$jscomp.generator.Engine_.prototype.yieldAllStep_=function(a,b,d){try{var f=a.call(this.context_.yieldAllIterator_,b);$jscomp.generator.ensureIteratorResultIsObject_(f);if(!f.done)return this.context_.stop_(),f;var e=f.value}catch(l){return this.context_.yieldAllIterator_=null,this.context_.throw_(l),this.nextStep_()}this.context_.yieldAllIterator_=null;d.call(this.context_,e);return this.nextStep_()};
 $jscomp.generator.Engine_.prototype.nextStep_=function(){for(;this.context_.nextAddress;)try{var a=this.program_(this.context_);if(a)return this.context_.stop_(),{value:a.value,done:!1}}catch(b){this.context_.yieldResult=void 0,this.context_.throw_(b)}this.context_.stop_();if(this.context_.abruptCompletion_){a=this.context_.abruptCompletion_;this.context_.abruptCompletion_=null;if(a.isException)throw a.exception;return{value:a.return,done:!0}}return{value:void 0,done:!0}};
-$jscomp.generator.Generator_=function(a){this.next=function(b){return a.next_(b)};this.throw=function(b){return a.throw_(b)};this.return=function(b){return a.return_(b)};$jscomp.initSymbolIterator();this[Symbol.iterator]=function(){return this}};$jscomp.generator.createGenerator=function(a,b){b=new $jscomp.generator.Generator_(new $jscomp.generator.Engine_(b));$jscomp.setPrototypeOf&&$jscomp.setPrototypeOf(b,a.prototype);return b};
-$jscomp.asyncExecutePromiseGenerator=function(a){function b(b){return a.next(b)}function c(b){return a.throw(b)}return new Promise(function(d,e){function g(a){a.done?d(a.value):Promise.resolve(a.value).then(b,c).then(g,e)}g(a.next())})};$jscomp.asyncExecutePromiseGeneratorFunction=function(a){return $jscomp.asyncExecutePromiseGenerator(a())};$jscomp.asyncExecutePromiseGeneratorProgram=function(a){return $jscomp.asyncExecutePromiseGenerator(new $jscomp.generator.Generator_(new $jscomp.generator.Engine_(a)))};
-$jscomp.polyfill("globalThis",function(a){return a||$jscomp.global},"es_next","es3");var fetchButton=document.querySelector(".js-fetchButton");fetchButton&&fetchButton.addEventListener("click",function(a){a.preventDefault();fetchPath()});
-function fetchPath(){var a,b,c;return $jscomp.asyncExecutePromiseGeneratorProgram(function(d){if(1==d.nextAddress)return a=document.querySelector(".js-fetchMessage"),a.textContent="Fetching "+a.dataset.path,document.querySelector(".js-fetchMessageSecondary").textContent="Feel free to navigate away and check back later, we\u2019ll keep working on it!",document.querySelector(".js-fetchButton").style.display="none",document.querySelector(".js-fetchLoading").style.display="block",d.yield(fetch("/fetch"+
-window.location.pathname,{method:"POST"}),2);if(3!=d.nextAddress)return b=d.yieldResult,b.ok?(window.location.reload(),d.return()):d.yield(b.text(),3);c=d.yieldResult;document.querySelector(".js-fetchLoading").style.display="none";document.querySelector(".js-fetchMessageSecondary").textContent="";document.querySelector(".js-fetchMessage").textContent=c;d.jumpToEnd()})};
+$jscomp.generator.Generator_=function(a){this.next=function(b){return a.next_(b)};this.throw=function(b){return a.throw_(b)};this.return=function(b){return a.return_(b)};this[Symbol.iterator]=function(){return this}};$jscomp.generator.createGenerator=function(a,b){b=new $jscomp.generator.Generator_(new $jscomp.generator.Engine_(b));$jscomp.setPrototypeOf&&a.prototype&&$jscomp.setPrototypeOf(b,a.prototype);return b};
+$jscomp.asyncExecutePromiseGenerator=function(a){function b(f){return a.next(f)}function d(f){return a.throw(f)}return new Promise(function(f,e){function l(c){c.done?f(c.value):Promise.resolve(c.value).then(b,d).then(l,e)}l(a.next())})};$jscomp.asyncExecutePromiseGeneratorFunction=function(a){return $jscomp.asyncExecutePromiseGenerator(a())};$jscomp.asyncExecutePromiseGeneratorProgram=function(a){return $jscomp.asyncExecutePromiseGenerator(new $jscomp.generator.Generator_(new $jscomp.generator.Engine_(a)))};
+$jscomp.initSymbol=function(){};$jscomp.polyfill("Symbol",function(a){if(a)return a;var b=function(e,l){this.$jscomp$symbol$id_=e;$jscomp.defineProperty(this,"description",{configurable:!0,writable:!0,value:l})};b.prototype.toString=function(){return this.$jscomp$symbol$id_};var d=0,f=function(e){if(this instanceof f)throw new TypeError("Symbol is not a constructor");return new b("jscomp_symbol_"+(e||"")+"_"+d++,e)};return f},"es6","es3");$jscomp.initSymbolIterator=function(){};
+$jscomp.polyfill("Symbol.iterator",function(a){if(a)return a;a=Symbol("Symbol.iterator");for(var b="Array Int8Array Uint8Array Uint8ClampedArray Int16Array Uint16Array Int32Array Uint32Array Float32Array Float64Array".split(" "),d=0;d<b.length;d++){var f=$jscomp.global[b[d]];"function"===typeof f&&"function"!=typeof f.prototype[a]&&$jscomp.defineProperty(f.prototype,a,{configurable:!0,writable:!0,value:function(){return $jscomp.iteratorPrototype($jscomp.arrayIteratorImpl(this))}})}return a},"es6",
+"es3");$jscomp.initSymbolAsyncIterator=function(){};$jscomp.iteratorPrototype=function(a){a={next:a};a[Symbol.iterator]=function(){return this};return a};$jscomp.FORCE_POLYFILL_PROMISE=!1;
+$jscomp.polyfill("Promise",function(a){function b(){this.batch_=null}function d(c){return c instanceof e?c:new e(function(g,h){g(c)})}if(a&&!$jscomp.FORCE_POLYFILL_PROMISE)return a;b.prototype.asyncExecute=function(c){if(null==this.batch_){this.batch_=[];var g=this;this.asyncExecuteFunction(function(){g.executeBatch_()})}this.batch_.push(c)};var f=$jscomp.global.setTimeout;b.prototype.asyncExecuteFunction=function(c){f(c,0)};b.prototype.executeBatch_=function(){for(;this.batch_&&this.batch_.length;){var c=
+this.batch_;this.batch_=[];for(var g=0;g<c.length;++g){var h=c[g];c[g]=null;try{h()}catch(k){this.asyncThrow_(k)}}}this.batch_=null};b.prototype.asyncThrow_=function(c){this.asyncExecuteFunction(function(){throw c;})};var e=function(c){this.state_=0;this.result_=void 0;this.onSettledCallbacks_=[];var g=this.createResolveAndReject_();try{c(g.resolve,g.reject)}catch(h){g.reject(h)}};e.prototype.createResolveAndReject_=function(){function c(k){return function(m){h||(h=!0,k.call(g,m))}}var g=this,h=!1;
+return{resolve:c(this.resolveTo_),reject:c(this.reject_)}};e.prototype.resolveTo_=function(c){if(c===this)this.reject_(new TypeError("A Promise cannot resolve to itself"));else if(c instanceof e)this.settleSameAsPromise_(c);else{a:switch(typeof c){case "object":var g=null!=c;break a;case "function":g=!0;break a;default:g=!1}g?this.resolveToNonPromiseObj_(c):this.fulfill_(c)}};e.prototype.resolveToNonPromiseObj_=function(c){var g=void 0;try{g=c.then}catch(h){this.reject_(h);return}"function"==typeof g?
+this.settleSameAsThenable_(g,c):this.fulfill_(c)};e.prototype.reject_=function(c){this.settle_(2,c)};e.prototype.fulfill_=function(c){this.settle_(1,c)};e.prototype.settle_=function(c,g){if(0!=this.state_)throw Error("Cannot settle("+c+", "+g+"): Promise already settled in state"+this.state_);this.state_=c;this.result_=g;this.executeOnSettledCallbacks_()};e.prototype.executeOnSettledCallbacks_=function(){if(null!=this.onSettledCallbacks_){for(var c=0;c<this.onSettledCallbacks_.length;++c)l.asyncExecute(this.onSettledCallbacks_[c]);
+this.onSettledCallbacks_=null}};var l=new b;e.prototype.settleSameAsPromise_=function(c){var g=this.createResolveAndReject_();c.callWhenSettled_(g.resolve,g.reject)};e.prototype.settleSameAsThenable_=function(c,g){var h=this.createResolveAndReject_();try{c.call(g,h.resolve,h.reject)}catch(k){h.reject(k)}};e.prototype.then=function(c,g){function h(n,p){return"function"==typeof n?function(q){try{k(n(q))}catch(r){m(r)}}:p}var k,m,t=new e(function(n,p){k=n;m=p});this.callWhenSettled_(h(c,k),h(g,m));return t};
+e.prototype.catch=function(c){return this.then(void 0,c)};e.prototype.callWhenSettled_=function(c,g){function h(){switch(k.state_){case 1:c(k.result_);break;case 2:g(k.result_);break;default:throw Error("Unexpected state: "+k.state_);}}var k=this;null==this.onSettledCallbacks_?l.asyncExecute(h):this.onSettledCallbacks_.push(h)};e.resolve=d;e.reject=function(c){return new e(function(g,h){h(c)})};e.race=function(c){return new e(function(g,h){for(var k=$jscomp.makeIterator(c),m=k.next();!m.done;m=k.next())d(m.value).callWhenSettled_(g,
+h)})};e.all=function(c){var g=$jscomp.makeIterator(c),h=g.next();return h.done?d([]):new e(function(k,m){function t(q){return function(r){n[q]=r;p--;0==p&&k(n)}}var n=[],p=0;do n.push(void 0),p++,d(h.value).callWhenSettled_(t(n.length-1),m),h=g.next();while(!h.done)})};return e},"es6","es3");var fetchButton=document.querySelector(".js-fetchButton");fetchButton&&fetchButton.addEventListener("click",function(a){a.preventDefault();fetchPath()});
+function fetchPath(){var a,b,d;return $jscomp.asyncExecutePromiseGeneratorProgram(function(f){if(1==f.nextAddress)return a=document.querySelector(".js-fetchMessage"),a.textContent="Fetching "+a.dataset.path,document.querySelector(".js-fetchMessageSecondary").textContent="Feel free to navigate away and check back later, we\u2019ll keep working on it!",document.querySelector(".js-fetchButton").style.display="none",document.querySelector(".js-fetchLoading").style.display="block",f.yield(fetch("/fetch"+
+window.location.pathname,{method:"POST"}),2);if(3!=f.nextAddress)return b=f.yieldResult,b.ok?(window.location.reload(),f.return()):f.yield(b.text(),3);d=f.yieldResult;document.querySelector(".js-fetchLoading").style.display="none";document.querySelector(".js-fetchMessageSecondary").textContent="";document.querySelector(".js-fetchMessage").textContent=d;f.jumpToEnd()})};
diff --git a/content/static/js/fixed_header.js b/content/static/js/fixed_header.js
new file mode 100644
index 0000000..1b8e359
--- /dev/null
+++ b/content/static/js/fixed_header.js
@@ -0,0 +1,58 @@
+/**
+ * @license
+ * Copyright 2019-2020 The Go Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ */
+
+/**
+ * Shows a fixed element when a separate element begins to go out of view.
+ */
+class FixedHeaderController {
+  /**
+   * @param {Element} el
+   * @param {Element} fixedEl
+   */
+  constructor(el, fixedEl) {
+    if (!el || !fixedEl) {
+      throw new Error('Must provide sentinel and fixed elements to constructor.');
+    }
+
+    /**
+     * The element to observe to determine whether to show the fixed element.
+     * @type {!Element}
+     * @private
+     */
+    this._el = /** @type {!Element} */ (el);
+
+    /**
+     * The element to show when the other begins to go out of view.
+     * @type {!Element}
+     * @private
+     */
+    this._fixedEl = /** @type {!Element} */ (fixedEl);
+
+    /**
+     * @type {!IntersectionObserver}
+     * @private
+     */
+    this._intersectionObserver = new IntersectionObserver(
+      (entries, observer) => this.intersectionObserverCallback(entries, observer),
+      {
+        threshold: 1.0,
+      }
+    );
+    this._intersectionObserver.observe(this._el);
+  }
+
+  /**
+   * @param {!Array<IntersectionObserverEntry>} entries
+   * @param {!IntersectionObserver} observer
+   * @private
+   */
+  intersectionObserverCallback(entries, observer) {
+    entries.forEach(entry => {
+      this._fixedEl.setAttribute('aria-hidden', entry.isIntersecting);
+    });
+  }
+}
diff --git a/content/static/js/jump.min.js b/content/static/js/jump.min.js
index 962d942..a945220 100644
--- a/content/static/js/jump.min.js
+++ b/content/static/js/jump.min.js
@@ -4,34 +4,34 @@
  Use of this source code is governed by a BSD-style
  license that can be found in the LICENSE file.
 */
-var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.arrayIteratorImpl=function(b){var c=0;return function(){return c<b.length?{done:!1,value:b[c++]}:{done:!0}}};$jscomp.arrayIterator=function(b){return{next:$jscomp.arrayIteratorImpl(b)}};$jscomp.makeIterator=function(b){var c="undefined"!=typeof Symbol&&Symbol.iterator&&b[Symbol.iterator];return c?c.call(b):$jscomp.arrayIterator(b)};
-(function(b,c){"object"===typeof exports&&"undefined"!==typeof module?module.exports=c():"function"===typeof define&&define.amd?define(c):(b=b||self,b.dialogPolyfill=c())})(this,function(){function b(a){for(;a&&a!==document.body;){var h=window.getComputedStyle(a),b=function(a,b){return!(void 0===h[a]||h[a]===b)};if(1>h.opacity||b("zIndex","auto")||b("transform","none")||b("mixBlendMode","normal")||b("filter","none")||b("perspective","none")||"isolate"===h.isolation||"fixed"===h.position||"touch"===
-h.webkitOverflowScrolling)return!0;a=a.parentElement}return!1}function c(a){for(;a;){if("dialog"===a.localName)return a;a=a.parentElement}return null}function e(a){a&&a.blur&&a!==document.body&&a.blur()}function d(a){return a&&a.hasAttribute("method")?"dialog"===a.getAttribute("method").toLowerCase():!1}function g(a){this.dialog_=a;this.openAsModal_=this.replacedStyleTop_=!1;a.hasAttribute("role")||a.setAttribute("role","dialog");a.show=this.show.bind(this);a.showModal=this.showModal.bind(this);a.close=
-this.close.bind(this);"returnValue"in a||(a.returnValue="");if("MutationObserver"in window)(new MutationObserver(this.maybeHideModal.bind(this))).observe(a,{attributes:!0,attributeFilter:["open"]});else{var b=!1,c=function(){b?this.downgradeModal():this.maybeHideModal();b=!1}.bind(this),d,f=function(h){h.target===a&&(b|="DOMNodeRemoved"===h.type.substr(0,14),window.clearTimeout(d),d=window.setTimeout(c,0))};["DOMAttrModified","DOMNodeRemoved","DOMNodeRemovedFromDocument"].forEach(function(b){a.addEventListener(b,
-f)})}Object.defineProperty(a,"open",{set:this.setOpen.bind(this),get:a.hasAttribute.bind(a,"open")});this.backdrop_=document.createElement("div");this.backdrop_.className="backdrop";this.backdrop_.addEventListener("click",this.backdropClick_.bind(this))}var l=window.CustomEvent;l&&"object"!==typeof l||(l=function(a,b){b=b||{};var h=document.createEvent("CustomEvent");h.initCustomEvent(a,!!b.bubbles,!!b.cancelable,b.detail||null);return h},l.prototype=window.Event.prototype);g.prototype={get dialog(){return this.dialog_},
-maybeHideModal:function(){this.dialog_.hasAttribute("open")&&document.body.contains(this.dialog_)||this.downgradeModal()},downgradeModal:function(){this.openAsModal_&&(this.openAsModal_=!1,this.dialog_.style.zIndex="",this.replacedStyleTop_&&(this.dialog_.style.top="",this.replacedStyleTop_=!1),this.backdrop_.parentNode&&this.backdrop_.parentNode.removeChild(this.backdrop_),f.dm.removeDialog(this))},setOpen:function(a){a?this.dialog_.hasAttribute("open")||this.dialog_.setAttribute("open",""):(this.dialog_.removeAttribute("open"),
+var $jscomp=$jscomp||{};$jscomp.scope={};$jscomp.arrayIteratorImpl=function(c){var d=0;return function(){return d<c.length?{done:!1,value:c[d++]}:{done:!0}}};$jscomp.arrayIterator=function(c){return{next:$jscomp.arrayIteratorImpl(c)}};$jscomp.makeIterator=function(c){var d="undefined"!=typeof Symbol&&Symbol.iterator&&c[Symbol.iterator];return d?d.call(c):$jscomp.arrayIterator(c)};
+(function(c,d){"object"===typeof exports&&"undefined"!==typeof module?module.exports=d():"function"===typeof define&&define.amd?define(d):(c=c||self,c.dialogPolyfill=d())})(this,function(){function c(a){for(;a&&a!==document.body;){var b=window.getComputedStyle(a),e=function(n,l){return!(void 0===b[n]||b[n]===l)};if(1>b.opacity||e("zIndex","auto")||e("transform","none")||e("mixBlendMode","normal")||e("filter","none")||e("perspective","none")||"isolate"===b.isolation||"fixed"===b.position||"touch"===
+b.webkitOverflowScrolling)return!0;a=a.parentElement}return!1}function d(a){for(;a;){if("dialog"===a.localName)return a;a=a.parentElement}return null}function h(a){a&&a.blur&&a!==document.body&&a.blur()}function f(a){return a&&a.hasAttribute("method")?"dialog"===a.getAttribute("method").toLowerCase():!1}function m(a){this.dialog_=a;this.openAsModal_=this.replacedStyleTop_=!1;a.hasAttribute("role")||a.setAttribute("role","dialog");a.show=this.show.bind(this);a.showModal=this.showModal.bind(this);a.close=
+this.close.bind(this);"returnValue"in a||(a.returnValue="");if("MutationObserver"in window)(new MutationObserver(this.maybeHideModal.bind(this))).observe(a,{attributes:!0,attributeFilter:["open"]});else{var b=!1,e=function(){b?this.downgradeModal():this.maybeHideModal();b=!1}.bind(this),n,l=function(k){k.target===a&&(b|="DOMNodeRemoved"===k.type.substr(0,14),window.clearTimeout(n),n=window.setTimeout(e,0))};["DOMAttrModified","DOMNodeRemoved","DOMNodeRemovedFromDocument"].forEach(function(k){a.addEventListener(k,
+l)})}Object.defineProperty(a,"open",{set:this.setOpen.bind(this),get:a.hasAttribute.bind(a,"open")});this.backdrop_=document.createElement("div");this.backdrop_.className="backdrop";this.backdrop_.addEventListener("click",this.backdropClick_.bind(this))}var p=window.CustomEvent;p&&"object"!==typeof p||(p=function(a,b){b=b||{};var e=document.createEvent("CustomEvent");e.initCustomEvent(a,!!b.bubbles,!!b.cancelable,b.detail||null);return e},p.prototype=window.Event.prototype);m.prototype={get dialog(){return this.dialog_},
+maybeHideModal:function(){this.dialog_.hasAttribute("open")&&document.body.contains(this.dialog_)||this.downgradeModal()},downgradeModal:function(){this.openAsModal_&&(this.openAsModal_=!1,this.dialog_.style.zIndex="",this.replacedStyleTop_&&(this.dialog_.style.top="",this.replacedStyleTop_=!1),this.backdrop_.parentNode&&this.backdrop_.parentNode.removeChild(this.backdrop_),g.dm.removeDialog(this))},setOpen:function(a){a?this.dialog_.hasAttribute("open")||this.dialog_.setAttribute("open",""):(this.dialog_.removeAttribute("open"),
 this.maybeHideModal())},backdropClick_:function(a){if(this.dialog_.hasAttribute("tabindex"))this.dialog_.focus();else{var b=document.createElement("div");this.dialog_.insertBefore(b,this.dialog_.firstChild);b.tabIndex=-1;b.focus();this.dialog_.removeChild(b)}b=document.createEvent("MouseEvents");b.initMouseEvent(a.type,a.bubbles,a.cancelable,window,a.detail,a.screenX,a.screenY,a.clientX,a.clientY,a.ctrlKey,a.altKey,a.shiftKey,a.metaKey,a.button,a.relatedTarget);this.dialog_.dispatchEvent(b);a.stopPropagation()},
-focus_:function(){var a=this.dialog_.querySelector("[autofocus]:not([disabled])");!a&&0<=this.dialog_.tabIndex&&(a=this.dialog_);a||(a=["button","input","keygen","select","textarea"].map(function(a){return a+":not([disabled])"}),a.push('[tabindex]:not([disabled]):not([tabindex=""])'),a=this.dialog_.querySelector(a.join(", ")));e(document.activeElement);a&&a.focus()},updateZIndex:function(a,b){if(a<b)throw Error("dialogZ should never be < backdropZ");this.dialog_.style.zIndex=a;this.backdrop_.style.zIndex=
-b},show:function(){this.dialog_.open||(this.setOpen(!0),this.focus_())},showModal:function(){if(this.dialog_.hasAttribute("open"))throw Error("Failed to execute 'showModal' on dialog: The element is already open, and therefore cannot be opened modally.");if(!document.body.contains(this.dialog_))throw Error("Failed to execute 'showModal' on dialog: The element is not in a Document.");if(!f.dm.pushDialog(this))throw Error("Failed to execute 'showModal' on dialog: There are too many open modal dialogs.");
-b(this.dialog_.parentElement)&&console.warn("A dialog is being shown inside a stacking context. This may cause it to be unusable. For more information, see this link: https://github.com/GoogleChrome/dialog-polyfill/#stacking-context");this.setOpen(!0);this.openAsModal_=!0;f.needsCentering(this.dialog_)?(f.reposition(this.dialog_),this.replacedStyleTop_=!0):this.replacedStyleTop_=!1;this.dialog_.parentNode.insertBefore(this.backdrop_,this.dialog_.nextSibling);this.focus_()},close:function(a){if(!this.dialog_.hasAttribute("open"))throw Error("Failed to execute 'close' on dialog: The element does not have an 'open' attribute, and therefore cannot be closed.");
-this.setOpen(!1);void 0!==a&&(this.dialog_.returnValue=a);a=new l("close",{bubbles:!1,cancelable:!1});if(this.dialog_.onclose instanceof Function)this.dialog_.onclose(a);this.dialog_.dispatchEvent(a)}};var f={reposition:function(a){var b=document.body.scrollTop||document.documentElement.scrollTop;a.style.top=Math.max(b,b+(window.innerHeight-a.offsetHeight)/2)+"px"},isInlinePositionSetByStylesheet:function(a){for(var b=0;b<document.styleSheets.length;++b){var c=document.styleSheets[b],d=null;try{d=
-c.cssRules}catch(m){}if(d)for(c=0;c<d.length;++c){var f=d[c],e=null;try{e=document.querySelectorAll(f.selectorText)}catch(m){}var g;if(!(g=!e)){a:{for(g=0;g<e.length;++g)if(e[g]===a){e=!0;break a}e=!1}g=!e}if(!g&&(e=f.style.getPropertyValue("top"),f=f.style.getPropertyValue("bottom"),e&&"auto"!==e||f&&"auto"!==f))return!0}}return!1},needsCentering:function(a){return"absolute"!==window.getComputedStyle(a).position||"auto"!==a.style.top&&""!==a.style.top||"auto"!==a.style.bottom&&""!==a.style.bottom?
-!1:!f.isInlinePositionSetByStylesheet(a)},forceRegisterDialog:function(a){(window.HTMLDialogElement||a.showModal)&&console.warn("This browser already supports <dialog>, the polyfill may not work correctly",a);if("dialog"!==a.localName)throw Error("Failed to register dialog: The element is not a dialog.");new g(a)},registerDialog:function(a){a.showModal||f.forceRegisterDialog(a)},DialogManager:function(){this.pendingDialogStack=[];var a=this.checkDOM_.bind(this);this.overlay=document.createElement("div");
-this.overlay.className="_dialog_overlay";this.overlay.addEventListener("click",function(b){this.forwardTab_=void 0;b.stopPropagation();a([])}.bind(this));this.handleKey_=this.handleKey_.bind(this);this.handleFocus_=this.handleFocus_.bind(this);this.zIndexLow_=1E5;this.zIndexHigh_=100150;this.forwardTab_=void 0;"MutationObserver"in window&&(this.mo_=new MutationObserver(function(b){var c=[];b.forEach(function(a){for(var b=0,h;h=a.removedNodes[b];++b)h instanceof Element&&("dialog"===h.localName&&c.push(h),
-c=c.concat(h.querySelectorAll("dialog")))});c.length&&a(c)}))}};f.DialogManager.prototype.blockDocument=function(){document.documentElement.addEventListener("focus",this.handleFocus_,!0);document.addEventListener("keydown",this.handleKey_);this.mo_&&this.mo_.observe(document,{childList:!0,subtree:!0})};f.DialogManager.prototype.unblockDocument=function(){document.documentElement.removeEventListener("focus",this.handleFocus_,!0);document.removeEventListener("keydown",this.handleKey_);this.mo_&&this.mo_.disconnect()};
-f.DialogManager.prototype.updateStacking=function(){for(var a=this.zIndexHigh_,b=0,c;c=this.pendingDialogStack[b];++b)c.updateZIndex(--a,--a),0===b&&(this.overlay.style.zIndex=--a);(a=this.pendingDialogStack[0])?(a.dialog.parentNode||document.body).appendChild(this.overlay):this.overlay.parentNode&&this.overlay.parentNode.removeChild(this.overlay)};f.DialogManager.prototype.containedByTopDialog_=function(a){for(;a=c(a);){for(var b=0,d;d=this.pendingDialogStack[b];++b)if(d.dialog===a)return 0===b;
-a=a.parentElement}return!1};f.DialogManager.prototype.handleFocus_=function(a){if(!this.containedByTopDialog_(a.target)&&document.activeElement!==document.documentElement&&(a.preventDefault(),a.stopPropagation(),e(a.target),void 0!==this.forwardTab_)){var b=this.pendingDialogStack[0];b.dialog.compareDocumentPosition(a.target)&Node.DOCUMENT_POSITION_PRECEDING&&(this.forwardTab_?b.focus_():a.target!==document.documentElement&&document.documentElement.focus());return!1}};f.DialogManager.prototype.handleKey_=
-function(a){this.forwardTab_=void 0;if(27===a.keyCode){a.preventDefault();a.stopPropagation();a=new l("cancel",{bubbles:!1,cancelable:!0});var b=this.pendingDialogStack[0];b&&b.dialog.dispatchEvent(a)&&b.dialog.close()}else 9===a.keyCode&&(this.forwardTab_=!a.shiftKey)};f.DialogManager.prototype.checkDOM_=function(a){this.pendingDialogStack.slice().forEach(function(b){-1!==a.indexOf(b.dialog)?b.downgradeModal():b.maybeHideModal()})};f.DialogManager.prototype.pushDialog=function(a){if(this.pendingDialogStack.length>=
-(this.zIndexHigh_-this.zIndexLow_)/2-1)return!1;1===this.pendingDialogStack.unshift(a)&&this.blockDocument();this.updateStacking();return!0};f.DialogManager.prototype.removeDialog=function(a){a=this.pendingDialogStack.indexOf(a);-1!==a&&(this.pendingDialogStack.splice(a,1),0===this.pendingDialogStack.length&&this.unblockDocument(),this.updateStacking())};f.dm=new f.DialogManager;f.formSubmitter=null;f.useValue=null;if(void 0===window.HTMLDialogElement){var k=document.createElement("form");k.setAttribute("method",
-"dialog");if("dialog"!==k.method&&(k=Object.getOwnPropertyDescriptor(HTMLFormElement.prototype,"method"))){var n=k.get;k.get=function(){return d(this)?"dialog":n.call(this)};var p=k.set;k.set=function(a){return"string"===typeof a&&"dialog"===a.toLowerCase()?this.setAttribute("method",a):p.call(this,a)};Object.defineProperty(HTMLFormElement.prototype,"method",k)}document.addEventListener("click",function(a){f.formSubmitter=null;f.useValue=null;if(!a.defaultPrevented){var b=a.target;if(b&&d(b.form)){if(!("submit"===
-b.type&&-1<["button","input"].indexOf(b.localName))){if("input"!==b.localName||"image"!==b.type)return;f.useValue=a.offsetX+","+a.offsetY}c(b)&&(f.formSubmitter=b)}}},!1);var q=HTMLFormElement.prototype.submit;HTMLFormElement.prototype.submit=function(){if(!d(this))return q.call(this);var a=c(this);a&&a.close()};document.addEventListener("submit",function(a){if(!a.defaultPrevented){var b=a.target;if(d(b)&&(a.preventDefault(),a=c(b))){var e=f.formSubmitter;e&&e.form===b?a.close(f.useValue||e.value):
-a.close();f.formSubmitter=null}}},!1)}return f});var jumpDialog=document.querySelector(".JumpDialog"),jumpBody=jumpDialog.querySelector(".JumpDialog-body"),jumpList=jumpDialog.querySelector(".JumpDialog-list"),jumpFilter=jumpDialog.querySelector(".JumpDialog-input"),searchInput=document.querySelector(".js-autoComplete");jumpDialog.showModal||dialogPolyfill.registerDialog(jumpDialog);var jumpListItems;
-function collectJumpListItems(){for(var b=[],c=document.querySelector(".Documentation"),e=$jscomp.makeIterator(c.querySelectorAll("[data-kind]")),d=e.next();!d.done;d=e.next())b.push(newJumpListItem(d.value));0==b.length&&(b=collectJumpListItemsFallback(c));c=$jscomp.makeIterator(b);for(e=c.next();!e.done;e=c.next())e.value.link.addEventListener("click",function(){jumpDialog.close()});b.sort(function(b,c){return b.lower.localeCompare(c.lower)});return b}
-function collectJumpListItemsFallback(b){var c=[],e={};b=$jscomp.makeIterator(b.querySelectorAll("*[id]"));for(var d=b.next();!d.done;d=b.next()){d=d.value;var g=d.getAttribute("id");!e[g]&&/^[^_][^-]*$/.test(g)&&(e[g]=!0,c.push(newJumpListItem(d)))}return c}
-function newJumpListItem(b){var c=document.createElement("a"),e=b.getAttribute("id");c.setAttribute("href","#"+e);c.setAttribute("tabindex","-1");var d=b.getAttribute("data-kind");d||(d=guessKind(b));return{link:c,name:e,kind:d,lower:e.toLowerCase()}}
-function guessKind(b){switch(b.getAttribute("class")){case "Documentation-functionHeader":case "Documentation-typeFuncHeader":return"function";case "Documentation-typeHeader":return"type";case "Documentation-typeMethodHeader":return"method";default:switch(b.closest("section").getAttribute("class")){case "Documentation-variables":return"variable";case "Documentation-constants":return"constant";case "Documentation-types":return"field";default:return""}}}var lastFilterValue,activeJumpItem=-1;
-function updateJumpList(b){lastFilterValue=b;jumpListItems||(jumpListItems=collectJumpListItems());for(setActiveJumpItem(-1);jumpList.firstChild;)jumpList.firstChild.remove();for(var c=new RegExp(b.replace(/([.*+?^=!:${}()|\[\]\/\\])/g,"\\$1"),"gi"),e=$jscomp.makeIterator(jumpListItems),d=e.next();!d.done;d=e.next()){d=d.value;var g=d.name;if(b&&(g=g.replace(c,function(b){return"<b>"+b+"</b>"}),g==d.name))continue;d.link.innerHTML=g+" <i>"+d.kind+"</i>";jumpList.appendChild(d.link)}jumpBody.scrollTop=
-0;0<jumpList.children.length&&setActiveJumpItem(0)}function setActiveJumpItem(b){var c=jumpList.children;0<=activeJumpItem&&c[activeJumpItem].classList.remove("JumpDialog-active");b>=c.length&&(b=c.length-1);if(0<=b){c[b].classList.add("JumpDialog-active");var e=c[b].offsetTop-c[0].offsetTop;c=e+c[b].clientHeight;e<jumpBody.scrollTop?jumpBody.scrollTop=e:c>jumpBody.scrollTop+jumpBody.clientHeight&&(jumpBody.scrollTop=c-jumpBody.clientHeight)}activeJumpItem=b}
-function incActiveJumpItem(b){0>activeJumpItem||(b=activeJumpItem+b,0>b&&(b=0),setActiveJumpItem(b))}jumpFilter.addEventListener("keyup",function(b){jumpFilter.value.toUpperCase()!=lastFilterValue.toUpperCase()&&updateJumpList(jumpFilter.value)});jumpFilter.addEventListener("keydown",function(b){switch(b.which){case 38:incActiveJumpItem(-1);b.preventDefault();break;case 40:incActiveJumpItem(1);b.preventDefault();break;case 13:0<=activeJumpItem&&jumpList.children[activeJumpItem].click()}});
+focus_:function(){var a=this.dialog_.querySelector("[autofocus]:not([disabled])");!a&&0<=this.dialog_.tabIndex&&(a=this.dialog_);a||(a=["button","input","keygen","select","textarea"].map(function(b){return b+":not([disabled])"}),a.push('[tabindex]:not([disabled]):not([tabindex=""])'),a=this.dialog_.querySelector(a.join(", ")));h(document.activeElement);a&&a.focus()},updateZIndex:function(a,b){if(a<b)throw Error("dialogZ should never be < backdropZ");this.dialog_.style.zIndex=a;this.backdrop_.style.zIndex=
+b},show:function(){this.dialog_.open||(this.setOpen(!0),this.focus_())},showModal:function(){if(this.dialog_.hasAttribute("open"))throw Error("Failed to execute 'showModal' on dialog: The element is already open, and therefore cannot be opened modally.");if(!document.body.contains(this.dialog_))throw Error("Failed to execute 'showModal' on dialog: The element is not in a Document.");if(!g.dm.pushDialog(this))throw Error("Failed to execute 'showModal' on dialog: There are too many open modal dialogs.");
+c(this.dialog_.parentElement)&&console.warn("A dialog is being shown inside a stacking context. This may cause it to be unusable. For more information, see this link: https://github.com/GoogleChrome/dialog-polyfill/#stacking-context");this.setOpen(!0);this.openAsModal_=!0;g.needsCentering(this.dialog_)?(g.reposition(this.dialog_),this.replacedStyleTop_=!0):this.replacedStyleTop_=!1;this.dialog_.parentNode.insertBefore(this.backdrop_,this.dialog_.nextSibling);this.focus_()},close:function(a){if(!this.dialog_.hasAttribute("open"))throw Error("Failed to execute 'close' on dialog: The element does not have an 'open' attribute, and therefore cannot be closed.");
+this.setOpen(!1);void 0!==a&&(this.dialog_.returnValue=a);a=new p("close",{bubbles:!1,cancelable:!1});if(this.dialog_.onclose instanceof Function)this.dialog_.onclose(a);this.dialog_.dispatchEvent(a)}};var g={reposition:function(a){var b=document.body.scrollTop||document.documentElement.scrollTop;a.style.top=Math.max(b,b+(window.innerHeight-a.offsetHeight)/2)+"px"},isInlinePositionSetByStylesheet:function(a){for(var b=0;b<document.styleSheets.length;++b){var e=document.styleSheets[b],n=null;try{n=
+e.cssRules}catch(t){}if(n)for(e=0;e<n.length;++e){var l=n[e],k=null;try{k=document.querySelectorAll(l.selectorText)}catch(t){}var r;if(!(r=!k)){a:{for(r=0;r<k.length;++r)if(k[r]===a){k=!0;break a}k=!1}r=!k}if(!r&&(k=l.style.getPropertyValue("top"),l=l.style.getPropertyValue("bottom"),k&&"auto"!==k||l&&"auto"!==l))return!0}}return!1},needsCentering:function(a){return"absolute"!==window.getComputedStyle(a).position||"auto"!==a.style.top&&""!==a.style.top||"auto"!==a.style.bottom&&""!==a.style.bottom?
+!1:!g.isInlinePositionSetByStylesheet(a)},forceRegisterDialog:function(a){(window.HTMLDialogElement||a.showModal)&&console.warn("This browser already supports <dialog>, the polyfill may not work correctly",a);if("dialog"!==a.localName)throw Error("Failed to register dialog: The element is not a dialog.");new m(a)},registerDialog:function(a){a.showModal||g.forceRegisterDialog(a)},DialogManager:function(){this.pendingDialogStack=[];var a=this.checkDOM_.bind(this);this.overlay=document.createElement("div");
+this.overlay.className="_dialog_overlay";this.overlay.addEventListener("click",function(b){this.forwardTab_=void 0;b.stopPropagation();a([])}.bind(this));this.handleKey_=this.handleKey_.bind(this);this.handleFocus_=this.handleFocus_.bind(this);this.zIndexLow_=1E5;this.zIndexHigh_=100150;this.forwardTab_=void 0;"MutationObserver"in window&&(this.mo_=new MutationObserver(function(b){var e=[];b.forEach(function(n){for(var l=0,k;k=n.removedNodes[l];++l)k instanceof Element&&("dialog"===k.localName&&e.push(k),
+e=e.concat(k.querySelectorAll("dialog")))});e.length&&a(e)}))}};g.DialogManager.prototype.blockDocument=function(){document.documentElement.addEventListener("focus",this.handleFocus_,!0);document.addEventListener("keydown",this.handleKey_);this.mo_&&this.mo_.observe(document,{childList:!0,subtree:!0})};g.DialogManager.prototype.unblockDocument=function(){document.documentElement.removeEventListener("focus",this.handleFocus_,!0);document.removeEventListener("keydown",this.handleKey_);this.mo_&&this.mo_.disconnect()};
+g.DialogManager.prototype.updateStacking=function(){for(var a=this.zIndexHigh_,b=0,e;e=this.pendingDialogStack[b];++b)e.updateZIndex(--a,--a),0===b&&(this.overlay.style.zIndex=--a);(a=this.pendingDialogStack[0])?(a.dialog.parentNode||document.body).appendChild(this.overlay):this.overlay.parentNode&&this.overlay.parentNode.removeChild(this.overlay)};g.DialogManager.prototype.containedByTopDialog_=function(a){for(;a=d(a);){for(var b=0,e;e=this.pendingDialogStack[b];++b)if(e.dialog===a)return 0===b;
+a=a.parentElement}return!1};g.DialogManager.prototype.handleFocus_=function(a){if(!this.containedByTopDialog_(a.target)&&document.activeElement!==document.documentElement&&(a.preventDefault(),a.stopPropagation(),h(a.target),void 0!==this.forwardTab_)){var b=this.pendingDialogStack[0];b.dialog.compareDocumentPosition(a.target)&Node.DOCUMENT_POSITION_PRECEDING&&(this.forwardTab_?b.focus_():a.target!==document.documentElement&&document.documentElement.focus());return!1}};g.DialogManager.prototype.handleKey_=
+function(a){this.forwardTab_=void 0;if(27===a.keyCode){a.preventDefault();a.stopPropagation();a=new p("cancel",{bubbles:!1,cancelable:!0});var b=this.pendingDialogStack[0];b&&b.dialog.dispatchEvent(a)&&b.dialog.close()}else 9===a.keyCode&&(this.forwardTab_=!a.shiftKey)};g.DialogManager.prototype.checkDOM_=function(a){this.pendingDialogStack.slice().forEach(function(b){-1!==a.indexOf(b.dialog)?b.downgradeModal():b.maybeHideModal()})};g.DialogManager.prototype.pushDialog=function(a){if(this.pendingDialogStack.length>=
+(this.zIndexHigh_-this.zIndexLow_)/2-1)return!1;1===this.pendingDialogStack.unshift(a)&&this.blockDocument();this.updateStacking();return!0};g.DialogManager.prototype.removeDialog=function(a){a=this.pendingDialogStack.indexOf(a);-1!==a&&(this.pendingDialogStack.splice(a,1),0===this.pendingDialogStack.length&&this.unblockDocument(),this.updateStacking())};g.dm=new g.DialogManager;g.formSubmitter=null;g.useValue=null;if(void 0===window.HTMLDialogElement){var q=document.createElement("form");q.setAttribute("method",
+"dialog");if("dialog"!==q.method&&(q=Object.getOwnPropertyDescriptor(HTMLFormElement.prototype,"method"))){var u=q.get;q.get=function(){return f(this)?"dialog":u.call(this)};var v=q.set;q.set=function(a){return"string"===typeof a&&"dialog"===a.toLowerCase()?this.setAttribute("method",a):v.call(this,a)};Object.defineProperty(HTMLFormElement.prototype,"method",q)}document.addEventListener("click",function(a){g.formSubmitter=null;g.useValue=null;if(!a.defaultPrevented){var b=a.target;if(b&&f(b.form)){if(!("submit"===
+b.type&&-1<["button","input"].indexOf(b.localName))){if("input"!==b.localName||"image"!==b.type)return;g.useValue=a.offsetX+","+a.offsetY}d(b)&&(g.formSubmitter=b)}}},!1);var w=HTMLFormElement.prototype.submit;HTMLFormElement.prototype.submit=function(){if(!f(this))return w.call(this);var a=d(this);a&&a.close()};document.addEventListener("submit",function(a){if(!a.defaultPrevented){var b=a.target;if(f(b)&&(a.preventDefault(),a=d(b))){var e=g.formSubmitter;e&&e.form===b?a.close(g.useValue||e.value):
+a.close();g.formSubmitter=null}}},!1)}return g});var jumpDialog=document.querySelector(".JumpDialog"),jumpBody=jumpDialog.querySelector(".JumpDialog-body"),jumpList=jumpDialog.querySelector(".JumpDialog-list"),jumpFilter=jumpDialog.querySelector(".JumpDialog-input"),searchInput=document.querySelector(".js-autoComplete");jumpDialog.showModal||dialogPolyfill.registerDialog(jumpDialog);var jumpListItems;
+function collectJumpListItems(){for(var c=[],d=document.querySelector(".Documentation"),h=$jscomp.makeIterator(d.querySelectorAll("[data-kind]")),f=h.next();!f.done;f=h.next())c.push(newJumpListItem(f.value));0==c.length&&(c=collectJumpListItemsFallback(d));d=$jscomp.makeIterator(c);for(h=d.next();!h.done;h=d.next())h.value.link.addEventListener("click",function(){jumpDialog.close()});c.sort(function(m,p){return m.lower.localeCompare(p.lower)});return c}
+function collectJumpListItemsFallback(c){var d=[],h={};c=$jscomp.makeIterator(c.querySelectorAll("*[id]"));for(var f=c.next();!f.done;f=c.next()){f=f.value;var m=f.getAttribute("id");!h[m]&&/^[^_][^-]*$/.test(m)&&(h[m]=!0,d.push(newJumpListItem(f)))}return d}
+function newJumpListItem(c){var d=document.createElement("a"),h=c.getAttribute("id");d.setAttribute("href","#"+h);d.setAttribute("tabindex","-1");var f=c.getAttribute("data-kind");f||(f=guessKind(c));return{link:d,name:h,kind:f,lower:h.toLowerCase()}}
+function guessKind(c){switch(c.getAttribute("class")){case "Documentation-functionHeader":case "Documentation-typeFuncHeader":return"function";case "Documentation-typeHeader":return"type";case "Documentation-typeMethodHeader":return"method";default:switch(c.closest("section").getAttribute("class")){case "Documentation-variables":return"variable";case "Documentation-constants":return"constant";case "Documentation-types":return"field";default:return""}}}var lastFilterValue,activeJumpItem=-1;
+function updateJumpList(c){lastFilterValue=c;jumpListItems||(jumpListItems=collectJumpListItems());for(setActiveJumpItem(-1);jumpList.firstChild;)jumpList.firstChild.remove();for(var d=new RegExp(c.replace(/([.*+?^=!:${}()|\[\]\/\\])/g,"\\$1"),"gi"),h=$jscomp.makeIterator(jumpListItems),f=h.next();!f.done;f=h.next()){f=f.value;var m=f.name;if(c&&(m=m.replace(d,function(p){return"<b>"+p+"</b>"}),m==f.name))continue;f.link.innerHTML=m+" <i>"+f.kind+"</i>";jumpList.appendChild(f.link)}jumpBody.scrollTop=
+0;0<jumpList.children.length&&setActiveJumpItem(0)}function setActiveJumpItem(c){var d=jumpList.children;0<=activeJumpItem&&d[activeJumpItem].classList.remove("JumpDialog-active");c>=d.length&&(c=d.length-1);if(0<=c){d[c].classList.add("JumpDialog-active");var h=d[c].offsetTop-d[0].offsetTop;d=h+d[c].clientHeight;h<jumpBody.scrollTop?jumpBody.scrollTop=h:d>jumpBody.scrollTop+jumpBody.clientHeight&&(jumpBody.scrollTop=d-jumpBody.clientHeight)}activeJumpItem=c}
+function incActiveJumpItem(c){0>activeJumpItem||(c=activeJumpItem+c,0>c&&(c=0),setActiveJumpItem(c))}jumpFilter.addEventListener("keyup",function(c){jumpFilter.value.toUpperCase()!=lastFilterValue.toUpperCase()&&updateJumpList(jumpFilter.value)});jumpFilter.addEventListener("keydown",function(c){switch(c.which){case 38:incActiveJumpItem(-1);c.preventDefault();break;case 40:incActiveJumpItem(1);c.preventDefault();break;case 13:0<=activeJumpItem&&jumpList.children[activeJumpItem].click()}});
 var shortcutsDialog=document.querySelector(".ShortcutsDialog");shortcutsDialog.showModal||dialogPolyfill.registerDialog(shortcutsDialog);
-document.addEventListener("keypress",function(b){if(!jumpDialog.open&&!shortcutsDialog.open){var c=b.target.tagName;if("INPUT"!=c&&"SELECT"!=c&&"TEXTAREA"!=c&&!(b.target.contentEditable&&"true"==b.target.contentEditable||b.metaKey||b.ctrlKey))switch(String.fromCharCode(b.which)){case "f":case "F":b.preventDefault();jumpFilter.value="";jumpDialog.showModal();updateJumpList("");break;case "?":shortcutsDialog.showModal();break;case "/":b.preventDefault(),searchInput.focus()}}});
+document.addEventListener("keypress",function(c){if(!jumpDialog.open&&!shortcutsDialog.open){var d=c.target.tagName;if("INPUT"!=d&&"SELECT"!=d&&"TEXTAREA"!=d&&!(c.target.contentEditable&&"true"==c.target.contentEditable||c.metaKey||c.ctrlKey))switch(String.fromCharCode(c.which)){case "f":case "F":c.preventDefault();jumpFilter.value="";jumpDialog.showModal();updateJumpList("");break;case "?":shortcutsDialog.showModal();break;case "/":c.preventDefault(),searchInput.focus()}}});
diff --git a/content/static/js/overflowing_tab_list.js b/content/static/js/overflowing_tab_list.js
new file mode 100644
index 0000000..c603c77
--- /dev/null
+++ b/content/static/js/overflowing_tab_list.js
@@ -0,0 +1,117 @@
+/**
+ * @license
+ * Copyright 2019-2020 The Go Authors. All rights reserved.
+ * Use of this source code is governed by a BSD-style
+ * license that can be found in the LICENSE file.
+ */
+
+/**
+ * Class names used by OverflowingTabListController.
+ * @private @enum {string}
+ */
+const OverflowingTabListClassName = {
+  IS_OVERFLOWING: 'is-overflowing',
+};
+
+/**
+ * Allows a list of tabs to overflow into a “more” menu depending on the size
+ * of the container.
+ */
+class OverflowingTabListController {
+  /**
+   * @param {Element} el
+   */
+  constructor(el) {
+    if (!el) {
+      throw new Error('Must provide an element.');
+    }
+
+    /**
+     * @type {!Element}
+     * @private
+     */
+    this._el = el;
+
+    const selectEl = this._el.querySelector('select');
+    if (!selectEl) {
+      throw new Error('Element must contain a <select> element.');
+    }
+
+    /**
+     * @type {!Element}
+     * @private
+     */
+    this._selectEl = /** @type {!Element} */ (selectEl);
+
+    /**
+     * An array of tab elements’ rightmost points.
+     * @type {!Array<number>}
+     * @private
+     */
+    this._tabRects = [];
+
+    if (!window.ResizeObserver) {
+      this._el.style.overflowX = 'scroll';
+      return;
+    }
+
+    let initialLeft = 0;
+    this._tabRects = Array.from(this._el.querySelectorAll(`[role='tab']`)).map((el, i) => {
+      if (i === 0) {
+        initialLeft = el.offsetLeft;
+      }
+      return el.offsetLeft + el.offsetWidth - initialLeft;
+    });
+
+    const resizeObserver = new ResizeObserver(entries => this.resizeObserverCallback(entries));
+    resizeObserver.observe(this._el);
+
+    this._selectEl.addEventListener('change', e =>
+      this.handleOverflowSelectChange(/** @type {!Event} */ (e))
+    );
+  }
+
+  /**
+   * @param {!Array<ResizeObserverEntry>} entries
+   * @private
+   */
+  resizeObserverCallback(entries) {
+    entries.forEach(entry => {
+      const containerRect = entry.target.getBoundingClientRect();
+      const hiddenEls = [];
+      this._el.querySelectorAll(`[role='tab']`).forEach((el, i) => {
+        const rect = this._tabRects[i];
+        let overflowPoint = containerRect.width;
+        const OVERFLOW_MENU_ELEMENT_ADJUSTMENT_PX = 40;
+        if (this._el.classList.contains(OverflowingTabListClassName.IS_OVERFLOWING)) {
+          overflowPoint -= OVERFLOW_MENU_ELEMENT_ADJUSTMENT_PX;
+        }
+        const hideEl = rect > overflowPoint;
+        el.setAttribute('aria-hidden', hideEl);
+        if (hideEl) {
+          hiddenEls.push(i);
+        }
+      });
+      this.setOverflowMenuHidden(hiddenEls.length === 0);
+      this._selectEl.querySelectorAll('option').forEach((el, i) => {
+        el.disabled = !hiddenEls.includes(i);
+      });
+    });
+  }
+
+  /**
+   * @param {boolean} hidden
+   * @private
+   */
+  setOverflowMenuHidden(hidden) {
+    this._el.classList.toggle(OverflowingTabListClassName.IS_OVERFLOWING, !hidden);
+  }
+
+  /**
+   * Handles when the overflow menu select element changes.
+   * @param {!Event} e
+   */
+  handleOverflowSelectChange(e) {
+    window.location.href = e.target.value;
+  }
+}
diff --git a/content/static/js/playground.min.js b/content/static/js/playground.min.js
index 53f5351..5f26ee0 100644
--- a/content/static/js/playground.min.js
+++ b/content/static/js/playground.min.js
@@ -4,6 +4,6 @@
  Use of this source code is governed by a BSD-style
  license that can be found in the LICENSE file.
 */
-var PlayExampleClassName={EXAMPLE_INPUT:".Documentation-exampleCode",EXAMPLE_OUTPUT:".Documentation-exampleOutput",EXAMPLE_ERROR:".Documentation-exampleError",PLAY_BUTTON:".Documentation-examplePlayButton"},PlaygroundExampleController=function(a){var d=this,c=!1;a||(console.warn("Must provide playground example element"),c=!0);var b=a.querySelector(PlayExampleClassName.EXAMPLE_ERROR);b||(c=!0);this._errorEl=b;(b=a.querySelector(PlayExampleClassName.PLAY_BUTTON))||(c=!0);this._playButtonEl=b;b=a.querySelector(PlayExampleClassName.EXAMPLE_INPUT);
-b||(console.warn("Input element is not detected"),c=!0);this._inputEl=b;this._outputEl=a.querySelector(PlayExampleClassName.EXAMPLE_OUTPUT);c||this._playButtonEl.addEventListener("click",function(a){return d.handlePlayButtonClick(a)})};PlaygroundExampleController.prototype.setOutputText=function(a){this._outputEl&&(this._outputEl.textContent=a)};PlaygroundExampleController.prototype.setErrorText=function(a){this._errorEl.textContent=a;this.setOutputText("An error has occurred\u2026")};
-PlaygroundExampleController.prototype.handlePlayButtonClick=function(a){var d=this;this.setOutputText("Waiting for remote server\u2026");fetch("/play/",{method:"POST",body:this._inputEl.textContent}).then(function(a){return a.text()}).then(function(a){window.open("//play.golang.org/p/"+a)}).catch(function(a){d.setErrorText(a)})};document.querySelectorAll(".js-exampleContainer").forEach(function(a){new PlaygroundExampleController(a)});
+var PlayExampleClassName={EXAMPLE_INPUT:".Documentation-exampleCode",EXAMPLE_OUTPUT:".Documentation-exampleOutput",EXAMPLE_ERROR:".Documentation-exampleError",PLAY_BUTTON:".Documentation-examplePlayButton"},PlaygroundExampleController=function(a){var d=this,b=!1;a||(console.warn("Must provide playground example element"),b=!0);var c=a.querySelector(PlayExampleClassName.EXAMPLE_ERROR);c||(b=!0);this._errorEl=c;(c=a.querySelector(PlayExampleClassName.PLAY_BUTTON))||(b=!0);this._playButtonEl=c;c=a.querySelector(PlayExampleClassName.EXAMPLE_INPUT);
+c||(console.warn("Input element is not detected"),b=!0);this._inputEl=c;this._outputEl=a.querySelector(PlayExampleClassName.EXAMPLE_OUTPUT);b||this._playButtonEl.addEventListener("click",function(e){return d.handlePlayButtonClick(e)})};PlaygroundExampleController.prototype.setOutputText=function(a){this._outputEl&&(this._outputEl.textContent=a)};PlaygroundExampleController.prototype.setErrorText=function(a){this._errorEl.textContent=a;this.setOutputText("An error has occurred\u2026")};
+PlaygroundExampleController.prototype.handlePlayButtonClick=function(a){var d=this;this.setOutputText("Waiting for remote server\u2026");fetch("/play/",{method:"POST",body:this._inputEl.textContent}).then(function(b){return b.text()}).then(function(b){window.open("//play.golang.org/p/"+b)}).catch(function(b){d.setErrorText(b)})};document.querySelectorAll(".js-exampleContainer").forEach(function(a){new PlaygroundExampleController(a)});
diff --git a/content/static/js/sidenav.js b/content/static/js/sidenav.js
index e0c110d..a8a1852 100644
--- a/content/static/js/sidenav.js
+++ b/content/static/js/sidenav.js
@@ -183,7 +183,7 @@
    * @private
    */
   scrollElementIntoView(el) {
-    const STICKY_HEADER_HEIGHT_PX = 105;
+    const STICKY_HEADER_HEIGHT_PX = 55;
     const viewportHeightPx = document.documentElement.clientHeight;
     const elRect = el.getBoundingClientRect();
     const verticalCenterPointPx = (viewportHeightPx - STICKY_HEADER_HEIGHT_PX) / 2;
@@ -545,7 +545,7 @@
     // the bottom of the site header. The root viewport of an IntersectionObserver
     // is inset by the header height plus one pixel to ensure that the container is
     // considered “out of view” when in a fixed position and can be styled appropriately.
-    const ROOT_TOP_MARGIN = '-65px';
+    const ROOT_TOP_MARGIN = '-57px';
 
     this._intersectionObserver = new IntersectionObserver(
       (entries, observer) => this.intersectionObserverCallback(entries, observer),
diff --git a/devtools/compile_js.sh b/devtools/compile_js.sh
index 15e80da..41f4c01 100755
--- a/devtools/compile_js.sh
+++ b/devtools/compile_js.sh
@@ -18,7 +18,12 @@
   local outfile=$1
   shift
   rm -f $outfile
-  docker run --rm -i femtopixel/google-closure-compiler-app:v20200112 < <(cat $@) > $outfile
+  local args
+  if [[ $1 = '-advanced' ]]; then
+    shift
+    args='--compilation_level=ADVANCED_OPTIMIZATIONS'
+  fi
+  docker run --rm -i femtopixel/google-closure-compiler-app:closure-compiler-parent-v20200719 $args < <(cat $@) > $outfile
   echo "wrote $outfile"
 }
 
@@ -39,13 +44,15 @@
   if [[ $1 = "-check" ]]; then
     cmd=check
   fi
-  $cmd $JSDIR/base.min.js       $JSDIR/{site,analytics}.js
-  # TODO: once this is not an experiment, add it to the line above.
-  $cmd $JSDIR/completion.min.js $JSDIR/completion.js
-  $cmd $JSDIR/fetch.min.js      $JSDIR/fetch.js
-  $cmd $JSDIR/playground.min.js $JSDIR/playground.js
-  $cmd $JSDIR/badge.min.js      $JSDIR/badge.js
-  $cmd $JSDIR/jump.min.js       third_party/dialog-polyfill/dialog-polyfill.js $JSDIR/jump.js
+  $cmd $JSDIR/base.min.js               $JSDIR/{site,analytics}.js
+  $cmd $JSDIR/details.min.js  -advanced $JSDIR/{clipboard,fixed_header,overflowing_tab_list,details}.js
+  $cmd $JSDIR/fetch.min.js              $JSDIR/fetch.js
+  $cmd $JSDIR/playground.min.js         $JSDIR/playground.js
+  $cmd $JSDIR/badge.min.js              $JSDIR/badge.js
+  $cmd $JSDIR/jump.min.js               third_party/dialog-polyfill/dialog-polyfill.js $JSDIR/jump.js
+
+  # TODO: once this is not an experiment, add it to the relevant line above.
+  $cmd $JSDIR/completion.min.js         $JSDIR/completion.js
 }
 
 main $@
diff --git a/internal/frontend/server_test.go b/internal/frontend/server_test.go
index 5c1a9f7..5554096 100644
--- a/internal/frontend/server_test.go
+++ b/internal/frontend/server_test.go
@@ -511,7 +511,7 @@
 			wantStatusCode: http.StatusOK,
 			want: in("",
 				pagecheck.PackageHeader(pkgV100, versioned),
-				in("li.selected", text(`Imports`)),
+				in("[role='tab'][aria-selected='true']", text(`Imports`)),
 				in(".Imports-heading", text(`Standard Library Imports`)),
 				in(".Imports-list",
 					in("li:nth-child(1) a", href("/fmt"), text("fmt")),
@@ -753,7 +753,7 @@
 			wantStatusCode: http.StatusOK,
 			want: in("",
 				pagecheck.ModuleHeader(mod, versioned),
-				in("li.selected", text(`Versions`)),
+				in("[role='tab'][aria-selected='true']", text(`Versions`)),
 				in("div.Versions", text("v1")),
 				in("li.Versions-item",
 					in("a",
diff --git a/internal/middleware/secureheaders.go b/internal/middleware/secureheaders.go
index de0bd9c..6f615be 100644
--- a/internal/middleware/secureheaders.go
+++ b/internal/middleware/secureheaders.go
@@ -18,7 +18,7 @@
 	// From content/static/html/pages/badge.tmpl
 	"'sha256-T7xOt6cgLji3rhOWyKK7t5XKv8+LASQwOnHiHHy8Kwk='",
 	// From content/static/html/pages/details.tmpl
-	"'sha256-s16e7aT7Gsajq5UH1DbaEFEnNx2VjvS5Xixcxwm4+F8='",
+	"'sha256-EWdCQW4XtY7zS2MZgs76+2EhMbqpaPtC+9EPGnbHBtM='",
 	// From content/static/html/pages/fetch.tmpl
 	"'sha256-1J6DWwTWs/QDZ2+ORDuUQCibmFnXXaNXYOtc0Jk6VU4='",
 	// From content/static/html/pages/pkg_doc.tmpl