diff --git a/public/demo/preview-chinese.png b/public/demo/preview-chinese.png new file mode 100644 index 0000000..6f1faf4 Binary files /dev/null and b/public/demo/preview-chinese.png differ diff --git a/public/demo/preview-english.png b/public/demo/preview-english.png new file mode 100644 index 0000000..7b8dba0 Binary files /dev/null and b/public/demo/preview-english.png differ diff --git a/public/demo/preview-formula.png b/public/demo/preview-formula.png new file mode 100644 index 0000000..97e52c8 Binary files /dev/null and b/public/demo/preview-formula.png differ diff --git a/src/components/AuthModal.tsx b/src/components/AuthModal.tsx index 04e04d6..0154f09 100644 --- a/src/components/AuthModal.tsx +++ b/src/components/AuthModal.tsx @@ -70,144 +70,287 @@ export default function AuthModal({ onClose, mandatory = false }: AuthModalProps await beginGoogleOAuth(); }; + const s = { + overlay: { + position: 'fixed' as const, + inset: 0, + background: 'rgba(31,26,23,0.45)', + backdropFilter: 'blur(4px)', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + zIndex: 1000, + padding: '16px', + }, + card: { + background: '#FFFDF9', + borderRadius: '24px', + boxShadow: '0 24px 64px rgba(198,134,85,0.18)', + maxWidth: '420px', + width: '100%', + padding: '32px', + fontFamily: "'DM Sans', sans-serif", + border: '1px solid #F1E6D8', + }, + header: { + display: 'flex', + justifyContent: 'space-between', + alignItems: 'center', + marginBottom: '24px', + }, + title: { + fontSize: '22px', + fontWeight: 700, + color: '#1F1A17', + fontFamily: "'Lora', serif", + }, + closeBtn: { + width: '32px', + height: '32px', + borderRadius: '50%', + border: '1px solid #F1E6D8', + background: 'transparent', + cursor: 'pointer', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + color: '#AA9685', + transition: 'all 0.15s', + }, + tabs: { + display: 'grid', + gridTemplateColumns: '1fr 1fr', + gap: '4px', + background: '#F5DDD0', + borderRadius: '14px', + padding: '4px', + marginBottom: '24px', + }, + tabActive: { + padding: '8px 12px', + borderRadius: '11px', + border: 'none', + background: '#FFFDF9', + color: '#C8622A', + fontWeight: 600, + fontSize: '14px', + cursor: 'pointer', + fontFamily: "'DM Sans', sans-serif", + boxShadow: '0 1px 4px rgba(200,98,42,0.12)', + transition: 'all 0.15s', + }, + tabInactive: { + padding: '8px 12px', + borderRadius: '11px', + border: 'none', + background: 'transparent', + color: '#6F6257', + fontWeight: 500, + fontSize: '14px', + cursor: 'pointer', + fontFamily: "'DM Sans', sans-serif", + transition: 'all 0.15s', + }, + fieldGroup: { + marginBottom: '16px', + }, + label: { + display: 'block', + fontSize: '13px', + fontWeight: 600, + color: '#6F6257', + marginBottom: '6px', + letterSpacing: '0.02em', + }, + input: { + width: '100%', + padding: '10px 14px', + border: '1.5px solid #F1E6D8', + borderRadius: '12px', + fontSize: '15px', + color: '#1F1A17', + background: '#FFFFFF', + outline: 'none', + fontFamily: "'DM Sans', sans-serif", + transition: 'border-color 0.15s', + }, + inputError: { + border: '1.5px solid #d97a6a', + }, + fieldError: { + marginTop: '4px', + fontSize: '12px', + color: '#c0503c', + }, + fieldHint: { + marginTop: '4px', + fontSize: '12px', + color: '#AA9685', + }, + errorBox: { + padding: '10px 14px', + background: '#fff0ed', + border: '1px solid #f5c0b0', + color: '#c0503c', + borderRadius: '12px', + fontSize: '13px', + fontWeight: 500, + marginBottom: '16px', + }, + submitBtn: { + width: '100%', + height: '48px', + background: '#C8622A', + color: 'white', + border: 'none', + borderRadius: '14px', + fontSize: '15px', + fontWeight: 600, + fontFamily: "'DM Sans', sans-serif", + cursor: 'pointer', + boxShadow: '0 2px 12px rgba(200,98,42,0.28)', + transition: 'all 0.2s', + marginBottom: '16px', + }, + divider: { + display: 'flex', + alignItems: 'center', + gap: '12px', + marginBottom: '16px', + }, + dividerLine: { + flex: 1, + height: '1px', + background: '#F1E6D8', + }, + dividerText: { + fontSize: '12px', + color: '#AA9685', + letterSpacing: '0.05em', + }, + googleBtn: { + width: '100%', + height: '48px', + border: '1.5px solid #F1E6D8', + borderRadius: '14px', + background: '#FFFFFF', + color: '#1F1A17', + fontSize: '15px', + fontWeight: 500, + fontFamily: "'DM Sans', sans-serif", + cursor: 'pointer', + display: 'flex', + alignItems: 'center', + justifyContent: 'center', + gap: '10px', + transition: 'all 0.2s', + }, + }; + return ( -
-
-
-

+
+
+
+

{mode === 'signup' ? t.auth.signUpTitle : t.auth.signInTitle}

{!mandatory && ( )}
-
+
-
-
- + +
+ { setEmail(e.target.value); - if (fieldErrors.email) { - setFieldErrors((prev) => ({ ...prev, email: undefined })); - } + if (fieldErrors.email) setFieldErrors((prev) => ({ ...prev, email: undefined })); }} - className={`w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent ${ - fieldErrors.email ? 'border-red-400' : 'border-gray-300' - }`} + style={fieldErrors.email ? { ...s.input, ...s.inputError } : s.input} placeholder="your@email.com" required disabled={isBusy} /> - {fieldErrors.email &&

{fieldErrors.email}

} - {mode === 'signup' && ( -

{t.auth.emailHint}

- )} + {fieldErrors.email &&

{fieldErrors.email}

} + {mode === 'signup' &&

{t.auth.emailHint}

}
-
- +
+ { setPassword(e.target.value); - if (fieldErrors.password) { - setFieldErrors((prev) => ({ ...prev, password: undefined })); - } + if (fieldErrors.password) setFieldErrors((prev) => ({ ...prev, password: undefined })); }} - className={`w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent ${ - fieldErrors.password ? 'border-red-400' : 'border-gray-300' - }`} + style={fieldErrors.password ? { ...s.input, ...s.inputError } : s.input} placeholder="••••••••" required minLength={6} disabled={isBusy} /> - {fieldErrors.password &&

{fieldErrors.password}

} - {mode === 'signup' && ( -

{t.auth.passwordHint}

- )} + {fieldErrors.password &&

{fieldErrors.password}

} + {mode === 'signup' &&

{t.auth.passwordHint}

}
{mode === 'signup' && ( -
- +
+ { setConfirmPassword(e.target.value); - if (fieldErrors.confirmPassword) { - setFieldErrors((prev) => ({ ...prev, confirmPassword: undefined })); - } + if (fieldErrors.confirmPassword) setFieldErrors((prev) => ({ ...prev, confirmPassword: undefined })); }} - className={`w-full px-4 py-2 border rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-transparent ${ - fieldErrors.confirmPassword ? 'border-red-400' : 'border-gray-300' - }`} + style={fieldErrors.confirmPassword ? { ...s.input, ...s.inputError } : s.input} placeholder="••••••••" required minLength={6} disabled={isBusy} /> - {fieldErrors.confirmPassword &&

{fieldErrors.confirmPassword}

} + {fieldErrors.confirmPassword &&

{fieldErrors.confirmPassword}

}
)} {(localError || authError) && ( -
+
{t.auth.error}: {localError || authError}
)} @@ -215,31 +358,28 @@ export default function AuthModal({ onClose, mandatory = false }: AuthModalProps -
-

- {zh ? '从免费试用到永久桌面版,按需选择,无需绑定订阅。' : 'From free trial to lifetime desktop — pick what fits, no subscription lock-in.'} + {zh + ? '从免费试用到永久授权,按需选择,无需绑定订阅。' + : 'From free trial to lifetime license — pick what fits, no subscription lock-in.'}

+ {/* Beta notice */} +
+ 🎉 + + {zh + ? '内测期间全部方案免费开放 · 无需绑定支付方式,注册即可解锁全部功能' + : 'Free during beta · No payment required — sign up and unlock all features now'} + +
+
+ + {/* Free */}
Free
-
$0
+
+ {zh ? <>¥0 : <>$0} +
{zh ? '永久免费' : 'Forever free'}
-
For first-time use and quick screenshots.
+
 
  • {zh ? '每月 30 次识别' : '30 recognitions / month'}
  • LaTeX {zh ? '输出' : 'output'}
  • Web App {zh ? '访问' : 'access'}
  • {zh ? '基础公式支持' : 'Basic formula support'}
- {zh ? '开始使用' : 'Get Started'} + {zh ? '免费体验' : 'Try Free'}
+ {/* Monthly */}
-
Monthly
-
$9
-
{zh ? '每月 / 随时取消' : '/month · cancel anytime'}
-
Unlimited recognition for everyday study.
+
+ {zh ? '限时免费' : 'Free Now'} +
+
{zh ? '月度会员' : 'Monthly'}
+
+ {zh + ? <>RMB ¥19.9 + : <>$2.99} +
+
+ {zh ? '教育优惠 ¥12.9 / 月' : 'Edu discount $1.99 / mo'} +
    -
  • {zh ? '无限次识别' : 'Unlimited recognitions'}
  • -
  • LaTeX + Markdown
  • -
  • {zh ? 'Word 原生公式' : 'Native Word equations'}
  • -
  • {zh ? '优先处理队列' : 'Priority queue'}
  • +
  • {zh ? '每月 1,000 次请求' : '1,000 requests / month'}
  • +
  • {zh ? '优先处理队列' : 'Priority processing'}
  • +
  • {zh ? '插件使用权限' : 'Plugin access'}
- {zh ? '开始使用' : 'Get Started'} + {zh ? '免费体验' : 'Try Free'}
-
-
Quarterly
-
$24
-
{zh ? '每季 · 省 $3/月' : '/quarter · save $3/mo'}
-
Best value for semester-long heavy usage.
+ {/* Quarterly — featured */} +
+
{zh ? '最优惠' : 'Best Value'}
+
+ {zh ? '限时免费' : 'Free Now'} +
+
{zh ? '季度会员' : 'Quarterly'}
+
+ {zh + ? <>RMB ¥49.9 + : <>$9.9} +
+
+ {zh ? '教育优惠 ¥29.9 / 季' : 'Edu discount $7.99 / quarter'} +
    -
  • {zh ? '无限次识别' : 'Unlimited recognitions'}
  • -
  • {zh ? '全格式输出' : 'All output formats'}
  • -
  • {zh ? '批量 PDF 提取' : 'Batch PDF extraction'}
  • +
  • {zh ? '每月 3,000 积分' : '3,000 credits / month'}
  • +
  • {zh ? '优先处理队列' : 'Priority processing'}
  • +
  • {zh ? '插件使用权限' : 'Plugin access'}
  • API {zh ? '访问(Beta)' : 'access (Beta)'}
- {zh ? '开始使用' : 'Get Started'} + {zh ? '免费体验' : 'Try Free'}
-
-
{zh ? '永久版' : 'Lifetime'}
-
Desktop
-
$79
-
{zh ? '一次购买 · 终身使用' : 'one-time · lifetime access'}
-
Lifetime access for offline and sensitive files.
+ {/* Lifetime License — coming soon */} +
+
Coming Soon
+
+ 🖥 + {zh ? '桌面应用 · 离线运行' : 'Desktop App · Offline'} +
+
{zh ? '永久授权' : 'Lifetime License'}
+
+ {zh + ? <>RMB ¥149 + : <>$29.9} +
+
+ {zh ? '一次购买 · 终身使用' : 'one-time · lifetime access'} +
+
+ {zh ? '教育优惠 ¥99' : 'Edu discount $24.9'} +
  • {zh ? '完全离线运行' : 'Fully offline'}
  • {zh ? '无限次识别' : 'Unlimited recognitions'}
  • -
  • {zh ? '批量 PDF 处理' : 'Batch PDF processing'}
  • {zh ? '本地隐私保护' : 'Local privacy'}
  • {zh ? '终身免费更新' : 'Lifetime free updates'}
- {zh ? '购买桌面版' : 'Buy Desktop'} +
+
diff --git a/src/components/home/ProductSuiteSection.tsx b/src/components/home/ProductSuiteSection.tsx index 4ed958a..8f2feb0 100644 --- a/src/components/home/ProductSuiteSection.tsx +++ b/src/components/home/ProductSuiteSection.tsx @@ -10,12 +10,12 @@ export default function ProductSuiteSection() {
Product Matrix

- {language === 'zh' ? '覆盖所有公式工作流' : 'Built for every formula workflow'} + {language === 'zh' ? '三端灵活,覆盖所有使用场景' : 'Three ways to use, every workflow covered'}

{language === 'zh' - ? '从浏览器即取即用,到扩展一键复制,再到桌面端离线处理——一个工具,覆盖学生写作业、研究者整理文献、工程师记录推导的全部场景。' - : 'From instant browser use to one-click extension copy to offline desktop — one tool for students, researchers, and engineers.'} + ? '浏览器即开即用,扩展随手一键,桌面端离线无忧——学生轻松完成作业,教师高效备课制件,研究者快速整理文献,总有一种方式最适合你。' + : 'Browser-ready, extension-powered, desktop offline — for students finishing homework, teachers preparing materials, and researchers organizing papers.'}

@@ -30,8 +30,8 @@ export default function ProductSuiteSection() {
Web App
{language === 'zh' - ? '浏览器内即时识别,无需安装。上传截图或手写图片,秒级输出 LaTeX。' - : 'Instant recognition in browser, no install needed. Upload screenshot or handwriting, get LaTeX in seconds.'} + ? '无需安装,打开浏览器即可使用。上传截图或手写图片,秒级输出 LaTeX——学生写作业、教师课堂即时识别都毫不费力。' + : 'No install needed. Upload a screenshot or handwriting, get LaTeX in seconds — perfect for students and teachers alike.'}
{language === 'zh' ? '浏览器即时识别 →' : 'Instant formula recognition in browser →'} @@ -49,8 +49,8 @@ export default function ProductSuiteSection() {
Extension
{language === 'zh' - ? '浏览器扩展,一键将 ChatGPT、Claude 输出的公式复制为 Word 原生数学公式。' - : 'Browser extension — one-click copy of formulas from ChatGPT or Claude as native Word equations.'} + ? '一键将 ChatGPT、Claude 输出的公式转为 Word 原生数学公式。教师备课制件、学生写报告,不再手动排版。' + : 'One-click copy of formulas from ChatGPT or Claude as native Word equations — ideal for teachers making slides and students writing reports.'}
{language === 'zh' ? '从 LLM 复制公式到 Word →' : 'Copy formulas from LLMs to Word →'} @@ -67,8 +67,8 @@ export default function ProductSuiteSection() {
Desktop
{language === 'zh' - ? '桌面端离线处理,适合论文批量提取与隐私保护场景,一次购买终身使用。' - : 'Offline desktop app for batch PDF extraction and privacy-sensitive work. One-time purchase.'} + ? '本地离线运行,数据不出机。研究者批量提取论文公式、保护敏感数据的首选。一次购买,终身使用。' + : 'Fully offline, data stays local. The go-to for researchers extracting formulas from papers at scale. One-time purchase.'}
{language === 'zh' ? '查看桌面版定价 →' : 'See Desktop pricing →'} diff --git a/src/components/layout/Footer.tsx b/src/components/layout/Footer.tsx index 99220ee..0f5c02e 100644 --- a/src/components/layout/Footer.tsx +++ b/src/components/layout/Footer.tsx @@ -46,19 +46,19 @@ export default function Footer() {
{zh ? '公司' : 'Company'}
{zh ? '法律' : 'Legal'}
diff --git a/src/components/layout/MarketingNavbar.tsx b/src/components/layout/MarketingNavbar.tsx index cfce2ee..5482c88 100644 --- a/src/components/layout/MarketingNavbar.tsx +++ b/src/components/layout/MarketingNavbar.tsx @@ -2,6 +2,7 @@ import { useState, useEffect, useRef } from 'react'; import { Link, useLocation } from 'react-router-dom'; import { useLanguage } from '../../contexts/LanguageContext'; import { useAuth } from '../../contexts/AuthContext'; +import AuthModal from '../AuthModal'; export default function MarketingNavbar() { const { language, setLanguage } = useLanguage(); @@ -11,6 +12,7 @@ export default function MarketingNavbar() { const [scrolled, setScrolled] = useState(false); const [activeSection, setActiveSection] = useState(''); const [userMenuOpen, setUserMenuOpen] = useState(false); + const [showAuthModal, setShowAuthModal] = useState(false); const userMenuRef = useRef(null); // Scroll: sticky style + active nav section @@ -52,90 +54,94 @@ export default function MarketingNavbar() { : []; return ( - + + {showAuthModal && setShowAuthModal(false)} />} + ); } diff --git a/src/pages/AboutPage.tsx b/src/pages/AboutPage.tsx new file mode 100644 index 0000000..ef09bf9 --- /dev/null +++ b/src/pages/AboutPage.tsx @@ -0,0 +1,168 @@ +import { Link } from 'react-router-dom'; +import { useLanguage } from '../contexts/LanguageContext'; +import SEOHead from '../components/seo/SEOHead'; + +export default function AboutPage() { + const { language } = useLanguage(); + const zh = language === 'zh'; + + return ( + <> + + +
+ + + {zh ? '返回首页' : 'Back to home'} + + +
+
+ {zh ? '公司' : 'Company'} +
+

{zh ? '关于 TexPixel' : 'About TexPixel'}

+
+ {zh ? '让数学排版触手可及' : 'Making math typesetting effortless'} +
+
+ +
+ {zh ? : } +
+
+ + ); +} + +function AboutEn() { + return ( + <> +

Our Mission

+

+ TexPixel exists to eliminate the most tedious part of academic writing: transcribing handwritten or printed + formulas into LaTeX. We believe that students, researchers, and educators should spend their time thinking + about ideas — not fighting with syntax. +

+

+ A photograph of a chalkboard, a scan of a textbook, a snapshot of your own handwriting — TexPixel turns any + of these into clean, copy-paste-ready LaTeX, Markdown, or Word equations in under a second. +

+ +

What We Build

+

+ Our core product is an AI-powered document recognition engine trained specifically on mathematical notation. + Unlike general-purpose OCR tools, TexPixel understands the structure of formulas — fractions, integrals, + summations, matrices, and multi-line expressions — and produces output that actually works the first time. +

+

We offer:

+
    +
  • Web App — instant recognition in the browser, no installation required.
  • +
  • API (Beta) — integrate formula recognition directly into your tools and workflows.
  • +
  • Desktop App — fully offline processing for privacy-sensitive documents.
  • +
+ +

Who Uses TexPixel

+

+ Our users range from undergraduate students digitizing lecture notes to researchers processing thousands of + equations from scanned papers. TexPixel is used in over 50 countries, with particular strength in China, + the United States, Germany, Japan, and India. +

+ +

Our Principles

+
    +
  • Speed over friction. Every extra click is one too many. We optimize for the fastest possible path from image to output.
  • +
  • Accuracy where it matters. A wrong minus sign or missing exponent can invalidate an entire equation. We hold our models to a high bar.
  • +
  • Privacy by design. Your documents belong to you. We do not use uploaded content to train models without your explicit consent.
  • +
  • Accessible pricing. Students should not have to pay enterprise prices. Our free tier is generous, and our paid plans are priced for individuals.
  • +
+ +

The Team

+

+ TexPixel is a small, focused team of engineers and researchers who care deeply about tools that make + scientific writing easier. We are based in China, with contributors around the world. +

+

+ We're always looking for people who share our obsession with accuracy and clean user interfaces. + If that sounds like you, reach out at hello@texpixel.com. +

+ +

Get in Touch

+

+ For general inquiries: hello@texpixel.com
+ For support: support@texpixel.com
+ For legal and privacy matters: legal@texpixel.com +

+

+ Send us a message → +

+ + ); +} + +function AboutZh() { + return ( + <> +

我们的使命

+

+ TexPixel 的存在,是为了消除学术写作中最繁琐的一环:将手写或印刷的公式转录为 LaTeX。 + 我们相信,学生、研究者和教育工作者的时间应该用来思考问题,而不是与语法格式较劲。 +

+

+ 一张黑板照片、一份教材扫描件、一页你自己的手写笔记——TexPixel 能在一秒内将它们转换为 + 可直接复制使用的 LaTeX、Markdown 或 Word 公式。 +

+ +

我们做什么

+

+ 我们的核心产品是一个专为数学符号训练的 AI 文档识别引擎。与通用 OCR 工具不同, + TexPixel 能理解公式的结构——分数、积分、求和、矩阵、多行表达式——并生成一次就能用的输出。 +

+

我们提供:

+
    +
  • Web 应用——在浏览器中即时识别,无需安装。
  • +
  • API(Beta)——将公式识别直接集成到您的工具和工作流程中。
  • +
  • 桌面版——完全离线处理,适合隐私敏感的文档场景。
  • +
+ +

谁在使用 TexPixel

+

+ 我们的用户从正在数字化课堂笔记的本科生,到处理大量扫描论文公式的科研人员,不一而足。 + TexPixel 已在全球 50 多个国家被广泛使用,在中国、美国、德国、日本和印度尤为普及。 +

+ +

我们的原则

+
    +
  • 速度优先,减少摩擦。每一次多余的点击都是累赘。我们追求从图片到输出的最短路径。
  • +
  • 精度至上。一个错误的负号或漏掉的指数,可能让整个方程失效。我们对模型保持高标准。
  • +
  • 隐私设计。您的文档属于您自己。未经您明确同意,我们不会使用上传内容训练模型。
  • +
  • 亲民定价。学生不应为企业级服务付费。我们的免费额度足够慷慨,付费套餐也专为个人用户定价。
  • +
+ +

我们的团队

+

+ TexPixel 是一支小而精的工程师与研究者团队,深度专注于让科学写作更便捷的工具。 + 我们总部位于中国,贡献者遍布全球。 +

+

+ 我们始终欢迎同样痴迷于精准度与简洁交互设计的伙伴加入。 + 如果这说的是你,请联系 hello@texpixel.com。 +

+ +

联系我们

+

+ 综合咨询:hello@texpixel.com
+ 技术支持:support@texpixel.com
+ 法律与隐私:legal@texpixel.com +

+

+ 发送消息 → +

+ + ); +} diff --git a/src/pages/ContactPage.tsx b/src/pages/ContactPage.tsx new file mode 100644 index 0000000..aaef912 --- /dev/null +++ b/src/pages/ContactPage.tsx @@ -0,0 +1,185 @@ +import { Link } from 'react-router-dom'; +import { useLanguage } from '../contexts/LanguageContext'; +import SEOHead from '../components/seo/SEOHead'; + +export default function ContactPage() { + const { language } = useLanguage(); + const zh = language === 'zh'; + + return ( + <> + + +
+ + + {zh ? '返回首页' : 'Back to home'} + + +
+
+ {zh ? '公司' : 'Company'} +
+

{zh ? '联系我们' : 'Contact Us'}

+
+ {zh ? '我们通常在 1 个工作日内回复' : 'We typically reply within 1 business day'} +
+
+ +
+ {zh ? : } +
+
+ + ); +} + +function ContactEn() { + return ( + <> +

+ Have a question, a bug to report, or an idea to share? We'd love to hear from you. + Choose the right channel below and we'll get back to you as quickly as we can. +

+ +

Support

+

+ For issues with recognition quality, account problems, credit purchases, or any technical questions about + the product: +

+

+ support@texpixel.com +

+

+ When writing in, please include: +

+
    +
  • A brief description of the issue
  • +
  • The task ID (shown in your history panel) if the issue is recognition-related
  • +
  • Your browser and operating system (for web app issues)
  • +
+ +

Billing & Credits

+

+ For questions about charges, credit balance discrepancies, or refund requests: +

+

+ billing@texpixel.com +

+

+ Please include your account email and a description of the issue. For potential billing errors, + include the transaction date and amount. +

+ +

Partnerships & API Access

+

+ Interested in integrating TexPixel into your platform, LMS, or research pipeline? Looking for volume + pricing or a custom agreement? +

+

+ partnerships@texpixel.com +

+ +

Legal & Privacy

+

+ For privacy requests (data access, deletion, correction), legal inquiries, or DMCA notices: +

+

+ legal@texpixel.com +

+ +

General Inquiries

+

+ For everything else — press, feedback, or just saying hello: +

+

+ hello@texpixel.com +

+ +

Response Times

+

+ We aim to respond to all inquiries within 1 business day (China Standard Time, UTC+8). + During periods of high volume, support requests may take up to 3 business days. +

+

+ For self-service help, check our documentation — most common questions are + answered there. +

+ + ); +} + +function ContactZh() { + return ( + <> +

+ 有问题想反馈、发现了 Bug,或者有好的建议?我们很乐意听到您的声音。 + 请根据需求选择对应的联系方式,我们会尽快回复。 +

+ +

技术支持

+

+ 如遇识别质量问题、账户故障、积分购买疑问或其他产品技术问题: +

+

+ support@texpixel.com +

+

来信时请提供以下信息,以便我们更快处理:

+
    +
  • 问题的简要描述
  • +
  • 任务 ID(在历史记录面板中可见),如问题与识别结果相关
  • +
  • 浏览器名称和操作系统(针对 Web 应用问题)
  • +
+ +

账单与积分

+

+ 如有扣款疑问、积分余额异常或退款申请: +

+

+ billing@texpixel.com +

+

+ 请在邮件中注明您的账户邮箱及问题描述。若涉及账单错误,请提供交易日期和金额。 +

+ +

合作与 API 接入

+

+ 希望将 TexPixel 集成到您的平台、学习管理系统或科研流程中?寻求批量定价或定制合作? +

+

+ partnerships@texpixel.com +

+ +

法律与隐私

+

+ 隐私权利请求(数据访问、删除、更正)、法律咨询或 DMCA 版权通知: +

+

+ legal@texpixel.com +

+ +

综合咨询

+

+ 其他一切事宜——媒体采访、产品反馈,或者只是想打个招呼: +

+

+ hello@texpixel.com +

+ +

响应时间

+

+ 我们争取在 1 个工作日内回复所有咨询(中国标准时间 UTC+8)。 + 高峰期内,支持请求最多可能需要 3 个工作日。 +

+

+ 如需自助解答,请查阅我们的文档,大多数常见问题都有详细解答。 +

+ + ); +} diff --git a/src/pages/CookiePolicyPage.tsx b/src/pages/CookiePolicyPage.tsx new file mode 100644 index 0000000..8344976 --- /dev/null +++ b/src/pages/CookiePolicyPage.tsx @@ -0,0 +1,304 @@ +import { Link } from 'react-router-dom'; +import { useLanguage } from '../contexts/LanguageContext'; +import SEOHead from '../components/seo/SEOHead'; + +const EFFECTIVE_DATE_EN = 'March 26, 2026'; +const EFFECTIVE_DATE_ZH = '2026年3月26日'; + +export default function CookiePolicyPage() { + const { language } = useLanguage(); + const zh = language === 'zh'; + + return ( + <> + + +
+ + + {zh ? '返回首页' : 'Back to home'} + + +
+
+ Legal +
+

{zh ? 'Cookie 政策' : 'Cookie Policy'}

+
+ {zh ? `生效日期:${EFFECTIVE_DATE_ZH}` : `Effective: ${EFFECTIVE_DATE_EN}`} + · + TexPixel +
+
+ +
+ {zh ? : } +
+
+ + ); +} + +function CookieEn() { + return ( + <> +

+ This Cookie Policy explains how TexPixel ("we", "us", or "our") uses cookies and similar technologies on our + website and web application. By using the Service, you consent to the use of cookies as described here. +

+ +

1. What Are Cookies?

+

+ Cookies are small text files placed on your device by websites you visit. They are widely used to make websites + work efficiently and to provide information to site owners. Beyond traditional cookies, we also use browser + localStorage — a similar technology that stores data in your browser without an expiration date. +

+ +

2. Cookies and Storage We Use

+

We use the following types of storage technologies:

+ +

+ Strictly Necessary +

+

+ These are essential for the Service to function. They cannot be disabled without breaking core functionality. +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
NameTypePurposeRetention
texpixel_tokenlocalStorageStores your JWT authentication token to keep you logged inUntil sign-out or token expiry
languagelocalStorageRemembers your language preference (en/zh)Persistent (until cleared)
texpixel_guest_usage_countlocalStorageTracks free-tier usage count for guest (unauthenticated) usersPersistent (until cleared)
+ +

+ Functional +

+

+ These enhance your experience but are not strictly required. Disabling them may affect some features. +

+ + + + + + + + + + + + + + + + + +
NameTypePurposeRetention
_ga, _gidCookieAnalytics (if enabled): distinguishes users and sessions for aggregate usage statistics2 years / 24 hours
+ +

3. Third-Party Cookies

+

+ When you use Sign in with Google, Google may set its own cookies as part of the OAuth + authentication flow. These cookies are governed by{' '} + Google's Privacy Policy. + We do not control Google's cookies and cannot disable them on Google's behalf. +

+

+ Our payment processor may also set session cookies during the checkout process. These are strictly necessary + for completing your purchase and are removed after the transaction. +

+ +

4. What We Do Not Do

+
    +
  • We do not use cookies or localStorage to track you across third-party websites.
  • +
  • We do not sell data derived from cookies to advertisers or data brokers.
  • +
  • We do not serve targeted advertising cookies.
  • +
+ +

5. Managing Cookies & Local Storage

+

+ You can control and delete cookies and localStorage data through your browser settings. Note that clearing + your authentication token (texpixel_token) will sign you out. Clearing the language{' '} + key will reset your language preference to auto-detection. +

+

Instructions for managing storage in common browsers:

+
    +
  • Chrome: Settings → Privacy and security → Clear browsing data
  • +
  • Firefox: Settings → Privacy & Security → Cookies and Site Data → Clear Data
  • +
  • Safari: Settings → Privacy → Manage Website Data
  • +
  • Edge: Settings → Privacy, search, and services → Clear browsing data
  • +
+

+ To inspect or manually delete our localStorage entries, open your browser's Developer Tools → Application + tab → Local Storage → texpixel.com. +

+ +

6. Changes to This Policy

+

+ We may update this Cookie Policy from time to time. The "Effective" date at the top of this page indicates + when the policy was last revised. Continued use of the Service after changes constitutes acceptance. +

+ +

7. Contact Us

+

+ If you have questions about our use of cookies, contact us at{' '} + privacy@texpixel.com. +

+ + ); +} + +function CookieZh() { + return ( + <> +

+ 本 Cookie 政策说明 TexPixel("我们")如何在我们的网站及 Web 应用中使用 Cookie 及类似技术。 + 使用本服务即表示您同意按本政策所述使用 Cookie。 +

+ +

1. 什么是 Cookie?

+

+ Cookie 是您访问网站时由网站在您设备上放置的小型文本文件。它们被广泛用于使网站高效运行, + 并向网站所有者提供信息。除传统 Cookie 外,我们还使用浏览器的 + localStorage——一种在浏览器中存储数据且无过期时间的类似技术。 +

+ +

2. 我们使用的 Cookie 及存储项

+

我们使用以下几类存储技术:

+ +

+ 严格必要类 +

+

这些存储项对于服务的正常运行不可或缺,禁用后核心功能将无法使用。

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
名称类型用途保留时间
texpixel_tokenlocalStorage存储 JWT 身份验证令牌,维持登录状态退出登录或令牌过期时清除
languagelocalStorage记录您的语言偏好(en/zh)持久(直至手动清除)
texpixel_guest_usage_countlocalStorage记录未登录访客用户的免费使用次数持久(直至手动清除)
+ +

+ 功能类 +

+

这些存储项可改善您的使用体验,但非严格必需。禁用可能影响部分功能。

+ + + + + + + + + + + + + + + + + +
名称类型用途保留时间
_ga, _gidCookie数据分析(如已启用):区分用户与会话,用于汇总使用统计2年 / 24小时
+ +

3. 第三方 Cookie

+

+ 使用谷歌登录时,Google 可能在 OAuth 身份验证流程中设置自己的 Cookie。 + 这些 Cookie 受{' '} + Google 隐私政策 + 约束。我们无法控制 Google 的 Cookie,也无法代表 Google 禁用它们。 +

+

+ 我们的支付处理商也可能在结账过程中设置会话 Cookie,这些 Cookie 是完成购买所必需的,交易结束后将自动删除。 +

+ +

4. 我们不会做的事

+
    +
  • 我们不会使用 Cookie 或 localStorage 跨第三方网站追踪您。
  • +
  • 我们不会将 Cookie 衍生数据出售给广告商或数据经纪商。
  • +
  • 我们不会投放定向广告 Cookie。
  • +
+ +

5. 管理 Cookie 与本地存储

+

+ 您可以通过浏览器设置控制和删除 Cookie 及 localStorage 数据。请注意,清除身份验证令牌 + (texpixel_token)将导致您退出登录;清除 language 键将重置语言偏好为自动检测。 +

+

常见浏览器管理存储的操作路径:

+
    +
  • Chrome:设置 → 隐私设置和安全性 → 清除浏览数据
  • +
  • Firefox:设置 → 隐私与安全 → Cookie 和网站数据 → 清除数据
  • +
  • Safari:设置 → 隐私 → 管理网站数据
  • +
  • Edge:设置 → 隐私、搜索和服务 → 清除浏览数据
  • +
+

+ 如需手动检查或删除我们的 localStorage 条目,请打开浏览器开发者工具 → Application 选项卡 → + Local Storage → texpixel.com。 +

+ +

6. 政策变更

+

+ 我们可能不时更新本 Cookie 政策。页面顶部的"生效日期"表示本政策最近一次修订的时间。 + 变更后继续使用本服务,即视为您接受修订内容。 +

+ +

7. 联系我们

+

+ 如对我们使用 Cookie 的方式有任何疑问,请通过{' '} + privacy@texpixel.com 联系我们。 +

+ + ); +} diff --git a/src/pages/PrivacyPage.tsx b/src/pages/PrivacyPage.tsx new file mode 100644 index 0000000..94b1ebc --- /dev/null +++ b/src/pages/PrivacyPage.tsx @@ -0,0 +1,283 @@ +import { Link } from 'react-router-dom'; +import { useLanguage } from '../contexts/LanguageContext'; +import SEOHead from '../components/seo/SEOHead'; + +const EFFECTIVE_DATE_EN = 'March 26, 2026'; +const EFFECTIVE_DATE_ZH = '2026年3月26日'; + +export default function PrivacyPage() { + const { language } = useLanguage(); + const zh = language === 'zh'; + + return ( + <> + + +
+ + + {zh ? '返回首页' : 'Back to home'} + + +
+
+ Legal +
+

{zh ? '隐私政策' : 'Privacy Policy'}

+
+ {zh ? `生效日期:${EFFECTIVE_DATE_ZH}` : `Effective: ${EFFECTIVE_DATE_EN}`} + · + TexPixel +
+
+ +
+ {zh ? : } +
+
+ + ); +} + +function PrivacyEn() { + return ( + <> +

+ TexPixel ("we", "us", or "our") is committed to protecting your privacy. This Privacy Policy explains what + information we collect, how we use it, and your rights regarding your data. By using the Service, you consent + to the practices described here. +

+ +

1. Information We Collect

+

Information you provide directly:

+
    +
  • Account data: email address, password (stored as a hashed value — we never see your plaintext password), and display name.
  • +
  • Google OAuth data: if you sign in with Google, we receive your Google account email, name, and profile picture URL as provided by Google.
  • +
  • Payment data: when you purchase credits, payment is processed by a third-party payment processor. We receive only a transaction ID and purchase amount — we do not store your card details.
  • +
  • User Content: documents, images, and files you upload for recognition processing.
  • +
  • Support communications: messages you send to our support team.
  • +
+

Information collected automatically:

+
    +
  • Usage data: pages visited, features used, recognition tasks submitted, timestamps, and error logs.
  • +
  • Device and technical data: IP address, browser type, operating system, and referring URL.
  • +
  • Cookies and local storage: authentication tokens (JWT stored in localStorage), language preference, and guest usage count. See our Cookie Policy for details.
  • +
+ +

2. How We Use Your Information

+
    +
  • Provide, operate, and improve the Service.
  • +
  • Authenticate your identity and maintain your session.
  • +
  • Process recognition tasks you submit.
  • +
  • Manage your credit balance and transaction history.
  • +
  • Send transactional emails: verification codes, payment receipts, and account security alerts.
  • +
  • Detect and prevent fraud, abuse, and violations of our Terms of Service.
  • +
  • Analyze aggregate usage patterns to improve the Service (using anonymized or pseudonymized data).
  • +
  • Comply with legal obligations.
  • +
+

+ We do not use your User Content to train AI or machine learning models without your explicit, + opt-in consent. We do not sell your personal information to third parties. +

+ +

3. Information Sharing

+

We share your information only in the following circumstances:

+
    +
  • Service providers: cloud object storage (for file storage), email delivery services (for verification codes and notifications), and payment processors. These parties process data on our behalf under data processing agreements.
  • +
  • Google: when you use Google OAuth, data is exchanged with Google in accordance with Google's Privacy Policy.
  • +
  • Legal compliance: we may disclose information if required by law, court order, or governmental authority, or to protect the rights, property, or safety of TexPixel, our users, or the public.
  • +
  • Business transfers: in the event of a merger, acquisition, or sale of assets, your information may be transferred to the successor entity, subject to the same privacy protections.
  • +
+ +

4. Data Retention

+
    +
  • Account data: retained for as long as your account is active, plus a 30-day grace period after deletion.
  • +
  • User Content: uploaded files are retained for up to 90 days after task completion, then permanently deleted unless you save them to your account history.
  • +
  • Task history: recognition results in your account history are retained until you delete them or close your account.
  • +
  • Payment records: retained for 7 years as required by applicable financial regulations.
  • +
  • Log data: server and access logs are retained for up to 90 days.
  • +
+ +

5. Data Security

+

+ We implement industry-standard security measures including TLS encryption for data in transit, encrypted storage + for sensitive credentials, and access controls limiting who can access production data. However, no system is + completely secure. We encourage you to use a strong, unique password and to contact us immediately if you suspect + unauthorized access to your account. +

+ +

6. Your Rights

+

+ Depending on your location, you may have the following rights regarding your personal data: +

+
    +
  • Access: request a copy of the personal data we hold about you.
  • +
  • Correction: request correction of inaccurate or incomplete data.
  • +
  • Deletion: request deletion of your personal data ("right to be forgotten"), subject to legal retention obligations.
  • +
  • Portability: receive your data in a structured, machine-readable format.
  • +
  • Objection / Restriction: object to or request restriction of certain processing activities.
  • +
  • Withdraw Consent: where processing is based on consent, withdraw that consent at any time.
  • +
+

+ To exercise any of these rights, contact us at privacy@texpixel.com. + We will respond within 30 days. We may need to verify your identity before processing your request. +

+ +

7. Children's Privacy

+

+ The Service is not directed to children under 13. We do not knowingly collect personal information from children + under 13. If we become aware that a child under 13 has provided us with personal information, we will delete it + promptly. If you believe a child has provided us with their data, please contact us immediately. +

+ +

8. International Data Transfers

+

+ TexPixel operates primarily from servers located in China. If you access the Service from outside China, + your data will be transferred to and processed in China. By using the Service, you consent to this transfer. + We take appropriate safeguards to ensure your data is treated in accordance with this Privacy Policy regardless + of where it is processed. +

+ +

9. Third-Party Links

+

+ The Service may contain links to third-party websites. This Privacy Policy does not apply to those sites. + We encourage you to review the privacy policies of any third-party services you visit. +

+ +

10. Changes to This Policy

+

+ We may update this Privacy Policy from time to time. We will notify you of material changes via email or a + prominent notice on the Service at least 14 days before the changes take effect. The "Effective" date at the + top of this page indicates when the policy was last revised. +

+ +

11. Contact Us

+

+ For privacy-related questions or to exercise your rights, contact us at{' '} + privacy@texpixel.com. +

+ + ); +} + +function PrivacyZh() { + return ( + <> +

+ TexPixel("我们")致力于保护您的隐私。本隐私政策说明我们收集哪些信息、如何使用这些信息, + 以及您对自己数据所享有的权利。使用本服务即表示您同意本政策所述的相关做法。 +

+ +

1. 我们收集的信息

+

您主动提供的信息:

+
    +
  • 账户数据:电子邮件地址、密码(以哈希形式存储,我们从不接触您的明文密码)及显示名称。
  • +
  • Google OAuth 数据:通过 Google 登录时,我们会获取 Google 提供的账户邮箱、姓名及头像 URL。
  • +
  • 支付数据:购买积分时,支付由第三方支付处理商完成。我们仅获取交易 ID 和购买金额,不存储您的银行卡信息。
  • +
  • 用户内容:您上传以供识别处理的文档、图片及文件。
  • +
  • 支持沟通:您向我们客服发送的消息。
  • +
+

自动收集的信息:

+
    +
  • 使用数据:访问的页面、使用的功能、提交的识别任务、时间戳及错误日志。
  • +
  • 设备与技术数据:IP 地址、浏览器类型、操作系统及来源页面 URL。
  • +
  • Cookie 与本地存储:身份验证令牌(JWT,存储于 localStorage)、语言偏好及访客使用次数。详情请参阅我们的 Cookie 政策。
  • +
+ +

2. 我们如何使用您的信息

+
    +
  • 提供、运营和改进本服务。
  • +
  • 验证您的身份并维持您的登录会话。
  • +
  • 处理您提交的识别任务。
  • +
  • 管理您的积分余额和交易记录。
  • +
  • 发送交易类邮件:验证码、支付收据及账户安全提醒。
  • +
  • 检测和防止欺诈、滥用及违反服务条款的行为。
  • +
  • 使用匿名化或假名化数据分析汇总使用模式,以改进服务。
  • +
  • 履行法律义务。
  • +
+

+ 未经您明确选择同意,我们不会使用您的用户内容训练 AI 或机器学习模型。 + 我们不会将您的个人信息出售给第三方。 +

+ +

3. 信息共享

+

仅在以下情况下,我们会共享您的信息:

+
    +
  • 服务提供商:云对象存储(用于文件存储)、邮件发送服务(用于验证码和通知)及支付处理商。这些方依据数据处理协议代表我们处理数据。
  • +
  • Google:使用 Google OAuth 时,数据将依据 Google 隐私政策与 Google 进行交换。
  • +
  • 法律合规:法律、法院命令或政府机构要求时,或为保护 TexPixel、用户或公众的权利、财产或安全时,我们可能披露相关信息。
  • +
  • 业务转让:发生合并、收购或资产出售时,您的信息可能转移至继承方,并受同等隐私保护。
  • +
+ +

4. 数据保留

+
    +
  • 账户数据:在账户有效期间保留,账户删除后额外保留 30 天宽限期。
  • +
  • 用户内容:上传的文件在任务完成后最多保留 90 天,之后永久删除,除非您将其保存至账户历史记录。
  • +
  • 任务历史:账户中的识别结果保留至您删除它们或注销账户为止。
  • +
  • 支付记录:依据适用财务法规保留 7 年。
  • +
  • 日志数据:服务器及访问日志保留最多 90 天。
  • +
+ +

5. 数据安全

+

+ 我们实施行业标准安全措施,包括传输中的 TLS 加密、敏感凭证的加密存储, + 以及限制生产数据访问权限的访问控制。然而,任何系统都无法做到绝对安全。 + 建议您使用强密码,并在怀疑账户遭到未授权访问时立即联系我们。 +

+ +

6. 您的权利

+

根据您所在地区,您可能对个人数据享有以下权利:

+
    +
  • 访问权:请求获取我们持有的关于您的个人数据副本。
  • +
  • 更正权:请求更正不准确或不完整的数据。
  • +
  • 删除权:请求删除您的个人数据("被遗忘权"),受法律保留义务约束。
  • +
  • 数据可携权:以结构化、机器可读的格式接收您的数据。
  • +
  • 反对权/限制权:反对或要求限制某些处理活动。
  • +
  • 撤回同意:对于基于同意的处理,可随时撤回同意。
  • +
+

+ 如需行使上述任何权利,请发送邮件至{' '} + privacy@texpixel.com。 + 我们将在 30 天内答复。处理请求前,我们可能需要验证您的身份。 +

+ +

7. 儿童隐私

+

+ 本服务不面向 13 周岁以下儿童。我们不会有意收集 13 周岁以下儿童的个人信息。 + 若发现 13 周岁以下儿童向我们提供了个人信息,我们将立即予以删除。 + 如您认为儿童已向我们提供个人数据,请立即联系我们。 +

+ +

8. 国际数据传输

+

+ TexPixel 主要依托位于中国的服务器运营。如您从中国境外访问本服务, + 您的数据将被传输至中国并在中国境内处理。使用本服务即表示您同意此类传输。 + 无论数据在何处处理,我们均采取适当保障措施,确保您的数据受本隐私政策保护。 +

+ +

9. 第三方链接

+

+ 本服务可能包含第三方网站的链接。本隐私政策不适用于这些网站。 + 建议您查阅所访问的任何第三方服务的隐私政策。 +

+ +

10. 政策变更

+

+ 我们可能不时更新本隐私政策。对于重大变更,我们将通过电子邮件或服务内显著通知的方式, + 在变更生效前至少 14 天提前告知您。页面顶部的"生效日期"表示本政策最近一次修订的时间。 +

+ +

11. 联系我们

+

+ 如有隐私相关问题或需行使您的权利,请通过{' '} + privacy@texpixel.com 联系我们。 +

+ + ); +} diff --git a/src/pages/TermsPage.tsx b/src/pages/TermsPage.tsx new file mode 100644 index 0000000..3c88117 --- /dev/null +++ b/src/pages/TermsPage.tsx @@ -0,0 +1,322 @@ +import { Link } from 'react-router-dom'; +import { useLanguage } from '../contexts/LanguageContext'; +import SEOHead from '../components/seo/SEOHead'; + +const EFFECTIVE_DATE_EN = 'March 26, 2026'; +const EFFECTIVE_DATE_ZH = '2026年3月26日'; + +export default function TermsPage() { + const { language } = useLanguage(); + const zh = language === 'zh'; + + return ( + <> + + +
+ + + {zh ? '返回首页' : 'Back to home'} + + +
+
+ Legal +
+

{zh ? '服务条款' : 'Terms of Service'}

+
+ {zh ? `生效日期:${EFFECTIVE_DATE_ZH}` : `Effective: ${EFFECTIVE_DATE_EN}`} + · + TexPixel +
+
+ +
+ {zh ? : } +
+
+ + ); +} + +function TermsEn() { + return ( + <> +

+ Please read these Terms of Service ("Terms") carefully before using TexPixel ("Service", "we", "us", or "our"). + By creating an account or using the Service, you agree to be bound by these Terms. If you do not agree, do not use the Service. +

+ +

1. Eligibility

+

+ You must be at least 13 years old to use the Service. If you are under 18, you must have your parent or legal guardian's + permission. By using the Service, you represent and warrant that you meet these requirements. Paid features (credits + purchases) are available only to users who are 18 or older or have legal capacity to enter into contracts in their jurisdiction. +

+ +

2. Account Registration

+

+ You may register using an email address and one-time verification code, or by linking a Google account via OAuth 2.0. + You are responsible for maintaining the confidentiality of your account credentials and for all activities that occur + under your account. You must provide accurate, current, and complete information and keep your account information updated. + We reserve the right to suspend or terminate accounts that contain false information or that are used fraudulently. +

+ +

3. Credits & Payment

+

+ Access to certain features of the Service requires purchasing credits. Credits are a prepaid, non-refundable virtual + currency used to pay for recognition tasks (image-to-LaTeX, PDF-to-Markdown, handwriting OCR, etc.). +

+
    +
  • No Refunds. Credits are non-refundable except where required by applicable law. If you believe + you were charged in error, contact us within 30 days of the charge.
  • +
  • Expiration. Credits do not expire as long as your account remains active. We reserve the right + to introduce expiration policies with at least 60 days' notice.
  • +
  • Price Changes. We may change credit prices at any time. Changes will not affect credits already purchased.
  • +
  • Taxes. You are responsible for all applicable taxes on credit purchases in your jurisdiction.
  • +
  • Free Tier. Guest users receive a limited number of free recognition tasks. Free usage is subject + to change without notice.
  • +
  • Chargebacks. Initiating a chargeback without first contacting us may result in immediate account suspension.
  • +
+ +

4. User Content

+

+ You retain all intellectual property rights in the documents, images, and files you upload ("User Content"). By + uploading User Content, you grant TexPixel a limited, non-exclusive, royalty-free license to process, store, and + transmit your content solely to provide the Service. +

+
    +
  • We do not use your User Content to train AI models without your explicit consent.
  • +
  • We do not share your User Content with third parties except as necessary to operate the Service (e.g., cloud + storage providers).
  • +
  • You are responsible for ensuring you have the right to upload and process any content you submit.
  • +
  • Do not upload content that is illegal, infringes third-party rights, or contains personally identifiable + information of others without their consent.
  • +
+ +

5. Accuracy Disclaimer

+

+ TexPixel uses AI-based recognition technology. Recognition results (LaTeX, Markdown, text) are provided on an + "as-is" basis. We do not warrant that results will be accurate, complete, or suitable for any particular purpose. + You are responsible for verifying all outputs before use in academic, professional, or published work. +

+ +

6. Prohibited Uses

+

You agree not to:

+
    +
  • Use the Service to process content that is illegal, obscene, defamatory, or violates third-party rights.
  • +
  • Reverse-engineer, decompile, or attempt to extract source code from the Service.
  • +
  • Automate requests to the Service in a manner that exceeds your plan limits or degrades service for others.
  • +
  • Use the Service to build a competing product or service without our written permission.
  • +
  • Share, sell, or transfer your account or credits to another party.
  • +
  • Use bots, scrapers, or automated tools to access the Service beyond what is permitted by the API documentation.
  • +
  • Circumvent any technical measures we use to limit usage or enforce these Terms.
  • +
+ +

7. Intellectual Property

+

+ The Service, including its software, design, trademarks, and content (excluding User Content), is owned by TexPixel + and protected by applicable intellectual property laws. You may not copy, modify, distribute, sell, or lease any part + of the Service without our prior written consent. +

+ +

8. Third-Party Services

+

+ The Service integrates with third-party services including Google (for OAuth), cloud object storage providers (for + file storage), and payment processors. Your use of these services is also subject to their respective terms and + privacy policies. We are not responsible for the practices of third-party services. +

+ +

9. Disclaimer of Warranties

+

+ THE SERVICE IS PROVIDED "AS IS" AND "AS AVAILABLE" WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, + INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT. + WE DO NOT WARRANT THAT THE SERVICE WILL BE UNINTERRUPTED, ERROR-FREE, OR SECURE. +

+ +

10. Limitation of Liability

+

+ TO THE MAXIMUM EXTENT PERMITTED BY LAW, TEXPIXEL SHALL NOT BE LIABLE FOR ANY INDIRECT, INCIDENTAL, SPECIAL, + CONSEQUENTIAL, OR PUNITIVE DAMAGES, INCLUDING LOSS OF DATA, LOSS OF PROFITS, OR BUSINESS INTERRUPTION, ARISING + FROM YOUR USE OF THE SERVICE, EVEN IF WE HAVE BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. +

+

+ OUR TOTAL LIABILITY TO YOU FOR ANY CLAIMS ARISING FROM YOUR USE OF THE SERVICE SHALL NOT EXCEED THE AMOUNT YOU + PAID US IN THE 12 MONTHS PRECEDING THE CLAIM. +

+ +

11. Termination

+

+ We may suspend or terminate your account at any time, with or without notice, for conduct that we determine violates + these Terms or is harmful to other users, us, or third parties. You may delete your account at any time by contacting + us. Upon termination, your right to use the Service ceases immediately. Unused credits at the time of termination for + cause are forfeited; credits remaining upon voluntary account closure may be refunded at our discretion. +

+ +

12. Indemnification

+

+ You agree to indemnify, defend, and hold harmless TexPixel and its officers, directors, employees, and agents from + any claims, liabilities, damages, and expenses (including reasonable attorneys' fees) arising from your use of the + Service, your User Content, or your violation of these Terms. +

+ +

13. Governing Law & Dispute Resolution

+

+ These Terms are governed by the laws of the People's Republic of China without regard to conflict-of-law principles. + Any disputes arising from these Terms shall first be subject to good-faith negotiation. If unresolved within 30 days, + disputes shall be submitted to binding arbitration in accordance with applicable rules, or to the competent courts of + the jurisdiction where TexPixel is incorporated. +

+ +

14. Changes to These Terms

+

+ We may modify these Terms at any time. We will provide notice of material changes via email or a prominent notice on + the Service at least 14 days before changes take effect. Your continued use of the Service after the effective date + constitutes your acceptance of the revised Terms. +

+ +

15. Contact Us

+

+ If you have questions about these Terms, please contact us at{' '} + legal@texpixel.com. +

+ + ); +} + +function TermsZh() { + return ( + <> +

+ 请在使用 TexPixel("服务"、"我们")之前仔细阅读本服务条款("条款")。 + 注册账户或使用本服务,即表示您同意受本条款约束。如您不同意,请勿使用本服务。 +

+ +

1. 使用资格

+

+ 您须年满 13 周岁方可使用本服务。若您未满 18 周岁,须取得父母或法定监护人的同意。 + 付费功能(积分购买)仅向具备完全民事行为能力的成年用户开放。 + 使用本服务即表示您保证符合上述要求。 +

+ +

2. 账户注册

+

+ 您可通过电子邮件地址及一次性验证码注册账户,或通过 Google OAuth 2.0 关联 Google 账号登录。 + 您有责任妥善保管账户凭证,并对账户下发生的所有活动承担责任。 + 您须提供真实、准确、完整的注册信息,并保持信息更新。 + 对于包含虚假信息或存在欺诈行为的账户,我们保留暂停或注销的权利。 +

+ +

3. 积分与付费

+

+ 使用本服务的部分功能需要购买积分。积分是一种预付制虚拟货币,用于支付识别任务费用(图片转 LaTeX、PDF 转 Markdown、手写识别等)。 +

+
    +
  • 不予退款。除法律另有规定外,积分一经购买不予退款。若您认为被错误扣款,请在扣款后 30 天内联系我们。
  • +
  • 有效期。只要账户保持活跃,积分不会过期。我们保留引入有效期规则的权利,届时将提前至少 60 天通知。
  • +
  • 价格变动。我们可随时调整积分价格,但调整不影响已购积分。
  • +
  • 税费。您须自行承担所在地区购买积分时产生的适用税费。
  • +
  • 免费额度。访客用户可享有有限次数的免费识别任务,免费额度可能随时变更,恕不另行通知。
  • +
  • 拒付争议。在未事先联系我们的情况下发起拒付,可能导致账户被立即暂停。
  • +
+ +

4. 用户内容

+

+ 您对上传的文档、图片及文件("用户内容")保留全部知识产权。上传用户内容,即表示您授予 TexPixel + 有限的、非独占的、免版税的许可,以仅为提供服务之目的处理、存储和传输您的内容。 +

+
    +
  • 未经您明确同意,我们不会使用您的用户内容训练 AI 模型。
  • +
  • 除运营服务所必需(如云存储服务商)外,我们不会将您的用户内容分享给第三方。
  • +
  • 您须确保有权上传并处理所提交的任何内容。
  • +
  • 请勿上传违法、侵犯第三方权利,或在未经当事人同意的情况下包含他人个人身份信息的内容。
  • +
+ +

5. 识别结果免责声明

+

+ TexPixel 采用基于 AI 的识别技术。识别结果(LaTeX、Markdown、文本等)按"现状"提供。 + 我们不保证结果的准确性、完整性或适用于特定用途。 + 在将输出用于学术、专业或发表场景之前,您有责任自行核验所有结果。 +

+ +

6. 禁止行为

+

您同意不得:

+
    +
  • 使用本服务处理违法、淫秽、诽谤或侵犯第三方权利的内容。
  • +
  • 对服务进行逆向工程、反编译或尝试提取源代码。
  • +
  • 以超出套餐限额或影响其他用户体验的方式自动化发送请求。
  • +
  • 在未获得我们书面许可的情况下,利用本服务构建竞争性产品或服务。
  • +
  • 转让、出售或将账户或积分转移给他人。
  • +
  • 使用机器人、爬虫或自动化工具以超出 API 文档许可范围的方式访问服务。
  • +
  • 绕过我们为限制使用或执行本条款而采取的任何技术措施。
  • +
+ +

7. 知识产权

+

+ 本服务(包括软件、设计、商标及内容,但用户内容除外)归 TexPixel 所有,受适用知识产权法律保护。 + 未经我们事先书面同意,您不得复制、修改、分发、出售或出租服务的任何部分。 +

+ +

8. 第三方服务

+

+ 本服务集成了第三方服务,包括 Google(用于 OAuth 登录)、云对象存储服务商(用于文件存储)及支付处理商。 + 您对上述服务的使用同样受其各自条款和隐私政策约束。我们不对第三方服务的做法承担责任。 +

+ +

9. 免责声明

+

+ 本服务按"现状"和"可用状态"提供,不附带任何明示或暗示的保证, + 包括但不限于适销性、特定用途适用性及不侵权保证。 + 我们不保证服务不中断、无错误或绝对安全。 +

+ +

10. 责任限制

+

+ 在法律允许的最大范围内,TexPixel 不对因您使用本服务而产生的任何间接、附带、特殊、 + 后果性或惩罚性损害(包括数据丢失、利润损失或业务中断)承担责任, + 即便我们已被告知此类损害的可能性。 +

+

+ 我们就您使用本服务的任何索赔所承担的全部责任,不超过索赔发生前 12 个月内您向我们支付的金额。 +

+ +

11. 账户终止

+

+ 对于违反本条款或有害于其他用户、我们或第三方的行为,我们可随时暂停或注销相关账户,无需事先通知。 + 您可随时通过联系我们删除账户。账户终止后,您使用本服务的权利立即终止。 + 因违规而终止账户时,未使用的积分将被没收;主动注销账户时,剩余积分是否退款由我们自行决定。 +

+ +

12. 赔偿

+

+ 您同意就因您使用本服务、您的用户内容或您违反本条款而产生的任何索赔、责任、损害及费用 + (包括合理律师费),向 TexPixel 及其管理人员、董事、员工和代理人进行赔偿和辩护。 +

+ +

13. 适用法律与争议解决

+

+ 本条款受中华人民共和国法律管辖,不考虑法律冲突原则。 + 因本条款引发的争议,双方应首先进行善意协商。 + 若 30 天内未能解决,争议将提交仲裁或由 TexPixel 注册地的有管辖权的法院处理。 +

+ +

14. 条款变更

+

+ 我们可随时修改本条款。对于重大变更,我们将通过电子邮件或服务内显著通知的方式, + 在变更生效前至少 14 天提前告知您。变更生效后继续使用本服务,即表示您接受修订后的条款。 +

+ +

15. 联系我们

+

+ 如您对本条款有任何疑问,请通过{' '} + legal@texpixel.com 联系我们。 +

+ + ); +} diff --git a/src/routes/AppRouter.tsx b/src/routes/AppRouter.tsx index ec6d4c9..609678f 100644 --- a/src/routes/AppRouter.tsx +++ b/src/routes/AppRouter.tsx @@ -10,6 +10,11 @@ const DocsListPage = lazy(() => import('../pages/DocsListPage')); const DocDetailPage = lazy(() => import('../pages/DocDetailPage')); const BlogListPage = lazy(() => import('../pages/BlogListPage')); const BlogDetailPage = lazy(() => import('../pages/BlogDetailPage')); +const TermsPage = lazy(() => import('../pages/TermsPage')); +const PrivacyPage = lazy(() => import('../pages/PrivacyPage')); +const CookiePolicyPage = lazy(() => import('../pages/CookiePolicyPage')); +const AboutPage = lazy(() => import('../pages/AboutPage')); +const ContactPage = lazy(() => import('../pages/ContactPage')); function LoadingFallback() { return ( @@ -29,6 +34,11 @@ export default function AppRouter() { } /> } /> } /> + } /> + } /> + } /> + } /> + } /> }> } /> diff --git a/src/styles/landing.css b/src/styles/landing.css index ff8df0b..0c7ab17 100644 --- a/src/styles/landing.css +++ b/src/styles/landing.css @@ -1,7 +1,13 @@ /* Landing page CSS — scoped under .marketing-page to prevent workspace bleed */ /* Extracted from texpixel-landing.html, lines 10-1593 */ -.marketing-page *, .marketing-page *::before, .marketing-page *::after { box-sizing: border-box; margin: 0; padding: 0; } +.marketing-page *, +.marketing-page *::before, +.marketing-page *::after { + box-sizing: border-box; + margin: 0; + padding: 0; +} :root { --primary: #C8622A; @@ -18,8 +24,8 @@ --gold: #F3C96A; --rose: #F2A38C; --lavender: #B7AFE8; - --shadow-soft: 0 8px 24px rgba(198,134,85,0.10); - --shadow-float: 0 18px 40px rgba(220,195,175,0.30); + --shadow-soft: 0 8px 24px rgba(198, 134, 85, 0.10); + --shadow-float: 0 18px 40px rgba(220, 195, 175, 0.30); --r-s: 16px; --r-m: 20px; --r-l: 28px; @@ -65,20 +71,29 @@ will-change: transform; transform: translateZ(0); } + .glow-blob-1 { - width: 520px; height: 400px; - background: radial-gradient(circle, rgba(200,98,42,0.13) 0%, transparent 70%); - top: -100px; right: 60px; + width: 520px; + height: 400px; + background: radial-gradient(circle, rgba(200, 98, 42, 0.13) 0%, transparent 70%); + top: -100px; + right: 60px; } + .glow-blob-2 { - width: 400px; height: 360px; - background: radial-gradient(circle, rgba(140,201,190,0.13) 0%, transparent 70%); - bottom: 25%; left: -100px; + width: 400px; + height: 360px; + background: radial-gradient(circle, rgba(140, 201, 190, 0.13) 0%, transparent 70%); + bottom: 25%; + left: -100px; } + .glow-blob-3 { - width: 360px; height: 300px; - background: radial-gradient(circle, rgba(243,201,106,0.11) 0%, transparent 70%); - top: 50%; right: -80px; + width: 360px; + height: 300px; + background: radial-gradient(circle, rgba(243, 201, 106, 0.11) 0%, transparent 70%); + top: 50%; + right: -80px; } /* ── LAYOUT ── */ @@ -91,7 +106,10 @@ } .marketing-page section, -.marketing-page main { position: relative; z-index: 1; } +.marketing-page main { + position: relative; + z-index: 1; +} /* ── NAVBAR ── */ .marketing-page nav { @@ -99,7 +117,7 @@ top: 0; z-index: 100; height: 72px; - background: rgba(255,251,247,0.85); + background: rgba(255, 251, 247, 0.85); backdrop-filter: blur(16px); border-bottom: 1px solid var(--border); } @@ -123,7 +141,8 @@ } .logo-icon { - width: 38px; height: 38px; + width: 38px; + height: 38px; background: var(--primary); border-radius: 10px; display: flex; @@ -132,7 +151,8 @@ } .logo-icon svg { - width: 22px; height: 22px; + width: 22px; + height: 22px; fill: none; stroke: white; stroke-width: 2; @@ -189,7 +209,10 @@ cursor: pointer; transition: all 0.15s; } -.lang-switch:hover { color: var(--text-body); } + +.lang-switch:hover { + color: var(--text-body); +} .btn-cta { height: 52px; @@ -204,12 +227,13 @@ cursor: pointer; transition: all 0.2s ease; white-space: nowrap; - box-shadow: 0 2px 12px rgba(200,98,42,0.25); + box-shadow: 0 2px 12px rgba(200, 98, 42, 0.25); } + .btn-cta:hover { background: #A84E20; transform: translateY(-1px); - box-shadow: 0 6px 20px rgba(200,98,42,0.32); + box-shadow: 0 6px 20px rgba(200, 98, 42, 0.32); } /* ── BUTTONS ── */ @@ -233,12 +257,13 @@ .btn-primary { background: var(--primary); color: white; - box-shadow: 0 2px 14px rgba(200,98,42,0.28); + box-shadow: 0 2px 14px rgba(200, 98, 42, 0.28); } + .btn-primary:hover { background: #A84E20; transform: translateY(-1px); - box-shadow: 0 8px 24px rgba(200,98,42,0.36); + box-shadow: 0 8px 24px rgba(200, 98, 42, 0.36); } .btn-secondary { @@ -247,6 +272,7 @@ border: 1.5px solid var(--border); box-shadow: var(--shadow-soft); } + .btn-secondary:hover { border-color: var(--primary-light); transform: translateY(-1px); @@ -274,13 +300,16 @@ } .pill-dot { - width: 8px; height: 8px; + width: 8px; + height: 8px; border-radius: 50%; background: var(--teal); flex-shrink: 0; } -.pill-dot.orange { background: var(--primary); } +.pill-dot.orange { + background: var(--primary); +} /* ── EYEBROW ── */ .eyebrow { @@ -308,7 +337,9 @@ flex: 0 0 560px; } -.hero-pill { margin-bottom: 28px; } +.hero-pill { + margin-bottom: 28px; +} .hero-title { font-family: 'Lora', serif; @@ -367,7 +398,9 @@ font-weight: 500; } -.trust-item svg { flex-shrink: 0; } +.trust-item svg { + flex-shrink: 0; +} .social-proof { display: flex; @@ -380,7 +413,8 @@ } .avatar { - width: 36px; height: 36px; + width: 36px; + height: 36px; border-radius: 50%; border: 2px solid var(--bg); margin-right: -10px; @@ -392,10 +426,23 @@ color: white; } -.av1 { background: var(--teal); } -.av2 { background: var(--rose); } -.av3 { background: var(--gold); color: #6f5800; } -.av4 { background: var(--lavender); color: #3d3870; } +.av1 { + background: var(--teal); +} + +.av2 { + background: var(--rose); +} + +.av3 { + background: var(--gold); + color: #6f5800; +} + +.av4 { + background: var(--lavender); + color: #3d3870; +} .social-text { font-size: 14px; @@ -403,7 +450,9 @@ font-weight: 500; } -.social-text strong { color: var(--text-body); } +.social-text strong { + color: var(--text-body); +} /* ── MOCK WINDOW ── */ .hero-right { @@ -415,14 +464,21 @@ background: var(--elevated); border-radius: var(--r-l); border: 1.5px solid var(--border); - box-shadow: var(--shadow-float), 0 2px 0 rgba(200,98,42,0.06); + box-shadow: var(--shadow-float), 0 2px 0 rgba(200, 98, 42, 0.06); overflow: hidden; animation: float 6s ease-in-out infinite; } @keyframes float { - 0%, 100% { transform: translateY(0); } - 50% { transform: translateY(-8px); } + + 0%, + 100% { + transform: translateY(0); + } + + 50% { + transform: translateY(-8px); + } } .window-topbar { @@ -441,12 +497,22 @@ } .window-dot { - width: 11px; height: 11px; + width: 11px; + height: 11px; border-radius: 50%; } -.wd-red { background: #FF6059; } -.wd-yellow { background: #FFBD2E; } -.wd-green { background: #29C940; } + +.wd-red { + background: #FF6059; +} + +.wd-yellow { + background: #FFBD2E; +} + +.wd-green { + background: #29C940; +} .window-url { flex: 1; @@ -464,7 +530,8 @@ } .url-lock { - width: 10px; height: 12px; + width: 10px; + height: 12px; fill: var(--teal); flex-shrink: 0; } @@ -476,45 +543,63 @@ gap: 16px; } -.upload-zone { - border: 1.5px dashed var(--border); - border-radius: var(--r-m); - padding: 28px 20px; - text-align: center; - background: var(--bg); - transition: border-color 0.2s; -} - -.upload-zone:hover { border-color: var(--primary-light); } - -.upload-icon-wrap { - width: 48px; height: 48px; - background: var(--warm-wash); - border-radius: 14px; +/* ── UPLOAD PREVIEW (hero demo) ── */ +.upload-zone-preview { + position: relative; + height: 148px; display: flex; align-items: center; justify-content: center; - margin: 0 auto 12px; + border-style: dashed; + border-color: var(--border); + background: var(--bg); + overflow: hidden; } -.upload-icon-wrap svg { - width: 24px; height: 24px; - stroke: var(--primary); - fill: none; - stroke-width: 1.8; +.upload-preview-img { + position: absolute; + height: 110px; + width: auto; + max-width: 80%; + object-fit: contain; + border-radius: 6px; + box-shadow: 0 2px 12px rgba(0,0,0,0.10); + background: white; + opacity: 0; + transition: opacity 0.5s ease; + pointer-events: none; } -.upload-text { - font-size: 13px; - color: var(--text-body); - font-weight: 500; - line-height: 1.5; +.upload-preview-img.upload-preview-active { + opacity: 1; + pointer-events: auto; } -.upload-sub { - font-size: 12px; - color: var(--text-muted); - margin-top: 4px; +.window-slide-dots { + display: flex; + justify-content: center; + gap: 6px; + padding: 8px 0 4px; +} + +.window-dot-btn { + width: 6px; + height: 6px; + border-radius: 50%; + border: none; + background: var(--border); + cursor: pointer; + padding: 0; + transition: background 0.2s, transform 0.2s; +} + +.window-dot-btn.window-dot-active { + background: var(--primary); + transform: scale(1.3); +} + +.window-dot-btn:hover { + background: var(--primary-light); } .output-zone { @@ -551,23 +636,36 @@ .output-badge::before { content: ''; - width: 6px; height: 6px; + width: 6px; + height: 6px; background: var(--teal); border-radius: 50%; } .output-code { - padding: 16px; + padding: 12px 16px; font-family: 'JetBrains Mono', monospace; - font-size: 14px; + font-size: 12.5px; color: var(--text-strong); - line-height: 1.7; - min-height: 72px; + line-height: 1.55; + height: 72px; + overflow: hidden; + position: relative; } -.code-comment { color: var(--text-muted); font-style: italic; font-size: 12px; } -.code-kw { color: var(--primary); } -.code-num { color: var(--teal); } +.code-comment { + color: var(--text-muted); + font-style: italic; + font-size: 12px; +} + +.code-kw { + color: var(--primary); +} + +.code-num { + color: var(--teal); +} .output-actions { padding: 10px 16px; @@ -593,12 +691,14 @@ color: white; } -.output-btn-copy:hover { background: #A84E20; } +.output-btn-copy:hover { + background: #A84E20; +} .output-btn-word { background: var(--warm-wash); color: var(--primary); - border: 1px solid rgba(200,98,42,0.2); + border: 1px solid rgba(200, 98, 42, 0.2); } .window-status { @@ -692,7 +792,8 @@ } .card-icon { - width: 54px; height: 54px; + width: 54px; + height: 54px; border-radius: 16px; display: flex; align-items: center; @@ -700,19 +801,36 @@ margin-bottom: 20px; } -.icon-orange { background: var(--warm-wash); } -.icon-teal { background: rgba(140,201,190,0.15); } -.icon-lavender { background: rgba(183,175,232,0.15); } +.icon-orange { + background: var(--warm-wash); +} + +.icon-teal { + background: rgba(140, 201, 190, 0.15); +} + +.icon-lavender { + background: rgba(183, 175, 232, 0.15); +} .card-icon svg { - width: 26px; height: 26px; + width: 26px; + height: 26px; fill: none; stroke-width: 1.8; } -.icon-orange svg { stroke: var(--primary); } -.icon-teal svg { stroke: var(--teal); } -.icon-lavender svg { stroke: var(--lavender); } +.icon-orange svg { + stroke: var(--primary); +} + +.icon-teal svg { + stroke: var(--teal); +} + +.icon-lavender svg { + stroke: var(--lavender); +} .card-title { font-family: 'Lora', serif; @@ -740,12 +858,14 @@ gap: 4px; } -.card-link:hover { gap: 8px; } +.card-link:hover { + gap: 8px; +} /* ── CORE FEATURES ── */ .core-features { padding: 96px 0; - background: linear-gradient(180deg, transparent, rgba(200,98,42,0.03), transparent); + background: linear-gradient(180deg, transparent, rgba(200, 98, 42, 0.03), transparent); } .feature-card { @@ -781,14 +901,22 @@ .feature-mini::before { content: ''; position: absolute; - top: 0; left: 0; right: 0; + top: 0; + left: 0; + right: 0; height: 2px; background: linear-gradient(90deg, transparent, var(--primary), transparent); } -.feature-speed { color: var(--teal); font-weight: 600; font-size: 20px; } +.feature-speed { + color: var(--teal); + font-weight: 600; + font-size: 20px; +} -.feature-card .card-title { margin-bottom: 6px; } +.feature-card .card-title { + margin-bottom: 6px; +} /* ── EXAMPLE SHOWCASE ── */ .showcase { @@ -885,9 +1013,17 @@ line-height: 1.7; } -.sc-output .kw { color: #C8622A; } -.sc-output .num { color: #6ee7b7; } -.sc-output .br { color: #c4b5fd; } +.sc-output .kw { + color: #C8622A; +} + +.sc-output .num { + color: #6ee7b7; +} + +.sc-output .br { + color: #c4b5fd; +} .showcase-footer { padding: 0 28px 28px; @@ -933,7 +1069,8 @@ } .map-dot { - width: 12px; height: 12px; + width: 12px; + height: 12px; border-radius: 50%; animation: pulse-dot 2s ease-in-out infinite; position: relative; @@ -947,8 +1084,29 @@ animation: pulse-ring 2s ease-in-out infinite; } -@keyframes pulse-dot { 0%,100%{transform:scale(1)} 50%{transform:scale(1.15)} } -@keyframes pulse-ring { 0%{opacity:0.6;transform:scale(1)} 100%{opacity:0;transform:scale(2.4)} } +@keyframes pulse-dot { + + 0%, + 100% { + transform: scale(1) + } + + 50% { + transform: scale(1.15) + } +} + +@keyframes pulse-ring { + 0% { + opacity: 0.6; + transform: scale(1) + } + + 100% { + opacity: 0; + transform: scale(2.4) + } +} .map-label { font-size: 11px; @@ -961,17 +1119,37 @@ color: var(--text-body); } -.dot-china { background: var(--primary); } -.dot-china::after { background: var(--primary); } +.dot-china { + background: var(--primary); +} -.dot-us { background: var(--teal); } -.dot-us::after { background: var(--teal); } +.dot-china::after { + background: var(--primary); +} -.dot-eu { background: var(--lavender); } -.dot-eu::after { background: var(--lavender); } +.dot-us { + background: var(--teal); +} -.dot-jp { background: var(--rose); } -.dot-jp::after { background: var(--rose); } +.dot-us::after { + background: var(--teal); +} + +.dot-eu { + background: var(--lavender); +} + +.dot-eu::after { + background: var(--lavender); +} + +.dot-jp { + background: var(--rose); +} + +.dot-jp::after { + background: var(--rose); +} .map-stat { margin-top: 32px; @@ -992,11 +1170,34 @@ padding: 96px 0; } +/* Beta notice */ +.pricing-beta-notice { + display: flex; + align-items: center; + justify-content: center; + gap: 10px; + background: rgba(22, 163, 74, 0.08); + border: 1px solid rgba(22, 163, 74, 0.22); + border-radius: var(--r-m); + padding: 12px 20px; + font-size: 13.5px; + font-weight: 500; + color: #15803d; + margin-bottom: 32px; + text-align: center; + line-height: 1.5; +} + +.pricing-beta-icon { + font-size: 16px; + flex-shrink: 0; +} + .pricing-cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; - align-items: start; + align-items: stretch; } .pricing-card { @@ -1006,6 +1207,10 @@ padding: 28px 24px; box-shadow: var(--shadow-soft); transition: all 0.22s ease; + position: relative; + overflow: hidden; + display: flex; + flex-direction: column; } .pricing-card:hover { @@ -1016,14 +1221,23 @@ .pricing-card.featured { background: linear-gradient(160deg, #FFF4EC, #FFFBF7); border: 2px solid var(--primary); - position: relative; - padding-top: 40px; - box-shadow: 0 8px 32px rgba(200,98,42,0.15); + padding-top: 44px; + box-shadow: 0 8px 32px rgba(200, 98, 42, 0.15); +} + +/* Desktop / Lifetime card */ +.pricing-card-desktop { + border: 1.5px solid rgba(200, 98, 42, 0.35); +} + +.pricing-card-desktop:hover { + border-color: rgba(200, 98, 42, 0.55); } .featured-badge { position: absolute; - top: -1px; left: 50%; + top: 0; + left: 50%; transform: translateX(-50%); background: var(--primary); color: white; @@ -1032,6 +1246,52 @@ padding: 5px 16px; border-radius: 0 0 12px 12px; letter-spacing: 0.04em; + white-space: nowrap; + z-index: 2; +} + +/* Diagonal corner ribbon */ +.plan-ribbon { + position: absolute; + top: 20px; + right: -34px; + width: 130px; + padding: 6px 0; + font-size: 11px; + font-weight: 800; + text-align: center; + transform: rotate(45deg); + letter-spacing: 0.06em; + pointer-events: none; + z-index: 3; +} + +.plan-ribbon-free { + background: #16a34a; + color: #fff; + box-shadow: 0 2px 10px rgba(22, 163, 74, 0.45); +} + +.plan-ribbon-soon { + background: #94a3b8; + color: #fff; + box-shadow: 0 2px 8px rgba(100, 116, 139, 0.3); +} + +/* Desktop tag badge */ +.plan-desktop-tag { + display: inline-flex; + align-items: center; + gap: 5px; + font-size: 11px; + font-weight: 700; + padding: 4px 10px; + border-radius: 20px; + margin-bottom: 12px; + letter-spacing: 0.04em; + background: rgba(200, 98, 42, 0.1); + color: var(--primary); + border: 1px solid rgba(200, 98, 42, 0.25); } .plan-name { @@ -1053,15 +1313,35 @@ } .plan-price span { - font-size: 22px; + font-size: 16px; color: var(--text-muted); font-weight: 600; + letter-spacing: 0; + font-family: 'DM Sans', sans-serif; } .plan-period { font-size: 13px; color: var(--text-muted); - margin-bottom: 16px; + margin-bottom: 8px; +} + +.plan-edu-price { + font-size: 12px; + color: var(--teal); + font-weight: 600; + margin-bottom: 20px; + padding: 4px 10px; + background: rgba(140, 201, 190, 0.12); + border-radius: 6px; + display: inline-block; +} + +.plan-edu-price-placeholder { + background: transparent; + color: transparent; + pointer-events: none; + user-select: none; } .plan-desc { @@ -1069,7 +1349,6 @@ color: var(--text-body); line-height: 1.55; margin-bottom: 24px; - min-height: 48px; } .plan-features { @@ -1078,6 +1357,7 @@ display: flex; flex-direction: column; gap: 8px; + flex: 1; } .plan-features li { @@ -1090,8 +1370,9 @@ .plan-features li::before { content: '✓'; - width: 18px; height: 18px; - background: rgba(140,201,190,0.2); + width: 18px; + height: 18px; + background: rgba(140, 201, 190, 0.2); color: var(--teal); border-radius: 50%; display: flex; @@ -1105,7 +1386,7 @@ } .featured .plan-features li::before { - background: rgba(200,98,42,0.12); + background: rgba(200, 98, 42, 0.12); color: var(--primary); } @@ -1136,7 +1417,7 @@ background: var(--primary); color: white; border-color: transparent; - box-shadow: 0 4px 16px rgba(200,98,42,0.28); + box-shadow: 0 4px 16px rgba(200, 98, 42, 0.28); } .plan-btn.featured-btn:hover { @@ -1144,6 +1425,24 @@ transform: translateY(-1px); } +.plan-btn-desktop-disabled { + display: block; + width: 100%; + height: 52px; + border-radius: var(--r-m); + font-size: 15px; + font-weight: 600; + font-family: 'DM Sans', sans-serif; + cursor: not-allowed; + opacity: 0.45; + background: var(--elevated); + color: var(--text-muted); + border: 1.5px solid var(--border); + box-shadow: none; + text-align: center; + line-height: 52px; +} + /* ── DOCS SEO ── */ .docs-seo { padding: 96px 0; @@ -1182,7 +1481,8 @@ } .doc-icon { - width: 44px; height: 44px; + width: 44px; + height: 44px; background: var(--bg); border: 1px solid var(--border); border-radius: 12px; @@ -1193,7 +1493,8 @@ } .doc-icon svg { - width: 20px; height: 20px; + width: 20px; + height: 20px; stroke: var(--primary); fill: none; stroke-width: 1.8; @@ -1282,7 +1583,9 @@ transition: color 0.15s; } -.footer-links a:hover { color: var(--primary); } +.footer-links a:hover { + color: var(--primary); +} .footer-bottom { border-top: 1px solid var(--border); @@ -1306,23 +1609,51 @@ } .footer-made svg { - width: 14px; height: 14px; + width: 14px; + height: 14px; fill: var(--rose); } /* ── HERO LOAD ANIMATION ── */ @keyframes fadeUp { - from { opacity: 0; transform: translateY(20px); } - to { opacity: 1; transform: none; } + from { + opacity: 0; + transform: translateY(20px); + } + + to { + opacity: 1; + transform: none; + } } -.hero-pill { animation: fadeUp 0.5s ease both; } -.hero-title { animation: fadeUp 0.55s ease 0.08s both; } -.hero-desc { animation: fadeUp 0.55s ease 0.16s both; } -.hero-actions { animation: fadeUp 0.55s ease 0.22s both; } -.hero-trust { animation: fadeUp 0.55s ease 0.28s both; } -.social-proof { animation: fadeUp 0.55s ease 0.34s both; } -.mock-window { animation: fadeUp 0.6s ease 0.18s both; } +.hero-pill { + animation: fadeUp 0.5s ease both; +} + +.hero-title { + animation: fadeUp 0.55s ease 0.08s both; +} + +.hero-desc { + animation: fadeUp 0.55s ease 0.16s both; +} + +.hero-actions { + animation: fadeUp 0.55s ease 0.22s both; +} + +.hero-trust { + animation: fadeUp 0.55s ease 0.28s both; +} + +.social-proof { + animation: fadeUp 0.55s ease 0.34s both; +} + +.mock-window { + animation: fadeUp 0.6s ease 0.18s both; +} /* ── DIVIDER ── */ .section-divider { @@ -1343,10 +1674,13 @@ } /* ── NAV AVATAR & USER MENU ── */ -.nav-user { position: relative; } +.nav-user { + position: relative; +} .nav-avatar { - width: 38px; height: 38px; + width: 38px; + height: 38px; border-radius: 50%; border: 1.5px solid var(--border); background: var(--card); @@ -1358,8 +1692,16 @@ color: var(--text-muted); } -.nav-avatar svg { width: 20px; height: 20px; } -.nav-avatar:hover { border-color: var(--primary-light); color: var(--primary); background: var(--warm-wash); } +.nav-avatar svg { + width: 20px; + height: 20px; +} + +.nav-avatar:hover { + border-color: var(--primary-light); + color: var(--primary); + background: var(--warm-wash); +} .nav-user-menu { position: absolute; @@ -1382,7 +1724,8 @@ } .nav-menu-avatar { - width: 34px; height: 34px; + width: 34px; + height: 34px; border-radius: 50%; background: var(--teal); color: #1a5c54; @@ -1425,12 +1768,37 @@ cursor: pointer; } -.nav-menu-item:hover { background: var(--bg); color: var(--text-strong); } -.nav-menu-item svg { color: var(--text-muted); flex-shrink: 0; } -.nav-menu-logout { color: #b84040; } -.nav-menu-logout:hover { background: #fff0f0; color: #b84040; } +.nav-menu-item:hover { + background: var(--bg); + color: var(--text-strong); +} -.nav-login-btn .btn-cta { height: 40px; font-size: 14px; padding: 0 18px; border-radius: 12px; } +.nav-menu-item svg { + color: var(--text-muted); + flex-shrink: 0; +} + +.nav-menu-logout { + color: #b84040; +} + +.nav-menu-logout:hover { + background: #fff0f0; + color: #b84040; +} + +.nav-login-btn .btn-cta { + height: 40px; + font-size: 14px; + padding: 0 18px; + border-radius: 12px; + display: inline-flex; + align-items: center; + justify-content: center; + line-height: 1; + text-decoration: none; + box-sizing: border-box; +} /* ── TESTIMONIAL CAROUSEL ── */ .testimonial-wrap { @@ -1442,7 +1810,7 @@ display: grid; grid-template-columns: repeat(6, calc(33.333% - 14px)); gap: 20px; - transition: transform 0.45s cubic-bezier(0.4,0,0.2,1); + transition: transform 0.45s cubic-bezier(0.4, 0, 0.2, 1); } .testimonial-card { @@ -1458,7 +1826,9 @@ transition: box-shadow 0.2s; } -.testimonial-card:hover { box-shadow: var(--shadow-float); } +.testimonial-card:hover { + box-shadow: var(--shadow-float); +} .t-quote { font-family: 'Lora', serif; @@ -1485,7 +1855,8 @@ } .t-avatar { - width: 36px; height: 36px; + width: 36px; + height: 36px; border-radius: 50%; font-size: 14px; font-weight: 700; @@ -1524,7 +1895,8 @@ } .t-nav-btn { - width: 36px; height: 36px; + width: 36px; + height: 36px; border-radius: 50%; border: 1.5px solid var(--border); background: var(--elevated); @@ -1549,7 +1921,8 @@ } .t-dot { - width: 6px; height: 6px; + width: 6px; + height: 6px; border-radius: 50%; background: var(--border); transition: all 0.2s; @@ -1574,11 +1947,29 @@ transform: translateY(0); } -.reveal-delay-1 { transition-delay: 0.10s; } -.reveal-delay-2 { transition-delay: 0.20s; } -.reveal-delay-3 { transition-delay: 0.30s; } +.reveal-delay-1 { + transition-delay: 0.10s; +} -@keyframes blink { 0%,100%{opacity:1} 50%{opacity:0} } +.reveal-delay-2 { + transition-delay: 0.20s; +} + +.reveal-delay-3 { + transition-delay: 0.30s; +} + +@keyframes blink { + + 0%, + 100% { + opacity: 1 + } + + 50% { + opacity: 0 + } +} /* ═══════════════════════════════════════════════════════ DOCS PAGES @@ -1756,7 +2147,9 @@ font-weight: 500; } -.docs-back-link:hover { color: var(--primary); } +.docs-back-link:hover { + color: var(--primary); +} .docs-back-link svg { width: 15px; @@ -1798,7 +2191,9 @@ flex-wrap: wrap; } -.docs-meta-sep { opacity: 0.4; } +.docs-meta-sep { + opacity: 0.4; +} /* ── Docs prose body ── */ .docs-prose { @@ -1808,7 +2203,9 @@ color: var(--text-body); } -.docs-prose > h1:first-child { display: none; } +.docs-prose>h1:first-child { + display: none; +} .docs-prose h2 { font-family: 'Lora', serif; @@ -1836,7 +2233,9 @@ margin: 24px 0 8px; } -.docs-prose p { margin-bottom: 20px; } +.docs-prose p { + margin-bottom: 20px; +} .docs-prose ul, .docs-prose ol { @@ -1844,7 +2243,9 @@ margin-bottom: 20px; } -.docs-prose li { margin-bottom: 8px; } +.docs-prose li { + margin-bottom: 8px; +} .docs-prose strong { color: var(--text-strong); @@ -1858,7 +2259,9 @@ text-underline-offset: 3px; } -.docs-prose a:hover { text-decoration-color: var(--primary); } +.docs-prose a:hover { + text-decoration-color: var(--primary); +} .docs-prose code { font-family: 'JetBrains Mono', monospace; @@ -1924,7 +2327,9 @@ vertical-align: top; } -.docs-prose tr:nth-child(even) td { background: var(--bg); } +.docs-prose tr:nth-child(even) td { + background: var(--bg); +} .docs-prose .katex-display { margin: 32px 0; @@ -1975,8 +2380,15 @@ } @keyframes skeleton-pulse { - 0%, 100% { opacity: 0.7; } - 50% { opacity: 0.35; } + + 0%, + 100% { + opacity: 0.7; + } + + 50% { + opacity: 0.35; + } } /* ════════════════════════════════════════ @@ -2029,7 +2441,7 @@ content: ''; position: absolute; inset: 0; - background: linear-gradient(135deg, rgba(200,98,42,0.04) 0%, transparent 60%); + background: linear-gradient(135deg, rgba(200, 98, 42, 0.04) 0%, transparent 60%); pointer-events: none; } @@ -2158,10 +2570,18 @@ } @media (max-width: 640px) { - .blog-grid { grid-template-columns: 1fr; } - .blog-featured { padding: 24px; } - .blog-page { padding: 40px 16px 64px; } + .blog-grid { + grid-template-columns: 1fr; + } + + .blog-featured { + padding: 24px; + } + + .blog-page { + padding: 40px 16px 64px; + } } /* ── Blog detail page (reuses .docs-detail, .docs-back-link, - .docs-prose, .docs-cta-box, .docs-skeleton-wrap) ── */ + .docs-prose, .docs-cta-box, .docs-skeleton-wrap) ── */ \ No newline at end of file