Repository: tidalmigrations/tidalmigrations.github.io
Pull request #285: improve look and feel of documentation
Author: login: dcolebatch
Created: 2025-05-06T23:41:47Z | Merged: 2025-05-08T17:20:34Z

Using CoPilot Agent mode, and various models as well as some elbow grease, this PR updates the plumbing and styling:

* Updated github pages stack
* Updated Dockerfile
* Tweaks to styling (fonts, spacing, some colour)
* Darkmode :godmode: 

<img width="1534" alt="image" src="https://github.com/user-attachments/assets/20086701-00e4-46ae-8c9e-08e1824e4797" />



Diff:
diff --git a/Dockerfile b/Dockerfile
index 0998d0e0..733291a1 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -1,4 +1,4 @@
-FROM ruby:2.1
+FROM ruby:3.3.4
 MAINTAINER mrafayaleem@gmail.com
 
 RUN apt-get clean \
@@ -8,18 +8,21 @@ RUN apt-get clean \
 RUN apt-get update
 
 RUN apt-get install -y \
-    node \
-    python-pygments \
+    nodejs \
+    python3-pygments \
+    build-essential \
+    libxml2-dev \
+    libxslt-dev \
   && apt-get clean \
   && rm -rf /var/lib/apt/lists/
 
 WORKDIR /tmp
 ADD Gemfile /tmp/
 ADD Gemfile.lock /tmp/
-RUN bundle install
+RUN gem install bundler && bundle install
 
 VOLUME /src
 EXPOSE 4000
 
 WORKDIR /src
-ENTRYPOINT ["jekyll", "serve", "-H", "0.0.0.0"]
\ No newline at end of file
+ENTRYPOINT ["bundle", "exec", "jekyll", "serve", "-H", "0.0.0.0"]
\ No newline at end of file
diff --git a/Gemfile b/Gemfile
index e3b9b9ab..aa272416 100644
--- a/Gemfile
+++ b/Gemfile
@@ -1,8 +1,17 @@
 source "https://rubygems.org"
 
+# Pinning problematic gems to compatible versions
+gem "commonmarker", "~> 0.23.8"
+gem "unf_ext", "~> 0.0.7.7"
+gem "eventmachine", "~> 1.2.5"
+gem "http_parser.rb", "~> 0.6.0"
+gem "racc", "~> 1.5.2"
+
 group :jekyll_plugins do
-  gem 'github-pages'
+  gem 'github-pages', '~> 232'
   gem 'jekyll-feed'
   gem 'jekyll-redirect-from'
   gem 'jekyll-sitemap'
 end
+
+
diff --git a/Gemfile.lock b/Gemfile.lock
index dfe596b9..29487b5d 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -11,10 +11,11 @@ GEM
     coffee-script (2.4.1)
       coffee-script-source
       execjs
-    coffee-script-source (1.11.1)
+    coffee-script-source (1.12.2)
     colorator (1.1.0)
     commonmarker (0.23.10)
     concurrent-ruby (1.2.2)
+    csv (3.3.4)
     dnsruby (1.61.9)
       simpleidn (~> 0.1)
     em-websocket (0.5.3)
@@ -31,16 +32,16 @@ GEM
     ffi (1.15.5)
     forwardable-extended (2.6.0)
     gemoji (3.0.1)
-    github-pages (228)
-      github-pages-health-check (= 1.17.9)
-      jekyll (= 3.9.3)
-      jekyll-avatar (= 0.7.0)
-      jekyll-coffeescript (= 1.1.1)
-      jekyll-commonmark-ghpages (= 0.4.0)
-      jekyll-default-layout (= 0.1.4)
-      jekyll-feed (= 0.15.1)
+    github-pages (232)
+      github-pages-health-check (= 1.18.2)
+      jekyll (= 3.10.0)
+      jekyll-avatar (= 0.8.0)
+      jekyll-coffeescript (= 1.2.2)
+      jekyll-commonmark-ghpages (= 0.5.1)
+      jekyll-default-layout (= 0.1.5)
+      jekyll-feed (= 0.17.0)
       jekyll-gist (= 1.5.0)
-      jekyll-github-metadata (= 2.13.0)
+      jekyll-github-metadata (= 2.16.1)
       jekyll-include-cache (= 0.2.1)
       jekyll-mentions (= 1.6.0)
       jekyll-optional-front-matter (= 0.3.2)
@@ -67,30 +68,32 @@ GEM
       jekyll-theme-tactile (= 0.2.0)
       jekyll-theme-time-machine (= 0.2.0)
       jekyll-titles-from-headings (= 0.5.3)
-      jemoji (= 0.12.0)
-      kramdown (= 2.3.2)
+      jemoji (= 0.13.0)
+      kramdown (= 2.4.0)
       kramdown-parser-gfm (= 1.1.0)
       liquid (= 4.0.4)
       mercenary (~> 0.3)
       minima (= 2.5.1)
-      nokogiri (>= 1.13.6, < 2.0)
-      rouge (= 3.26.0)
+      nokogiri (>= 1.16.2, < 2.0)
+      rouge (= 3.30.0)
       terminal-table (~> 1.4)
-    github-pages-health-check (1.17.9)
+      webrick (~> 1.8)
+    github-pages-health-check (1.18.2)
       addressable (~> 2.3)
       dnsruby (~> 1.60)
-      octokit (~> 4.0)
-      public_suffix (>= 3.0, < 5.0)
+      octokit (>= 4, < 8)
+      public_suffix (>= 3.0, < 6.0)
       typhoeus (~> 1.3)
     html-pipeline (2.14.3)
       activesupport (>= 2)
       nokogiri (>= 1.4)
-    http_parser.rb (0.8.0)
+    http_parser.rb (0.6.0)
     i18n (1.14.1)
       concurrent-ruby (~> 1.0)
-    jekyll (3.9.3)
+    jekyll (3.10.0)
       addressable (~> 2.4)
       colorator (~> 1.0)
+      csv (~> 3.0)
       em-websocket (~> 0.5)
       i18n (>= 0.7, < 2)
       jekyll-sass-converter (~> 1.0)
@@ -101,27 +104,28 @@ GEM
       pathutil (~> 0.9)
       rouge (>= 1.7, < 4)
       safe_yaml (~> 1.0)
-    jekyll-avatar (0.7.0)
+      webrick (>= 1.0)
+    jekyll-avatar (0.8.0)
       jekyll (>= 3.0, < 5.0)
-    jekyll-coffeescript (1.1.1)
+    jekyll-coffeescript (1.2.2)
       coffee-script (~> 2.2)
-      coffee-script-source (~> 1.11.1)
+      coffee-script-source (~> 1.12)
     jekyll-commonmark (1.4.0)
       commonmarker (~> 0.22)
-    jekyll-commonmark-ghpages (0.4.0)
-      commonmarker (~> 0.23.7)
-      jekyll (~> 3.9.0)
+    jekyll-commonmark-ghpages (0.5.1)
+      commonmarker (>= 0.23.7, < 1.1.0)
+      jekyll (>= 3.9, < 4.0)
       jekyll-commonmark (~> 1.4.0)
       rouge (>= 2.0, < 5.0)
-    jekyll-default-layout (0.1.4)
-      jekyll (~> 3.0)
-    jekyll-feed (0.15.1)
+    jekyll-default-layout (0.1.5)
+      jekyll (>= 3.0, < 5.0)
+    jekyll-feed (0.17.0)
       jekyll (>= 3.7, < 5.0)
     jekyll-gist (1.5.0)
       octokit (~> 4.2)
-    jekyll-github-metadata (2.13.0)
+    jekyll-github-metadata (2.16.1)
       jekyll (>= 3.4, < 5.0)
-      octokit (~> 4.0, != 4.4.0)
+      octokit (>= 4, < 7, != 4.4.0)
     jekyll-include-cache (0.2.1)
       jekyll (>= 3.7, < 5.0)
     jekyll-mentions (1.6.0)
@@ -192,11 +196,11 @@ GEM
       jekyll (>= 3.3, < 5.0)
     jekyll-watch (2.2.1)
       listen (~> 3.0)
-    jemoji (0.12.0)
-      gemoji (~> 3.0)
+    jemoji (0.13.0)
+      gemoji (>= 3, < 5)
       html-pipeline (~> 2.2)
       jekyll (>= 3.0, < 5.0)
-    kramdown (2.3.2)
+    kramdown (2.4.0)
       rexml
     kramdown-parser-gfm (1.1.0)
       kramdown (~> 2.0)
@@ -205,14 +209,14 @@ GEM
       rb-fsevent (~> 0.10, >= 0.10.3)
       rb-inotify (~> 0.9, >= 0.9.10)
     mercenary (0.3.6)
-    mini_portile2 (2.8.1)
+    mini_portile2 (2.8.8)
     minima (2.5.1)
       jekyll (>= 3.5, < 5.0)
       jekyll-feed (~> 0.9)
       jekyll-seo-tag (~> 2.1)
     minitest (5.19.0)
-    nokogiri (1.14.3)
-      mini_portile2 (~> 2.8.0)
+    nokogiri (1.18.8)
+      mini_portile2 (~> 2.8.2)
       racc (~> 1.4)
     octokit (4.25.1)
       faraday (>= 1, < 3)
@@ -220,12 +224,12 @@ GEM
     pathutil (0.16.2)
       forwardable-extended (~> 2.6)
     public_suffix (4.0.7)
-    racc (1.6.2)
+    racc (1.5.2)
     rb-fsevent (0.11.2)
     rb-inotify (0.10.1)
       ffi (~> 1.0)
-    rexml (3.2.5)
-    rouge (3.26.0)
+    rexml (3.4.1)
+    rouge (3.30.0)
     ruby2_keywords (0.0.5)
     rubyzip (2.3.2)
     safe_yaml (1.0.5)
@@ -247,17 +251,23 @@ GEM
       concurrent-ruby (~> 1.0)
     unf (0.1.4)
       unf_ext
-    unf_ext (0.0.8.2)
+    unf_ext (0.0.7.7)
     unicode-display_width (1.8.0)
+    webrick (1.9.1)
 
 PLATFORMS
   ruby
 
 DEPENDENCIES
-  github-pages
+  commonmarker (~> 0.23.8)
+  eventmachine (~> 1.2.5)
+  github-pages (~> 232)
+  http_parser.rb (~> 0.6.0)
   jekyll-feed
   jekyll-redirect-from
   jekyll-sitemap
+  racc (~> 1.5.2)
+  unf_ext (~> 0.0.7.7)
 
 BUNDLED WITH
-   1.17.3
+   2.6.8
diff --git a/_config.yml b/_config.yml
index 689c77f3..ec923a1b 100644
--- a/_config.yml
+++ b/_config.yml
@@ -3,10 +3,10 @@ repository: tomjoht/documentation-theme-jekyll
 output: web
 # this property is useful for conditional filtering of content that is separate from the PDF.
 
-topnav_title: Tidal
+topnav_title: Tidal.cloud Guides
 # this appears on the top navigation bar next to the home button
 
-site_title: Tidal
+site_title: Tidal.cloud Guides
 # this appears in the html browser tab for the site title (seen mostly by search engines, not users)
 
 company_name: Tidal SW Inc
diff --git a/_data/sidebars/main_sidebar.yml b/_data/sidebars/main_sidebar.yml
index 05b91612..564ed3ed 100644
--- a/_data/sidebars/main_sidebar.yml
+++ b/_data/sidebars/main_sidebar.yml
@@ -7,81 +7,81 @@ entries:
         folderitems:
           - title: Layering Discovery Techniques
             output: web
-            url: index.html
+            url: /index.html
           - title: Setup Tidal Tools
             output: web
-            url: tidal-tools.html
+            url: /tidal-tools.html
           - title: Setup Tidal Tools on AWS
             output: web
-            url: tidal-tools-aws.html
+            url: /tidal-tools-aws.html
           - title: Setup Tidal Tools on GCP
             output: web
-            url: tidal-tools-gcp.html
+            url: /tidal-tools-gcp.html
           - title: Tidal Tools Autocompletion
             output: web
-            url: autocompletion.html
+            url: /autocompletion.html
           - title: Tidal Offline
             output: web
-            url: tidal-offline.html
+            url: /tidal-offline.html
 
       - title: Discover
         output: web
         folderitems:
           - title: Importing Data From Excel
             output: web
-            url: import-from-excel.html
+            url: /import-from-excel.html
           - title: Bulk Editing Records
             output: web
-            url: bulk-edits.html
+            url: /bulk-edits.html
           - title: Tidal Discover
             output: web
-            url: discover.html
+            url: /discover.html
           - title: Public URL Discovery
             output: web
-            url: public-urls.html
+            url: /public-urls.html
           - title: Tidal Analyze
             output: web
-            url: analyze.html
+            url: /analyze.html
           - title: Sync your Server Inventory
             output: web
-            url: sync-servers.html
+            url: /sync-servers.html
           - title: Gathering Machine Stats
             output: web
-            url: machine_stats.html
+            url: /machine_stats.html
           - title: Host discovery with Nmap
             output: web
-            url: host-discovery.html
+            url: /host-discovery.html
           - title: Integrating with vSphere
             output: web
-            url: vsphere.html
+            url: /vsphere.html
           - title: Integrating with Ansible Tower
             output: web
-            url: ansible-tower.html
+            url: /ansible-tower.html
           - title: Integrating with Azure Migrate
             output: web
-            url: azure-migrate.html          
+            url: /azure-migrate.html          
           - title: Windows DNS Zonefile Export
             output: web
-            url: windows-zone-export.html
+            url: /windows-zone-export.html
           - title: Tidal Tools Virtual Machine Image
             output: web
-            url: tidal-discovery-vm.html
+            url: /tidal-discovery-vm.html
 
       - title: Assess
         output: web
         folderitems:
           - title: Code Analysis Overview
             output: web
-            url: code-analysis-overview.html
+            url: /code-analysis-overview.html
           - title: Performing Code Analysis
             output: web
-            url: analyze-source-code.html
+            url: /analyze-source-code.html
           - title: HTTP Web Log Analysis
             output: web
-            url: analyze-logs.html
+            url: /analyze-logs.html
           - title: Application Interview Best Practices
             output: web
-            url: interviews.html
+            url: /interviews.html
           - title: Creating interview questions
             output: web
             url: /create-interview-questions.html
@@ -146,17 +146,17 @@ entries:
         folderitems:
           - title: General Troubleshooting
             output: web
-            url: general-troubleshooting.html
+            url: /general-troubleshooting.html
           - title: Tidal Tools Troubleshooting
             output: web
-            url: troubleshooting.html
+            url: /troubleshooting.html
           - title: Troubleshooting Ansible Tower Integration
             output: web
-            url: troubleshoot-ansible.html
+            url: /troubleshoot-ansible.html
 
       - title: Downloads
         output: web
         folderitems:
           - title: Downloads
             output: web
-            url: downloads.html
+            url: /downloads.html
diff --git a/_data/strings.yml b/_data/strings.yml
index d7c13924..228aa579 100644
--- a/_data/strings.yml
+++ b/_data/strings.yml
@@ -1,5 +1,5 @@
 
 
 # placed here for translation purposes
-search_placeholder_text: search...
+search_placeholder_text: Search...
 search_no_results_text: No results found.
diff --git a/_includes/head.html b/_includes/head.html
index 7cd7b7bd..b791a2f0 100644
--- a/_includes/head.html
+++ b/_includes/head.html
@@ -16,6 +16,47 @@
 <!-- most color styles are extracted out to here -->
 <link rel="stylesheet" href="css/theme-blue.css">
 
+<style>
+  :root {
+  --background-color: #ffffff;
+  --text-color: #000000;
+  --header-background: #4ABFD3;
+  --header-text-color: #ffffff;
+  --sidebar-background: #ffffff;
+  --sidebar-text-color: #000000;
+  --sidebar-hover-background: #e9ecef;
+  --sidebar-hover-text-color: #0056b3;
+  --table-background: #ffffff;
+  --table-header-background: #343a40;
+  --table-header-text-color: #ffffff;
+  --table-row-background: #f8f9fa;
+}
+
+[data-theme="dark"] {
+  --background-color: #212529;
+  --text-color: #f8f9fa;
+  --header-background: #343a40;
+  --header-text-color: #f8f9fa;
+  --sidebar-background: #343a40;
+  --sidebar-text-color: #adb5bd;
+  --sidebar-hover-background: #495057;
+  --sidebar-hover-text-color: #ffffff;
+  --table-background: #343a40;
+  --table-header-background: #495057;
+  --table-header-text-color: #f8f9fa;
+  --table-row-background: #212529;
+}
+  .navbar-inverse {
+    background-color: var(--header-background);
+    color: var(--header-text-color);
+  }
+
+  .navbar-inverse .navbar-nav > li > a,
+  .navbar-inverse .navbar-brand {
+    color: var(--header-text-color);
+  }
+</style>
+
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js"></script>
 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-cookie/1.4.1/jquery.cookie.min.js"></script>
diff --git a/_includes/sidebar.html b/_includes/sidebar.html
index 47a6490d..926779e0 100644
--- a/_includes/sidebar.html
+++ b/_includes/sidebar.html
@@ -1,7 +1,6 @@
 {% assign sidebar = site.data.sidebars[page.sidebar].entries %}
 
 <ul id="mysidebar" class="nav">
-  <li class="sidebarTitle">{{sidebar[0].product}} {{sidebar[0].version}}</li>
   {% for entry in sidebar %}
   {% for folder in entry.folders %}
   {% if folder.output contains "web" %}
diff --git a/_includes/topnav.html b/_includes/topnav.html
index ba9c151e..d8f55c16 100644
--- a/_includes/topnav.html
+++ b/_includes/topnav.html
@@ -13,8 +13,34 @@
         <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
             <ul class="nav navbar-nav navbar-right">
                 <!-- toggle sidebar button -->
-                <li><a id="tg-sb-link" href="#"><i id="tg-sb-icon" class="fa fa-toggle-on"></i> Nav</a></li>
-                <!-- entries without drop-downs appear here -->
+                <li><a id="tg-sb-link" href="#"><i id="tg-sb-icon" class="fa fa-toggle-on"></i> Nav</a></li>               
+                <li>
+                  <a id="theme-toggle-link" href="#" onclick="toggleTheme()">
+                    <i id="theme-icon" class="fa fa-toggle-off"></i> Darkmode
+                  </a>
+                </li>
+                <script>
+                  function toggleTheme() {
+                    const currentTheme = document.documentElement.getAttribute('data-theme');
+                    const newTheme = currentTheme === 'dark' ? 'light' : 'dark';
+                    document.documentElement.setAttribute('data-theme', newTheme);
+                    localStorage.setItem('theme', newTheme);
+
+                    // Update the icon
+                    const themeIcon = document.getElementById('theme-icon');
+                    themeIcon.className = newTheme === 'dark' ? 'fa fa-toggle-on' : 'fa fa-toggle-off';
+                  }
+
+                  // Initialize theme on page load
+                  document.addEventListener('DOMContentLoaded', () => {
+                    const savedTheme = localStorage.getItem('theme') || 'light';
+                    document.documentElement.setAttribute('data-theme', savedTheme);
+
+                    // Set the correct icon
+                    const themeIcon = document.getElementById('theme-icon');
+                    themeIcon.className = savedTheme === 'dark' ? 'fa fa-toggle-on' : 'fa fa-toggle-off';
+                  });
+                </script>
                 <li>
                     <!--start search-->
                     <div id="search-demo-container">
@@ -35,7 +61,6 @@
                     </script>
                     <!--end search-->
                 </li>
-
 {% assign topnav = site.data[page.topnav] %}
 {% assign topnav_dropdowns = site.data[page.topnav].topnav_dropdowns %}
 
diff --git a/css/customstyles.css b/css/customstyles.css
index 9695725e..2656fcb8 100644
--- a/css/customstyles.css
+++ b/css/customstyles.css
@@ -1,60 +1,242 @@
+/* General styles */
 body {
-  font-size: 15px;
+  background-color: var(--background-color);
+  color: var(--text-color);
+  font-family: 'Arial', sans-serif;
+  font-size: 16px;
+  line-height: 1.6;
+  margin: 0;
+  padding: 0;
 }
 
-.bs-callout {
-  padding: 20px;
-  margin: 20px 0;
-  border: 1px solid #eee;
-  border-left-width: 5px;
-  border-radius: 3px;
+/* Updated header styles */
+[data-theme="light"] h1, h2, h3, h4, h5, h6 {
+  font-weight: 600;
+  color: #212529;
+  margin-bottom: 1rem;
 }
-.bs-callout h4 {
-  margin-top: 0;
-  margin-bottom: 5px;
+[data-theme="dark"] h1, h2, h3, h4, h5, h6 {
+  color: #f8f9fa;
 }
-.bs-callout p:last-child {
-  margin-bottom: 0;
+
+/* Navigation bar */
+.navbar-inverse {
+  background-color: var(--header-background);
+  color: var(--header-text-color);
 }
-.bs-callout code {
-  border-radius: 3px;
+
+.navbar-inverse .navbar-nav > li > a,
+.navbar-inverse .navbar-brand {
+  color: var(--header-text-color);
+  background-color: transparent;
+  border: none;
+  font-weight: 500;
+  padding: 10px 15px;
+  text-decoration: none;
 }
-.bs-callout + .bs-callout {
-  margin-top: -5px;
+
+.navbar-inverse .navbar-nav > li > a:hover {
+  color: #0056b3;
+  text-decoration: underline;
 }
-.bs-callout-default {
-  border-left-color: #777;
+
+.navbar-inverse .navbar-nav > .active > a,
+.navbar-inverse .navbar-nav > .active > a:hover,
+.navbar-inverse .navbar-nav > .active > a:focus {
+  border-radius: 5px;
 }
-.bs-callout-default h4 {
-  color: #777;
+
+.navbar-inverse .navbar-nav > .open > a,
+.navbar-inverse .navbar-nav > .open > a:focus,
+.navbar-inverse .navbar-nav > .open > a:hover {
+  border-radius: 5px;
+}
+
+/* Sidebar */
+#mysidebar {
+  color: var(--sidebar-text-color);
+  padding: 0px;
+  border-radius: 5px;
+}
+
+#mysidebar ul {
+  list-style: none;
+  padding: 0;
 }
-.bs-callout-primary {
-  border-left-color: #428bca;
+
+#mysidebar ul li {
+  margin: 0.5rem 0;
 }
-.bs-callout-primary h4 {
-  color: #428bca;
+
+#mysidebar ul li a {
+  color: var(--sidebar-text-color);
+  padding: 3px 12px;
+  display: block;
+  border-radius: 4px;
+  transition: background-color 0.3s, color 0.3s;
+  text-decoration: none;
 }
-.bs-callout-success {
-  border-left-color: #5cb85c;
+
+#mysidebar ul li a:hover {
+  background-color: var(--sidebar-hover-background);
+  color: var(--sidebar-hover-text-color);
 }
-.bs-callout-success h4 {
-  color: #5cb85c;
+
+#mysidebar ul li a.active {
+  background-color: var(--sidebar-hover-background);
+  color: var(--sidebar-hover-text-color);
+  font-weight: bold;
 }
-.bs-callout-danger {
-  border-left-color: #d9534f;
+
+#mysidebar ul li.active > a {
+  background-color: var(--sidebar-hover-background);
+  color: var(--sidebar-hover-text-color);
+  font-weight: bold;
+  border-radius: 4px;
 }
-.bs-callout-danger h4 {
-  color: #d9534f;
+
+#mysidebar ul li.active {
+  background-color: transparent;
 }
-.bs-callout-warning {
-  border-left-color: #f0ad4e;
+
+[data-theme="dark"] #mysidebar ul li {
+  background-color: #23272b;
+}
+[data-theme="dark"] #mysidebar ul li a {
+  color: #dcdbdb;
+  background-color: #23272b;
+}
+[data-theme="dark"] #mysidebar ul li a:hover,
+[data-theme="dark"] #mysidebar ul li.active > a,
+[data-theme="dark"] #mysidebar ul li a.active {
+  background-color: #495057;
+  color: #fff;
+}
+[data-theme="dark"] #mysidebar ul li {
+  border-bottom: 1px solid #343a40;
+}
+[data-theme="dark"] #mysidebar {
+  color: #e0e0e0;
+}
+[data-theme="dark"] .nav li a {
+  color: #2f2f2f;
+  background-color: #7d98a2;
+} 
+[data-theme="dark"] #results-container li a {
+  color: #ffffff;
+  background-color: #485c64 ;
+} 
+[data-theme="dark"] .topnavlinks li a {
+  background-color: #343A40;
+} 
+[data-theme="dark"] .nav li a:hover {
+  background-color: #495057;
+  color: #fff;
+}
+[data-theme="dark"] .nav ul li a {
+  border: none;
+  color: #333;
+}
+
+[data-theme="dark"] div#toc ul {
+  background-color: #23272b;
+  color: #e0e0e0;
+}
+[data-theme="dark"] div#toc ul li {
+  color: #e0e0e0;
+}
+[data-theme="dark"] div#toc ul li a {
+  color: #7ab4ff;
+}
+[data-theme="dark"] div#toc ul li a:hover {
+  color: #fff;
+}
+[data-theme="dark"] div#toc > ul::before {
+  color: #b0b0b0;
+}
+[data-theme="dark"] div#toc ul li ul li::before {
+  color: #b0b0b0;
+}
+div#toc ul {
+  background-color: #23272b; /* much darker, subtle background */
+}
+
+[data-theme="light"] div#toc ul {
+  background-color: #f4f4f6; /* lighter than #23272b, but not whitesmoke */
 }
+
+[data-theme="dark"] div#toc ul {
+  background-color: #23272b;
+}
+
+/* Table styles */
+table {
+  border-collapse: collapse;
+  width: 100%;
+  margin-bottom: 1rem;
+  background-color: var(--table-background);
+}
+
+table th {
+  background-color: var(--table-header-background);
+  color: var(--table-header-text-color);
+  padding: 0.75rem;
+  text-align: left;
+  border-bottom: 2px solid #dee2e6;
+}
+
+table td {
+  padding: 0.75rem;
+  border-top: 1px solid #dee2e6;
+}
+
+table tr:nth-of-type(odd) {
+  background-color: var(--table-row-background);
+}
+
+/* Search area */
+#search-input {
+  background-color: var(--sidebar-background);
+  color: var(--text-color);
+  border: 1px solid var(--sidebar-hover-background);
+  padding: 0 0.5em;
+  margin-left: 20px;
+  width: 20em;
+  font-size: 0.8em;
+  box-sizing: border-box;
+  margin-top: 10px;
+}
+
+#search-input::placeholder {
+  color: var(--sidebar-text-color);
+  opacity: 0.7;
+}
+
+#search-demo-container {
+  position: relative;
+}
+
+#results-container {
+  position: absolute;
+  top: 100%;
+  left: 0;
+  right: 0;
+  z-index: 9999;
+  background: #fff;
+  box-shadow: 0 2px 8px rgba(0,0,0,0.15);
+  max-height: 300px;
+  overflow-y: auto;
+}
+
+/* Additional styles */
 .bs-callout-warning h4 {
   color: #f0ad4e;
 }
+
 .bs-callout-info {
   border-left-color: #5bc0de;
 }
+
 .bs-callout-info h4 {
   color: #5bc0de;
 }
@@ -62,18 +244,21 @@ body {
 .gi-2x {
   font-size: 2em;
 }
-.gi-3x {
-  font-size: 3em;
-}
-.gi-4x {
-  font-size: 4em;
-}
-.gi-5x {
-  font-size: 5em;
+
+.footer img {
+  max-width: 150px;
+  margin-top: 10px;
 }
 
-.breadcrumb > .active {
-  color: #777 !important;
+.footerMeta {
+  background-color: transparent;
+  padding: 10px;
+  max-width: 250px;
+  border-radius: 5px;
+  margin-top: 50px;
+  font-style: italic;
+  font-size: 12px;
+  color: #f8f9fa;
 }
 
 /* make room for the nav bar */
@@ -120,43 +305,17 @@ dt[id] {
   color: gray;
 }
 
-table {
-  background-color: transparent;
-}
 caption {
   padding-top: 8px;
   padding-bottom: 8px;
   color: #777;
   text-align: left;
 }
+
 th {
   text-align: left;
 }
-table {
-  max-width: 90%;
-  margin-bottom: 20px;
-  border: 1px solid #dedede;
-}
 
-table > thead > tr > th,
-table > tbody > tr > th,
-table > tfoot > tr > th,
-table > thead > tr > td,
-table > tbody > tr > td,
-table > tfoot > tr > td {
-  padding: 8px;
-  line-height: 1.42857143;
-  vertical-align: top;
-  border-top: 1px solid #ddd;
-}
-table > thead > tr > th {
-  vertical-align: bottom;
-  border-bottom: 2px solid #ddd;
-  text-transform: none;
-  background-color: #777;
-  color: white;
-  text-align: left;
-}
 table > caption + thead > tr:first-child > th,
 table > colgroup + thead > tr:first-child > th,
 table > thead:first-child > tr:first-child > th,
@@ -166,15 +325,12 @@ table > thead:first-child > tr:first-child > td {
   border-top: 0;
 }
 
-table > tbody > tr:nth-of-type(odd) {
-  background-color: #f9f9f9;
-}
-
 table col[class*="col-"] {
   position: static;
   display: table-column;
   float: none;
 }
+
 table td[class*="col-"],
 table th[class*="col-"] {
   position: static;
@@ -196,6 +352,7 @@ p.external a {
 #definition-box-container div a.active {
   font-weight: bold;
 }
+
 p.post-meta {
   font-size: 80%;
   color: #777;
@@ -209,45 +366,10 @@ p.post-meta {
   text-transform: uppercase;
 }
 
-/* search area */
-#search-demo-container ul#results-container {
-  list-style: none;
-  font-size: 12px;
-  background-color: white;
-  position: absolute;
-  top: 40px; /* if you change anything about the nav, you'll prob. need to reset the top and left values here.*/
-  left: 20px;
-  z-index: 10 !important;
-  width: 223px;
-  border-left: 1px solid #dedede;
-}
-
-ul#results-container a {
-  background-color: transparent;
-}
-
-ul#results-container a:hover {
-  color: black;
-}
-
-#search-demo-container a:hover {
-  color: black;
-}
-#search-input {
-  padding: 0.5em;
-  margin-left: 20px;
-  width: 20em;
-  font-size: 0.8em;
-  -webkit-box-sizing: border-box;
-  -moz-box-sizing: border-box;
-  box-sizing: border-box;
-  margin-top: 10px;
-}
-/* end search */
-
 .filter-options {
   margin-bottom: 20px;
 }
+
 .filter-options button {
   margin: 3px;
 }
@@ -257,6 +379,7 @@ div#toc ul li {
   font-size: 90%;
   list-style: square;
 }
+
 div#toc ul {
   background-color: whitesmoke;
   padding: 5px;
@@ -273,19 +396,6 @@ div#toc ul li ul li::before {
   content: "–  ";
 }
 
-div#toc > ul::before {
-  content: "Table of Contents";
-  font-weight: 500;
-  color: #555;
-  text-align: center;
-  margin-left: auto;
-  margin-right: auto;
-  width: 70px;
-  padding-top: 20px;
-  padding-bottom: 20px;
-  padding-left: 10px;
-}
-
 li.dropdownActive a {
   font-weight: bold;
 }
@@ -294,11 +404,6 @@ li.dropdownActive a {
   color: orange;
 }
 
-.navbar-inverse .navbar-nav > li > a {
-  background-color: transparent;
-  margin-top: 10px;
-}
-
 .post-content .rssfeedLink {
   color: #248ec2;
 }
@@ -307,7 +412,6 @@ footer {
   font-size: smaller;
 }
 
-/* FAQ page */
 #accordion .panel-heading {
   font-size: 12px;
 }
@@ -318,7 +422,6 @@ a.accordion-collapsed {
   text-decoration: none;
 }
 
-/* navgoco sidebar styles (customized) */
 .nav,
 .nav ul,
 .nav li {
@@ -327,12 +430,10 @@ a.accordion-collapsed {
 
 .nav ul {
   padding: 0;
-  /*margin: 0 0 0 18px;*/
   margin: 0px;
 }
 
 .nav {
-  /* padding: 4px;*/
   padding: 0px;
   margin: 0px;
 }
@@ -349,9 +450,6 @@ a.accordion-collapsed {
   color: #333;
   display: block;
   outline: none;
-  /*-webkit-border-radius: 4px;
-    -moz-border-radius: 4px;
-    border-radius: 4px;*/
   text-decoration: none;
 }
 
@@ -364,6 +462,7 @@ a.accordion-collapsed {
 .nav li > a > span:after {
   content: "\25be";
 }
+
 .nav li.active > a > span:after {
   content: "\25b4";
 }
@@ -423,19 +522,6 @@ ul#mysidebar {
   border-top: 1px solid whitesmoke;
   padding-left: 10px;
 }
-/* end sidebar */
-
-.navbar-inverse .navbar-nav > .active > a,
-.navbar-inverse .navbar-nav > .active > a:hover,
-.navbar-inverse .navbar-nav > .active > a:focus {
-  border-radius: 5px;
-}
-
-.navbar-inverse .navbar-nav > .open > a,
-.navbar-inverse .navbar-nav > .open > a:focus,
-.navbar-inverse .navbar-nav > .open > a:hover {
-  border-radius: 5px;
-}
 
 span.projectTitle {
   font-family: Helvetica, sans-serif;
@@ -445,24 +531,16 @@ span.projectTitle {
 .footer {
   text-align: right;
 }
+
 .footer-link::after {
   visibility: hidden;
 }
+
 .footer-logo {
   position: relative;
   right: -33px;
 }
 
-.footerMeta {
-  background-color: whitesmoke;
-  padding: 10px;
-  max-width: 250px;
-  border-radius: 5px;
-  margin-top: 50px;
-  font-style: italic;
-  font-size: 12px;
-}
-
 img.screenshotSmall {
   max-width: 300px;
 }
@@ -500,9 +578,6 @@ figcaption {
 table.dataTable thead {
   background-color: #444;
 }
-table td {
-  hyphens: auto;
-}
 
 section table tr.success {
   background-color: #dff0d8 !important;
@@ -517,6 +592,7 @@ table tr.testing,
 table tr.testing > td.sorting_1 {
   background-color: #fcf8e3 !important;
 }
+
 section table tr.danger,
 table tr.preference,
 table tr.preference > td.sorting_1 {
@@ -547,6 +623,7 @@ table.request thead tr th {
   text-align: center;
   margin: 5px;
 }
+
 span.myLabel {
   padding-left: 10px;
   padding-right: 10px;
@@ -602,15 +679,19 @@ hr.shaded {
 .fa-6x {
   font-size: 900%;
 }
+
 .fa-7x {
   font-size: 1100%;
 }
+
 .fa-8x {
   font-size: 1300%;
 }
+
 .fa-9x {
   font-size: 1500%;
 }
+
 .fa-10x {
   font-size: 1700%;
 }
@@ -641,18 +722,6 @@ a.fa.fa-envelope-o.mailto {
   font-weight: 600;
 }
 
-h3 {
-  color: #ed1951;
-  font-weight: normal;
-  font-size: 130%;
-}
-h4 {
-  color: #808080;
-  font-weight: normal;
-  font-size: 120%;
-  font-style: italic;
-}
-
 .alert,
 .callout {
   overflow: hidden;
@@ -668,6 +737,7 @@ h4 {
 ol li ol li {
   list-style-type: lower-alpha;
 }
+
 ol li ul li {
   list-style-type: disc;
 }
@@ -708,7 +778,7 @@ div.alert code,
 h2 code {
   background-color: transparent !important;
 }
-/* without this, the links in these notes aren't visible.*/
+
 .alert a {
   text-decoration: underline;
 }
@@ -737,6 +807,7 @@ h2 {
   font-size: 24px;
   line-height: 29px;
 }
+
 span.otherProgrammingLanguages {
   font-style: normal;
 }
@@ -783,7 +854,6 @@ ol.series li {
   display: block;
 }
 
-/* not sure if using this ...*/
 .navbar-inverse .navbar-collapse,
 .navbar-inverse .navbar-form {
   border-color: #248ec2 !important;
@@ -793,6 +863,7 @@ ol.series li {
 #mysidebar .nav ul {
   background-color: #fafafa;
 }
+
 .nav ul.series li {
   list-style: decimal;
   font-size: 12px;
@@ -801,6 +872,7 @@ ol.series li {
 .nav ul.series li a:hover {
   background-color: gray;
 }
+
 .nav ul.series {
   padding-left: 30px;
 }
@@ -809,12 +881,6 @@ ol.series li {
   background-color: #fafafa;
 }
 
-/*
-a.dropdown-toggle.otherProgLangs {
-    color: #f7e68f !important;
-}
-*/
-
 span.muted {
   color: #666;
 }
@@ -835,11 +901,11 @@ table p {
 
 pre,
 table code {
-  white-space: pre-wrap; /* css-3 */
-  white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
-  white-space: -pre-wrap; /* Opera 4-6 */
-  white-space: -o-pre-wrap; /* Opera 7 */
-  word-wrap: break-word; /* Internet Explorer 5.5+ */
+  white-space: pre-wrap;
+  white-space: -moz-pre-wrap;
+  white-space: -pre-wrap;
+  white-space: -o-pre-wrap;
+  word-wrap: break-word;
 }
 
 pre {
@@ -876,6 +942,7 @@ dd {
   margin: 0px;
   margin-bottom: 6px;
 }
+
 .panel-heading {
   font-weight: bold;
 }
@@ -995,9 +1062,7 @@ span.soft {
   padding: 10px;
 }
 
-/* this part adds an icon after external links, using FontAwesome*/
-a[href^="http://"]:after, a[href^="https://"]:after
-{
+a[href^="http://"]:after, a[href^="https://"]:after {
   content: "\f08e";
   font-family: FontAwesome;
   font-weight: normal;
@@ -1007,7 +1072,6 @@ a[href^="http://"]:after, a[href^="https://"]:after
   padding-left: 3px;
 }
 
-/* Strip the outbound icon when this class is present */
 a[href].noCrossRef::after,
 a.no_icon:after {
   content: "" !important;
@@ -1018,26 +1082,25 @@ a.no_icon:after {
   margin-bottom: 10px;
 }
 
-/* algolia search */
-
 .search {
   text-align: left;
 }
+
 .search input {
   font-size: 20px;
   width: 300px;
 }
+
 .results {
   margin: auto;
   text-align: left;
 }
+
 .results ul {
   list-style-type: none;
   padding: 0;
 }
 
-/* algolia */
-
 div.results {
   position: absolute;
   background-color: white;
@@ -1072,6 +1135,7 @@ span.label.label-default {
 span.label.label-primary {
   background-color: #f0ad4e;
 }
+
 .col-lg-12 .nav li a {
   background-color: white;
 }
@@ -1200,29 +1264,21 @@ div.box.box1 {
 }
 
 #userMap .btn-lg {
-  white-space: pre-wrap; /* css-3 */
-  white-space: -moz-pre-wrap; /* Mozilla, since 1999 */
-  white-space: -pre-wrap; /* Opera 4-6 */
-  white-space: -o-pre-wrap; /* Opera 7 */
-  word-wrap: break-word; /* Internet Explorer 5.5+ */
+  white-space: pre-wrap;
+  white-space: -moz-pre-wrap;
+  white-space: -pre-wrap;
+  white-space: -o-pre-wrap;
+  word-wrap: break-word;
   font-size: 14px;
 }
 
-/*
- * Let's target IE to respect aspect ratios and sizes for img tags containing SVG files
- *
- * [1] IE9
- * [2] IE10+
- */
-/* 1 */
 .ie9 img[src$=".svg"] {
   width: 100%;
 }
-/* 2 */
+
 @media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) {
   img[src$=".svg"] {
     width: 100%;
-  }
 }
 
 h4.panel-title {
@@ -1230,8 +1286,6 @@ h4.panel-title {
   margin-top: 0px;
 }
 
-/*set navbar breakpoint so that it converts to hamburger earlier */
-
 @media (max-width: 1200px) {
   .navbar-header {
     float: none;
diff --git a/css/theme-blue.css b/css/theme-blue.css
index 1de57c42..1c46ab21 100644
--- a/css/theme-blue.css
+++ b/css/theme-blue.css
@@ -5,9 +5,6 @@
 }
 
 
-h3 {color: #ED1951; }
-h4 {color: #808080; }
-
 .nav-tabs > li.active > a, .nav-tabs > li.active > a:hover, .nav-tabs > li.active > a:focus {
     background-color: #248ec2;
     color: white;
@@ -39,7 +36,7 @@ a[data-toggle="tooltip"] {
 
 .navbar-inverse {
     background-color: #4ABFD3;
-    border-color: #015CAE;
+    border-color: #4ABFD3;
 }
 .navbar-inverse .navbar-nav>li>a, .navbar-inverse .navbar-brand {
     color: white;
diff --git a/css/theme-dark.css b/css/theme-dark.css
new file mode 100644
index 00000000..e69de29b
diff --git a/docker-compose.yml b/docker-compose.yml
index f372ae68..6da6be3c 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -1,4 +1,14 @@
-version: '2'
+# Docker Compose file for the web server
+# This file is used to build and run the web server for the Tidal documentation site.
+#
+# to run the server, use the command:
+# docker-compose up
+# to stop the server, use the command:
+# docker-compose down
+# to rebuild the server, use the command:
+# docker-compose build
+# to view the logs, use the command:
+# docker-compose logs -f  
 services:
   server:
     build:
diff --git a/netlify.toml b/netlify.toml
new file mode 100644
index 00000000..357f05f9
--- /dev/null
+++ b/netlify.toml
@@ -0,0 +1,7 @@
+[build.environment]
+  NODE_VERSION = "22"
+  RUBY_VERSION = "3.3.4"
+
+[build]
+  command = "bundle install && bundle exec jekyll build"
+  publish = "_site"
\ No newline at end of file


Reviews:
user: login: justinbarclay
state: APPROVED
author_association: MEMBER
submitted_at: 2025-05-08T16:12:12Z
user: login: dcolebatch
state: COMMENTED
author_association: MEMBER
submitted_at: 2025-05-08T17:21:13Z
user: login: SamDesmondKing
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-12T06:55:12Z

Review comments:
diff_hunk: @@ -1,4 +1,4 @@
-FROM ruby:2.1
+FROM ruby:3.3.4
path: Dockerfile
user: login: justinbarclay
body: I'm not sure where this Docker image is used. Do you know?
created_at: 2025-05-08T16:12:07Z
author_association: MEMBER
diff_hunk: @@ -1,4 +1,4 @@
-FROM ruby:2.1
+FROM ruby:3.3.4
path: Dockerfile
user: login: dcolebatch
body: Used for local dev/build environments is all I could determine.  The AI even used it to serve it up to me.
created_at: 2025-05-08T17:21:13Z
author_association: MEMBER
path: css/theme-dark.css
user: login: SamDesmondKing
body: why is this empty file here?
created_at: 2025-05-12T06:55:12Z
author_association: CONTRIBUTOR

PR comments:
user: login: netlify[bot]
created_at: 2025-05-06T23:42:03Z
body: ### <span aria-hidden="true">✅</span> Deploy Preview for *tidal-guides* ready!


|  Name | Link |
|:-:|------------------------|
|<span aria-hidden="true">🔨</span> Latest commit | 0e3103f527707b0310afec6cf702b23936d23660 |
|<span aria-hidden="true">🔍</span> Latest deploy log | https://app.netlify.com/sites/tidal-guides/deploys/681cd23af7bf9600084e35d4 |
|<span aria-hidden="true">😎</span> Deploy Preview | [https://deploy-preview-285--tidal-guides.netlify.app](https://deploy-preview-285--tidal-guides.netlify.app) |
|<span aria-hidden="true">📱</span> Preview on mobile | <details><summary> Toggle QR Code... </summary><br /><br />![QR Code](https://app.netlify.com/qr-code/eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1cmwiOiJodHRwczovL2RlcGxveS1wcmV2aWV3LTI4NS0tdGlkYWwtZ3VpZGVzLm5ldGxpZnkuYXBwIn0.TMNvSEq73kYGT3QE24B8_praER1INKUQB0uezg7pdq0)<br /><br />_Use your smartphone camera to open QR code link._</details> |
---
<!-- [tidal-guides Preview](https://deploy-preview-285--tidal-guides.netlify.app) -->
_To edit notification comments on pull requests, go to your [Netlify site configuration](https://app.netlify.com/sites/tidal-guides/configuration/notifications#deploy-webhooks)._
author_association: NONE
user: login: dcolebatch
created_at: 2025-05-07T13:27:51Z
body: Hmm - right, netlify. 
Does anyone have any tips on updating netlify to use latest ruby? 

<img width="1107" alt="image" src="https://github.com/user-attachments/assets/debc422e-83af-4f1d-95f5-4933071f5284" />

author_association: MEMBER
user: login: dcolebatch
created_at: 2025-05-08T15:58:15Z
body: The david-assisted GitHub CoPilot Agent Mode trial is over.  The results are: https://681cd23af7bf9600084e35d4--tidal-guides.netlify.app/#

My takeaway is:
* Powerful for improving productivity
* Helps you to learn new things
* Reduces cognitive load
* but try to improve your build toolchain *first* :) 
author_association: MEMBER
user: login: SamDesmondKing
created_at: 2025-05-12T06:20:41Z
body: FYI page sub-headers are now invisible in light mode 
![image](https://github.com/user-attachments/assets/17f70645-c64b-4180-8b01-0be509924862)

author_association: CONTRIBUTOR
user: login: SamDesmondKing
created_at: 2025-05-12T06:24:20Z
body: Also, in my opinion it would be better if the color palette in both light and dark mode adhered to our style guide's established color palette.

![image](https://github.com/user-attachments/assets/0dae6eb4-5314-40e6-b676-b3cc1d4dc7a0)

author_association: CONTRIBUTOR
user: login: SamDesmondKing
created_at: 2025-05-12T06:59:23Z
body: I was going to open a PR to address my concerns here but I see Justin has started a full re-write.
author_association: CONTRIBUTOR