diff --git a/src/components/Footer.css b/src/components/Footer.css
index 101202f..6cf2305 100644
--- a/src/components/Footer.css
+++ b/src/components/Footer.css
@@ -7,11 +7,6 @@
margin-top: auto;
}
-[data-theme="light"] .footer {
- background: #fff;
- border-top-color: rgba(0, 0, 0, 0.12);
-}
-
.footer-container {
max-width: 1280px;
margin: 0 auto;
@@ -34,10 +29,6 @@
margin: 0;
}
-[data-theme="light"] .footer-copyright {
- color: rgba(0, 0, 0, 0.75);
-}
-
.footer-social {
display: flex;
gap: 1rem;
@@ -56,11 +47,6 @@
transition: opacity 0.2s, transform 0.2s;
}
-[data-theme="light"] .footer-social-icon {
- background: rgba(0, 0, 0, 0.08);
- color: #1a1a1a;
-}
-
.footer-social-icon:hover {
opacity: 0.9;
transform: scale(1.05);
diff --git a/src/components/Header.css b/src/components/Header.css
index 88114b3..dc606ec 100644
--- a/src/components/Header.css
+++ b/src/components/Header.css
@@ -9,14 +9,10 @@
backdrop-filter: blur(10px);
}
-[data-theme="dark"] .header {
+.header {
background-color: rgba(0, 0, 0, 0.95);
}
-[data-theme="light"] .header {
- background-color: rgba(255, 255, 255, 0.95);
-}
-
.header-container {
max-width: 1280px;
margin: 0 auto;
@@ -108,80 +104,6 @@
color: #fff;
}
-.theme-toggle {
- position: relative;
-}
-
-.theme-toggle-btn {
- width: 42px;
- height: 42px;
- display: flex;
- align-items: center;
- justify-content: center;
- background: var(--bg-secondary);
- border: 2px solid #ff69b4;
- border-radius: 8px;
- cursor: pointer;
- font-size: 1.1rem;
- transition: all 0.2s ease;
-}
-
-.theme-toggle-btn:hover {
- background: linear-gradient(135deg, #ff69b4 0%, #ff1493 100%);
- border-color: #ff69b4;
- transform: scale(1.05);
-}
-
-.theme-dropdown {
- position: absolute;
- top: calc(100% + 8px);
- right: 0;
- background: var(--bg-secondary);
- border: 1px solid var(--border-color);
- border-radius: 10px;
- padding: 6px;
- display: flex;
- flex-direction: column;
- gap: 4px;
- opacity: 0;
- visibility: hidden;
- transform: translateY(-10px);
- transition: all 0.2s ease;
- min-width: 140px;
- box-shadow: 0 8px 24px rgba(0, 0, 0, 0.3);
- z-index: 100;
-}
-
-.theme-toggle:hover .theme-dropdown {
- opacity: 1;
- visibility: visible;
- transform: translateY(0);
-}
-
-.theme-option {
- display: flex;
- align-items: center;
- gap: 10px;
- padding: 10px 12px;
- border: none;
- background: transparent;
- border-radius: 8px;
- cursor: pointer;
- font-size: 0.85rem;
- color: var(--text-primary);
- transition: all 0.15s ease;
- text-align: left;
-}
-
-.theme-option:hover {
- background: var(--bg-tertiary);
-}
-
-.theme-option.active {
- background: linear-gradient(135deg, #ff69b4 0%, #ff1493 100%);
- color: white;
-}
-
@media (max-width: 768px) {
.header-container {
padding: 1rem;
diff --git a/src/components/Header.tsx b/src/components/Header.tsx
index 21a0261..ae2cf2a 100644
--- a/src/components/Header.tsx
+++ b/src/components/Header.tsx
@@ -1,4 +1,3 @@
-import { ThemeToggle } from './ThemeToggle'
import { APP_URL } from '../config'
import logo from '@/assets/logo.png'
import './Header.css'
@@ -16,9 +15,8 @@ function Header() {
diff --git a/src/components/ThemeToggle.tsx b/src/components/ThemeToggle.tsx
deleted file mode 100644
index d3d984b..0000000
--- a/src/components/ThemeToggle.tsx
+++ /dev/null
@@ -1,71 +0,0 @@
-import { useState, useEffect } from 'react'
-
-type Theme = 'light' | 'dark' | 'system'
-
-export function ThemeToggle() {
- const [theme, setTheme] = useState(() => {
- const saved = localStorage.getItem('theme') as Theme
- return saved || 'system'
- })
-
- useEffect(() => {
- const applyTheme = (selectedTheme: Theme) => {
- let effectiveTheme: 'light' | 'dark' = 'dark'
-
- if (selectedTheme === 'system') {
- effectiveTheme = window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark'
- } else {
- effectiveTheme = selectedTheme
- }
-
- document.documentElement.setAttribute('data-theme', effectiveTheme)
- localStorage.setItem('theme', selectedTheme)
- }
-
- applyTheme(theme)
-
- if (theme === 'system') {
- const mediaQuery = window.matchMedia('(prefers-color-scheme: light)')
- const handleChange = () => applyTheme('system')
- mediaQuery.addEventListener('change', handleChange)
- return () => mediaQuery.removeEventListener('change', handleChange)
- }
- }, [theme])
-
- return (
-
-
{
- const nextTheme = theme === 'light' ? 'system' : theme === 'system' ? 'dark' : 'light'
- setTheme(nextTheme)
- }}
- >
- {theme === 'light' ? '☀️' : theme === 'dark' ? '🌙' : '💻'}
-
-
- setTheme('light')}
- >
- ☀️
- Light
-
- setTheme('system')}
- >
- 💻
- System
-
- setTheme('dark')}
- >
- 🌙
- Dark
-
-
-
- )
-}
diff --git a/src/index.css b/src/index.css
index ea28456..7a65d85 100644
--- a/src/index.css
+++ b/src/index.css
@@ -19,28 +19,12 @@
--text-muted: #666666;
}
-[data-theme="dark"] {
+:root {
color-scheme: dark;
color: var(--text-primary);
background-color: var(--bg-primary);
}
-[data-theme="light"] {
- --bg-primary: #ffffff;
- --bg-secondary: #f5f5f5;
- --bg-tertiary: #eeeeee;
- --bg-card: #ffffff;
- --border-color: #dddddd;
- --border-light: #cccccc;
- --text-primary: #1a1a1a;
- --text-secondary: #666666;
- --text-muted: #888888;
-
- color-scheme: light;
- color: var(--text-primary);
- background-color: var(--bg-primary);
-}
-
* {
margin: 0;
padding: 0;
diff --git a/src/main.tsx b/src/main.tsx
index 8847f4a..87711af 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -4,6 +4,8 @@ import App from './App'
import favicon from '@/assets/logo.png'
import './index.css'
+document.documentElement.setAttribute('data-theme', 'dark')
+
let link = document.querySelector('link[rel="icon"]')
if (!link) {
link = document.createElement('link')
diff --git a/src/pages/Landing.css b/src/pages/Landing.css
index 9b7e597..a78c66c 100644
--- a/src/pages/Landing.css
+++ b/src/pages/Landing.css
@@ -1,534 +1,586 @@
-@import url('https://fonts.googleapis.com/css2?family=JetBrains+Mono:wght@400;600;700&display=swap');
+@import url('https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@400;500;700&family=JetBrains+Mono:wght@400;600;700&display=swap');
+
+:root {
+ --bg: #050505;
+ --surface: #121212;
+ --card: #1a1a1c;
+ --primary: #f72585;
+ --primary-hover: #d41f72;
+ --success: #22c55e;
+ --text: #ffffff;
+ --text-muted: #a1a1aa;
+ --border: #27272a;
+}
.landing {
- position: relative;
- min-height: calc(100vh - 74px);
- background: #000;
- margin: 0 -2rem -2rem -2rem;
+ margin: 0 -2rem -2rem;
+ background: radial-gradient(circle at 18% 10%, rgba(247, 37, 133, 0.2), transparent 35%),
+ radial-gradient(circle at 88% 18%, rgba(114, 9, 183, 0.18), transparent 34%),
+ var(--bg);
+ color: var(--text);
+ font-family: 'Space Grotesk', sans-serif;
}
-.landing-hero-section {
+.hero-section {
position: relative;
- min-height: 70vh;
- display: flex;
- align-items: center;
- justify-content: center;
overflow: hidden;
+ padding: 6rem 2rem 5rem;
+ border-bottom: 1px solid var(--border);
}
-[data-theme="light"] .landing {
- background: #ffffff;
+.hero-orbit {
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+ z-index: 0;
}
-.landing-orbit {
+.hero-orbit-guide {
position: absolute;
inset: 0;
- pointer-events: none;
+ width: min(88vw, 980px);
+ height: min(62vh, 520px);
+ margin: auto;
+ opacity: 0.22;
}
-/* Integrated with section */
-.landing-integrated-section {
- padding: 2.5rem 0;
- border-top: 1px solid rgba(255, 255, 255, 0.08);
- border-bottom: 1px solid rgba(255, 255, 255, 0.08);
- overflow: hidden;
+.hero-orbit-guide path {
+ fill: none;
+ stroke: rgba(247, 37, 133, 0.35);
+ stroke-width: 2.5;
+ stroke-linecap: round;
+ stroke-dasharray: 8 12;
}
-.landing-integrated-title {
+.hero-orbit-icon {
+ --token-color: #666;
+ --orbit-index: 0;
+ --orbit-total: 12;
+ position: absolute;
+ left: 50%;
+ top: 50%;
+ width: 34px;
+ height: 34px;
+ border-radius: 50%;
+ background: var(--token-color);
+ color: #fff;
+ display: flex;
+ align-items: center;
+ justify-content: center;
font-family: 'JetBrains Mono', monospace;
font-weight: 700;
- font-size: clamp(1.5rem, 4vw, 2.25rem);
- color: #fff;
- text-align: center;
- margin: 0 0 1.5rem 0;
+ font-size: 0.72rem;
+ box-shadow: 0 0 18px rgba(255, 255, 255, 0.12);
+ opacity: 0.78;
+ animation: orbit-infinity 62s linear infinite;
+ animation-delay: calc(var(--orbit-index) / var(--orbit-total) * -62s);
}
-[data-theme="light"] .landing-integrated-section {
- border-color: rgba(0, 0, 0, 0.1);
+.hero-orbit-icon span {
+ transform: translateY(0.5px);
}
-[data-theme="light"] .landing-integrated-title {
- color: #1a1a1a;
+@supports (offset-path: path('M 0,0')) {
+ .hero-orbit-icon {
+ offset-path: var(--orbit-path);
+ offset-anchor: 50% 50%;
+ offset-rotate: 0deg;
+ }
}
-.landing-integrated-marquee {
- overflow: hidden;
- mask-image: linear-gradient(to right, transparent, black 10%, black 90%, transparent);
- -webkit-mask-image: linear-gradient(to right, transparent, black 10%, black 90%, transparent);
+@supports not (offset-path: path('M 0,0')) {
+ .hero-orbit-icon {
+ animation: float-fallback 6s ease-in-out infinite;
+ }
}
-.landing-integrated-track {
- display: flex;
- gap: 3rem;
- width: max-content;
- padding: 0 1.5rem;
- animation: landing-integrated-scroll 30s linear infinite;
- will-change: transform;
+.hero-content {
+ max-width: 980px;
+ margin: 0 auto;
+ position: relative;
+ z-index: 2;
+ animation: reveal-up 0.7s ease-out;
}
-.landing-integrated-track:hover {
- animation-play-state: paused;
+.hero-title {
+ margin: 0;
+ font-size: clamp(2.9rem, 9vw, 6.2rem);
+ line-height: 1;
+ letter-spacing: 0.04em;
+ text-transform: uppercase;
+ text-shadow: 0 0 18px rgba(247, 37, 133, 0.35);
}
-@keyframes landing-integrated-scroll {
- 0% {
- transform: translateX(0);
- }
- 100% {
- transform: translateX(calc(-100% / 4));
- }
+.hero-subtitle {
+ margin: 0.9rem 0 0;
+ font-size: clamp(1.05rem, 2.2vw, 1.55rem);
+ color: rgba(255, 255, 255, 0.86);
}
-.landing-integrated-logo {
- display: flex;
- align-items: center;
- gap: 0.5rem;
- text-decoration: none;
- color: rgba(255, 255, 255, 0.9);
- flex-shrink: 0;
- transition: color 0.2s, opacity 0.2s;
+.hero-link-row {
+ margin: 1.2rem 0 0;
+ font-family: 'JetBrains Mono', monospace;
+ font-size: 0.96rem;
+ color: #f3f4f6;
}
-.landing-integrated-logo:hover {
- color: #fff;
- opacity: 1;
+.hero-link {
+ color: var(--primary);
+ text-decoration: none;
+ border-bottom: 1px dashed var(--primary);
+ transition: color 0.2s, border-color 0.2s;
}
-.landing-integrated-logo img {
- width: 40px;
- height: 40px;
- object-fit: contain;
+.hero-link:hover {
+ color: var(--primary-hover);
+ border-color: var(--primary-hover);
}
-.landing-integrated-logo .landing-integrated-logo-dark {
- display: block;
+.manifesto-section {
+ border-top: 1px solid var(--border);
+ border-bottom: 1px solid var(--border);
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0));
}
-.landing-integrated-logo .landing-integrated-logo-light {
- display: none;
+.manifesto-content {
+ max-width: 980px;
+ margin: 0 auto;
+ padding: 2.8rem 2rem;
}
-[data-theme="light"] .landing-integrated-logo .landing-integrated-logo-dark {
- display: none;
+.manifesto-content p {
+ margin: 0.35rem 0;
+ font-family: 'JetBrains Mono', monospace;
+ font-size: clamp(1rem, 1.6vw, 1.2rem);
+ color: #e4e4e7;
}
-[data-theme="light"] .landing-integrated-logo .landing-integrated-logo-light {
- display: block;
+.hero-emphasis {
+ color: var(--primary);
+ font-weight: 700;
+ text-shadow: 0 0 10px rgba(247, 37, 133, 0.45);
}
+.backtest-section {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 4rem 2rem 5rem;
+}
-.landing-integrated-name {
- font-family: 'JetBrains Mono', monospace;
- font-size: 1rem;
- font-weight: 600;
- white-space: nowrap;
+.section-heading h2 {
+ margin: 0;
+ font-size: clamp(1.8rem, 4vw, 2.6rem);
}
-.landing-integrated-logo[href*="uniswap"] .landing-integrated-name {
- color: #ff007a;
+.section-heading p {
+ margin: 0.8rem 0 0;
+ color: var(--text-muted);
+ font-size: 1.03rem;
}
-[data-theme="light"] .landing-integrated-logo {
- color: rgba(0, 0, 0, 0.85);
+.backtest-grid {
+ margin-top: 2rem;
+ display: grid;
+ grid-template-columns: minmax(280px, 360px) 1fr;
+ gap: 1.2rem;
}
-[data-theme="light"] .landing-integrated-logo:hover {
- color: #1a1a1a;
+.control-card,
+.chart-card {
+ border: 1px solid var(--border);
+ background: linear-gradient(160deg, rgba(255, 255, 255, 0.02), rgba(255, 255, 255, 0.01));
+ border-radius: 16px;
+ box-shadow: 0 12px 36px rgba(0, 0, 0, 0.28);
}
-/* Mint Pools section */
-.landing-mint-section {
- padding: 4rem 2rem;
- max-width: 1280px;
- margin: 0 auto;
+.control-card {
+ padding: 1.2rem;
+ display: flex;
+ flex-direction: column;
+ gap: 0.7rem;
}
-.landing-mint-title {
- font-family: 'JetBrains Mono', monospace;
- font-weight: 700;
- font-size: clamp(1.5rem, 3vw, 2rem);
- color: #fff;
- text-align: center;
- margin: 0 0 2.5rem 0;
+.control-card h3,
+.chart-card h3 {
+ margin: 0;
+ font-size: 1.1rem;
+ text-transform: uppercase;
+ letter-spacing: 0.05em;
+ color: #f3f4f6;
}
-[data-theme="light"] .landing-mint-title {
- color: #1a1a1a;
+.control-card label {
+ margin-top: 0.25rem;
+ font-size: 0.78rem;
+ color: var(--text-muted);
+ text-transform: uppercase;
+ letter-spacing: 0.08em;
}
-.landing-mint-card {
- background: #0a0a0a;
- border: 1px solid rgba(255, 255, 255, 0.12);
- border-radius: 16px;
- overflow: hidden;
+.control-card input {
+ width: 100%;
+ box-sizing: border-box;
+ border: 1px solid var(--border);
+ background: var(--surface);
+ color: var(--text);
+ border-radius: 10px;
+ padding: 0.72rem 0.85rem;
+ font-family: 'JetBrains Mono', monospace;
+ outline: none;
}
-.landing-mint-content {
- display: grid;
- grid-template-columns: calc(50% - 1rem) calc(50% - 1rem);
- gap: 2rem;
- min-height: 50vh;
- container-type: inline-size;
- container-name: mint-content;
+.control-card input:focus {
+ border-color: var(--primary);
}
-[data-theme="light"] .landing-mint-card {
- background: #fff;
- border-color: rgba(0, 0, 0, 0.12);
+input::-webkit-calendar-picker-indicator {
+ filter: invert(1);
+ opacity: 0.7;
+ cursor: pointer;
}
-.landing-mint-visual {
- position: relative;
- min-height: 320px;
- width: 100%;
- align-self: stretch;
+.result-box {
+ margin-top: 0.5rem;
+ border: 1px solid rgba(247, 37, 133, 0.4);
+ border-radius: 12px;
+ padding: 0.9rem;
+ background: linear-gradient(145deg, rgba(247, 37, 133, 0.15), rgba(247, 37, 133, 0.05));
}
-.landing-mint-visual img {
- position: absolute;
- inset: 0;
- width: 50cqi;
- max-width: 100%;
- height: 100%;
- left: 50%;
- transform: translateX(-50%);
- object-fit: cover;
- object-position: 15% center;
- display: block;
- opacity: 0;
- transition: opacity 0.4s ease;
- -webkit-mask-image: radial-gradient(ellipse 100% 100% at 50% 50%, black 88%, transparent 100%);
- mask-image: radial-gradient(ellipse 100% 100% at 50% 50%, black 88%, transparent 100%);
+.result-label {
+ margin: 0;
+ font-size: 0.8rem;
+ color: var(--text-muted);
}
-.landing-mint-visual img.active {
- opacity: 1;
+.result-value {
+ margin: 0.4rem 0 0;
+ font-size: 1.55rem;
+ font-weight: 700;
+ text-shadow: 0 0 14px rgba(247, 37, 133, 0.4);
}
+.result-meta {
+ margin: 0.35rem 0 0;
+ font-size: 0.85rem;
+ color: #f5f5f5;
+}
-.landing-mint-text-block {
- padding: 2.5rem;
- display: flex;
- flex-direction: column;
- justify-content: center;
- align-items: flex-start;
+.metric-list {
+ list-style: none;
+ padding: 0;
+ margin: 0.35rem 0 0;
+ border-top: 1px solid var(--border);
}
-.landing-mint-toggle-row {
+.metric-list li {
display: flex;
- align-items: center;
+ justify-content: space-between;
gap: 1rem;
- margin-bottom: 1.25rem;
+ font-size: 0.86rem;
+ padding: 0.75rem 0;
+ border-bottom: 1px solid var(--border);
}
-.landing-mint-toggle-group {
- display: flex;
- flex-direction: column;
- align-items: center;
- gap: 0.35rem;
+.metric-list span {
+ color: var(--text-muted);
}
-.landing-mint-toggle-label {
+.metric-list strong {
font-family: 'JetBrains Mono', monospace;
- font-size: 0.95rem;
- font-weight: 600;
- color: rgba(255, 255, 255, 0.5);
- text-transform: uppercase;
- letter-spacing: 0.05em;
}
-[data-theme="light"] .landing-mint-toggle-label {
- color: rgba(0, 0, 0, 0.5);
+.metric-list .positive {
+ color: var(--success);
}
-.landing-mint-toggle-or {
- font-family: 'JetBrains Mono', monospace;
- font-size: 0.85rem;
- font-weight: 600;
- color: rgba(255, 255, 255, 0.5);
- margin-top: 1.1rem;
+.metric-list .accent {
+ color: var(--primary);
}
-[data-theme="light"] .landing-mint-toggle-or {
- color: rgba(0, 0, 0, 0.5);
+.footnote {
+ margin: 0.2rem 0 0;
+ color: var(--text-muted);
+ font-size: 0.78rem;
+ line-height: 1.45;
}
-.landing-mint-toggle {
- display: flex;
- gap: 0;
- background: rgba(255, 255, 255, 0.08);
- border-radius: 10px;
- padding: 4px;
+.backtest-test-btn {
+ margin-top: 0.55rem;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-height: 52px;
+ min-width: 210px;
+ padding: 0.9rem 1.35rem;
+ border-radius: 12px;
+ border: 1px solid var(--primary);
+ background: rgba(247, 37, 133, 0.08);
+ color: var(--primary);
+ text-decoration: none;
+ font-weight: 700;
+ font-size: 0.98rem;
+ transition: background-color 0.2s, color 0.2s, transform 0.2s;
}
-.landing-mint-toggle-btn {
- font-family: 'JetBrains Mono', monospace;
- font-size: 0.9rem;
- font-weight: 600;
- padding: 0.5rem 1.25rem;
- text-transform: uppercase;
- border: none;
- border-radius: 8px;
- background: transparent;
- color: rgba(255, 255, 255, 0.6);
- cursor: pointer;
- transition: all 0.2s;
+.backtest-test-btn:hover {
+ background: var(--primary);
+ color: #fff;
+ transform: translateY(-1px);
}
-.landing-mint-toggle-btn:hover {
- color: rgba(255, 255, 255, 0.9);
+.chart-card {
+ padding: 1rem;
}
-.landing-mint-toggle-btn.active {
- background: linear-gradient(90deg, #ff69b4, #ff1493);
- color: #fff;
+.chart-header {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ gap: 1rem;
+ flex-wrap: wrap;
}
-[data-theme="light"] .landing-mint-toggle {
- background: rgba(0, 0, 0, 0.06);
+.legend {
+ display: flex;
+ gap: 1rem;
+ font-size: 0.82rem;
+ color: var(--text-muted);
}
-[data-theme="light"] .landing-mint-toggle-btn {
- color: rgba(0, 0, 0, 0.6);
+.legend span {
+ display: flex;
+ align-items: center;
+ gap: 0.35rem;
}
-[data-theme="light"] .landing-mint-toggle-btn:hover {
- color: rgba(0, 0, 0, 0.9);
+.legend-dot {
+ width: 9px;
+ height: 9px;
+ border-radius: 50%;
+ display: inline-block;
}
-.landing-mint-subtitle {
- font-family: 'JetBrains Mono', monospace;
- font-size: 1rem;
- font-weight: 600;
- color: #fff;
- margin: 0 0 1rem 0;
+.legend-dot.strategy {
+ background: var(--primary);
+ box-shadow: 0 0 8px rgba(247, 37, 133, 0.7);
}
-[data-theme="light"] .landing-mint-subtitle {
- color: #1a1a1a;
+.legend-dot.market {
+ background: #3b82f6;
}
-.landing-mint-text {
- font-family: 'JetBrains Mono', monospace;
- font-size: 0.9rem;
- line-height: 1.7;
- color: rgba(255, 255, 255, 0.85);
- margin: 0 0 1.5rem 0;
+.chart-wrapper {
+ margin-top: 0.8rem;
+ border-radius: 12px;
+ border: 1px solid var(--border);
+ background: var(--card);
+ padding: 0.75rem 0.75rem 0.45rem;
}
-[data-theme="light"] .landing-mint-text {
- color: rgba(0, 0, 0, 0.75);
+.chart-wrapper svg {
+ width: 100%;
+ height: 340px;
+ display: block;
}
-.landing-mint-btn {
- font-family: 'JetBrains Mono', monospace;
- font-weight: 700;
- font-size: 0.95rem;
- color: #fff;
- background: linear-gradient(90deg, #ff69b4, #ff1493);
- border: none;
- padding: 0.9rem 2rem;
- border-radius: 12px;
- cursor: pointer;
- align-self: flex-start;
- transition: transform 0.2s, box-shadow 0.2s;
- text-decoration: none;
- display: inline-block;
+.strategy-line {
+ fill: none;
+ stroke: var(--primary);
+ stroke-width: 4;
+ stroke-linecap: round;
+ stroke-linejoin: round;
}
-.landing-mint-btn:hover {
- transform: scale(1.03);
- box-shadow: 0 6px 24px rgba(255, 105, 180, 0.4);
- color: #fff;
+.market-line {
+ fill: none;
+ stroke: #3b82f6;
+ stroke-width: 3;
+ stroke-linecap: round;
+ stroke-linejoin: round;
+ stroke-dasharray: 12 9;
}
-@media (max-width: 900px) {
- .landing-mint-content {
- grid-template-columns: 1fr;
- }
-
- .landing-mint-visual {
- min-height: 240px;
- }
+.x-axis-labels {
+ margin-top: 0.1rem;
+ display: grid;
+ grid-template-columns: repeat(12, 1fr);
+ gap: 0.2rem;
+ font-size: 0.72rem;
+ color: var(--text-muted);
+ font-family: 'JetBrains Mono', monospace;
}
+.x-axis-labels span {
+ text-align: center;
+}
-.landing-orbit-icon {
- --token-color: #666;
- --orbit-index: 0;
- --orbit-total: 16;
- position: absolute;
- width: 42px;
- height: 42px;
- border-radius: 50%;
- background: var(--token-color);
- display: flex;
- align-items: center;
- justify-content: center;
- font-size: 0.75rem;
- font-weight: 700;
- color: #fff;
- left: 50%;
- top: 50%;
- opacity: 0.7;
- box-shadow: 0 0 20px rgba(255, 255, 255, 0.1);
- animation: orbit-infinity 80s linear infinite;
- animation-delay: calc(var(--orbit-index) / var(--orbit-total) * -80s);
+.chart-footer {
+ margin-top: 0.9rem;
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 0.8rem;
}
-@supports (offset-path: path("M 0,0")) {
- .landing-orbit-icon {
- offset-path: var(--orbit-path);
- offset-anchor: 50% 50%;
- offset-rotate: auto;
- }
+.chart-footer p {
+ margin: 0;
+ font-size: 0.75rem;
+ color: var(--text-muted);
}
-[data-theme="light"] .landing-orbit-icon {
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.12);
+.chart-footer strong {
+ margin-top: 0.2rem;
+ display: block;
+ font-family: 'JetBrains Mono', monospace;
+ font-size: 0.98rem;
}
-/* Smooth continuous motion - single linear sweep */
-@keyframes orbit-infinity {
- to {
- offset-distance: 100%;
- }
+.chart-footer .accent {
+ color: var(--primary);
}
-/* Fallback for browsers without offset-path - smooth continuous motion */
-@supports not (offset-path: path("M 0,0")) {
- @keyframes orbit-infinity {
- 0%, 100% { transform: translate(-50%, -50%) translate(46vw, 0); }
- 12.5% { transform: translate(-50%, -50%) translate(32vw, 18vh); }
- 25% { transform: translate(-50%, -50%) translate(0, 0); }
- 37.5% { transform: translate(-50%, -50%) translate(-32vw, -18vh); }
- 50% { transform: translate(-50%, -50%) translate(-46vw, 0); }
- 62.5% { transform: translate(-50%, -50%) translate(-32vw, 18vh); }
- 75% { transform: translate(-50%, -50%) translate(0, 0); }
- 87.5% { transform: translate(-50%, -50%) translate(32vw, -18vh); }
- }
+.chart-action-row {
+ margin-top: 0.85rem;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 0.6rem;
}
-.landing-orbit-icon-symbol {
+.chart-action-copy {
+ margin: 0;
+ text-align: center;
font-family: 'JetBrains Mono', monospace;
- font-size: 0.6rem;
+ font-size: 0.84rem;
+ color: rgba(255, 255, 255, 0.84);
+ max-width: 560px;
}
-.landing-hero-bg {
- position: absolute;
- inset: 0;
+.landing-bottom-cta {
display: flex;
+ flex-direction: column;
align-items: center;
justify-content: center;
- pointer-events: none;
+ padding: 0 2rem 4.75rem;
}
-.landing-hero-logo {
- width: min(40vw, 400px);
- height: auto;
- opacity: 0.12;
- object-fit: contain;
-}
-
-.landing-hero {
- position: relative;
- z-index: 2;
+.landing-bottom-copy {
+ margin: 0 0 1rem;
+ font-family: 'JetBrains Mono', monospace;
+ font-size: clamp(0.92rem, 1.8vw, 1.08rem);
+ color: #e4e4e7;
text-align: center;
- max-width: 720px;
- padding: 2rem;
}
-.landing-title {
- font-family: 'JetBrains Mono', monospace;
+.landing-invest-btn {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 220px;
+ height: 62px;
+ border-radius: 16px;
+ text-decoration: none;
+ font-size: 1rem;
font-weight: 700;
- font-size: clamp(2rem, 5vw, 3.5rem);
- line-height: 1.2;
+ letter-spacing: 0.04em;
color: #fff;
- margin: 0 0 1.5rem 0;
- display: flex;
- flex-direction: column;
- gap: 0.25rem;
+ background: linear-gradient(90deg, #f72585, #d41f72);
+ box-shadow: 0 10px 28px rgba(247, 37, 133, 0.34);
+ transition: transform 0.2s, box-shadow 0.2s;
}
-[data-theme="light"] .landing-title {
- color: #1a1a1a;
+.landing-invest-btn:hover {
+ transform: translateY(-2px);
+ box-shadow: 0 14px 30px rgba(247, 37, 133, 0.44);
}
-.landing-title span:first-child {
- color: #ff69b4;
+.landing-ai-note {
+ margin: 0.55rem 0 0;
+ font-family: 'JetBrains Mono', monospace;
+ font-size: 0.1rem;
+ line-height: 1;
+ color: rgba(0, 0, 0, 0.45);
+ letter-spacing: 0.04em;
}
-[data-theme="light"] .landing-title span:first-child {
- color: #ff1493;
+@keyframes reveal-up {
+ 0% {
+ opacity: 0;
+ transform: translateY(16px);
+ }
+ 100% {
+ opacity: 1;
+ transform: translateY(0);
+ }
}
-.landing-title span:last-child {
- font-size: 0.85em;
- font-weight: 600;
+@keyframes orbit-infinity {
+ to {
+ offset-distance: 100%;
+ }
}
-.landing-subtitle {
- font-family: 'JetBrains Mono', monospace;
- font-size: clamp(0.95rem, 2vw, 1.15rem);
- line-height: 1.7;
- color: rgba(255, 255, 255, 0.85);
- margin: 0 0 2rem 0;
+@keyframes float-fallback {
+ 0% {
+ transform: translate(-8px, 0);
+ }
+ 50% {
+ transform: translate(8px, -8px);
+ }
+ 100% {
+ transform: translate(-8px, 0);
+ }
}
-[data-theme="light"] .landing-subtitle {
- color: rgba(26, 26, 26, 0.8);
+@media (max-width: 1024px) {
+ .backtest-grid {
+ grid-template-columns: 1fr;
+ }
}
-.landing-cta {
- font-family: 'JetBrains Mono', monospace;
- font-weight: 700;
- font-size: 1rem;
- color: #fff;
- background: linear-gradient(90deg, #ff69b4, #ff1493);
- border: none;
- padding: 1rem 2.5rem;
- border-radius: 12px;
- cursor: pointer;
- transition: transform 0.2s, box-shadow 0.2s;
- text-decoration: none;
- display: inline-block;
-}
+@media (max-width: 768px) {
+ .landing {
+ margin: 0 -1rem -1rem;
+ }
-.landing-cta:hover {
- transform: scale(1.05);
- box-shadow: 0 8px 30px rgba(255, 105, 180, 0.5);
- color: #fff;
-}
+ .hero-section {
+ padding: 4.5rem 1rem 4rem;
+ }
-/* Spawned particle - flies from center via random path to button */
-.landing-particle {
- --mid-x: 0px;
- --mid-y: 0px;
- --end-x: 0px;
- --end-y: 0px;
- position: absolute;
- left: 50%;
- top: 50%;
- width: 12px;
- height: 12px;
- border-radius: 50%;
- background: linear-gradient(135deg, #ff69b4, #a78bfa);
- pointer-events: none;
- z-index: 5;
- animation: particle-fly 3s ease-in-out forwards;
-}
+ .hero-orbit-guide {
+ width: min(94vw, 760px);
+ height: min(44vh, 340px);
+ }
-@keyframes particle-fly {
- 0% {
- transform: translate(-50%, -50%) translate(0, 0) scale(1);
- opacity: 1;
+ .hero-orbit-icon {
+ width: 28px;
+ height: 28px;
+ font-size: 0.62rem;
}
- 40% {
- transform: translate(-50%, -50%) translate(var(--mid-x), var(--mid-y)) scale(0.9);
- opacity: 0.9;
+
+ .backtest-section {
+ padding: 3rem 1rem 4rem;
}
- 100% {
- transform: translate(-50%, -50%) translate(var(--end-x), var(--end-y)) scale(0.4);
- opacity: 0;
+
+ .manifesto-content {
+ padding: 2.3rem 1rem;
+ }
+
+ .chart-wrapper svg {
+ height: 260px;
+ }
+
+ .chart-footer {
+ grid-template-columns: 1fr;
+ }
+
+ .landing-bottom-cta {
+ padding: 0 1rem 3.5rem;
+ }
+
+ .landing-invest-btn {
+ width: 100%;
+ max-width: 320px;
}
}
diff --git a/src/pages/Landing.tsx b/src/pages/Landing.tsx
index b90ccfc..932d587 100644
--- a/src/pages/Landing.tsx
+++ b/src/pages/Landing.tsx
@@ -1,273 +1,318 @@
-import { useState, useRef, useEffect, useCallback } from 'react'
+import { useMemo, useState, type CSSProperties } from 'react'
import { APP_URL } from '../config'
-import logo from '@/assets/logo.png'
-import binanceLogo from '@/assets/binance-logo.png'
-import cowLogo from '@/assets/cow-logo.png'
-import logoLifiDark from '@/assets/logo_lifi_dark.svg'
-import logoLifiLight from '@/assets/logo_lifi_light.svg'
-import bullSell from '@/assets/bull-sell.png'
-import bullIllustration from '@/assets/bull-illustration.png'
import './Landing.css'
-/* Lemniscate path for even arc-length distribution (64 points) */
+const APY = 0.2
+const MARKET_APY = 0.08
+
+const LABELS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
+const STRATEGY_DATA = [100, 108, 106, 118, 122, 120, 130, 135, 132, 142, 145, 148.5]
+const MARKET_DATA = [100, 105, 98, 112, 110, 102, 115, 118, 112, 120, 115, 118.2]
+
const LEMNISCATE_PATH = (() => {
- const pts: string[] = []
- const scaleX = 520
- const scaleY = 500
+ const points: string[] = []
+ const scaleX = 420
+ const scaleY = 320
+
for (let i = 0; i <= 64; i++) {
const t = (2 * Math.PI * i) / 64
- const denom = 1 + Math.sin(t) ** 2
- const x = (Math.cos(t) / denom) * scaleX
- const y = (Math.sin(t) * Math.cos(t) / denom) * scaleY
- pts.push(`${x.toFixed(1)},${y.toFixed(1)}`)
+ const denominator = 1 + Math.sin(t) ** 2
+ const x = (Math.cos(t) / denominator) * scaleX
+ const y = (Math.sin(t) * Math.cos(t) / denominator) * scaleY
+ points.push(`${x.toFixed(1)},${y.toFixed(1)}`)
}
- return `M ${pts.join(' L ')} Z`
-})()
-const INTEGRATED_PARTNERS = [
- { id: 'ethereum', name: 'ETHEREUM', href: 'https://ethereum.org', img: 'https://assets.coingecko.com/coins/images/279/small/ethereum.png' },
- { id: 'arbitrum', name: 'ARBITRUM', href: 'https://arbitrum.io', img: 'https://assets.coingecko.com/coins/images/16547/small/photo_2023-03-29_21.47.00.jpeg' },
- { id: 'binance', name: 'BINANCE', href: 'https://binance.com', img: binanceLogo },
- { id: 'cow', name: 'COW PROTOCOL', href: 'https://cow.fi', img: cowLogo },
- { id: 'solana', name: 'SOLANA', href: 'https://solana.com', img: 'https://assets.coingecko.com/coins/images/4128/small/solana.png' },
- { id: 'lifi', name: 'LI.FI', href: 'https://li.fi', img: logoLifiDark, imgLight: logoLifiLight },
-]
+ return `M ${points.join(' L ')}`
+})()
const ORBIT_TOKENS = [
{ symbol: 'USDC', color: '#2775ca', label: '$' },
{ symbol: 'WETH', color: '#627eea', label: 'W' },
- { symbol: 'USDT', color: '#26a17b', label: '₮' },
+ { symbol: 'USDT', color: '#26a17b', label: 'T' },
{ symbol: 'UNI', color: '#ff007a', label: 'U' },
{ symbol: 'AAVE', color: '#2ebac6', label: 'A' },
{ symbol: 'DAI', color: '#f4b731', label: 'D' },
- { symbol: 'WBTC', color: '#f09242', label: '₿' },
+ { symbol: 'WBTC', color: '#f09242', label: 'B' },
{ symbol: 'LINK', color: '#2a5ada', label: 'L' },
{ symbol: 'CRV', color: '#40649f', label: 'C' },
{ symbol: 'MKR', color: '#1aab9b', label: 'M' },
{ symbol: 'SNX', color: '#00d1ff', label: 'S' },
- { symbol: 'SUSHI', color: '#fa52a0', label: 'H' },
- { symbol: 'COMP', color: '#00d395', label: 'C' },
- { symbol: 'ARB', color: '#28a0f0', label: 'A' },
{ symbol: 'OP', color: '#ff0420', label: 'O' },
]
-interface SpawnedParticle {
- id: number
- midX: number
- midY: number
- endX: number
- endY: number
+function formatCurrency(value: number): string {
+ return value.toLocaleString('en-US', {
+ style: 'currency',
+ currency: 'USD',
+ maximumFractionDigits: 2,
+ })
+}
+
+function formatPercent(value: number): string {
+ const sign = value >= 0 ? '+' : ''
+ return `${sign}${value.toFixed(2)}%`
+}
+
+function clamp(value: number, min: number, max: number): number {
+ return Math.min(Math.max(value, min), max)
+}
+
+function seriesToPath(values: number[], width: number, height: number, padding: number): string {
+ const min = Math.min(...values)
+ const max = Math.max(...values)
+ const range = Math.max(max - min, 1)
+ const innerWidth = width - padding * 2
+ const innerHeight = height - padding * 2
+
+ return values
+ .map((value, index) => {
+ const x = padding + (index / (values.length - 1)) * innerWidth
+ const y = padding + ((max - value) / range) * innerHeight
+ return `${index === 0 ? 'M' : 'L'} ${x.toFixed(1)} ${y.toFixed(1)}`
+ })
+ .join(' ')
}
export default function Landing() {
- const landingRef = useRef(null)
- const buttonRef = useRef(null)
- const [particles, setParticles] = useState([])
- const [mintMode, setMintMode] = useState<'buy' | 'sell'>('buy')
- const [activeToggle, setActiveToggle] = useState<0 | 1>(0)
- const nextIdRef = useRef(0)
-
- const spawnParticle = useCallback(() => {
- const landing = landingRef.current
- const button = buttonRef.current
- if (!landing || !button) return
-
- const landingRect = landing.getBoundingClientRect()
- const buttonRect = button.getBoundingClientRect()
-
- const centerX = landingRect.width / 2
- const centerY = landingRect.height / 2
- const buttonCenterX = buttonRect.left - landingRect.left + buttonRect.width / 2
- const buttonCenterY = buttonRect.top - landingRect.top + buttonRect.height / 2
- const endX = buttonCenterX - centerX
- const endY = buttonCenterY - centerY
-
- const midX = (Math.random() - 0.5) * 200
- const midY = (Math.random() - 0.5) * 200
-
- const id = nextIdRef.current++
- setParticles((prev) => [
- ...prev,
- { id, midX, midY, endX, endY },
- ])
- setTimeout(() => {
- setParticles((prev) => prev.filter((p) => p.id !== id))
- }, 3200)
- }, [])
-
- useEffect(() => {
- const initial = setTimeout(spawnParticle, 2000)
- const timer = setInterval(spawnParticle, 7000)
- return () => {
- clearTimeout(initial)
- clearInterval(timer)
+ const [investment, setInvestment] = useState(10000)
+ const [startDate, setStartDate] = useState('2025-01-01')
+ const [endDate, setEndDate] = useState('2025-12-31')
+
+ const {
+ years,
+ finalStrategy,
+ finalMarket,
+ strategyReturn,
+ marketReturn,
+ alpha,
+ } = useMemo(() => {
+ const start = new Date(startDate)
+ const end = new Date(endDate)
+ const amount = clamp(Number.isFinite(investment) ? investment : 0, 0, Number.MAX_SAFE_INTEGER)
+
+ if (Number.isNaN(start.getTime()) || Number.isNaN(end.getTime()) || end <= start) {
+ return {
+ years: 0,
+ finalStrategy: amount,
+ finalMarket: amount,
+ strategyReturn: 0,
+ marketReturn: 0,
+ alpha: 0,
+ }
}
- }, [spawnParticle])
+
+ const msPerYear = 1000 * 60 * 60 * 24 * 365.25
+ const elapsedYears = (end.getTime() - start.getTime()) / msPerYear
+
+ const strategyFinal = amount * (1 + APY) ** elapsedYears
+ const marketFinal = amount * (1 + MARKET_APY) ** elapsedYears
+
+ const strategyPct = amount > 0 ? ((strategyFinal - amount) / amount) * 100 : 0
+ const marketPct = amount > 0 ? ((marketFinal - amount) / amount) * 100 : 0
+
+ return {
+ years: elapsedYears,
+ finalStrategy: strategyFinal,
+ finalMarket: marketFinal,
+ strategyReturn: strategyPct,
+ marketReturn: marketPct,
+ alpha: strategyPct - marketPct,
+ }
+ }, [investment, startDate, endDate])
+
+ const chartWidth = 900
+ const chartHeight = 360
+ const chartPadding = 28
+
+ const strategyPath = useMemo(
+ () => seriesToPath(STRATEGY_DATA, chartWidth, chartHeight, chartPadding),
+ [chartWidth, chartHeight, chartPadding],
+ )
+ const marketPath = useMemo(
+ () => seriesToPath(MARKET_DATA, chartWidth, chartHeight, chartPadding),
+ [chartWidth, chartHeight, chartPadding],
+ )
return (
-
-
-
- {ORBIT_TOKENS.map((token, i) => (
-
- {token.label}
-
- ))}
-
-
-
-
-
-
-