From 9784a7ae45b324c43747c5bdae1833271cbdbe32 Mon Sep 17 00:00:00 2001 From: Shamik Karkhanis Date: Thu, 23 Apr 2026 16:01:40 -0400 Subject: [PATCH 1/2] experimenting --- index.html | 2 +- package-lock.json | 8 +-- package.json | 2 +- src/index.css | 7 +++ src/lander/Lander.module.css | 38 ++++++++++++++ src/lander/Lander.tsx | 51 ++++++++++++++----- .../sections/CapyRailSection.module.css | 43 ++++++++++++++++ src/lander/sections/ContactSection.module.css | 32 ++++++++++++ .../sections/FeaturesSection.module.css | 23 +++++++++ src/lander/sections/HeroSection.module.css | 27 ++++++++++ .../sections/InterfaceSection.module.css | 28 ++++++++++ src/shared/components/TopNav.module.css | 28 ++++++++++ 12 files changed, 270 insertions(+), 19 deletions(-) diff --git a/index.html b/index.html index b3b6103..2541be3 100644 --- a/index.html +++ b/index.html @@ -3,7 +3,7 @@ - + CAPY diff --git a/package-lock.json b/package-lock.json index 1ebc9e9..c119735 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,7 +32,7 @@ "jest": "^30.3.0", "jest-environment-jsdom": "^30.3.0", "lint-staged": "^16.4.0", - "prettier": "^3.8.1", + "prettier": "^3.8.3", "ts-jest": "^29.4.6", "typescript": "~5.9.3", "typescript-eslint": "^8.57.0", @@ -6902,9 +6902,9 @@ } }, "node_modules/prettier": { - "version": "3.8.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.1.tgz", - "integrity": "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==", + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.8.3.tgz", + "integrity": "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==", "dev": true, "license": "MIT", "bin": { diff --git a/package.json b/package.json index bda6422..6bbf2da 100644 --- a/package.json +++ b/package.json @@ -41,7 +41,7 @@ "jest": "^30.3.0", "jest-environment-jsdom": "^30.3.0", "lint-staged": "^16.4.0", - "prettier": "^3.8.1", + "prettier": "^3.8.3", "ts-jest": "^29.4.6", "typescript": "~5.9.3", "typescript-eslint": "^8.57.0", diff --git a/src/index.css b/src/index.css index 1bec510..7f8df20 100644 --- a/src/index.css +++ b/src/index.css @@ -17,6 +17,13 @@ body { overflow: hidden; } +@media (max-width: 768px) { + html, + body { + background: var(--c-bg); + } +} + body { font-family: var(--font-body); font-synthesis: none; diff --git a/src/lander/Lander.module.css b/src/lander/Lander.module.css index 99a9f8c..cb5690e 100644 --- a/src/lander/Lander.module.css +++ b/src/lander/Lander.module.css @@ -71,3 +71,41 @@ min-height: var(--lander-panel-height); border-radius: var(--radius-card); } + +.mobileSnapScroller { + display: none; +} + +@media (max-width: 768px) { + .appRoot { + overflow: hidden; + height: 100svh; + min-height: 100svh; + padding: 0; + } + + .mobileSnapScroller { + display: block; + width: 100%; + height: 100svh; + overflow-y: scroll; + overflow-x: hidden; + scroll-snap-type: y mandatory; + -webkit-overflow-scrolling: touch; + scrollbar-width: none; + } + + .mobileSnapScroller::-webkit-scrollbar { + display: none; + } + + :global(.panel) { + width: 100%; + height: 100svh; + min-height: 100svh; + border-radius: 0; + border: none; + scroll-snap-align: start; + scroll-snap-stop: always; + } +} diff --git a/src/lander/Lander.tsx b/src/lander/Lander.tsx index fe2fcc1..b1f5609 100644 --- a/src/lander/Lander.tsx +++ b/src/lander/Lander.tsx @@ -1,4 +1,4 @@ -import { useRef } from 'react' +import { useEffect, useRef, useState } from 'react' import { motion } from 'framer-motion' import { TopNav } from '@/shared/components/TopNav' import { ExitOverlay } from '@/shared/components/ExitOverlay' @@ -12,6 +12,8 @@ import { InterfaceSection } from './sections/InterfaceSection' import { Helmet } from 'react-helmet-async' import styles from './Lander.module.css' +const MOBILE_QUERY = '(max-width: 768px)' + /** * The main Lander component. * Serves as the landing page for capy, featuring scrolling sections and product details. @@ -19,7 +21,19 @@ import styles from './Lander.module.css' */ function Lander() { const scrollerRef = useRef(null) - useHorizontalWheelScroll(scrollerRef, { endCutoffPx: 300 }) + const disabledRef = useRef(null) + const [isMobile, setIsMobile] = useState( + () => typeof window !== 'undefined' && window.matchMedia(MOBILE_QUERY).matches, + ) + + useEffect(() => { + const mq = window.matchMedia(MOBILE_QUERY) + const handler = (event: MediaQueryListEvent) => setIsMobile(event.matches) + mq.addEventListener('change', handler) + return () => mq.removeEventListener('change', handler) + }, []) + + useHorizontalWheelScroll(isMobile ? disabledRef : scrollerRef, { endCutoffPx: 300 }) usePageTransition() @@ -33,22 +47,33 @@ function Lander() { />
- - -
- + {isMobile ? ( +
- -
+
+ ) : ( + <> + +
+ + + + + + + +
+ + )}
diff --git a/src/lander/sections/CapyRailSection.module.css b/src/lander/sections/CapyRailSection.module.css index 87e2597..f1146a6 100644 --- a/src/lander/sections/CapyRailSection.module.css +++ b/src/lander/sections/CapyRailSection.module.css @@ -128,3 +128,46 @@ opacity: 0.28; } } + +@media (max-width: 768px) { + .capyRailPanel { + width: 100%; + height: 100svh; + border: none; + border-radius: 0; + background: var(--c-surface-light); + } + + .railContent { + width: calc(100% - var(--space-32)); + margin: var(--space-50) var(--space-16) var(--space-32); + height: calc(100svh - var(--space-50) - var(--space-32)); + } + + .railLinks { + margin-top: var(--space-24); + } + + .verticalMarkWrap { + display: block; + position: absolute; + top: 0; + bottom: 0; + left: auto; + right: 0; + width: 160px; + height: 100%; + opacity: 0.25; + pointer-events: none; + } + + .verticalMark { + position: absolute; + top: 50%; + left: 50%; + width: 100svh; + height: 160px; + transform: translate(-50%, -50%) rotate(-90deg); + transform-origin: center center; + } +} diff --git a/src/lander/sections/ContactSection.module.css b/src/lander/sections/ContactSection.module.css index 16395f2..c5f15a0 100644 --- a/src/lander/sections/ContactSection.module.css +++ b/src/lander/sections/ContactSection.module.css @@ -70,3 +70,35 @@ margin-top: 18px; } } + +@media (max-width: 768px) { + .contactPanel { + width: 100%; + height: 100svh; + padding: var(--space-50) var(--space-24) var(--space-32); + backdrop-filter: none; + } + + .contactPanel h2 { + font-size: clamp(36px, 9vw, 52px); + } + + .contactContent { + min-height: 100%; + gap: var(--space-16); + } + + .contactLead { + font-size: 22px; + margin-top: var(--space-16); + } + + .emailPill { + margin-top: var(--space-16); + width: 100%; + } + + .contactMeta { + margin-top: var(--space-16); + } +} diff --git a/src/lander/sections/FeaturesSection.module.css b/src/lander/sections/FeaturesSection.module.css index 8eafafe..8f61122 100644 --- a/src/lander/sections/FeaturesSection.module.css +++ b/src/lander/sections/FeaturesSection.module.css @@ -39,3 +39,26 @@ gap: var(--space-16); } } + +@media (max-width: 768px) { + .featuresPanel { + display: flex; + flex-direction: column; + width: 100%; + height: 100svh; + overflow-y: auto; + gap: var(--space-16); + padding: var(--space-50) var(--space-24) var(--space-32); + } + + .card-col1-row1, + .card-col2-row1, + .card-col2-row2, + .card-col1-row2-span2, + .card-col2-row3 { + grid-column: unset; + grid-row: unset; + min-height: 200px; + flex-shrink: 0; + } +} diff --git a/src/lander/sections/HeroSection.module.css b/src/lander/sections/HeroSection.module.css index 7bf118a..7595c09 100644 --- a/src/lander/sections/HeroSection.module.css +++ b/src/lander/sections/HeroSection.module.css @@ -144,3 +144,30 @@ line-height: 0.88; } } + +@media (max-width: 768px) { + .heroPanel { + width: 100%; + height: 100svh; + padding: var(--space-50) var(--space-24) var(--space-32); + justify-content: center; + backdrop-filter: none; + } + + .heroRowTitle h1 { + font-size: clamp(52px, 16vw, 80px); + } + + .heroDescription { + max-width: 100%; + } + + .heroRowBottom { + flex-direction: column; + align-items: flex-start; + } + + .heroCtas { + margin: var(--space-16) 0 0; + } +} diff --git a/src/lander/sections/InterfaceSection.module.css b/src/lander/sections/InterfaceSection.module.css index f5b0b6a..0480a95 100644 --- a/src/lander/sections/InterfaceSection.module.css +++ b/src/lander/sections/InterfaceSection.module.css @@ -56,3 +56,31 @@ text-align: left; } } + +@media (max-width: 768px) { + .interfacePanel { + width: 100%; + height: 100svh; + padding: var(--space-50) var(--space-24) var(--space-32); + } + + .interfacePanel h2 { + font-size: clamp(36px, 9vw, 52px); + } + + .interfaceContent { + min-height: 100%; + gap: var(--space-16); + } + + .interfaceSub { + font-size: 22px; + margin-top: var(--space-16); + } + + .interfaceFoot { + text-align: left; + align-self: start; + margin-top: var(--space-16); + } +} diff --git a/src/shared/components/TopNav.module.css b/src/shared/components/TopNav.module.css index 93771db..6f99a9a 100644 --- a/src/shared/components/TopNav.module.css +++ b/src/shared/components/TopNav.module.css @@ -134,3 +134,31 @@ font-size: 16px; } } + +@media (max-width: 768px) { + .topNav { + grid-template-columns: auto 1fr auto; + padding: 12px var(--space-16); + gap: var(--space-8); + } + + .brandLogo { + width: 96px; + } + + .navPill { + padding: 0 var(--space-8); + gap: var(--space-8); + min-height: 44px; + } + + .navPill a { + font-size: 14px; + padding: 0 10px; + min-height: 32px; + } + + .navActions { + gap: 8px; + } +} From f025581f321593a5b21789927d5928253eca5fc0 Mon Sep 17 00:00:00 2001 From: Shamik Karkhanis Date: Thu, 23 Apr 2026 18:56:40 -0400 Subject: [PATCH 2/2] scrolling, scaling, sleeping... --- index.html | 1 + src/index.css | 9 +++--- src/lander/Lander.module.css | 11 ++++---- src/lander/Lander.tsx | 2 -- .../sections/CapyRailSection.module.css | 10 +++++-- src/lander/sections/CapyRailSection.tsx | 17 +++++++++++ src/lander/sections/ContactSection.module.css | 5 ++-- .../sections/FeaturesSection.module.css | 17 +++++++---- src/lander/sections/HeroSection.module.css | 28 +++++++++++++++++-- src/lander/sections/HeroSection.tsx | 4 ++- .../sections/InterfaceSection.module.css | 5 ++-- src/shared/components/GlassCard.module.css | 7 +++++ src/shared/components/TopNav.module.css | 2 +- 13 files changed, 88 insertions(+), 30 deletions(-) diff --git a/index.html b/index.html index 2541be3..96b7b8a 100644 --- a/index.html +++ b/index.html @@ -4,6 +4,7 @@ + CAPY diff --git a/src/index.css b/src/index.css index 7f8df20..10a21e1 100644 --- a/src/index.css +++ b/src/index.css @@ -15,13 +15,12 @@ body, html, body { overflow: hidden; + background: var(--c-bg); + transition: background-color 200ms ease; } -@media (max-width: 768px) { - html, - body { - background: var(--c-bg); - } +body.rail-active { + background: var(--c-surface-light); } body { diff --git a/src/lander/Lander.module.css b/src/lander/Lander.module.css index cb5690e..d76c6a3 100644 --- a/src/lander/Lander.module.css +++ b/src/lander/Lander.module.css @@ -79,15 +79,16 @@ @media (max-width: 768px) { .appRoot { overflow: hidden; - height: 100svh; - min-height: 100svh; + height: 100dvh; + min-height: 100dvh; padding: 0; + background: var(--c-bg); } .mobileSnapScroller { display: block; width: 100%; - height: 100svh; + height: 100dvh; overflow-y: scroll; overflow-x: hidden; scroll-snap-type: y mandatory; @@ -101,8 +102,8 @@ :global(.panel) { width: 100%; - height: 100svh; - min-height: 100svh; + height: 100dvh; + min-height: 100dvh; border-radius: 0; border: none; scroll-snap-align: start; diff --git a/src/lander/Lander.tsx b/src/lander/Lander.tsx index b1f5609..951bc6c 100644 --- a/src/lander/Lander.tsx +++ b/src/lander/Lander.tsx @@ -51,8 +51,6 @@ function Lander() {
- -
) : ( diff --git a/src/lander/sections/CapyRailSection.module.css b/src/lander/sections/CapyRailSection.module.css index f1146a6..635c0a0 100644 --- a/src/lander/sections/CapyRailSection.module.css +++ b/src/lander/sections/CapyRailSection.module.css @@ -132,7 +132,7 @@ @media (max-width: 768px) { .capyRailPanel { width: 100%; - height: 100svh; + height: 100dvh; border: none; border-radius: 0; background: var(--c-surface-light); @@ -140,8 +140,12 @@ .railContent { width: calc(100% - var(--space-32)); - margin: var(--space-50) var(--space-16) var(--space-32); - height: calc(100svh - var(--space-50) - var(--space-32)); + margin: calc(var(--space-50) + env(safe-area-inset-top)) var(--space-16) + calc(var(--space-32) + env(safe-area-inset-bottom)); + height: calc( + 100dvh - var(--space-50) - var(--space-32) - env(safe-area-inset-top) - + env(safe-area-inset-bottom) + ); } .railLinks { diff --git a/src/lander/sections/CapyRailSection.tsx b/src/lander/sections/CapyRailSection.tsx index 107818d..0699702 100644 --- a/src/lander/sections/CapyRailSection.tsx +++ b/src/lander/sections/CapyRailSection.tsx @@ -1,3 +1,4 @@ +import { useEffect } from 'react' import { AnimatedPanel } from '@/shared/components/AnimatedPanel' import { AspectImage } from '@/shared/components/AspectImage' import { StaggerWords } from '@/shared/components/StaggerWords' @@ -15,6 +16,22 @@ const socialAssets = [ ] export function CapyRailSection() { + useEffect(() => { + const el = document.getElementById('more') + if (!el) return + const observer = new IntersectionObserver( + ([entry]) => { + document.body.classList.toggle('rail-active', entry.intersectionRatio >= 0.85) + }, + { threshold: [0, 0.85, 1] }, + ) + observer.observe(el) + return () => { + observer.disconnect() + document.body.classList.remove('rail-active') + } + }, []) + return (