PageSourceSearch

https://taubyte.com/

html taubyte.com collected 2026-09-25 21:03:49 UTC 249,988 bytes, 2,402 lines download raw bytes

1<!DOCTYPE html><html lang="en"> <head><meta charset="UTF-8"><meta name="description" content="Taubyte is a fullstack workspace for developers and coding agents, moving software from local creation to production on infrastructure you control."><meta name="viewport" content="width=device-width"><link rel="icon" type="image/svg+xml" href="/favicon.svg"><link rel="canonical" href="https://taubyte.com/"><meta name="generator" content="Astro v5.15.1"><meta property="og:type" content="website"><meta property="og:url" content="https://taubyte.com/"><meta property="og:title" content="Taubyte - Fullstack Workspace for Humans &#38; Machines"><meta property="og:description" content="Taubyte is a fullstack workspace for developers and coding agents, moving software from local creation to production on infrastructure you control."><meta property="og:image" content="https://taubyte.com/screenshots/home-preview.png"><meta property="og:image:width" content="1200"><meta property="og:image:height" content="630"><meta name="twitter:card" content="summary_large_image"><meta name="twitter:title" content="Taubyte - Fullstack Workspace for Humans &#38; Machines"><meta name="twitter:description" content="Taubyte is a fullstack workspace for developers and coding agents, moving software from local creation to production on infrastructure you control."><meta name="twitter:image" content="https://taubyte.com/screenshots/home-preview.png"><meta property="article:modified_time" content="2026-05-10T07:52:12.220Z"><meta property="og:updated_time" content="2026-05-10T07:52:12.220Z"><link rel="alternate" type="application/rss+xml" title="Taubyte — White Papers & Research" href="/rss.xml">
1<script type="application/ld+json">{"@context":"https://schema.org","@type":"WebSite","name":"Taubyte","alternateName":"Taubyte - Fullstack Workspace for Humans & Machines","url":"https://taubyte.com","description":"Taubyte is a fullstack workspace for developers and coding agents, moving software from local creation to production on infrastructure you control.","inLanguage":"en","publisher":{"@id":"https://taubyte.com/#organization"},"dateModified":"2026-05-10T07:52:12.220Z"}</script>
1<script type="application/ld+json">{"@context":"https://schema.org","@type":"Organization","@id":"https://taubyte.com/#organization","name":"Taubyte","url":"https://taubyte.com","description":"Taubyte is a fullstack workspace for developers and coding agents, moving software from local creation to production on infrastructure you control.","logo":{"@type":"ImageObject","url":"https://taubyte.com/taubyte-logo.svg"},"sameAs":["https://github.com/taubyte/tau","https://x.com/dtaubyte","https://www.linkedin.com/company/taubyte-page","https://discord.com/invite/KbN3KN7kpQ","https://www.instagram.com/dtaubyte"],"contactPoint":{"@type":"ContactPoint","contactType":"customer support","url":"https://taubyte.com/contact/"}}</script>
1<script type="application/ld+json">{"@context":"https://schema.org","@type":"FAQPage","mainEntity":[{"@type":"Question","name":"What is Taubyte?","acceptedAnswer":{"@type":"Answer","text":"Taubyte is a fullstack workspace for developers and coding agents that keeps software grounded from local creation to production, then ships and runs it on infrastructure the customer controls."}},{"@type":"Question","name":"Where does Taubyte run?","acceptedAnswer":{"@type":"Answer","text":"Taubyte runs on infrastructure you control: on-prem, private, hybrid, or provider environments, including the edge."}},{"@type":"Question","name":"How does deployment work in Taubyte?","acceptedAnswer":{"@type":"Answer","text":"Taubyte is Git-native. Push to Git and Taubyte handles deployment, routing, scaling, and recovery automatically — every commit moves through one grounded path toward production."}},{"@type":"Question","name":"What can you build with Taubyte?","acceptedAnswer":{"@type":"Answer","text":"Functions, websites, databases, storage, and other infrastructure primitives — all defined in one fullstack workspace and deployed from Git."}},{"@type":"Question","name":"How do I develop and test locally?","acceptedA
1nswer":{"@type":"Answer","text":"Use Dream CLI to spin up a local runtime that mirrors production. Iterate with MCP and desktop tools, then push to Git when ready to ship."}},{"@type":"Question","name":"Is Taubyte open source?","acceptedAnswer":{"@type":"Answer","text":"The Taubyte runtime, tau, is open source and available at github.com/taubyte/tau."}}]}</script>
vendor: 63 bytes, line 1
1<script async src="https://www.googletagmanager.com/gtag/js?id=
1G-1Y0G0GVEQP
vendor: 11 bytes, line 1
1"></script>
1<script>
2      
vendor: 145 bytes, lines 2-5
2window.dataLayer = window.dataLayer || [];
3      function gtag(){dataLayer.push(arguments);}
4      gtag('js', new Date());
5      gtag('config', '
5G-1Y0G0GVEQP
vendor: 8 bytes, lines 5-6
5');
6    
6</script>
6<script>
7      !function(key) {if (window.reb2b) return;window.reb2b = {loaded: true};var s = document.createElement("script");s.async = true;s.src = "https://ddwl4m2hdecbv.cloudfront.net/b/" + key + "/" + key + ".js.gz";document.getElementsByTagName("script")[0].parentNode.insertBefore(s, document.getElementsByTagName("script")[0]);}("DNXY8HDR10O0");
8    </script>
8<script async src="https://t.contentsquare.net/uxa/3c0c3e6933d89.js"></script>
8<script type="module">(function(){try{var h=localStorage.getItem("theme"),m=window.matchMedia&&window.matchMedia("(prefers-color-scheme: light)").matches,l=h||(m?"light":"dark"),t=l==="dark";t?document.documentElement.classList.add("dark"):document.documentElement.classList.remove("dark");var e=document.querySelector('link[rel="icon"]');if(e&&e instanceof HTMLLinkElement){var a=t?'<svg width="120mm" height="120mm" version="1.1" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="m0.64401 10.882c2.0263 11.607 11.55 18.974 20.476 21.646v62.992c0 7.5331 6.0654 13.597 13.598 13.597h16.845l5.8002-21.647h-14.596v-54.942h19.736l5.8002-21.647zm76.444 0-5.8002 21.647h26.421v54.942h-31.561l-5.8002 21.647h45.411c7.5332 0 13.597-6.0642 13.597-13.597v-71.04c0-7.5332-6.064-13.598-13.597-13.598z"/></svg>':'<svg width="120mm" height="120mm" version="1.1" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg"><path fill="#000000" d="m0.64401 10.882c2.0263 11.607 11.55 18.974 20.476 21.646v62.992c0 7.5331 6.0654 13.597 13.598 13.597h16.845l5.8002-21.647h-14.596v-54.942h19.736l5.8002-21.647zm76.444 0-5.8002 21.647h26.421v54.942h-31.561l-5.8002 21.647h45.411c7.5332 0 13.597-6.0642 13.597-13.597v-71.04c0-7.5332-6.064-13.598-13.597-13.598z"/></svg>';e.href="data:image/svg+xml;base64,"+btoa(a)}}catch{}})();</script>
8<title>Taubyte - Fullstack Workspace for Humans &amp; Machines</title><meta name="astro-view-transitions-enabled" content="true"><meta name="astro-view-transitions-fallback" content="animate">
8<script type="module" src="/_astro/ClientRouter.astro_astro_type_script_index_0_lang.elfUsALL.js"></script>
8<style>#mobile-menu-main[data-astro-cid-3ef6ksr2],#mobile-menu-resources[data-astro-cid-3ef6ksr2]{transition:opacity .2s ease,transform .2s ease}#mobile-menu-main[data-astro-cid-3ef6ksr2].hidden,#mobile-menu-resources[data-astro-cid-3ef6ksr2].hidden{display:none}@keyframes astroFadeInOut{0%{opacity:1}to{opacity:0}}@keyframes astroFadeIn{0%{opacity:0;mix-blend-mode:plus-lighter}to{opacity:1;mix-blend-mode:plus-lighter}}@keyframes astroFadeOut{0%{opacity:1;mix-blend-mode:plus-lighter}to{opacity:0;mix-blend-mode:plus-lighter}}@keyframes astroSlideFromRight{0%{transform:translate(100%)}}@keyframes astroSlideFromLeft{0%{transform:translate(-100%)}}@keyframes astroSlideToRight{to{transform:translate(100%)}}@keyframes astroSlideToLeft{to{transform:translate(-100%)}}@media(prefers-reduced-motion){::view-transition-group(*),::view-transition-old(*),::view-transition-new(*){animation:none!important}[data-astro-transition-scope]{animation:none!important}}
9</style>
10<link rel="stylesheet" href="/_astro/about.BMvEtlz4.css">
11<style>:root{--ds-background-100: #000000;--ds-background-200: transparent;--ds-gray-900: #333333;--guide-color: #555;--color: #099a40}.code-tab[data-astro-cid-ynql2ou5]{transition:all .2s ease-in-out;color:#999}
11.code-tab[data-astro-cid-ynql2ou5].active{border-bottom-color:#666;color:#fff}.code-tab[data-astro-cid-ynql2ou5]:hover:not(.active){color:#fff}.code-tab[data-astro-cid-ynql2ou5] svg[data-astro-cid-ynql2ou5]{width:14px;height:14px;display:block}.tab-content[data-astro-cid-ynql2ou5]{display:none;opacity:0;transform:translateY(10px);transition:opacity .3s ease,transform .3s ease}.tab-content[data-astro-cid-ynql2ou5].active{display:block;opacity:1;transform:translateY(0)}.platform-desktop[data-astro-cid-mw4b5lvp]{transition:opacity .4s ease-in-out;opacity:1}.platform-desktop[data-astro-cid-mw4b5lvp].fade-out{opacity:0}.platform-desktop[data-astro-cid-mw4b5lvp].fade-in{opacity:1}.platform-desktop[data-astro-cid-6vxrobne]{transition:opacity .4s ease-in-out}.platform-desktop[data-astro-cid-6vxrobne]:not([data-platform="${platform}"]){display:none}.platform-desktop[data-astro-cid-6vxrobne][data-platform="${platform}"]{opacity:1}
12@keyframes fadeIn{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}.animate-fade-in[data-astro-cid-tkm6qkaw]{animation:fadeIn .3s ease-out}@keyframes slideInUp{0%{opacity:0;transform:translateY(20px)}to{opacity:1;transform:translateY(0)}}@keyframes slideInFromRight{0%{opacity:0;transform:translate(20px)}to{opacity:1;transform:translate(0)}}.floating-avatar-enter[data-astro-cid-tkm6qkaw]{animation:slideInUp .4s ease-out}.floating-message-enter[data-astro-cid-tkm6qkaw]{animation:slideInFromRight .4s ease-out}
13</style>
14<link rel="stylesheet" href="/_astro/index.D2FX36cn.css"></head> <body class="bg-white dark:bg-[#151515] text-black dark:text-white antialiased transition-colors" style="font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif;">  <header class="fixed top-0 left-0 right-0 z-50 bg-white dark:bg-[#151515] transition-colors" id="main-header" data-astro-cid-3ef6ksr2 data-astro-transition-persist="astro-c22sul6k-1">  <nav class="py-3" data-astro-cid-3ef6ksr2> <div class="px-6" data-astro-cid-3ef6ksr2> <div class="container mx-auto max-w-7xl" data-astro-cid-3ef6ksr2> <div class="flex items-center justify-between relative" data-astro-cid-3ef6ksr2> <!-- Logo --> <div class="flex items-center logo-wrapper -ml-2 -mt-1" data-astro-cid-3ef6ksr2> <a href="/" class="block cursor-pointer relative" id="logo-link" aria-label="Taubyte Home" data-astro-cid-3ef6ksr2> <svg class="h-6 w-auto dark:brightness-0 dark:invert" version="1.1" viewBox="0 0 198 41.6" xmlns="http://www.w3.org/2000/svg" data-astro-cid-3ef6ksr2> <defs data-astro-cid-3ef6ksr2> <style>
15                svg:hover .logo-right { opacity: 0.3; transition: opacity 0.5s ease; }
16                .logo-right { transition: opacity 0.5s ease; }
17              </style> </defs> <g transform="matrix(1,0,0,0.998,0,-255)" stroke-width="0.179px" aria-label="taubyte" style="fill:#101010;fill-opacity:1" data-astro-cid-3ef6ksr2> <path d="m 69.1,287 q -0.688,0.619 -1.69,0.963 -0.998,0.31 -2.1,0.31 -2.55,0 -3.92,-1.38 -1.38,-1.38 -1.38,-3.89 v -17 h 2.44 v 3.96 h 5.47 v 2.06 h -5.47 v 10.8 q 0,1.62 0.791,2.48 0.791,0.826 2.3,0.826 1.65,0 2.68,-0.929 z" style="fill:#101010;fill-opacity:1" data-astro-cid-3ef6ksr2></path> <path d="m 89.9,270 v 18.1 h -2.34 v -3.58 q -1.1,1.82 -2.92,2.79 -1.79,0.963 -4.06,0.963 -2.55,0 -4.61,-1.17 -2.06,-1.17 -3.23,-3.27 -1.17,-2.1 -1.17,-4.78 0,-2.68 1.17,-4.78 1.17,-2.1 3.23,-3.23 2.06,-1.17 4.61,-1.17 2.2,0 3.96,0.929 1.79,0.894 2.92,2.65 v -3.44 z m -9.12,16.1 q 1.89,0 3.41,-0.86 1.55,-0.894 2.41,-2.51 0.894,-1.62 0.894,-3.68 0,-2.06 -0.894,-3.68 -0.86,-1.62 -2.41,-2.48 -1.51,-0.894 -3.41,-0.894 -1.93,0 -3.47,0.894 -1.51,0.86 -2.41,2.48 -0.86,1.62 -0.86,3.68 0,2.06 0.86,3.68 0.894,1.62 2.41,2.51 1.55,0.86 3.47,0.86 z" style="fill:#101010;fill-opacity:1" data-astro-cid-3ef6ksr2></path> <path d="m 113,270 v 18.1 h -2.34 v -3.3 q -0.963,1.65 -2.65,2.58 -1.69,0.894 -3.85,0.894 -3.54,0 -5.61,-1.96 -2.03,-2 -2.03,-5.81 v -10.5 h 2.44 v 10.3 q 0,2.86 1.41,4.33 1.41,1.47 4.02,1.48 2.86,0 4.51,-1.72 1.65,-1.75 1.65,-4.85 v -9.49 z" style="fill:#101010;fill-opacity:1" data-astro-cid-3ef6ksr2></path> <path d="m 130,269 q 2.55,0 4.61,1.17 2.06,1.14 3.23,3.23 1.17,2.1 1.17,4.78 0,2.68 -1.17,4.78 -1.17,2.1 -3.23,3.27 -2.06,1.17 -4.61,1.17 -2.27,0 -4.09,-0.963 -1.79,-0.963 -2.89,-2.79 v 3.58 h -2.34 v -25.5 h 2.44 v 10.9 q 1.14,-1.75 2.89,-2.65 1.79,-0.929 3.99,-0.929 z m -0.172,16.2 q 1.89,0 3.44,-0.86 1.55,-0.894 2.41,-2.51 0.894,-1.62 0.894,-3.68 0,-2.06 -0.894,-3.68 -0.86,-1.62 -2.41,-2.48 -1.55,-0.894 -3.44,-0.894 -1.93,0 -3.47,0.894 -1.51,0.86 -2.41,2.48 -0.86,1.62 -0.86,3.68 0,2.06 0.86,3.68 0.894,1.62 2.41,2.51 1.55,0.86 3.47,0.86 z" style="fill:#101010;fill-opacity:1" data-astro-cid-3ef6ksr2></path> <path d="m 161,270 v 15.9 q 0,4.61 -2.1,6.81 -2.1,2.24 -6.33,2.24 -2.37,0 -4.51,-0.757 -2.1,-0.722 -3.41,-2.03 l 1.24,-1.86 q 1.17,1.17 2.89,1.82 1.72,0.654 3.68,0.654 3.13,0 4.61,-1.62 1.48,-1.58 1.48,-4.95 v -2.1 q -0.963,1.58 -2.65,2.44 -1.65,0.86 -3.75,0.86 -3.54,0 -5.61,-1.96 -2.03,-2 -2.03,-5.81 v -9.63 h 2.44 v 9.39 q 0,2.86 1.41,4.33 1.41,1.47 4.02,1.48 2.86,0 4.51,-1.72 1.65,-1.75 1.65,-4.85 v -8.63 z" style="fill:#101010;fill-opacity:1" data-astro-cid-3ef6ksr2></path> <path d="m 177,287 q -0.688,0.619 -1.69,0.963 -0.998,0.31 -2.1,0.31 -2.55,0 
17-3.92,-1.38 -1.37,-1.38 -1.38,-3.89 v -17 h 2.44 v 3.96 h 5.47 v 2.06 h -5.47 v 10.8 q 0,1.62 0.791,2.48 0.791,0.826 2.3,0.826 1.65,0 2.68,-0.929 z" style="fill:#101010;fill-opacity:1" data-astro-cid-3ef6ksr2></path> <path d="m 189,286 q 1.69,0 3.1,-0.585 1.44,-0.619 2.44,-1.79 l 1.38,1.58 q -1.2,1.44 -2.99,2.2 -1.79,0.757 -3.96,0.757 -2.79,0 -4.95,-1.17 -2.17,-1.2 -3.37,-3.3 -1.2,-2.1 -1.2,-4.75 0,-2.65 1.14,-4.75 1.17,-2.1 3.2,-3.27 2.03,-1.17 4.61,-1.17 2.41,0 4.33,1.1 1.96,1.1 3.1,3.06 1.17,1.96 1.24,4.47 l -14.9,2.89 q 0.688,2.2 2.48,3.47 1.82,1.24 4.33,1.24 z m -0.619,-14.1 q -1.89,0 -3.41,0.894 -1.48,0.86 -2.34,2.44 -0.826,1.55 -0.826,3.58 0,0.516 0.0344,0.757 l 12.8,-2.48 q -0.413,-2.27 -2.1,-3.72 -1.69,-1.48 -4.13,-1.48 z" style="fill:#101010;fill-opacity:1" data-astro-cid-3ef6ksr2></path> </g> <g class="logo-container" data-astro-cid-3ef6ksr2> <path class="logo-left" d="M 0,4.2347e-4 C 0.858687,4.9191349 4.894556,8.0410561 8.677137,9.1733727 V 35.867559 c 0,3.192311 2.57034,5.762016 5.762438,5.762016 H 21.578 l 2.457956,-9.173372 H 17.850593 V 9.1733727 h 8.363546 L 28.672096,0 Z" style="stroke-width:0.423772;fill:#101010;fill-opacity:1;" data-astro-cid-3ef6ksr2></path> <path class="logo-right" d="m 32.394755,4.2347e-4 -2.457956,9.17337283 h 11.196452 v 23.2832522 H 27.758616 L 25.300658,41.63 h 19.243867 c 3.192354,0 5.762017,-2.569834 5.762017,-5.762016 V 5.7632873 c 0,-3.1923524 -2.569749,-5.76244035 -5.762017,-5.76244035 z" style="stroke-width:0.423772;fill:#101010;fill-opacity:1;" data-astro-cid-3ef6ksr2></path> </g> </svg> </a> </div> <!-- Desktop Navigation Links --> <div class="hidden md:flex items-center space-x-8 absolute left-1/2 -translate-x-1/2" data-astro-cid-3ef6ksr2> <a href="/features" class="text-sm text-black dark:text-white hover:text-gray-400 dark:hover:text-gray-300 transition-colors" data-astro-cid-3ef6ksr2>Features</a> <a href="/enterprise" class="text-sm text-black dark:text-white hover:text-gray-400 dark:hover:text-gray-300 transition-colors" data-astro-cid-3ef6ksr2>Enterprise</a> <!-- Resources Dropdown --> <div class="relative" onmouseenter="showResourcesDropdown()" onmouseleave="hideResourcesDropdown()" data-astro-cid-3ef6ksr2> <button id="resources-desktop-button" class="text-sm text-black dark:text-white hover:text-gray-400 dark:hover:text-gray-300 transition-colors flex items-center gap-1" aria-expanded="false" aria-haspopup="true" data-astro-cid-3ef6ksr2>
18Resources
19<svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24" data-astro-cid-3ef6ksr2> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 9l-7 7-7-7" data-astro-cid-3ef6ksr2></path> </svg> </button> <div id="resources-desktop-dropdown" class="hidden absolute top-full left-0 pt-2 w-80 bg-transparent z-50" onmouseenter="showResourcesDropdown()" onmouseleave="hideResourcesDropdown()" data-astro-cid-3ef6ksr2> <div class="bg-white/95 dark:bg-[#151515]/95 backdrop-blur-md rounded-lg border border-black/10 dark:border-white/10 py-2" data-astro-cid-3ef6ksr2> <div class="grid grid-cols-2 gap-0" data-astro-cid-3ef6ksr2> <a href="/blog" class="block px-4 py-2 text-sm text-black dark:text-white hover:text-gray-400 dark:hover:text-gray-300 transition-colors" data-astro-cid-3ef6ksr2>Blog</a> <a href="/doc" class="block px-4 py-2 text-sm text-black dark:text-white hover:text-gray-400 dark:hover:text-gray-300 transition-colors" data-astro-cid-3ef6ksr2>Documentation</a> <a href="/white-papers" class="block px-4 py-2 text-sm text-black dark:text-white hover:text-gray-400 dark:hover:text-gray-300 transition-colors" data-astro-cid-3ef6ksr2>White Papers</a> <a href="/community" class="block px-4 py-2 text-sm text-black dark:text-white hover:text-gray-400 dark:hover:text-gray-300 transition-colors" data-astro-cid-3ef6ksr2>Community</a> </div> </div> </div> </div> </div> <!-- Desktop CTA Buttons --> <div class="hidden md:flex items-center space-x-2" data-astro-cid-3ef6ksr2> <a href="https://console.taubyte.com" target="_blank" class="px-2.5 py-1 rounded-full border border-black text-black hover:bg-gray-100 dark:border-white dark:text-white dark:hover:bg-white/10 text-sm font-medium transition-colors" data-webmcp-toolname="signin-console" data-webmcp-tooldescription="Sign in to the Taubyte cloud console." data-astro-cid-3ef6ksr2>
20Sign in
21</a> <a href="/book-a-demo" class="px-2.5 py-1 rounded-full bg-black text-white dark:bg-white dark:text-black text-sm font-medium hover:bg-black/90 dark:hover:bg-white/90 hover:text-white dark:hover:text-black no-underline transition-colors" data-webmcp-toolname="book-demo" data-webmcp-tooldescription="Schedule a technical demo with the Taubyte team." data-astro-cid-3ef6ksr2>
22Book a demo <i class="ri-arrow-right-up-line" data-astro-cid-3ef6ksr2></i> </a> </div> <!-- Mobile Hamburger Button --> <div class="flex md:hidden items-center" data-astro-cid-3ef6ksr2> <button id="mobile-menu-button" type="button" class="inline-flex items-center justify-center p-2 rounded-md text-black dark:text-white hover:bg-gray-100 dark:hover:bg-white/10 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white" aria-controls="mobile-menu" aria-expanded="false" onclick="toggleMobileMenu()" data-astro-cid-3ef6ksr2> <span class="sr-only" data-astro-cid-3ef6ksr2>
22Open main menu</span> <!-- Hamburger Icon --> <svg id="hamburger-icon" class="block h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" data-astro-cid-3ef6ksr2> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 6h16M4 12h16M4 18h16" data-astro-cid-3ef6ksr2></path> </svg> <!-- Close Icon --> <svg id="close-icon" class="hidden h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" data-astro-cid-3ef6ksr2> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" data-astro-cid-3ef6ksr2></path> </svg> </button> </div> </div> </div> </div></nav> <!-- Mobile Menu Backdrop --> <div id="mobile-menu-backdrop" class="hidden md:hidden fixed inset-0 bg-black/50 dark:bg-black/70 z-40 transition-opacity duration-300" onclick="toggleMobileMenu()" data-astro-cid-3ef6ksr2></div> <!-- Mobile Menu --> <div id="mobile-menu" class="hidden md:hidden fixed inset-0 z-50 bg-white dark:bg-[#1a1a1a] overflow-hidden" data-astro-cid-3ef6ksr2> <!-- Main Menu --> <div id="mobile-menu-main" class="h-full flex flex-col" data-astro-cid-3ef6ksr2> <div class="flex justify-end p-6" data-astro-cid-3ef6ksr2> <button onclick="toggleMobileMenu()" class="inline-flex items-center justify-center p-2 rounded-md text-black dark:text-white hover:opacity-70 focus:outline-none transition-opacity" aria-label="Close menu" data-astro-cid-3ef6ksr2> <svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" data-astro-cid-3ef6ksr2> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" data-astro-cid-3ef6ksr2></path> </svg> </button> </div> <div class="flex-1 overflow-y-auto px-6 pb-12" data-astro-cid-3ef6ksr2> <nav class="space-y-8" data-astro-cid-3ef6ksr2> <a href="/features" class="block text-2xl md:text-3xl font-normal text-black dark:text-white hover:opacity-70 transition-opacity" onclick="toggleMobileMenu()" data-astro-cid-3ef6ksr2>
23Features
24</a> <a href="/enterprise" class="block text-2xl md:text-3xl font-normal text-black dark:text-white hover:opacity-70 transition-opacity" onclick="toggleMobileMenu()" data-astro-cid-3ef6ksr2>
25Enterprise
26</a> <button id="resources-mobile-button" onclick="showResourcesSubmenu()" class="flex w-full text-left text-2xl md:text-3xl font-normal text-black dark:text-white hover:opacity-70 transition-opacity items-center justify-between" data-astro-cid-3ef6ksr2> <span data-astro-cid-3ef6ksr2>Resources</span> <i class="ri-arrow-right-s-line text-xl" data-astro-cid-3ef6ksr2></i> </button> <a href="#signin" class="block text-2xl md:text-3xl font-normal text-black dark:text-white hover:opacity-70 transition-opacity" onclick="toggleMobileMenu()" data-astro-cid-3ef6ksr2>
27Sign in
28</a> <a href="/book-a-demo" class="flex px-6 py-3 rounded-full bg-white dark:bg-white text-black font-normal text-xl md:text-2xl hover:opacity-90 transition-opacity items-center gap-2 mt-4" onclick="toggleMobileMenu()" data-astro-cid-3ef6ksr2>
29Book a demo
30<i class="ri-arrow-right-up-line text-xl" data-astro-cid-3ef6ksr2></i> </a> </nav> </div> </div> <!-- Resources Submenu Page --> <div id="mobile-menu-resources" class="hidden h-full" data-astro-cid-3ef6ksr2> <div class="flex justify-end p-6" data-astro-cid-3ef6ksr2> <button onclick="toggleMobileMenu()" class="inline-flex items-center justify-center p-2 rounded-md text-black dark:text-white hover:opacity-70 focus:outline-none transition-opacity" aria-label="Close menu" data-astro-cid-3ef6ksr2> <svg class="h-6 w-6" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" data-astro-cid-3ef6ksr2> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12" data-astro-cid-3ef6ksr2></path> </svg> </button> </div> <div class="flex-1 overflow-y-auto px-6 pb-12" data-astro-cid-3ef6ksr2> <button onclick="showMainMenu()" class="mb-8 text-lg font-normal text-black dark:text-white hover:opacity-70 transition-opacity flex items-center gap-2" data-astro-cid-3ef6ksr2> <i class="ri-arrow-left-s-line text-xl" data-astro-cid-3ef6ksr2></i> <span data-astro-cid-3ef6ksr2>Back</span> </button> <nav class="space-y-8" data-astro-cid-3ef6ksr2> <a href="/blog" class="block text-2xl md:text-3xl font-normal text-black dark:text-white hover:opacity-70 transition-opacity" onclick="toggleMobileMenu()" data-astro-cid-3ef6ksr2>
31Blog
32</a> <a href="/doc" class="block text-2xl md:text-3xl font-normal text-black dark:text-white hover:opacity-70 transition-opacity" onclick="toggleMobileMenu()" data-astro-cid-3ef6ksr2>
33Documentation
34</a> <a href="/white-papers" class="block text-2xl md:text-3xl font-normal text-black dark:text-white hover:opacity-70 transition-opacity" onclick="toggleMobileMenu()" data-astro-cid-3ef6ksr2>
35White Papers
36</a> <a href="/community" class="block text-2xl md:text-3xl font-normal text-black dark:text-white hover:opacity-70 transition-opacity" onclick="toggleMobileMenu()" data-astro-cid-3ef6ksr2>
37Community
38</a> </nav> </div> </div> </div> </header> 
38<script>
39  function toggleMobileMenu() {
40    const menu = document.getElementById('mobile-menu');
41    const button = document.getElementById('mobile-menu-button');
42    const hamburgerIcon = document.getElementById('hamburger-icon');
43    const closeIcon = document.getElementById('close-icon');
44    const mainMenu = document.getElementById('mobile-menu-main');
45    const resourcesMenu = document.getElementById('mobile-menu-resources');
46    const isOpen = !menu?.classList.contains('hidden');
47    
48    if (isOpen) {
49      menu?.classList.add('hidden');
50      hamburgerIcon?.classList.remove('hidden');
51      hamburgerIcon?.classList.add('block');
52      closeIcon?.classList.add('hidden');
53      closeIcon?.classList.remove('block');
54      button?.setAttribute('aria-expanded', 'false');
55      // Reset to main menu
56      showMainMenu();
57      // Re-enable body scrolling
58      document.body.style.overflow = '';
59    } else {
60      menu?.classList.remove('hidden');
61      hamburgerIcon?.classList.add('hidden');
62      hamburgerIcon?.classList.remove('block');
63      closeIcon?.classList.remove('hidden');
64      closeIcon?.classList.add('block');
65      button?.setAttribute('aria-expanded', 'true');
66      // Show main menu
67      showMainMenu();
68      // Prevent body scrolling when menu is open
69      document.body.style.overflow = 'hidden';
70    }
71  }
72
73  function showMainMenu() {
74    const mainMenu = document.getElementById('mobile-menu-main');
75    const resourcesMenu = document.getElementById('mobile-menu-resources');
76    
77    if (mainMenu) mainMenu.classList.remove('hidden');
78    if (resourcesMenu) {
79      resourcesMenu.classList.add('hidden');
80      resourcesMenu.classList.remove('flex', 'flex-col');
81    }
82  }
83
84  function showResourcesSubmenu() {
85    const mainMenu = document.getElementById('mobile-menu-main');
86    const resourcesMenu = document.getElementById('mobile-menu-resources');
87    
88    if (mainMenu) mainMenu.classList.add('hidden');
89    if (resourcesMenu) {
90      resourcesMenu.classList.remove('hidden');
91      resourcesMenu.classList.add('flex', 'flex-col');
92    }
93  }
94
95  // Desktop Resources Dropdown
96  let resourcesDropdownTimeout = null;
97
98  function showResourcesDropdown() {
99    const dropdown = document.getElementById('resources-desktop-dropdown');
100    const button = document.getElementById('resources-desktop-button');
101    
102    // Clear any pending hide timeout
103    if (resourcesDropdownTimeout) {
104      clearTimeout(resourcesDropdownTimeout);
105      resourcesDropdownTimeout = null;
106    }
107    
108    if (dropdown && button) {
109      dropdown.classList.remove('hidden');
110      button.classList.add('text-gray-400', 'dark:text-gray-300');
111      button.classList.remove('text-black', 'dark:text-white');
112      button.setAttribute('aria-expanded', 'true');
113    }
114  }
115
116  function hideResourcesDropdown() {
117    const dropdown = document.getElementById('resources-desktop-dropdown');
118    const button = document.getElementById('resources-desktop-button');
119    
120    // Clear any existing timeout
121    if (resourcesDropdownTimeout) {
122      clearTimeout(resourcesDropdownTimeout);
123    }
124    
125    // Add a small delay before hiding to make it easier to catch
126    resourcesDropdownTimeout = setTimeout(() => {
127      if (dropdown && button) {
128        dropdown.classList.add('hidden');
129        button.classList.remove('text-gray-400', 'dark:text-gray-300');
130        button.classList.add('text-black', 'dark:text-white');
131        button.setAttribute('aria-expanded', 'false');
132      }
133      resourcesDropdownTimeout = null;
134    }, 150);
135  }
136
137
138</script>
138 <main> <section id="hero-section" class="relative pt-24 pb-12 px-6 bg-white dark:bg-[#151515] transition-colors"> <div class="container mx-auto max-w-7xl"> <!-- Main Heading --> <div class="mb-16 mt-8"> <h1 class="text-lg md:text-xl lg:text-2xl font-normal leading-tight mb-6 max-w-4xl text-black dark:text-white transition-colors">
139Fullstack workspace for humans and machines.
140</h1> <p class="text-base md:text-lg text-black/70 dark:text-white/70 max-w-3xl mb-8">
141Taubyte keeps software grounded from local creation to production, then ships and runs it on infrastructure you control.
142</p> <a href="/download?os=linux&binary=dream" class="hidden md:inline-flex items-center gap-2 px-6 py-3 bg-black dark:bg-white text-white dark:text-black text-sm font-medium rounded-full hover:bg-black/90 dark:hover:bg-white/90 hover:text-white dark:hover:text-black no-underline transition-colors" id="hero-download-btn" data-webmcp-toolname="download-taubyte" data-webmcp-tooldescription="Download Taubyte and the Dream CLI for local development."> <span id="hero-download-text">Download for Linux</span> <i class="ri-download-line"></i> </a> 
142<script type="module" src="/_astro/DownloadButton.astro_astro_type_script_index_0_lang.D1cddKQx.js"></script>
142 <a href="/getting-started" class="inline-flex items-center px-6 py-3 border-1 border-black dark:border-white text-black dark:text-white bg-transparent text-sm font-medium rounded-full hover:bg-gray-100 dark:hover:bg-white/10 no-underline transition-colors md:ml-3 ml-0" id="hero-documentation-btn" data-webmcp-toolname="get-started-guide" data-webmcp-tooldescription="Open the step-by-step Taubyte getting-started guide.">
143Step-by-step
144</a> </div> <!-- Demo Container --> <div class="relative hidden lg:block"> <!-- Demo Container --><div class="relative overflow-visible" style="height: min(650px, 60vh); min-height: 600px;" data-astro-cid-6vxrobne> <!-- Desktop Instances for each platform --> <!-- Your Cloud Desktop --><div class="platform-desktop absolute inset-0 flex flex-col items-center justify-center z-1" data-platform="your-cloud" style="display: block;" data-astro-cid-ynql2ou5> <!-- Desktop Background with border and gradient --> <div class="absolute inset-0 bg-gradient-to-t from-[#0f0f0f] via-[#151515] to-[#1a1a1a] rounded-2xl border border-white/10 desktop-background" data-platform="your-cloud" data-astro-cid-ynql2ou5></div> <!-- Content --> <div class="relative w-full h-full flex justify-center items-start pt-24" data-astro-cid-ynql2ou5> <!-- Code viewer window --> <div class="absolute top-12 z-10 bg-[#1a1a1a] rounded-lg w-96 md:w-[28rem] shadow-[0_35px_60px_-12px_rgba(0,0,0,0.5)] border border-white/10 overflow-hidden" data-astro-cid-ynql2ou5> <!-- Window title bar --> <div class="flex items-center justify-between px-4 py-1.5 bg-[#222] border-b border-white/10" data-astro-cid-ynql2ou5> <div class="flex items-center gap-1" data-astro-cid-ynql2ou5> <span class="w-2.5 h-2.5 rounded-full bg-white/20" data-astro-cid-ynql2ou5></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20" data-astro-cid-ynql2ou5></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20" data-astro-cid-ynql2ou5></span> </div> <div class="text-xs text-white/60" data-astro-cid-ynql2ou5>&nbsp;</div> <div class="w-20" data-astro-cid-ynql2ou5></div> </div> <!-- Tabs --> <div class="flex border-b border-white/10" role="tablist" aria-label="Code examples" data-astro-cid-ynql2ou5> <button type="button" class="code-tab px-3 py-2 text-xs font-mono border-b-2 border-transparent transition-colors cursor-pointer flex items-center gap-1.5 hover:bg-white/5 active" role="tab" aria-selected="true" aria-controls="tab-panel-ai" id="tab-ai" data-tab-id="ai" data-astro-cid-ynql2ou5> <span data-astro-cid-ynql2ou5><svg width="24" height="24" fill="currentColor" viewBox="0 0 32 32"><path d="M 16 1 C 14.894531 1 14 1.894531 14 3 C 14 3.738281 14.402344 4.371094 15 4.71875 L 15 7 L 10 7 C 7.25 7 5 9.25 5 12 L 5 14 L 2 14 L 2 22 L 5 22 L 5 27 L 27 27 L 27 22 L 30 22 L 30 14 L 27 14 L 27 12 C 27 9.25 24.75 7 22 7 L 17 7 L 17 4.71875 C 17.597656 4.371094 18 3.738281 18 3 C 18 1.894531 17.105469 1 16 1 Z M 10 9 L 22 9 C 23.667969 9 25 10.332031 25 12 L 25 25 L 23 25 L 23 20 L 9 20 L 9 25 L 7 25 L 7 12 C 7 10.332031 8.332031 9 10 9 Z M 12 13 C 10.894531 13 10 13.894531 10 15 C 10 16.105469 10.894531 17 12 17 C 13.105469 17 14 16.105469 14 15 C 14 13.894531 13.105469 13 12 13 Z M 20 13 C 18.894531 13 18 13.894531 18 15 C 18 16.105469 18.894531 17 20 17 C 21.105469 17 22 16.105469 22 15 C 22 13.894531 21.105469 13 20 13 Z M 4 16 L 5 16 L 5 20 L 4 20 Z M 27 16 L 28 16 L 28 20 L 27 20 Z M 11 22 L 13 22 L 13 25 L 11 25 Z M 15 22 L 17 22 L 17 25 L 15 25 Z M 19 22 L 21 22 L 21 25 L 19 25 Z"/></svg></span> AI </button><button type="button" class="code-tab px-3 py-2 text-xs font-mono border-b-2 border-transparent transition-colors cursor-pointer flex items-center gap-1.5 hover:bg-white/5 " role="tab" aria-selected="false" aria-controls="tab-panel-cli" id="tab-cli" data-tab-id="cli" data-astro-cid-ynql2ou5> <span data-astro-cid-ynql2ou5><svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M6 17L11 12L6 7M13 17H20" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span> CLI </button><button type="button" class="code-tab px-3 py-2 text-xs font-mono border-b-2 border-transparent transition-colors cursor-pointer flex items-center gap-1.5 hover:bg-white/5 " role="tab" aria-selected="false" aria-controls="tab-panel-code" id="tab-code" data-tab-id="code" data-astro-cid-ynql2ou5> <span data-astro-cid-ynql2ou5>
144<svg width="16" height="16" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M7 8L3 12L7 16M17 8L21 12L17 16M14 4L10 20" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/></svg></span> Code </button> </div> <!-- Tab content --> <div class="p-4 bg-[#1a1a1a] rounded-b-lg" data-astro-cid-ynql2ou5> <div class="tab-content active" role="tabpanel" aria-labelledby="tab-ai" id="tab-panel-ai" data-tab-panel="ai" data-astro-cid-ynql2ou5> <div class="text-left" data-astro-cid-ynql2ou5> 
145      <div class="space-y-2 text-xs font-mono text-white">
146        <!-- User message -->
147        <div class="flex items-start gap-2">
148          <div class="shrink-0">
149            <svg width="24" height="24" fill="none" stroke="white" stroke-width="1.5" viewBox="0 0 24 24">
150              <circle cx="12" cy="12" r="10" />
151              <circle cx="12" cy="10" r="4" />
152              <path d="M6 18a6 6 0 0 1 12 0" />
153            </svg>
154          </div>
155          <p class="rounded-xl border border-[#2a2a2a] px-3 py-1 text-white">Add 1.2.3.4 as a compute host</p>
156        </div>
157        
158        <!-- AI messages -->
159        <div class="flex justify-end">
160          <p class="text-gray-400 py-0.5 animate-pulse" id="ai-thinking">Thinking...</p>
161        </div>
162        
163        <div class="flex justify-end">
164          <div class="rounded-xl border border-[#2a2a2a] px-3 py-1 flex items-center gap-3 text-white">
165            <span>Run <span class="font-semibold">spore-drive displace</span>?</span>
166            <div class="flex gap-1">
167                <span class="px-2 py-1 text-xs rounded border border-[#2a2a2a] bg-[#1a1a1a] text-white">Reject</span>
168              <span class="px-2 py-1 text-xs rounded border border-[#2a2a2a] bg-[#2a2a2a] text-white">Accept</span>
169            </div>
170          </div>
171        </div>
172      </div>
173     </div> </div><div class="tab-content " role="tabpanel" aria-labelledby="tab-cli" id="tab-panel-cli" data-tab-panel="cli" data-astro-cid-ynql2ou5> <pre class="text-left text-gray-300 font-mono text-xs leading-relaxed whitespace-pre-wrap" data-astro-cid-ynql2ou5>$ spore new cloud --fqdn ...
174$ spore add host ...
175$ spore displace</pre> </div><div class="tab-content " role="tabpanel" aria-labelledby="tab-code" id="tab-panel-code" data-tab-panel="code" data-astro-cid-ynql2ou5> <pre class="text-left text-gray-300 font-mono text-xs leading-relaxed whitespace-pre-wrap" data-astro-cid-ynql2ou5>import "@taubyte/spore-drive";
176const config = new Config("...");
177const drive = new Drive(config, TauLatest);
178await drive.displace();</pre> </div> </div> </div> <!-- Wireframe cloud SVG --> <svg aria-hidden="true" height="70%" viewBox="-1 -1 802 402" width="100%" class="absolute bottom-0 left-0 right-0" data-astro-cid-ynql2ou5> <g data-testid="globe-wireframe" mask="url(#fade-mask)" data-astro-cid-ynql2ou5> <circle cx="400" cy="400" fill="var(--ds-background-200)" r="400" data-astro-cid-ynql2ou5></circle> <path d="M 400 800 A -400 400 0 0 0 400 0" fill="none" stroke="url(#globe-gradient)" stroke-width="1" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path><path d="M 400 800 A -328.701 400 0 0 0 400 0" fill="none" stroke="url(#globe-gradient)" stroke-width="1" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path><path d="M 400 800 A -235.355 400 0 0 0 400 0" fill="none" stroke="url(#globe-gradient)" stroke-width="1" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path><path d="M 400 800 A -123.097 400 0 0 0 400 0" fill="none" stroke="url(#globe-gradient)" stroke-width="1" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path><path d="M 400 800 A 0 400 0 0 0 400 0" fill="none" stroke="url(#globe-gradient)" stroke-width="1" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path><path d="M 400 0 A 123.097 400 0 0 0 400 800" fill="none" stroke="url(#globe-gradient)" stroke-width="1" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path><path d="M 400 0 A 235.355 400 0 0 0 400 800" fill="none" stroke="url(#globe-gradient)" stroke-width="1" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path><path d="M 400 0 A 328.701 400 0 0 0 400 800" fill="none" stroke="url
178(#globe-gradient)" stroke-width="1" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path><path d="M 400 0 A 400 400 0 0 0 400 800" fill="none" stroke="url(#globe-gradient)" stroke-width="1" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path><path d="M160,80 h480" fill="none" stroke="url(#globe-gradient)" stroke-width="1" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path><path d="M80,160 h640" fill="none" stroke="url(#globe-gradient)" stroke-width="1" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path><path d="M33.394,240 h733.212" fill="none" stroke="url(#globe-gradient)" stroke-width="1" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path><path d="M8.082,320 h783.837" fill="none" stroke="url(#globe-gradient)" stroke-width="1" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path><path d="M0,400 h800" fill="none" stroke="url(#globe-gradient)" stroke-width="1" vector-effect="non-scaling-stroke" stroke-opacity="0" data-astro-cid-ynql2ou5></path><path d="M8.082,480 h783.837" fill="none" stroke="url(#globe-gradient)" stroke-width="1" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path><path d="M33.394,560 h733.212" fill="none" stroke="url(#globe-gradient)" stroke-width="1" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path><path d="M80,640 h640" fill="none" stroke="url(#globe-gradient)" stroke-width="1" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path><path d="M160,720 h480" fill="none" stroke="url(#globe-gradient)" stroke-width="1" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path> </g> <g data-testid="globe-nodes" data-astro-cid-ynql2ou5> <g data-testid="dynamic-node-0" data-astro-cid-ynql2ou5>  <defs data-astro-cid-ynql2ou5> <radialGradient id="conn-grad-0" gradientUnits="userSpaceOnUse" r="0" style="--normal-color: #45DEC4;" data-astro-cid-ynql2ou5> <stop offset="0" stop-color="var(--color)" data-astro-cid-ynql2ou5></stop> <stop offset="0.4" stop-color="var(--color)" data-astro-cid-ynql2ou5></stop> <stop offset="1" stop-color="var(--color)" stop-opacity="0" data-astro-cid-ynql2ou5></stop> <animate attributeName="cx" dur="4.5s" repeatCount="indefinite" keyTimes="0;1;1" values="400;597.2206;597.2206" data-astro-cid-ynql2ou5></animate> <animate attributeName="cy" dur="4.5s" repeatCount="indefinite" keyTimes="0;1;1" values="0;80;80" data-astro-cid-ynql2ou5></animate> <animate attributeName="r" dur="4.5s" repeatCount="indefinite" keyTimes="0;0.5;0.5;1" values="0;120;120;0" data-astro-cid-ynql2ou5></animate> </radialGradient> </defs> <path d="M 400 0 A 328.701 400 0 0 1 597.2206 80" fill="none" stroke="url(#conn-grad-0)" stroke-width="3" stroke-linecap="round" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path> <!-- Chip-shaped glow animation --> <g transform="translate(597.2206, 80)" data-astro-cid-ynql2ou5> <rect x="-12" y="-12" width="24" height="24" rx="3" fill="none" stroke="var(--color)" stroke-width="2" opacity="0" data-astro-cid-ynql2ou5> <animate attributeName="opacity" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="0;1;0.5;0;0;0" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="width" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="24;32;40;48;24;24" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="height" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="24;32;40;48;24;24" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="x" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="-12;-16;-20;-24;-12;-12" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="y" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="-12;-16;-20;-24;-12;-12" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> </rect> </g> <rect x="581.2206" y="64" width="32" height="32" rx="4" fill="#151515" stroke="url(#node-gradient)" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></rect> <!-- Chip icon --> <g transform="translate(590.2206, 73)" fill="white" stroke="white" data-astro-cid-ynql2ou5> <!-- Chip body --> <rect x="0" y="0" width="14" height="14" rx="2" fill="none" stroke-width="1.2" data-astro-cid-ynql2ou5></rect> <!-- Central processor area --> <rect x="3" y="3" width="8" height="8" rx="1" fill="none" stroke-width="0.8" data-astro-cid-ynql2ou5></rect>
178 <!-- Circuit lines --> <line x1="3" y1="6" x2="1" y2="6" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="3" y1="8" x2="1" y2="8" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="13" y1="6" x2="11" y2="6" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="13" y1="8" x2="11" y2="8" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="6" y1="3" x2="6" y2="1" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="8" y1="3" x2="8" y2="1" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="6" y1="13" x2="6" y2="11" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="8" y1="13" x2="8" y2="11" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <!-- Pin connections --> <circle cx="1" cy="6" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="1" cy="8" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="13" cy="6" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="13" cy="8" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="6" cy="1" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="8" cy="1" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="6" cy="13" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="8" cy="13" r="0.4" data-astro-cid-ynql2ou5></circle> </g> </g><g data-testid="dynamic-node-1" data-astro-cid-ynql2ou5>  <defs data-astro-cid-ynql2ou5> <radialGradient id="conn-grad-1" gradientUnits="userSpaceOnUse" r="0" style="--normal-color: #45DEC4;" data-astro-cid-ynql2ou5> <stop offset="0" stop-color="var(--color)" data-astro-cid-ynql2ou5></stop> <stop offset="0.4" stop-color="var(--color)" data-astro-cid-ynql2ou5></stop> <stop offset="1" stop-color="var(--color)" stop-opacity="0" data-astro-cid-ynql2ou5></stop> <animate attributeName="cx" dur="4.5s" repeatCount="indefinite" keyTimes="0;0.8117686738908175;1;1" values="400;169.40013663490606;77.94010882297061;77.94010882297061" data-astro-cid-ynql2ou5></animate> <animate attributeName="cy" dur="4.5s" repeatCount="indefinite" keyTimes="0;0.8117686738908175;1;1" values="0;320;320;320" data-astro-cid-ynql2ou5></animate> <animate attributeName="r" dur="4.5s" repeatCount="indefinite" keyTimes="0;0.5;0.5;1" values="0;120;120;0" data-astro-cid-ynql2ou5></animate> </radialGradient> </defs> <path d="M 400 0 A 235.355 400 0 0 0 169.40013663490606 320 L 77.94010882297061 320" fill="none" stroke="url(#conn-grad-1)" stroke-width="3" stroke-linecap="round" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path> <!-- Chip-shaped glow animation --> <g transform="translate(77.94010882297061, 320)" data-astro-cid-ynql2ou5> <rect x="-12" y="-12" width="24" height="24" rx="3" fill="none" stroke="var(--color)" stroke-width="2" opacity="0" data-astro-cid-ynql2ou5> <animate attributeName="opacity" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="0;1;0.5;0;0;0" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="width" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="24;32;40;48;24;24" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="height" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="24;32;40;48;24;24" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="x" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="-12;-16;-20;-24;-12;-12" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="y" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="-12;-16;-20;-24;-12;-12" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> </rect> </g> <rect x="61.940108822970615" y="304" width="32" height="32" rx="4" fill="#151515" stroke="url(#node-gradient)" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></rect> <!-- Chip icon --> <g transform="translate(70.94010882297061, 313)" fill="white" stroke="white" data-astro-cid-ynql2ou5> <!-- Chip body --> <rect x="0" y="0" width="14" height="14" rx="2" fill="none" stroke-width="1.2" data-astro-cid-ynql2ou5></rect> <!-- Central processor area --> <rect x="3" y="3" width="8" height="8" rx="1" fill="none" stroke-width="0.8" data-astro-cid-ynql2ou5></rect>
178 <!-- Circuit lines --> <line x1="3" y1="6" x2="1" y2="6" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="3" y1="8" x2="1" y2="8" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="13" y1="6" x2="11" y2="6" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="13" y1="8" x2="11" y2="8" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="6" y1="3" x2="6" y2="1" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="8" y1="3" x2="8" y2="1" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="6" y1="13" x2="6" y2="11" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="8" y1="13" x2="8" y2="11" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <!-- Pin connections --> <circle cx="1" cy="6" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="1" cy="8" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="13" cy="6" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="13" cy="8" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="6" cy="1" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="8" cy="1" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="6" cy="13" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="8" cy="13" r="0.4" data-astro-cid-ynql2ou5></circle> </g> </g><g data-testid="dynamic-node-2" data-astro-cid-ynql2ou5>  <defs data-astro-cid-ynql2ou5> <radialGradient id="conn-grad-2" gradientUnits="userSpaceOnUse" r="0" style="--normal-color: #45DEC4;" data-astro-cid-ynql2ou5> <stop offset="0" stop-color="var(--color)" data-astro-cid-ynql2ou5></stop> <stop offset="0.4" stop-color="var(--color)" data-astro-cid-ynql2ou5></stop> <stop offset="1" stop-color="var(--color)" stop-opacity="0" data-astro-cid-ynql2ou5></stop> <animate attributeName="cx" dur="4.5s" repeatCount="indefinite" keyTimes="0;1;1" values="400;400;400" data-astro-cid-ynql2ou5></animate> <animate attributeName="cy" dur="4.5s" repeatCount="indefinite" keyTimes="0;1;1" values="0;80;80" data-astro-cid-ynql2ou5></animate> <animate attributeName="r" dur="4.5s" repeatCount="indefinite" keyTimes="0;0.5;0.5;1" values="0;120;120;0" data-astro-cid-ynql2ou5></animate> </radialGradient> </defs> <path d="M 400 0 A 0 400 0 0 1 400 80" fill="none" stroke="url(#conn-grad-2)" stroke-width="3" stroke-linecap="round" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path> <!-- Chip-shaped glow animation --> <g transform="translate(400, 80)" data-astro-cid-ynql2ou5> <rect x="-12" y="-12" width="24" height="24" rx="3" fill="none" stroke="var(--color)" stroke-width="2" opacity="0" data-astro-cid-ynql2ou5> <animate attributeName="opacity" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="0;1;0.5;0;0;0" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="width" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="24;32;40;48;24;24" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="height" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="24;32;40;48;24;24" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="x" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="-12;-16;-20;-24;-12;-12" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="y" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="-12;-16;-20;-24;-12;-12" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> </rect> </g> <rect x="384" y="64" width="32" height="32" rx="4" fill="#151515" stroke="url(#node-gradient)" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></rect> <!-- Chip icon --> <g transform="translate(393, 73)" fill="white" stroke="white" data-astro-cid-ynql2ou5> <!-- Chip body --> <rect x="0" y="0" width="14" height="14" rx="2" fill="none" stroke-width="1.2" data-astro-cid-ynql2ou5></rect> <!-- Central processor area --> <rect x="3" y="3" width="8" height="8" rx="1" fill="none" stroke-width="0.8" data-astro-cid-ynql2ou5></rect> <!-- Circuit lines --> <line x1="3" y1="6" x2="1" y2="6" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="3" y1="8" x2="1" y2="8" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="13" y1="6" x2="11" y2="6" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="13" y1="8" x2="11" y2="8" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="6" y1="3" x2="6" y2="1" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="8" y1="3" x2="8" y2="1" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="6" y1="13" x2="6" y2="11" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="8" y1="13" x2="8" y2="11" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <!-- Pin connections --> <circle cx="1" cy="6" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="1" cy="8" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="13" cy="6" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="13" cy="8" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="6" cy="1" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="8" cy="1" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="6" cy="13" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="8" cy="13" r="0.4" data-astro-cid-ynql2ou5></circle> </g> </g><g data-testid="dynamic-node-3" data-astro-cid-ynql2ou5>  <defs data-astro-cid-ynql2ou5> <radialGradient id="conn-grad-3" gradientUnits="userSpaceOnUse" r="0" style="--normal-color: #45DEC4;" data-astro-cid-ynql2ou5> <stop offset="0" stop-color="var(--color)" data-astro-cid-ynql2ou5></stop> <stop offset="0.4" stop-color="var(--color)" data-astro-cid-ynql2ou5></stop> <stop offset="1" stop-color="var(--color)" stop-opacity="0" data-astro-cid-ynql2ou5></stop>
178 <animate attributeName="cx" dur="4.5s" repeatCount="indefinite" keyTimes="0;0.7904363824519829;1;1" values="400;615.7064205372664;701.2594427015359;701.2594427015359" data-astro-cid-ynql2ou5></animate> <animate attributeName="cy" dur="4.5s" repeatCount="indefinite" keyTimes="0;0.7904363824519829;1;1" values="0;240;240;240" data-astro-cid-ynql2ou5></animate> <animate attributeName="r" dur="4.5s" repeatCount="indefinite" keyTimes="0;0.5;0.5;1" values="0;120;120;0" data-astro-cid-ynql2ou5></animate> </radialGradient> </defs> <path d="M 400 0 A 235.355 400 0 0 1 615.7064205372664 240 L 701.2594427015359 240" fill="none" stroke="url(#conn-grad-3)" stroke-width="3" stroke-linecap="round" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path> <!-- Chip-shaped glow animation --> <g transform="translate(701.2594427015359, 240)" data-astro-cid-ynql2ou5> <rect x="-12" y="-12" width="24" height="24" rx="3" fill="none" stroke="var(--color)" stroke-width="2" opacity="0" data-astro-cid-ynql2ou5> <animate attributeName="opacity" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="0;1;0.5;0;0;0" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="width" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="24;32;40;48;24;24" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="height" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="24;32;40;48;24;24" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="x" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="-12;-16;-20;-24;-12;-12" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="y" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="-12;-16;-20;-24;-12;-12" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> </rect> </g> <rect x="685.2594427015359" y="224" width="32" height="32" rx="4" fill="#151515" stroke="url(#node-gradient)" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></rect> <!-- Chip icon --> <g transform="translate(694.2594427015359, 233)" fill="white" stroke="white" data-astro-cid-ynql2ou5> <!-- Chip body --> <rect x="0" y="0" width="14" height="14" rx="2" fill="none" stroke-width="1.2" data-astro-cid-ynql2ou5></rect> <!-- Central processor area --> <rect x="3" y="3" width="8" height="8" rx="1" fill="none" stroke-width="0.8" data-astro-cid-ynql2ou5></rect> <!-- Circuit lines --> <line x1="3" y1="6" x2="1" y2="6" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="3" y1="8" x2="1" y2="8" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="13" y1="6" x2="11" y2="6" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="13" y1="8" x2="11" y2="8" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="6" y1="3" x2="6" y2="1" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="8" y1="3" x2="8" y2="1" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="6" y1="13" x2="6" y2="11" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="8" y1="13" x2="8" y2="11" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <!-- Pin connections --> <circle cx="1" cy="6" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="1" cy="8" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="13" cy="6" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="13" cy="8" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="6" cy="1" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="8" cy="1" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="6" cy="13" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="8" cy="13" r="0.4" data-astro-cid-ynql2ou5></circle> </g> </g><g data-testid="dynamic-node-4" data-astro-cid-ynql2ou5>  <defs data-astro-cid-ynql2ou5> <radialGradient id="conn-grad-4" gradientUnits="userSpaceOnUse" r="0" style="--normal-color: #45DEC4;" data-astro-cid-ynql2ou5> <stop offset="0" stop-color="var(--color)" data-astro-cid-ynql2ou5></stop> <stop offset="0.4" stop-color="var(--color)" data-astro-cid-ynql2ou5></stop> <stop offset="1" stop-color="var(--color)" stop-opacity="0" data-astro-cid-ynql2ou5></stop>
178 <animate attributeName="cx" dur="4.5s" repeatCount="indefinite" keyTimes="0;1;1" values="400;137.0392;137.0392" data-astro-cid-ynql2ou5></animate> <animate attributeName="cy" dur="4.5s" repeatCount="indefinite" keyTimes="0;1;1" values="0;160;160" data-astro-cid-ynql2ou5></animate> <animate attributeName="r" dur="4.5s" repeatCount="indefinite" keyTimes="0;0.5;0.5;1" values="0;120;120;0" data-astro-cid-ynql2ou5></animate> </radialGradient> </defs> <path d="M 400 0 A 328.701 400 0 0 0 137.0392 160" fill="none" stroke="url(#conn-grad-4)" stroke-width="3" stroke-linecap="round" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path> <!-- Chip-shaped glow animation --> <g transform="translate(137.0392, 160)" data-astro-cid-ynql2ou5> <rect x="-12" y="-12" width="24" height="24" rx="3" fill="none" stroke="var(--color)" stroke-width="2" opacity="0" data-astro-cid-ynql2ou5> <animate attributeName="opacity" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="0;1;0.5;0;0;0" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="width" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="24;32;40;48;24;24" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="height" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="24;32;40;48;24;24" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="x" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="-12;-16;-20;-24;-12;-12" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="y" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="-12;-16;-20;-24;-12;-12" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> </rect> </g> <rect x="121.0392" y="144" width="32" height="32" rx="4" fill="#151515" stroke="url(#node-gradient)" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></rect> <!-- Chip icon --> <g transform="translate(130.0392, 153)" fill="white" stroke="white" data-astro-cid-ynql2ou5> <!-- Chip body --> <rect x="0" y="0" width="14" height="14" rx="2" fill="none" stroke-width="1.2" data-astro-cid-ynql2ou5></rect> <!-- Central processor area --> <rect x="3" y="3" width="8" height="8" rx="1" fill="none" stroke-width="0.8" data-astro-cid-ynql2ou5></rect> <!-- Circuit lines --> <line x1="3" y1="6" x2="1" y2="6" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="3" y1="8" x2="1" y2="8" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="13" y1="6" x2="11" y2="6" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="13" y1="8" x2="11" y2="8" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="6" y1="3" x2="6" y2="1" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="8" y1="3" x2="8" y2="1" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="6" y1="13" x2="6" y2="11" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="8" y1="13" x2="8" y2="11" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <!-- Pin connections --> <circle cx="1" cy="6" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="1" cy="8" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="13" cy="6" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="13" cy="8" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="6" cy="1" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="8" cy="1" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="6" cy="13" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="8" cy="13" r="0.4" data-astro-cid-ynql2ou5></circle> </g> </g><g data-testid="dynamic-node-5" data-astro-cid-ynql2ou5>  <defs data-astro-cid-ynql2ou5> <radialGradient id="conn-grad-5" gradientUnits="userSpaceOnUse" r="0" style="--normal-color: #45DEC4;" data-astro-cid-ynql2ou5> <stop offset="0" stop-color="var(--color)" data-astro-cid-ynql2ou5></stop> <stop offset="0.4" stop-color="var(--color)" data-astro-cid-ynql2ou5></stop> <stop offset="1" stop-color="var(--color)" stop-opacity="0" data-astro-cid-ynql2ou5></stop> <animate attributeName="cx" dur="4.5s" repeatCount="indefinite" keyTimes="0;1;1" values="400;301.5224;301.5224" data-astro-cid-ynql2ou5></animate>
178 <animate attributeName="cy" dur="4.5s" repeatCount="indefinite" keyTimes="0;1;1" values="0;160;160" data-astro-cid-ynql2ou5></animate> <animate attributeName="r" dur="4.5s" repeatCount="indefinite" keyTimes="0;0.5;0.5;1" values="0;120;120;0" data-astro-cid-ynql2ou5></animate> </radialGradient> </defs> <path d="M 400 0 A 123.097 400 0 0 0 301.5224 160" fill="none" stroke="url(#conn-grad-5)" stroke-width="3" stroke-linecap="round" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path> <!-- Chip-shaped glow animation --> <g transform="translate(301.5224, 160)" data-astro-cid-ynql2ou5> <rect x="-12" y="-12" width="24" height="24" rx="3" fill="none" stroke="var(--color)" stroke-width="2" opacity="0" data-astro-cid-ynql2ou5> <animate attributeName="opacity" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="0;1;0.5;0;0;0" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="width" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="24;32;40;48;24;24" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="height" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="24;32;40;48;24;24" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="x" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="-12;-16;-20;-24;-12;-12" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="y" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="-12;-16;-20;-24;-12;-12" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> </rect> </g> <rect x="285.5224" y="144" width="32" height="32" rx="4" fill="#151515" stroke="url(#node-gradient)" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></rect> <!-- Chip icon --> <g transform="translate(294.5224, 153)" fill="white" stroke="white" data-astro-cid-ynql2ou5> <!-- Chip body --> <rect x="0" y="0" width="14" height="14" rx="2" fill="none" stroke-width="1.2" data-astro-cid-ynql2ou5></rect> <!-- Central processor area --> <rect x="3" y="3" width="8" height="8" rx="1" fill="none" stroke-width="0.8" data-astro-cid-ynql2ou5></rect> <!-- Circuit lines --> <line x1="3" y1="6" x2="1" y2="6" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="3" y1="8" x2="1" y2="8" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="13" y1="6" x2="11" y2="6" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="13" y1="8" x2="11" y2="8" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="6" y1="3" x2="6" y2="1" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="8" y1="3" x2="8" y2="1" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="6" y1="13" x2="6" y2="11" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="8" y1="13" x2="8" y2="11" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <!-- Pin connections --> <circle cx="1" cy="6" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="1" cy="8" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="13" cy="6" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="13" cy="8" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="6" cy="1" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="8" cy="1" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="6" cy="13" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="8" cy="13" r="0.4" data-astro-cid-ynql2ou5></circle> </g> </g><g data-testid="dynamic-node-6" data-astro-cid-ynql2ou5>  <defs data-astro-cid-ynql2ou5> <radialGradient id="conn-grad-6" gradientUnits="userSpaceOnUse" r="0" style="--normal-color: #45DEC4;" data-astro-cid-ynql2ou5> <stop offset="0" stop-color="var(--color)" data-astro-cid-ynql2ou5></stop> <stop offset="0.4" stop-color="var(--color)" data-astro-cid-ynql2ou5></stop> <stop offset="1" stop-color="var(--color)" stop-opacity="0" data-astro-cid-ynql2ou5></stop> <animate attributeName="cx" dur="4.5s" repeatCount="indefinite" keyTimes="0;0.42091446746981026;0.6415407555438832;1;1" values="400;498.4776;400;400;400" data-astro-cid-ynql2ou5></animate>
178 <animate attributeName="cy" dur="4.5s" repeatCount="indefinite" keyTimes="0;0.42091446746981026;0.6415407555438832;1;1" values="0;160;160;320;320" data-astro-cid-ynql2ou5></animate> <animate attributeName="r" dur="4.5s" repeatCount="indefinite" keyTimes="0;0.5;0.5;1" values="0;120;120;0" data-astro-cid-ynql2ou5></animate> </radialGradient> </defs> <path d="M 400 0 A 123.097 400 0 0 1 498.4776 160 L 400 160 L 400 320" fill="none" stroke="url(#conn-grad-6)" stroke-width="3" stroke-linecap="round" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></path> <!-- Chip-shaped glow animation --> <g transform="translate(400, 320)" data-astro-cid-ynql2ou5> <rect x="-12" y="-12" width="24" height="24" rx="3" fill="none" stroke="var(--color)" stroke-width="2" opacity="0" data-astro-cid-ynql2ou5> <animate attributeName="opacity" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="0;1;0.5;0;0;0" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="width" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="24;32;40;48;24;24" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="height" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="24;32;40;48;24;24" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="x" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="-12;-16;-20;-24;-12;-12" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> <animate attributeName="y" dur="4.5s" keyTimes="0;0.167;0.333;0.5;0.667;1" values="-12;-16;-20;-24;-12;-12" repeatCount="indefinite" data-astro-cid-ynql2ou5></animate> </rect> </g> <rect x="384" y="304" width="32" height="32" rx="4" fill="#151515" stroke="url(#node-gradient)" vector-effect="non-scaling-stroke" data-astro-cid-ynql2ou5></rect> <!-- Chip icon --> <g transform="translate(393, 313)" fill="white" stroke="white" data-astro-cid-ynql2ou5> <!-- Chip body --> <rect x="0" y="0" width="14" height="14" rx="2" fill="none" stroke-width="1.2" data-astro-cid-ynql2ou5></rect> <!-- Central processor area --> <rect x="3" y="3" width="8" height="8" rx="1" fill="none" stroke-width="0.8" data-astro-cid-ynql2ou5></rect> <!-- Circuit lines --> <line x1="3" y1="6" x2="1" y2="6" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="3" y1="8" x2="1" y2="8" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="13" y1="6" x2="11" y2="6" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="13" y1="8" x2="11" y2="8" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="6" y1="3" x2="6" y2="1" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="8" y1="3" x2="8" y2="1" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="6" y1="13" x2="6" y2="11" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <line x1="8" y1="13" x2="8" y2="11" stroke-width="0.8" data-astro-cid-ynql2ou5></line> <!-- Pin connections --> <circle cx="1" cy="6" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="1" cy="8" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="13" cy="6" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="13" cy="8" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="6" cy="1" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="8" cy="1" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="6" cy="13" r="0.4" data-astro-cid-ynql2ou5></circle> <circle cx="8" cy="13" r="0.4" data-astro-cid-ynql2ou5></circle> </g> </g> </g> <defs data-astro-cid-ynql2ou5> <linearGradient id="globe-gradient" gradientUnits="userSpaceOnUse" x1="0" y1="0" x2="0" y2="400" data-astro-cid-ynql2ou5> <stop offset="0%" stop-color="var(--guide-color)" data-astro-cid-ynql2ou5></stop> <stop offset="100%" stop-color="var(--guide-color)" data-astro-cid-ynql2ou5></stop> </linearGradient> <!-- Fade mask for bottom fade-out --> <linearGradient id="fade-gradient" x1="0" y1="0" x2="0" y2="1" gradientUnits="objectBoundingBox" data-astro-cid-ynql2ou5> <stop offset="0" stop-color="white" data-astro-cid-ynql2ou5></stop> <stop offset="0.75" stop-color="white" data-astro-cid-ynql2ou5></stop> <stop offset="1" stop-color="black" data-astro-cid-ynql2ou5></stop> </linearGradient> <mask id="fade-mask" maskUnits="objectBoundingBox" data-astro-cid-ynql2ou5> <rect x="0" y="0" width="100%" height="100%" fill="url(#fade-gradient)" data-astro-cid-ynql2ou5></rect> </mask> <!-- Default gradient reused by node circles --> <linearGradient id="node-gradient" x1="0" y1="0" x2="0" y2="1" data-astro-cid-ynql2ou5> <stop offset="0" stop-color="var(--color)" data-astro-cid-ynql2ou5></stop> <stop offset="1" stop-color="var(--color)" data-astro-cid-ynql2ou5></stop> </linearGradient> </defs> </svg> </div> </div> 
178<script type="module">function f(){const t=document.querySelector('[role="tablist"]');if(!t)return;const r=t.querySelectorAll('[role="tab"]');document.querySelectorAll('[role="tabpanel"]');function l(o){const n=o.getAttribute("data-tab-id");if(!n||!t)return;const s=t.querySelectorAll('[role="tab"]'),i=document.querySelectorAll('[role="tabpanel"]');s.forEach(e=>{const a=e===o;e.setAttribute("aria-selected",a?"true":"false"),e.classList.toggle("active",a)}),i.forEach(e=>{e.getAttribute("data-tab-panel")===n?e.classList.add("active"):e.classList.remove("active")}),o.focus()}r.forEach(o=>{const n=o,s=n;s._tabBound!==!0&&(s._tabBound=!0,n.addEventListener("click",i=>{i.preventDefault(),l(n)}),n.addEventListener("keydown",i=>{const e=i,a=t.querySelectorAll('[role="tab"]'),c=Array.from(a).indexOf(n);let u=c;switch(e.key){case"ArrowLeft":e.preventDefault(),u=c>0?c-1:a.length-1;break;case"ArrowRight":e.preventDefault(),u=c<a.length-1?c+1:0;break;case"Home":e.preventDefault(),u=0;break;case"End":e.preventDefault(),u=a.length-1;break;default:return}l(a[u])}))})}let d=null;const b=["Thinking...","Is the user using Code or not?","User is using configuration files","Reading Configuration","Configuration file updated"];function v(){const t=document.getElementById("ai-thinking");if(!t)return;d&&clearInterval(d);let r=0;d=setInterval(()=>{t.style.opacity="0",setTimeout(()=>{t.textContent=b[r],t.style.opacity="1",r=(r+1)%b.length},150)},1e3)}function g(){const t=document.querySelector('[data-tab-id="ai"]'),r=document.getElementById("tab-panel-ai");if(t&&r){const l=r,o=l._observer;o&&o.disconnect();const n=new IntersectionObserver(s=>{s.forEach(i=>{i.isIntersecting&&v()})},{threshold:.1});l._observer=n,n.observe(r)}}typeof window<"u"&&(document.readyState==="loading"?document.addEventListener("DOMContentLoaded",()=>{f(),g()}):(f(),g()));document.addEventListener("astro:page-load",()=>{requestAnimationFrame(()=>{f(),g()})});</script>
178 <!-- Build Desktop --><div class="platform-desktop absolute inset-0  z-1" data-platform="build" style="display: none;"> <!-- Desktop Background --> <!-- Desktop Background --><div class="absolute inset-0 bg-cover bg-center rounded-2xl desktop-background" style="background-image: url('/amazigh-desert-background.png')"></div> <!-- Web Console Window --> <!-- Taubyte Console Window (Floating) --><div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-5xl shadow-[0_35px_60px_-12px_rgba(0,0,0,0.5)] rounded-lg console-window" id="draggable-window-build" data-platform="build"> <div class="bg-[#1a1a1a] rounded-lg overflow-hidden border border-white/10 flex flex-col" style="height: 520px;"> <!-- Browser Tabs --> <div class="bg-[#222] border-b border-white/10 px-4 py-1.5 flex items-center gap-1 cursor-move drag-handle" data-platform="build"> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="ml-4 text-white/60 text-xs">Console</span> </div> <!-- Top Header Bar --> <div class="bg-[#2d2d2d] h-10 px-4 flex items-center justify-between border-b border-white/10"> <!-- Left: Logo and Menu --> <div class="flex items-center gap-4"> <i class="ri-menu-2-line text-white/60"></i> </div> <!-- Right: Icons and Actions --> <div class="flex items-center gap-4"> <div class="flex items-center gap-1.5 text-white/60 text-xs bg-white/5 px-2 py-1 rounded"> <i class="ri-git-branch-line text-white/60"></i> <span>main</span> </div> <i class="ri-notification-3-line text-white/60"></i> <i class="ri-question-line text-white/60"></i> <div class="flex items-center gap-2 text-white/60"> <img src="/samy-git-avatar.png" alt="Avatar" class="w-6 h-6 rounded-full border border-gray-500"> </div> </div> </div> <!-- Main Content --> <div class="flex flex-1 overflow-hidden"> <!-- Left Sidebar --> <div class="w-40 bg-[#252525] border-r border-white/10 p-3 space-y-0.5 overflow-auto flex flex-col"> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-home-line text-xs"></i> <span class="text-xs">Home</span> </div> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-function-line text-xs"></i> <span class="text-xs">Applications</span> </div> <div class="flex items-center gap-1.5 px-2 py-1 rounded text-green-500 bg-white/10"> <i class="ri-flashlight-line text-xs"></i> <span class="text-xs">Functions</span> </div> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-stack-line text-xs"></i> <span class="text-xs">Libraries</span> </div> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-global-line text-xs"></i> <span class="text-xs">Websites</span> </div> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-hard-drive-2-line text-xs"></i> <span class="text-xs">Storages</span> </div> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-mail-line text-xs"></i> <span class="text-xs">Messaging</span> </div> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-database-2-line text-xs"></i> <span class="text-xs">Databases</span> </div> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-compass-3-line text-xs"></i> <span class="text-xs">Domains</span> </div> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-server-line text-xs"></i> <span class="text-xs">Services</span> </div> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-settings-4-line text-xs"></i> <span class="text-xs">SmartOps</span> </div> <div class="border-t border-white/10 my-1"></div> <div class="flex items-center gap-1.5 px-2 py-1 rounded text-white/60"> <i class="ri-task-line text-xs"></i> <span class="text-xs">Builds</span> </div> <div class="flex items-center gap-1.5 text-white/60 px-2 py-1 rounded"> <i class="ri-archive-drawer-line text-xs"></i> <span class="text-xs text-gray-500">Config</span> </div> <div class="flex items-center gap-1.5 text-white/60 px-2 py-1 rounded"> <i class="ri-folder-line text-xs"></i> <span class="text-xs text-gray-500">Buckets</span> </div> <div class="mt-auto pt-2 text-[10px] text-gray-500 text-center">Version: 1.0.0</div> </div> <!-- Main Content Area --> <div class="flex-1 bg-[#1a1a1a] p-4 overflow-auto"> <div class="mb-2"> <span class="text-[10px] text-gray-500">Project > Functions</span> </div> <div class="mb-3"> <!-- Functions Content -->
179              <div class="bg-[#252525] rounded-lg p-2 mb-3 flex items-center gap-2"> <div class="text-green-500 text-lg"> <i class="ri-flashlight-line"></i> </div> <div> <div class="text-lg font-bold text-white">3</div> <div class="text-[10px] text-white/60">Unchanged</div> </div> </div>  <div class="bg-[#252525] border-2 border-dashed border-white/10 rounded-lg h-10 flex items-center justify-center mb-3 cursor-pointer hover:border-green-500 transition-colors"> <div class="text-green-500 text-2xl font-light">+</div> </div>  <div class="bg-[#252525] rounded-lg overflow-hidden"> <table class="w-full"> <thead class="bg-[#2a2a2a]"> <tr> <th class="px-3 py-2 text-left text-[10px] font-medium text-white/60 uppercase tracking-wider"> <div class="flex items-center gap-1">
180Name
181<i class="ri-arrow-up-line text-xs"></i> </div> </th> <th class="px-3 py-2 text-left text-[10px] font-medium text-white/60 uppercase tracking-wider">Id</th> <th class="px-3 py-2 text-left text-[10px] font-medium text-white/60 uppercase tracking-wider">Description</th> <th class="px-3 py-2 text-left text-[10px] font-medium text-white/60 uppercase tracking-wider">Tags</th> <th class="px-3 py-2 text-left text-[10px] font-medium text-white/60 uppercase tracking-wider">Actions</th> </tr> </thead> <tbody class="divide-y divide-white/10"> <tr class="hover:bg-[#2a2a2a]"> <td class="px-3 py-2 text-xs text-white">login</td> <td class="px-3 py-2 text-[10px] text-white/60 font-mono">QmYditGQeF2g...</td> <td class="px-3 py-2 text-xs text-white/60">login</td> <td class="px-3 py-2 text-xs text-white/60">auth</td> <td class="px-3 py-2"> <div class="flex items-center gap-1"> <button class="text-green-500 hover:text-green-400"> <i class="ri-edit-line text-sm"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-file-copy-line text-sm"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-delete-bin-line text-sm"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-flashlight-line text-sm"></i> </button> </div> </td> </tr> <tr class="hover:bg-[#2a2a2a]"> <td class="px-3 py-2 text-xs text-white">send_email</td> <td class="px-3 py-2 text-[10px] text-white/60 font-mono">QmK8tpRgQ2p...</td> <td class="px-3 py-2 text-xs text-white/60">send_email</td> <td class="px-3 py-2 text-xs text-white/60">email</td> <td class="px-3 py-2"> <div class="flex items-center gap-1"> <button class="text-green-500 hover:text-green-400"> <i class="ri-edit-line text-sm"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-file-copy-line text-sm"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-delete-bin-line text-sm"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-flashlight-line text-sm"></i> </button> </div> </td> </tr> <tr class="hover:bg-[#2a2a2a]"> <td class="px-3 py-2 text-xs text-white">
181upload_file</td> <td class="px-3 py-2 text-[10px] text-white/60 font-mono">QmS9rmHgW3f...</td> <td class="px-3 py-2 text-xs text-white/60">upload_file</td> <td class="px-3 py-2 text-xs text-white/60">storage</td> <td class="px-3 py-2"> <div class="flex items-center gap-1"> <button class="text-green-500 hover:text-green-400"> <i class="ri-edit-line text-sm"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-file-copy-line text-sm"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-delete-bin-line text-sm"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-flashlight-line text-sm"></i> </button> </div> </td> </tr> </tbody> </table> </div>  <div class="flex items-center justify-end gap-1 mt-2"> <button class="px-2 py-0.5 text-white/60 hover:text-white text-[10px]">«</button> <button class="px-2 py-0.5 text-white/60 hover:text-white text-[10px]">‹</button> <button class="px-2 py-0.5 bg-green-500 text-white text-[10px] rounded">1</button> <button class="px-2 py-0.5 text-white/60 hover:text-white text-[10px]">›</button> <button class="px-2 py-0.5 text-white/60 hover:text-white text-[10px]">»</button> </div>  </div> </div> </div> <!-- Floating Action Button --> <div class="absolute bottom-6 right-6"> <button class="w-10 h-10 bg-green-500 rounded-full flex items-center justify-center shadow-lg hover:bg-green-600 transition-colors"> <i class="ri-git-pull-request-fill text-2xl text-white"></i> </button> </div> </div> </div> 
181<script>(function(){const id = "draggable-window-build";
182const platform = "build";
183
184  let _docDrag = null;
185  let _docDragEnd = null;
186
187  function initWebConsoleWindow() {
188    const window = document.getElementById(id);
189    const dragHandle = document.querySelector(`.drag-handle[data-platform="${platform}"]`);
190    const container = window?.parentElement;
191    
192    if (!window || !dragHandle || !container) return;
193    
194    // Check if already bound to prevent duplicates
195    if (dragHandle._dragBound === true) return;
196    dragHandle._dragBound = true;
197    
198    let isDragging = false;
199    let initialX = 0;
200    let initialY = 0;
201    
202    function dragStart(e) {
203      if (e.button !== 0) return;
204      
205      isDragging = true;
206      
207      const rect = window.getBoundingClientRect();
208      const containerRect = container.getBoundingClientRect();
209      
210      // Calculate where we clicked relative to the window
211      initialX = e.clientX - rect.left;
212      initialY = e.clientY - rect.top;
213      
214      // Remove transform classes and set initial position
215      window.classList.remove('-translate-x-1/2', '-translate-y-1/2');
216      window.classList.add('translate-x-0', 'translate-y-0');
217      
218      // Get current position
219      const currentLeft = rect.left - containerRect.left;
220      const currentTop = rect.top - containerRect.top;
221      
222      // Set initial positions
223      window.style.left = currentLeft + 'px';
224      window.style.top = currentTop + 'px';
225      
226      window.classList.add('user-select-none');
227      document.body.style.cursor = 'grabbing';
228    }
229    
230    function drag(e) {
231      if (!isDragging) return;
232      
233      e.preventDefault();
234      
235      const containerRect = container.getBoundingClientRect();
236      const windowRect = window.getBoundingClientRect();
237      
238      // Calculate new position
239      const newX = e.clientX - containerRect.left - initialX;
240      const newY = e.clientY - containerRect.top - initialY;
241      
242      // Keep window within container bounds
243      const maxX = containerRect.width - windowRect.width;
244      const maxY = containerRect.height - windowRect.height;
245      
246      const boundedX = Math.max(0, Math.min(newX, maxX));
247      const boundedY = Math.max(0, Math.min(newY, maxY));
248      
249      window.style.left = boundedX + 'px';
250      window.style.top = boundedY + 'px';
251    }
252    
253    function dragEnd() {
254      if (!isDragging) return;
255      
256      isDragging = false;
257      window.classList.remove('user-select-none');
258      document.body.style.cursor = '';
259    }
260    
261    dragHandle.addEventListener('mousedown', dragStart);
262    if (!_docDrag) {
263      _docDrag = drag;
264      _docDragEnd = dragEnd;
265      document.addEventListener('mousemove', _docDrag);
266      document.addEventListener('mouseup', _docDragEnd);
267      document.addEventListener('mouseleave', _docDragEnd);
268    }
269  }
270
271  // Initialize on page load
272  if (typeof window !== 'undefined') {
273    if (document.readyState === 'loading') {
274      document.addEventListener('DOMContentLoaded', initWebConsoleWindow);
275    } else {
276      initWebConsoleWindow();
277    }
278  }
279
280  // Re-initialize after view transitions
281  document.addEventListener('astro:page-load', () => {
282    requestAnimationFrame(initWebConsoleWindow);
283  });
284
285  document.addEventListener('astro:before-swap', () => {
286    if (_docDrag) {
287      document.removeEventListener('mousemove', _docDrag);
288      document.removeEventListener('mouseup', _docDragEnd);
289      document.removeEventListener('mouseleave', _docDragEnd);
290      _docDrag = null;
291      _docDragEnd = null;
292    }
293  });
294})();</script>
294 </div> <!-- Test Desktop --><div class="platform-desktop absolute inset-0  z-1" data-platform="test" style="display: none;"> <!-- Desktop Background --> <!-- Desktop Background --><div class="absolute inset-0 bg-cover bg-center rounded-2xl desktop-background" style="background-image: url('/test-background.png')"></div> <!-- Web Console Window --> <!-- Dream Desktop Window (Floating) --><div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-full shadow-[0_35px_60px_-12px_rgba(0,0,0,0.5)] rounded-lg max-w-4xl max-h-xl" id="draggable-dream-window-lnco2c2"> <div class="bg-[#1a1a1a] rounded-lg overflow-hidden border border-white/10 flex flex-col h-full"> <!-- Browser-style title bar - spans full width --> <div class="bg-[#222] px-4 py-1.5 flex items-center border-b border-white/10 drag-handle cursor-move"> <div class="flex items-center gap-1"> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> </div> <span class="ml-4 text-white/60 text-xs">Dream Desktop</span> </div> <div class="flex flex-1 overflow-hidden"> <!-- Left persistent panel --> <div class="w-60 bg-[#252525] border-r border-white/10 flex flex-col"> <!-- Stats --> <div class="grid grid-cols-3 gap-1 p-3 text-center border-b border-white/10"> <div class="bg-[#2a2a2a] rounded px-2 py-1"> <div class="text-[10px] text-white/50 uppercase">Memory</div> <div class="text-xs text-white font-medium">0%</div> <div class="text-[9px] text-white/40">77MB</div> </div> <div class="bg-[#2a2a2a] rounded px-2 py-1"> <div class="text-[10px] text-white/50 uppercase">CPU</div> <div class="text-xs text-white font-medium">7%</div> </div> <div class="bg-[#2a2a2a] rounded px-2 py-1"> <div class="text-[10px] text-white/50 uppercase">Universes</div> <div class="text-xs text-white font-medium">1</div> </div> </div> <!-- Sidebar list --> <div class="px-3 py-3 flex-1"> <div class="flex items-center justify-between mb-2"> <div class="text-[10px] text-white/50 uppercase tracking-wide">Persistent</div> <div class="flex items-center gap-1"> <button class="text-white/40 hover:text-white"><i class="ri-refresh-line text-xs"></i></button> <button class="text-white/40 hover:text-white"><i class="ri-more-2-fill text-xs"></i></button> </div> </div> <button class="w-full flex items-center justify-between bg-[#2a2a2a] hover:bg-[#2d2d2d] text-white text-sm px-2 py-2 rounded mb-1"> <span class="flex items-center gap-2"> <span class="w-2 h-2 rounded-full bg-green-500"></span>
295blackhole
296</span> <i class="ri-arrow-right-s-line text-white/60"></i> </button> </div> <div class="mt-auto p-3 space-y-2 border-t border-white/10"> <button class="w-full bg-linear-to-r from-green-600 to-green-700 hover:from-green-700 hover:to-green-800 text-white py-2 rounded text-sm font-medium flex items-center justify-center gap-2"> <i class="ri-add-line"></i>
297Create New
298</button> <div class="text-[10px] text-white/40 uppercase tracking-wide mb-1 mt-3">Services</div> <div class="space-y-1"> <div class="flex items-center justify-between text-[11px] text-white/80 py-1"> <span class="flex items-center gap-2"> <span class="w-2 h-2 rounded-full bg-green-500"></span>
299API Service
300</span> <button class="text-white/30 hover:text-white"><i class="ri-more-2-fill"></i></button> </div> <div class="flex items-center justify-between text-[11px] text-white/80 py-1"> <span class="flex items-center gap-2"> <span class="w-2 h-2 rounded-full bg-green-500"></span>
301MCP Server
302</span> <button class="text-white/30 hover:text-white"><i class="ri-more-2-fill"></i></button> </div> <div class="flex items-center justify-between text-[11px] text-white/80 py-1"> <span class="flex items-center gap-2"> <span class="w-2 h-2 rounded-full bg-green-500"></span>
303Name Server (DNS)
304</span> <button class="text-white/30 hover:text-white"><i class="ri-more-2-fill"></i></button> </div> </div> </div> </div> <!-- Main content area --> <div class="flex-1 flex flex-col"> <!-- Top Header Bar with blackhole --> <div class="bg-[#2d2d2d] h-10 px-4 flex items-center justify-between border-b border-white/10"> <div class="flex items-center gap-3"> <i class="ri-cloud-line text-white"></i> <span class="text-white font-medium text-sm">blackhole</span> <span class="text-[10px] bg-green-900/40 text-green-400 px-2 py-0.5 rounded">RUNNING</span> </div> <div class="flex items-center gap-2"> <button class="px-3 py-1 text-xs bg-red-600/80 hover:bg-red-600 text-white rounded flex items-center gap-1"> <i class="ri-stop-fill"></i>
305Stop
306</button> <button class="px-3 py-1 text-xs bg-white/5 hover:bg-white/10 text-white/60 rounded flex items-center gap-1"> <i class="ri-delete-bin-line"></i>
307Delete
308</button> <button class="text-white/60 hover:text-white"><i class="ri-refresh-line"></i></button> <button class="text-white/60 hover:text-white"><i class="ri-close-line"></i></button> </div> </div> <!-- Navigation tabs --> <div class="px-4 flex items-center gap-6 border-b border-white/10 bg-[#252525] text-[13px]"> <button class="flex items-center gap-2 text-white/60 hover:text-white border-b-2 border-transparent hover:border-white/30 transition-colors py-2"> <i class="ri-home-line text-sm"></i>Overview
309</button> <button class="flex items-center gap-2 text-white/60 hover:text-white border-b-2 border-transparent hover:border-white/30 transition-colors py-2"> <i class="ri-radar-line text-sm"></i>Network
310</button> <button class="flex items-center gap-2 text-blue-400 border-b-2 border-blue-400 -mb-[2px] py-2"> <i class="ri-folder-3-line text-sm"></i>Projects
311</button> <button class="flex items-center gap-2 text-white/60 hover:text-white border-b-2 border-transparent hover:border-white/30 transition-colors py-2"> <i class="ri-file-list-3-line text-sm"></i>Logs
312</button> </div> <!-- Content area --> <div class="flex-1 flex overflow-hidden bg-[#1a1a1a]"> <!-- Column 1: Projects list --> <div class="w-64 border-r border-white/10 flex flex-col bg-[#252525]"> <div class="px-4 py-3 border-b border-white/10 flex items-center justify-between"> <div class="flex items-center gap-2"> <span class="text-white text-sm font-medium">Projects</span> <span class="bg-white/10 text-white/60 text-[10px] px-1.5 py-0.5 rounded">1</span> </div> <button class="text-white/60 hover:text-white"><i class="ri-refresh-line"></i></button> </div> <div class="p-2"> <button class="w-full text-left text-green-500 text-sm px-3 py-2 rounded bg-green-500/10 hover:bg-green-500/20">
313demo
314</button> </div> </div> <!-- Column 2 & 3: Project details --> <div class="flex-1 flex flex-col"> <div class="px-4 py-3 border-b border-white/10 flex items-center justify-between bg-[#252525]"> <span class="text-white text-sm font-medium">demo</span> <button class="px-3 py-1 text-xs bg-red-600/80 hover:bg-red-600 text-white rounded flex items-center gap-1"> <i class="ri-delete-bin-line"></i>
315Delete
316</button> </div> <div class="flex-1 overflow-auto p-4"> <!-- Info grid --> <div class="grid grid-cols-2 gap-x-6 gap-y-2 text-xs mb-4"> <div class="flex gap-2"> <span class="text-white/50">ID:</span> <span class="text-white font-mono">QmUrnA...1s5FTV</span> <button class="text-white/40 hover:text-white"><i class="ri-file-copy-line text-xs"></i></button> </div> <div class="flex gap-2"> <span class="text-white/50">Provider:</span> <span class="text-white">github</span> </div> <div class="flex gap-2"> <span class="text-white/50">Email:</span> <span class="text-white">[email protected]</span> </div> <div class="flex gap-2"> <span class="text-white/50">Description:</span> <span class="text-white/60">Demo project</span> </div> </div> <!-- Sub tabs --> <div class="flex border-b border-white/10 mb-4 -mx-4"> <button class="flex items-center gap-2 px-4 py-2 text-xs text-white/60 hover:text-white border-b-2 border-transparent hover:border-white/30 transition-colors"> <i class="ri-git-repository-line"></i>
317Repositories
318</button> <button class="flex items-center gap-2 px-4 py-2 text-xs text-blue-400 border-b-2 border-blue-400 -mb-[2px]">
318 <i class="ri-grid-line"></i>
319Resources
320</button> <button class="flex items-center gap-2 px-4 py-2 text-xs text-white/60 hover:text-white border-b-2 border-transparent hover:border-white/30 transition-colors"> <i class="ri-folder-3-line"></i>
321Assets
322</button> </div> <!-- Resources content --> <div class="bg-[#252525] rounded-lg border border-white/10 overflow-hidden"> <!-- GLOBAL section --> <div class="border-b border-white/10"> <div class="px-3 py-1 flex items-center gap-2 bg-[#2a2a2a]"> <button class="text-white/60"><i class="ri-arrow-down-s-line text-sm"></i></button> <i class="ri-global-line text-white/60 text-sm"></i> <span class="text-white/70 text-xs uppercase tracking-wide">Global</span> </div> <!-- Functions --> <div class="border-t border-white/10"> <div class="px-3 py-1 flex items-center gap-2"> <i class="ri-flashlight-line text-white/60"></i> <span class="text-white text-xs">Functions</span> <span class="bg-white/10 text-white/60 text-[10px] px-1.5 py-0.5 rounded">1</span> </div> <div class="px-6 py-1 bg-[#1a1a1a]"> <div class="flex items-center justify-between"> <span class="text-white/80 text-xs">ping_pong</span> <div class="flex items-center gap-2"> <span class="text-[10px] bg-green-900/40 text-green-400 px-2 py-0.5 rounded">HTTPS</span> <button class="text-white/40 hover:text-white"><i class="ri-file-list-3-line text-xs"></i></button> <button class="text-white/40 hover:text-white"><i class="ri-more-2-fill text-xs"></i></button> </div> </div> </div> </div> <!-- Domains --> <div class="border-t border-white/10"> <div class="px-3 py-1 flex items-center gap-2"> <i class="ri-earth-line text-white/60"></i> <span class="text-white text-xs">Domains</span> <span class="bg-white/10 text-white/60 text-[10px] px-1.5 py-0.5 rounded">1</span> </div> <div class="px-6 py-1 bg-[#1a1a1a]"> <div class="flex items-center justify-between"> <div class="text-white/80 text-xs">GeneratedDomain</div> <div class="flex items-center gap-2"> <div class="text-white/50 text-[10px]">5d1s5ftv0.g.blackhole.localtau</div> <button class="text-white/40 hover:text-white"><i class="ri-more-2-fill text-xs"></i></button> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> </div> 
322<script type="module" src="/_astro/DreamDesktopWindow.astro_astro_type_script_index_0_lang.C8vB3kjN.js"></script>
322 
322<script>(function(){const id = "draggable-dream-window-lnco2c2";
323const activeTab = "projects";
324
325  let _docDrag = null;
326  let _docDragEnd = null;
327
328  function initDreamDesktopDrag() {
329    const windowEl = document.getElementById(id);
330    const dragHandle = windowEl?.querySelector('.drag-handle');
331    const container = windowEl?.parentElement;
332    if (!windowEl || !dragHandle || !container) return;
333
334    // Check if already bound to prevent duplicates
335    if (dragHandle._dragBound === true) return;
336    dragHandle._dragBound = true;
337
338    let isDragging = false;
339    let initialX = 0;
340    let initialY = 0;
341
342    function dragStart(e) {
343      if (e.button !== 0) return;
344      isDragging = true;
345      const rect = windowEl.getBoundingClientRect();
346      const containerRect = container.getBoundingClientRect();
347      initialX = e.clientX - rect.left;
348      initialY = e.clientY - rect.top;
349      windowEl.classList.remove('-translate-x-1/2', '-translate-y-1/2');
350      windowEl.classList.add('translate-x-0', 'translate-y-0');
351      const currentLeft = rect.left - containerRect.left;
352      const currentTop = rect.top - containerRect.top;
353      windowEl.style.left = currentLeft + 'px';
354      windowEl.style.top = currentTop + 'px';
355      document.body.style.cursor = 'grabbing';
356    }
357
358    function drag(e) {
359      if (!isDragging) return;
360      e.preventDefault();
361      const containerRect = container.getBoundingClientRect();
362      const windowRect = windowEl.getBoundingClientRect();
363      const newX = e.clientX - containerRect.left - initialX;
364      const newY = e.clientY - containerRect.top - initialY;
365      const maxX = containerRect.width - windowRect.width;
366      const maxY = containerRect.height - windowRect.height;
367      const boundedX = Math.max(0, Math.min(newX, maxX));
368      const boundedY = Math.max(0, Math.min(newY, maxY));
369      windowEl.style.left = boundedX + 'px';
370      windowEl.style.top = boundedY + 'px';
371    }
372
373    function dragEnd() {
374      if (!isDragging) return;
375      isDragging = false;
376      document.body.style.cursor = '';
377    }
378
379    dragHandle.addEventListener('mousedown', dragStart);
380    if (!_docDrag) {
381      _docDrag = drag;
382      _docDragEnd = dragEnd;
383      document.addEventListener('mousemove', _docDrag);
384      document.addEventListener('mouseup', _docDragEnd);
385      document.addEventListener('mouseleave', _docDragEnd);
386    }
387  }
388
389  // Initialize drag on page load
390  if (typeof window !== 'undefined') {
391    if (document.readyState === 'loading') {
392      document.addEventListener('DOMContentLoaded', initDreamDesktopDrag);
393    } else {
394      initDreamDesktopDrag();
395    }
396  }
397
398  // Re-initialize after view transitions
399  document.addEventListener('astro:page-load', () => {
400    requestAnimationFrame(initDreamDesktopDrag);
401  });
402
403  document.addEventListener('astro:before-swap', () => {
404    if (_docDrag) {
405      document.removeEventListener('mousemove', _docDrag);
406      document.removeEventListener('mouseup', _docDragEnd);
407      document.removeEventListener('mouseleave', _docDragEnd);
408      _docDrag = null;
409      _docDragEnd = null;
410    }
411  });
412
413  // Initialize vis-network in Network tab
414  function initNetworkIfNeeded(retries = 8) {
415    if (activeTab !== 'network') return;
416    const containerEl = document.getElementById(`${id}-network`);
417    if (!containerEl) {
418      if (retries > 0) setTimeout(() => initNetworkIfNeeded(retries - 1), 120);
419      return;
420    }
421    if ((containerEl)._visInit) return;
422    try {
423      function withVis(callback) {
424        const g = window;
425        if (g.vis && g.vis.Network && g.vis.DataSet) {
426          callback(g.vis);
427          return;
428        }
429        // Wait for npm import to load
430        setTimeout(() => {
431          if (g.vis && g.vis.Network && g.vis.DataSet) {
432            callback(g.vis);
433          } else {
434            console.error('vis-network failed to load');
435          }
436        }, 100);
437      }
438
439      withVis((vis) => {
440
441        const data = {
442          nodes: [
443            { id: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc', name: 'elder@blackhole', category: 0, value: { p2p: 13151 } },
444            { id: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs', name: 'monkey@blackhole', category: 1, value: { copies: 1, dns: 13404, http: 13100, p2p: 13263 } },
445            { id: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', name: 'hoarder@blackhole', category: 2, value: { copies: 1, dns: 13404, http: 13100, p2p: 13242 } },
446            { id: '12D3KooWAn9uLqFu3xiJywFpyppDxumfM4bztmReoBrKt68L5Dak', name: 'tns@blackhole', category: 3, value: { copies: 1, dns: 13404, http: 13566, p2p: 13326 } },
447            { id: '12D3KooWDShcNAro86QDo5HiWTbXnoG66YWK66PH3B2uA6Wz1x85', name: 'patrick@blackhole', category: 4, value: { copies: 1, dns: 13404, http: 13524, p2p: 13284 } },
448            { id: '12D3KooWKAqfJ8S7LzJMUsSB7MkefgDqHnucx6u2EsGDzGSeBxnJ', name: 'auth@blackhole', category: 5, value: { copies: 1, dns: 13404, http: 13545, p2p: 13221 } },
449            { id: '12D3KooWDoxzWtQTmRBycxpAqQ3UXCiCx6Qt8KYF6KcfWDN7Pj8P', name: 'seer@blackhole', category: 6, value: { copies: 1, dns: 13404, http: 13503, p2p: 13305 } },
450            { id: '12D3KooWLE7HGRCJoq7Nfzp55YV9AdLoBpdmJat9qDjmXsmWcbbd', name: 'gateway@blackhole', category: 7, value: { p2p: 13152 } },
451            { id: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K', name: 'substrate@blackhole', category: 8, value: { copies: 1, dns: 13404, http: 13629, p2p: 13382 } },
452          ],
453          links: [
454            { source: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc', target: '12D3KooWDShcNAro86QDo5HiWTbXnoG66YWK66PH3B2uA6Wz1x85' },
455            { source: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc', target: '12D3KooWDoxzWtQTmRBycxpAqQ3UXCiCx6Qt8KYF6KcfWDN7Pj8P' },
456            { source: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc', target: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K' },
457            { source: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc', target: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs' },
458            { source: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc', target: '12D3KooWAn9uLqFu3xiJywFpyppDxumfM4bztmReoBrKt68L5Dak' },
459            { source: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc', target: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP' },
460            { source: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc', target: '12D3KooWKAqfJ8S7LzJMUsSB7MkefgDqHnucx6u2EsGDzGSeBxnJ' },
461            { source: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc', target: '12D3KooWLE7HGRCJoq7Nfzp55YV9AdLoBpdmJat9qDjmXsmWcbbd' },
462            { source: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs', target: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc' },
463            { source: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs', target: '12D3KooWAn9uLqFu3xiJywFpyppDxumfM4bztmReoBrKt68L5Dak' },
464            { source: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs', target: '12D3KooWDShcNAro86QDo5HiWTbXnoG66YWK66PH3B2uA6Wz1x85' },
465            { source: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs', target: '12D3KooWKAqfJ8S7LzJMUsSB7MkefgDqHnucx6u2EsGDzGSeBxnJ' },
466            { source: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs', target: '12D3KooWDoxzWtQTmRBycxpAqQ3UXCiCx6Qt8KYF6KcfWDN7Pj8P' },
467            { source: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs', target: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP' },
468            { source: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs', target: '12D3KooWLE7HGRCJoq7Nfzp55YV9AdLoBpdmJat9qDjmXsmWcbbd' },
469            { source: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs', target: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K' },
470            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWLE7HGRCJoq7Nfzp55YV9AdLoBpdmJat9qDjmXsmWcbbd' },
471            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K' },
472            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWKAqfJ8S7LzJMUsSB7MkefgDqHnucx6u2EsGDzGSeBxnJ' },
473            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWDoxzWtQTmRBycxpAqQ3UXCiCx6Qt8KYF6KcfWDN7Pj8P' },
474            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc' },
475            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWAn9uLqFu3xiJywFpypp
475DxumfM4bztmReoBrKt68L5Dak' },
476            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs' },
477            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWDShcNAro86QDo5HiWTbXnoG66YWK66PH3B2uA6Wz1x85' },
478            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWLE7HGRCJoq7Nfzp55YV9AdLoBpdmJat9qDjmXsmWcbbd' },
479            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K' },
480            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs' },
481            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWAn9uLqFu3xiJywFpyppDxumfM4bztmReoBrKt68L5Dak' },
482            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc' },
483            { source: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K', target: '12D3KooWLE7HGRCJoq7Nfzp55YV9AdLoBpdmJat9qDjmXsmWcbbd' },
484            { source: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K', target: '12D3KooWDoxzWtQTmRBycxpAqQ3UXCiCx6Qt8KYF6KcfWDN7Pj8P' },
485            { source: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K', target: '12D3KooWAn9uLqFu3xiJywFpyppDxumfM4bztmReoBrKt68L5Dak' },
486            { source: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K', target: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc' },
487            { source: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K', target: '12D3KooWDShcNAro86QDo5HiWTbXnoG66YWK66PH3B2uA6Wz1x85' },
488            { source: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K', target: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP' },
489            { source: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K', target: '12D3KooWKAqfJ8S7LzJMUsSB7MkefgDqHnucx6u2EsGDzGSeBxnJ' },
490            { source: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K', target: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs' },
491          ],
492        };
493
494        const isDark = (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches));
495        const accentColor = '#099a40';
496        const linkColor = '#777777';
497
498        const nodes = new vis.DataSet(
499          data.nodes.map((n) => ({
500            id: n.id,
501            label: n.name.split('@')[0],
502            shape: 'image',
503            image: '/taubyte-node.svg',
504            size: 25
505          }))
506        );
507
508        const dedupedEdges = [];
509        const seenPairs = new Set();
510        data.links.forEach((l) => {
511          const key = [l.source, l.target].sort().join('|');
512          if (!seenPairs.has(key)) {
513            seenPairs.add(key);
514            dedupedEdges.push({ from: l.source, to: l.target });
515          }
516        });
517        const edges = new vis.DataSet(dedupedEdges);
518
519        const options = {
520          autoResize: true,
521          height: '100%',
522          width: '100%',
523          interaction: { hover: true, tooltipDelay: 50, zoomView: false, dragView: false },
524          nodes: {
525            shape: 'image',
526            shadow: { enabled: true, color: 'rgba(9,154,64,0.35)', size: 10, x: 0, y: 0 },
527            borderWidth: 0,
528            size: 25,
529            font: { size: 14, color: accentColor, vadjust: 2 },
530          },
531          edges: { width: 1, shadow: false, color: linkColor },
532          physics: {
533            solver: 'repulsion',
534            repulsion: {
535              nodeDistance: 100,
536              centralGravity: 0.15,
537              springLength: 220,
538              springConstant: 0.02,
539              damping: 0.09
540            }
541          },
542        };
543
544        const network = new vis.Network(containerEl, { nodes, edges }, options);
545        network.once('afterDrawing', () => network.fit({ maxZoomLevel: 0.8 }));
546        (containerEl)._visInit = true;
547        (containerEl)._visNetwork = network;
548      });
549    } catch (e) {
550      console.error('vis init error', e);
551    }
552  }
553
554  // Tear down the existing vis-network instance before a re-init so WebGL/canvas
555  // resources don't accumulate across view transitions.
556  function resetNetwork() {
557    const containerEl = document.getElementById(`${id}-network`);
558    if (!containerEl) return;
559    try { (containerEl)._visNetwork?.destroy?.(); } catch (_) {}
560    (containerEl)._visNetwork = null;
561    (containerEl)._visInit = false;
562  }
563
564  // Initialize on page load
565  if (typeof window !== 'undefined') {
566    if (document.readyState === 'loading') {
567      document.addEventListener('DOMContentLoaded', () => {
568        initNetworkIfNeeded();
569      });
570    } else {
571      initNetworkIfNeeded();
572    }
573  }
574
575  // Re-initialize network after view transitions
576  document.addEventListener('astro:page-load', () => {
577    requestAnimationFrame(() => {
578      resetNetwork();
579      initNetworkIfNeeded();
580    });
581  });
582  document.addEventListener('astro:after-swap', () => {
583    requestAnimationFrame(() => {
584      resetNetwork();
585      initNetworkIfNeeded();
586    });
587  });
588})();</script>
588 </div> <!-- Ship Desktop --><div class="platform-desktop absolute inset-0  z-1" data-platform="ship" style="display: none;"> <!-- Desktop Background --> <!-- Desktop Background --><div class="absolute inset-0 bg-cover bg-center rounded-2xl desktop-background" style="background-image: url('/desktop-ship-sail.png')"></div> <!-- Web Console Window --> <!-- Taubyte Console Window (Floating) --><div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-5xl shadow-[0_35px_60px_-12px_rgba(0,0,0,0.5)] rounded-lg console-window" id="draggable-window-ship" data-platform="ship"> <div class="bg-[#1a1a1a] rounded-lg overflow-hidden border border-white/10 flex flex-col" style="height: 520px;"> <!-- Browser Tabs --> <div class="bg-[#222] border-b border-white/10 px-4 py-1.5 flex items-center gap-1 cursor-move drag-handle" data-platform="ship"> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="ml-4 text-white/60 text-xs">Console</span> </div> <!-- Top Header Bar --> <div class="bg-[#2d2d2d] h-10 px-4 flex items-center justify-between border-b border-white/10"> <!-- Left: Logo and Menu --> <div class="flex items-center gap-4"> <i class="ri-menu-2-line text-white/60"></i> </div> <!-- Right: Icons and Actions --> <div class="flex items-center gap-4"> <div class="flex items-center gap-1.5 text-white/60 text-xs bg-white/5 px-2 py-1 rounded"> <i class="ri-git-branch-line text-white/60"></i> <span>main</span> </div> <i class="ri-notification-3-line text-white/60"></i> <i class="ri-question-line text-white/60"></i> <div class="flex items-center gap-2 text-white/60"> <img src="/samy-git-avatar.png" alt="Avatar" class="w-6 h-6 rounded-full border border-gray-500"> </div> </div> </div> <!-- Main Content --> <div class="flex flex-1 overflow-hidden"> <!-- Left Sidebar --> <div class="w-40 bg-[#252525] border-r border-white/10 p-3 space-y-0.5 overflow-auto flex flex-col"> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-home-line text-xs"></i> <span class="text-xs">Home</span> </div> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-function-line text-xs"></i> <span class="text-xs">Applications</span> </div> <div class="flex items-center gap-1.5 px-2 py-1 rounded text-white/60 hover:text-white hover:bg-white/10"> <i class="ri-flashlight-line text-xs"></i> <span class="text-xs">Functions</span> </div> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-stack-line text-xs"></i> <span class="text-xs">Libraries</span> </div> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-global-line text-xs"></i> <span class="text-xs">Websites</span> </div> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-hard-drive-2-line text-xs"></i> <span class="text-xs">Storages</span> </div> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-mail-line text-xs"></i> <span class="text-xs">Messaging</span> </div> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-database-2-line text-xs"></i> <span class="text-xs">Databases</span> </div> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-compass-3-line text-xs"></i> <span class="text-xs">Domains</span> </div> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-server-line text-xs"></i> <span class="text-xs">Services</span> </div> <div class="flex items-center gap-1.5 text-white/60 hover:text-white hover:bg-white/10 px-2 py-1 rounded"> <i class="ri-settings-4-line text-xs"></i> <span class="text-xs">SmartOps</span> </div> <div class="border-t border-white/10 my-1"></div> <div class="flex items-center gap-1.5 px-2 py-1 rounded text-green-500 bg-white/10"> <i class="ri-task-line text-xs"></i> <span class="text-xs">Builds</span> </div> <div class="flex items-center gap-1.5 text-white/60 px-2 py-1 rounded"> <i class="ri-archive-drawer-line text-xs"></i> <span class="text-xs text-gray-500">Config</span> </div> <div class="flex items-center gap-1.5 text-white/60 px-2 py-1 rounded"> <i class="ri-folder-line text-xs"></i> <span class="text-xs text-gray-500">Buckets</span> </div> <div class="mt-auto pt-2 text-[10px] text-gray-500 text-center">Version: 1.0.0</div> </div> <!-- Main Content Area --> <div class="flex-1 bg-[#1a1a1a] p-4 overflow-auto"> <div class="mb-2"> <span class="text-[10px] text-gray-500">Project > Builds</span> </div> <div class="mb-3"> <!-- Builds Content -->
589              <div class="flex items-center justify-between mb-4"> <h1 class="text-white text-base font-semibold tracking-wide">BUILDS</h1> <div class="flex items-center gap-3 text-xs text-white/60"> <div class="flex items-center gap-1"> <span>Show</span> <select class="bg-[#252525] border border-white/10 text-white text-xs px-1.5 py-0.5 rounded"> <option>5</option> <option>10</option> <option>25</option> <option>50</option> </select> <span>entries</span> </div> <div class="flex items-center gap-1"> <span>Search:</span> <input type="text" placeholder="..." class="bg-[#252525] border border-white/10 text-white text-xs px-2 py-0.5 rounded w-32"> </div> </div> </div>  <div class="bg-[#252525] rounded-lg overflow-hidden"> <table class="w-full"> <thead class="bg-[#2a2a2a]"> <tr> <th class="px-4 py-2 text-left text-xs font-medium text-white/70 uppercase tracking-wide"> <div class="flex items-center gap-1">
590Date
591<i class="ri-arrow-up-down-line text-xs opacity-50"></i> </div> </th> <th class="px-4 py-2 text-left text-xs font-medium text-white/70 uppercase tracking-wide"> <div class="flex items-center gap-1">
592Type
593<i class="ri-arrow-up-down-line text-xs opacity-50"></i> </div> </th> <th class="px-4 py-2 text-left text-xs font-medium text-white/70 uppercase tracking-wide"> <div class="flex items-center gap-1">
594Build Status
595<i class="ri-arrow-up-down-line text-xs opacity-50"></i> </div> </th> <th class="px-4 py-2 text-left text-xs font-medium text-white/70 uppercase tracking-wide"> <div class="flex items-center gap-1">
596Commit ID
597<i class="ri-arrow-up-down-line text-xs opacity-50"></i> </div> </th> <th class="px-4 py-2 text-left text-xs font-medium text-white/70 uppercase tracking-wide">Actions</th> </tr> </thead> <tbody class="divide-y divide-white/10"> <tr class="hover:bg-[#2a2a2a]"> <td class="px-3 py-2 text-xs text-white/80">05/10/2026 2:52:12 AM</td> <td class="px-3 py-2 text-xs text-white/80">Config</td> <td class="px-3 py-2"> <span class="bg-green-900/40 text-green-400 px-2 py-1 rounded text-xs">Success</span> </td> <td class="px-3 py-2 text-xs text-white/60 font-mono">f694e4f4105f23266d5d2eda6fc1836f1b7ad12e</td> <td class="px-3 py-2"> <div class="flex items-center gap-2"> <button class="text-green-500 hover:text-green-400"> <i class="ri-eye-line"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-external-link-line"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-forbid-line"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-refresh-line"></i> </button> </div> </td> </tr> <tr class="hover:bg-[#2a2a2a]"> <td class="px-3 py-2 text-xs text-white/80">05/10/2026 2:52:12 AM</td> <td class="px-3 py-2 text-xs text-white/80">Website</td> <td class="px-3 py-2"> <span class="bg-green-900/40 text-green-400 px-2 py-1 rounded text-xs">Success</span> </td> <td class="px-3 py-2 text-xs text-white/60 font-mono">a1b2c3d4e5f6789012345678901234567890abcd</td> <td class="px-3 py-2"> <div class="flex items-center gap-2"> <button class="text-green-500 hover:text-green-400"> <i class="ri-eye-line"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-external-link-line"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-forbid-line"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-refresh-line"></i> </button> </div> </td> </tr> <tr class="hover:bg-[#2a2a2a]"> <td class="px-3 py-2 text-xs text-white/80">05/10/2026 2:52:12 AM</td> <td class="px-3 py-2 text-xs text-white/80">Config</td> <td class="px-3 py-2"> <span class="bg-green-900/40 text-green-400 px-2 py-1 rounded text-xs">Success</span> </td> <td class="px-3 py-2 text-xs text-white/60 font-mono">9876543210abcdef1234567890abcdef12345678</td> <td class="px-3 py-2"> <div class="flex items-center gap-2"> <button class="text-green-500 hover:text-green-400"> <i class="ri-eye-line"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-external-link-line"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-forbid-line"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-refresh-line"></i> </button> </div> </td> </tr> <tr class="hover:bg-[#2a2a2a]"> <td class="px-3 py-2 text-xs text-white/80">05/10/2026 2:52:12 AM</td> <td class="px-3 py-2 text-xs text-white/80">Library</td> <td class="px-3 py-2"> <span class="bg-green-900/40 text-green-400 px-2 py-1 rounded text-xs">Success</span> </td> <td class="px-3 py-2 text-xs text-white/60 font-mono">
597aabbccddeeff1122334455667788990011223344</td> <td class="px-3 py-2"> <div class="flex items-center gap-2"> <button class="text-green-500 hover:text-green-400"> <i class="ri-eye-line"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-external-link-line"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-forbid-line"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-refresh-line"></i> </button> </div> </td> </tr> <tr class="hover:bg-[#2a2a2a]"> <td class="px-3 py-2 text-xs text-white/80">05/10/2026 2:52:12 AM</td> <td class="px-3 py-2 text-xs text-white/80">Library</td> <td class="px-3 py-2"> <span class="bg-green-900/40 text-green-400 px-2 py-1 rounded text-xs">Success</span> </td> <td class="px-3 py-2 text-xs text-white/60 font-mono">5566778899001122334455667788990011223344</td> <td class="px-3 py-2"> <div class="flex items-center gap-2"> <button class="text-green-500 hover:text-green-400"> <i class="ri-eye-line"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-external-link-line"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-forbid-line"></i> </button> <button class="text-green-500 hover:text-green-400"> <i class="ri-refresh-line"></i> </button> </div> </td> </tr> </tbody> </table> </div>  <div class="flex items-center justify-between mt-4"> <button class="bg-green-600 hover:bg-green-700 text-white px-3 py-1 rounded text-xs font-medium">
598Refresh
599</button> <!-- Pagination --> <div class="flex items-center gap-1"> <button class="px-2 py-0.5 text-white/60 hover:text-white text-[10px]">«</button> <button class="px-2 py-0.5 text-white/60 hover:text-white text-[10px]">‹</button> <button class="px-2 py-0.5 bg-green-500 text-white text-[10px] rounded">1</button> <button class="px-2 py-0.5 text-white/60 hover:text-white text-[10px]">›</button> <button class="px-2 py-0.5 text-white/60 hover:text-white text-[10px]">»</button> </div> </div>  </div> </div> </div> <!-- Floating Action Button -->  </div> </div> 
599<script>(function(){const id = "draggable-window-ship";
600const platform = "ship";
601
602  let _docDrag = null;
603  let _docDragEnd = null;
604
605  function initWebConsoleWindow() {
606    const window = document.getElementById(id);
607    const dragHandle = document.querySelector(`.drag-handle[data-platform="${platform}"]`);
608    const container = window?.parentElement;
609    
610    if (!window || !dragHandle || !container) return;
611    
612    // Check if already bound to prevent duplicates
613    if (dragHandle._dragBound === true) return;
614    dragHandle._dragBound = true;
615    
616    let isDragging = false;
617    let initialX = 0;
618    let initialY = 0;
619    
620    function dragStart(e) {
621      if (e.button !== 0) return;
622      
623      isDragging = true;
624      
625      const rect = window.getBoundingClientRect();
626      const containerRect = container.getBoundingClientRect();
627      
628      // Calculate where we clicked relative to the window
629      initialX = e.clientX - rect.left;
630      initialY = e.clientY - rect.top;
631      
632      // Remove transform classes and set initial position
633      window.classList.remove('-translate-x-1/2', '-translate-y-1/2');
634      window.classList.add('translate-x-0', 'translate-y-0');
635      
636      // Get current position
637      const currentLeft = rect.left - containerRect.left;
638      const currentTop = rect.top - containerRect.top;
639      
640      // Set initial positions
641      window.style.left = currentLeft + 'px';
642      window.style.top = currentTop + 'px';
643      
644      window.classList.add('user-select-none');
645      document.body.style.cursor = 'grabbing';
646    }
647    
648    function drag(e) {
649      if (!isDragging) return;
650      
651      e.preventDefault();
652      
653      const containerRect = container.getBoundingClientRect();
654      const windowRect = window.getBoundingClientRect();
655      
656      // Calculate new position
657      const newX = e.clientX - containerRect.left - initialX;
658      const newY = e.clientY - containerRect.top - initialY;
659      
660      // Keep window within container bounds
661      const maxX = containerRect.width - windowRect.width;
662      const maxY = containerRect.height - windowRect.height;
663      
664      const boundedX = Math.max(0, Math.min(newX, maxX));
665      const boundedY = Math.max(0, Math.min(newY, maxY));
666      
667      window.style.left = boundedX + 'px';
668      window.style.top = boundedY + 'px';
669    }
670    
671    function dragEnd() {
672      if (!isDragging) return;
673      
674      isDragging = false;
675      window.classList.remove('user-select-none');
676      document.body.style.cursor = '';
677    }
678    
679    dragHandle.addEventListener('mousedown', dragStart);
680    if (!_docDrag) {
681      _docDrag = drag;
682      _docDragEnd = dragEnd;
683      document.addEventListener('mousemove', _docDrag);
684      document.addEventListener('mouseup', _docDragEnd);
685      document.addEventListener('mouseleave', _docDragEnd);
686    }
687  }
688
689  // Initialize on page load
690  if (typeof window !== 'undefined') {
691    if (document.readyState === 'loading') {
692      document.addEventListener('DOMContentLoaded', initWebConsoleWindow);
693    } else {
694      initWebConsoleWindow();
695    }
696  }
697
698  // Re-initialize after view transitions
699  document.addEventListener('astro:page-load', () => {
700    requestAnimationFrame(initWebConsoleWindow);
701  });
702
703  document.addEventListener('astro:before-swap', () => {
704    if (_docDrag) {
705      document.removeEventListener('mousemove', _docDrag);
706      document.removeEventListener('mouseup', _docDragEnd);
707      document.removeEventListener('mouseleave', _docDragEnd);
708      _docDrag = null;
709      _docDragEnd = null;
710    }
711  });
712})();</script>
712 </div> <!-- Switcher - Only show if not in screenshot mode --> <!-- Switcher - Half floating, half inside --><div class="absolute -top-6 left-1/2 -translate-x-1/2 z-10 flex justify-center" data-astro-cid-mw4b5lvp> <div class="platform-switcher-container relative inline-flex rounded-full p-1 bg-[#151515]/80 dark:bg-[#151515]/80 backdrop-blur-md dark:border dark:border-white/10 transition-colors shadow-lg" role="tablist" aria-label="Platform options" data-astro-cid-mw4b5lvp> <!-- Sliding indicator --> <div class="platform-switcher-indicator absolute rounded-full bg-white shadow-sm transition-all duration-300 ease-linear" style="height: calc(100% - 8px); top: 4px; left: 4px; width: calc(25% - 8px);" data-astro-cid-mw4b5lvp></div> <button class="platform-switcher-btn relative px-6 py-2 text-black font-medium text-sm transition-all duration-300 ease-linear" role="tab" aria-selected="true" aria-controls="panel-your-cloud" data-astro-cid-mw4b5lvp>
713Your Cloud
714</button> <button class="platform-switcher-btn relative px-6 py-2 text-sm font-medium transition-all duration-300 ease-linear text-white" role="tab" aria-selected="false" aria-controls="panel-build" data-astro-cid-mw4b5lvp>
715Build
716</button> <button class="platform-switcher-btn relative px-6 py-2 text-sm font-medium transition-all duration-300 ease-linear text-white" role="tab" aria-selected="false" aria-controls="panel-test" data-astro-cid-mw4b5lvp>
717Test
718</button> <button class="platform-switcher-btn relative px-6 py-2 text-sm font-medium transition-all duration-300 ease-linear text-white" role="tab" aria-selected="false" aria-controls="panel-ship" data-astro-cid-mw4b5lvp>
719Ship
720</button> </div> </div> 
720<script type="module">function p(){const r=document.querySelector(".platform-switcher-container");if(!r)return;const a=r.querySelectorAll(".platform-switcher-btn"),l=r.querySelector(".platform-switcher-indicator");document.querySelectorAll(".platform-desktop").forEach(o=>{const t=o;t.style.transition="opacity 0.4s ease-in-out",t.dataset.platform==="your-cloud"?(t.style.display="block",t.style.opacity="1",t.classList.add("fade-in"),t.classList.remove("fade-out")):(t.style.opacity="0",t.classList.add("fade-out"),t.classList.remove("fade-in"),t.style.display="none")});function c(o){if(!l)return;const t=o.closest(".platform-switcher-container");if(!t)return;const i=o.getBoundingClientRect(),d=t.getBoundingClientRect(),n=i.left-d.left,e=i.width;l.style.left=`${n}px`,l.style.width=`${e}px`}l&&a.length>0&&c(a[0]),a.forEach(o=>{const t=o;t._platformBound!==!0&&(t._platformBound=!0,t.addEventListener("click",()=>{a.forEach(e=>{e.classList.remove("text-black"),e.classList.add("text-white"),e.setAttribute("aria-selected","false")}),t.classList.remove("text-white"),t.classList.add("text-black"),t.setAttribute("aria-selected","true"),c(t);const i=t.getAttribute("aria-controls"),n={"panel-your-cloud":"your-cloud","panel-build":"build","panel-test":"test","panel-ship":"ship"}[i||""];if(n){const e=document.querySelector(`.platform-desktop[data-platform="${n}"]`);if(!e)return;document.querySelectorAll(".platform-desktop").forEach(f=>{const s=f;s!==e&&(s.style.transition="opacity 0.4s ease-in-out",s.style.opacity="0",s.classList.add("fade-out"),s.classList.remove("fade-in"),s.style.display!=="none"&&setTimeout(()=>{s.style.display="none"},400))}),e.style.display==="none"&&(e.style.display="block",e.style.opacity="0",e.classList.remove("fade-out"),e.offsetHeight,requestAnimationFrame(()=>{e.style.opacity="1",e.classList.add("fade-in")}))}}))})}document.addEventListener("astro:page-load",()=>{p()});document.addEventListener("reinit-switchers",()=>{p()});</script>
720 <!-- Platform Info Bar --> <!-- Platform Info Bar --><div class="absolute -bottom-10 left-0 right-0 bg-[#101010]/90 backdrop-blur-md rounded-b-2xl px-4 pt-24 pb-2 shadow-lg z-0"> <!-- Platform-specific content --> <div class="platform-content text-center"> <div class="platform-info text-gray-300 text-sm md:text-base lg:text-lg " data-platform="your-cloud"> Run Taubyte on infrastructure you control: private, hybrid, or provider environments — including the edge </div><div class="platform-info text-gray-300 text-sm md:text-base lg:text-lg hidden" data-platform="build"> Create software locally with developers and coding agents in one fullstack workspace </div><div class="platform-info text-gray-300 text-sm md:text-base lg:text-lg hidden" data-platform="test"> Keep local work grounded in production-like behavior with Dream CLI, MCP, and desktop tools </div><div class="platform-info text-gray-300 text-sm md:text-base lg:text-lg hidden" data-platform="ship"> Push to Git and let Taubyte deploy, route, and run it on your infrastructure </div> </div> </div> 
720<script type="module">function i(){const e=document.querySelector(".platform-content");if(!e||e.dataset.initialized==="true")return;e.dataset.initialized="true";const l=document.querySelectorAll(".platform-info");function a(o){l.forEach(n=>{const t=n;t.dataset.platform===o?t.classList.remove("hidden"):t.classList.add("hidden")})}document.querySelectorAll(".platform-switcher-btn").forEach(o=>{o.addEventListener("click",()=>{const n={"panel-your-cloud":"your-cloud","panel-build":"build","panel-test":"test","panel-ship":"ship"},t=o.getAttribute("aria-controls"),r=n[t||""];r&&a(r)})}),a("your-cloud")}document.addEventListener("astro:page-load",()=>{i()});</script>
720 </div> </div> <!-- Mobile Platform Cards --> <!-- Mobile Platform Cards --><div class="lg:hidden"> <div class="mt-8"> <div class="space-y-12"> <div class="relative"> <!-- Floating Title --> <div class="absolute -top-6 left-1/2 -translate-x-1/2 z-10"> <div class="bg-[#151515]/80 dark:bg-[#151515]/80 backdrop-blur-md border border-white/10 rounded-full px-6 py-2 shadow-lg"> <h3 class="text-sm font-medium text-white"> Your Cloud </h3> </div> </div> <div class="bg-[#1a1a1a] border border-white/10 rounded-lg overflow-hidden hover:border-white/20 transition-colors"> <!-- Screenshot preview --> <div class="aspect-video bg-[#2a2a2a] flex items-center justify-center"> <img src="/screenshots/your-cloud-desktop.png" alt="Your Cloud desktop interface" class="w-full h-full object-cover" loading="lazy"> </div> <!-- Content --> <div class="p-3 text-center"> <p class="text-sm md:text-base lg:text-lg text-gray-300"> Run Taubyte on infrastructure you control: private, hybrid, or provider environments — including the edge </p> </div> </div> </div><div class="relative"> <!-- Floating Title --> <div class="absolute -top-6 left-1/2 -translate-x-1/2 z-10"> <div class="bg-[#151515]/80 dark:bg-[#151515]/80 backdrop-blur-md border border-white/10 rounded-full px-6 py-2 shadow-lg"> <h3 class="text-sm font-medium text-white"> Build </h3> </div> </div> <div class="bg-[#1a1a1a] border border-white/10 rounded-lg overflow-hidden hover:border-white/20 transition-colors"> <!-- Screenshot preview --> <div class="aspect-video bg-[#2a2a2a] flex items-center justify-center"> <img src="/screenshots/build-desktop.png" alt="Build desktop interface" class="w-full h-full object-cover" loading="lazy"> </div> <!-- Content --> <div class="p-3 text-center"> <p class="text-sm md:text-base lg:text-lg text-gray-300"> Create software locally with developers and coding agents in one fullstack workspace </p> </div> </div> </div><div class="relative"> <!-- Floating Title --> <div class="absolute -top-6 left-1/2 -translate-x-1/2 z-10"> <div class="bg-[#151515]/80 dark:bg-[#151515]/80 backdrop-blur-md border border-white/10 rounded-full px-6 py-2 shadow-lg"> <h3 class="text-sm font-medium text-white"> Test </h3> </div> </div> <div class="bg-[#1a1a1a] border border-white/10 rounded-lg overflow-hidden hover:border-white/20 transition-colors"> <!-- Screenshot preview --> <div class="aspect-video bg-[#2a2a2a] flex items-center justify-center"> <img src="/screenshots/test-desktop.png" alt="Test desktop interface" class="w-full h-full object-cover" loading="lazy"> </div> <!-- Content --> <div class="p-3 text-center"> <p class="text-sm md:text-base lg:text-lg text-gray-300"> Keep local work grounded in production-like behavior with Dream CLI, MCP, and desktop tools </p> </div> </div> </div><div class="relative"> <!-- Floating Title --> <div class="absolute -top-6 left-1/2 -translate-x-1/2 z-10"> <div class="bg-[#151515]/80 dark:bg-[#151515]/80 backdrop-blur-md border border-white/10 rounded-full px-6 py-2 shadow-lg"> <h3 class="text-sm font-medium text-white"> Ship </h3> </div> </div> <div class="bg-[#1a1a1a] border border-white/10 rounded-lg overflow-hidden hover:border-white/20 transition-colors"> <!-- Screenshot preview --> <div class="aspect-video bg-[#2a2a2a] flex items-center justify-center"> <img src="/screenshots/ship-desktop.png" alt="Ship desktop interface" class="w-full h-full object-cover" loading="lazy"> </div> <!-- Content --> <div class="p-3 text-center"> <p class="text-sm md:text-base lg:text-lg text-gray-300"> Push to Git and let Taubyte deploy, route, and run it on your infrastructure </p> </div> </div> </div> </div> </div> </div> </div> </section> <section id="features-section" class="relative px-6 mt-16" aria-labelledby="features-heading"> <div class="container mx-auto max-w-7xl"> <h2 id="features-heading" class="sr-only">
721Build, test, and ship in one workspace
722</h2> <div id="feature-your-own-cloud" class="rounded-2xl bg-black/10 dark:bg-[#111] p-6 md:p-8 mb-8"> <div class="flex flex-col lg:flex-row gap-8 items-center"> <div class="order-1 lg:order-1 shrink-0 w-full lg:w-1/3"> <div> <div> <a href="/features#your-own-cloud" class="inline-flex items-center gap-2 text-xl md:text-2xl font-semibold leading-tight text-black dark:text-white hover:opacity-80"> Customer-Owned Cloud <i class="ri-arrow-right-line mt-1" aria-hidden="true"></i> </a> <p class="mt-4 text-base md:text-lg text-black/70 dark:text-white/70 max-w-2xl">
722Run Taubyte on infrastructure you control: on-prem, private, hybrid, or provider environments, including the edge.</p>  </div>  </div> </div> <div class="order-2 lg:order-2 grow w-full lg:w-2/3"> <div> <!-- Mobile: Static screenshot --> <div class="lg:hidden relative rounded-xl overflow-hidden bg-[#0b0b0b] aspect-16/10 w-full"> <img src="/screenshots/your-own-cloud-feature-desktop.png" alt="Customer-Owned Cloud feature interface" class="w-full h-full object-cover" loading="lazy"> </div> <!-- Desktop: Interactive component --> <div class="hidden lg:block relative rounded-xl overflow-hidden bg-[#0b0b0b] aspect-16/10 w-full"> <img src="/amazigh-desert-background.png" alt="" class="absolute inset-0 h-full w-full object-cover pointer-events-none" loading="lazy"> <!-- Desktop windows --> <div class="absolute inset-0"> <div class="relative w-full h-full overflow-hidden"> <!-- Login Window - positioned away from top and left --> <div class="absolute inset-0" style="transform: translate(-5%, -5%);"> <!-- Browser Window with Login Page (Floating) --><div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-xl shadow-[0_35px_60px_-12px_rgba(0,0,0,0.5)] rounded-lg" id="draggable-window-cloud-login" data-platform="cloud-login"> <div class="bg-[#1a1a1a] rounded-lg overflow-hidden border border-white/10 flex flex-col" style="height: 380px;"> <!-- Browser Window Controls --> <div class="bg-[#222] border-b border-white/10 px-4 py-1 flex items-center gap-1 cursor-move drag-handle" data-platform="cloud-login"> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span id="loginWindowTitle" class="ml-4 text-white/60 text-xs">Taubyte Cloud Login</span> </div> <!-- Browser Address Bar --> <div class="bg-[#2d2d2d] px-4 py-1 border-b border-white/10"> <div class="flex items-center gap-2"> <!-- Navigation Buttons --> <div class="flex items-center gap-1"> <button class="w-5 h-5 flex items-center justify-center text-white/40 hover:text-white/70 hover:bg-white/10 rounded"> <i class="ri-arrow-left-s-line text-xs"></i> </button> <button class="w-5 h-5 flex items-center justify-center text-white/40 hover:text-white/70 hover:bg-white/10 rounded"> <i class="ri-arrow-right-s-line text-xs"></i> </button> <button class="w-5 h-5 flex items-center justify-center text-white/40 hover:text-white/70 hover:bg-white/10 rounded"> <i class="ri-refresh-line text-xs"></i> </button> </div> <!-- Address Bar --> <div class="flex-1 bg-[#1a1a1a] border border-white/10 rounded px-2 py-1 flex items-center gap-1.5"> <i id="loginLockIcon" class="ri-lock-line text-green-500 text-[10px]"></i> <span id="loginAddressUrl" class="text-white/70 text-[10px]">https://cloud.taubyte.com/login</span> </div> <!-- Browser Menu --> <div class="flex items-center gap-2"> <button class="w-5 h-5 flex items-center justify-center text-white/40 hover:text-white/70 hover:bg-white/10 rounded"> <i class="ri-more-2-line text-xs"></i> </button> </div> </div> </div> <!-- Browser Content - Login Page --> <div class="flex-1 bg-[#1a1a1a] overflow-auto"> <!-- Login Page Content --> <div class="min-h-full flex items-center justify-center bg-gradient-to-br from-[#1a1a1a] to-[#2d2d2d] p-3"> <div class="w-full max-w-sm"> <!-- Login Form --> <div class="bg-[#252525] rounded-lg border border-white/10 p-3 shadow-lg"> <form class="space-y-2"> <!-- Logo --> <div class="flex justify-center mb-2"> <img id="loginLogo" src="/taubyte-logo-icon.svg" alt="Taubyte" class="max-h-8 w-auto"> </div> <!-- Email/Username Field --> <div> <input type="text" id="email" placeholder="Email or Username" class="w-full bg-[#1a1a1a] border border-white/10 rounded-md px-2 py-1 text-white placeholder:text-white/40 text-[10px] focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent transition-all"> </div> <!-- Password Field --> <div> <div class="relative"> <input type="password" id="password" placeholder="Password" class="w-full bg-[#1a1a1a] border border-white/10 rounded-md px-2 py-1 text-white placeholder:text-white/40 text-[10px] focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent transition-all pr-8"> <button type="button" class="absolute right-2 top-1/2 -translate-y-1/2 text-white/40 hover:text-white/70"> <i class="ri-eye-off-line text-[10px]"></i> </button> </div> </div> <!-- Remember Me & Forgot Password --> <div class="flex items-center justify-between text-[10px]"> <label class="flex items-center gap-1 cursor-pointer"> <input type="checkbox" class="w-3 h-3 rounded border-white/20 bg-[#1a1a1a] text-green-500 focus:ring-green-500 focus:ring-offset-0"> <span class="text-white/70">Remember me</span> </label> <a id="loginForgotPasswordLink" href="#" class="text-green-500 hover:text-green-400 transition-colors text-[10px]">
723Forgot password?
724</a> </div> <!-- Sign In Button --> <button type="submit" id="loginSignInButton" class="w-full bg-green-600 hover:bg-green-700 text-white font-medium py-1 px-3 rounded-md transition-colors shadow-lg text-[10px]">
725Sign In
726</button> <!-- Divider --> <div class="relative my-2"> <div class="absolute inset-0 flex items-center"> <div class="w-full border-t border-white/10"></div> </div> <div class="relative flex justify-center text-[10px]"> <span class="px-2 bg-[#252525] text-white/40">Or continue with</span> </div> </div> <!-- Social Login Buttons --> <div class="grid grid-cols-3 gap-1.5"> <button type="button" class="flex items-center justify-center gap-1 bg-[#1a1a1a] border border-white/10 text-white/70 hover:text-white hover:border-white/20 px-2 py-1 rounded-md transition-colors text-[10px]"> <i class="ri-github-fill text-xs"></i> <span>GitHub</span> </button> <button type="button" class="flex items-center justify-center gap-1 bg-[#1a1a1a] border border-white/10 text-white/70 hover:text-white hover:border-white/20 px-2 py-1 rounded-md transition-colors text-[10px]"> <i class="ri-gitlab-fill text-xs"></i> <span>GitLab</span> </button> <button type="button" class="flex items-center justify-center gap-1 bg-[#1a1a1a] border border-white/10 text-white/70 hover:text-white hover:border-white/20 px-2 py-1 rounded-md transition-colors text-[10px]">
726 <i class="ri-code-s-slash-line text-xs"></i> <span>Bitbucket</span> </button> </div> <!-- Sign Up Link --> <div class="text-center text-[10px] mt-2"> <span class="text-white/60">Don't have an account? </span> <a id="loginSignUpLink" href="#" class="text-green-500 hover:text-green-400 font-medium transition-colors">
727Sign up
728</a> </div> </form> </div> </div> </div> </div> </div> </div> 
728<script>(function(){const id = "draggable-window-cloud-login";
729const platform = "cloud-login";
730
731  let _docDrag = null;
732  let _docDragEnd = null;
733
734  function initLoginWindow() {
735    const window = document.getElementById(id);
736    if (!window) {
737      // Retry after a short delay if element isn't ready (for view transitions)
738      setTimeout(initLoginWindow, 50);
739      return;
740    }
741    
742    // Skip if already initialized
743    if (window.dataset.loginInitialized === 'true') {
744      return;
745    }
746    window.dataset.loginInitialized = 'true';
747    
748    const dragHandle = document.querySelector(`.drag-handle[data-platform="${platform}"]`);
749    const container = window?.parentElement;
750    
751    if (!dragHandle || !container) {
752      // Elements might not be ready yet, retry
753      window.dataset.loginInitialized = 'false';
754      setTimeout(initLoginWindow, 50);
755      return;
756    }
757    
758    let isDragging = false;
759    let initialX = 0;
760    let initialY = 0;
761    
762    function dragStart(e) {
763      if (e.button !== 0) return;
764      
765      isDragging = true;
766      
767      const rect = window.getBoundingClientRect();
768      const containerRect = container.getBoundingClientRect();
769      
770      // Calculate where we clicked relative to the window
771      initialX = e.clientX - rect.left;
772      initialY = e.clientY - rect.top;
773      
774      // Remove transform classes and set initial position
775      window.classList.remove('-translate-x-1/2', '-translate-y-1/2');
776      window.classList.add('translate-x-0', 'translate-y-0');
777      
778      // Get current position
779      const currentLeft = rect.left - containerRect.left;
780      const currentTop = rect.top - containerRect.top;
781      
782      // Set initial positions
783      window.style.left = currentLeft + 'px';
784      window.style.top = currentTop + 'px';
785      
786      window.classList.add('user-select-none');
787      document.body.style.cursor = 'grabbing';
788    }
789    
790    function drag(e) {
791      if (!isDragging) return;
792      
793      e.preventDefault();
794      
795      const containerRect = container.getBoundingClientRect();
796      const windowRect = window.getBoundingClientRect();
797      
798      // Calculate new position
799      const newX = e.clientX - containerRect.left - initialX;
800      const newY = e.clientY - containerRect.top - initialY;
801      
802      // Keep window within container bounds
803      const maxX = containerRect.width - windowRect.width;
804      const maxY = containerRect.height - windowRect.height;
805      
806      const boundedX = Math.max(0, Math.min(newX, maxX));
807      const boundedY = Math.max(0, Math.min(newY, maxY));
808      
809      window.style.left = boundedX + 'px';
810      window.style.top = boundedY + 'px';
811    }
812    
813    function dragEnd() {
814      if (!isDragging) return;
815      
816      isDragging = false;
817      window.classList.remove('user-select-none');
818      document.body.style.cursor = '';
819    }
820    
821    dragHandle.addEventListener('mousedown', dragStart);
822    if (!_docDrag) {
823      _docDrag = drag;
824      _docDragEnd = dragEnd;
825      document.addEventListener('mousemove', _docDrag);
826      document.addEventListener('mouseup', _docDragEnd);
827      document.addEventListener('mouseleave', _docDragEnd);
828    }
829  }
830
831  // Initialize on DOM ready
832  if (document.readyState === 'loading') {
833    document.addEventListener('DOMContentLoaded', initLoginWindow);
834  } else {
835    initLoginWindow();
836  }
837
838  // Also initialize after view transitions
839  document.addEventListener('astro:page-load', initLoginWindow);
840  document.addEventListener('astro:after-swap', initLoginWindow);
841
842  document.addEventListener('astro:before-swap', () => {
843    if (_docDrag) {
844      document.removeEventListener('mousemove', _docDrag);
845      document.removeEventListener('mouseup', _docDragEnd);
846      document.removeEventListener('mouseleave', _docDragEnd);
847      _docDrag = null;
848      _docDragEnd = null;
849    }
850  });
851})();</script>
851 </div> <!-- Settings Window - positioned to the right and slightly down --> <div class="absolute inset-0" style="transform: translate(20%, 15%);"> <!-- Settings Window (Floating) --><div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-xs shadow-[0_35px_60px_-12px_rgba(0,0,0,0.5)] rounded-lg" id="draggable-settings-window-cloud-settings" data-platform="cloud-settings"> <div class="bg-[#1a1a1a] rounded-lg overflow-hidden border border-white/10 flex flex-col"> <!-- Window Title Bar --> <div class="bg-[#222] border-b border-white/10 px-4 py-1 flex items-center gap-1 cursor-move drag-handle" data-platform="cloud-settings"> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="ml-4 text-white/60 text-xs">Settings</span> </div> <!-- Window Content --> <div class="flex-1 bg-[#1a1a1a] overflow-auto"> <!-- Settings Content --> <div class="p-4"> <div class="space-y-3"> <!-- Logo Drop Zone --> <div> <div id="logoDropZone" class="w-full h-20 bg-[#252525] border-2 border-dashed border-white/20 rounded-md flex items-center justify-center cursor-pointer hover:border-green-500 hover:bg-[#2d2d2d] transition-colors"> <input type="file" id="logoUpload" accept="image/*" class="hidden"> <div id="logoDropText" class="text-center"> <i class="ri-image-add-line text-white/40 text-lg block mb-1"></i> <span class="text-[10px] text-white/60">Drop logo here or click to browse</span> </div> </div> </div> <!-- Main Color --> <div class="flex items-center gap-2"> <label for="mainColor" class="text-[10px] text-white/60 whitespace-nowrap">Main Color</label> <input type="color" id="mainColor" value="#22c55e" class="flex-1 h-8 bg-[#252525] border border-white/10 rounded-md cursor-pointer"> </div> <!-- Domain --> <div class="flex items-center gap-2"> <label for="domain" class="text-[10px] text-white/60 whitespace-nowrap">Domain</label> <input type="text" id="domain" placeholder="cloud.taubyte.com" value="cloud.taubyte.com" class="flex-1 bg-[#252525] border border-white/10 rounded-md px-2 py-1 text-white placeholder:text-white/40 text-[10px] focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent transition-all"> </div> <!-- Company Name --> <div class="flex items-center gap-2"> <label for="companyName" class="text-[10px] text-white/60 whitespace-nowrap">Company Name</label> <input type="text" id="companyName" placeholder="Company Name" value="Taubyte" class="flex-1 bg-[#252525] border border-white/10 rounded-md px-2 py-1 text-white placeholder:text-white/40 text-[10px] focus:outline-none focus:ring-2 focus:ring-green-500 focus:border-transparent transition-all"> </div> </div> </div> </div> </div> </div> 
851<script>(function(){const id = "draggable-settings-window-cloud-settings";
852const platform = "cloud-settings";
853
854  let _docDrag = null;
855  let _docDragEnd = null;
856
857  function initSettingsWindow() {
858    const window = document.getElementById(id);
859    if (!window) {
860      // Retry after a short delay if element isn't ready (for view transitions)
861      setTimeout(initSettingsWindow, 50);
862      return;
863    }
864    
865    // Skip if already initialized (check for data attribute)
866    if (window.dataset.settingsInitialized === 'true') {
867      return;
868    }
869    window.dataset.settingsInitialized = 'true';
870    
871    const dragHandle = document.querySelector(`.drag-handle[data-platform="${platform}"]`);
872    const container = window?.parentElement;
873    
874    if (!dragHandle || !container) {
875      // Elements might not be ready yet, retry
876      window.dataset.settingsInitialized = 'false';
877      setTimeout(initSettingsWindow, 50);
878      return;
879    }
880    
881    let isDragging = false;
882    let initialX = 0;
883    let initialY = 0;
884    
885    function dragStart(e) {
886      if (e.button !== 0) return;
887      
888      isDragging = true;
889      
890      const rect = window.getBoundingClientRect();
891      const containerRect = container.getBoundingClientRect();
892      
893      initialX = e.clientX - rect.left;
894      initialY = e.clientY - rect.top;
895      
896      window.classList.remove('-translate-x-1/2', '-translate-y-1/2');
897      window.classList.add('translate-x-0', 'translate-y-0');
898      
899      const currentLeft = rect.left - containerRect.left;
900      const currentTop = rect.top - containerRect.top;
901      
902      window.style.left = currentLeft + 'px';
903      window.style.top = currentTop + 'px';
904      
905      window.classList.add('user-select-none');
906      document.body.style.cursor = 'grabbing';
907    }
908    
909    function drag(e) {
910      if (!isDragging) return;
911      
912      e.preventDefault();
913      
914      const containerRect = container.getBoundingClientRect();
915      const windowRect = window.getBoundingClientRect();
916      
917      const newX = e.clientX - containerRect.left - initialX;
918      const newY = e.clientY - containerRect.top - initialY;
919      
920      const maxX = containerRect.width - windowRect.width;
921      const maxY = containerRect.height - windowRect.height;
922      
923      const boundedX = Math.max(0, Math.min(newX, maxX));
924      const boundedY = Math.max(0, Math.min(newY, maxY));
925      
926      window.style.left = boundedX + 'px';
927      window.style.top = boundedY + 'px';
928    }
929    
930    function dragEnd() {
931      if (!isDragging) return;
932      
933      isDragging = false;
934      window.classList.remove('user-select-none');
935      document.body.style.cursor = '';
936    }
937    
938    dragHandle.addEventListener('mousedown', dragStart);
939    if (!_docDrag) {
940      _docDrag = drag;
941      _docDragEnd = dragEnd;
942      document.addEventListener('mousemove', _docDrag);
943      document.addEventListener('mouseup', _docDragEnd);
944      document.addEventListener('mouseleave', _docDragEnd);
945    }
946
947    // Logo upload functionality
948    const logoDropZone = document.getElementById('logoDropZone');
949    const logoUpload = document.getElementById('logoUpload');
950
951    if (logoDropZone && logoUpload) {
952      // Click to browse
953      logoDropZone.addEventListener('click', () => {
954        logoUpload.click();
955      });
956
957      // File input change
958      logoUpload.addEventListener('change', (e) => {
959        const file = e.target.files?.[0];
960        if (file && file.type.startsWith('image/')) {
961          handleLogoFile(file);
962        }
963      });
964
965      // Drag and drop
966      logoDropZone.addEventListener('dragover', (e) => {
967        e.preventDefault();
968        e.stopPropagation();
969        logoDropZone.classList.add('border-green-500', 'bg-[#2d2d2d]');
970      });
971
972      logoDropZone.addEventListener('dragleave', (e) => {
973        e.preventDefault();
974        e.stopPropagation();
975        logoDropZone.classList.remove('border-green-500', 'bg-[#2d2d2d]');
976      });
977
978      logoDropZone.addEventListener('drop', (e) => {
979        e.preventDefault();
980        e.stopPropagation();
981        logoDropZone.classList.remove('border-green-500', 'bg-[#2d2d2d]');
982        
983        const file = e.dataTransfer.files?.[0];
984        if (file && file.type.startsWith('image/')) {
985          logoUpload.files = e.dataTransfer.files;
986          handleLogoFile(file);
987        }
988      });
989
990      function handleLogoFile(file) {
991        const reader = new FileReader();
992        reader.onload = (e) => {
993          // Update login window logo directly
994          const loginLogo = document.getElementById('loginLogo');
995          if (loginLogo) {
996            loginLogo.src = e.target.result;
997          }
998        };
999        reader.readAsDataURL(file);
1000      }
1001    }
1002
1003    // Update login window when settings change
1004    const mainColorInput = document.getElementById('mainColor');
1005    const domainInput = document.getElementById('domain');
1006    const companyNameInput = document.getElementById('companyName');
1007
1008    // Update main color
1009    if (mainColorInput) {
1010      mainColorInput.addEventListener('input', (e) => {
1011        const color = e.target.value;
1012        
1013        // Update sign in button
1014        const signInButton = document.getElementById('loginSignInButton');
1015        if (signInButton) {
1016          signInButton.style.backgroundColor = color;
1017          // Remove old hover listeners if they exist
1018          const hoverColor = adjustBrightness(color, -20);
1019          signInButton.onmouseenter = () => {
1020            signInButton.style.backgroundColor = hoverColor;
1021          };
1022          signInButton.onmouseleave = () => {
1023            signInButton.style.backgroundColor = color;
1024          };
1025        }
1026        
1027        // Update sign up link
1028        const signUpLink = document.getElementById('loginSignUpLink');
1029        if (signUpLink) {
1030          signUpLink.style.color = color;
1031          // Remove old hover listeners if they exist
1032          const hoverLinkColor = adjustBrightness(color, 20);
1033          signUpLink.onmouseenter = () => {
1034            signUpLink.style.color = hoverLinkColor;
1035          };
1036          signUpLink.onmouseleave = () => {
1037            signUpLink.style.color = color;
1038          };
1039        }
1040        
1041        // Update forgot password link
1042        const forgotPasswordLink = document.getElementById('loginForgotPasswordLink');
1043        if (forgotPasswordLink) {
1044          forgotPasswordLink.style.color = color;
1045          const hoverLinkColor = adjustBrightness(color, 20);
1046          forgotPasswordLink.onmouseenter = () => {
1047            forgotPasswordLink.style.color = hoverLinkColor;
1048          };
1049          forgotPasswordLink.onmouseleave = () => {
1050            forgotPasswordLink.style.color = color;
1051          };
1052        }
1053      });
1054    }
1055
1056    // Update domain
1057    if (domainInput) {
1058      domainInput.addEventListener('input', (e) => {
1059        const domain = e.target.value || 'cloud.taubyte.com';
1060        
1061        // Update address bar
1062        const loginUrl = document.getElementById('loginAddressUrl');
1063        if (loginUrl) {
1064          loginUrl.textContent = `https://${domain}/login`;
1065        }
1066      });
1067    }
1068
1069    // Update company name in title
1070    if (companyNameInput) {
1071      // Set initial title on load
1072      const initialCompanyName = companyNameInput.value.trim();
1073      const loginTitle = document.getElementById('loginWindowTitle');
1074      if (loginTitle && initialCompanyName) {
1075        loginTitle.textContent = `${initialCompanyName} Cloud Login`;
1076      }
1077      
1078      companyNameInput.addEventListener('input', (e) => {
1079        const companyName = e.target.value.trim();
1080        if (loginTitle) {
1081          if (companyName) {
1082            loginTitle.textContent = `${companyName} Cloud Login`;
1083          } else {
1084            loginTitle.textContent = 'Taubyte Cloud Login';
1085          }
1086        }
1087      });
1088    }
1089
1090    // Helper function to adjust color brightness
1091    function adjustBrightness(hex, percent) {
1092      const num = parseInt(hex.replace('#', ''), 16);
1093      const amt = Math.round(2.55 * percent);
1094      const R = Math.min(255, Math.max(0, (num >> 16) + amt));
1095      const G = Math.min(255, Math.max(0, ((num >> 8) & 0x00FF) + amt));
1096      const B = Math.min(255, Math.max(0, (num & 0x0000FF) + amt));
1097      return '#' + (0x1000000 + R * 0x10000 + G * 0x100 + B).toString(16).slice(1);
1098    }
1099  }
1100
1101  // Initialize on DOM ready
1102  if (document.readyState === 'loading') {
1103    document.addEventListener('DOMContentLoaded', initSettingsWindow);
1104  } else {
1105    initSettingsWindow();
1106  }
1107
1108  // Also initialize after view transitions
1109  document.addEventListener('astro:page-load', initSettingsWindow);
1110  document.addEventListener('astro:after-swap', initSettingsWindow);
1111
1112  document.addEventListener('astro:before-swap', () => {
1113    if (_docDrag) {
1114      document.removeEventListener('mousemove', _docDrag);
1115      document.removeEventListener('mouseup', _docDragEnd);
1116      document.removeEventListener('mouseleave', _docDragEnd);
1117      _docDrag = null;
1118      _docDragEnd = null;
1119    }
1120  });
1121})();</script>
1121 </div> </div> </div> </div> </div> </div> </div> </div> <div id="feature-autonomous" class="rounded-2xl bg-black/10 dark:bg-[#111] p-6 md:p-8 mb-8"> <div class="flex flex-col lg:flex-row gap-8 items-center"> <div class="order-1 lg:order-2 shrink-0 w-full lg:w-1/3"> <div> <div> <a href="/features#autonomous" class="inline-flex items-center gap-2 text-xl md:text-2xl font-semibold leading-tight text-black dark:text-white hover:opacity-80"> Low-Ops Runtime <i class="ri-arrow-right-line mt-1" aria-hidden="true"></i> </a> <p class="mt-4 text-base md:text-lg text-black/70 dark:text-white/70 max-w-2xl">Taubyte handles routing, scaling, deployment, and recovery loops so platform teams do less glue work as software volume grows.</p> <div class="mt-4 flex flex-wrap gap-2"> <span class="inline-flex items-center rounded-full border border-black/20 dark:border-white/20 bg-black/5 dark:bg-white/5 px-3 py-1 text-xs font-medium text-black/70 dark:text-white/70"> Route </span><span class="inline-flex items-center rounded-full border border-black/20 dark:border-white/20 bg-black/5 dark:bg-white/5 px-3 py-1 text-xs font-medium text-black/70 dark:text-white/70"> Scale </span><span class="inline-flex items-center rounded-full border border-black/20 dark:border-white/20 bg-black/5 dark:bg-white/5 px-3 py-1 text-xs font-medium text-black/70 dark:text-white/70"> Recover </span> </div> </div>  </div> </div> <div class="order-2 lg:order-1 grow w-full lg:w-2/3"> <div> <!-- Mobile: Static screenshot --> <div class="lg:hidden relative rounded-xl overflow-hidden bg-[#0b0b0b] aspect-16/10 w-full"> <img src="/screenshots/autonomous-feature-desktop.png" alt="Low-Ops Runtime feature interface" class="w-full h-full object-cover" loading="lazy"> </div> <!-- Desktop: Interactive component --> <div class="hidden lg:block relative rounded-xl overflow-hidden bg-[#0b0b0b] aspect-16/10 w-full"> <img src="/soc-background.png" alt="" class="absolute inset-0 h-full w-full object-cover pointer-events-none" loading="lazy"> <!-- Dream desktop window centered inside container --> <div class="absolute inset-0"> <div class="relative w-full h-full"> <div class="absolute inset-0"> <!-- Browser Window with Nodes Map (Floating) --><div class="absolute bottom-8 left-8 w-full max-w-lg shadow-[0_35px_60px_-12px_rgba(0,0,0,0.5)] rounded-lg z-10" id="draggable-window-nodes-map" data-platform="nodes-map"> <div class="bg-[#1a1a1a] rounded-lg overflow-hidden border border-white/10 flex flex-col" style="height: 320px;"> <!-- Browser Window Controls --> <div class="bg-[#222] border-b border-white/10 px-4 py-1 flex items-center gap-1 cursor-move drag-handle" data-platform="nodes-map"> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span id="nodesMapWindowTitle" class="ml-4 text-white/60 text-xs">Console</span> </div> <!-- Map Container --> <div id="nodes-map-nodes-map" class="flex-1 w-full bg-[#1a1a1a] min-h-0"></div> <!-- Nodes List --> <div class="bg-[#1a1a1a] border-t border-white/10 px-4 py-2 relative"> <div class="flex gap-4 items-start"> <!-- Online Section --> <div class="flex-1" style="flex-grow: 2;"> <div class="text-[10px] text-white/60 mb-1.5 font-medium">Online</div> <div class="flex flex-wrap items-start gap-2 node-section" data-section="online"> <div class="flex items-center gap-2 px-3 py-1.5 rounded-md bg-[#222]/50 border border-green-500/30 hover:bg-[#222] hover:border-green-500/50 transition-colors cursor-grab shrink-0 node-item draggable-node" draggable="true" data-node-name="Dallas" data-node-lat="32.7767" data-node-lng="-96.797" data-online="true"> <div class="w-2 h-2 rounded-full bg-green-500 shrink-0"></div> <span class="text-white/80 text-[10px] font-medium whitespace-nowrap">Dallas</span> </div><div class="flex items-center gap-2 px-3 py-1.5 rounded-md bg-[#222]/50 border border-green-500/30 hover:bg-[#222] hover:border-green-500/50 transition-colors cursor-grab shrink-0 node-item draggable-node" draggable="true" data-node-name="Paris" data-node-lat="48.8566" data-node-lng="2.3522" data-online="true"> <div class="w-2 h-2 rounded-full bg-green-500 shrink-0"></div> <span class="text-white/80 text-[10px] font-medium whitespace-nowrap">Paris</span> </div><div class="flex items-center gap-2 px-3 py-1.5 rounded-md bg-[#222]/50 border border-green-500/30 hover:bg-[#222] hover:border-green-500/50 transition-colors cursor-grab shrink-0 node-item draggable-node" draggable="true" data-node-name="Moscow" data-node-lat="55.7558" data-node-lng="37.6173" data-online="true"> <div class="w-2 h-2 rounded-full bg-green-500 shrink-0"></div> <span class="text-white/80 text-[10px] font-medium whitespace-nowrap">Moscow</span> </div> </div> </div> <!-- Vertical Divider --> <div class="absolute left-[66.666%] top-0 bottom-0 w-px bg-white/10 -translate-x-1/2"></div> <!-- Offline Section --> <div class="flex-1 pl-4"> <div class="text-[10px] text-white/60 mb-1.5 font-medium">Offline</div> <div class="relative flex flex-wrap items-start gap-2 node-section" data-section="offline">  <div class="w-full flex items-center justify-center text-white/40 text-xs italic py-1 offline-placeholder">
1122Move one of the nodes here
1123</div> </div> </div> </div> </div> </div> </div>  
1123<script type="module" src="/_astro/NodesMapWindow.astro_astro_type_script_index_0_lang.ByY7CPJp.js"></script>
1123 
1123<script>(function(){const id = "draggable-window-nodes-map";
1124const platform = "nodes-map";
1125const mapId = "nodes-map-nodes-map";
1126const nodes = [{"name":"Dallas","lat":32.7767,"lng":-96.797,"online":true},{"name":"Paris","lat":48.8566,"lng":2.3522,"online":true},{"name":"Moscow","lat":55.7558,"lng":37.6173,"online":true}];
1127
1128  let _docDrag = null;
1129  let _docDragEnd = null;
1130
1131  function initNodesMapWindow() {
1132    const windowEl = document.getElementById(id);
1133    const mapContainer = document.getElementById(mapId);
1134    
1135    if (!windowEl || !mapContainer) {
1136      // Retry after a short delay if element isn't ready (for view transitions)
1137      setTimeout(initNodesMapWindow, 50);
1138      return;
1139    }
1140    
1141    // Check if map actually exists (for view transitions)
1142    const mapExists = mapContainer._leafletMap && typeof mapContainer._leafletMap.remove === 'function';
1143    
1144    // Initialize Leaflet map if it doesn't exist
1145    if (!mapExists) {
1146      // Wait for Leaflet to be available
1147      if (window.Leaflet) {
1148        // Clean up any existing map instance if it exists
1149        if (mapContainer._leafletMap) {
1150          mapContainer._leafletMap.remove();
1151          mapContainer._leafletMap = null;
1152          mapContainer._leafletMarkers = null;
1153          mapContainer._leafletMarkerMap = null;
1154        }
1155        
1156        const L = window.Leaflet;
1157        
1158        // Create map centered on world view
1159        const map = L.map(mapId, {
1160          center: [20, 0],
1161          zoom: 2,
1162          zoomControl: true,
1163          attributionControl: false
1164        });
1165
1166        // Add dark mode tile layer (CartoDB Dark Matter)
1167        L.tileLayer('https://{s}.basemaps.cartocdn.com/dark_all/{z}/{x}/{y}{r}.png', {
1168          maxZoom: 19,
1169          attribution: '© OpenStreetMap contributors, © CARTO',
1170          subdomains: 'abcd'
1171        }).addTo(map);
1172
1173        // Create custom icons for nodes
1174        const createNodeIcon = (isOnline) => {
1175          const color = isOnline ? '#22c55e' : '#6b7280';
1176          const shadowColor = isOnline ? 'rgba(34, 197, 94, 0.3)' : 'rgba(107, 114, 128, 0.2)';
1177          return L.divIcon({
1178            className: 'custom-node-marker',
1179            html: `<div style="width: 12px; height: 12px; background-color: ${color}; border-radius: 50%; border: 2px solid #1a1a1a; box-shadow: 0 0 0 2px ${shadowColor};"></div>`,
1180            iconSize: [12, 12],
1181            iconAnchor: [6, 6]
1182          });
1183        };
1184
1185        // Add markers for each node and collect them with node data
1186        const markers = [];
1187        const markerMap = {}; // Map node names to markers
1188        nodes.forEach(node => {
1189          const icon = createNodeIcon(node.online);
1190          const marker = L.marker([node.lat, node.lng], { icon: icon })
1191            .addTo(map)
1192            .bindPopup(node.name + (node.online ? ' (Online)' : ' (Offline)'));
1193          marker._nodeData = node;
1194          markers.push(marker);
1195          markerMap[node.name] = marker;
1196        });
1197        
1198        // Store marker map for updates
1199        mapContainer._leafletMarkerMap = markerMap;
1200
1201        // Fit map to show all nodes with padding
1202        if (markers.length > 0) {
1203          const group = new L.featureGroup(markers);
1204          map.fitBounds(group.getBounds().pad(0.1), {
1205            maxZoom: 8,
1206            padding: [30, 30]
1207          });
1208        }
1209
1210        // Store map instance for use in click handlers
1211        mapContainer._leafletMap = map;
1212        mapContainer._leafletMarkers = markers;
1213        mapContainer.dataset.mapInitialized = 'true';
1214
1215        // Invalidate map size after a short delay to ensure proper rendering
1216        setTimeout(() => {
1217          map.invalidateSize();
1218          // Re-fit bounds after size is validated
1219          if (markers.length > 0) {
1220            const group = new L.featureGroup(markers);
1221            map.fitBounds(group.getBounds().pad(0.1), {
1222              maxZoom: 8,
1223              padding: [30, 30]
1224            });
1225          }
1226        }, 100);
1227      } else {
1228        // Leaflet not ready yet, retry map initialization later
1229        setTimeout(() => {
1230          if (!mapContainer._leafletMap) {
1231            initNodesMapWindow();
1232          }
1233        }, 100);
1234        // Continue to initialize dragging even if map isn't ready
1235      }
1236    }
1237    
1238    const dragHandle = document.querySelector(`.drag-handle[data-platform="${platform}"]`);
1239    const container = windowEl?.parentElement;
1240    
1241    if (!dragHandle || !container) {
1242      // Elements might not be ready yet, retry
1243      setTimeout(initNodesMapWindow, 50);
1244      return;
1245    }
1246    
1247    // Skip dragging initialization if already done (for view transitions, allow reinitialization)
1248    // Check if event listeners are already attached by checking if dragHandle has a data attribute
1249    if (windowEl.dataset.draggingInitialized === 'true' && mapExists) {
1250      return;
1251    }
1252    windowEl.dataset.draggingInitialized = 'true';
1253    
1254    let isDragging = false;
1255    let initialX = 0;
1256    let initialY = 0;
1257    
1258    function dragStart(e) {
1259      if (e.button !== 0) return;
1260      
1261      isDragging = true;
1262      
1263      const rect = windowEl.getBoundingClientRect();
1264      const containerRect = container.getBoundingClientRect();
1265      
1266      // Calculate where we clicked relative to the window
1267      initialX = e.clientX - rect.left;
1268      initialY = e.clientY - rect.top;
1269      
1270      // Remove positioning classes that might conflict
1271      windowEl.classList.remove('-translate-x-1/2', '-translate-y-1/2', 'bottom-8', 'left-8');
1272      windowEl.classList.add('translate-x-0', 'translate-y-0');
1273      
1274      // Get current position
1275      const currentLeft = rect.left - containerRect.left;
1276      const currentTop = rect.top - containerRect.top;
1277      
1278      // Set initial positions using explicit pixel values
1279      windowEl.style.left = currentLeft + 'px';
1280      windowEl.style.top = currentTop + 'px';
1281      windowEl.style.bottom = 'auto';
1282      windowEl.style.right = 'auto';
1283      
1284      windowEl.classList.add('user-select-none');
1285      document.body.style.cursor = 'grabbing';
1286    }
1287    
1288    function drag(e) {
1289      if (!isDragging) return;
1290      
1291      e.preventDefault();
1292      
1293      const containerRect = container.getBoundingClientRect();
1294      const windowRect = windowEl.getBoundingClientRect();
1295      
1296      // Calculate new position
1297      const newX = e.clientX - containerRect.left - initialX;
1298      const newY = e.clientY - containerRect.top - initialY;
1299      
1300      // Keep window within container bounds
1301      const maxX = containerRect.width - windowRect.width;
1302      const maxY = containerRect.height - windowRect.height;
1303      
1304      const boundedX = Math.max(0, Math.min(newX, maxX));
1305      const boundedY = Math.max(0, Math.min(newY, maxY));
1306      
1307      windowEl.style.left = boundedX + 'px';
1308      windowEl.style.top = boundedY + 'px';
1309    }
1310    
1311    function dragEnd() {
1312      if (!isDragging) return;
1313      
1314      isDragging = false;
1315      windowEl.classList.remove('user-select-none');
1316      document.body.style.cursor = '';
1317    }
1318    
1319    dragHandle.addEventListener('mousedown', dragStart);
1320    if (!_docDrag) {
1321      _docDrag = drag;
1322      _docDragEnd = dragEnd;
1323      document.addEventListener('mousemove', _docDrag);
1324      document.addEventListener('mouseup', _docDragEnd);
1325      document.addEventListener('mouseleave', _docDragEnd);
1326    }
1327
1328    // Drag and drop functionality for nodes
1329    let draggedElement = null;
1330    
1331    // Make nodes draggable
1332    const draggableNodes = windowEl.querySelectorAll('.draggable-node');
1333    draggableNodes.forEach(node => {
1334      node.addEventListener('dragstart', function(e) {
1335        draggedElement = this;
1336        this.style.opacity = '0.5';
1337        this.style.cursor = 'grabbing';
1338        document.body.style.cursor = 'grabbing';
1339        e.dataTransfer.effectAllowed = 'move';
1340        e.dataTransfer.setData('text/html', this.innerHTML);
1341      });
1342      
1343      node.addEventListener('dragend', function() {
1344        this.style.opacity = '1';
1345        this.style.cursor = '';
1346        document.body.style.cursor = '';
1347      });
1348      
1349      // Click to zoom to node
1350      node.addEventListener('click', function() {
1351        const lat = parseFloat(this.dataset.nodeLat);
1352        const lng = parseFloat(this.dataset.nodeLng);
1353        
1354        if (mapContainer._leafletMap && !isNaN(lat) && !isNaN(lng)) {
1355          const map = mapContainer._leafletMap;
1356          map.setView([lat, lng], 6, {
1357            animate: true,
1358            duration: 0.5
1359          });
1360          
1361          const markerMap = mapContainer._leafletMarkerMap;
1362          if (markerMap && markerMap[this.dataset.nodeName]) {
1363            markerMap[this.dataset.nodeName].openPopup();
1364          }
1365        }
1366      });
1367    });
1368    
1369    // Drop zones
1370    const dropZones = windowEl.querySelectorAll('.node-section');
1371    dropZones.forEach(zone => {
1372      zone.addEventListener('dragover', function(e) {
1373        e.preventDefault();
1374        const targetSection = this.dataset.section;
1375        const isOnline = targetSection === 'online';
1376        
1377        // Check if offline section already has a node
1378        if (!isOnline) {
1379          const existingOfflineNodes = this.querySelectorAll('.draggable-node');
1380          if (existingOfflineNodes.length > 0 && draggedElement && draggedElement.dataset.online !== 'false') {
1381            e.dataTransfer.dropEffect = 'none';
1382            this.style.backgroundColor = 'rgba(239, 68, 68, 0.1)';
1383            return;
1384          }
1385        }
1386        
1387        e.dataTransfer.dropEffect = 'move';
1388        this.style.backgroundColor = 'rgba(34, 197, 94, 0.1)';
1389      });
1390      
1391      zone.addEventListener('dragleave', function() {
1392        this.style.backgroundColor = '';
1393      });
1394      
1395      zone.addEventListener('drop', function(e) {
1396        e.preventDefault();
1397        this.style.backgroundColor = '';
1398        
1399        if (draggedElement) {
1400          const targetSection = this.dataset.section;
1401          const isOnline = targetSection === 'online';
1402          const nodeName = draggedElement.dataset.nodeName;
1403          
1404          // Prevent moving to offline if it already has a node (unless moving from offline)
1405          if (!isOnline) {
1406            const existingOfflineNodes = this.querySelectorAll('.draggable-node');
1407            if (existingOfflineNodes.length > 0 && draggedElement.dataset.online !== 'false') {
1408              draggedElement.style.opacity = '1';
1409              draggedElement = null;
1410              return;
1411            }
1412          }
1413          
1414          // Remove placeholder message if it exists
1415          const placeholder = this.querySelector('.offline-placeholder');
1416          if (placeholder) {
1417            placeholder.remove();
1418          }
1419          
1420          // Move the node element
1421          this.appendChild(draggedElement);
1422          
1423          // Update node data
1424          draggedElement.dataset.online = isOnline;
1425          
1426          // Update visual appearance
1427          const indicator = draggedElement.querySelector('div[class*="rounded-full"]');
1428          const label = draggedElement.querySelector('span');
1429          
1430          if (isOnline) {
1431            indicator.className = 'w-2 h-2 rounded-full bg-green-500 shrink-0';
1432            indicator.style.backgroundColor = '#22c55e';
1433            // Update border classes
1434            draggedElement.classList.remove('border-white/5', 'hover:border-white/10');
1435            draggedElement.classList.add('border-green-500/30', 'hover:border-green-500/50');
1436            label.className = 'text-white/80 text-[10px] font-medium whitespace-nowrap';
1437          } else {
1438            indicator.className = 'w-2 h-2 rounded-full bg-gray-500 shrink-0';
1439            indicator.style.backgroundColor = '#6b7280';
1440            // Update border classes
1441            draggedElement.classList.remove('border-green-500/30', 'hover:border-green-500/50');
1442            draggedElement.classList.add('border-white/5', 'hover:border-white/10');
1443            label.className = 'text-white/60 text-[10px] font-medium whitespace-nowrap';
1444          }
1445          
1446          // Update marker on map
1447          const markerMap = mapContainer._leafletMarkerMap;
1448          if (markerMap && markerMap[nodeName]) {
1449            const marker = markerMap[nodeName];
1450            const L = window.Leaflet;
1451            const newIcon = L.divIcon({
1452              className: 'custom-node-marker',
1453              html: `<div style="width: 12px; height: 12px; background-color: ${isOnline ? '#22c55e' : '#6b7280'}; border-radius: 50%; border: 2px solid #1a1a1a; box-shadow: 0 0 0 2px ${isOnline ? 'rgba(34, 197, 94, 0.3)' : 'rgba(107, 114, 128, 0.2)'};"></div>`,
1454              iconSize: [12, 12],
1455              iconAnchor: [6, 6]
1456            });
1457            marker.setIcon(newIcon);
1458            marker.setPopupContent(nodeName + (isOnline ? ' (Online)' : ' (Offline)'));
1459            marker._nodeData.online = isOnline;
1460          }
1461          
1462          // Add placeholder back to offline section if it becomes empty
1463          if (isOnline) {
1464            const offlineSection = windowEl.querySelector('[data-section="offline"]');
1465            const offlineNodes = offlineSection?.querySelectorAll('.draggable-node');
1466            if (offlineSection && (!offlineNodes || offlineNodes.length === 0)) {
1467              const placeholder = document.createElement('div');
1468              placeholder.className = 'w-full flex items-center justify-center text-white/40 text-xs italic py-1 offline-placeholder';
1469              placeholder.textContent = 'Move one of the nodes here';
1470              offlineSection.appendChild(placeholder);
1471            }
1472          }
1473          
1474          // Dispatch event with updated node states
1475          const allNodes = windowEl.querySelectorAll('.draggable-node');
1476          const nodeStates = Array.from(allNodes).map(node => ({
1477            name: node.dataset.nodeName,
1478            online: node.dataset.online === 'true'
1479          }));
1480          
1481          const event = new CustomEvent('nodes-state-changed', {
1482            detail: { nodes: nodeStates, platform: platform }
1483          });
1484          document.dispatchEvent(event);
1485          
1486          draggedElement = null;
1487        }
1488      });
1489    });
1490  }
1491
1492  // Initialize on DOM ready
1493  if (document.readyState === 'loading') {
1494    document.addEventListener('DOMContentLoaded', initNodesMapWindow);
1495  } else {
1496    initNodesMapWindow();
1497  }
1498
1499  // Also initialize after view transitions
1500  document.addEventListener('astro:page-load', initNodesMapWindow);
1501  document.addEventListener('astro:after-swap', initNodesMapWindow);
1502
1503  document.addEventListener('astro:before-swap', () => {
1504    if (_docDrag) {
1505      document.removeEventListener('mousemove', _docDrag);
1506      document.removeEventListener('mouseup', _docDragEnd);
1507      document.removeEventListener('mouseleave', _docDragEnd);
1508      _docDrag = null;
1509      _docDragEnd = null;
1510    }
1511  });
1512})();</script>
1512 <!-- Terminal Window (Floating) --><div class="absolute top-8 right-8 w-full max-w-sm shadow-[0_35px_60px_-12px_rgba(0,0,0,0.5)] rounded-lg z-30" id="terminal-window-autonomous-terminal" data-platform="autonomous-terminal"> <div class="bg-[#1a1a1a] rounded-lg overflow-hidden border border-white/10 flex flex-col" style> <!-- Browser Window Controls --> <div class="bg-[#222] border-b border-white/10 px-4 py-1 flex items-center gap-1 cursor-move drag-handle" data-platform="autonomous-terminal"> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="ml-4 text-white/60 text-xs">Terminal</span> </div> <!-- Terminal Content --> <div class="w-full bg-[#1a1a1a] p-4 font-mono text-xs text-white/80" style>  <div id="terminal-content-nodes-map" class="space-y-1"> <div class="text-white/80">$ nslookup your.app.domain</div> <div class="text-white/80" id="addresses-label">Addresses:</div> <div class="text-white/80 node-address" data-node="Dallas"> 45.76.142.123	dallas.your.cloud</div> <div class="text-white/80 node-address" data-node="Paris"> 185.199.108.42	paris.your.cloud</div> <div class="text-white/80 node-address" data-node="Moscow"> 178.154.213.87	moscow.your.cloud</div> <div class="text-white/80"></div> <div class="text-white/80">$</div> </div>  </div> </div> </div> 
1512<script>(function(){const id = "terminal-window-autonomous-terminal";
1513const platform = "autonomous-terminal";
1514
1515  let _docDrag = null;
1516  let _docDragEnd = null;
1517
1518  function initTerminalWindow() {
1519    const windowEl = document.getElementById(id);
1520    
1521    if (!windowEl) {
1522      // Retry after a short delay if element isn't ready (for view transitions)
1523      setTimeout(initTerminalWindow, 50);
1524      return;
1525    }
1526    
1527    // Skip if already initialized
1528    if (windowEl.dataset.terminalInitialized === 'true') {
1529      return;
1530    }
1531    windowEl.dataset.terminalInitialized = 'true';
1532    
1533    const dragHandle = document.querySelector(`.drag-handle[data-platform="${platform}"]`);
1534    const container = windowEl?.parentElement;
1535    
1536    if (!dragHandle || !container) {
1537      // Elements might not be ready yet, retry
1538      windowEl.dataset.terminalInitialized = 'false';
1539      setTimeout(initTerminalWindow, 50);
1540      return;
1541    }
1542    
1543    let isDragging = false;
1544    let initialX = 0;
1545    let initialY = 0;
1546    
1547    function dragStart(e) {
1548      if (e.button !== 0) return;
1549      
1550      isDragging = true;
1551      
1552      const rect = windowEl.getBoundingClientRect();
1553      const containerRect = container.getBoundingClientRect();
1554      
1555      // Calculate where we clicked relative to the window
1556      initialX = e.clientX - rect.left;
1557      initialY = e.clientY - rect.top;
1558      
1559      // Remove positioning classes that might conflict
1560      windowEl.classList.remove('-translate-x-1/2', '-translate-y-1/2', 'top-8', 'right-8', 'bottom-8', 'left-8');
1561      windowEl.classList.add('translate-x-0', 'translate-y-0');
1562      
1563      // Get current position
1564      const currentLeft = rect.left - containerRect.left;
1565      const currentTop = rect.top - containerRect.top;
1566      
1567      // Set initial positions using explicit pixel values
1568      windowEl.style.left = currentLeft + 'px';
1569      windowEl.style.top = currentTop + 'px';
1570      windowEl.style.bottom = 'auto';
1571      windowEl.style.right = 'auto';
1572      
1573      windowEl.classList.add('user-select-none');
1574      document.body.style.cursor = 'grabbing';
1575    }
1576    
1577    function drag(e) {
1578      if (!isDragging) return;
1579      
1580      e.preventDefault();
1581      
1582      const containerRect = container.getBoundingClientRect();
1583      const windowRect = windowEl.getBoundingClientRect();
1584      
1585      // Calculate new position
1586      const newX = e.clientX - containerRect.left - initialX;
1587      const newY = e.clientY - containerRect.top - initialY;
1588      
1589      // Keep window within container bounds
1590      const maxX = containerRect.width - windowRect.width;
1591      const maxY = containerRect.height - windowRect.height;
1592      
1593      const boundedX = Math.max(0, Math.min(newX, maxX));
1594      const boundedY = Math.max(0, Math.min(newY, maxY));
1595      
1596      windowEl.style.left = boundedX + 'px';
1597      windowEl.style.top = boundedY + 'px';
1598    }
1599    
1600    function dragEnd() {
1601      if (!isDragging) return;
1602      
1603      isDragging = false;
1604      windowEl.classList.remove('user-select-none');
1605      document.body.style.cursor = '';
1606    }
1607    
1608    dragHandle.addEventListener('mousedown', dragStart);
1609    if (!_docDrag) {
1610      _docDrag = drag;
1611      _docDragEnd = dragEnd;
1612      document.addEventListener('mousemove', _docDrag);
1613      document.addEventListener('mouseup', _docDragEnd);
1614      document.addEventListener('mouseleave', _docDragEnd);
1615    }
1616  }
1617
1618  // Initialize on DOM ready
1619  if (document.readyState === 'loading') {
1620    document.addEventListener('DOMContentLoaded', initTerminalWindow);
1621  } else {
1622    initTerminalWindow();
1623  }
1624
1625  // Also initialize after view transitions
1626  document.addEventListener('astro:page-load', initTerminalWindow);
1627  document.addEventListener('astro:after-swap', initTerminalWindow);
1628
1629  document.addEventListener('astro:before-swap', () => {
1630    if (_docDrag) {
1631      document.removeEventListener('mousemove', _docDrag);
1632      document.removeEventListener('mouseup', _docDragEnd);
1633      document.removeEventListener('mouseleave', _docDragEnd);
1634      _docDrag = null;
1635      _docDragEnd = null;
1636    }
1637  });
1638})();</script>
1638 </div> </div> </div> </div> </div> </div> </div> </div> 
1638<script type="module">const m={Dallas:"45.76.142.123",Paris:"185.199.108.42",Moscow:"178.154.213.87"};function l(o){const n=document.getElementById("terminal-content-nodes-map");if(!n)return;const t=document.getElementById("addresses-label");if(!t)return;n.querySelectorAll(".node-address").forEach(e=>e.remove());const r=o.filter(e=>e.online);if(r.forEach(e=>{const c=e.name.toLowerCase(),i=m[e.name];if(i){const d=document.createElement("div");d.className="text-white/80 node-address",d.dataset.node=e.name,d.textContent=`	  ${i}	${c}.your.cloud`,t.after(d)}}),r.length===0){const e=document.createElement("div");e.className="text-white/80 node-address italic",e.textContent="	  (no online nodes)",t.after(e)}}function a(){document.addEventListener("nodes-state-changed",n=>{const t=n;t.detail.platform==="nodes-map"&&l(t.detail.nodes)});const o=document.getElementById("draggable-window-nodes-map");if(o){const n=o.querySelectorAll(".draggable-node"),t=Array.from(n).map(s=>({name:s.dataset.nodeName||"",online:s.dataset.online==="true"}));t.length>0&&l(t)}}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",a):a();document.addEventListener("astro:page-load",a);document.addEventListener("astro:after-swap",a);</script>
1638 <div id="feature-git-native" class="rounded-2xl bg-black/10 dark:bg-[#111] p-6 md:p-8 mb-8"> <div class="flex flex-col lg:flex-row gap-8 items-center"> <div class="order-1 lg:order-1 shrink-0 w-full lg:w-1/3"> <div> <div> <a href="/features#git-native" class="inline-flex items-center gap-2 text-xl md:text-2xl font-semibold leading-tight text-black dark:text-white hover:opacity-80"> Git-Native Delivery <i class="ri-arrow-right-line mt-1" aria-hidden="true"></i> </a> <p class="mt-4 text-base md:text-lg text-black/70 dark:text-white/70 max-w-2xl">Git is the control plane. Code, config, routing, and deployment history stay tracked, traceable, and versioned.</p>  </div>  </div> </div> <div class="order-2 lg:order-2 grow w-full lg:w-2/3"> <div data-astro-cid-acpfs63d><!-- Mobile: Static screenshot --><div class="lg:hidden relative rounded-xl overflow-hidden bg-[#0b0b0b] aspect-16/10 w-full" data-astro-cid-acpfs63d><img src="/screenshots/gitnative-feature-desktop.png" alt="Git-Native Delivery feature interface" class="w-full h-full object-cover" loading="lazy" data-astro-cid-acpfs63d></div><!-- Desktop: Interactive component --><div class="hidden lg:block relative rounded-xl overflow-hidden bg-[#0b0b0b] aspect-16/10 w-full" data-astro-cid-acpfs63d><img src="/git-native-background.png" alt="" class="absolute inset-0 h-full w-full object-cover pointer-events-none" loading="lazy" data-astro-cid-acpfs63d><!-- Dream desktop window centered inside container --><div class="absolute inset-0" data-astro-cid-acpfs63d><div class="relative w-full h-full" data-astro-cid-acpfs63d><div class="absolute inset-0" data-astro-cid-acpfs63d><!-- Web Application --><!-- Generic Browser Window (Floating) --><div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-sm shadow-[0_35px_60px_-12px_rgba(0,0,0,0.5)] rounded-lg !top-[8%] !left-[8%] !translate-x-0 !translate-y-0" id="draggable-window-fullstack-chat" data-platform="fullstack-chat" data-astro-cid-o7mjncmp> <div class="bg-[#1a1a1a] rounded-lg overflow-hidden border border-white/10 flex flex-col" style="height: 378px;" data-astro-cid-o7mjncmp> <!-- Browser Window Controls --> <div class="bg-[#222] border-b border-white/10 px-4 py-1 flex items-center gap-1 cursor-move drag-handle" data-platform="fullstack-chat" data-astro-cid-o7mjncmp> <span class="w-2.5 h-2.5 rounded-full bg-white/20" data-astro-cid-o7mjncmp></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20" data-astro-cid-o7mjncmp></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20" data-astro-cid-o7mjncmp></span> <span class="ml-4 text-white/60 text-xs" data-astro-cid-o7mjncmp>Web Application</span> </div> <!-- Browser Address Bar --> <div class="bg-[#2d2d2d] px-4 py-1 border-b border-white/10" data-astro-cid-o7mjncmp> <div class="flex items-center gap-2" data-astro-cid-o7mjncmp> <!-- Navigation Buttons --> <div class="flex items-center gap-1" data-astro-cid-o7mjncmp> <button class="w-5 h-5 flex items-center justify-center text-white/40 hover:text-white/70 hover:bg-white/10 rounded" data-astro-cid-o7mjncmp> <i class="ri-arrow-left-s-line text-xs" data-astro-cid-o7mjncmp></i> </button> <button class="w-5 h-5 flex items-center justify-center text-white/40 hover:text-white/70 hover:bg-white/10 rounded" data-astro-cid-o7mjncmp> <i class="ri-arrow-right-s-line text-xs" data-astro-cid-o7mjncmp></i> </button> <button id="refresh-btn-fullstack-chat" class="w-5 h-5 flex items-center justify-center text-white/40 hover:text-white/70 hover:bg-white/10 rounded" data-astro-cid-o7mjncmp> <i class="ri-refresh-line text-xs" data-astro-cid-o7mjncmp></i> </button> </div> <!-- Address Bar --> <div class="flex-1 bg-[#1a1a1a] border border-white/10 rounded px-2 py-1 flex items-center gap-1.5" data-astro-cid-o7mjncmp> <i class="ri-lock-line text-green-500 text-[10px]" data-astro-cid-o7mjncmp></i> <span class="text-white/70 text-[10px]" data-astro-cid-o7mjncmp>https://example.com</span> </div> <!-- Browser Menu --> <div class="flex items-center gap-2" data-astro-cid-o7mjncmp> <button class="w-5 h-5 flex items-center justify-center text-white/40 hover:text-white/70 hover:bg-white/10 rounded" data-astro-cid-o7mjncmp> <i class="ri-more-2-line text-xs" data-astro-cid-o7mjncmp></i> </button> </div> </div> </div> <!-- Browser Content --> <div class="flex-1 bg-[#1a1a1a] overflow-auto" data-astro-cid-o7mjncmp> <div class="h-full flex flex-col bg-[#0b0b0b] overflow-y-auto scrollbar-sleek" data-astro-cid-acpfs63d><!-- Header --><header class="bg-[#1a1a1a] border-b border-white/10 px-4 py-3" data-astro-cid-acpfs63d><div class="flex items-center justify-between" data-astro-cid-acpfs63d><div class="flex items-center gap-3" data-astro-cid-acpfs63d><div class="w-8 h-8 bg-white/10 rounded animate-pulse" data-astro-cid-acpfs63d></div><div class="h-4 w-24 bg-white/10 rounded animate-pulse" data-astro-cid-acpfs63d></div></div><div class="flex items-center gap-2" data-astro-cid-acpfs63d><div class="w-6 h-6 bg-white/10 rounded animate-pulse" data-astro-cid-acpfs63d></div><div class="w-6 h-6 bg-white/10 rounded-full animate-pulse" data-astro-cid-acpfs63d></div></div></div></header><!-- Hero Section --><div class="bg-gradient-to-br from-blue-500 to-purple-600 px-4 py-8" data-astro-cid-acpfs63d><h1 id="hero-title-gitnative" class="text-white text-xl font-bold text-center mb-4" data-pending-title="" data-astro-cid-acpfs63d>Git Native Workflow</h1><div class="flex gap-2 justify-center" data-astro-cid-acpfs63d><div class="h-8 w-20 bg-white/20 rounded animate-pulse" data-astro-cid-acpfs63d></div><div class="h-8 w-20 bg-white/20 rounded animate-pulse" data-astro-cid-acpfs63d></div></div></div><!-- Content Section --><div class="flex-1 px-4 py-4 space-y-4" data-astro-cid-acpfs63d><!-- Skeleton Card 1 --><div class="bg-[#1a1a1a] rounded-lg border border-white/10 p-4" data-astro-cid-acpfs63d><div class="flex items-start gap-3" data-astro-cid-acpfs63d><div class="w-12 h-12 bg-white/10 rounded-lg animate-pulse shrink-0" data-astro-cid-acpfs63d></div><div class="flex-1 space-y-2" data-astro-cid-acpfs63d><div class="h-4 w-3/4 bg-white/10 rounded animate-pulse" data-astro-cid-acpfs63d></div><div class="h-3 w-full bg-white/10 rounded animate-pulse" data-astro-cid-acpfs63d></div><div class="h-3 w-5/6 bg-white/10 rounded animate-pulse" data-astro-cid-acpfs63d></div></div></div></div><!-- Skeleton Card 2 --><div class="bg-[#1a1a1a] rounded-lg border border-white/10 p-4" data-astro-cid-acpfs63d><div class="flex items-start gap-3" data-astro-cid-acpfs63d><div class="w-12 h-12 bg-white/10 rounded-lg animate-pulse shrink-0" data-astro-cid-acpfs63d></div><div class="flex-1 space-y-2" data-astro-cid-acpfs63d><div class="h-4 w-2/3 bg-white/10 rounded animate-pulse" data-astro-cid-acpfs63d></div><div class="h-3 w-full bg-white/10 rounded animate-pulse" data-astro-cid-acpfs63d></div><div class="h-3 w-4/5 bg-white/10 rounded animate-pulse" data-astro-cid-acpfs63d></div></div></div></div><!-- Skeleton Card 3 --><div class="bg-[#1a1a1a] rounded-lg border border-white/10 p-4" data-astro-cid-acpfs63d><div class="space-y-3" data-astro-cid-acpfs63d><div class="h-4 w-1/2 bg-white/10 rounded animate-pulse" data-astro-cid-acpfs63d></div><div class="grid grid-cols-3 gap-2" data-astro-cid-acpfs63d><div class="h-16 bg-white/10 rounded animate-pulse" data-astro-cid-acpfs63d></div><div class="h-16 bg-white/10 rounded animate-pulse" data-astro-cid-acpfs63d></div><div class="h-16 bg-white/10 rounded animate-pulse" data-astro-cid-acpfs63d></div></div></div></div></div></div> </div> </div> </div> 
1638<script>(function(){const id = "draggable-window-fullstack-chat";
1639const platform = "fullstack-chat";
1640
1641  // Module-scope refs so astro:before-swap can detach the document listeners
1642  // installed by initBrowserWindow without leaking on every navigation.
1643  let _docDrag = null;
1644  let _docDragEnd = null;
1645
1646  function initBrowserWindow() {
1647    const window = document.getElementById(id);
1648    if (!window) {
1649      // Retry after a short delay if element isn't ready (for view transitions)
1650      setTimeout(initBrowserWindow, 50);
1651      return;
1652    }
1653    
1654    // Skip if already initialized
1655    if (window.dataset.browserInitialized === 'true') {
1656      return;
1657    }
1658    window.dataset.browserInitialized = 'true';
1659    
1660    const dragHandle = document.querySelector(`.drag-handle[data-platform="${platform}"]`);
1661    const container = window?.parentElement;
1662    
1663    if (!dragHandle || !container) {
1664      // Elements might not be ready yet, retry
1665      window.dataset.browserInitialized = 'false';
1666      setTimeout(initBrowserWindow, 50);
1667      return;
1668    }
1669    
1670    let isDragging = false;
1671    let initialX = 0;
1672    let initialY = 0;
1673    
1674    function dragStart(e) {
1675      if (e.button !== 0) return;
1676      
1677      isDragging = true;
1678      
1679      const rect = window.getBoundingClientRect();
1680      const containerRect = container.getBoundingClientRect();
1681      
1682      // Calculate where we clicked relative to the window
1683      initialX = e.clientX - rect.left;
1684      initialY = e.clientY - rect.top;
1685      
1686      // Remove transform classes and set initial position
1687      window.classList.remove('-translate-x-1/2', '-translate-y-1/2', 'translate-x-0', 'translate-y-0');
1688      
1689      // Get current position
1690      const currentLeft = rect.left - containerRect.left;
1691      const currentTop = rect.top - containerRect.top;
1692      
1693      // Set initial positions using inline styles with !important to override !important classes
1694      window.style.setProperty('left', currentLeft + 'px', 'important');
1695      window.style.setProperty('top', currentTop + 'px', 'important');
1696      window.style.setProperty('right', 'auto', 'important');
1697      window.style.setProperty('bottom', 'auto', 'important');
1698      
1699      window.classList.add('user-select-none');
1700      document.body.style.cursor = 'grabbing';
1701    }
1702    
1703    function drag(e) {
1704      if (!isDragging) return;
1705      
1706      e.preventDefault();
1707      
1708      const containerRect = container.getBoundingClientRect();
1709      const windowRect = window.getBoundingClientRect();
1710      
1711      // Calculate new position
1712      const newX = e.clientX - containerRect.left - initialX;
1713      const newY = e.clientY - containerRect.top - initialY;
1714      
1715      // Keep window within container bounds
1716      const maxX = containerRect.width - windowRect.width;
1717      const maxY = containerRect.height - windowRect.height;
1718      
1719      const boundedX = Math.max(0, Math.min(newX, maxX));
1720      const boundedY = Math.max(0, Math.min(newY, maxY));
1721      
1722      window.style.setProperty('left', boundedX + 'px', 'important');
1723      window.style.setProperty('top', boundedY + 'px', 'important');
1724    }
1725    
1726    function dragEnd() {
1727      if (!isDragging) return;
1728      
1729      isDragging = false;
1730      window.classList.remove('user-select-none');
1731      document.body.style.cursor = '';
1732    }
1733    
1734    dragHandle.addEventListener('mousedown', dragStart);
1735    if (!_docDrag) {
1736      _docDrag = drag;
1737      _docDragEnd = dragEnd;
1738      document.addEventListener('mousemove', _docDrag);
1739      document.addEventListener('mouseup', _docDragEnd);
1740      document.addEventListener('mouseleave', _docDragEnd);
1741    }
1742  }
1743
1744  // Initialize on DOM ready
1745  if (document.readyState === 'loading') {
1746    document.addEventListener('DOMContentLoaded', initBrowserWindow);
1747  } else {
1748    initBrowserWindow();
1749  }
1750
1751  // Also initialize after view transitions
1752  document.addEventListener('astro:page-load', initBrowserWindow);
1753  document.addEventListener('astro:after-swap', initBrowserWindow);
1754
1755  // Detach document-level drag listeners before the page swaps so they don't
1756  // accumulate across navigations.
1757  document.addEventListener('astro:before-swap', () => {
1758    if (_docDrag) {
1759      document.removeEventListener('mousemove', _docDrag);
1760      document.removeEventListener('mouseup', _docDragEnd);
1761      document.removeEventListener('mouseleave', _docDragEnd);
1762      _docDrag = null;
1763      _docDragEnd = null;
1764    }
1765  });
1766})();</script>
1766 <!-- Git Interface (GitKraken/VSCode Style) --><!-- Git Interface Window (Simple, No Nav) --><div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-full max-w-sm shadow-[0_35px_60px_-12px_rgba(0,0,0,0.5)] rounded-lg top-[60%] left-[70%] -translate-x-1/2 -translate-y-1/2" id="git-window-git-native" data-platform="git-native" data-astro-cid-3a3eqpua> <div class="bg-[#1a1a1a] rounded-lg overflow-hidden border border-white/10 flex flex-col" style="height: 300px;" data-astro-cid-3a3eqpua> <!-- Title Bar --> <div class="bg-[#222] border-b border-white/10 px-4 py-1 flex items-center gap-1 cursor-move drag-handle" data-platform="git-native" data-astro-cid-3a3eqpua> <span class="w-2.5 h-2.5 rounded-full bg-white/20" data-astro-cid-3a3eqpua></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20" data-astro-cid-3a3eqpua></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20" data-astro-cid-3a3eqpua></span> <span class="ml-4 text-white/60 text-xs" data-astro-cid-3a3eqpua>Source Control</span> </div> <!-- Commit Section --> <div class="px-3 py-2 border-b border-white/10 bg-[#161616]" data-astro-cid-3a3eqpua> <div class="flex items-center gap-2" data-astro-cid-3a3eqpua> <div class="flex-1 flex items-center gap-0 bg-[#1a1a1a] border border-white/10 rounded overflow-hidden" data-astro-cid-3a3eqpua> <span class="pl-2 pr-0.5 py-1.5 text-white text-[10px] shrink-0" data-astro-cid-3a3eqpua>Changed title to</span> <input id="title-input-git-window-git-native" type="text" placeholder="put your title here" value="" class="flex-1 bg-transparent border-0 pl-0.5 pr-1 py-1.5 text-white placeholder:text-white/30 text-[10px] focus:outline-none focus:ring-0 resize-none" data-astro-cid-3a3eqpua> </div> <button class="px-2 py-1 bg-white/5 hover:bg-white/10 text-white/70 hover:text-white text-[9px] rounded shrink-0" data-astro-cid-3a3eqpua>
1767Cancel
1768</button> <button id="commit-btn-git-window-git-native" class="px-2 py-1 bg-green-600 hover:bg-green-700 text-white text-[9px] rounded flex items-center gap-1 shrink-0" data-astro-cid-3a3eqpua> <i class="ri-check-line text-xs" data-astro-cid-3a3eqpua></i>
1769Commit
1770</button> </div> </div> <!-- Main Content - Everything in one view --> <div class="flex-1 overflow-y-auto scrollbar-sleek flex flex-col" data-astro-cid-3a3eqpua> <!-- Changes Section --> <div data-astro-cid-3a3eqpua> <!-- Modified Files Section --> <div class="px-2 pt-2 pb-1" data-astro-cid-3a3eqpua> <div class="text-white/50 text-[9px] uppercase tracking-wider mb-1 px-2" data-astro-cid-3a3eqpua>Changes</div> <!-- Modified File --> <div class="flex items-center gap-2 px-2 py-1.5 hover:bg-white/5 rounded cursor-pointer group" data-astro-cid-3a3eqpua> <i class="ri-file-edit-line text-orange-400 text-xs" data-astro-cid-3a3eqpua></i> <span class="text-white text-[10px] flex-1" data-astro-cid-3a3eqpua>src/component/title.tsx</span> <span class="text-white/40 text-[9px] group-hover:text-white/60" data-astro-cid-3a3eqpua>M</span> </div> </div> </div> <!-- History Section --> <div class="border-t border-white/5 mt-2" data-astro-cid-3a3eqpua> <div class="px-3 py-2" data-astro-cid-3a3eqpua> <div id="git-tree-container-git-window-git-native" data-astro-cid-3a3eqpua> <div class="relative " style="min-height: 112px;"> <!-- SVG for lines and circles --> <svg class="absolute inset-0 w-full h-full pointer-events-none z-0" style="overflow: visible;"><line x1="11" y1="0" x2="11" y2="112" stroke="#60a5fa" stroke-width="2" /><line x1="23" y1="42" x2="23" y2="112" stroke="#a855f7" stroke-width="2" /><line x1="11" y1="42" x2="23" y2="42" stroke="#a855f7" stroke-width="2" /><circle cx="11" cy="14" r="5" fill="#60a5fa" stroke="#1a1a1a" stroke-width="2" /><circle cx="11" cy="42" r="5" fill="#60a5fa" stroke="#1a1a1a" stroke-width="2" /><circle cx="23" cy="70" r="5" fill="#a855f7" stroke="#1a1a1a" stroke-width="2" /><circle cx="23" cy="98" r="5" fill="#a855f7" stroke="#1a1a1a" stroke-width="2" /></svg> <div class="flex items-center gap-3 relative z-10" style="height: 28px; margin-top: 0;"> <div class="w-6 shrink-0 h-6 flex items-center justify-center"></div> <div class="flex-1"> <div class="text-white text-[11px] leading-snug" style> Changed the title to Git Native Workflow </div> </div> </div><div class="flex items-center gap-3 relative z-10" style="height: 28px; "> <div class="w-6 shrink-0 h-6 flex items-center justify-center"></div> <div class="flex-1"> <div class="text-white/80 text-[11px] leading-snug" style> merge: git graph component </div> </div> </div><div class="flex items-center gap-3 relative z-10" style="height: 28px; "> <div class="w-6 shrink-0 h-6 flex items-center justify-center"></div> <div class="flex-1"> <div class="text-white text-[11px] leading-snug" style="color: #ec4899;"> fix: graph_rendrer() calls </div> </div> </div><div class="flex items-center gap-3 relative z-10" style="height: 28px; "> <div class="w-6 shrink-0 h-6 flex items-center justify-center"></div> <div class="flex-1"> <div class="text-white text-[11px] leading-snug" style="color: #ec4899;"> add: git graph component </div> </div> </div> </div> </div> </div> </div> </div> </div> </div>  
1770<script>(function(){const id = "git-window-git-native";
1771const platform = "git-native";
1772
1773  let _docDrag = null;
1774  let _docDragEnd = null;
1775
1776  function initGitWindow() {
1777    const window = document.getElementById(id);
1778    if (!window) {
1779      // Retry after a short delay if element isn't ready (for view transitions)
1780      setTimeout(initGitWindow, 50);
1781      return;
1782    }
1783    
1784    // Skip if already initialized
1785    if (window.dataset.gitInitialized === 'true') {
1786      return;
1787    }
1788    window.dataset.gitInitialized = 'true';
1789    
1790    const dragHandle = document.querySelector(`.drag-handle[data-platform="${platform}"]`);
1791    const container = window?.parentElement;
1792    
1793    if (!dragHandle || !container) {
1794      // Elements might not be ready yet, retry
1795      window.dataset.gitInitialized = 'false';
1796      setTimeout(initGitWindow, 50);
1797      return;
1798    }
1799    
1800    let isDragging = false;
1801    let initialX = 0;
1802    let initialY = 0;
1803    
1804    function dragStart(e) {
1805      if (e.button !== 0) return;
1806      
1807      isDragging = true;
1808      
1809      const rect = window.getBoundingClientRect();
1810      const containerRect = container.getBoundingClientRect();
1811      
1812      // Calculate where we clicked relative to the window
1813      initialX = e.clientX - rect.left;
1814      initialY = e.clientY - rect.top;
1815      
1816      // Remove transform classes and set initial position
1817      window.classList.remove('-translate-x-1/2', '-translate-y-1/2');
1818      window.classList.add('translate-x-0', 'translate-y-0');
1819      
1820      // Get current position
1821      const currentLeft = rect.left - containerRect.left;
1822      const currentTop = rect.top - containerRect.top;
1823      
1824      // Set initial positions
1825      window.style.left = currentLeft + 'px';
1826      window.style.top = currentTop + 'px';
1827      
1828      window.classList.add('user-select-none');
1829      document.body.style.cursor = 'grabbing';
1830    }
1831    
1832    function drag(e) {
1833      if (!isDragging) return;
1834      
1835      e.preventDefault();
1836      
1837      const containerRect = container.getBoundingClientRect();
1838      const windowRect = window.getBoundingClientRect();
1839      
1840      // Calculate new position
1841      const newX = e.clientX - containerRect.left - initialX;
1842      const newY = e.clientY - containerRect.top - initialY;
1843      
1844      // Keep window within container bounds
1845      const maxX = containerRect.width - windowRect.width;
1846      const maxY = containerRect.height - windowRect.height;
1847      
1848      const boundedX = Math.max(0, Math.min(newX, maxX));
1849      const boundedY = Math.max(0, Math.min(newY, maxY));
1850      
1851      window.style.left = boundedX + 'px';
1852      window.style.top = boundedY + 'px';
1853    }
1854    
1855    function dragEnd() {
1856      if (!isDragging) return;
1857      
1858      isDragging = false;
1859      window.classList.remove('user-select-none');
1860      document.body.style.cursor = '';
1861    }
1862    
1863    dragHandle.addEventListener('mousedown', dragStart);
1864    if (!_docDrag) {
1865      _docDrag = drag;
1866      _docDragEnd = dragEnd;
1867      document.addEventListener('mousemove', _docDrag);
1868      document.addEventListener('mouseup', _docDragEnd);
1869      document.addEventListener('mouseleave', _docDragEnd);
1870    }
1871  }
1872
1873  // Initialize on DOM ready
1874  if (document.readyState === 'loading') {
1875    document.addEventListener('DOMContentLoaded', initGitWindow);
1876  } else {
1877    initGitWindow();
1878  }
1879
1880  // Also initialize after view transitions
1881  document.addEventListener('astro:page-load', initGitWindow);
1882  document.addEventListener('astro:after-swap', initGitWindow);
1883
1884  document.addEventListener('astro:before-swap', () => {
1885    if (_docDrag) {
1886      document.removeEventListener('mousemove', _docDrag);
1887      document.removeEventListener('mouseup', _docDragEnd);
1888      document.removeEventListener('mouseleave', _docDragEnd);
1889      _docDrag = null;
1890      _docDragEnd = null;
1891    }
1892  });
1893  
1894  // Commit functionality - update hero title and add to git graph
1895  function initCommitButton() {
1896    const commitBtn = document.getElementById(`commit-btn-${id}`);
1897    const titleInput = document.getElementById(`title-input-${id}`);
1898    const heroTitle = document.getElementById('hero-title-gitnative');
1899    const gitTreeContainer = document.getElementById(`git-tree-container-${id}`);
1900    
1901    if (!commitBtn || !titleInput || !heroTitle || !gitTreeContainer) {
1902      setTimeout(initCommitButton, 50);
1903      return;
1904    }
1905    
1906    commitBtn.addEventListener('click', () => {
1907      const titleValue = titleInput.value.trim();
1908      if (titleValue) {
1909        // Store pending title (don't update yet)
1910        heroTitle.setAttribute('data-pending-title', titleValue);
1911        
1912        // Add commit to git graph
1913        const commitMessage = `Changed title to ${titleValue}`;
1914        addCommitToGraph(gitTreeContainer, commitMessage, 0);
1915        
1916        // Clear the input
1917        titleInput.value = '';
1918        
1919        // Glow the refresh button as a hint
1920        const refreshBtn = document.getElementById('refresh-btn-fullstack-chat');
1921        if (refreshBtn) {
1922          refreshBtn.classList.add('refresh-glow');
1923          setTimeout(() => {
1924            refreshBtn.classList.remove('refresh-glow');
1925          }, 3000);
1926        }
1927      }
1928    });
1929    
1930    // Handle browser refresh button
1931    const refreshBtn = document.getElementById('refresh-btn-fullstack-chat');
1932    if (refreshBtn) {
1933      refreshBtn.addEventListener('click', () => {
1934        const pendingTitle = heroTitle.getAttribute('data-pending-title');
1935        if (pendingTitle) {
1936          // Update hero title on refresh
1937          heroTitle.textContent = pendingTitle;
1938          heroTitle.removeAttribute('data-pending-title');
1939          // Remove glow if still active
1940          refreshBtn.classList.remove('refresh-glow');
1941        }
1942      });
1943    }
1944  }
1945  
1946  function addCommitToGraph(container, message, column) {
1947    const rowHeight = 28;
1948    const firstColumnX = 11;
1949    const columnSpacing = 12;
1950    const mainBranchColor = '#60a5fa';
1951    
1952    // Get the SVG and commit list
1953    const svg = container.querySelector('svg');
1954    const commitList = container.querySelector('div[class*="relative"]');
1955    
1956    if (!svg || !commitList) return;
1957    
1958    // Get current commit count
1959    const existingCommits = commitList.querySelectorAll('div[class*="flex items-center gap-3"]');
1960    const newIndex = 0; // New commit goes at the top
1961    
1962    // Shift all existing circles and lines down by one row
1963    const allCircles = Array.from(svg.querySelectorAll('circle'));
1964    allCircles.forEach((circle) => {
1965      const currentY = parseFloat(circle.getAttribute('cy') || '0');
1966      const newY = currentY + rowHeight;
1967      circle.setAttribute('cy', newY.toString());
1968    });
1969    
1970    // Shift horizontal connection lines and branch start positions down
1971    const allLines = Array.from(svg.querySelectorAll('line'));
1972    allLines.forEach((line) => {
1973      const x1 = parseFloat(line.getAttribute('x1') || '0');
1974      const x2 = parseFloat(line.getAttribute('x2') || '0');
1975      const y1 = parseFloat(line.getAttribute('y1') || '0');
1976      const y2 = parseFloat(line.getAttribute('y2') || '0');
1977      
1978      // Skip main branch vertical line (it starts at y1=0 and we'll update y2 separately)
1979      if (x1 === firstColumnX && x2 === firstColumnX && y1 === 0) {
1980        // This is the main branch line - just extend it
1981        const newHeight = (existingCommits.length + 1) * rowHeight;
1982        line.setAttribute('y2', newHeight.toString());
1983      } else {
1984        // Shift all other lines (horizontal connections, branch lines)
1985        if (y1 > 0) line.setAttribute('y1', (y1 + rowHeight).toString());
1986        if (y2 > 0) line.setAttribute('y2', (y2 + rowHeight).toString());
1987      }
1988    });
1989    
1990    // Add new circle at the top (position 0)
1991    const newY = rowHeight / 2;
1992    const x = firstColumnX + (column * columnSpacing);
1993    const newCircle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
1994    newCircle.setAttribute('cx', x.toString());
1995    newCircle.setAttribute('cy', newY.toString());
1996    newCircle.setAttribute('r', '5');
1997    newCircle.setAttribute('fill', mainBranchColor);
1998    newCircle.setAttribute('stroke', '#1a1a1a');
1999    newCircle.setAttribute('stroke-width', '2');
2000    svg.insertBefore(newCircle, svg.firstChild);
2001    
2002    // Add new commit row at the top
2003    const newRow = document.createElement('div');
2004    newRow.className = 'flex items-center gap-3 relative z-10';
2005    newRow.style.height = `${rowHeight}px`;
2006    newRow.style.marginTop = '0';
2007    
2008    const spacer = document.createElement('div');
2009    spacer.className = 'w-6 shrink-0 h-6 flex items-center justify-center';
2010    
2011    const messageContainer = document.createElement('div');
2012    messageContainer.className = 'flex-1';
2013    
2014    const messageText = document.createElement('div');
2015    messageText.className = 'text-white text-[11px] leading-snug';
2016    messageText.textContent = message;
2017    
2018    messageContainer.appendChild(messageText);
2019    newRow.appendChild(spacer);
2020    newRow.appendChild(messageContainer);
2021    
2022    // Remove margin-top from first existing commit if any
2023    if (existingCommits.length > 0) {
2024      existingCommits[0].style.marginTop = '';
2025    }
2026    
2027    // Insert at the beginning
2028    commitList.insertBefore(newRow, commitList.firstChild);
2029    
2030    // Update container height
2031    const newTotalHeight = (existingCommits.length + 1) * rowHeight;
2032    commitList.style.minHeight = `${newTotalHeight}px`;
2033  }
2034  
2035  // Initialize commit button
2036  if (document.readyState === 'loading') {
2037    document.addEventListener('DOMContentLoaded', initCommitButton);
2038  } else {
2039    initCommitButton();
2040  }
2041  
2042  document.addEventListener('astro:page-load', initCommitButton);
2043  document.addEventListener('astro:after-swap', initCommitButton);
2044})();</script>
2044</div></div></div></div></div> </div> </div> </div> <div id="feature-build-local" class="rounded-2xl bg-black/10 dark:bg-[#111] p-6 md:p-8 mb-8"> <div class="flex flex-col lg:flex-row gap-8 items-center"> <div class="order-1 lg:order-2 shrink-0 w-full lg:w-1/3"> <div> <div> <a href="/features#build-local" class="inline-flex items-center gap-2 text-xl md:text-2xl font-semibold leading-tight text-black dark:text-white hover:opacity-80"> Production Parity From The Start <i class="ri-arrow-right-line mt-1" aria-hidden="true"></i> </a> <p class="mt-4 text-base md:text-lg text-black/70 dark:text-white/70 max-w-2xl">Dream gives developers and agents a local environment that behaves like production before anything ships.</p>  </div>  </div> </div> <div class="order-2 lg:order-1 grow w-full lg:w-2/3"> <div> <!-- Mobile: Static screenshot --> <div class="lg:hidden relative rounded-xl overflow-hidden bg-[#0b0b0b] aspect-16/10 w-full"> <img src="/screenshots/build-local-feature-desktop.png" alt="Production Parity From The Start feature interface" class="w-full h-full object-cover" loading="lazy"> </div> <!-- Desktop: Interactive component --> <div class="hidden lg:block relative rounded-xl overflow-hidden bg-[#0b0b0b] aspect-16/10 w-full"> <img src="/test-background.png" alt="" class="absolute inset-0 h-full w-full object-cover pointer-events-none" loading="lazy"> <!-- Dream desktop window centered inside container --> <div class="absolute inset-0"> <!-- Dream Desktop Window (Floating) --><div class="absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 w-full shadow-[0_35px_60px_-12px_rgba(0,0,0,0.5)] rounded-lg max-w-[43.2rem] max-h-xl" id="draggable-dream-window-f58l14l"> <div class="bg-[#1a1a1a] rounded-lg overflow-hidden border border-white/10 flex flex-col h-full"> <!-- Browser-style title bar - spans full width --> <div class="bg-[#222] px-4 py-1.5 flex items-center border-b border-white/10 drag-handle cursor-move"> <div class="flex items-center gap-1"> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> <span class="w-2.5 h-2.5 rounded-full bg-white/20"></span> </div> <span class="ml-4 text-white/60 text-xs">Dream Desktop</span> </div> <div class="flex flex-1 overflow-hidden"> <!-- Left persistent panel --> <div class="w-60 bg-[#252525] border-r border-white/10 flex flex-col"> <!-- Stats --> <div class="grid grid-cols-3 gap-1 p-3 text-center border-b border-white/10"> <div class="bg-[#2a2a2a] rounded px-2 py-1"> <div class="text-[10px] text-white/50 uppercase">Memory</div> <div class="text-xs text-white font-medium">0%</div> <div class="text-[9px] text-white/40">77MB</div> </div> <div class="bg-[#2a2a2a] rounded px-2 py-1"> <div class="text-[10px] text-white/50 uppercase">CPU</div> <div class="text-xs text-white font-medium">7%</div> </div> <div class="bg-[#2a2a2a] rounded px-2 py-1"> <div class="text-[10px] text-white/50 uppercase">Universes</div> <div class="text-xs text-white font-medium">1</div> </div> </div> <!-- Sidebar list --> <div class="px-3 py-3 flex-1"> <div class="flex items-center justify-between mb-2"> <div class="text-[10px] text-white/50 uppercase tracking-wide">Persistent</div> <div class="flex items-center gap-1"> <button class="text-white/40 hover:text-white"><i class="ri-refresh-line text-xs"></i></button> <button class="text-white/40 hover:text-white"><i class="ri-more-2-fill text-xs"></i></button> </div> </div> <button class="w-full flex items-center justify-between bg-[#2a2a2a] hover:bg-[#2d2d2d] text-white text-sm px-2 py-2 rounded mb-1"> <span class="flex items-center gap-2"> <span class="w-2 h-2 rounded-full bg-green-500"></span>
2045blackhole
2046</span> <i class="ri-arrow-right-s-line text-white/60"></i> </button> </div> <div class="mt-auto p-3 space-y-2 border-t border-white/10"> <button class="w-full bg-linear-to-r from-green-600 to-green-700 hover:from-green-700 hover:to-green-800 text-white py-2 rounded text-sm font-medium flex items-center justify-center gap-2"> <i class="ri-add-line"></i>
2047Create New
2048</button> <div class="text-[10px] text-white/40 uppercase tracking-wide mb-1 mt-3">Services</div> <div class="space-y-1"> <div class="flex items-center justify-between text-[11px] text-white/80 py-1"> <span class="flex items-center gap-2"> <span class="w-2 h-2 rounded-full bg-green-500"></span>
2049API Service
2050</span> <button class="text-white/30 hover:text-white"><i class="ri-more-2-fill"></i></button> </div> <div class="flex items-center justify-between text-[11px] text-white/80 py-1"> <span class="flex items-center gap-2"> <span class="w-2 h-2 rounded-full bg-green-500"></span>
2051MCP Server
2052</span> <button class="text-white/30 hover:text-white"><i class="ri-more-2-fill"></i></button> </div> <div class="flex items-center justify-between text-[11px] text-white/80 py-1"> <span class="flex items-center gap-2"> <span class="w-2 h-2 rounded-full bg-green-500"></span>
2053Name Server (DNS)
2054</span> <button class="text-white/30 hover:text-white"><i class="ri-more-2-fill"></i></button> </div> </div> </div> </div> <!-- Main content area --> <div class="flex-1 flex flex-col"> <!-- Top Header Bar with blackhole --> <div class="bg-[#2d2d2d] h-10 px-4 flex items-center justify-between border-b border-white/10"> <div class="flex items-center gap-3"> <i class="ri-cloud-line text-white"></i> <span class="text-white font-medium text-sm">blackhole</span> <span class="text-[10px] bg-green-900/40 text-green-400 px-2 py-0.5 rounded">RUNNING</span> </div> <div class="flex items-center gap-2"> <button class="px-3 py-1 text-xs bg-red-600/80 hover:bg-red-600 text-white rounded flex items-center gap-1"> <i class="ri-stop-fill"></i>
2055Stop
2056</button> <button class="px-3 py-1 text-xs bg-white/5 hover:bg-white/10 text-white/60 rounded flex items-center gap-1"> <i class="ri-delete-bin-line"></i>
2057Delete
2058</button> <button class="text-white/60 hover:text-white"><i class="ri-refresh-line"></i></button> <button class="text-white/60 hover:text-white"><i class="ri-close-line"></i></button> </div> </div> <!-- Navigation tabs --> <div class="px-4 flex items-center gap-6 border-b border-white/10 bg-[#252525] text-[13px]"> <button class="flex items-center gap-2 text-white/60 hover:text-white border-b-2 border-transparent hover:border-white/30 transition-colors py-2"> <i class="ri-home-line text-sm"></i>Overview
2059</button> <button class="flex items-center gap-2 text-blue-400 border-b-2 border-blue-400 -mb-[2px] py-2"> <i class="ri-radar-line text-sm"></i>Network
2060</button> <button class="flex items-center gap-2 text-white/60 hover:text-white border-b-2 border-transparent hover:border-white/30 transition-colors py-2"> <i class="ri-folder-3-line text-sm"></i>Projects
2061</button> <button class="flex items-center gap-2 text-white/60 hover:text-white border-b-2 border-transparent hover:border-white/30 transition-colors py-2"> <i class="ri-file-list-3-line text-sm"></i>Logs
2062</button> </div> <!-- Content area --> <div class="flex-1 overflow-hidden bg-[#1a1a1a]"> <div id="draggable-dream-window-f58l14l-network" class="w-full h-full"></div> </div> </div> </div> </div> </div>  
2062<script>(function(){const id = "draggable-dream-window-f58l14l";
2063const activeTab = "network";
2064
2065  let _docDrag = null;
2066  let _docDragEnd = null;
2067
2068  function initDreamDesktopDrag() {
2069    const windowEl = document.getElementById(id);
2070    const dragHandle = windowEl?.querySelector('.drag-handle');
2071    const container = windowEl?.parentElement;
2072    if (!windowEl || !dragHandle || !container) return;
2073
2074    // Check if already bound to prevent duplicates
2075    if (dragHandle._dragBound === true) return;
2076    dragHandle._dragBound = true;
2077
2078    let isDragging = false;
2079    let initialX = 0;
2080    let initialY = 0;
2081
2082    function dragStart(e) {
2083      if (e.button !== 0) return;
2084      isDragging = true;
2085      const rect = windowEl.getBoundingClientRect();
2086      const containerRect = container.getBoundingClientRect();
2087      initialX = e.clientX - rect.left;
2088      initialY = e.clientY - rect.top;
2089      windowEl.classList.remove('-translate-x-1/2', '-translate-y-1/2');
2090      windowEl.classList.add('translate-x-0', 'translate-y-0');
2091      const currentLeft = rect.left - containerRect.left;
2092      const currentTop = rect.top - containerRect.top;
2093      windowEl.style.left = currentLeft + 'px';
2094      windowEl.style.top = currentTop + 'px';
2095      document.body.style.cursor = 'grabbing';
2096    }
2097
2098    function drag(e) {
2099      if (!isDragging) return;
2100      e.preventDefault();
2101      const containerRect = container.getBoundingClientRect();
2102      const windowRect = windowEl.getBoundingClientRect();
2103      const newX = e.clientX - containerRect.left - initialX;
2104      const newY = e.clientY - containerRect.top - initialY;
2105      const maxX = containerRect.width - windowRect.width;
2106      const maxY = containerRect.height - windowRect.height;
2107      const boundedX = Math.max(0, Math.min(newX, maxX));
2108      const boundedY = Math.max(0, Math.min(newY, maxY));
2109      windowEl.style.left = boundedX + 'px';
2110      windowEl.style.top = boundedY + 'px';
2111    }
2112
2113    function dragEnd() {
2114      if (!isDragging) return;
2115      isDragging = false;
2116      document.body.style.cursor = '';
2117    }
2118
2119    dragHandle.addEventListener('mousedown', dragStart);
2120    if (!_docDrag) {
2121      _docDrag = drag;
2122      _docDragEnd = dragEnd;
2123      document.addEventListener('mousemove', _docDrag);
2124      document.addEventListener('mouseup', _docDragEnd);
2125      document.addEventListener('mouseleave', _docDragEnd);
2126    }
2127  }
2128
2129  // Initialize drag on page load
2130  if (typeof window !== 'undefined') {
2131    if (document.readyState === 'loading') {
2132      document.addEventListener('DOMContentLoaded', initDreamDesktopDrag);
2133    } else {
2134      initDreamDesktopDrag();
2135    }
2136  }
2137
2138  // Re-initialize after view transitions
2139  document.addEventListener('astro:page-load', () => {
2140    requestAnimationFrame(initDreamDesktopDrag);
2141  });
2142
2143  document.addEventListener('astro:before-swap', () => {
2144    if (_docDrag) {
2145      document.removeEventListener('mousemove', _docDrag);
2146      document.removeEventListener('mouseup', _docDragEnd);
2147      document.removeEventListener('mouseleave', _docDragEnd);
2148      _docDrag = null;
2149      _docDragEnd = null;
2150    }
2151  });
2152
2153  // Initialize vis-network in Network tab
2154  function initNetworkIfNeeded(retries = 8) {
2155    if (activeTab !== 'network') return;
2156    const containerEl = document.getElementById(`${id}-network`);
2157    if (!containerEl) {
2158      if (retries > 0) setTimeout(() => initNetworkIfNeeded(retries - 1), 120);
2159      return;
2160    }
2161    if ((containerEl)._visInit) return;
2162    try {
2163      function withVis(callback) {
2164        const g = window;
2165        if (g.vis && g.vis.Network && g.vis.DataSet) {
2166          callback(g.vis);
2167          return;
2168        }
2169        // Wait for npm import to load
2170        setTimeout(() => {
2171          if (g.vis && g.vis.Network && g.vis.DataSet) {
2172            callback(g.vis);
2173          } else {
2174            console.error('vis-network failed to load');
2175          }
2176        }, 100);
2177      }
2178
2179      withVis((vis) => {
2180
2181        const data = {
2182          nodes: [
2183            { id: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc', name: 'elder@blackhole', category: 0, value: { p2p: 13151 } },
2184            { id: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs', name: 'monkey@blackhole', category: 1, value: { copies: 1, dns: 13404, http: 13100, p2p: 13263 } },
2185            { id: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', name: 'hoarder@blackhole', category: 2, value: { copies: 1, dns: 13404, http: 13100, p2p: 13242 } },
2186            { id: '12D3KooWAn9uLqFu3xiJywFpyppDxumfM4bztmReoBrKt68L5Dak', name: 'tns@blackhole', category: 3, value: { copies: 1, dns: 13404, http: 13566, p2p: 13326 } },
2187            { id: '12D3KooWDShcNAro86QDo5HiWTbXnoG66YWK66PH3B2uA6Wz1x85', name: 'patrick@blackhole', category: 4, value: { copies: 1, dns: 13404, http: 13524, p2p: 13284 } },
2188            { id: '12D3KooWKAqfJ8S7LzJMUsSB7MkefgDqHnucx6u2EsGDzGSeBxnJ', name: 'auth@blackhole', category: 5, value: { copies: 1, dns: 13404, http: 13545, p2p: 13221 } },
2189            { id: '12D3KooWDoxzWtQTmRBycxpAqQ3UXCiCx6Qt8KYF6KcfWDN7Pj8P', name: 'seer@blackhole', category: 6, value: { copies: 1, dns: 13404, http: 13503, p2p: 13305 } },
2190            { id: '12D3KooWLE7HGRCJoq7Nfzp55YV9AdLoBpdmJat9qDjmXsmWcbbd', name: 'gateway@blackhole', category: 7, value: { p2p: 13152 } },
2191            { id: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K', name: 'substrate@blackhole', category: 8, value: { copies: 1, dns: 13404, http: 13629, p2p: 13382 } },
2192          ],
2193          links: [
2194            { source: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc', target: '12D3KooWDShcNAro86QDo5HiWTbXnoG66YWK66PH3B2uA6Wz1x85' },
2195            { source: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc', target: '12D3KooWDoxzWtQTmRBycxpAqQ3UXCiCx6Qt8KYF6KcfWDN7Pj8P' },
2196            { source: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc', target: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K' },
2197            { source: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc', target: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs' },
2198            { source: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc', target: '12D3KooWAn9uLqFu3xiJywFpyppDxumfM4bztmReoBrKt68L5Dak' },
2199            { source: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc', target: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP' },
2200            { source: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc', target: '12D3KooWKAqfJ8S7LzJMUsSB7MkefgDqHnucx6u2EsGDzGSeBxnJ' },
2201            { source: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc', target: '12D3KooWLE7HGRCJoq7Nfzp55YV9AdLoBpdmJat9qDjmXsmWcbbd' },
2202            { source: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs', target: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc' },
2203            { source: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs', target: '12D3KooWAn9uLqFu3xiJywFpyppDxumfM4bztmReoBrKt68L5Dak' },
2204            { source: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs', target: '12D3KooWDShcNAro86QDo5HiWTbXnoG66YWK66PH3B2uA6Wz1x85' },
2205            { source: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs', target: '12D3KooWKAqfJ8S7LzJMUsSB7MkefgDqHnucx6u2EsGDzGSeBxnJ' },
2206            { source: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs', target: '12D3KooWDoxzWtQTmRBycxpAqQ3UXCiCx6Qt8KYF6KcfWDN7Pj8P' },
2207            { source: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs', target: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP' },
2208            { source: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs', target: '12D3KooWLE7HGRCJoq7Nfzp55YV9AdLoBpdmJat9qDjmXsmWcbbd' },
2209            { source: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs', target: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K' },
2210            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWLE7HGRCJoq7Nfzp55YV9AdLoBpdmJat9qDjmXsmWcbbd' },
2211            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K' },
2212            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWKAqfJ8S7LzJMUsSB7MkefgDqHnucx6u2EsGDzGSeBxnJ' },
2213            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWDoxzWtQTmRBycxpAqQ3UXCiCx6Qt8KYF6KcfWDN7Pj8P' },
2214            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc' },
2215            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWAn9uLqFu3xiJywFpypp
2215DxumfM4bztmReoBrKt68L5Dak' },
2216            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs' },
2217            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWDShcNAro86QDo5HiWTbXnoG66YWK66PH3B2uA6Wz1x85' },
2218            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWLE7HGRCJoq7Nfzp55YV9AdLoBpdmJat9qDjmXsmWcbbd' },
2219            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K' },
2220            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs' },
2221            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWAn9uLqFu3xiJywFpyppDxumfM4bztmReoBrKt68L5Dak' },
2222            { source: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP', target: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc' },
2223            { source: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K', target: '12D3KooWLE7HGRCJoq7Nfzp55YV9AdLoBpdmJat9qDjmXsmWcbbd' },
2224            { source: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K', target: '12D3KooWDoxzWtQTmRBycxpAqQ3UXCiCx6Qt8KYF6KcfWDN7Pj8P' },
2225            { source: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K', target: '12D3KooWAn9uLqFu3xiJywFpyppDxumfM4bztmReoBrKt68L5Dak' },
2226            { source: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K', target: '12D3KooWJ75qxH6HpBHQZNqJjHyns7R2nQBCdgAdwbwPZdrBH9Dc' },
2227            { source: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K', target: '12D3KooWDShcNAro86QDo5HiWTbXnoG66YWK66PH3B2uA6Wz1x85' },
2228            { source: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K', target: '12D3KooWCKkKpKxj4GfgnVnYG8NrcTQsJdWWWTENkDCgP2cynyxP' },
2229            { source: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K', target: '12D3KooWKAqfJ8S7LzJMUsSB7MkefgDqHnucx6u2EsGDzGSeBxnJ' },
2230            { source: '12D3KooWLBzChxCSmcW98w2FWbRYAjFcQH6Ahi8duHJPQF4pY46K', target: '12D3KooWFvAAt8dRbE6CQdU8mFHBxmz8uLhMgta6EgkAmqGMMmjs' },
2231          ],
2232        };
2233
2234        const isDark = (localStorage.theme === 'dark' || (!('theme' in localStorage) && window.matchMedia('(prefers-color-scheme: dark)').matches));
2235        const accentColor = '#099a40';
2236        const linkColor = '#777777';
2237
2238        const nodes = new vis.DataSet(
2239          data.nodes.map((n) => ({
2240            id: n.id,
2241            label: n.name.split('@')[0],
2242            shape: 'image',
2243            image: '/taubyte-node.svg',
2244            size: 25
2245          }))
2246        );
2247
2248        const dedupedEdges = [];
2249        const seenPairs = new Set();
2250        data.links.forEach((l) => {
2251          const key = [l.source, l.target].sort().join('|');
2252          if (!seenPairs.has(key)) {
2253            seenPairs.add(key);
2254            dedupedEdges.push({ from: l.source, to: l.target });
2255          }
2256        });
2257        const edges = new vis.DataSet(dedupedEdges);
2258
2259        const options = {
2260          autoResize: true,
2261          height: '100%',
2262          width: '100%',
2263          interaction: { hover: true, tooltipDelay: 50, zoomView: false, dragView: false },
2264          nodes: {
2265            shape: 'image',
2266            shadow: { enabled: true, color: 'rgba(9,154,64,0.35)', size: 10, x: 0, y: 0 },
2267            borderWidth: 0,
2268            size: 25,
2269            font: { size: 14, color: accentColor, vadjust: 2 },
2270          },
2271          edges: { width: 1, shadow: false, color: linkColor },
2272          physics: {
2273            solver: 'repulsion',
2274            repulsion: {
2275              nodeDistance: 100,
2276              centralGravity: 0.15,
2277              springLength: 220,
2278              springConstant: 0.02,
2279              damping: 0.09
2280            }
2281          },
2282        };
2283
2284        const network = new vis.Network(containerEl, { nodes, edges }, options);
2285        network.once('afterDrawing', () => network.fit({ maxZoomLevel: 0.8 }));
2286        (containerEl)._visInit = true;
2287        (containerEl)._visNetwork = network;
2288      });
2289    } catch (e) {
2290      console.error('vis init error', e);
2291    }
2292  }
2293
2294  // Tear down the existing vis-network instance before a re-init so WebGL/canvas
2295  // resources don't accumulate across view transitions.
2296  function resetNetwork() {
2297    const containerEl = document.getElementById(`${id}-network`);
2298    if (!containerEl) return;
2299    try { (containerEl)._visNetwork?.destroy?.(); } catch (_) {}
2300    (containerEl)._visNetwork = null;
2301    (containerEl)._visInit = false;
2302  }
2303
2304  // Initialize on page load
2305  if (typeof window !== 'undefined') {
2306    if (document.readyState === 'loading') {
2307      document.addEventListener('DOMContentLoaded', () => {
2308        initNetworkIfNeeded();
2309      });
2310    } else {
2311      initNetworkIfNeeded();
2312    }
2313  }
2314
2315  // Re-initialize network after view transitions
2316  document.addEventListener('astro:page-load', () => {
2317    requestAnimationFrame(() => {
2318      resetNetwork();
2319      initNetworkIfNeeded();
2320    });
2321  });
2322  document.addEventListener('astro:after-swap', () => {
2323    requestAnimationFrame(() => {
2324      resetNetwork();
2325      initNetworkIfNeeded();
2326    });
2327  });
2328})();</script>
2328 </div> </div> </div> </div> </div> </div> </div> </section> <!-- Chat Section --><section id="taure-section" class="mt-12 px-6 pt-12 pb-6 bg-gray-50 dark:bg-[#1a1a1a] transition-colors" data-astro-cid-tkm6qkaw> <div class="container mx-auto max-w-4xl" data-astro-cid-tkm6qkaw> <!-- Chat Messages Container --> <div id="chat-messages" class="space-y-4 mb-6" data-astro-cid-tkm6qkaw> <!-- Messages will be added here dynamically --> </div> <!-- Dynamic Prompt Area --> <div id="prompt-area" class="scroll-mt-4 mb-8 mt-12" data-astro-cid-tkm6qkaw> <!-- Newsletter Form (Initial State) --> <form id="newsletter-form" data-astro-cid-tkm6qkaw> <div class="flex gap-2 flex-col sm:flex-row" data-astro-cid-tkm6qkaw> <input type="text" name="name" id="newsletter-name" placeholder="Your name" required class="flex-1 px-4 py-3 rounded-full border border-black/10 dark:border-white/10 bg-white dark:bg-[#151515] text-black dark:text-white placeholder-black/40 dark:placeholder-white/40 focus:outline-none focus:ring-2 focus:ring-black dark:focus:ring-white transition-all text-sm" data-astro-cid-tkm6qkaw> <input type="email" name="email" id="newsletter-email" placeholder="Your email" required class="flex-1 px-4 py-3 rounded-full border border-black/10 dark:border-white/10 bg-white dark:bg-[#151515] text-black dark:text-white placeholder-black/40 dark:placeholder-white/40 focus:outline-none focus:ring-2 focus:ring-black dark:focus:ring-white transition-all text-sm" data-astro-cid-tkm6qkaw> <button type="submit" id="newsletter-submit" name="action" value="subscribe" class="px-6 py-3 bg-black dark:bg-white text-white dark:text-black text-sm font-medium rounded-full hover:bg-black/90 dark:hover:bg-white/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap" data-astro-cid-tkm6qkaw>
2329Subscribe
2330</button> <button type="button" id="chat-button" class="px-6 py-3 bg-white dark:bg-[#151515] text-black dark:text-white text-sm font-medium rounded-full border border-black/10 dark:border-white/10 hover:bg-black/5 dark:hover:bg-white/5 transition-colors whitespace-nowrap" data-astro-cid-tkm6qkaw>
2331Not today
2332</button> </div> <div id="newsletter-message" class="mt-3 text-sm hidden" data-astro-cid-tkm6qkaw></div> </form> <!-- Regular Chat Input (Hidden Initially) --> <div id="regular-chat-prompt" class="hidden" data-astro-cid-tkm6qkaw> <div class="flex gap-2" data-astro-cid-tkm6qkaw> <input type="text" id="chat-input" placeholder="Ask me anything about Taubyte..." class="flex-1 px-4 py-3 rounded-full border border-black/10 dark:border-white/10 bg-white dark:bg-[#151515] text-black dark:text-white placeholder-black/40 dark:placeholder-white/40 focus:outline-none focus:ring-2 focus:ring-black dark:focus:ring-white transition-all text-sm" data-astro-cid-tkm6qkaw> <button type="button" id="chat-send" class="px-6 py-3 bg-black dark:bg-white text-white dark:text-black text-sm font-medium rounded-full hover:bg-black/90 dark:hover:bg-white/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed" data-astro-cid-tkm6qkaw>
2333Send
2334</button> </div> </div> <!-- Name/Email Collection Prompt (Hidden Initially) --> <div id="name-email-prompt" class="hidden" data-astro-cid-tkm6qkaw> <form id="name-email-form" class="flex gap-2 flex-col sm:flex-row" data-astro-cid-tkm6qkaw> <input type="text" id="name-input" name="name" placeholder="Your name" required class="flex-1 px-4 py-3 rounded-full border border-black/10 dark:border-white/10 bg-white dark:bg-[#151515] text-black dark:text-white placeholder-black/40 dark:placeholder-white/40 focus:outline-none focus:ring-2 focus:ring-black dark:focus:ring-white transition-all text-sm" data-astro-cid-tkm6qkaw> <input type="email" id="email-input" name="email" placeholder="Your email" required class="flex-1 px-4 py-3 rounded-full border border-black/10 dark:border-white/10 bg-white dark:bg-[#151515] text-black dark:text-white placeholder-black/40 dark:placeholder-white/40 focus:outline-none focus:ring-2 focus:ring-black dark:focus:ring-white transition-all text-sm" data-astro-cid-tkm6qkaw> <button type="submit" id="name-email-submit" class="px-6 py-3 bg-black dark:bg-white text-white dark:text-black text-sm font-medium rounded-full hover:bg-black/90 dark:hover:bg-white/90 transition-colors disabled:opacity-50 disabled:cursor-not-allowed whitespace-nowrap" data-astro-cid-tkm6qkaw>
2335Continue
2336</button> </form> <div id="name-email-message" class="mt-3 text-sm hidden" data-astro-cid-tkm6qkaw></div> </div> </div> </div> </section> <!-- Floating Taure Avatar --> <div id="floating-taure-avatar" class="fixed bottom-6 right-6 z-50 hidden" data-astro-cid-tkm6qkaw> <div class="flex items-center gap-0 relative" data-astro-cid-tkm6qkaw> <!-- Message Bubble --> <div id="floating-taure-message" class="hidden h-[64px] pl-4 pr-12 flex items-center bg-white dark:bg-[#151515] rounded-l-full rounded-r-lg shadow-lg border border-black/10 dark:border-white/10 -mr-[32px] relative z-0" data-astro-cid-tkm6qkaw> <p class="text-sm text-black dark:text-white" data-astro-cid-tkm6qkaw>howdy</p> </div> <!-- Avatar --> <div class="w-[64px] h-[64px] rounded-full overflow-hidden shadow-lg border-2 border-white dark:border-[#151515] cursor-pointer hover:scale-110 transition-transform duration-200 shrink-0 relative z-10" data-astro-cid-tkm6qkaw> <img id="floating-taure-avatar-img" src="/taure-avatar.png" alt="Taure" class="w-full h-full object-cover" data-astro-cid-tkm6qkaw> </div> </div> </div> 
2336<script type="module" src="/_astro/Taure.astro_astro_type_script_index_0_lang.CWNAM_wp.js"></script>
2336 </main> <footer class="bg-white dark:bg-[#151515] transition-colors border-t border-black/10 dark:border-white/10" data-astro-transition-persist="astro-tvayyljk-2"> <div class="container mx-auto max-w-7xl px-6 py-8 md:py-12"> <div class="flex flex-col gap-8"> <!-- Main Footer Content --> <div class="grid grid-cols-2 md:grid-cols-5 gap-8 md:gap-6"> <!-- Logo and Brand --> <div class="col-span-2 md:col-span-1 flex flex-col gap-4"> <a href="/" class="block cursor-pointer w-fit"> <object data="/taubyte-logo-static.svg" type="image/svg+xml" class="h-6 w-auto dark:brightness-0 dark:invert pointer-events-none"></object> </a> <p class="text-xs text-black/60 dark:text-white/60 max-w-xs">
2337Fullstack workspace for humans & machines.
2338</p> </div> <!-- Product Section --> <div class="flex flex-col gap-3"> <h3 class="text-sm font-semibold text-black dark:text-white">Product</h3> <nav class="flex flex-col gap-2"> <a href="/download" class="text-sm text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors">Download</a> <a href="/features" class="text-sm text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors">Features</a> <a href="/getting-started" class="text-sm text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors">Getting Started</a> </nav> </div> <!-- Tools Section --> <div class="flex flex-col gap-3"> <h3 class="text-sm font-semibold text-black dark:text-white">Tools</h3> <nav class="flex flex-col gap-2"> <a href="/tools/toon" class="text-sm text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors">TOON Converter</a> <a href="/tools/tokenizer" class="text-sm text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors">Tokenizer Playground</a> <a href="/tools/embedder" class="text-sm text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors">Text Embedder</a> <a href="/tools/wasm" class="text-sm text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors">WebAssembly Playground</a> <a href="/tools/k8s-tax" class="text-sm text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors">K8s Tax Calculator</a> <a href="/tools/hf-mem" class="text-sm text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors">Model Memory Estimator</a> <a href="/tools/cloud-opportunity" class="text-sm text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors">What Taubyte Opens</a> </nav> </div> <!-- Resources Section --> <div class="flex flex-col gap-3"> <h3 class="text-sm font-semibold text-black dark:text-white">Resources</h3> <nav class="flex flex-col gap-2"> <a href="/doc" class="text-sm text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors">Documentation</a> <a href="/blog" class="text-sm text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors">Blog</a> <a href="/community" class="text-sm text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors">Community</a> </nav> </div> <!-- Legal & Company Section --> <div class="flex flex-col gap-3"> <h3 class="text-sm font-semibold text-black dark:text-white">Company</h3> <nav class="flex flex-col gap-2"> <a href="/about" class="text-sm text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors">About</a> <a href="/contact" class="text-sm text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors">Contact</a> <a href="/book-a-demo" class="text-sm text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors">Book a Demo</a> <a href="/privacy" class="text-sm text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors">Privacy</a> <a href="/terms" class="text-sm text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors">Terms</a> </nav> </div> </div> <!-- Bottom Bar: Social Links, Theme Toggle, and Copyright --> <div class="flex flex-col md:flex-row justify-between items-center gap-4 pt-6"> <!-- Copyright --> <p class="text-xs text-black/60 dark:text-white/60 text-center md:text-left">
2339© 2026 Taubyte. All rights reserved.
2340</p> <!-- Social Links and Theme Toggle --> <div class="flex items-center justify-center space-x-4"> <div class="flex items-center gap-2"> <button id="theme-toggle" class="p-2 rounded-md hover:bg-gray-100 dark:hover:bg-white/10 transition-colors text-gray-700 dark:text-gray-300" aria-label="Toggle theme" type="button"> <svg id="sun-icon" class="w-5 h-5 hidden dark:block" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 3v1m0 16v1m9-9h-1M4 12H3m15.364 6.364l-.707-.707M6.343 6.343l-.707-.707m12.728 0l-.707.707M6.343 17.657l-.707.707M16 12a4 4 0 11-8 0 4 4 0 018 0z"></path> </svg> <svg id="moon-icon" class="w-5 h-5 block dark:hidden" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"></path> </svg> </button> </div> 
2340<script type="module">document.addEventListener("DOMContentLoaded",function(){const t=document.getElementById("theme-toggle"),e=document.documentElement;t&&t.addEventListener("click",()=>{e.classList.contains("dark")?(e.classList.remove("dark"),localStorage.setItem("theme","light")):(e.classList.add("dark"),localStorage.setItem("theme","dark"))})});</script>
2340 <a href="https://x.com/dtaubyte" target="_blank" rel="noopener noreferrer" class="text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors" aria-label="X (Twitter)"> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"> <path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z"></path> </svg> </a> <a href="https://github.com/taubyte/tau" target="_blank" rel="noopener noreferrer" class="text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors" aria-label="GitHub"> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"> <path fill-rule="evenodd" d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0112 6.844c.85.004 1.705.115 2.504.337 1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.019 10.019 0 0022 12.017C22 6.484 17.522 2 12 2z" clip-rule="evenodd"></path> </svg> </a> <a href="https://www.linkedin.com/company/taubyte-page" target="_blank" rel="noopener noreferrer" class="text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors" aria-label="LinkedIn"> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"> <path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.063 2.063 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z"></path> </svg> </a> <a href="https://discord.com/invite/KbN3KN7kpQ" target="_blank" rel="noopener noreferrer" class="text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors" aria-label="Discord"> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"> <path d="M20.317 4.492c-1.53-.69-3.17-1.2-4.885-1.49a.075.075 0 0 0-.079.036c-.21.369-.444.85-.608 1.23a18.566 18.566 0 0 0-5.487 0 12.36 12.36 0 0 0-.617-1.23A.077.077 0 0 0 8.562 3c-1.714.29-3.354.8-4.885 1.491a.07.07 0 0 0-.032.027C.533 9.093-.32 13.555.099 17.961a.08.08 0 0 0 .031.055 20.03 20.03 0 0 0 5.993 2.98.078.078 0 0 0 .084-.026c.462-.62.874-1.275 1.226-1.963.021-.04.001-.088-.041-.104a13.201 13.201 0 0 1-1.872-.878.075.075 0 0 1-.008-.125c.126-.093.252-.19.372-.287a.075.075 0 0 1 .078-.01c3.927 1.764 8.18 1.764 12.061 0a.075.075 0 0 1 .079.009c.12.098.245.195.372.288a.075.075 0 0 1-.006.125c-.598.344-1.22.635-1.873.877a.075.075 0 0 0-.041.105c.36.687.772 1.341 1.225 1.962a.077.077 0 0 0 .084.028 19.963 19.963 0 0 0 6.002-2.981.076.076 0 0 0 .032-.054c.5-5.094-.838-9.52-3.549-13.442a.06.06 0 0 0-.031-.028zM8.02 15.278c-1.182 0-2.157-1.069-2.157-2.38 0-1.312.956-2.38 2.157-2.38 1.21 0 2.176 1.077 2.157 2.38 0 1.312-.956 2.38-2.157 2.38zm7.975 0c-1.183 0-2.157-1.069-2.157-2.38 0-1.312.955-2.38 2.157-2.38 1.21 0 2.176 1.077 2.157 2.38 0 1.312-.946 2.38-2.157 2.38z"></path> </svg> </a> <a href="https://www.instagram.com/dtaubyte" target="_blank" rel="noopener noreferrer" class="text-black/70 dark:text-white/70 hover:text-black dark:hover:text-white transition-colors" aria-label="Instagram"> <svg class="w-5 h-5" fill="currentColor" viewBox="0 0 24 24"> <path d="M12 2.163c3.204 0 3.584.012 4.85.07 3.252.148 4.771 1.691 4.919 4.919.058 1.265.069 1.645.069 4.849 0 3.205-.012 3.584-.069 4.849-.149 3.225-1.664 4.771-4.919 4.919-1.266.058-1.644.07-4.85.07-3.204 0-3.584-.012-4.849-.07-3.26-.149-4.771-1.699-4.919-4.92-.058-1.265-.07-1.644-.07-4.849 0-3.204.013-3.583.07-4.849.149-3.227 1.664-4.771 4.919-4.919 1.266-.057 1.645-.069 4.849-.069zm0-2.163c-3.259 
23400-3.667.014-4.947.072-4.358.2-6.78 2.618-6.98 6.98-.059 1.281-.073 1.689-.073 4.948 0 3.259.014 3.668.072 4.948.2 4.358 2.618 6.78 6.98 6.98 1.281.058 1.689.072 4.948.072 3.259 0 3.668-.014 4.948-.072 4.354-.2 6.782-2.618 6.979-6.98.059-1.28.073-1.689.073-4.948 0-3.259-.014-3.667-.072-4.947-.196-4.354-2.617-6.78-6.979-6.98-1.281-.059-1.69-.073-4.949-.073zm0 5.838c-3.403 0-6.162 2.759-6.162 6.162s2.759 6.163 6.162 6.163 6.162-2.759 6.162-6.163c0-3.403-2.759-6.162-6.162-6.162zm0 10.162c-2.209 0-4-1.79-4-4 0-2.209 1.791-4 4-4s4 1.791 4 4c0 2.21-1.791 4-4 4zm6.406-11.845c-.796 0-1.441.645-1.441 1.44s.645 1.44 1.441 1.44c.795 0 1.439-.645 1.439-1.44s-.644-1.44-1.439-1.44z"></path> </svg> </a> </div> </div> </div> </div> </footer>  
2340<script>
2341  // Function to update favicon based on theme
2342  function updateFavicon() {
2343    var isDark = document.documentElement.classList.contains('dark');
2344    var favicon = document.querySelector('link[rel="icon"]');
2345    if (favicon && favicon instanceof HTMLLinkElement) {
2346      // Update via Data URI for immediate effect
2347      var svgContent = isDark 
2348        ? '<svg width="120mm" height="120mm" version="1.1" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg"><path fill="#ffffff" d="m0.64401 10.882c2.0263 11.607 11.55 18.974 20.476 21.646v62.992c0 7.5331 6.0654 13.597 13.598 13.597h16.845l5.8002-21.647h-14.596v-54.942h19.736l5.8002-21.647zm76.444 0-5.8002 21.647h26.421v54.942h-31.561l-5.8002 21.647h45.411c7.5332 0 13.597-6.0642 13.597-13.597v-71.04c0-7.5332-6.064-13.598-13.597-13.598z"/></svg>'
2349        : '<svg width="120mm" height="120mm" version="1.1" viewBox="0 0 120 120" xmlns="http://www.w3.org/2000/svg"><path fill="#000000" d="m0.64401 10.882c2.0263 11.607 11.55 18.974 20.476 21.646v62.992c0 7.5331 6.0654 13.597 13.598 13.597h16.845l5.8002-21.647h-14.596v-54.942h19.736l5.8002-21.647zm76.444 0-5.8002 21.647h26.421v54.942h-31.561l-5.8002 21.647h45.411c7.5332 0 13.597-6.0642 13.597-13.597v-71.04c0-7.5332-6.064-13.598-13.597-13.598z"/></svg>';
2350      favicon.href = 'data:image/svg+xml;base64,' + btoa(svgContent);
2351    }
2352  }
2353
2354  // Carry current theme class to the incoming document during view transitions
2355  document.addEventListener('astro:before-swap', (event) => {
2356    const isDark = document.documentElement.classList.contains('dark');
2357    if (isDark) {
2358      event.newDocument.documentElement.classList.add('dark');
2359    } else {
2360      event.newDocument.documentElement.classList.remove('dark');
2361    }
2362  });
2363
2364  // Ensure theme is re-applied after navigation as well
2365  document.addEventListener('astro:page-load', () => {
2366    try {
2367      var saved = localStorage.getItem('theme');
2368      var prefersLight = window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches;
2369      var theme = saved || (prefersLight ? 'light' : 'dark');
2370      if (theme === 'dark') {
2371        document.documentElement.classList.add('dark');
2372      } else {
2373        document.documentElement.classList.remove('dark');
2374      }
2375      updateFavicon();
2376    } catch (e) {}
2377    
2378    // Track pageview for Google Analytics on View Transition navigation
2379    try {
2380      if (typeof window !== 'undefined' && window.gtag) {
2381        window.gtag('config', 'G-1Y0G0GVEQP', {
2382          page_path: window.location.pathname + window.location.search
2383        });
2384      }
2385    } catch (e) {}
2386  });
2387
2388  // Watch for theme changes
2389  document.addEventListener('DOMContentLoaded', () => {
2390    updateFavicon();
2391    
2392    // Create a MutationObserver to watch for class changes on html element
2393    const observer = new MutationObserver(() => {
2394      updateFavicon();
2395    });
2396    
2397    observer.observe(document.documentElement, {
2398      attributes: true,
2399      attributeFilter: ['class']
2400    });
2401  });
2402</script>
2402 </body></html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.