Files
doc_ai_frontend/docs/superpowers/plans/2026-03-26-landing-refactor.md

1524 lines
54 KiB
Markdown
Raw Normal View History

# Landing Page Refactor Implementation Plan
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
**Goal:** Replace all marketing home components with the UI from `texpixel-landing.html`, preserving exact visual fidelity while integrating with React Router, AuthContext, and existing app infrastructure.
**Architecture:** Extract the reference HTML's `<style>` block into a scoped `landing.css` (imported only in `MarketingLayout`), convert each HTML section into a focused React component, and convert the reference's `<script>` behaviors into `useEffect` hooks and a shared `useScrollReveal` hook.
**Tech Stack:** React 18, TypeScript, React Router v6, Tailwind CSS (workspace only), custom CSS (marketing only), `useAuth` / `useLanguage` contexts.
**Spec:** `docs/superpowers/specs/2026-03-26-landing-refactor-design.md`
**Reference:** `texpixel-landing.html` (lines 10-1593 = CSS, lines 1602-2183 = HTML, lines 2185-2289 = JS)
---
## File Map
### Create
- `src/styles/landing.css` — all marketing CSS, scoped under `.marketing-page`
- `src/hooks/useScrollReveal.ts` — IntersectionObserver for `.reveal` elements
- `src/components/home/ProductSuiteSection.tsx``.product-suite` section
- `src/components/home/ShowcaseSection.tsx``.showcase` section
- `src/components/home/TestimonialsSection.tsx``.user-love` carousel section
- `src/components/home/DocsSeoSection.tsx``.docs-seo` section
### Modify
- `index.html` — add Lora + JetBrains Mono fonts
- `src/components/layout/MarketingLayout.tsx` — import CSS, add `.marketing-page` wrapper + glow blobs
- `src/components/layout/MarketingNavbar.tsx` — replace with reference nav design
- `src/components/layout/Footer.tsx` — replace with reference footer design
- `src/components/home/HeroSection.tsx` — replace with reference hero + typing effect
- `src/components/home/FeaturesSection.tsx` — replace with reference core features
- `src/components/home/PricingSection.tsx` — replace with reference pricing
- `src/pages/HomePage.tsx` — update section order, add new sections, add scroll reveal
- `src/lib/translations.ts` — remove dead `contact` key from `marketing.nav`
### Delete
- `src/components/home/HowItWorksSection.tsx`
- `src/components/home/ContactSection.tsx`
---
## Task 1: Add Fonts to index.html
**Files:**
- Modify: `index.html:15`
- [ ] **Step 1: Add Lora and JetBrains Mono to the Google Fonts link**
Replace the existing fonts line (line 15) in `index.html`:
```html
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@500;600;700;800&family=DM+Sans:ital,wght@0,400;0,500;0,600;1,400&display=swap" rel="stylesheet" />
```
With:
```html
<link href="https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@500;600;700;800&family=DM+Sans:ital,opsz,wght@0,9..40,300;0,9..40,400;0,9..40,500;0,9..40,600;1,9..40,300&family=Lora:ital,wght@0,400;0,600;0,700;1,400&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet" />
```
- [ ] **Step 2: Verify build still passes**
```bash
npm run typecheck
```
Expected: no errors
- [ ] **Step 3: Commit**
```bash
git add index.html
git commit -m "feat: add Lora and JetBrains Mono fonts for landing page"
```
---
## Task 2: Extract Landing CSS
**Files:**
- Create: `src/styles/landing.css`
- [ ] **Step 1: Create the styles directory and file**
```bash
mkdir -p src/styles
```
- [ ] **Step 2: Copy the CSS from the reference and apply scoping**
Copy lines 101593 from `texpixel-landing.html` (everything inside the `<style>` tag) into `src/styles/landing.css`.
Then apply these transformations to prevent workspace bleed:
| Original selector | Replace with |
|---|---|
| `body {` | `.marketing-page {` |
| `body::before {` | `.marketing-page::before {` |
| `html { scroll-behavior: smooth; }` | Remove this line (already in `index.css` via Tailwind base) |
| `section { position: relative; z-index: 1; }` | `.marketing-page section { position: relative; z-index: 1; }` |
| `nav {` | `.marketing-page nav {` |
| `footer {` (the footer padding rule) | `.marketing-page footer {` |
Leave `:root { ... }` untouched — the variable names (`--primary`, `--bg`, etc.) don't conflict with the workspace's variables (`--color-primary`, `--color-bg`).
All class-based selectors (`.hero`, `.btn`, `.product-card`, etc.) need no change — they are unique enough to not affect the workspace.
At the very end of the file, add the scroll reveal animation rule used by JS:
```css
.reveal {
opacity: 0;
transform: translateY(24px);
transition: opacity 0.55s ease, transform 0.55s ease;
}
.reveal.visible {
opacity: 1;
transform: translateY(0);
}
.reveal-delay-1 { transition-delay: 0.10s; }
.reveal-delay-2 { transition-delay: 0.20s; }
.reveal-delay-3 { transition-delay: 0.30s; }
```
- [ ] **Step 3: Verify the file exists**
```bash
ls src/styles/landing.css
```
Expected: file listed
- [ ] **Step 4: Commit**
```bash
git add src/styles/landing.css
git commit -m "feat: extract landing page CSS from reference HTML"
```
---
## Task 3: Update MarketingLayout
**Files:**
- Modify: `src/components/layout/MarketingLayout.tsx`
- [ ] **Step 1: Replace MarketingLayout.tsx**
```tsx
import { Outlet } from 'react-router-dom';
import MarketingNavbar from './MarketingNavbar';
import Footer from './Footer';
import '../../styles/landing.css';
export default function MarketingLayout() {
return (
<div className="marketing-page">
<div className="glow-blob glow-blob-1" />
<div className="glow-blob glow-blob-2" />
<div className="glow-blob glow-blob-3" />
<MarketingNavbar />
<main>
<Outlet />
</main>
<Footer />
</div>
);
}
```
- [ ] **Step 2: Verify typecheck passes**
```bash
npm run typecheck
```
Expected: no errors
- [ ] **Step 3: Commit**
```bash
git add src/components/layout/MarketingLayout.tsx
git commit -m "feat: wire landing.css into MarketingLayout with .marketing-page scope"
```
---
## Task 4: Create useScrollReveal Hook
**Files:**
- Create: `src/hooks/useScrollReveal.ts`
- [ ] **Step 1: Create hooks directory and hook file**
```typescript
// src/hooks/useScrollReveal.ts
import { useEffect } from 'react';
export function useScrollReveal() {
useEffect(() => {
const observer = new IntersectionObserver(
(entries) => {
entries.forEach((e) => {
if (e.isIntersecting) {
e.target.classList.add('visible');
observer.unobserve(e.target);
}
});
},
{ threshold: 0.12, rootMargin: '0px 0px -40px 0px' }
);
document.querySelectorAll('.reveal').forEach((el) => observer.observe(el));
return () => observer.disconnect();
}, []);
}
```
- [ ] **Step 2: Verify typecheck**
```bash
npm run typecheck
```
Expected: no errors
- [ ] **Step 3: Commit**
```bash
git add src/hooks/useScrollReveal.ts
git commit -m "feat: add useScrollReveal hook for intersection-based fade-in"
```
---
## Task 5: Replace MarketingNavbar
**Files:**
- Modify: `src/components/layout/MarketingNavbar.tsx`
The reference navbar has: sticky bar, SVG logo, nav links, lang switch, user avatar dropdown (auth-aware), CTA button.
- [ ] **Step 1: Replace MarketingNavbar.tsx**
```tsx
import { useState, useEffect, useRef } from 'react';
import { Link, useLocation } from 'react-router-dom';
import { useLanguage } from '../../contexts/LanguageContext';
import { useAuth } from '../../contexts/AuthContext';
export default function MarketingNavbar() {
const { language, setLanguage } = useLanguage();
const { user, signOut } = useAuth();
const location = useLocation();
const isHome = location.pathname === '/';
const [scrolled, setScrolled] = useState(false);
const [activeSection, setActiveSection] = useState('');
const [userMenuOpen, setUserMenuOpen] = useState(false);
const userMenuRef = useRef<HTMLDivElement>(null);
// Scroll: sticky style + active nav section
useEffect(() => {
const handleScroll = () => {
setScrolled(window.scrollY > 10);
if (!isHome) return;
let current = '';
document.querySelectorAll('section[id]').forEach((s) => {
if (window.scrollY >= (s as HTMLElement).offsetTop - 100) {
current = s.id;
}
});
setActiveSection(current);
};
window.addEventListener('scroll', handleScroll, { passive: true });
return () => window.removeEventListener('scroll', handleScroll);
}, [isHome]);
// Close user menu on outside click
useEffect(() => {
const handle = (e: MouseEvent) => {
if (userMenuRef.current && !userMenuRef.current.contains(e.target as Node)) {
setUserMenuOpen(false);
}
};
document.addEventListener('mousedown', handle);
return () => document.removeEventListener('mousedown', handle);
}, []);
const navLinks = [
{ href: '/', label: language === 'zh' ? '首页' : 'Home', isRouter: true },
{ href: '/docs', label: language === 'zh' ? '文档' : 'Docs', isRouter: true },
{ href: '/blog', label: language === 'zh' ? '博客' : 'Blog', isRouter: true },
];
const anchorLinks = isHome
? [{ href: '#pricing', label: language === 'zh' ? '价格' : 'Pricing' }]
: [];
return (
<nav style={{ opacity: scrolled ? 1 : undefined }}>
<div className="nav-inner">
<Link to="/" className="nav-logo">
<div className="logo-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="white" strokeWidth="2">
<path d="M4 6h16M4 10h10M4 14h12M4 18h8" />
</svg>
</div>
<span style={{ fontFamily: "'Lora', serif" }}>TexPixel</span>
</Link>
<ul className="nav-links">
{navLinks.map((link) => (
<li key={link.href}>
<Link
to={link.href}
className={location.pathname === link.href ? 'active' : ''}
>
{link.label}
</Link>
</li>
))}
{anchorLinks.map((link) => (
<li key={link.href}>
<a
href={link.href}
className={activeSection === link.href.slice(1) ? 'active' : ''}
>
{link.label}
</a>
</li>
))}
</ul>
<div className="nav-right">
<button
className="lang-switch"
onClick={() => setLanguage(language === 'zh' ? 'en' : 'zh')}
>
{language === 'zh' ? 'EN' : '中文'}
</button>
{user ? (
<div className="nav-user" ref={userMenuRef} style={{ position: 'relative' }}>
<div
className="nav-avatar"
onClick={() => setUserMenuOpen((o) => !o)}
style={{ cursor: 'pointer' }}
>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8">
<circle cx="12" cy="8" r="4" />
<path d="M4 20c0-4 3.6-7 8-7s8 3 8 7" />
</svg>
</div>
{userMenuOpen && (
<div className="nav-user-menu" style={{ display: 'block' }}>
<div className="nav-menu-divider" />
<Link to="/app" className="nav-menu-item" onClick={() => setUserMenuOpen(false)}>
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8">
<rect x="2" y="3" width="20" height="14" rx="2" />
<path d="M8 21h8M12 17v4" />
</svg>
{language === 'zh' ? '启动应用' : 'Launch App'}
</Link>
<div className="nav-menu-divider" />
<button
className="nav-menu-item nav-menu-logout"
onClick={() => { signOut(); setUserMenuOpen(false); }}
style={{ background: 'none', border: 'none', width: '100%', textAlign: 'left', cursor: 'pointer' }}
>
{language === 'zh' ? '退出登录' : 'Sign Out'}
</button>
</div>
)}
</div>
) : (
<div className="nav-login-btn">
<Link to="/app" className="btn-cta" style={{ display: 'inline-block', lineHeight: '52px', padding: '0 24px', textDecoration: 'none' }}>
{language === 'zh' ? '免费试用' : 'Try Free'}
</Link>
</div>
)}
</div>
</div>
</nav>
);
}
```
- [ ] **Step 2: Verify typecheck**
```bash
npm run typecheck
```
Expected: no errors
- [ ] **Step 3: Commit**
```bash
git add src/components/layout/MarketingNavbar.tsx
git commit -m "feat: replace MarketingNavbar with reference design"
```
---
## Task 6: Replace HeroSection
**Files:**
- Modify: `src/components/home/HeroSection.tsx`
The hero has: left text column, right mock window with upload zone + typing LaTeX output.
- [ ] **Step 1: Replace HeroSection.tsx**
```tsx
import { useEffect, useRef } from 'react';
import { Link } from 'react-router-dom';
import { useLanguage } from '../../contexts/LanguageContext';
const LATEX_LINES = [
'<span class="code-kw">\\frac</span>{-b \\pm <span class="code-kw">\\sqrt</span>{b² - 4ac}}{2a}',
'<span class="code-kw">\\int</span>_0^1 x^2\\,dx',
'<span class="code-kw">\\sum</span>_{i=<span class="code-num">1</span>}^n \\frac{1}{i^2}',
];
export default function HeroSection() {
const { language } = useLanguage();
const codeRef = useRef<HTMLDivElement>(null);
// Typing cycling effect
useEffect(() => {
let idx = 0;
const interval = setInterval(() => {
idx = (idx + 1) % LATEX_LINES.length;
if (codeRef.current) {
codeRef.current.innerHTML = LATEX_LINES[idx] + '<span class="cursor-blink"></span>';
}
}, 3500);
return () => clearInterval(interval);
}, []);
return (
<section className="hero">
<div className="container">
<div className="hero-inner">
<div className="hero-left">
<h1 className="hero-title">
{language === 'zh' ? (
<>数学公式<br />秒级转换为<br /><em className="latex-word">LaTeX</em></>
) : (
<>Math Formulas<br />Converted to<br /><em className="latex-word">LaTeX</em></>
)}
</h1>
<p className="hero-desc">
{language === 'zh'
? 'AI 驱动的复杂数学公式识别,支持手写与论文截图,毫秒级输出 LaTeX、Markdown 与 Word 原生公式。'
: 'AI-powered recognition for complex math formulas. Supports handwriting and paper screenshots. Instant LaTeX, Markdown, and Word output.'}
</p>
<div className="hero-actions">
<Link to="/app" className="btn btn-primary">
<svg width="17" height="17" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2">
<path d="M5 3l14 9-14 9V3z" />
</svg>
{language === 'zh' ? '免费试用 TexPixel' : 'Try TexPixel Free'}
</Link>
<a href="#products" className="btn btn-secondary">
{language === 'zh' ? '了解更多 →' : 'Learn More →'}
</a>
</div>
<div className="hero-trust">
<div className="trust-item">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2">
<circle cx="12" cy="12" r="10" /><path d="M12 8v4l3 3" />
</svg>
{language === 'zh' ? '秒级输出' : 'Sub-second output'}
</div>
<div className="trust-item">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
<polyline points="14 2 14 8 20 8" />
</svg>
{language === 'zh' ? '支持 PDF · 手写 · 截图' : 'PDF · Handwriting · Screenshots'}
</div>
<div className="trust-item">
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.2">
<path d="M20 7H4a2 2 0 0 0-2 2v6a2 2 0 0 0 2 2h16a2 2 0 0 0 2-2V9a2 2 0 0 0-2-2z" />
<circle cx="12" cy="12" r="1" />
</svg>
{language === 'zh' ? '免费套餐可用' : 'Free plan available'}
</div>
</div>
</div>
<div className="hero-right">
<div className="mock-window">
<div className="window-topbar">
<div className="window-dots">
<div className="window-dot wd-red" />
<div className="window-dot wd-yellow" />
<div className="window-dot wd-green" />
</div>
<div className="window-url">
<svg className="url-lock" viewBox="0 0 12 14">
<rect x="1" y="6" width="10" height="7" rx="2" />
<path d="M3 6V4a3 3 0 0 1 6 0v2" fill="none" stroke="#8CC9BE" strokeWidth="1.4" />
</svg>
texpixel.com/app
</div>
</div>
<div className="window-body">
<div className="upload-zone">
<div className="upload-icon-wrap">
<svg viewBox="0 0 24 24">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4" />
<polyline points="17 8 12 3 7 8" />
<line x1="12" y1="3" x2="12" y2="15" />
</svg>
</div>
<div className="upload-text">
{language === 'zh' ? '点击、拖拽或粘贴文件开始解析' : 'Click, drag or paste a file to start'}
</div>
<div className="upload-sub">
{language === 'zh' ? '支持 PNG · JPG · PDF · 手写截图' : 'PNG · JPG · PDF · Handwriting'}
</div>
</div>
<div className="output-zone">
<div className="output-header">
<span className="output-label">LaTeX Output</span>
<span className="output-badge">{language === 'zh' ? '识别完成' : 'Done'}</span>
</div>
<div
className="output-code"
ref={codeRef}
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{
__html: LATEX_LINES[0] + '<span class="cursor-blink"></span>',
}}
/>
<div className="output-actions">
<button className="output-btn output-btn-copy">
{language === 'zh' ? '复制 LaTeX' : 'Copy LaTeX'}
</button>
<button className="output-btn output-btn-word">
{language === 'zh' ? '复制到 Word' : 'Copy to Word'}
</button>
</div>
</div>
<div className="window-status">
<div className="status-time">{language === 'zh' ? '识别耗时 0.38s' : 'Recognized in 0.38s'}</div>
<div className="status-format">
<div className="fmt-tag">LaTeX</div>
<div className="fmt-tag">Markdown</div>
<div className="fmt-tag">Word</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
);
}
```
- [ ] **Step 2: Verify typecheck**
```bash
npm run typecheck
```
Expected: no errors
- [ ] **Step 3: Commit**
```bash
git add src/components/home/HeroSection.tsx
git commit -m "feat: replace HeroSection with reference design + typing effect"
```
---
## Task 7: Create ProductSuiteSection
**Files:**
- Create: `src/components/home/ProductSuiteSection.tsx`
- [ ] **Step 1: Create ProductSuiteSection.tsx**
```tsx
import { Link } from 'react-router-dom';
import { useLanguage } from '../../contexts/LanguageContext';
export default function ProductSuiteSection() {
const { language } = useLanguage();
return (
<section className="product-suite" id="products">
<div className="container">
<div className="section-header reveal">
<div className="eyebrow">Product Matrix</div>
<h2 className="section-title">
{language === 'zh' ? '覆盖所有公式工作流' : 'Built for every formula workflow'}
</h2>
<p className="section-desc">
{language === 'zh'
? '从浏览器即取即用,到扩展一键复制,再到桌面端离线处理——一个工具,覆盖学生写作业、研究者整理文献、工程师记录推导的全部场景。'
: 'From instant browser use to one-click extension copy to offline desktop — one tool for students, researchers, and engineers.'}
</p>
</div>
<div className="cards-3">
<div className="product-card reveal reveal-delay-1">
<div className="card-icon icon-orange">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8">
<rect x="2" y="3" width="20" height="14" rx="2" />
<path d="M8 21h8M12 17v4" />
</svg>
</div>
<div className="card-title">Web App</div>
<div className="card-desc">
{language === 'zh'
? '浏览器内即时识别,无需安装。上传截图或手写图片,秒级输出 LaTeX。'
: 'Instant recognition in browser, no install needed. Upload screenshot or handwriting, get LaTeX in seconds.'}
</div>
<Link to="/app" className="card-link">
{language === 'zh' ? '浏览器即时识别 →' : 'Instant formula recognition in browser →'}
</Link>
</div>
<div className="product-card reveal reveal-delay-2">
<div className="card-icon icon-teal">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8">
<path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
<polyline points="14 2 14 8 20 8" />
<path d="M8 13h8M8 17h5" />
</svg>
</div>
<div className="card-title">Extension</div>
<div className="card-desc">
{language === 'zh'
? '浏览器扩展,一键将 ChatGPT、Claude 输出的公式复制为 Word 原生数学公式。'
: 'Browser extension — one-click copy of formulas from ChatGPT or Claude as native Word equations.'}
</div>
<a href="#" className="card-link">
{language === 'zh' ? '从 LLM 复制公式到 Word →' : 'Copy formulas from LLMs to Word →'}
</a>
</div>
<div className="product-card reveal reveal-delay-3">
<div className="card-icon icon-lavender">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8">
<rect x="2" y="3" width="20" height="14" rx="2" />
<path d="M2 8h20M8 3v5" />
</svg>
</div>
<div className="card-title">Desktop</div>
<div className="card-desc">
{language === 'zh'
? '桌面端离线处理,适合论文批量提取与隐私保护场景,一次购买终身使用。'
: 'Offline desktop app for batch PDF extraction and privacy-sensitive work. One-time purchase.'}
</div>
<a href="#pricing" className="card-link">
{language === 'zh' ? '查看桌面版定价 →' : 'See Desktop pricing →'}
</a>
</div>
</div>
</div>
</section>
);
}
```
- [ ] **Step 2: Verify typecheck**
```bash
npm run typecheck
```
Expected: no errors
- [ ] **Step 3: Commit**
```bash
git add src/components/home/ProductSuiteSection.tsx
git commit -m "feat: add ProductSuiteSection"
```
---
## Task 8: Replace FeaturesSection (Core Features)
**Files:**
- Modify: `src/components/home/FeaturesSection.tsx`
- [ ] **Step 1: Replace FeaturesSection.tsx**
```tsx
import { useLanguage } from '../../contexts/LanguageContext';
export default function FeaturesSection() {
const { language } = useLanguage();
return (
<section className="core-features">
<div className="container">
<div className="section-header reveal">
<div className="eyebrow">Core Features</div>
<h2 className="section-title">
{language === 'zh'
? '学生留下来的三个理由'
: 'Three reasons students stay with TexPixel'}
</h2>
</div>
<div className="cards-3">
<div className="feature-card reveal reveal-delay-1">
<div className="feature-mini">
<span className="feature-speed">⚡ t &lt; 1s</span>
</div>
<div className="card-title">{language === 'zh' ? '极速识别' : 'Sub-second Recognition'}</div>
<div className="card-desc">
{language === 'zh'
? '上传截图LaTeX 随即出现。拍下笔记,无需等待,直接复制。'
: 'Upload a screenshot, LaTeX appears instantly. Take a photo of your notes and copy right away.'}
</div>
</div>
<div className="feature-card reveal reveal-delay-2">
<div className="feature-mini" style={{ fontSize: '13px', color: 'var(--text-body)' }}>
<span style={{ fontFamily: "'JetBrains Mono', monospace", color: 'var(--primary)' }}>
\int_0^1 x^2 dx
</span>
</div>
<div className="card-title">{language === 'zh' ? '复杂公式支持' : 'Complex Formula Support'}</div>
<div className="card-desc">
{language === 'zh'
? '矩阵、积分、求和、化学式全部支持。多行公式对齐、角标嵌套一次识别。'
: 'Matrices, integrals, summations, chemical formulas — all supported. Multi-line alignment and nested scripts in one pass.'}
</div>
</div>
<div className="feature-card reveal reveal-delay-3">
<div className="feature-mini">
<span style={{ fontFamily: "'JetBrains Mono', monospace", color: 'var(--text-body)', fontSize: '13px' }}>
\mathbf{'{A}'}<sup style={{ fontSize: '9px', color: 'var(--teal)' }}>1</sup>b
</span>
</div>
<div className="card-title">{language === 'zh' ? '高准确度' : 'High Accuracy'}</div>
<div className="card-desc">
{language === 'zh'
? '论文级别识别准确率。在 arXiv 截图测试集上准确率超过 95%,持续迭代提升中。'
: 'Publication-grade accuracy. Over 95% on arXiv screenshot benchmarks, continuously improving.'}
</div>
</div>
</div>
</div>
</section>
);
}
```
- [ ] **Step 2: Verify typecheck**
```bash
npm run typecheck
```
- [ ] **Step 3: Commit**
```bash
git add src/components/home/FeaturesSection.tsx
git commit -m "feat: replace FeaturesSection with reference core features design"
```
---
## Task 9: Create ShowcaseSection
**Files:**
- Create: `src/components/home/ShowcaseSection.tsx`
- [ ] **Step 1: Create ShowcaseSection.tsx**
```tsx
import { Link } from 'react-router-dom';
import { useLanguage } from '../../contexts/LanguageContext';
export default function ShowcaseSection() {
const { language } = useLanguage();
return (
<section className="showcase">
<div className="container">
<div className="section-header reveal">
<div className="eyebrow">Live Examples</div>
<h2 className="section-title">
{language === 'zh' ? '真实案例演示' : 'Try Real Examples'}
</h2>
<p className="section-desc">
{language === 'zh'
? '看看 TexPixel 如何处理真实的论文截图与手写笔记。'
: 'See how TexPixel handles real paper screenshots and handwritten notes.'}
</p>
</div>
<div className="showcase-cards">
<div className="showcase-card reveal reveal-delay-1">
<div className="showcase-header">
<div className="showcase-tag">{language === 'zh' ? '复杂公式' : 'Complex Formula'}</div>
<div className="showcase-title">
{language === 'zh' ? '论文截图到可复制 LaTeX' : 'Paper Screenshot to Copyable LaTeX'}
</div>
<div className="showcase-sub">arXiv PDF · 0.41s</div>
</div>
<div className="showcase-body">
<div className="sc-input">
<span style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: '15px', opacity: 0.6 }}>
∑ ¹/ᵢ² · · · [{language === 'zh' ? '图片占位' : 'image placeholder'}]
</span>
</div>
<div className="sc-arrow">↓</div>
<div
className="sc-output"
dangerouslySetInnerHTML={{
__html: '<span class="kw">\\sum</span>_{i=<span class="num">1</span>}^{n}<span class="kw">\\frac</span>{<span class="num">1</span>}{i^<span class="num">2</span>}',
}}
/>
</div>
<div className="showcase-footer">
<Link to="/app" className="btn btn-secondary" style={{ height: '44px', fontSize: '14px', padding: '0 20px' }}>
{language === 'zh' ? '试试这个例子 →' : 'Try this example →'}
</Link>
</div>
</div>
<div className="showcase-card reveal reveal-delay-2">
<div className="showcase-header">
<div className="showcase-tag" style={{ background: 'rgba(140,201,190,0.15)', color: 'var(--teal)' }}>
{language === 'zh' ? '手写公式' : 'Handwritten Formula'}
</div>
<div className="showcase-title">
{language === 'zh' ? '课堂笔记到标准表达式' : 'Classroom Notes to Standard Expression'}
</div>
<div className="showcase-sub">{language === 'zh' ? '手机拍摄笔记 · 0.38s' : 'Phone photo of notes · 0.38s'}</div>
</div>
<div className="showcase-body">
<div className="sc-input">
<span style={{ fontFamily: "'JetBrains Mono', monospace", fontSize: '15px', opacity: 0.6 }}>
lim sin(x)/x [{language === 'zh' ? '手写' : 'handwritten'}]
</span>
</div>
<div className="sc-arrow">↓</div>
<div
className="sc-output"
dangerouslySetInnerHTML={{
__html: '<span class="kw">\\lim</span>_{x<span class="br">\\to</span> <span class="num">0</span>}<span class="kw">\\frac</span>{<span class="kw">\\sin</span> x}{x}',
}}
/>
</div>
<div className="showcase-footer">
<Link to="/app" className="btn btn-secondary" style={{ height: '44px', fontSize: '14px', padding: '0 20px' }}>
{language === 'zh' ? '试试这个例子 →' : 'Try this example →'}
</Link>
</div>
</div>
</div>
</div>
</section>
);
}
```
- [ ] **Step 2: Verify typecheck**
```bash
npm run typecheck
```
- [ ] **Step 3: Commit**
```bash
git add src/components/home/ShowcaseSection.tsx
git commit -m "feat: add ShowcaseSection with formula examples"
```
---
## Task 10: Create TestimonialsSection (Carousel)
**Files:**
- Create: `src/components/home/TestimonialsSection.tsx`
- [ ] **Step 1: Create TestimonialsSection.tsx**
6 testimonials, 3 visible at a time = 4 pages. Carousel uses CSS `transform: translateX` on a flex track.
```tsx
import { useState, useEffect, useCallback, useRef } from 'react';
import { useLanguage } from '../../contexts/LanguageContext';
const TESTIMONIALS = [
{
quote: '写论文的时候截图粘进去LaTeX 就出来了。以前每个公式都要手敲,现在一个截图解决,省了我大概 40% 的时间。',
name: '林同学',
role: '数学系研究生 · 北京大学',
avatarBg: 'var(--teal)',
avatarColor: '#1a5c54',
avatarLetter: '林',
stars: '★★★★★',
},
{
quote: '手写推导拍一张,马上就是干净的 LaTeX。对我这种每天要整理大量笔记的人来说真的是刚需级别的工具。',
name: '田晓雯',
role: '物理学博士候选人 · 清华大学',
avatarBg: 'var(--lavender)',
avatarColor: '#3d3870',
avatarLetter: '田',
stars: '★★★★★',
},
{
quote: "I use it every day for my thesis. The accuracy on complex integrals and matrix expressions is surprisingly good — way better than anything I've tried before.",
name: 'Sarah M.',
role: 'Applied Math PhD · MIT',
avatarBg: 'var(--rose)',
avatarColor: '#7a2e1e',
avatarLetter: 'S',
stars: '★★★★★',
},
{
quote: 'Desktop 版的离线功能对我来说很重要,论文数据不想上传到云端。买断价格也合理,不用每个月担心订阅。',
name: '陈博士',
role: '生物信息学研究员 · 中科院',
avatarBg: 'var(--gold)',
avatarColor: '#6f5800',
avatarLetter: '陈',
stars: '★★★★★',
},
{
quote: 'The browser extension is a game changer. I copy equations from Claude or ChatGPT straight into Word as native math — no more reformatting nightmares.',
name: 'Alex K.',
role: 'Engineering Student · TU Berlin',
avatarBg: '#8CB4C9',
avatarColor: '#1a3d52',
avatarLetter: 'A',
stars: '★★★★★',
},
{
quote: '教材扫描件里的公式以前完全没法用,现在截图一框就搞定。连化学方程式都能识别,超出我的预期。',
name: '王梓涵',
role: '化学工程本科 · 浙江大学',
avatarBg: '#C9A88C',
avatarColor: '#4a2e14',
avatarLetter: '王',
stars: '★★★★☆',
},
];
const VISIBLE = 3;
const TOTAL = TESTIMONIALS.length;
const PAGES = TOTAL - VISIBLE + 1; // 4
export default function TestimonialsSection() {
const { language } = useLanguage();
const [currentPage, setCurrentPage] = useState(0);
const trackRef = useRef<HTMLDivElement>(null);
const autoTimerRef = useRef<ReturnType<typeof setInterval> | null>(null);
const goTo = useCallback((idx: number) => {
const clamped = Math.max(0, Math.min(idx, PAGES - 1));
setCurrentPage(clamped);
if (trackRef.current) {
const cardW = trackRef.current.parentElement!.offsetWidth;
const gap = 20;
const singleW = (cardW - gap * (VISIBLE - 1)) / VISIBLE;
const offset = clamped * (singleW + gap);
trackRef.current.style.transform = `translateX(-${offset}px)`;
}
}, []);
const resetAuto = useCallback(() => {
if (autoTimerRef.current) clearInterval(autoTimerRef.current);
autoTimerRef.current = setInterval(() => {
setCurrentPage((prev) => {
const next = (prev + 1) % PAGES;
goTo(next);
return next;
});
}, 5000);
}, [goTo]);
useEffect(() => {
resetAuto();
return () => { if (autoTimerRef.current) clearInterval(autoTimerRef.current); };
}, [resetAuto]);
useEffect(() => {
const handleResize = () => goTo(currentPage);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, [currentPage, goTo]);
const handleGoTo = (idx: number) => {
goTo(idx);
resetAuto();
};
return (
<section className="user-love">
<div className="container">
<div className="section-header reveal">
<div className="eyebrow">User Love</div>
<h2 className="section-title">
{language === 'zh' ? '全球学生都在用' : 'Loved by students worldwide'}
</h2>
<p className="section-desc">
{language === 'zh' ? '来自真实用户的反馈。' : 'Feedback from real users.'}
</p>
</div>
<div className="testimonial-wrap reveal">
<div
className="testimonial-track"
ref={trackRef}
style={{ transition: 'transform 0.4s ease' }}
>
{TESTIMONIALS.map((t, i) => (
<div key={i} className="testimonial-card">
<div className="t-quote">"</div>
<p className="t-body">{t.quote}</p>
<div className="t-footer">
<div
className="t-avatar"
style={{ background: t.avatarBg, color: t.avatarColor }}
>
{t.avatarLetter}
</div>
<div>
<div className="t-name">{t.name}</div>
<div className="t-role">{t.role}</div>
</div>
<div className="t-stars">{t.stars}</div>
</div>
</div>
))}
</div>
<div className="testimonial-nav">
<button
className="t-nav-btn"
onClick={() => handleGoTo(currentPage - 1)}
aria-label={language === 'zh' ? '上一条' : 'Previous'}
>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M15 18l-6-6 6-6" />
</svg>
</button>
<div className="t-dots">
{Array.from({ length: PAGES }).map((_, i) => (
<div
key={i}
className={`t-dot${i === currentPage ? ' active' : ''}`}
onClick={() => handleGoTo(i)}
/>
))}
</div>
<button
className="t-nav-btn"
onClick={() => handleGoTo(currentPage + 1)}
aria-label={language === 'zh' ? '下一条' : 'Next'}
>
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2">
<path d="M9 18l6-6-6-6" />
</svg>
</button>
</div>
</div>
</div>
</section>
);
}
```
- [ ] **Step 2: Verify typecheck**
```bash
npm run typecheck
```
Expected: no errors
- [ ] **Step 3: Commit**
```bash
git add src/components/home/TestimonialsSection.tsx
git commit -m "feat: add TestimonialsSection with auto-advancing carousel"
```
---
## Task 11: Replace PricingSection
**Files:**
- Modify: `src/components/home/PricingSection.tsx`
- [ ] **Step 1: Replace PricingSection.tsx**
```tsx
import { Link } from 'react-router-dom';
import { useLanguage } from '../../contexts/LanguageContext';
export default function PricingSection() {
const { language } = useLanguage();
const zh = language === 'zh';
return (
<section className="pricing" id="pricing">
<div className="container">
<div className="section-header reveal">
<div className="eyebrow">Pricing</div>
<h2 className="section-title">
{zh ? '选择适合你的方案' : 'Choose the plan that fits your workflow'}
</h2>
<p className="section-desc">
{zh ? '从免费试用到永久桌面版,按需选择,无需绑定订阅。' : 'From free trial to lifetime desktop — pick what fits, no subscription lock-in.'}
</p>
</div>
<div className="pricing-cards">
<div className="pricing-card reveal reveal-delay-1">
<div className="plan-name">Free</div>
<div className="plan-price">$<span style={{ fontSize: '44px', color: 'var(--text-strong)' }}>0</span></div>
<div className="plan-period">{zh ? '永久免费' : 'Forever free'}</div>
<div className="plan-desc">For first-time use and quick screenshots.</div>
<ul className="plan-features">
<li>{zh ? '每月 30 次识别' : '30 recognitions / month'}</li>
<li>LaTeX {zh ? '输出' : 'output'}</li>
<li>Web App {zh ? '访问' : 'access'}</li>
<li>{zh ? '基础公式支持' : 'Basic formula support'}</li>
</ul>
<Link to="/app" className="plan-btn">{zh ? '开始使用' : 'Get Started'}</Link>
</div>
<div className="pricing-card reveal reveal-delay-2">
<div className="plan-name">Monthly</div>
<div className="plan-price"><span>$</span>9</div>
<div className="plan-period">{zh ? '每月 / 随时取消' : '/month · cancel anytime'}</div>
<div className="plan-desc">Unlimited recognition for everyday study.</div>
<ul className="plan-features">
<li>{zh ? '无限次识别' : 'Unlimited recognitions'}</li>
<li>LaTeX + Markdown</li>
<li>{zh ? 'Word 原生公式' : 'Native Word equations'}</li>
<li>{zh ? '优先处理队列' : 'Priority queue'}</li>
</ul>
<Link to="/app" className="plan-btn">{zh ? '开始使用' : 'Get Started'}</Link>
</div>
<div className="pricing-card reveal reveal-delay-3">
<div className="plan-name">Quarterly</div>
<div className="plan-price"><span>$</span>24</div>
<div className="plan-period">{zh ? '每季 · 省 $3/月' : '/quarter · save $3/mo'}</div>
<div className="plan-desc">Best value for semester-long heavy usage.</div>
<ul className="plan-features">
<li>{zh ? '无限次识别' : 'Unlimited recognitions'}</li>
<li>{zh ? '全格式输出' : 'All output formats'}</li>
<li>{zh ? '批量 PDF 提取' : 'Batch PDF extraction'}</li>
<li>API {zh ? '访问Beta' : 'access (Beta)'}</li>
</ul>
<Link to="/app" className="plan-btn">{zh ? '开始使用' : 'Get Started'}</Link>
</div>
<div className="pricing-card featured reveal">
<div className="featured-badge">{zh ? '永久版' : 'Lifetime'}</div>
<div className="plan-name">Desktop</div>
<div className="plan-price"><span>$</span>79</div>
<div className="plan-period">{zh ? '一次购买 · 终身使用' : 'one-time · lifetime access'}</div>
<div className="plan-desc">Lifetime access for offline and sensitive files.</div>
<ul className="plan-features">
<li>{zh ? '完全离线运行' : 'Fully offline'}</li>
<li>{zh ? '无限次识别' : 'Unlimited recognitions'}</li>
<li>{zh ? '批量 PDF 处理' : 'Batch PDF processing'}</li>
<li>{zh ? '本地隐私保护' : 'Local privacy'}</li>
<li>{zh ? '终身免费更新' : 'Lifetime free updates'}</li>
</ul>
<Link to="/app" className="plan-btn featured-btn">{zh ? '购买桌面版' : 'Buy Desktop'}</Link>
</div>
</div>
</div>
</section>
);
}
```
- [ ] **Step 2: Verify typecheck**
```bash
npm run typecheck
```
- [ ] **Step 3: Commit**
```bash
git add src/components/home/PricingSection.tsx
git commit -m "feat: replace PricingSection with reference 4-tier pricing design"
```
---
## Task 12: Create DocsSeoSection
**Files:**
- Create: `src/components/home/DocsSeoSection.tsx`
- [ ] **Step 1: Create DocsSeoSection.tsx**
```tsx
import { Link } from 'react-router-dom';
import { useLanguage } from '../../contexts/LanguageContext';
const GUIDES = [
{
icon: <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/>,
icon2: <polyline points="14 2 14 8 20 8"/>,
titleEn: 'How to convert image to LaTeX',
titleZh: '图片转 LaTeX 完整指南',
metaEn: '5 min read · Most popular',
metaZh: '5 分钟 · 最受欢迎',
},
{
icon: <><rect x="4" y="4" width="16" height="16" rx="2"/><path d="M8 9h8M8 12h6M8 15h4"/></>,
titleEn: 'Copy formula to Word — native equation format',
titleZh: '复制公式到 Word — 原生公式格式',
metaEn: '4 min read · Extension users',
metaZh: '4 分钟 · 扩展用户',
},
{
icon: <><circle cx="11" cy="11" r="8"/><path d="m21 21-4.35-4.35"/></>,
titleEn: 'OCR math formula guide — accuracy tips',
titleZh: 'OCR 数学公式指南 — 提高准确度',
metaEn: '6 min read · Power users',
metaZh: '6 分钟 · 进阶用户',
},
{
icon: <><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z"/><path d="M14 2v6h6M10 12l2 2 4-4"/></>,
titleEn: 'PDF formula extraction — batch workflow',
titleZh: 'PDF 公式批量提取工作流',
metaEn: '8 min read · Desktop users',
metaZh: '8 分钟 · 桌面版用户',
},
];
export default function DocsSeoSection() {
const { language } = useLanguage();
const zh = language === 'zh';
return (
<section className="docs-seo" id="docs">
<div className="container">
<div className="section-header reveal">
<div className="eyebrow">Guides</div>
<h2 className="section-title">Image to LaTeX Guides</h2>
<p className="section-desc">
{zh
? '为学生、研究者和数学写作者准备的一步步工作流指南。'
: 'Step-by-step workflows for students, researchers, and anyone writing math.'}
</p>
</div>
<div className="doc-cards reveal">
{GUIDES.map((g, i) => (
<Link key={i} to="/docs" className="doc-card">
<div className="doc-card-left">
<div className="doc-icon">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8">
{g.icon}
{g.icon2}
</svg>
</div>
<div>
<div className="doc-title">{zh ? g.titleZh : g.titleEn}</div>
<div className="doc-meta">{zh ? g.metaZh : g.metaEn}</div>
</div>
</div>
<div className="doc-read">{zh ? '阅读指南 →' : 'Read Guide →'}</div>
</Link>
))}
</div>
</div>
</section>
);
}
```
- [ ] **Step 2: Verify typecheck**
```bash
npm run typecheck
```
- [ ] **Step 3: Commit**
```bash
git add src/components/home/DocsSeoSection.tsx
git commit -m "feat: add DocsSeoSection with guide cards"
```
---
## Task 13: Replace Footer
**Files:**
- Modify: `src/components/layout/Footer.tsx`
- [ ] **Step 1: Replace Footer.tsx**
```tsx
import { Link } from 'react-router-dom';
import { useLanguage } from '../../contexts/LanguageContext';
export default function Footer() {
const { language } = useLanguage();
const zh = language === 'zh';
return (
<footer>
<div className="container">
<div className="footer-grid">
<div className="footer-brand">
<Link to="/" className="footer-logo">
<div className="logo-icon" style={{ width: '32px', height: '32px', borderRadius: '9px' }}>
<svg viewBox="0 0 24 24" style={{ width: '18px', height: '18px' }} fill="none" stroke="white" strokeWidth="2">
<path d="M4 6h16M4 10h10M4 14h12M4 18h8" />
</svg>
</div>
<span>TexPixel</span>
</Link>
<p className="footer-tagline">
{zh ? '为学生、研究者和数学写作者而设计。' : 'Designed for students, researchers, and anyone writing math.'}
</p>
</div>
<div>
<div className="footer-col-title">Product</div>
<ul className="footer-links">
<li><Link to="/app">Web App</Link></li>
<li><a href="#">Extension</a></li>
<li><a href="#pricing">{zh ? '桌面版' : 'Desktop'}</a></li>
<li><a href="#">API (Beta)</a></li>
</ul>
</div>
<div>
<div className="footer-col-title">Docs</div>
<ul className="footer-links">
<li><Link to="/docs">Image to LaTeX</Link></li>
<li><Link to="/docs">PDF to Markdown</Link></li>
<li><Link to="/docs">{zh ? '手写识别' : 'Handwritten OCR'}</Link></li>
<li><Link to="/docs">Word Equations</Link></li>
</ul>
</div>
<div>
<div className="footer-col-title">{zh ? '公司' : 'Company'}</div>
<ul className="footer-links">
<li><a href="#">{zh ? '关于我们' : 'About'}</a></li>
<li><a href="#pricing">{zh ? '价格' : 'Pricing'}</a></li>
<li><Link to="/blog">{zh ? '博客' : 'Blog'}</Link></li>
<li><a href="#">{zh ? '联系我们' : 'Contact'}</a></li>
</ul>
</div>
<div>
<div className="footer-col-title">{zh ? '法律' : 'Legal'}</div>
<ul className="footer-links">
<li><a href="#">{zh ? '服务条款' : 'Terms of Service'}</a></li>
<li><a href="#">{zh ? '隐私政策' : 'Privacy Policy'}</a></li>
<li><a href="#">{zh ? 'Cookie 政策' : 'Cookie Policy'}</a></li>
</ul>
</div>
</div>
<div className="footer-bottom">
<div className="footer-copy">© 2026 TexPixel. All rights reserved.</div>
<div className="footer-made">
Made with{' '}
<svg viewBox="0 0 24 24" style={{ display: 'inline', width: '14px', height: '14px', verticalAlign: 'middle', fill: 'var(--rose)' }}>
<path d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z" />
</svg>
{' '}{zh ? '为全球学生而作' : 'for students worldwide'}
</div>
</div>
</div>
</footer>
);
}
```
- [ ] **Step 2: Verify typecheck**
```bash
npm run typecheck
```
- [ ] **Step 3: Commit**
```bash
git add src/components/layout/Footer.tsx
git commit -m "feat: replace Footer with reference design"
```
---
## Task 14: Update HomePage + Delete Old Components + Clean Translations
**Files:**
- Modify: `src/pages/HomePage.tsx`
- Modify: `src/lib/translations.ts`
- Delete: `src/components/home/HowItWorksSection.tsx`
- Delete: `src/components/home/ContactSection.tsx`
- [ ] **Step 1: Replace HomePage.tsx**
```tsx
import SEOHead from '../components/seo/SEOHead';
import HeroSection from '../components/home/HeroSection';
import ProductSuiteSection from '../components/home/ProductSuiteSection';
import FeaturesSection from '../components/home/FeaturesSection';
import ShowcaseSection from '../components/home/ShowcaseSection';
import TestimonialsSection from '../components/home/TestimonialsSection';
import PricingSection from '../components/home/PricingSection';
import DocsSeoSection from '../components/home/DocsSeoSection';
import { useScrollReveal } from '../hooks/useScrollReveal';
import { useLanguage } from '../contexts/LanguageContext';
export default function HomePage() {
const { t } = useLanguage();
useScrollReveal();
return (
<>
<SEOHead
title="TexPixel - AI Math Formula Recognition | LaTeX, MathML OCR Tool"
description={t.marketing.hero.subtitle}
path="/"
/>
<HeroSection />
<div className="section-divider" />
<ProductSuiteSection />
<FeaturesSection />
<ShowcaseSection />
<div className="section-divider" />
<TestimonialsSection />
<div className="section-divider" />
<PricingSection />
<div className="section-divider" />
<DocsSeoSection />
</>
);
}
```
- [ ] **Step 2: Remove dead `contact` keys from translations.ts**
In `src/lib/translations.ts`:
- Remove `contact: 'Contact',` from the `en.marketing.nav` block (around line 115)
- Remove `contact: '联系我们',` from the `zh.marketing.nav` block (around line 297)
- Remove the entire `en.marketing.contact` block (the object starting with `contact: { title:` around line 165175)
- Remove the entire `zh.marketing.contact` block (equivalent block in the zh section)
- [ ] **Step 3: Delete old components**
```bash
rm src/components/home/HowItWorksSection.tsx
rm src/components/home/ContactSection.tsx
```
- [ ] **Step 4: Verify typecheck and build**
```bash
npm run typecheck && npm run build
```
Expected: no TypeScript errors, build succeeds
- [ ] **Step 5: Commit**
```bash
git add src/pages/HomePage.tsx src/lib/translations.ts
git rm src/components/home/HowItWorksSection.tsx src/components/home/ContactSection.tsx
git commit -m "feat: wire all landing sections in HomePage, remove obsolete components"
```
---
## Task 15: Verify CSS Scoping Does Not Break Workspace
**Files:**
- No code changes — verification only
- [ ] **Step 1: Run the dev server and navigate to /app**
```bash
npm run dev
```
Open `http://localhost:5173/app` — verify:
- The workspace `AppLayout` and `WorkspacePage` render correctly
- No `.marketing-page` CSS rules leak (no warm beige background, no grid overlay on the workspace)
- [ ] **Step 2: Navigate to / (home)**
Open `http://localhost:5173/` — verify:
- Background matches reference (`#FFFBF7` warm cream with grid pattern)
- All three glow blobs visible as ambient background
- Navbar, Hero, all sections, and Footer match the reference HTML visually
- [ ] **Step 3: Run full build**
```bash
npm run build
```
Expected: success with no errors
- [ ] **Step 4: Final commit**
```bash
git add -A
git commit -m "chore: final verification — landing refactor complete"
```