diff --git a/.astro/types.d.ts b/.astro/types.d.ts
index 03d7cc4..f964fe0 100644
--- a/.astro/types.d.ts
+++ b/.astro/types.d.ts
@@ -1,2 +1 @@
 /// <reference types="astro/client" />
-/// <reference path="content.d.ts" />
\ No newline at end of file
diff --git a/config/README.md b/config/README.md
new file mode 100644
index 0000000..5b865e0
--- /dev/null
+++ b/config/README.md
@@ -0,0 +1,56 @@
+# Site Configuration
+
+This directory contains configuration files for the website. Instead of hardcoding values in the TypeScript files, these JSON files are used to make the site more configurable.
+
+## Available Configuration Files
+
+- **site.json**: Contains global site metadata, menu structure, and text strings
+- **services.json**: Contains homelab services organized by category
+- **socials.json**: Contains social media profile configurations (the single source of truth for all social profiles)
+
+## How to Use
+
+To modify any configuration values, simply edit the appropriate JSON file. The changes will be reflected in the application without having to modify any TypeScript code.
+
+### Example: Updating Menu Items
+
+To add or remove a menu item, edit the `menu` section in `site.json`:
+
+```json
+"menu": {
+  "home": "/",
+  "about": "/about",
+  "blog": "/blog",
+  "projects": "/projects",
+  "homelab": "/homelab",
+  "code": "https://code.justin.deal",
+  "new-page": "/new-page"
+}
+```
+
+### Example: Adding a New Service
+
+To add a new service, find the appropriate category in `services.json` and add a new item:
+
+```json
+"Media": [
+  {
+    "name": "Jellyfin",
+    "link": "https://watch.justin.deal",
+    "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/jellyfin.svg",
+    "alt": "Jellyfin",
+    "tags": []
+  },
+  {
+    "name": "Plex",
+    "link": "https://plex.justin.deal",
+    "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/plex.svg",
+    "alt": "Plex Media Server",
+    "tags": ["media", "streaming"]
+  }
+]
+```
+
+## Technical Implementation
+
+The configuration files are loaded from this directory using the `loadConfig` function in `src/lib/config.ts`. The function reads the JSON files, parses them, and caches the results to avoid reading the files multiple times.
diff --git a/config/services.json b/config/services.json
new file mode 100644
index 0000000..fe778a4
--- /dev/null
+++ b/config/services.json
@@ -0,0 +1,153 @@
+{
+  "Websites": [
+    {
+      "name": "justin.deal",
+      "link": "https://justin.deal",
+      "icon": "/pixel_avatar.png",
+      "alt": "Personal Website"
+    }
+  ],
+  "Utilities": [
+    {
+      "name": "Silverbullet",
+      "link": "https://notes.justin.deal",
+      "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/png/silverbullet.png",
+      "alt": "Silverbullet",
+      "tags": ["notes", "markdown", "knowledge base"]
+    },
+    {
+      "name": "Vikunja",
+      "link": "https://todo.justin.deal",
+      "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/vikunja.svg",
+      "alt": "Vikunja",
+      "tags": ["todo", "tasks", "productivity"]
+    },
+    {
+      "name": "Actual",
+      "link": "https://budget.justin.deal",
+      "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/actual-budget.svg",
+      "alt": "Actual",
+      "tags": ["finance", "budget", "money"]
+    },
+    {
+      "name": "Searxng",
+      "link": "https://search.justin.deal",
+      "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/searxng.svg",
+      "alt": "Searxng",
+      "tags": ["search", "privacy", "metasearch"]
+    },
+    {
+      "name": "BaiKal",
+      "link": "https://dav.justin.deal",
+      "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/png/baikal.png",
+      "alt": "BaiKal",
+      "tags": []
+    },
+    {
+      "name": "Cryptpad",
+      "link": "https://docs.justin.deal",
+      "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/cryptpad.svg",
+      "alt": "Cryptpad",
+      "tags": []
+    }
+  ],
+  "Development": [
+    {
+      "name": "Gitea",
+      "link": "https://code.justin.deal",
+      "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/gitea.svg",
+      "alt": "Gitea",
+      "tags": []
+    },
+    {
+      "name": "OpenGist",
+      "link": "https://snippets.justin.deal",
+      "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/opengist.svg",
+      "alt": "OpenGist",
+      "tags": []
+    },
+    {
+      "name": "IT-Tools",
+      "link": "https://tools.justin.deal",
+      "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/it-tools.svg",
+      "alt": "IT-Tools",
+      "tags": []
+    }
+  ],
+  "Media": [
+    {
+      "name": "Jellyfin",
+      "link": "https://watch.justin.deal",
+      "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/jellyfin.svg",
+      "alt": "Jellyfin",
+      "tags": []
+    },
+    {
+      "name": "Calibre-Web",
+      "link": "https://books.justin.deal",
+      "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/calibre-web.svg",
+      "alt": "Calibre-Web",
+      "tags": []
+    }
+  ],
+  "Analytics": [
+    {
+      "name": "Uptime Kuma",
+      "link": "https://status.justin.deal",
+      "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/uptime-kuma.svg",
+      "alt": "Uptime Kuma",
+      "tags": []
+    },
+    {
+      "name": "Umami",
+      "link": "https://analytics.justin.deal",
+      "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/umami.svg",
+      "alt": "Umami",
+      "tags": []
+    },
+    {
+      "name": "TeslaMate",
+      "link": "https://tesla.justin.deal",
+      "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/teslamate.svg",
+      "alt": "TeslaMate",
+      "tags": []
+    }
+  ],
+  "Infrastructure": [
+    {
+      "name": "Pi-hole",
+      "link": "https://pihole.justin.deal",
+      "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/pi-hole.svg",
+      "alt": "Pi-hole",
+      "tags": []
+    },
+    {
+      "name": "Ntfy",
+      "link": "https://ntfy.justin.deal",
+      "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/ntfy.svg",
+      "alt": "Ntfy",
+      "tags": []
+    },
+    {
+      "name": "Vaultwarden",
+      "link": "https://passwords.justin.deal",
+      "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/vaultwarden.svg",
+      "alt": "Vaultwarden",
+      "tags": []
+    },
+    {
+      "name": "Authentik",
+      "link": "https://auth.justin.deal",
+      "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/authentik.svg",
+      "alt": "Authentik",
+      "tags": []
+    },
+    {
+      "name": "Traefik",
+      "link": "https://proxy.justin.deal:8080",
+      "icon": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/traefik.svg",
+      "alt": "Traefik",
+      "tags": []
+    }
+  ]
+}
diff --git a/config/site.json b/config/site.json
new file mode 100644
index 0000000..2a694d2
--- /dev/null
+++ b/config/site.json
@@ -0,0 +1,32 @@
+{
+  "username": "Justin Deal",
+  "rootUrl": "https://justin.deal",
+  "shortDescription": "My personal slice of the internet",
+  "longDescription": "My personal blog, portfolio, and homelab dashboard built with Astro, TypeScript, TailwindCSS, and Alpine.js.",
+  
+  "articlesName": "Articles",
+  "projectsName": "Projects",
+  "viewAll": "View All",
+  
+  "noArticles": "No featured articles yet.",
+  "noProjects": "No featured projects yet.",
+
+  "blogTitle": "My Thoughts & Takes",
+  "blogShortDescription": "Practical wisdom, unfiltered thoughts, and hot takes.",
+  "blogLongDescription": "Web development, tech trends, and the occasional programming mishap.",
+
+  "projectTitle": "Projects and Code",
+  "projectShortDescription": "A list of my web development projects and developer tools.",
+  "projectLongDescription": "All of my projects, including both frontend and full-stack applications.",
+
+  "profileImage": "pixel_avatar.png",
+  
+  "menu": {
+    "home": "/",
+    "about": "/about",
+    "blog": "/blog",
+    "projects": "/projects",
+    "homelab": "/homelab",
+    "code": "https://code.justin.deal"
+  }
+}
diff --git a/config/socials.json b/config/socials.json
new file mode 100644
index 0000000..23c1382
--- /dev/null
+++ b/config/socials.json
@@ -0,0 +1,29 @@
+[
+  {
+    "name": "Gitea",
+    "url": "https://code.justin.deal/dealjus",
+    "iconDark": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/gitea-dark.svg",
+    "iconLight": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/gitea-light.svg",
+    "alt": "Gitea Profile",
+    "showInFooter": true,
+    "showInAbout": true
+  },
+  {
+    "name": "LinkedIn",
+    "url": "https://www.linkedin.com/in/justin-deal/",
+    "iconDark": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/linkedin-dark.svg",
+    "iconLight": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/linkedin-light.svg",
+    "alt": "LinkedIn Profile",
+    "showInFooter": true,
+    "showInAbout": true
+  },
+  {
+    "name": "GitHub",
+    "url": "https://github.com/justintdeal",
+    "iconDark": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/github-dark.svg",
+    "iconLight": "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/github-light.svg",
+    "alt": "GitHub Profile",
+    "showInFooter": true,
+    "showInAbout": true
+  }
+]
diff --git a/src/components/Footer.astro b/src/components/Footer.astro
index 4354dad..7290f8b 100644
--- a/src/components/Footer.astro
+++ b/src/components/Footer.astro
@@ -20,7 +20,8 @@ const footerSocials = socials.filter(social => social.showInFooter);
           <SocialIcon 
             name={social.name}
             url={social.url}
-            icon={social.icon}
+            iconDark={social.iconDark}
+            iconLight={social.iconLight}
             alt={social.alt}
           />
         ))}
diff --git a/src/components/common/SocialIcon.astro b/src/components/common/SocialIcon.astro
index 54ddf43..db1ce08 100644
--- a/src/components/common/SocialIcon.astro
+++ b/src/components/common/SocialIcon.astro
@@ -4,12 +4,18 @@ import Anchor from "./Anchor.astro";
 export interface Props {
   name: string;
   url: string;
-  icon: string;
+  iconDark?: string;
+  iconLight?: string;
+  icon?: string; // For backward compatibility
   alt: string;
   size?: "sm" | "md" | "lg";
 }
 
-const { name, url, icon, alt, size = "md" } = Astro.props;
+const { name, url, iconDark, iconLight, icon, alt, size = "md" } = Astro.props;
+
+// Use provided icons or fallback to the legacy icon prop
+const darkIcon = iconDark || icon;
+const lightIcon = iconLight || icon;
 
 const sizeClasses = {
   sm: "w-6 h-6",
@@ -19,9 +25,28 @@ const sizeClasses = {
 ---
 
 <Anchor url={url} aria-label={alt}>
+  <!-- Dark icon shown in light theme -->
   <img 
-    src={icon} 
+    src={darkIcon} 
     alt={alt} 
-    class={`${sizeClasses[size]} zag-transition`} 
+    class={`${sizeClasses[size]} light-theme-only zag-transition`} 
+  />
+  <!-- Light icon shown in dark theme -->
+  <img 
+    src={lightIcon} 
+    alt={alt} 
+    class={`${sizeClasses[size]} dark-theme-only zag-transition`} 
   />
 </Anchor>
+
+<style>
+  /* Hide dark icon in dark theme */
+  :global(.dark-theme) .light-theme-only {
+    display: none;
+  }
+  
+  /* Hide light icon in light theme */
+  :global(.light-theme) .dark-theme-only {
+    display: none;
+  }
+</style>
diff --git a/src/lib/config.ts b/src/lib/config.ts
new file mode 100644
index 0000000..f1de7fe
--- /dev/null
+++ b/src/lib/config.ts
@@ -0,0 +1,97 @@
+import fs from 'node:fs';
+import path from 'node:path';
+import { fileURLToPath } from 'node:url';
+
+// Get the directory of the current module
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+// Path to the config directory (two levels up from lib directory)
+const configDir = path.resolve(__dirname, '../../config');
+
+/**
+ * Cache to avoid loading config files multiple times
+ */
+const configCache = new Map<string, any>();
+
+/**
+ * Load and parse a JSON configuration file
+ * @param name The name of the config file without extension
+ * @returns The parsed configuration object
+ */
+export function loadConfig<T>(name: string): T {
+  // If the config is already in cache, return it
+  if (configCache.has(name)) {
+    return configCache.get(name) as T;
+  }
+
+  try {
+    // Load the config file
+    const configPath = path.join(configDir, `${name}.json`);
+    const configData = fs.readFileSync(configPath, 'utf-8');
+    const config = JSON.parse(configData);
+
+    // Cache the result
+    configCache.set(name, config);
+    
+    return config as T;
+  } catch (error) {
+    console.error(`Error loading config '${name}':`, error);
+    throw new Error(`Failed to load config: ${name}`);
+  }
+}
+
+/**
+ * Site configuration type
+ */
+export interface SiteConfig {
+  username: string;
+  rootUrl: string;
+  shortDescription: string;
+  longDescription: string;
+  articlesName: string;
+  projectsName: string;
+  viewAll: string;
+  noArticles: string;
+  noProjects: string;
+  blogTitle: string;
+  blogShortDescription: string;
+  blogLongDescription: string;
+  projectTitle: string;
+  projectShortDescription: string;
+  projectLongDescription: string;
+  profileImage: string;
+  menu: Record<string, string>;
+}
+
+/**
+ * Service category type (from types.ts)
+ */
+export type ServiceCategory = Record<string, Service[]>;
+
+/**
+ * Service type (based on types.ts)
+ */
+export interface Service {
+  name: string;
+  link: string;
+  icon: string;
+  alt: string;
+  tags?: string[];
+}
+
+/**
+ * Social media type (based on types.ts)
+ */
+export interface SocialMedia {
+  name: string;
+  url: string;
+  iconDark: string;
+  iconLight: string;
+  alt: string;
+  showInFooter: boolean;
+  showInAbout: boolean;
+}
+
+// Convenience exports for commonly used configs
+export const site = loadConfig<SiteConfig>('site');
+export const services = loadConfig<ServiceCategory>('services');
+export const socials = loadConfig<SocialMedia[]>('socials');
diff --git a/src/lib/socials.ts b/src/lib/socials.ts
index 754c732..2b4cfe8 100644
--- a/src/lib/socials.ts
+++ b/src/lib/socials.ts
@@ -1,31 +1,12 @@
 import { type SocialMedia } from "./types";
+import { socials as socialsConfig } from "./config";
 
 /**
  * Social media profiles
+ * This is now loaded from a JSON configuration file
+ * located at /config/socials.json
+ * 
+ * To modify social profiles, edit that JSON file rather than
+ * modifying the values here.
  */
-export const socials: SocialMedia[] = [
-  {
-    name: "Gitea",
-    url: "https://code.justin.deal/dealjus",
-    icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/gitea-dark.svg",
-    alt: "Gitea Profile",
-    showInFooter: true,
-    showInAbout: true
-  },
-  {
-    name: "LinkedIn",
-    url: "https://www.linkedin.com/in/justin-deal/",
-    icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/linkedin-dark.svg",
-    alt: "LinkedIn Profile",
-    showInFooter: true,
-    showInAbout: true
-  },
-  {
-    name: "GitHub",
-    url: "https://github.com/justintdeal",
-    icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/github-dark.svg",
-    alt: "GitHub Profile",
-    showInFooter: true,
-    showInAbout: true
-  }
-];
+export const socials: SocialMedia[] = socialsConfig;
diff --git a/src/lib/types.ts b/src/lib/types.ts
index 25ebffe..11b34cb 100644
--- a/src/lib/types.ts
+++ b/src/lib/types.ts
@@ -140,9 +140,16 @@ export type SocialMedia = {
   url: string;
   
   /**
-   * The URL to the icon from selfh.st/icons
+   * The URL to the dark version of the icon from selfh.st/icons
+   * Used in light theme
    */
-  icon: string;
+  iconDark: string;
+  
+  /**
+   * The URL to the light version of the icon from selfh.st/icons
+   * Used in dark theme
+   */
+  iconLight: string;
   
   /**
    * Alternative text for the icon
diff --git a/src/lib/variables.ts b/src/lib/variables.ts
index 7bebe10..8f5835f 100644
--- a/src/lib/variables.ts
+++ b/src/lib/variables.ts
@@ -1,72 +1,12 @@
-// Set any item to undefined to remove it from the site or to use the default value
-
 /**
  * Global variables used throughout the site
- * @property {string} username - The username displayed on the site
- * @property {string} rootUrl - The root URL of the site
- * @property {string} shortDescription - A short description of the site
- * @property {string} longDescription - A longer description of the site
- * @property {string} articlesName - The name used for articles
- * @property {string} projectsName - The name used for projects
- * @property {string} viewAll - The text used for "View All" links
- * @property {string} noArticles - The text used when there are no articles
- * @property {string} noProjects - The text used when there are no projects
- * @property {string} blogTitle - The title of the blog section
- * @property {string} blogShortDescription - A short description of the blog
- * @property {string} blogLongDescription - A longer description of the blog
- * @property {string} projectTitle - The title of the projects section
- * @property {string} projectShortDescription - A short description of the projects
- * @property {string} projectLongDescription - A longer description of the projects
- * @property {string} profileImage - The profile image filename
- * @property {string} githubProfile - The URL to the GitHub profile
- * @property {string} linkedinProfile - The URL to the LinkedIn profile
- * @property {string} giteaProfile - The URL to the Gitea profile
- * @property {Object} menu - The menu items
+ * This is now loaded from a JSON configuration file
+ * located at /config/site.json
+ * 
+ * To modify site configuration, edit that JSON file
+ * rather than modifying the values here.
  */
-export const GLOBAL = {
-  // Site metadata
-  username: "Justin Deal",
-  rootUrl: "https://justin.deal",
-  shortDescription: "My personal slice of the internet",
-  longDescription: "My personal blog, portfolio, and homelab dashboard built with Astro, TypeScript, TailwindCSS, and Alpine.js.",
-  
-  // Common text names used throughout the site
-  articlesName: "Articles",
-  projectsName: "Projects",
-  viewAll: "View All",
-  
-  // Common descriptions used throughout the site
-  noArticles: "No featured articles yet.",
-  noProjects: "No featured projects yet.",
+import { site } from './config';
 
-  // Blog metadata
-  blogTitle: "My Thoughts & Takes",
-  blogShortDescription: "Practical wisdom, unfiltered thoughts, and hot takes.",
-  blogLongDescription: "Web development, tech trends, and the occasional programming mishap.",
-
-  // Project metadata
-  projectTitle: "Projects and Code",
-  projectShortDescription: "A list of my web development projects and developer tools.",
-  projectLongDescription: "All of my projects, including both frontend and full-stack applications.",
-
-  // Profile image
-  profileImage: "pixel_avatar.png",
-  
-  // Social media profiles
-  githubProfile: "https://github.com/justindeal",
-  linkedinProfile: "https://www.linkedin.com/in/justin-deal/",
-  giteaProfile: "https://code.justin.deal/dealjus",
-
-  // Menu items
-  menu: {
-    home: "/",
-    about: "/about",
-    blog: "/blog",
-    projects: "/projects",
-    homelab: "/homelab",
-    code: "https://code.justin.deal",
-    // videos: "https://www.youtube.com/@justin_deal",
-    // homelab: "https://homelab.justin.deal",
-    // contact: "/contact",
-  }
-};
+// Re-export site configuration as GLOBAL for backward compatibility
+export const GLOBAL = site;
diff --git a/src/pages/about.astro b/src/pages/about.astro
index 461bda3..527b8ba 100644
--- a/src/pages/about.astro
+++ b/src/pages/about.astro
@@ -299,7 +299,10 @@ const aboutSocials = socials.filter(social => social.showInAbout);
       <div class="flex flex-wrap gap-4">
         {aboutSocials.map((social) => (
           <a href={social.url} target="_blank" rel="noopener noreferrer" class="flex items-center gap-2 zag-bg-alt p-4 rounded-lg shadow-sm hover:zag-bg-accent-light transition-colors">
-            <img src={social.icon} alt={social.alt} class="w-6 h-6 zag-text" />
+            <!-- Dark icon for light theme -->
+            <img src={social.iconDark} alt={social.alt} class="w-6 h-6 zag-text light-theme-only" />
+            <!-- Light icon for dark theme -->
+            <img src={social.iconLight} alt={social.alt} class="w-6 h-6 zag-text dark-theme-only" />
             <span>{social.name}</span>
           </a>
         ))}
diff --git a/src/pages/homelab/services.ts b/src/pages/homelab/services.ts
index 80555ac..6c45e2c 100644
--- a/src/pages/homelab/services.ts
+++ b/src/pages/homelab/services.ts
@@ -1,158 +1,12 @@
 import { type Service, type ServiceCategory } from "../../lib/types";
+import { services as servicesConfig } from "../../lib/config";
 
 /**
  * Services available in the homelab, organized by category
+ * This is now loaded from a JSON configuration file
+ * located at /config/services.json
+ * 
+ * To modify services, edit that JSON file rather than
+ * modifying the values here.
  */
-export const services: ServiceCategory = {
-    Websites: [
-      {
-        name: "justin.deal",
-        link: "https://justin.deal",
-        icon: "/pixel_avatar.png",
-        alt: "Personal Website"
-      }
-    ],
-    Utilities: [
-      {
-        name: "Silverbullet",
-        link: "https://notes.justin.deal",
-        icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/silverbullet.png",
-        alt: "Silverbullet",
-        tags: ["notes", "markdown", "knowledge base"]
-      },
-      {
-        name: "Vikunja",
-        link: "https://todo.justin.deal",
-        icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/vikunja.svg",
-        alt: "Vikunja",
-        tags: ["todo", "tasks", "productivity"]
-      },
-      {
-        name: "Actual",
-        link: "https://budget.justin.deal",
-        icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/actual-budget.svg",
-        alt: "Actual",
-        tags: ["finance", "budget", "money"]
-      },
-      {
-        name: "Searxng",
-        link: "https://search.justin.deal",
-        icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/searxng.svg",
-        alt: "Searxng",
-        tags: ["search", "privacy", "metasearch"]
-      },
-      {
-        name: "BaiKal",
-        link: "https://dav.justin.deal",
-        icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/png/baikal.png",
-        alt: "BaiKal",
-        tags: []
-      },
-      {
-        name: "Cryptpad",
-        link: "https://docs.justin.deal",
-        icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/cryptpad.svg",
-        alt: "Cryptpad",
-        tags: []
-      }
-    ],
-    Development: [
-      {
-        name: "Gitea",
-        link: "https://code.justin.deal",
-        icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/gitea.svg",
-        alt: "Gitea",
-        tags: []
-      },
-      {
-        name: "OpenGist",
-        link: "https://snippets.justin.deal",
-        icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/opengist.svg",
-        alt: "OpenGist",
-        tags: []
-      },
-      {
-        name: "IT-Tools",
-        link: "https://tools.justin.deal",
-        icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/it-tools.svg",
-        alt: "IT-Tools",
-        tags: []
-      }
-    ],
-    Media: [
-      {
-        name: "Jellyfin",
-        link: "https://watch.justin.deal",
-        icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/jellyfin.svg",
-        alt: "Jellyfin",
-        tags: []
-      },
-      {
-        name: "Calibre-Web",
-        link: "https://books.justin.deal",
-        icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/calibre-web.svg",
-        alt: "Calibre-Web",
-        tags: []
-      }
-    ],
-    Analytics: [
-      {
-        name: "Uptime Kuma",
-        link: "https://status.justin.deal",
-        icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/uptime-kuma.svg",
-        alt: "Uptime Kuma",
-        tags: []
-      },
-      {
-        name: "Umami",
-        link: "https://analytics.justin.deal",
-        icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/umami.svg",
-        alt: "Umami",
-        tags: []
-      },
-      {
-        name: "TeslaMate",
-        link: "https://tesla.justin.deal",
-        icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/teslamate.svg",
-        alt: "TeslaMate",
-        tags: []
-      },
-    ],
-    Infrastructure: [
-      {
-        name: "Pi-hole",
-        link: "https://pihole.justin.deal",
-        icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/pi-hole.svg",
-        alt: "Pi-hole",
-        tags: []
-      },
-      {
-        name: "Ntfy",
-        link: "https://ntfy.justin.deal",
-        icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/ntfy.svg",
-        alt: "Ntfy",
-        tags: []
-      },
-      {
-        name: "Vaultwarden",
-        link: "https://passwords.justin.deal",
-        icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/vaultwarden.svg",
-        alt: "Vaultwarden",
-        tags: []
-      },
-      {
-        name: "Authentik",
-        link: "https://auth.justin.deal",
-        icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/authentik.svg",
-        alt: "Authentik",
-        tags: []
-      },
-      {
-        name: "Traefik",
-        link: "https://proxy.justin.deal:8080",
-        icon: "https://cdn.jsdelivr.net/gh/selfhst/icons/svg/traefik.svg",
-        alt: "Traefik",
-        tags: []
-      }
-    ]
-  };
+export const services: ServiceCategory = servicesConfig;
diff --git a/src/styles/global.css b/src/styles/global.css
index 6ff7db6..247cd24 100644
--- a/src/styles/global.css
+++ b/src/styles/global.css
@@ -394,6 +394,21 @@
 }
 
 @layer utilities {
+  /* Theme-specific visibility utilities */
+  .light-theme-only {
+    display: block;
+    :where(.dark, .dark *) & {
+      display: none;
+    }
+  }
+
+  .dark-theme-only {
+    display: none;
+    :where(.dark, .dark *) & {
+      display: block;
+    }
+  }
+
   /* Base backgrounds and text */
   .zag-bg {
     background-color: var(--color-zag-light);