content/static: move banners below main header

Moves the retracted, redirect, and major version banners
below the main header. Required updates to the layout
and styles of the module header. Header size is now
dynamically calculated to support overflow content inside
of the banners and breadcrumbs. This is necessary to create
a smooth transition between the sticky and regular header,
properly position the mobile documentation nav, and prevent
unwanted layout shift as sticky elements require an absolute
value for their top position.

Change-Id: Ie1ce80db658a1da87f686b340cfc292f83c2e7e5
Reviewed-on: https://go-review.googlesource.com/c/pkgsite/+/306890
Trust: Jamal Carvalho <jamal@golang.org>
Run-TryBot: Jamal Carvalho <jamal@golang.org>
TryBot-Result: kokoro <noreply+kokoro@google.com>
Reviewed-by: Julie Qiu <julie@golang.org>
diff --git a/content/static/css/sidenav.css b/content/static/css/sidenav.css
index ebd5eed..a554b62 100644
--- a/content/static/css/sidenav.css
+++ b/content/static/css/sidenav.css
@@ -20,7 +20,7 @@
   height: 3rem;
   margin: 0 -1rem;
   position: sticky;
-  top: var(--header-height);
+  top: calc(var(--header-height, 0) + var(--banner-height, 0));
   transition: box-shadow 0.2s linear;
   z-index: 100;
 }
diff --git a/content/static/css/stylesheet.css b/content/static/css/stylesheet.css
index 0797ef6..41c1b56 100644
--- a/content/static/css/stylesheet.css
+++ b/content/static/css/stylesheet.css
@@ -146,10 +146,18 @@
 }
 .Site-margin {
   margin: auto;
-  max-width: 95rem;
+  max-width: 97rem;
   width: 100%;
+  padding-left: 1rem;
+  padding-right: 1rem;
 }
-
+@media only screen and (min-width: 57.5rem) {
+  .Site-margin  {
+    max-width: 98rem;
+    padding-left: 1.5rem;
+    padding-right: 1.5rem;
+  }
+}
 .FeedbackButton {
   cursor: pointer;
 }
diff --git a/content/static/css/unit_details.css b/content/static/css/unit_details.css
index a8cd2d7..9be5a30 100644
--- a/content/static/css/unit_details.css
+++ b/content/static/css/unit_details.css
@@ -56,7 +56,7 @@
   height: calc(100vh - 7.8475rem);
   margin-top: 1.5rem;
   position: sticky;
-  top: 4.5rem;
+  top: calc(var(--header-height) + var(--banner-height) + 1rem);
 }
 @media only screen and (min-width: 64rem) {
   .UnitDetails-outline {
diff --git a/content/static/css/unit_header.css b/content/static/css/unit_header.css
index 7594299..ca394e9 100644
--- a/content/static/css/unit_header.css
+++ b/content/static/css/unit_header.css
@@ -5,55 +5,17 @@
  */
 
 .UnitHeader {
-  border-bottom: 0.0625rem solid var(--gray-8);
-  padding-bottom: 1rem;
+  min-height: calc(var(--full-header-height));
   position: sticky;
-  top: 0;
+  top: calc(var(--breadcrumbs-height) * -1);
   white-space: nowrap;
-}
-.UnitHeader--sticky {
-  padding-bottom: 0;
-}
-.UnitHeader-outer {
-  background-color: var(--white);
-  min-height: 6.0625rem;
-  position: sticky;
-  top: -2.5rem;
   z-index: 100;
 }
-.UnitHeader-outer--main {
-  min-height: 9.5625rem;
-  top: -6rem;
-}
-.UnitHeader-outer--main.UnitHeader-outer--package {
-  min-height: 13.0625rem;
-  top: -9.5rem;
-}
-@media only screen and (min-width: 64rem) {
-  .UnitHeader-outer--main {
-    min-height: 6.0625rem;
-    top: -2.5rem;
-  }
-  .UnitHeader-outer--main.UnitHeader-outer--package {
-    min-height: 6.0625rem;
-    top: -2.5rem;
-  }
-}
-.UnitHeader-inner {
-  display: flex;
-  flex-direction: column;
-  justify-content: space-between;
-  min-height: var(--header-height);
-}
-.UnitHeader--sticky .UnitHeader-inner {
-  align-items: center;
-  flex-direction: row;
-}
 
 .UnitHeader-breadcrumbs {
   background-color: var(--white);
   line-height: 1.5rem;
-  margin-top: 1rem;
+  padding-top: 1rem;
   white-space: initial;
 }
 .UnitHeader-breadcrumbItem {
@@ -66,17 +28,21 @@
   padding: 0 0.5rem;
 }
 
-.UnitHeader,
-.UnitHeader-breadcrumbs {
-  padding-left: 1rem;
-  padding-right: 1rem;
+.UnitHeader-content {
+  background-color: var(--white);
+  border-bottom: 0.0625rem solid var(--gray-8);
 }
-@media only screen and (min-width: 57.5rem) {
-  .UnitHeader,
-  .UnitHeader-breadcrumbs {
-    padding-left: 1.5rem;
-    padding-right: 1.5rem;
-  }
+.UnitHeader-content > div {
+  display: flex;
+  flex-direction: column;
+  justify-content: space-between;
+  min-height: var(--header-height);
+  padding-bottom: 1rem;
+}
+.UnitHeader--sticky .UnitHeader-content > div {
+  align-items: center;
+  flex-direction: row;
+  padding-bottom: 0;
 }
 
 .UnitHeader-title {
@@ -132,10 +98,10 @@
     font-size: 1.5rem;
   }
 }
-.UnitHeader-inner .CopyToClipboardButton {
+.UnitHeader-content .CopyToClipboardButton {
   display: none;
 }
-.UnitHeader--sticky .UnitHeader-inner .CopyToClipboardButton {
+.UnitHeader--sticky .UnitHeader-content .CopyToClipboardButton {
   display: initial;
 }
 
@@ -180,7 +146,6 @@
   height: 1.5rem;
   position: absolute;
   right: 1rem;
-  top: 1.125rem;
   width: 1.5rem;
 }
 .UnitHeader--sticky .UnitHeader-overflowContainer {
@@ -239,14 +204,12 @@
   }
 }
 
+.UnitHeader-banners {
+  z-index: 10;
+}
 .UnitHeader-banner {
   display: flex;
-  padding: 0.75rem 1rem;
-}
-@media only screen and (min-width: 57.7rem) {
-  .UnitHeader-banner {
-    padding: 0.75rem 1.5rem;
-  }
+  padding: 0.75rem 0;
 }
 .UnitHeader-bannerContent {
   align-items: center;
diff --git a/content/static/css/unit_outline.css b/content/static/css/unit_outline.css
index 551457d..b977381 100644
--- a/content/static/css/unit_outline.css
+++ b/content/static/css/unit_outline.css
@@ -15,7 +15,7 @@
   flex-direction: column;
   max-height: 100%;
   position: sticky;
-  top: 4.5rem;
+  top: calc(var(--header-height) + var(--banner-height) + 1rem);
 }
 .UnitOutline-jumpTo {
   display: flex;
diff --git a/content/static/html/helpers/_unit_header.tmpl b/content/static/html/helpers/_unit_header.tmpl
index 5f3282b..38fbe4e 100644
--- a/content/static/html/helpers/_unit_header.tmpl
+++ b/content/static/html/helpers/_unit_header.tmpl
@@ -7,44 +7,12 @@
 {{/* . is internal/frontend.UnitPage */}}
 
 {{define "unit_header"}}
-  {{template "unit_header_breadcrumbs" .}}
-  <div class="js-headerSentinel"></div>
-  <div class="UnitHeader-outer
-      {{if .Unit.IsPackage}} UnitHeader-outer--package{{end}}
-      {{if eq .SelectedTab.Name ""}} UnitHeader-outer--main{{end}}">
-    <header class="UnitHeader UnitHeader--full js-unitHeader" role="complementary"
-      aria-label="{{if eq .PageType "std"}}module{{else}}{{.PageType}}{{end}} {{.Title}} information">
-      <div class="Site-margin UnitHeader-inner">
-        {{template "unit_header_title" .}}
-        {{with .Breadcrumb}}
-          {{if .CopyData}}
-            <button class="CopyToClipboardButton js-copyToClipboard"
-                title="Copy path to clipboard.&#10;&#10;{{.CopyData}}"
-                data-to-copy="{{.CopyData}}"
-                tabindex="-1">
-              <img class="CopyToClipboardButton-image" src="/static/img/copy-click.svg" alt="">
-            </button>
-          {{end}}
-        {{end}}
-        <div style="flex-grow: 1;"></div>
-        <div class="UnitHeader-details">
-          {{if (eq .SelectedTab.Name "")}}
-            {{template "detail_item_version" .}}
-            {{template "detail_item_commit_time" .}}
-            {{template "detail_item_licenses" .}}
-            {{if .Unit.IsPackage}}
-              {{template "detail_item_imports" .}}
-              {{template "detail_item_importedby" .}}
-            {{end}}
-          {{else}}
-            {{template "detail_page_nav" .}}
-          {{end}}
-        </div>
-        {{template "detail_items_overflow" .}}
-      </div>
-    </header>
-  </div>
-  {{template "unit_header_banners" .}}
+  <header class="js-unitHeader UnitHeader{{if eq .SelectedTab.Name ""}} UnitHeader--full UnitHeader--main{{if .Unit.IsPackage}}--package{{end}}{{end}}" aria-label="{{if eq .PageType "std"}}module{{else}}{{.PageType}}{{end}} {{.Title}} information" role="complementary">
+    <div class="js-headerSentinel"></div>
+    {{template "unit_header_banners" .}}
+    {{template "unit_header_breadcrumbs" .}}
+    {{template "unit_header_content" .}}
+  </header>
 {{end}}
 
 {{define "unit_header_breadcrumbs"}}
@@ -71,6 +39,39 @@
   </div>
 {{end}}
 
+{{define "unit_header_content"}}
+  <div class="UnitHeader-content">
+    <div class="Site-margin">
+      {{template "unit_header_title" .}}
+      {{with .Breadcrumb}}
+        {{if .CopyData}}
+          <button class="CopyToClipboardButton js-copyToClipboard"
+              title="Copy path to clipboard.&#10;&#10;{{.CopyData}}"
+              data-to-copy="{{.CopyData}}"
+              tabindex="-1">
+            <img class="CopyToClipboardButton-image" src="/static/img/copy-click.svg" alt="">
+          </button>
+        {{end}}
+      {{end}}
+      <div style="flex-grow: 1;"></div>
+      <div class="UnitHeader-details">
+        {{if (eq .SelectedTab.Name "")}}
+          {{template "detail_item_version" .}}
+          {{template "detail_item_commit_time" .}}
+          {{template "detail_item_licenses" .}}
+          {{if .Unit.IsPackage}}
+            {{template "detail_item_imports" .}}
+            {{template "detail_item_importedby" .}}
+          {{end}}
+        {{else}}
+          {{template "detail_page_nav" .}}
+        {{end}}
+      </div>
+      {{template "detail_items_overflow" .}}
+    </div>
+  </div>
+{{end}}
+
 {{define "unit_header_title"}}
   <div class="UnitHeader-title">
     <div class="UnitHeader-logo">
@@ -191,48 +192,50 @@
 {{end}}
 
 {{define "unit_header_banners"}}
-  {{with .RedirectedFromPath}}
-    <div class="UnitHeader-banner UnitHeader-banner--redirected">
-      <span class="Site-margin UnitHeader-bannerContent">
-        <img height="19px" width="16px" class="UnitHeader-banner-icon" src="/static/img/pkg-icon-info_19x16.svg" alt="">
-        <span>
-        Redirected from <span data-test-id="redirected-banner-text">{{.}}</span>.
-        </span>
-      </span>
-    </div>
-  {{end}}
-  {{if (.Experiments.IsActive "retractions")}}
-    {{if .Unit.Deprecated}}
-      <div class="UnitHeader-banner UnitHeader-banner--deprecated">
+  <div class="UnitHeader-banners">
+    {{with .RedirectedFromPath}}
+      <div class="UnitHeader-banner UnitHeader-banner--redirected">
         <span class="Site-margin UnitHeader-bannerContent">
-          <strong>Deprecated</strong>
-          {{with .Unit.DeprecationComment}}
-            <strong>:</strong>&nbsp;{{.}}
-          {{end}}
+          <img height="19px" width="16px" class="UnitHeader-banner-icon" src="/static/img/pkg-icon-info_19x16.svg" alt="">
+          <span>
+          Redirected from <span data-test-id="redirected-banner-text">{{.}}</span>.
+          </span>
         </span>
       </div>
     {{end}}
-    {{if .Unit.Retracted}}
-      <div class="UnitHeader-banner UnitHeader-banner--retracted">
+    {{if (.Experiments.IsActive "retractions")}}
+      {{if .Unit.Deprecated}}
+        <div class="UnitHeader-banner UnitHeader-banner--deprecated">
+          <span class="Site-margin UnitHeader-bannerContent">
+            <strong>Deprecated</strong>
+            {{with .Unit.DeprecationComment}}
+              <strong>:</strong>&nbsp;{{.}}
+            {{end}}
+          </span>
+        </div>
+      {{end}}
+      {{if .Unit.Retracted}}
+        <div class="UnitHeader-banner UnitHeader-banner--retracted">
+          <span class="Site-margin UnitHeader-bannerContent">
+            <strong>Retracted</strong>
+              {{with .Unit.RetractionRationale}}
+              <strong>:</strong>&nbsp;{{.}}
+            {{end}}
+          </span>
+        </div>
+      {{end}}
+    {{end}}
+    {{if .LatestMajorVersion}}
+      <div class="UnitHeader-banner UnitHeader-banner--majorVersion" data-test-id="UnitHeader-majorVersionBanner">
         <span class="Site-margin UnitHeader-bannerContent">
-          <strong>Retracted</strong>
-            {{with .Unit.RetractionRationale}}
-            <strong>:</strong> {{.}}
-          {{end}}
+          <img height="19px" width="16px" class="UnitHeader-banner-icon" src="/static/img/pkg-icon-info_19x16.svg" alt="">
+          <span>
+            The highest tagged major version is <a href="/{{.LatestMajorVersionURL}}">{{.LatestMajorVersion}}</a>.
+          </span>
         </span>
       </div>
     {{end}}
-  {{end}}
-  {{if .LatestMajorVersion}}
-    <div class="UnitHeader-banner UnitHeader-banner--majorVersion" data-test-id="UnitHeader-majorVersionBanner">
-      <span class="Site-margin UnitHeader-bannerContent">
-        <img height="19px" width="16px" class="UnitHeader-banner-icon" src="/static/img/pkg-icon-info_19x16.svg" alt="">
-        <span>
-          The highest tagged major version is <a href="/{{.LatestMajorVersionURL}}">{{.LatestMajorVersion}}</a>.
-        </span>
-      </span>
-    </div>
-  {{end}}
+  </div>
 {{end}}
 
 {{define "severity_toggletip"}}
diff --git a/content/static/js/unit.js b/content/static/js/unit.js
index 72af9b3..c31c690 100644
--- a/content/static/js/unit.js
+++ b/content/static/js/unit.js
@@ -3,5 +3,5 @@
  * Copyright 2021 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.
- */import{CopyToClipboardController as m}from"./clipboard.js";import"./toggle-tip.js";import{ExpandableRowsTableController as u}from"./table.js";document.querySelectorAll(".js-expandableTable").forEach(e=>new u(e,document.querySelector(".js-expandAllDirectories"))),document.querySelectorAll(".js-copyToClipboard").forEach(e=>{new m(e)});const t=document.querySelector(".js-readme"),o=document.querySelector(".js-readmeContent"),s=document.querySelector(".js-readmeOutline"),d=document.querySelectorAll(".js-readmeExpand"),a=document.querySelector(".js-readmeCollapse");t&&o&&s&&d.length&&a&&(window.location.hash.includes("readme")&&t.classList.add("UnitReadme--expanded"),d.forEach(e=>e.addEventListener("click",r=>{r.preventDefault(),t.classList.add("UnitReadme--expanded"),t.scrollIntoView()})),a.addEventListener("click",e=>{e.preventDefault(),t.classList.remove("UnitReadme--expanded"),d[1]&&d[1].scrollIntoView({block:"center"})}),o.addEventListener("keyup",()=>{t.classList.add("UnitReadme--expanded")}),o.addEventListener("click",()=>{t.classList.add("UnitReadme--expanded")}),s.addEventListener("click",()=>{t.classList.add("UnitReadme--expanded")}),document.addEventListener("keydown",e=>{(e.ctrlKey||e.metaKey)&&e.key==="f"&&t.classList.add("UnitReadme--expanded")}));const i=document.querySelector(".js-readmeOption");i&&!t&&i.setAttribute("disabled","true");const p=document.querySelector(".js-unitDirectories"),l=document.querySelector(".js-directoriesOption");!p&&l&&l.setAttribute("disabled","true"),document.querySelectorAll(".js-buildContextSelect").forEach(e=>{e.addEventListener("change",r=>{window.location.search=`?GOOS=${r.target.value}`})});const n=document.querySelector(".js-unitHeader");n?.addEventListener("dblclick",e=>{e.target===n.firstElementChild&&n.classList.contains("UnitHeader--sticky")&&(window.getSelection()?.removeAllRanges(),window.scrollTo({top:0}))});const L=new IntersectionObserver(([e])=>{e.intersectionRatio<1?(n?.classList.add("UnitHeader--sticky"),n?.classList.remove("UnitHeader--full")):(n?.classList.remove("UnitHeader--sticky"),n?.classList.add("UnitHeader--full"))},{threshold:1,rootMargin:"-20px"}),c=document.querySelector(".js-headerSentinel");c&&L.observe(c);
+ */import{CopyToClipboardController as p}from"./clipboard.js";import"./toggle-tip.js";import{ExpandableRowsTableController as y}from"./table.js";document.querySelectorAll(".js-expandableTable").forEach(e=>new y(e,document.querySelector(".js-expandAllDirectories"))),document.querySelectorAll(".js-copyToClipboard").forEach(e=>{new p(e)});const t=document.querySelector(".js-readme"),d=document.querySelector(".js-readmeContent"),l=document.querySelector(".js-readmeOutline"),o=document.querySelectorAll(".js-readmeExpand"),s=document.querySelector(".js-readmeCollapse");t&&d&&l&&o.length&&s&&(window.location.hash.includes("readme")&&t.classList.add("UnitReadme--expanded"),o.forEach(e=>e.addEventListener("click",r=>{r.preventDefault(),t.classList.add("UnitReadme--expanded"),t.scrollIntoView()})),s.addEventListener("click",e=>{e.preventDefault(),t.classList.remove("UnitReadme--expanded"),o[1]&&o[1].scrollIntoView({block:"center"})}),d.addEventListener("keyup",()=>{t.classList.add("UnitReadme--expanded")}),d.addEventListener("click",()=>{t.classList.add("UnitReadme--expanded")}),l.addEventListener("click",()=>{t.classList.add("UnitReadme--expanded")}),document.addEventListener("keydown",e=>{(e.ctrlKey||e.metaKey)&&e.key==="f"&&t.classList.add("UnitReadme--expanded")}));const i=document.querySelector(".js-readmeOption");i&&!t&&i.setAttribute("disabled","true");const h=document.querySelector(".js-unitDirectories"),a=document.querySelector(".js-directoriesOption");!h&&a&&a.setAttribute("disabled","true"),document.querySelectorAll(".js-buildContextSelect").forEach(e=>{e.addEventListener("change",r=>{window.location.search=`?GOOS=${r.target.value}`})});const n=document.querySelector(".js-unitHeader");n?.addEventListener("dblclick",e=>{e.target===n.firstElementChild&&n.classList.contains("UnitHeader--sticky")&&(window.getSelection()?.removeAllRanges(),window.scrollTo({top:0}))});const c=document.querySelector(".UnitHeader"),E=c?.querySelector(".UnitHeader-breadcrumbs"),L=c?.querySelector(".UnitHeader-content"),m=()=>{document.documentElement.style.removeProperty("--full-header-height"),document.documentElement.style.setProperty("--full-header-height",`${(c?.getBoundingClientRect().height??0)/16}rem`),document.documentElement.style.setProperty("--banner-height","0rem"),document.documentElement.style.setProperty("--breadcrumbs-height",`${(E?.getBoundingClientRect().height??0)/16}rem`),document.documentElement.style.setProperty("--content-height",`${(L?.getBoundingClientRect().height??0)/16}rem`)};m(),window.addEventListener("resize",function(){m()});const b=new IntersectionObserver(([e])=>{e.intersectionRatio<1?(n?.classList.add("UnitHeader--sticky"),n?.classList.remove("UnitHeader--full")):(n?.classList.remove("UnitHeader--sticky"),n?.classList.add("UnitHeader--full"))},{threshold:1,rootMargin:"-20px"}),u=document.querySelector(".js-headerSentinel");u&&b.observe(u);
 //# sourceMappingURL=unit.js.map
diff --git a/content/static/js/unit.js.map b/content/static/js/unit.js.map
index a6d7217..5cb6150 100644
--- a/content/static/js/unit.js.map
+++ b/content/static/js/unit.js.map
@@ -1,7 +1,7 @@
 {
   "version": 3,
   "sources": ["unit.ts"],
-  "sourcesContent": ["/*!\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { CopyToClipboardController } from './clipboard.js';\nimport './toggle-tip.js';\nimport { ExpandableRowsTableController } from './table.js';\n\ndocument\n  .querySelectorAll<HTMLTableElement>('.js-expandableTable')\n  .forEach(\n    el =>\n      new ExpandableRowsTableController(\n        el,\n        document.querySelector<HTMLButtonElement>('.js-expandAllDirectories')\n      )\n  );\n\n/**\n * Instantiates CopyToClipboardController controller copy buttons\n * on the unit page.\n */\ndocument.querySelectorAll<HTMLButtonElement>('.js-copyToClipboard').forEach(el => {\n  new CopyToClipboardController(el);\n});\n\n/**\n * Event handlers for expanding and collapsing the readme section.\n */\nconst readme = document.querySelector('.js-readme');\nconst readmeContent = document.querySelector('.js-readmeContent');\nconst readmeOutline = document.querySelector('.js-readmeOutline');\nconst readmeExpand = document.querySelectorAll('.js-readmeExpand');\nconst readmeCollapse = document.querySelector('.js-readmeCollapse');\nif (readme && readmeContent && readmeOutline && readmeExpand.length && readmeCollapse) {\n  if (window.location.hash.includes('readme')) {\n    readme.classList.add('UnitReadme--expanded');\n  }\n  readmeExpand.forEach(el =>\n    el.addEventListener('click', e => {\n      e.preventDefault();\n      readme.classList.add('UnitReadme--expanded');\n      readme.scrollIntoView();\n    })\n  );\n  readmeCollapse.addEventListener('click', e => {\n    e.preventDefault();\n    readme.classList.remove('UnitReadme--expanded');\n    if (readmeExpand[1]) {\n      readmeExpand[1].scrollIntoView({ block: 'center' });\n    }\n  });\n  readmeContent.addEventListener('keyup', () => {\n    readme.classList.add('UnitReadme--expanded');\n  });\n  readmeContent.addEventListener('click', () => {\n    readme.classList.add('UnitReadme--expanded');\n  });\n  readmeOutline.addEventListener('click', () => {\n    readme.classList.add('UnitReadme--expanded');\n  });\n  document.addEventListener('keydown', e => {\n    if ((e.ctrlKey || e.metaKey) && e.key === 'f') {\n      readme.classList.add('UnitReadme--expanded');\n    }\n  });\n}\n\n/**\n * Disable unavailable sections in navigation dropdown on mobile.\n */\nconst readmeOption = document.querySelector('.js-readmeOption');\nif (readmeOption && !readme) {\n  readmeOption.setAttribute('disabled', 'true');\n}\nconst unitDirectories = document.querySelector('.js-unitDirectories');\nconst directoriesOption = document.querySelector('.js-directoriesOption');\nif (!unitDirectories && directoriesOption) {\n  directoriesOption.setAttribute('disabled', 'true');\n}\ndocument.querySelectorAll('.js-buildContextSelect').forEach(el => {\n  el.addEventListener('change', e => {\n    window.location.search = `?GOOS=${(e.target as HTMLSelectElement).value}`;\n  });\n});\n\nconst unitHeader = document.querySelector('.js-unitHeader');\nunitHeader?.addEventListener('dblclick', e => {\n  const target = e.target as HTMLElement;\n  if (\n    target === unitHeader.firstElementChild &&\n    unitHeader.classList.contains('UnitHeader--sticky')\n  ) {\n    window.getSelection()?.removeAllRanges();\n    window.scrollTo({ top: 0 });\n  }\n});\nconst observer = new IntersectionObserver(\n  ([e]) => {\n    if (e.intersectionRatio < 1) {\n      unitHeader?.classList.add('UnitHeader--sticky');\n      unitHeader?.classList.remove('UnitHeader--full');\n    } else {\n      unitHeader?.classList.remove('UnitHeader--sticky');\n      unitHeader?.classList.add('UnitHeader--full');\n    }\n  },\n  { threshold: 1.0, rootMargin: '-20px' }\n);\n\nconst headerSentinel = document.querySelector('.js-headerSentinel');\nif (headerSentinel) {\n  observer.observe(headerSentinel);\n}\n"],
-  "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAOA,2DACA,wBACA,2DAEA,SACG,iBAAmC,uBACnC,QACC,GACE,GAAI,GACF,EACA,SAAS,cAAiC,8BAQlD,SAAS,iBAAoC,uBAAuB,QAAQ,GAAM,CAChF,GAAI,GAA0B,KAMhC,KAAM,GAAS,SAAS,cAAc,cAChC,EAAgB,SAAS,cAAc,qBACvC,EAAgB,SAAS,cAAc,qBACvC,EAAe,SAAS,iBAAiB,oBACzC,EAAiB,SAAS,cAAc,sBAC9C,AAAI,GAAU,GAAiB,GAAiB,EAAa,QAAU,GACjE,QAAO,SAAS,KAAK,SAAS,WAChC,EAAO,UAAU,IAAI,wBAEvB,EAAa,QAAQ,GACnB,EAAG,iBAAiB,QAAS,GAAK,CAChC,EAAE,iBACF,EAAO,UAAU,IAAI,wBACrB,EAAO,oBAGX,EAAe,iBAAiB,QAAS,GAAK,CAC5C,EAAE,iBACF,EAAO,UAAU,OAAO,wBACpB,EAAa,IACf,EAAa,GAAG,eAAe,CAAE,MAAO,aAG5C,EAAc,iBAAiB,QAAS,IAAM,CAC5C,EAAO,UAAU,IAAI,0BAEvB,EAAc,iBAAiB,QAAS,IAAM,CAC5C,EAAO,UAAU,IAAI,0BAEvB,EAAc,iBAAiB,QAAS,IAAM,CAC5C,EAAO,UAAU,IAAI,0BAEvB,SAAS,iBAAiB,UAAW,GAAK,CACxC,AAAK,GAAE,SAAW,EAAE,UAAY,EAAE,MAAQ,KACxC,EAAO,UAAU,IAAI,2BAQ3B,KAAM,GAAe,SAAS,cAAc,oBAC5C,AAAI,GAAgB,CAAC,GACnB,EAAa,aAAa,WAAY,QAExC,KAAM,GAAkB,SAAS,cAAc,uBACzC,EAAoB,SAAS,cAAc,yBACjD,AAAI,CAAC,GAAmB,GACtB,EAAkB,aAAa,WAAY,QAE7C,SAAS,iBAAiB,0BAA0B,QAAQ,GAAM,CAChE,EAAG,iBAAiB,SAAU,GAAK,CACjC,OAAO,SAAS,OAAS,SAAU,EAAE,OAA6B,YAItE,KAAM,GAAa,SAAS,cAAc,kBAC1C,GAAY,iBAAiB,WAAY,GAAK,CAE5C,AACE,AAFa,EAAE,SAEJ,EAAW,mBACtB,EAAW,UAAU,SAAS,uBAE9B,QAAO,gBAAgB,kBACvB,OAAO,SAAS,CAAE,IAAK,OAG3B,KAAM,GAAW,GAAI,sBACnB,CAAC,CAAC,KAAO,CACP,AAAI,EAAE,kBAAoB,EACxB,IAAY,UAAU,IAAI,sBAC1B,GAAY,UAAU,OAAO,qBAE7B,IAAY,UAAU,OAAO,sBAC7B,GAAY,UAAU,IAAI,sBAG9B,CAAE,UAAW,EAAK,WAAY,UAG1B,EAAiB,SAAS,cAAc,sBAC9C,AAAI,GACF,EAAS,QAAQ",
+  "sourcesContent": ["/*!\n * @license\n * Copyright 2021 The Go Authors. All rights reserved.\n * Use of this source code is governed by a BSD-style\n * license that can be found in the LICENSE file.\n */\n\nimport { CopyToClipboardController } from './clipboard.js';\nimport './toggle-tip.js';\nimport { ExpandableRowsTableController } from './table.js';\n\ndocument\n  .querySelectorAll<HTMLTableElement>('.js-expandableTable')\n  .forEach(\n    el =>\n      new ExpandableRowsTableController(\n        el,\n        document.querySelector<HTMLButtonElement>('.js-expandAllDirectories')\n      )\n  );\n\n/**\n * Instantiates CopyToClipboardController controller copy buttons\n * on the unit page.\n */\ndocument.querySelectorAll<HTMLButtonElement>('.js-copyToClipboard').forEach(el => {\n  new CopyToClipboardController(el);\n});\n\n/**\n * Event handlers for expanding and collapsing the readme section.\n */\nconst readme = document.querySelector('.js-readme');\nconst readmeContent = document.querySelector('.js-readmeContent');\nconst readmeOutline = document.querySelector('.js-readmeOutline');\nconst readmeExpand = document.querySelectorAll('.js-readmeExpand');\nconst readmeCollapse = document.querySelector('.js-readmeCollapse');\nif (readme && readmeContent && readmeOutline && readmeExpand.length && readmeCollapse) {\n  if (window.location.hash.includes('readme')) {\n    readme.classList.add('UnitReadme--expanded');\n  }\n  readmeExpand.forEach(el =>\n    el.addEventListener('click', e => {\n      e.preventDefault();\n      readme.classList.add('UnitReadme--expanded');\n      readme.scrollIntoView();\n    })\n  );\n  readmeCollapse.addEventListener('click', e => {\n    e.preventDefault();\n    readme.classList.remove('UnitReadme--expanded');\n    if (readmeExpand[1]) {\n      readmeExpand[1].scrollIntoView({ block: 'center' });\n    }\n  });\n  readmeContent.addEventListener('keyup', () => {\n    readme.classList.add('UnitReadme--expanded');\n  });\n  readmeContent.addEventListener('click', () => {\n    readme.classList.add('UnitReadme--expanded');\n  });\n  readmeOutline.addEventListener('click', () => {\n    readme.classList.add('UnitReadme--expanded');\n  });\n  document.addEventListener('keydown', e => {\n    if ((e.ctrlKey || e.metaKey) && e.key === 'f') {\n      readme.classList.add('UnitReadme--expanded');\n    }\n  });\n}\n\n/**\n * Disable unavailable sections in navigation dropdown on mobile.\n */\nconst readmeOption = document.querySelector('.js-readmeOption');\nif (readmeOption && !readme) {\n  readmeOption.setAttribute('disabled', 'true');\n}\nconst unitDirectories = document.querySelector('.js-unitDirectories');\nconst directoriesOption = document.querySelector('.js-directoriesOption');\nif (!unitDirectories && directoriesOption) {\n  directoriesOption.setAttribute('disabled', 'true');\n}\ndocument.querySelectorAll('.js-buildContextSelect').forEach(el => {\n  el.addEventListener('change', e => {\n    window.location.search = `?GOOS=${(e.target as HTMLSelectElement).value}`;\n  });\n});\n\n/**\n * Adds double click event listener to the header that will\n * scroll the page back to the top.\n */\nconst unitHeader = document.querySelector('.js-unitHeader');\nunitHeader?.addEventListener('dblclick', e => {\n  const target = e.target as HTMLElement;\n  if (\n    target === unitHeader.firstElementChild &&\n    unitHeader.classList.contains('UnitHeader--sticky')\n  ) {\n    window.getSelection()?.removeAllRanges();\n    window.scrollTo({ top: 0 });\n  }\n});\n\n/**\n * Calculates dynamic heights values for header elements to support\n * variable size sticky positioned elements in the header so that banners\n * and breadcumbs may overflow to multiple lines.\n */\nconst header = document.querySelector<HTMLElement>('.UnitHeader');\nconst breadcrumbs = header?.querySelector<HTMLElement>('.UnitHeader-breadcrumbs');\nconst content = header?.querySelector<HTMLElement>('.UnitHeader-content');\nconst calcSize = () => {\n  document.documentElement.style.removeProperty('--full-header-height');\n  document.documentElement.style.setProperty(\n    '--full-header-height',\n    `${(header?.getBoundingClientRect().height ?? 0) / 16}rem`\n  );\n  document.documentElement.style.setProperty('--banner-height', `0rem`);\n  document.documentElement.style.setProperty(\n    '--breadcrumbs-height',\n    `${(breadcrumbs?.getBoundingClientRect().height ?? 0) / 16}rem`\n  );\n  document.documentElement.style.setProperty(\n    '--content-height',\n    `${(content?.getBoundingClientRect().height ?? 0) / 16}rem`\n  );\n};\ncalcSize();\nwindow.addEventListener('resize', function () {\n  calcSize();\n});\n\n/**\n * Observer for header that applies classnames to transition\n * header elements into their sticky position and back into the\n * full size position.\n */\nconst observer = new IntersectionObserver(\n  ([e]) => {\n    if (e.intersectionRatio < 1) {\n      unitHeader?.classList.add('UnitHeader--sticky');\n      unitHeader?.classList.remove('UnitHeader--full');\n    } else {\n      unitHeader?.classList.remove('UnitHeader--sticky');\n      unitHeader?.classList.add('UnitHeader--full');\n    }\n  },\n  { threshold: 1.0, rootMargin: '-20px' }\n);\n\nconst headerSentinel = document.querySelector('.js-headerSentinel');\nif (headerSentinel) {\n  observer.observe(headerSentinel);\n}\n"],
+  "mappings": "AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,GAOA,2DACA,wBACA,2DAEA,SACG,iBAAmC,uBACnC,QACC,GACE,GAAI,GACF,EACA,SAAS,cAAiC,8BAQlD,SAAS,iBAAoC,uBAAuB,QAAQ,GAAM,CAChF,GAAI,GAA0B,KAMhC,KAAM,GAAS,SAAS,cAAc,cAChC,EAAgB,SAAS,cAAc,qBACvC,EAAgB,SAAS,cAAc,qBACvC,EAAe,SAAS,iBAAiB,oBACzC,EAAiB,SAAS,cAAc,sBAC9C,AAAI,GAAU,GAAiB,GAAiB,EAAa,QAAU,GACjE,QAAO,SAAS,KAAK,SAAS,WAChC,EAAO,UAAU,IAAI,wBAEvB,EAAa,QAAQ,GACnB,EAAG,iBAAiB,QAAS,GAAK,CAChC,EAAE,iBACF,EAAO,UAAU,IAAI,wBACrB,EAAO,oBAGX,EAAe,iBAAiB,QAAS,GAAK,CAC5C,EAAE,iBACF,EAAO,UAAU,OAAO,wBACpB,EAAa,IACf,EAAa,GAAG,eAAe,CAAE,MAAO,aAG5C,EAAc,iBAAiB,QAAS,IAAM,CAC5C,EAAO,UAAU,IAAI,0BAEvB,EAAc,iBAAiB,QAAS,IAAM,CAC5C,EAAO,UAAU,IAAI,0BAEvB,EAAc,iBAAiB,QAAS,IAAM,CAC5C,EAAO,UAAU,IAAI,0BAEvB,SAAS,iBAAiB,UAAW,GAAK,CACxC,AAAK,GAAE,SAAW,EAAE,UAAY,EAAE,MAAQ,KACxC,EAAO,UAAU,IAAI,2BAQ3B,KAAM,GAAe,SAAS,cAAc,oBAC5C,AAAI,GAAgB,CAAC,GACnB,EAAa,aAAa,WAAY,QAExC,KAAM,GAAkB,SAAS,cAAc,uBACzC,EAAoB,SAAS,cAAc,yBACjD,AAAI,CAAC,GAAmB,GACtB,EAAkB,aAAa,WAAY,QAE7C,SAAS,iBAAiB,0BAA0B,QAAQ,GAAM,CAChE,EAAG,iBAAiB,SAAU,GAAK,CACjC,OAAO,SAAS,OAAS,SAAU,EAAE,OAA6B,YAQtE,KAAM,GAAa,SAAS,cAAc,kBAC1C,GAAY,iBAAiB,WAAY,GAAK,CAE5C,AACE,AAFa,EAAE,SAEJ,EAAW,mBACtB,EAAW,UAAU,SAAS,uBAE9B,QAAO,gBAAgB,kBACvB,OAAO,SAAS,CAAE,IAAK,OAS3B,KAAM,GAAS,SAAS,cAA2B,eAC7C,EAAc,GAAQ,cAA2B,2BACjD,EAAU,GAAQ,cAA2B,uBAC7C,EAAW,IAAM,CACrB,SAAS,gBAAgB,MAAM,eAAe,wBAC9C,SAAS,gBAAgB,MAAM,YAC7B,uBACA,GAAI,IAAQ,wBAAwB,QAAU,GAAK,SAErD,SAAS,gBAAgB,MAAM,YAAY,kBAAmB,QAC9D,SAAS,gBAAgB,MAAM,YAC7B,uBACA,GAAI,IAAa,wBAAwB,QAAU,GAAK,SAE1D,SAAS,gBAAgB,MAAM,YAC7B,mBACA,GAAI,IAAS,wBAAwB,QAAU,GAAK,UAGxD,IACA,OAAO,iBAAiB,SAAU,UAAY,CAC5C,MAQF,KAAM,GAAW,GAAI,sBACnB,CAAC,CAAC,KAAO,CACP,AAAI,EAAE,kBAAoB,EACxB,IAAY,UAAU,IAAI,sBAC1B,GAAY,UAAU,OAAO,qBAE7B,IAAY,UAAU,OAAO,sBAC7B,GAAY,UAAU,IAAI,sBAG9B,CAAE,UAAW,EAAK,WAAY,UAG1B,EAAiB,SAAS,cAAc,sBAC9C,AAAI,GACF,EAAS,QAAQ",
   "names": []
 }
diff --git a/content/static/js/unit.ts b/content/static/js/unit.ts
index 6b7beca..fee5e91 100644
--- a/content/static/js/unit.ts
+++ b/content/static/js/unit.ts
@@ -87,6 +87,10 @@
   });
 });
 
+/**
+ * Adds double click event listener to the header that will
+ * scroll the page back to the top.
+ */
 const unitHeader = document.querySelector('.js-unitHeader');
 unitHeader?.addEventListener('dblclick', e => {
   const target = e.target as HTMLElement;
@@ -98,6 +102,41 @@
     window.scrollTo({ top: 0 });
   }
 });
+
+/**
+ * Calculates dynamic heights values for header elements to support
+ * variable size sticky positioned elements in the header so that banners
+ * and breadcumbs may overflow to multiple lines.
+ */
+const header = document.querySelector<HTMLElement>('.UnitHeader');
+const breadcrumbs = header?.querySelector<HTMLElement>('.UnitHeader-breadcrumbs');
+const content = header?.querySelector<HTMLElement>('.UnitHeader-content');
+const calcSize = () => {
+  document.documentElement.style.removeProperty('--full-header-height');
+  document.documentElement.style.setProperty(
+    '--full-header-height',
+    `${(header?.getBoundingClientRect().height ?? 0) / 16}rem`
+  );
+  document.documentElement.style.setProperty('--banner-height', `0rem`);
+  document.documentElement.style.setProperty(
+    '--breadcrumbs-height',
+    `${(breadcrumbs?.getBoundingClientRect().height ?? 0) / 16}rem`
+  );
+  document.documentElement.style.setProperty(
+    '--content-height',
+    `${(content?.getBoundingClientRect().height ?? 0) / 16}rem`
+  );
+};
+calcSize();
+window.addEventListener('resize', function () {
+  calcSize();
+});
+
+/**
+ * Observer for header that applies classnames to transition
+ * header elements into their sticky position and back into the
+ * full size position.
+ */
 const observer = new IntersectionObserver(
   ([e]) => {
     if (e.intersectionRatio < 1) {