From affbe751eca578879cff83c8d9bebbe7837ca7e0 Mon Sep 17 00:00:00 2001 From: ryaneggz Date: Fri, 19 Jun 2026 22:28:24 -0600 Subject: [PATCH 1/4] feat: add Our Technology Ecosystem section below About MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Relocate the technology slider out of the footer into its own homepage section directly beneath the About section, upgraded to the adaptive.biz "Our Technology Ecosystem" treatment: - Two opposite-scrolling logo-card carousels (seamless loop via per-card margin) + View All ⇄ Hide responsive grid toggle - Per-card hover tooltips; logo cards with onError + naturalWidth fallback to green initials for logo-less techs - Mifune stack + theme (green accents, theme tokens); brand logos on light cards for legibility - A11y preserved: Pause/Resume + hover-pause, prefers-reduced-motion static fallback, aria-labelledby, alt text, aria-pressed/expanded - Keyframes live in tailwind.config (ship in static CSS) - Footer reverted to its pre-slider state Co-Authored-By: Claude Opus 4.8 (1M context) --- public/sw.js | 2 +- src/app/page.tsx | 2 + src/sections/FooterSection.tsx | 96 +------ src/sections/TechnologyEcosystemSection.tsx | 261 ++++++++++++++++++++ tailwind.config.ts | 11 + 5 files changed, 276 insertions(+), 96 deletions(-) create mode 100644 src/sections/TechnologyEcosystemSection.tsx diff --git a/public/sw.js b/public/sw.js index 1d4b1f6..caff655 100644 --- a/public/sw.js +++ b/public/sw.js @@ -1 +1 @@ -if(!self.define){let e,s={};const n=(n,a)=>(n=new URL(n+".js",a).href,s[n]||new Promise((s=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=s,document.head.appendChild(e)}else e=n,importScripts(n),s()})).then((()=>{let e=s[n];if(!e)throw new Error(`Module ${n} didn’t register its module`);return e})));self.define=(a,c)=>{const i=e||("document"in self?document.currentScript.src:"")||location.href;if(s[i])return;let t={};const r=e=>n(e,i),f={module:{uri:i},exports:t,require:r};s[i]=Promise.all(a.map((e=>f[e]||r(e)))).then((e=>(c(...e),t)))}}define(["./workbox-c06b064f"],(function(e){"use strict";importScripts("/fallback-8e5b7798448a30a7.js"),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/static/chunks/0dbeb660-b76dd34eb4ea8fd0.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/1096-4330136a329db0a7.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/1396.1ccf2e49a70685e7.js",revision:"1ccf2e49a70685e7"},{url:"/_next/static/chunks/169.91746092641a81ae.js",revision:"91746092641a81ae"},{url:"/_next/static/chunks/1766.ca1028667f51c812.js",revision:"ca1028667f51c812"},{url:"/_next/static/chunks/1941.c94eabc784600153.js",revision:"c94eabc784600153"},{url:"/_next/static/chunks/2274.4d5b9b3f7dd91bf1.js",revision:"4d5b9b3f7dd91bf1"},{url:"/_next/static/chunks/231-deca7f6a78a61bbe.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/235.619031ab3b883a4c.js",revision:"619031ab3b883a4c"},{url:"/_next/static/chunks/2409-c325d016f0fd3075.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/2566.ff4fbb9d92501aba.js",revision:"ff4fbb9d92501aba"},{url:"/_next/static/chunks/2884-253d5fd11cce33b9.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/2889.5a548b41e09e5af8.js",revision:"5a548b41e09e5af8"},{url:"/_next/static/chunks/2cdb6380.bd4f57458181ed03.js",revision:"bd4f57458181ed03"},{url:"/_next/static/chunks/3234.32712ed297a98b5b.js",revision:"32712ed297a98b5b"},{url:"/_next/static/chunks/3321.a8f2ab5ab226c94d.js",revision:"a8f2ab5ab226c94d"},{url:"/_next/static/chunks/3570.5def040bfbfddb75.js",revision:"5def040bfbfddb75"},{url:"/_next/static/chunks/3764.be3713068ae0b8c3.js",revision:"be3713068ae0b8c3"},{url:"/_next/static/chunks/4208-8aa9b7e2ae8e3264.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/4583.2c80267207d6712b.js",revision:"2c80267207d6712b"},{url:"/_next/static/chunks/4866.b6bb0686c0d638e5.js",revision:"b6bb0686c0d638e5"},{url:"/_next/static/chunks/5042-50804081516c71bf.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/5190-b46161770304692e.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/5332.4350d6d296d61103.js",revision:"4350d6d296d61103"},{url:"/_next/static/chunks/53c13509-0d7f8ecc1d3cdb44.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/5810.81ec6045eb031643.js",revision:"81ec6045eb031643"},{url:"/_next/static/chunks/5877.094a29a371c68a8b.js",revision:"094a29a371c68a8b"},{url:"/_next/static/chunks/6129.99781c93bb1a5f1c.js",revision:"99781c93bb1a5f1c"},{url:"/_next/static/chunks/6177.9060afbc5ca6fc4e.js",revision:"9060afbc5ca6fc4e"},{url:"/_next/static/chunks/631.b3f7a82af86bfe6e.js",revision:"b3f7a82af86bfe6e"},{url:"/_next/static/chunks/6504.ac17212621239b87.js",revision:"ac17212621239b87"},{url:"/_next/static/chunks/6644.1aaaaa2ed16e82f4.js",revision:"1aaaaa2ed16e82f4"},{url:"/_next/static/chunks/6841.173217920e27cbb4.js",revision:"173217920e27cbb4"},{url:"/_next/static/chunks/6866.0daf2918ee969ac5.js",revision:"0daf2918ee969ac5"},{url:"/_next/static/chunks/6868.24f5c37c5aa9bdd1.js",revision:"24f5c37c5aa9bdd1"},{url:"/_next/static/chunks/6885.f7cf0bb6d0721914.js",revision:"f7cf0bb6d0721914"},{url:"/_next/static/chunks/6939.656342a877cb755f.js",revision:"656342a877cb755f"},{url:"/_next/static/chunks/7005.f9bbd0695f3d5f72.js",revision:"f9bbd0695f3d5f72"},{url:"/_next/static/chunks/7064.04862e2771650cd2.js",revision:"04862e2771650cd2"},{url:"/_next/static/chunks/7544.46aa6b1962665928.js",revision:"46aa6b1962665928"},{url:"/_next/static/chunks/7604.488d784a6f9f474e.js",revision:"488d784a6f9f474e"},{url:"/_next/static/chunks/795d4814-26980cfb0ce5b7d6.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/8090.644579c441122462.js",revision:"644579c441122462"},{url:"/_next/static/chunks/830.23eb3b4843bd3854.js",revision:"23eb3b4843bd3854"},{url:"/_next/static/chunks/8643.54a9c73cdba9280a.js",revision:"54a9c73cdba9280a"},{url:"/_next/static/chunks/8876.caf8bbc098330da7.js",revision:"caf8bbc098330da7"},{url:"/_next/static/chunks/8e1d74a4-3dce167276a2bc37.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/90542734.2bd0a0a7451654b8.js",revision:"2bd0a0a7451654b8"},{url:"/_next/static/chunks/9183.8b669201afc4176c.js",revision:"8b669201afc4176c"},{url:"/_next/static/chunks/9472.640c45e761e124de.js",revision:"640c45e761e124de"},{url:"/_next/static/chunks/9492.5c74bb8f5ac9ef66.js",revision:"5c74bb8f5ac9ef66"},{url:"/_next/static/chunks/9822.39d6b3cfa93badd5.js",revision:"39d6b3cfa93badd5"},{url:"/_next/static/chunks/9861.98ed6ce5ac74aa66.js",revision:"98ed6ce5ac74aa66"},{url:"/_next/static/chunks/app/_not-found/page-54e3008a84d64074.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/app/blog/%5Bslug%5D/page-d36124fddbb1e1ef.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/app/blog/page-84e6e7105b53962d.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/app/case-studies/page-b01394112390fe86.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/app/layout-a1b2eb94e7884912.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/app/offline/page-1b69cf363bbaf8bc.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/app/page-1d77de50ca97aa44.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/app/pricing/page-d4b1cf3faaf84a58.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/app/services/layout-8e3eb591a1917a5a.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/app/services/page-ec9c8ff921b0e8bf.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/app/socials/page-5eb59b5afa6afb83.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/d3ac728e.015cf0093df3cdc6.js",revision:"015cf0093df3cdc6"},{url:"/_next/static/chunks/ee560e2c-93d0c3fe3cadd807.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/fd9d1056-b848dae799369838.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/framework-08aa667e5202eed8.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/main-6eabcdc505217536.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/main-app-1e79748853859877.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/pages/_app-f870474a17b7f2fd.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/pages/_error-c66a4e8afc46f17b.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js",revision:"79330112775102f91e1010318bae2bd3"},{url:"/_next/static/chunks/webpack-f766f65bbfcbbef3.js",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/_next/static/css/0cd52fa32357e4b5.css",revision:"0cd52fa32357e4b5"},{url:"/_next/static/css/0ed87202b54c3e18.css",revision:"0ed87202b54c3e18"},{url:"/_next/static/media/1f173e5e25f3efee-s.woff2",revision:"f143fb4877cf7ada1b84423ee86a0198"},{url:"/_next/static/media/36966cca54120369-s.p.woff2",revision:"25ea4a783c12103f175f5b157b7d96aa"},{url:"/_next/static/media/48e2044251ef3125-s.woff2",revision:"45ea393f38e4ecd97f4dbeb12ef23877"},{url:"/_next/static/media/904be59b21bd51cb-s.p.woff2",revision:"c154477b9affa3a0a47f894c8b80c03c"},{url:"/_next/static/media/b1f344208eb4edfe-s.woff2",revision:"b5818778898bf6d34b7423ff99c6beb4"},{url:"/_next/static/media/b7387a63dd068245-s.woff2",revision:"dea099b7d5a5ea45bd4367f8aeff62ab"},{url:"/_next/static/media/bf24a9759715e608-s.woff2",revision:"d185d272afd4e2d7b4801eabba1463a1"},{url:"/_next/static/media/e1aab0933260df4d-s.woff2",revision:"207f8e9f3761dbd724063a177d906a99"},{url:"/_next/static/z6MNbQnDqcqJczCRWGSZr/_buildManifest.js",revision:"3e2d62a10f4d6bf0b92e14aecf7836f4"},{url:"/_next/static/z6MNbQnDqcqJczCRWGSZr/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/fallback-8e5b7798448a30a7.js",revision:"a5281aa1504c5d6bcd7ba1097870376a"},{url:"/images/iphone-mock.png",revision:"c18b97249020ce36f6d017b46a0333da"},{url:"/images/logo-bg.png",revision:"1c6017df99acb611cc2df967ff3423ab"},{url:"/images/ruska_logo_200.png",revision:"e5f5e1527492c08d5b0ba18a2917734d"},{url:"/images/ryan-eggleston.png",revision:"78bcd693d2a6f2a62979322751fdf3bc"},{url:"/images/ryan_egg.png",revision:"c0293d621986355348b887dc5caa4448"},{url:"/llm.txt",revision:"b78aae937d81ea7f99c072e12d789bc0"},{url:"/manifest.json",revision:"634850c6e1d0c42c3353287176982fda"},{url:"/next.svg",revision:"8e061864f388b47f33a1c3780831193e"},{url:"/offline",revision:"z6MNbQnDqcqJczCRWGSZr"},{url:"/pe-logo.png",revision:"e798d97498601321e902e076a112848b"},{url:"/resume.pdf",revision:"d23871a0bd5ba764a57d127c998be4c4"},{url:"/swe-worker-4da67dda9bc18c53.js",revision:"5a47d90db13bb1309b25bdf7b363570e"},{url:"/vercel.svg",revision:"61c6b19abff40ea7acd577be818f3976"}],{ignoreURLParametersMatching:[/^utm_/,/^fbclid$/]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:async({response:e})=>e&&"opaqueredirect"===e.type?new Response(e.body,{status:200,statusText:"OK",headers:e.headers}):e},{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,new e.CacheFirst({cacheName:"google-fonts-webfonts",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:31536e3}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,new e.StaleWhileRevalidate({cacheName:"google-fonts-stylesheets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,new e.StaleWhileRevalidate({cacheName:"static-font-assets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,new e.StaleWhileRevalidate({cacheName:"static-image-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:2592e3}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\/_next\/static.+\.js$/i,new e.CacheFirst({cacheName:"next-static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\/_next\/image\?url=.+$/i,new e.StaleWhileRevalidate({cacheName:"next-image",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:mp3|wav|ogg)$/i,new e.CacheFirst({cacheName:"static-audio-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:mp4|webm)$/i,new e.CacheFirst({cacheName:"static-video-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:js)$/i,new e.StaleWhileRevalidate({cacheName:"static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:48,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:css|less)$/i,new e.StaleWhileRevalidate({cacheName:"static-style-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\/_next\/data\/.+\/.+\.json$/i,new e.StaleWhileRevalidate({cacheName:"next-data",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:json|xml|csv)$/i,new e.NetworkFirst({cacheName:"static-data-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({sameOrigin:e,url:{pathname:s}})=>!(!e||s.startsWith("/api/auth/callback")||!s.startsWith("/api/"))),new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({request:e,url:{pathname:s},sameOrigin:n})=>"1"===e.headers.get("RSC")&&"1"===e.headers.get("Next-Router-Prefetch")&&n&&!s.startsWith("/api/")),new e.NetworkFirst({cacheName:"pages-rsc-prefetch",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({request:e,url:{pathname:s},sameOrigin:n})=>"1"===e.headers.get("RSC")&&n&&!s.startsWith("/api/")),new e.NetworkFirst({cacheName:"pages-rsc",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({url:{pathname:e},sameOrigin:s})=>s&&!e.startsWith("/api/")),new e.NetworkFirst({cacheName:"pages",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({sameOrigin:e})=>!e),new e.NetworkFirst({cacheName:"cross-origin",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:3600}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),self.__WB_DISABLE_DEV_LOGS=!0})); +if(!self.define){let e,s={};const a=(a,n)=>(a=new URL(a+".js",n).href,s[a]||new Promise((s=>{if("document"in self){const e=document.createElement("script");e.src=a,e.onload=s,document.head.appendChild(e)}else e=a,importScripts(a),s()})).then((()=>{let e=s[a];if(!e)throw new Error(`Module ${a} didn’t register its module`);return e})));self.define=(n,t)=>{const i=e||("document"in self?document.currentScript.src:"")||location.href;if(s[i])return;let c={};const r=e=>a(e,i),d={module:{uri:i},exports:c,require:r};s[i]=Promise.all(n.map((e=>d[e]||r(e)))).then((e=>(t(...e),c)))}}define(["./workbox-c06b064f"],(function(e){"use strict";importScripts("/fallback-8e5b7798448a30a7.js"),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/static/C_GjIh2S1RbbtQABQ8ZBh/_buildManifest.js",revision:"3e2d62a10f4d6bf0b92e14aecf7836f4"},{url:"/_next/static/C_GjIh2S1RbbtQABQ8ZBh/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/_next/static/chunks/0dbeb660-b76dd34eb4ea8fd0.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/1096-070f2c4af6ff1a95.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/1396.1ccf2e49a70685e7.js",revision:"1ccf2e49a70685e7"},{url:"/_next/static/chunks/169.91746092641a81ae.js",revision:"91746092641a81ae"},{url:"/_next/static/chunks/1766.ca1028667f51c812.js",revision:"ca1028667f51c812"},{url:"/_next/static/chunks/1941.c94eabc784600153.js",revision:"c94eabc784600153"},{url:"/_next/static/chunks/2274.4d5b9b3f7dd91bf1.js",revision:"4d5b9b3f7dd91bf1"},{url:"/_next/static/chunks/231-deca7f6a78a61bbe.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/235.619031ab3b883a4c.js",revision:"619031ab3b883a4c"},{url:"/_next/static/chunks/2409-c325d016f0fd3075.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/2566.ff4fbb9d92501aba.js",revision:"ff4fbb9d92501aba"},{url:"/_next/static/chunks/2884-253d5fd11cce33b9.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/2889.5a548b41e09e5af8.js",revision:"5a548b41e09e5af8"},{url:"/_next/static/chunks/2cdb6380.bd4f57458181ed03.js",revision:"bd4f57458181ed03"},{url:"/_next/static/chunks/3234.32712ed297a98b5b.js",revision:"32712ed297a98b5b"},{url:"/_next/static/chunks/3321.a8f2ab5ab226c94d.js",revision:"a8f2ab5ab226c94d"},{url:"/_next/static/chunks/3570.5def040bfbfddb75.js",revision:"5def040bfbfddb75"},{url:"/_next/static/chunks/3764.be3713068ae0b8c3.js",revision:"be3713068ae0b8c3"},{url:"/_next/static/chunks/4208-8aa9b7e2ae8e3264.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/4583.2c80267207d6712b.js",revision:"2c80267207d6712b"},{url:"/_next/static/chunks/4866.b6bb0686c0d638e5.js",revision:"b6bb0686c0d638e5"},{url:"/_next/static/chunks/5042-50804081516c71bf.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/5190-b46161770304692e.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/5332.4350d6d296d61103.js",revision:"4350d6d296d61103"},{url:"/_next/static/chunks/53c13509-0d7f8ecc1d3cdb44.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/5810.81ec6045eb031643.js",revision:"81ec6045eb031643"},{url:"/_next/static/chunks/5877.094a29a371c68a8b.js",revision:"094a29a371c68a8b"},{url:"/_next/static/chunks/6129.99781c93bb1a5f1c.js",revision:"99781c93bb1a5f1c"},{url:"/_next/static/chunks/6177.9060afbc5ca6fc4e.js",revision:"9060afbc5ca6fc4e"},{url:"/_next/static/chunks/631.b3f7a82af86bfe6e.js",revision:"b3f7a82af86bfe6e"},{url:"/_next/static/chunks/6504.ac17212621239b87.js",revision:"ac17212621239b87"},{url:"/_next/static/chunks/6644.1aaaaa2ed16e82f4.js",revision:"1aaaaa2ed16e82f4"},{url:"/_next/static/chunks/6841.173217920e27cbb4.js",revision:"173217920e27cbb4"},{url:"/_next/static/chunks/6866.0daf2918ee969ac5.js",revision:"0daf2918ee969ac5"},{url:"/_next/static/chunks/6868.24f5c37c5aa9bdd1.js",revision:"24f5c37c5aa9bdd1"},{url:"/_next/static/chunks/6885.f7cf0bb6d0721914.js",revision:"f7cf0bb6d0721914"},{url:"/_next/static/chunks/6939.656342a877cb755f.js",revision:"656342a877cb755f"},{url:"/_next/static/chunks/7005.f9bbd0695f3d5f72.js",revision:"f9bbd0695f3d5f72"},{url:"/_next/static/chunks/7064.04862e2771650cd2.js",revision:"04862e2771650cd2"},{url:"/_next/static/chunks/7544.46aa6b1962665928.js",revision:"46aa6b1962665928"},{url:"/_next/static/chunks/7604.488d784a6f9f474e.js",revision:"488d784a6f9f474e"},{url:"/_next/static/chunks/795d4814-26980cfb0ce5b7d6.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/8090.644579c441122462.js",revision:"644579c441122462"},{url:"/_next/static/chunks/830.23eb3b4843bd3854.js",revision:"23eb3b4843bd3854"},{url:"/_next/static/chunks/8643.54a9c73cdba9280a.js",revision:"54a9c73cdba9280a"},{url:"/_next/static/chunks/8876.caf8bbc098330da7.js",revision:"caf8bbc098330da7"},{url:"/_next/static/chunks/8e1d74a4-0c312d1addb5f27c.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/90542734.2bd0a0a7451654b8.js",revision:"2bd0a0a7451654b8"},{url:"/_next/static/chunks/9183.8b669201afc4176c.js",revision:"8b669201afc4176c"},{url:"/_next/static/chunks/9472.640c45e761e124de.js",revision:"640c45e761e124de"},{url:"/_next/static/chunks/9492.5c74bb8f5ac9ef66.js",revision:"5c74bb8f5ac9ef66"},{url:"/_next/static/chunks/9822.39d6b3cfa93badd5.js",revision:"39d6b3cfa93badd5"},{url:"/_next/static/chunks/9861.98ed6ce5ac74aa66.js",revision:"98ed6ce5ac74aa66"},{url:"/_next/static/chunks/app/_not-found/page-54e3008a84d64074.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/blog/%5Bslug%5D/page-d36124fddbb1e1ef.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/blog/page-84e6e7105b53962d.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/case-studies/page-b01394112390fe86.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/layout-a1b2eb94e7884912.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/offline/page-1b69cf363bbaf8bc.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/page-37600ce25102b58f.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/pricing/page-d4b1cf3faaf84a58.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/services/layout-8e3eb591a1917a5a.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/services/page-47d6d58934a3208e.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/socials/page-4afd329d6270db39.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/d3ac728e.015cf0093df3cdc6.js",revision:"015cf0093df3cdc6"},{url:"/_next/static/chunks/ee560e2c-93d0c3fe3cadd807.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/fd9d1056-b848dae799369838.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/framework-08aa667e5202eed8.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/main-6eabcdc505217536.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/main-app-1e79748853859877.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/pages/_app-f870474a17b7f2fd.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/pages/_error-c66a4e8afc46f17b.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js",revision:"79330112775102f91e1010318bae2bd3"},{url:"/_next/static/chunks/webpack-f766f65bbfcbbef3.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/css/0ed87202b54c3e18.css",revision:"0ed87202b54c3e18"},{url:"/_next/static/css/35228d8fbb2d2c09.css",revision:"35228d8fbb2d2c09"},{url:"/_next/static/media/1f173e5e25f3efee-s.woff2",revision:"f143fb4877cf7ada1b84423ee86a0198"},{url:"/_next/static/media/36966cca54120369-s.p.woff2",revision:"25ea4a783c12103f175f5b157b7d96aa"},{url:"/_next/static/media/48e2044251ef3125-s.woff2",revision:"45ea393f38e4ecd97f4dbeb12ef23877"},{url:"/_next/static/media/904be59b21bd51cb-s.p.woff2",revision:"c154477b9affa3a0a47f894c8b80c03c"},{url:"/_next/static/media/b1f344208eb4edfe-s.woff2",revision:"b5818778898bf6d34b7423ff99c6beb4"},{url:"/_next/static/media/b7387a63dd068245-s.woff2",revision:"dea099b7d5a5ea45bd4367f8aeff62ab"},{url:"/_next/static/media/bf24a9759715e608-s.woff2",revision:"d185d272afd4e2d7b4801eabba1463a1"},{url:"/_next/static/media/e1aab0933260df4d-s.woff2",revision:"207f8e9f3761dbd724063a177d906a99"},{url:"/fallback-8e5b7798448a30a7.js",revision:"a5281aa1504c5d6bcd7ba1097870376a"},{url:"/images/iphone-mock.png",revision:"c18b97249020ce36f6d017b46a0333da"},{url:"/images/logo-bg.png",revision:"1c6017df99acb611cc2df967ff3423ab"},{url:"/images/ruska_logo_200.png",revision:"e5f5e1527492c08d5b0ba18a2917734d"},{url:"/images/ryan-eggleston.png",revision:"78bcd693d2a6f2a62979322751fdf3bc"},{url:"/images/ryan_egg.png",revision:"c0293d621986355348b887dc5caa4448"},{url:"/llm.txt",revision:"b78aae937d81ea7f99c072e12d789bc0"},{url:"/manifest.json",revision:"634850c6e1d0c42c3353287176982fda"},{url:"/next.svg",revision:"8e061864f388b47f33a1c3780831193e"},{url:"/offline",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/pe-logo.png",revision:"e798d97498601321e902e076a112848b"},{url:"/resume.pdf",revision:"d23871a0bd5ba764a57d127c998be4c4"},{url:"/swe-worker-4da67dda9bc18c53.js",revision:"5a47d90db13bb1309b25bdf7b363570e"},{url:"/vercel.svg",revision:"61c6b19abff40ea7acd577be818f3976"}],{ignoreURLParametersMatching:[/^utm_/,/^fbclid$/]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:async({response:e})=>e&&"opaqueredirect"===e.type?new Response(e.body,{status:200,statusText:"OK",headers:e.headers}):e},{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,new e.CacheFirst({cacheName:"google-fonts-webfonts",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:31536e3}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,new e.StaleWhileRevalidate({cacheName:"google-fonts-stylesheets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,new e.StaleWhileRevalidate({cacheName:"static-font-assets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,new e.StaleWhileRevalidate({cacheName:"static-image-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:2592e3}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\/_next\/static.+\.js$/i,new e.CacheFirst({cacheName:"next-static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\/_next\/image\?url=.+$/i,new e.StaleWhileRevalidate({cacheName:"next-image",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:mp3|wav|ogg)$/i,new e.CacheFirst({cacheName:"static-audio-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:mp4|webm)$/i,new e.CacheFirst({cacheName:"static-video-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:js)$/i,new e.StaleWhileRevalidate({cacheName:"static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:48,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:css|less)$/i,new e.StaleWhileRevalidate({cacheName:"static-style-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\/_next\/data\/.+\/.+\.json$/i,new e.StaleWhileRevalidate({cacheName:"next-data",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:json|xml|csv)$/i,new e.NetworkFirst({cacheName:"static-data-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({sameOrigin:e,url:{pathname:s}})=>!(!e||s.startsWith("/api/auth/callback")||!s.startsWith("/api/"))),new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({request:e,url:{pathname:s},sameOrigin:a})=>"1"===e.headers.get("RSC")&&"1"===e.headers.get("Next-Router-Prefetch")&&a&&!s.startsWith("/api/")),new e.NetworkFirst({cacheName:"pages-rsc-prefetch",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({request:e,url:{pathname:s},sameOrigin:a})=>"1"===e.headers.get("RSC")&&a&&!s.startsWith("/api/")),new e.NetworkFirst({cacheName:"pages-rsc",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({url:{pathname:e},sameOrigin:s})=>s&&!e.startsWith("/api/")),new e.NetworkFirst({cacheName:"pages",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({sameOrigin:e})=>!e),new e.NetworkFirst({cacheName:"cross-origin",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:3600}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),self.__WB_DISABLE_DEV_LOGS=!0})); diff --git a/src/app/page.tsx b/src/app/page.tsx index 126b533..b0f2f7a 100644 --- a/src/app/page.tsx +++ b/src/app/page.tsx @@ -4,6 +4,7 @@ import PainSection from "@/sections/PainSection"; import PricingSection from "@/sections/PricingSection"; import ProductShowcaseSection from "@/sections/ProductShowcaseSection"; import AboutSection from "@/sections/AboutSection"; +import TechnologyEcosystemSection from "@/sections/TechnologyEcosystemSection"; import FAQSection from "@/sections/FAQSection"; import EnterpriseSection from "@/sections/EnterpriseSection"; import CTASection from "@/sections/CTASection"; @@ -21,6 +22,7 @@ export default function Home() { + diff --git a/src/sections/FooterSection.tsx b/src/sections/FooterSection.tsx index 6ba9882..267e435 100644 --- a/src/sections/FooterSection.tsx +++ b/src/sections/FooterSection.tsx @@ -5,35 +5,9 @@ import Link from "next/link"; import { apiClient } from "@/utils/client"; import { socialIcons } from "@/config/app"; -const technologies = [ - "LangGraph", - "LangChain", - "DeepAgents", - "Claude Code", - "OpenAI Codex", - "Hermes", - "Pi", - "DSPy", - "FastAPI", - "Python", - "TypeScript", - "React", - "Next.js", - "Tailwind CSS", - "MCP", - "A2A", - "PostgreSQL + pgvector", - "Redis", - "Playwright", - "Ollama", -]; - -const technologyRail = [...technologies, ...technologies]; - const FooterSection = () => { const [email, setEmail] = useState(''); const [loading, setLoading] = useState(false); - const [isTechnologyRailPaused, setIsTechnologyRailPaused] = useState(false); const handleSubmit = async (e: any) => { e.preventDefault(); @@ -70,7 +44,7 @@ const FooterSection = () => {

- Build dependable AI workflows on a broad, production-ready agent stack. + Build your AI digital workforce with intelligent agents powered by LangChain DeepAgents.

@@ -166,74 +140,6 @@ const FooterSection = () => { - {/* Technologies Slider */} -
-
-
-

- Technologies we use -

- -
-
-

- From agent runtimes to production infrastructure, Mifune builds across the modern AI engineering ecosystem. -

- -
-
- -
-
- {technologyRail.map((technology, index) => { - const isDuplicate = index >= technologies.length; - - return ( - - {technology} - - ); - })} -
-
-
- - - {/* Bottom Bar */}
diff --git a/src/sections/TechnologyEcosystemSection.tsx b/src/sections/TechnologyEcosystemSection.tsx new file mode 100644 index 0000000..baceccc --- /dev/null +++ b/src/sections/TechnologyEcosystemSection.tsx @@ -0,0 +1,261 @@ +"use client"; + +import { useState } from "react"; +import { motion } from "framer-motion"; +import { FaEye, FaTimes } from "react-icons/fa"; + +type Technology = { + name: string; + description: string; + logo?: string; +}; + +const technologies: Technology[] = [ + { name: "LangGraph", logo: "https://cdn.simpleicons.org/langgraph", description: "Stateful multi-agent graphs" }, + { name: "LangChain", logo: "https://cdn.simpleicons.org/langchain", description: "LLM application framework" }, + { name: "DeepAgents", description: "Deep agent runtime" }, + { name: "Claude Code", logo: "https://cdn.simpleicons.org/anthropic", description: "Anthropic coding agent" }, + { name: "OpenAI Codex", logo: "https://upload.wikimedia.org/wikipedia/commons/4/4d/OpenAI_Logo.svg", description: "OpenAI coding agent" }, + { name: "Hermes", description: "Open-weight LLM" }, + { name: "Pi", description: "Coding-agent runtime" }, + { name: "DSPy", description: "Declarative LM programming" }, + { name: "FastAPI", logo: "https://cdn.simpleicons.org/fastapi", description: "Python API framework" }, + { name: "Python", logo: "https://cdn.simpleicons.org/python", description: "Backend language" }, + { name: "TypeScript", logo: "https://cdn.simpleicons.org/typescript", description: "Typed JavaScript" }, + { name: "React", logo: "https://cdn.simpleicons.org/react", description: "UI library" }, + { name: "Next.js", logo: "https://cdn.simpleicons.org/nextdotjs", description: "React framework" }, + { name: "Tailwind CSS", logo: "https://cdn.simpleicons.org/tailwindcss", description: "Utility-first CSS" }, + { name: "MCP", logo: "https://cdn.simpleicons.org/modelcontextprotocol", description: "Model Context Protocol" }, + { name: "A2A", description: "Agent-to-Agent protocol" }, + { name: "PostgreSQL + pgvector", logo: "https://cdn.simpleicons.org/postgresql", description: "Vector-enabled SQL" }, + { name: "Redis", logo: "https://cdn.simpleicons.org/redis", description: "In-memory data store" }, + { name: "Playwright", logo: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/playwright/playwright-original.svg", description: "Browser automation" }, + { name: "Ollama", logo: "https://cdn.simpleicons.org/ollama", description: "Local model runtime" }, +]; + +const firstRowTechnologies = technologies.slice(0, 10); +const secondRowTechnologies = technologies.slice(10); + +// A single logo card: light surface (the one intentional light surface here, +// since most brand logos are dark) with a green-tinted initials fallback when +// no logo is provided or the remote logo 404s, plus a hover tooltip carrying +// the one-line description. The tech name is always rendered as visible text so +// information is never carried by the tooltip alone. +// +// The fallback is driven by a client `failed` flag rather than DOM mutation so +// it survives SSR: a logo that 404s during server render (before hydration) +// would otherwise paint a broken-image glyph because `onError` never fires on +// the server. The `ref` callback below catches an already-failed image on +// mount (`complete && naturalWidth === 0`) and `onError` catches future +// failures — either path degrades cleanly to the initials box. +const TechCard = ({ + tech, + duplicate = false, + fluid = false, + className = "", +}: { + tech: Technology; + duplicate?: boolean; + fluid?: boolean; + className?: string; +}) => { + const initials = tech.name.substring(0, 2).toUpperCase(); + const [failed, setFailed] = useState(false); + + return ( +
+
+
+ {tech.logo && !failed ? ( + <> + {/* eslint-disable-next-line @next/next/no-img-element */} + {`${tech.name} setFailed(true)} + ref={(node) => { + if (node && node.complete && node.naturalWidth === 0) { + setFailed(true); + } + }} + /> + + ) : ( +
+ {initials} +
+ )} +
+ + {tech.name} + +
+ {/* Tooltip (enhancement only — the name above is the source of truth) */} +
+ {tech.description} +
+
+ ); +}; + +// One scrolling carousel row. The rail is the row's techs duplicated so the +// CSS keyframes can translate exactly one set's width (-50%) for a seamless +// loop. Inter-card spacing is a per-card right margin (mr-4) rather than a +// flex gap, so the duplicated set is an exact 50% of the rail and -50% lands +// precisely on the seam (a flex gap would leave the loop half a gap short and +// jump every cycle). The duplicated half is aria-hidden and hidden under +// reduced motion, where the row collapses to a static wrapped layout (gap-y-4 +// restores the vertical rhythm the removed flex gap used to provide). Hover +// and the explicit Pause/Resume control both pause the animation. The row +// uses overflow-x-clip (not overflow-hidden) for the horizontal mask; the +// extra top padding gives the -top-9 tooltip room to render within the box. +const TechCarouselRow = ({ + technologies: rowTechnologies, + reverse = false, + paused = false, +}: { + technologies: Technology[]; + reverse?: boolean; + paused?: boolean; +}) => { + const rail = [...rowTechnologies, ...rowTechnologies]; + + return ( +
+
+ {rail.map((tech, index) => ( + = rowTechnologies.length} + className="mr-4" + /> + ))} +
+
+ ); +}; + +const TechnologyEcosystemSection = () => { + const [isTechnologyRailPaused, setIsTechnologyRailPaused] = useState(false); + const [showAllTech, setShowAllTech] = useState(false); + + return ( +
+
+ {/* Header */} + +

+ Technologies +

+

+ Our Technology Ecosystem +

+

+ From agent runtimes to production infrastructure, Mifune builds + across the modern AI engineering ecosystem. +

+
+ + {/* Panel */} + +
+ {!showAllTech && ( + + )} + +
+ + {showAllTech ? ( +
+ {technologies.map((tech, index) => ( + + ))} +
+ ) : ( +
+ + +
+ )} +
+
+
+ ); +}; + +export default TechnologyEcosystemSection; diff --git a/tailwind.config.ts b/tailwind.config.ts index 01acbcf..6bc1c8c 100644 --- a/tailwind.config.ts +++ b/tailwind.config.ts @@ -79,6 +79,9 @@ const config: Config = { "pulse-grow-shrink": "pulse-grow-shrink 2s infinite", "accordion-down": "accordion-down 0.2s ease-out", "accordion-up": "accordion-up 0.2s ease-out", + "tech-ecosystem-scroll": "tech-ecosystem-scroll 54s linear infinite", + "tech-ecosystem-scroll-reverse": + "tech-ecosystem-scroll-reverse 48s linear infinite", }, keyframes: { fadeIn: { @@ -97,6 +100,14 @@ const config: Config = { from: { height: "var(--radix-accordion-content-height)" }, to: { height: "0" }, }, + "tech-ecosystem-scroll": { + from: { transform: "translateX(0)" }, + to: { transform: "translateX(-50%)" }, + }, + "tech-ecosystem-scroll-reverse": { + from: { transform: "translateX(-50%)" }, + to: { transform: "translateX(0)" }, + }, }, transitionDelay: { "500": "500ms", From 80f9a1210e23db3e78f6c72466a7ebc94309bf2c Mon Sep 17 00:00:00 2001 From: ryaneggz Date: Fri, 19 Jun 2026 22:43:40 -0600 Subject: [PATCH 2/4] feat: use adaptive.biz technology icon set in ecosystem section Switch the technology list to the icons from adaptive.biz (the old site), per request: - Base = adaptive.biz "Our Technology Ecosystem" set (deduped) - Remove LangGraph, Make.com, Pinecone, Zapier - Replace Next.js -> Vercel; add Microsoft Teams, Zoho - Use browser-safe logo sources for Anthropic, AWS, LangChain (brandfetch / langchain.com block hotlinking); all 21 logos verified rendering on the light cards, initials fallback intact Co-Authored-By: Claude Opus 4.8 (1M context) --- public/sw.js | 2 +- src/sections/TechnologyEcosystemSection.tsx | 43 +++++++++++---------- 2 files changed, 23 insertions(+), 22 deletions(-) diff --git a/public/sw.js b/public/sw.js index caff655..1f75c75 100644 --- a/public/sw.js +++ b/public/sw.js @@ -1 +1 @@ -if(!self.define){let e,s={};const a=(a,n)=>(a=new URL(a+".js",n).href,s[a]||new Promise((s=>{if("document"in self){const e=document.createElement("script");e.src=a,e.onload=s,document.head.appendChild(e)}else e=a,importScripts(a),s()})).then((()=>{let e=s[a];if(!e)throw new Error(`Module ${a} didn’t register its module`);return e})));self.define=(n,t)=>{const i=e||("document"in self?document.currentScript.src:"")||location.href;if(s[i])return;let c={};const r=e=>a(e,i),d={module:{uri:i},exports:c,require:r};s[i]=Promise.all(n.map((e=>d[e]||r(e)))).then((e=>(t(...e),c)))}}define(["./workbox-c06b064f"],(function(e){"use strict";importScripts("/fallback-8e5b7798448a30a7.js"),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/static/C_GjIh2S1RbbtQABQ8ZBh/_buildManifest.js",revision:"3e2d62a10f4d6bf0b92e14aecf7836f4"},{url:"/_next/static/C_GjIh2S1RbbtQABQ8ZBh/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/_next/static/chunks/0dbeb660-b76dd34eb4ea8fd0.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/1096-070f2c4af6ff1a95.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/1396.1ccf2e49a70685e7.js",revision:"1ccf2e49a70685e7"},{url:"/_next/static/chunks/169.91746092641a81ae.js",revision:"91746092641a81ae"},{url:"/_next/static/chunks/1766.ca1028667f51c812.js",revision:"ca1028667f51c812"},{url:"/_next/static/chunks/1941.c94eabc784600153.js",revision:"c94eabc784600153"},{url:"/_next/static/chunks/2274.4d5b9b3f7dd91bf1.js",revision:"4d5b9b3f7dd91bf1"},{url:"/_next/static/chunks/231-deca7f6a78a61bbe.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/235.619031ab3b883a4c.js",revision:"619031ab3b883a4c"},{url:"/_next/static/chunks/2409-c325d016f0fd3075.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/2566.ff4fbb9d92501aba.js",revision:"ff4fbb9d92501aba"},{url:"/_next/static/chunks/2884-253d5fd11cce33b9.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/2889.5a548b41e09e5af8.js",revision:"5a548b41e09e5af8"},{url:"/_next/static/chunks/2cdb6380.bd4f57458181ed03.js",revision:"bd4f57458181ed03"},{url:"/_next/static/chunks/3234.32712ed297a98b5b.js",revision:"32712ed297a98b5b"},{url:"/_next/static/chunks/3321.a8f2ab5ab226c94d.js",revision:"a8f2ab5ab226c94d"},{url:"/_next/static/chunks/3570.5def040bfbfddb75.js",revision:"5def040bfbfddb75"},{url:"/_next/static/chunks/3764.be3713068ae0b8c3.js",revision:"be3713068ae0b8c3"},{url:"/_next/static/chunks/4208-8aa9b7e2ae8e3264.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/4583.2c80267207d6712b.js",revision:"2c80267207d6712b"},{url:"/_next/static/chunks/4866.b6bb0686c0d638e5.js",revision:"b6bb0686c0d638e5"},{url:"/_next/static/chunks/5042-50804081516c71bf.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/5190-b46161770304692e.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/5332.4350d6d296d61103.js",revision:"4350d6d296d61103"},{url:"/_next/static/chunks/53c13509-0d7f8ecc1d3cdb44.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/5810.81ec6045eb031643.js",revision:"81ec6045eb031643"},{url:"/_next/static/chunks/5877.094a29a371c68a8b.js",revision:"094a29a371c68a8b"},{url:"/_next/static/chunks/6129.99781c93bb1a5f1c.js",revision:"99781c93bb1a5f1c"},{url:"/_next/static/chunks/6177.9060afbc5ca6fc4e.js",revision:"9060afbc5ca6fc4e"},{url:"/_next/static/chunks/631.b3f7a82af86bfe6e.js",revision:"b3f7a82af86bfe6e"},{url:"/_next/static/chunks/6504.ac17212621239b87.js",revision:"ac17212621239b87"},{url:"/_next/static/chunks/6644.1aaaaa2ed16e82f4.js",revision:"1aaaaa2ed16e82f4"},{url:"/_next/static/chunks/6841.173217920e27cbb4.js",revision:"173217920e27cbb4"},{url:"/_next/static/chunks/6866.0daf2918ee969ac5.js",revision:"0daf2918ee969ac5"},{url:"/_next/static/chunks/6868.24f5c37c5aa9bdd1.js",revision:"24f5c37c5aa9bdd1"},{url:"/_next/static/chunks/6885.f7cf0bb6d0721914.js",revision:"f7cf0bb6d0721914"},{url:"/_next/static/chunks/6939.656342a877cb755f.js",revision:"656342a877cb755f"},{url:"/_next/static/chunks/7005.f9bbd0695f3d5f72.js",revision:"f9bbd0695f3d5f72"},{url:"/_next/static/chunks/7064.04862e2771650cd2.js",revision:"04862e2771650cd2"},{url:"/_next/static/chunks/7544.46aa6b1962665928.js",revision:"46aa6b1962665928"},{url:"/_next/static/chunks/7604.488d784a6f9f474e.js",revision:"488d784a6f9f474e"},{url:"/_next/static/chunks/795d4814-26980cfb0ce5b7d6.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/8090.644579c441122462.js",revision:"644579c441122462"},{url:"/_next/static/chunks/830.23eb3b4843bd3854.js",revision:"23eb3b4843bd3854"},{url:"/_next/static/chunks/8643.54a9c73cdba9280a.js",revision:"54a9c73cdba9280a"},{url:"/_next/static/chunks/8876.caf8bbc098330da7.js",revision:"caf8bbc098330da7"},{url:"/_next/static/chunks/8e1d74a4-0c312d1addb5f27c.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/90542734.2bd0a0a7451654b8.js",revision:"2bd0a0a7451654b8"},{url:"/_next/static/chunks/9183.8b669201afc4176c.js",revision:"8b669201afc4176c"},{url:"/_next/static/chunks/9472.640c45e761e124de.js",revision:"640c45e761e124de"},{url:"/_next/static/chunks/9492.5c74bb8f5ac9ef66.js",revision:"5c74bb8f5ac9ef66"},{url:"/_next/static/chunks/9822.39d6b3cfa93badd5.js",revision:"39d6b3cfa93badd5"},{url:"/_next/static/chunks/9861.98ed6ce5ac74aa66.js",revision:"98ed6ce5ac74aa66"},{url:"/_next/static/chunks/app/_not-found/page-54e3008a84d64074.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/blog/%5Bslug%5D/page-d36124fddbb1e1ef.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/blog/page-84e6e7105b53962d.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/case-studies/page-b01394112390fe86.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/layout-a1b2eb94e7884912.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/offline/page-1b69cf363bbaf8bc.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/page-37600ce25102b58f.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/pricing/page-d4b1cf3faaf84a58.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/services/layout-8e3eb591a1917a5a.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/services/page-47d6d58934a3208e.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/app/socials/page-4afd329d6270db39.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/d3ac728e.015cf0093df3cdc6.js",revision:"015cf0093df3cdc6"},{url:"/_next/static/chunks/ee560e2c-93d0c3fe3cadd807.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/fd9d1056-b848dae799369838.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/framework-08aa667e5202eed8.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/main-6eabcdc505217536.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/main-app-1e79748853859877.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/pages/_app-f870474a17b7f2fd.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/pages/_error-c66a4e8afc46f17b.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js",revision:"79330112775102f91e1010318bae2bd3"},{url:"/_next/static/chunks/webpack-f766f65bbfcbbef3.js",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/_next/static/css/0ed87202b54c3e18.css",revision:"0ed87202b54c3e18"},{url:"/_next/static/css/35228d8fbb2d2c09.css",revision:"35228d8fbb2d2c09"},{url:"/_next/static/media/1f173e5e25f3efee-s.woff2",revision:"f143fb4877cf7ada1b84423ee86a0198"},{url:"/_next/static/media/36966cca54120369-s.p.woff2",revision:"25ea4a783c12103f175f5b157b7d96aa"},{url:"/_next/static/media/48e2044251ef3125-s.woff2",revision:"45ea393f38e4ecd97f4dbeb12ef23877"},{url:"/_next/static/media/904be59b21bd51cb-s.p.woff2",revision:"c154477b9affa3a0a47f894c8b80c03c"},{url:"/_next/static/media/b1f344208eb4edfe-s.woff2",revision:"b5818778898bf6d34b7423ff99c6beb4"},{url:"/_next/static/media/b7387a63dd068245-s.woff2",revision:"dea099b7d5a5ea45bd4367f8aeff62ab"},{url:"/_next/static/media/bf24a9759715e608-s.woff2",revision:"d185d272afd4e2d7b4801eabba1463a1"},{url:"/_next/static/media/e1aab0933260df4d-s.woff2",revision:"207f8e9f3761dbd724063a177d906a99"},{url:"/fallback-8e5b7798448a30a7.js",revision:"a5281aa1504c5d6bcd7ba1097870376a"},{url:"/images/iphone-mock.png",revision:"c18b97249020ce36f6d017b46a0333da"},{url:"/images/logo-bg.png",revision:"1c6017df99acb611cc2df967ff3423ab"},{url:"/images/ruska_logo_200.png",revision:"e5f5e1527492c08d5b0ba18a2917734d"},{url:"/images/ryan-eggleston.png",revision:"78bcd693d2a6f2a62979322751fdf3bc"},{url:"/images/ryan_egg.png",revision:"c0293d621986355348b887dc5caa4448"},{url:"/llm.txt",revision:"b78aae937d81ea7f99c072e12d789bc0"},{url:"/manifest.json",revision:"634850c6e1d0c42c3353287176982fda"},{url:"/next.svg",revision:"8e061864f388b47f33a1c3780831193e"},{url:"/offline",revision:"C_GjIh2S1RbbtQABQ8ZBh"},{url:"/pe-logo.png",revision:"e798d97498601321e902e076a112848b"},{url:"/resume.pdf",revision:"d23871a0bd5ba764a57d127c998be4c4"},{url:"/swe-worker-4da67dda9bc18c53.js",revision:"5a47d90db13bb1309b25bdf7b363570e"},{url:"/vercel.svg",revision:"61c6b19abff40ea7acd577be818f3976"}],{ignoreURLParametersMatching:[/^utm_/,/^fbclid$/]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:async({response:e})=>e&&"opaqueredirect"===e.type?new Response(e.body,{status:200,statusText:"OK",headers:e.headers}):e},{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,new e.CacheFirst({cacheName:"google-fonts-webfonts",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:31536e3}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,new e.StaleWhileRevalidate({cacheName:"google-fonts-stylesheets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,new e.StaleWhileRevalidate({cacheName:"static-font-assets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,new e.StaleWhileRevalidate({cacheName:"static-image-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:2592e3}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\/_next\/static.+\.js$/i,new e.CacheFirst({cacheName:"next-static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\/_next\/image\?url=.+$/i,new e.StaleWhileRevalidate({cacheName:"next-image",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:mp3|wav|ogg)$/i,new e.CacheFirst({cacheName:"static-audio-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:mp4|webm)$/i,new e.CacheFirst({cacheName:"static-video-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:js)$/i,new e.StaleWhileRevalidate({cacheName:"static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:48,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:css|less)$/i,new e.StaleWhileRevalidate({cacheName:"static-style-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\/_next\/data\/.+\/.+\.json$/i,new e.StaleWhileRevalidate({cacheName:"next-data",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:json|xml|csv)$/i,new e.NetworkFirst({cacheName:"static-data-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({sameOrigin:e,url:{pathname:s}})=>!(!e||s.startsWith("/api/auth/callback")||!s.startsWith("/api/"))),new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({request:e,url:{pathname:s},sameOrigin:a})=>"1"===e.headers.get("RSC")&&"1"===e.headers.get("Next-Router-Prefetch")&&a&&!s.startsWith("/api/")),new e.NetworkFirst({cacheName:"pages-rsc-prefetch",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({request:e,url:{pathname:s},sameOrigin:a})=>"1"===e.headers.get("RSC")&&a&&!s.startsWith("/api/")),new e.NetworkFirst({cacheName:"pages-rsc",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({url:{pathname:e},sameOrigin:s})=>s&&!e.startsWith("/api/")),new e.NetworkFirst({cacheName:"pages",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({sameOrigin:e})=>!e),new e.NetworkFirst({cacheName:"cross-origin",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:3600}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),self.__WB_DISABLE_DEV_LOGS=!0})); +if(!self.define){let e,s={};const n=(n,a)=>(n=new URL(n+".js",a).href,s[n]||new Promise((s=>{if("document"in self){const e=document.createElement("script");e.src=n,e.onload=s,document.head.appendChild(e)}else e=n,importScripts(n),s()})).then((()=>{let e=s[n];if(!e)throw new Error(`Module ${n} didn’t register its module`);return e})));self.define=(a,t)=>{const i=e||("document"in self?document.currentScript.src:"")||location.href;if(s[i])return;let c={};const r=e=>n(e,i),d={module:{uri:i},exports:c,require:r};s[i]=Promise.all(a.map((e=>d[e]||r(e)))).then((e=>(t(...e),c)))}}define(["./workbox-c06b064f"],(function(e){"use strict";importScripts("/fallback-8e5b7798448a30a7.js"),self.skipWaiting(),e.clientsClaim(),e.precacheAndRoute([{url:"/_next/static/PzwQqSvndv_ykk5ftCrhZ/_buildManifest.js",revision:"3e2d62a10f4d6bf0b92e14aecf7836f4"},{url:"/_next/static/PzwQqSvndv_ykk5ftCrhZ/_ssgManifest.js",revision:"b6652df95db52feb4daf4eca35380933"},{url:"/_next/static/chunks/0dbeb660-b76dd34eb4ea8fd0.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/1096-070f2c4af6ff1a95.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/1396.1ccf2e49a70685e7.js",revision:"1ccf2e49a70685e7"},{url:"/_next/static/chunks/169.91746092641a81ae.js",revision:"91746092641a81ae"},{url:"/_next/static/chunks/1766.ca1028667f51c812.js",revision:"ca1028667f51c812"},{url:"/_next/static/chunks/1941.c94eabc784600153.js",revision:"c94eabc784600153"},{url:"/_next/static/chunks/2274.4d5b9b3f7dd91bf1.js",revision:"4d5b9b3f7dd91bf1"},{url:"/_next/static/chunks/231-deca7f6a78a61bbe.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/235.619031ab3b883a4c.js",revision:"619031ab3b883a4c"},{url:"/_next/static/chunks/2409-c325d016f0fd3075.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/2566.ff4fbb9d92501aba.js",revision:"ff4fbb9d92501aba"},{url:"/_next/static/chunks/2884-253d5fd11cce33b9.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/2889.5a548b41e09e5af8.js",revision:"5a548b41e09e5af8"},{url:"/_next/static/chunks/2cdb6380.bd4f57458181ed03.js",revision:"bd4f57458181ed03"},{url:"/_next/static/chunks/3234.32712ed297a98b5b.js",revision:"32712ed297a98b5b"},{url:"/_next/static/chunks/3321.a8f2ab5ab226c94d.js",revision:"a8f2ab5ab226c94d"},{url:"/_next/static/chunks/3570.5def040bfbfddb75.js",revision:"5def040bfbfddb75"},{url:"/_next/static/chunks/3764.be3713068ae0b8c3.js",revision:"be3713068ae0b8c3"},{url:"/_next/static/chunks/4208-8aa9b7e2ae8e3264.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/4583.2c80267207d6712b.js",revision:"2c80267207d6712b"},{url:"/_next/static/chunks/4866.b6bb0686c0d638e5.js",revision:"b6bb0686c0d638e5"},{url:"/_next/static/chunks/5042-50804081516c71bf.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/5190-b46161770304692e.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/5332.4350d6d296d61103.js",revision:"4350d6d296d61103"},{url:"/_next/static/chunks/53c13509-0d7f8ecc1d3cdb44.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/5810.81ec6045eb031643.js",revision:"81ec6045eb031643"},{url:"/_next/static/chunks/5877.094a29a371c68a8b.js",revision:"094a29a371c68a8b"},{url:"/_next/static/chunks/6129.99781c93bb1a5f1c.js",revision:"99781c93bb1a5f1c"},{url:"/_next/static/chunks/6177.9060afbc5ca6fc4e.js",revision:"9060afbc5ca6fc4e"},{url:"/_next/static/chunks/631.b3f7a82af86bfe6e.js",revision:"b3f7a82af86bfe6e"},{url:"/_next/static/chunks/6504.ac17212621239b87.js",revision:"ac17212621239b87"},{url:"/_next/static/chunks/6644.1aaaaa2ed16e82f4.js",revision:"1aaaaa2ed16e82f4"},{url:"/_next/static/chunks/6841.173217920e27cbb4.js",revision:"173217920e27cbb4"},{url:"/_next/static/chunks/6866.0daf2918ee969ac5.js",revision:"0daf2918ee969ac5"},{url:"/_next/static/chunks/6868.24f5c37c5aa9bdd1.js",revision:"24f5c37c5aa9bdd1"},{url:"/_next/static/chunks/6885.f7cf0bb6d0721914.js",revision:"f7cf0bb6d0721914"},{url:"/_next/static/chunks/6939.656342a877cb755f.js",revision:"656342a877cb755f"},{url:"/_next/static/chunks/7005.f9bbd0695f3d5f72.js",revision:"f9bbd0695f3d5f72"},{url:"/_next/static/chunks/7064.04862e2771650cd2.js",revision:"04862e2771650cd2"},{url:"/_next/static/chunks/7544.46aa6b1962665928.js",revision:"46aa6b1962665928"},{url:"/_next/static/chunks/7604.488d784a6f9f474e.js",revision:"488d784a6f9f474e"},{url:"/_next/static/chunks/795d4814-26980cfb0ce5b7d6.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/8090.644579c441122462.js",revision:"644579c441122462"},{url:"/_next/static/chunks/830.23eb3b4843bd3854.js",revision:"23eb3b4843bd3854"},{url:"/_next/static/chunks/8643.54a9c73cdba9280a.js",revision:"54a9c73cdba9280a"},{url:"/_next/static/chunks/8876.caf8bbc098330da7.js",revision:"caf8bbc098330da7"},{url:"/_next/static/chunks/8e1d74a4-0c312d1addb5f27c.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/90542734.2bd0a0a7451654b8.js",revision:"2bd0a0a7451654b8"},{url:"/_next/static/chunks/9183.8b669201afc4176c.js",revision:"8b669201afc4176c"},{url:"/_next/static/chunks/9472.640c45e761e124de.js",revision:"640c45e761e124de"},{url:"/_next/static/chunks/9492.5c74bb8f5ac9ef66.js",revision:"5c74bb8f5ac9ef66"},{url:"/_next/static/chunks/9822.39d6b3cfa93badd5.js",revision:"39d6b3cfa93badd5"},{url:"/_next/static/chunks/9861.98ed6ce5ac74aa66.js",revision:"98ed6ce5ac74aa66"},{url:"/_next/static/chunks/app/_not-found/page-54e3008a84d64074.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/app/blog/%5Bslug%5D/page-d36124fddbb1e1ef.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/app/blog/page-84e6e7105b53962d.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/app/case-studies/page-b01394112390fe86.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/app/layout-a1b2eb94e7884912.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/app/offline/page-1b69cf363bbaf8bc.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/app/page-de33a91446865a5e.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/app/pricing/page-d4b1cf3faaf84a58.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/app/services/layout-8e3eb591a1917a5a.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/app/services/page-47d6d58934a3208e.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/app/socials/page-4afd329d6270db39.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/d3ac728e.015cf0093df3cdc6.js",revision:"015cf0093df3cdc6"},{url:"/_next/static/chunks/ee560e2c-93d0c3fe3cadd807.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/fd9d1056-b848dae799369838.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/framework-08aa667e5202eed8.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/main-6eabcdc505217536.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/main-app-1e79748853859877.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/pages/_app-f870474a17b7f2fd.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/pages/_error-c66a4e8afc46f17b.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/chunks/polyfills-78c92fac7aa8fdd8.js",revision:"79330112775102f91e1010318bae2bd3"},{url:"/_next/static/chunks/webpack-f766f65bbfcbbef3.js",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/_next/static/css/0ed87202b54c3e18.css",revision:"0ed87202b54c3e18"},{url:"/_next/static/css/35228d8fbb2d2c09.css",revision:"35228d8fbb2d2c09"},{url:"/_next/static/media/1f173e5e25f3efee-s.woff2",revision:"f143fb4877cf7ada1b84423ee86a0198"},{url:"/_next/static/media/36966cca54120369-s.p.woff2",revision:"25ea4a783c12103f175f5b157b7d96aa"},{url:"/_next/static/media/48e2044251ef3125-s.woff2",revision:"45ea393f38e4ecd97f4dbeb12ef23877"},{url:"/_next/static/media/904be59b21bd51cb-s.p.woff2",revision:"c154477b9affa3a0a47f894c8b80c03c"},{url:"/_next/static/media/b1f344208eb4edfe-s.woff2",revision:"b5818778898bf6d34b7423ff99c6beb4"},{url:"/_next/static/media/b7387a63dd068245-s.woff2",revision:"dea099b7d5a5ea45bd4367f8aeff62ab"},{url:"/_next/static/media/bf24a9759715e608-s.woff2",revision:"d185d272afd4e2d7b4801eabba1463a1"},{url:"/_next/static/media/e1aab0933260df4d-s.woff2",revision:"207f8e9f3761dbd724063a177d906a99"},{url:"/fallback-8e5b7798448a30a7.js",revision:"a5281aa1504c5d6bcd7ba1097870376a"},{url:"/images/iphone-mock.png",revision:"c18b97249020ce36f6d017b46a0333da"},{url:"/images/logo-bg.png",revision:"1c6017df99acb611cc2df967ff3423ab"},{url:"/images/ruska_logo_200.png",revision:"e5f5e1527492c08d5b0ba18a2917734d"},{url:"/images/ryan-eggleston.png",revision:"78bcd693d2a6f2a62979322751fdf3bc"},{url:"/images/ryan_egg.png",revision:"c0293d621986355348b887dc5caa4448"},{url:"/llm.txt",revision:"b78aae937d81ea7f99c072e12d789bc0"},{url:"/manifest.json",revision:"634850c6e1d0c42c3353287176982fda"},{url:"/next.svg",revision:"8e061864f388b47f33a1c3780831193e"},{url:"/offline",revision:"PzwQqSvndv_ykk5ftCrhZ"},{url:"/pe-logo.png",revision:"e798d97498601321e902e076a112848b"},{url:"/resume.pdf",revision:"d23871a0bd5ba764a57d127c998be4c4"},{url:"/swe-worker-4da67dda9bc18c53.js",revision:"5a47d90db13bb1309b25bdf7b363570e"},{url:"/vercel.svg",revision:"61c6b19abff40ea7acd577be818f3976"}],{ignoreURLParametersMatching:[/^utm_/,/^fbclid$/]}),e.cleanupOutdatedCaches(),e.registerRoute("/",new e.NetworkFirst({cacheName:"start-url",plugins:[{cacheWillUpdate:async({response:e})=>e&&"opaqueredirect"===e.type?new Response(e.body,{status:200,statusText:"OK",headers:e.headers}):e},{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:gstatic)\.com\/.*/i,new e.CacheFirst({cacheName:"google-fonts-webfonts",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:31536e3}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/^https:\/\/fonts\.(?:googleapis)\.com\/.*/i,new e.StaleWhileRevalidate({cacheName:"google-fonts-stylesheets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:eot|otf|ttc|ttf|woff|woff2|font.css)$/i,new e.StaleWhileRevalidate({cacheName:"static-font-assets",plugins:[new e.ExpirationPlugin({maxEntries:4,maxAgeSeconds:604800}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:jpg|jpeg|gif|png|svg|ico|webp)$/i,new e.StaleWhileRevalidate({cacheName:"static-image-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:2592e3}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\/_next\/static.+\.js$/i,new e.CacheFirst({cacheName:"next-static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\/_next\/image\?url=.+$/i,new e.StaleWhileRevalidate({cacheName:"next-image",plugins:[new e.ExpirationPlugin({maxEntries:64,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:mp3|wav|ogg)$/i,new e.CacheFirst({cacheName:"static-audio-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:mp4|webm)$/i,new e.CacheFirst({cacheName:"static-video-assets",plugins:[new e.RangeRequestsPlugin,new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:js)$/i,new e.StaleWhileRevalidate({cacheName:"static-js-assets",plugins:[new e.ExpirationPlugin({maxEntries:48,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:css|less)$/i,new e.StaleWhileRevalidate({cacheName:"static-style-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\/_next\/data\/.+\/.+\.json$/i,new e.StaleWhileRevalidate({cacheName:"next-data",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute(/\.(?:json|xml|csv)$/i,new e.NetworkFirst({cacheName:"static-data-assets",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({sameOrigin:e,url:{pathname:s}})=>!(!e||s.startsWith("/api/auth/callback")||!s.startsWith("/api/"))),new e.NetworkFirst({cacheName:"apis",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:16,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({request:e,url:{pathname:s},sameOrigin:n})=>"1"===e.headers.get("RSC")&&"1"===e.headers.get("Next-Router-Prefetch")&&n&&!s.startsWith("/api/")),new e.NetworkFirst({cacheName:"pages-rsc-prefetch",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({request:e,url:{pathname:s},sameOrigin:n})=>"1"===e.headers.get("RSC")&&n&&!s.startsWith("/api/")),new e.NetworkFirst({cacheName:"pages-rsc",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({url:{pathname:e},sameOrigin:s})=>s&&!e.startsWith("/api/")),new e.NetworkFirst({cacheName:"pages",plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:86400}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),e.registerRoute((({sameOrigin:e})=>!e),new e.NetworkFirst({cacheName:"cross-origin",networkTimeoutSeconds:10,plugins:[new e.ExpirationPlugin({maxEntries:32,maxAgeSeconds:3600}),{handlerDidError:async({request:e})=>"undefined"!=typeof self?self.fallback(e):Response.error()}]}),"GET"),self.__WB_DISABLE_DEV_LOGS=!0})); diff --git a/src/sections/TechnologyEcosystemSection.tsx b/src/sections/TechnologyEcosystemSection.tsx index baceccc..cad07a2 100644 --- a/src/sections/TechnologyEcosystemSection.tsx +++ b/src/sections/TechnologyEcosystemSection.tsx @@ -11,30 +11,31 @@ type Technology = { }; const technologies: Technology[] = [ - { name: "LangGraph", logo: "https://cdn.simpleicons.org/langgraph", description: "Stateful multi-agent graphs" }, + { name: "OpenAI", logo: "https://upload.wikimedia.org/wikipedia/commons/0/04/ChatGPT_logo.svg", description: "Advanced language models" }, + { name: "Anthropic", logo: "https://cdn.simpleicons.org/anthropic", description: "Constitutional AI assistant" }, + { name: "AWS", logo: "https://www.vectorlogo.zone/logos/amazon_aws/amazon_aws-icon.svg", description: "Cloud platform" }, + { name: "Docker", logo: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/docker/docker-original.svg", description: "Containerization" }, + { name: "Google Cloud", logo: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/googlecloud/googlecloud-original.svg", description: "AI/ML services" }, + { name: "Kubernetes", logo: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/kubernetes/kubernetes-plain.svg", description: "Orchestration" }, { name: "LangChain", logo: "https://cdn.simpleicons.org/langchain", description: "LLM application framework" }, - { name: "DeepAgents", description: "Deep agent runtime" }, - { name: "Claude Code", logo: "https://cdn.simpleicons.org/anthropic", description: "Anthropic coding agent" }, - { name: "OpenAI Codex", logo: "https://upload.wikimedia.org/wikipedia/commons/4/4d/OpenAI_Logo.svg", description: "OpenAI coding agent" }, - { name: "Hermes", description: "Open-weight LLM" }, - { name: "Pi", description: "Coding-agent runtime" }, - { name: "DSPy", description: "Declarative LM programming" }, - { name: "FastAPI", logo: "https://cdn.simpleicons.org/fastapi", description: "Python API framework" }, - { name: "Python", logo: "https://cdn.simpleicons.org/python", description: "Backend language" }, - { name: "TypeScript", logo: "https://cdn.simpleicons.org/typescript", description: "Typed JavaScript" }, - { name: "React", logo: "https://cdn.simpleicons.org/react", description: "UI library" }, - { name: "Next.js", logo: "https://cdn.simpleicons.org/nextdotjs", description: "React framework" }, - { name: "Tailwind CSS", logo: "https://cdn.simpleicons.org/tailwindcss", description: "Utility-first CSS" }, - { name: "MCP", logo: "https://cdn.simpleicons.org/modelcontextprotocol", description: "Model Context Protocol" }, - { name: "A2A", description: "Agent-to-Agent protocol" }, - { name: "PostgreSQL + pgvector", logo: "https://cdn.simpleicons.org/postgresql", description: "Vector-enabled SQL" }, - { name: "Redis", logo: "https://cdn.simpleicons.org/redis", description: "In-memory data store" }, - { name: "Playwright", logo: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/playwright/playwright-original.svg", description: "Browser automation" }, - { name: "Ollama", logo: "https://cdn.simpleicons.org/ollama", description: "Local model runtime" }, + { name: "Microsoft Azure", logo: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/azure/azure-original.svg", description: "Enterprise cloud" }, + { name: "MongoDB", logo: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/mongodb/mongodb-original.svg", description: "Document database" }, + { name: "Vercel", logo: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/vercel/vercel-original.svg", description: "Frontend cloud platform" }, + { name: "Node.js", logo: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/nodejs/nodejs-original.svg", description: "Server runtime" }, + { name: "PostgreSQL", logo: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/postgresql/postgresql-original.svg", description: "Relational database" }, + { name: "Python", logo: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/python/python-original.svg", description: "AI/ML backend" }, + { name: "React", logo: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/react/react-original.svg", description: "UI framework" }, + { name: "Slack", logo: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/slack/slack-original.svg", description: "Team integration" }, + { name: "Supabase", logo: "https://supabase.com/dashboard/img/supabase-logo.svg", description: "Postgres & vector storage" }, + { name: "Tailwind CSS", logo: "https://www.vectorlogo.zone/logos/tailwindcss/tailwindcss-icon.svg", description: "Utility-first CSS" }, + { name: "TypeScript", logo: "https://cdn.jsdelivr.net/gh/devicons/devicon/icons/typescript/typescript-original.svg", description: "Type-safe JavaScript" }, + { name: "Vite", logo: "https://vitejs.dev/logo.svg", description: "Next-gen frontend tooling" }, + { name: "Microsoft Teams", logo: "https://upload.wikimedia.org/wikipedia/commons/9/94/Microsoft_Office_Teams_%282019%E2%80%932025%29.svg", description: "Team collaboration" }, + { name: "Zoho", logo: "https://cdn.simpleicons.org/zoho", description: "Business apps suite" }, ]; -const firstRowTechnologies = technologies.slice(0, 10); -const secondRowTechnologies = technologies.slice(10); +const firstRowTechnologies = technologies.slice(0, 11); +const secondRowTechnologies = technologies.slice(11); // A single logo card: light surface (the one intentional light surface here, // since most brand logos are dark) with a green-tinted initials fallback when From 5a0bc9c004a3417c68b7ed01216a66dc05c6746e Mon Sep 17 00:00:00 2001 From: ryaneggz Date: Fri, 19 Jun 2026 23:10:21 -0600 Subject: [PATCH 3/4] fix: render Technology grid as two rows and add dark-mode parity MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit View All now renders exactly two static rows (11 + 10) in a single horizontal-scroll container — centered when they fit, scroll on narrow screens, never a third row — replacing the ragged lg:grid-cols-8 layout. Cards are now theme-aware: surface flips white -> elevated muted gray in dark mode, label uses text-foreground, and each logo sits on a constant white chip so near-black brand marks (OpenAI/Anthropic/Vercel/Zoho) stay legible on the dark card. Carousel, toggle, SSR fallback, and a11y are unchanged; the 21-tech list is untouched. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/sections/TechnologyEcosystemSection.tsx | 105 ++++++++++++-------- 1 file changed, 66 insertions(+), 39 deletions(-) diff --git a/src/sections/TechnologyEcosystemSection.tsx b/src/sections/TechnologyEcosystemSection.tsx index cad07a2..0ea1dd4 100644 --- a/src/sections/TechnologyEcosystemSection.tsx +++ b/src/sections/TechnologyEcosystemSection.tsx @@ -37,11 +37,12 @@ const technologies: Technology[] = [ const firstRowTechnologies = technologies.slice(0, 11); const secondRowTechnologies = technologies.slice(11); -// A single logo card: light surface (the one intentional light surface here, -// since most brand logos are dark) with a green-tinted initials fallback when -// no logo is provided or the remote logo 404s, plus a hover tooltip carrying -// the one-line description. The tech name is always rendered as visible text so -// information is never carried by the tooltip alone. +// A single logo card: theme-aware surface (white in light, an elevated muted +// gray in dark) with a constant white logo chip so near-black brand marks stay +// legible in both themes, a green-tinted initials fallback when no logo is +// provided or the remote logo 404s, and a hover tooltip carrying the one-line +// description. The tech name is always rendered as visible text so information +// is never carried by the tooltip alone. // // The fallback is driven by a client `failed` flag rather than DOM mutation so // it survives SSR: a logo that 404s during server render (before hydration) @@ -52,12 +53,12 @@ const secondRowTechnologies = technologies.slice(11); const TechCard = ({ tech, duplicate = false, - fluid = false, + compact = false, className = "", }: { tech: Technology; duplicate?: boolean; - fluid?: boolean; + compact?: boolean; className?: string; }) => { const initials = tech.name.substring(0, 2).toUpperCase(); @@ -67,8 +68,7 @@ const TechCard = ({
-
- {tech.logo && !failed ? ( - <> - {/* eslint-disable-next-line @next/next/no-img-element */} - {`${tech.name} setFailed(true)} - ref={(node) => { - if (node && node.complete && node.naturalWidth === 0) { - setFailed(true); - } - }} - /> - - ) : ( -
- {initials} -
- )} -
- + {tech.logo && !failed ? ( + // Constant white chip keeps near-black brand marks legible on the + // dark card surface; this tile never flips theme. +
+ {/* eslint-disable-next-line @next/next/no-img-element */} + {`${tech.name} setFailed(true)} + ref={(node) => { + if (node && node.complete && node.naturalWidth === 0) { + setFailed(true); + } + }} + /> +
+ ) : ( +
+ {initials} +
+ )} + {tech.name}
@@ -235,10 +241,31 @@ const TechnologyEcosystemSection = () => {
{showAllTech ? ( -
- {technologies.map((tech, index) => ( - - ))} + // Two static rows (11 + 10) inside a single horizontal-scroll + // container: centered when they fit the panel, left-anchored scroll + // on narrow screens. It never wraps to a third row. pt-10 gives the + // row-one tooltips room so the scroll box does not clip them. +
+
+
+ {firstRowTechnologies.map((tech, index) => ( + + ))} +
+
+ {secondRowTechnologies.map((tech, index) => ( + + ))} +
+
) : (
From b9bae7aaf754a7f8229a8f77a47091bf81ad7a54 Mon Sep 17 00:00:00 2001 From: ryaneggz Date: Fri, 19 Jun 2026 23:21:36 -0600 Subject: [PATCH 4/4] fix: simplify Technology section to a single two-row auto-slider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Drop the second "View All" grid mode and all toggle/pause controls so the section renders one thing — the two rows auto-sliding slowly in opposite directions, matching the adaptive.biz reference. Cards are tightened to a denser tile (w-24) for closer parity. Theme-aware styling (white logo chip, dark:bg-muted surface, text-foreground), the SSR fallback, hover-pause, reduced-motion fallback, and a11y all preserved; the 21-tech list is untouched. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/sections/TechnologyEcosystemSection.tsx | 116 +++----------------- 1 file changed, 16 insertions(+), 100 deletions(-) diff --git a/src/sections/TechnologyEcosystemSection.tsx b/src/sections/TechnologyEcosystemSection.tsx index 0ea1dd4..16dd6bc 100644 --- a/src/sections/TechnologyEcosystemSection.tsx +++ b/src/sections/TechnologyEcosystemSection.tsx @@ -2,7 +2,6 @@ import { useState } from "react"; import { motion } from "framer-motion"; -import { FaEye, FaTimes } from "react-icons/fa"; type Technology = { name: string; @@ -42,7 +41,8 @@ const secondRowTechnologies = technologies.slice(11); // legible in both themes, a green-tinted initials fallback when no logo is // provided or the remote logo 404s, and a hover tooltip carrying the one-line // description. The tech name is always rendered as visible text so information -// is never carried by the tooltip alone. +// is never carried by the tooltip alone. Tiles are kept small and dense so two +// rows of marks read as a quiet logo ticker rather than a heavy grid. // // The fallback is driven by a client `failed` flag rather than DOM mutation so // it survives SSR: a logo that 404s during server render (before hydration) @@ -53,12 +53,10 @@ const secondRowTechnologies = technologies.slice(11); const TechCard = ({ tech, duplicate = false, - compact = false, className = "", }: { tech: Technology; duplicate?: boolean; - compact?: boolean; className?: string; }) => { const initials = tech.name.substring(0, 2).toUpperCase(); @@ -75,16 +73,11 @@ const TechCard = ({ .filter(Boolean) .join(" ")} > -
+
{tech.logo && !failed ? ( // Constant white chip keeps near-black brand marks legible on the // dark card surface; this tile never flips theme. -
+
{/* eslint-disable-next-line @next/next/no-img-element */}
) : ( -
+
{initials}
)} - + {tech.name}
@@ -125,23 +113,21 @@ const TechCard = ({ // One scrolling carousel row. The rail is the row's techs duplicated so the // CSS keyframes can translate exactly one set's width (-50%) for a seamless -// loop. Inter-card spacing is a per-card right margin (mr-4) rather than a +// loop. Inter-card spacing is a per-card right margin (mr-3) rather than a // flex gap, so the duplicated set is an exact 50% of the rail and -50% lands // precisely on the seam (a flex gap would leave the loop half a gap short and // jump every cycle). The duplicated half is aria-hidden and hidden under // reduced motion, where the row collapses to a static wrapped layout (gap-y-4 -// restores the vertical rhythm the removed flex gap used to provide). Hover -// and the explicit Pause/Resume control both pause the animation. The row -// uses overflow-x-clip (not overflow-hidden) for the horizontal mask; the -// extra top padding gives the -top-9 tooltip room to render within the box. +// restores the vertical rhythm the removed flex gap used to provide). Hovering +// the rail pauses the animation. The row uses overflow-x-clip (not +// overflow-hidden) for the horizontal mask; the extra top padding gives the +// -top-9 tooltip room to render within the box. const TechCarouselRow = ({ technologies: rowTechnologies, reverse = false, - paused = false, }: { technologies: Technology[]; reverse?: boolean; - paused?: boolean; }) => { const rail = [...rowTechnologies, ...rowTechnologies]; @@ -152,14 +138,14 @@ const TechCarouselRow = ({ reverse ? "animate-tech-ecosystem-scroll-reverse" : "animate-tech-ecosystem-scroll" - } ${paused ? "[animation-play-state:paused]" : ""}`} + }`} > {rail.map((tech, index) => ( = rowTechnologies.length} - className="mr-4" + className="mr-3" /> ))}
@@ -168,9 +154,6 @@ const TechCarouselRow = ({ }; const TechnologyEcosystemSection = () => { - const [isTechnologyRailPaused, setIsTechnologyRailPaused] = useState(false); - const [showAllTech, setShowAllTech] = useState(false); - return (
{ transition={{ duration: 0.6, delay: 0.1 }} className="rounded-3xl border border-border bg-card p-6 md:p-8" > -
- {!showAllTech && ( - - )} - +
+ +
- - {showAllTech ? ( - // Two static rows (11 + 10) inside a single horizontal-scroll - // container: centered when they fit the panel, left-anchored scroll - // on narrow screens. It never wraps to a third row. pt-10 gives the - // row-one tooltips room so the scroll box does not clip them. -
-
-
- {firstRowTechnologies.map((tech, index) => ( - - ))} -
-
- {secondRowTechnologies.map((tech, index) => ( - - ))} -
-
-
- ) : ( -
- - -
- )}