steelforesight/src/pages/Pulse/Pulse.tsx

581 lines
28 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { useState, useEffect } from 'react'
import { useLang } from '@/context/LangContext'
import SnapshotBar from '@/pages/Home/sections/SnapshotBar'
const STATS = {
fa: [
{ label: 'تولید فولاد خام', value: '۳۱.۲', unit: 'میلیون تن', delta: '+۴.۱٪' },
{ label: 'صادرات فولاد', value: '۸.۷', unit: 'میلیون تن', delta: '+۱.۸٪' },
{ label: 'واردات سنگ‌آهن', value: '۱۲.۴', unit: 'میلیون تن', delta: '-۲.۳٪' },
{ label: 'ظرفیت نصب‌شده', value: '۳۸', unit: 'میلیون تن', delta: '—' },
],
en: [
{ label: 'Crude Steel Production', value: '31.2', unit: 'Million tons', delta: '+4.1%' },
{ label: 'Steel Exports', value: '8.7', unit: 'Million tons', delta: '+1.8%' },
{ label: 'Iron Ore Imports', value: '12.4', unit: 'Million tons', delta: '-2.3%' },
{ label: 'Installed Capacity', value: '38', unit: 'Million tons', delta: '—' },
],
}
const T = {
fa: {
overline: 'MARKET & STEEL CHAIN', heading: 'بازار و زنجیره فولاد',
sub: 'سامانه جامع آمار و اطلاعات صنعت فولاد ایران — داده‌های لحظه‌ای تولید، صادرات، واردات و قیمت‌ها',
statsLabel: 'آمار کلیدی صنعت · ۱۴۰۳',
gateAccess: 'دسترسی اعضا',
gateHeading: 'دسترسی کامل به سامانه بازار و زنجیره فولاد',
gateSub: 'اعضای اندیشکده به پایگاه داده جامع فولاد ایران شامل آمار لحظه‌ای تولید، صادرات، واردات، قیمت‌های داخلی و بین‌المللی و ۵۰۰+ شاخص صنعتی دسترسی دارند.',
features: [
'داده‌های لحظه‌ای تولید کارخانه‌های بزرگ',
'آمار صادرات تفکیک‌شده بر اساس کشور مقصد',
'نمودارهای تعاملی و قابل دانلود',
'گزارش‌های تحلیلی ماهانه اختصاصی',
],
cta: 'درخواست عضویت سازمانی ←',
ctaDone: '✓ درخواست شما ثبت شد. تیم ما ظرف ۴۸ ساعت با شما تماس می‌گیرد.',
},
en: {
overline: 'MARKET & STEEL CHAIN', heading: 'Market & Steel Chain',
sub: 'Comprehensive statistics and data platform for Iran\'s steel industry — live production, export, import, and price data',
statsLabel: 'KEY INDUSTRY STATS · 1403',
gateAccess: 'MEMBERS ONLY',
gateHeading: 'Full Access to Market & Steel Chain',
gateSub: 'Institute members have access to Iran\'s comprehensive steel database including live production stats, export/import data, domestic and international prices, and 500+ industrial indicators.',
features: [
'Real-time production data from major plants',
'Export statistics broken down by destination country',
'Interactive downloadable charts',
'Exclusive monthly analytical reports',
],
cta: 'Request Organizational Membership →',
ctaDone: '✓ Your request has been received. Our team will contact you within 48 hours.',
},
}
const TX = {
fa: {
tableHeaders: ['عنوان', 'بیشترین', 'کمترین', 'آخرین', '۳۰ روز', '۶۰ روز', '۹۰ روز', '۱۸۰ روز', '۳۶۰ روز'],
paywallCta: 'برای مشاهده کامل، عضویت سازمانی دریافت کنید ←',
coverageTitle: 'پوشش قیمتی زنجیره فولاد',
productLabel: 'محصول', indexLabel: 'شاخص', sourceLabel: 'منبع داده',
membersOnly: 'MEMBERS ONLY',
coverageDesc: 'دسترسی کامل به قیمت‌های لحظه‌ای، تاریخی و گزارش‌های تحلیلی هفتگی برای تمام محصولات.',
coverageFeatures: ['قیمت‌های لحظه‌ای و تاریخی', 'گزارش‌های هفتگی اختصاصی', 'نمودارهای تعاملی دانلودی', 'پشتیبانی تحلیلی'],
sectionsLabel: 'حوزه‌های پوشش',
contentSections: ['صنعت فولاد', 'بازار سرمایه', 'فلزات و کامودیتی', 'ارزهای دیجیتال', 'بازار ارز و طلا', 'اقتصاد کلان'],
dsTitle: 'دسترسی به گزارش‌های Platts، Fastmarkets و منابع برتر جهانی',
dsBody: 'بیشتر سازمان‌های ایرانی به این منابع دسترسی ندارند — اشتراک جداگانه‌شان چندین هزار دلار در سال هزینه دارد. اعضای اندیشکده از گزارش‌های روزانه و هفتگی Platts، Fastmarkets، Bainfo China و Dlpibica بهره‌مند می‌شوند؛ داده‌هایی که مستقیماً قیمت‌گذاری، خرید و تصمیمات صادراتی را تغییر می‌دهند.',
requestBtn: 'درخواست عضویت سازمانی ←',
contactNote: 'تیم ما ظرف ۴۸ ساعت تماس می‌گیرد',
},
en: {
tableHeaders: ['Title', 'High', 'Low', 'Last', '30D', '60D', '90D', '180D', '360D'],
paywallCta: 'Subscribe for full access →',
coverageTitle: 'Steel Chain Price Coverage',
productLabel: 'Products', indexLabel: 'Indicators', sourceLabel: 'Data Sources',
membersOnly: 'MEMBERS ONLY',
coverageDesc: 'Full access to real-time, historical prices and weekly analytical reports for all products.',
coverageFeatures: ['Real-time & historical prices', 'Exclusive weekly reports', 'Interactive downloadable charts', 'Dedicated analytical support'],
sectionsLabel: 'Coverage Areas',
contentSections: ['Steel Industry', 'Capital Markets', 'Metals & Commodities', 'Digital Assets', 'FX & Gold', 'Macro Economy'],
dsTitle: 'Access to Platts, Fastmarkets and Top Global Data Sources',
dsBody: 'Most Iranian organizations lack direct access to these sources — individual subscriptions cost thousands of dollars per year. Institute members benefit from daily and weekly reports from Platts, Fastmarkets, Bainfo China, and Dlpibica; data that directly impacts pricing, procurement, and export decisions.',
requestBtn: 'Request Organizational Membership →',
contactNote: 'Our team will contact you within 48 hours',
},
}
const SLIDES = Array.from({ length: 13 }, (_, i) => `/${i + 1}.jpg`)
/* ─── price table data ───────────────────────────────────── */
const PRICE_TABLE_ROWS = [
{ title: 'سنگ نیکل - Carbonate, Mn ۱۳%min EXW China', high: 855.06, low: 898.57, last: 739.35, d30: 9.99, d60: 7.89, d90: 5.23, d180: -6.92, d360: 7.88 },
{ title: 'فرو نیکل - S.A. ۳۶%min In Qinzhou Port', high: 892.53, low: 826.70, last: 751.05, d30: -6.31, d60: 8.48, d90: 2.43, d180: 5.13, d360: 3.89 },
{ title: 'کاند نیکل - Carbonate, Mn ۱۳%min EXW China', high: 804.93, low: 801.05, last: 961.74, d30: -6.35, d60: 0.12, d90: 4.44, d180: 6.81, d360: 5.95 },
{ title: 'سنگ نیکل - S.A. ۳۷%min In Qinzhou Port', high: 774.65, low: 759.59, last: 742.73, d30: -6.03, d60: -5.78, d90: 1.21, d180: 5.82, d360: 5.47 },
{ title: 'سولفات نیکل - Gabonese ۴۴%min In Qinzhou Port', high: 873.00, low: 895.82, last: 720.87, d30: -9.57, d60: 5.91, d90: 8.58, d180: 9.15, d360: -2.43 },
{ title: 'کاند نیکل - Carbonate, Mn ۱۳%min EXW China', high: 926.83, low: 825.50, last: 745.22, d30: -5.03, d60: -1.54, d90: -0.53, d180: -5.85, d360: 5.54 },
{ title: 'فرو نیکل - min FOB S.A.%۳۸', high: 885.21, low: 753.25, last: 753.76, d30: 3.45, d60: 1.07, d90: 8.25, d180: -7.04, d360: -1.44 },
{ title: 'فرو نیکل - Carbonate, Mn ۱۳%min EXW China', high: 786.10, low: 739.25, last: 939.99, d30: 8.78, d60: -0.53, d90: 8.58, d180: -9.65, d360: 2.88 },
]
function PctCell({ v }: { v: number }) {
const pos = v > 0
const zero = v === 0
return (
<td style={{
padding: '10px 12px',
textAlign: 'center',
background: zero ? 'transparent' : pos ? 'rgba(46,160,67,0.15)' : 'rgba(218,54,51,0.13)',
color: zero ? 'var(--ink-4)' : pos ? '#1a7f37' : '#cf222e',
fontWeight: 700,
fontSize: 12,
fontVariantNumeric: 'tabular-nums',
whiteSpace: 'nowrap',
}}>
{v > 0 ? '+' : ''}{v.toFixed(2)}
</td>
)
}
function PriceTable({ blurFrom, lang }: { blurFrom: number; lang: 'fa' | 'en' }) {
const tx = TX[lang]
return (
<div style={{ marginBottom: 48, position: 'relative', border: '1px solid var(--rule-thin)', overflowX: 'auto' }}>
<table style={{ width: '100%', borderCollapse: 'collapse', fontSize: 12, direction: 'rtl', minWidth: 820 }}>
<thead>
<tr style={{ background: 'rgba(7,29,73,0.06)', borderBottom: '2px solid var(--ink)' }}>
{tx.tableHeaders.map((h, i) => (
<th key={h} style={{
padding: '12px 14px',
textAlign: i === 0 ? 'right' : 'center',
fontWeight: 700,
fontSize: 11,
color: 'var(--ink-3)',
whiteSpace: 'nowrap',
}}>{h}</th>
))}
</tr>
</thead>
<tbody>
{PRICE_TABLE_ROWS.map((row, i) => {
const shouldBlur = i >= blurFrom
return (
<tr
key={i}
style={{
borderBottom: '1px solid var(--rule-thin)',
background: i % 2 === 0 ? 'var(--paper)' : 'var(--paper-2)',
filter: shouldBlur ? 'blur(4px)' : 'none',
userSelect: shouldBlur ? 'none' : 'auto',
pointerEvents: shouldBlur ? 'none' : 'auto',
}}
>
<td style={{ padding: '10px 14px', fontWeight: 500, color: 'var(--ink)', fontSize: 11.5, direction: 'rtl', whiteSpace: 'nowrap' }}>{row.title}</td>
<td style={{ padding: '10px 12px', textAlign: 'center', fontWeight: 700, fontVariantNumeric: 'tabular-nums', whiteSpace: 'nowrap' }}>{row.high.toFixed(2)}</td>
<td style={{ padding: '10px 12px', textAlign: 'center', fontVariantNumeric: 'tabular-nums', whiteSpace: 'nowrap' }}>{row.low.toFixed(2)}</td>
<td style={{ padding: '10px 12px', textAlign: 'center', fontWeight: 700, fontVariantNumeric: 'tabular-nums', whiteSpace: 'nowrap' }}>{row.last.toFixed(2)}</td>
<PctCell v={row.d30} />
<PctCell v={row.d60} />
<PctCell v={row.d90} />
<PctCell v={row.d180} />
<PctCell v={row.d360} />
</tr>
)
})}
</tbody>
</table>
{/* paywall overlay over blurred rows */}
<div style={{
position: 'absolute',
bottom: 0,
left: 0,
right: 0,
height: `${((PRICE_TABLE_ROWS.length - blurFrom) / PRICE_TABLE_ROWS.length) * 100}%`,
background: 'linear-gradient(to bottom, transparent 0%, rgba(var(--paper-rgb,255,255,255),0.7) 40%)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
pointerEvents: 'none',
}}>
<div style={{
background: 'var(--ink)',
color: 'var(--paper)',
padding: '8px 20px',
fontSize: 11,
fontWeight: 700,
letterSpacing: '1.5px',
pointerEvents: 'auto',
}}>
{tx.paywallCta}
</div>
</div>
</div>
)
}
function ImageSlider() {
const [current, setCurrent] = useState(0)
useEffect(() => {
const id = setInterval(() => setCurrent(c => (c + 1) % SLIDES.length), 3500)
return () => clearInterval(id)
}, [])
return (
<div style={{ position: 'relative', overflow: 'hidden', border: '1px solid var(--rule-thin)', background: '#000', height: '100%' }}>
{/* Slides */}
{SLIDES.map((src, i) => (
<img
key={src}
src={src}
alt=""
aria-hidden="true"
style={{
position: i === 0 ? 'relative' : 'absolute',
inset: 0, width: '100%',
height: i === 0 ? 'auto' : '100%',
objectFit: 'cover', display: 'block',
userSelect: 'none', pointerEvents: 'none',
opacity: i === current ? 1 : 0,
transition: 'opacity 0.8s ease',
}}
/>
))}
{/* Radial blur overlay */}
<div style={{
position: 'absolute', inset: 0,
backdropFilter: 'blur(10px)',
WebkitBackdropFilter: 'blur(10px)',
maskImage: 'radial-gradient(ellipse 55% 45% at 50% 50%, transparent 25%, black 72%)',
WebkitMaskImage: 'radial-gradient(ellipse 55% 45% at 50% 50%, transparent 25%, black 72%)',
}} />
{/* Vignette */}
<div style={{
position: 'absolute', inset: 0,
background: 'radial-gradient(ellipse 70% 60% at 50% 50%, transparent 30%, rgba(7,29,73,0.55) 100%)',
}} />
{/* Dot indicators */}
<div style={{
position: 'absolute', bottom: 12, left: '50%', transform: 'translateX(-50%)',
display: 'flex', gap: 6, zIndex: 10,
}}>
{SLIDES.map((_, i) => (
<button
key={i}
onClick={() => setCurrent(i)}
style={{
width: i === current ? 18 : 6, height: 6,
background: i === current ? 'var(--color-blue)' : 'rgba(255,255,255,0.4)',
border: 'none', cursor: 'pointer', padding: 0,
transition: 'width 0.3s, background 0.3s',
}}
/>
))}
</div>
</div>
)
}
function MembershipForm({ lang }: { lang: 'fa' | 'en' }) {
const [name, setName] = useState('')
const [phone, setPhone] = useState('')
const [email, setEmail] = useState('')
const [status, setStatus] = useState<'idle'|'sending'|'done'|'error'>('idle')
const lbl = lang === 'fa'
? { name: 'نام و نام‌خانوادگی', phone: 'شماره همراه', email: 'آدرس ایمیل', btn: 'ارسال درخواست', sending: 'در حال ارسال...', done: '✓ درخواست شما ثبت شد. به‌زودی با شما تماس می‌گیریم.', error: 'خطا در ارسال. لطفاً مجدد تلاش کنید.' }
: { name: 'Full Name', phone: 'Phone Number', email: 'Email Address', btn: 'Send Request', sending: 'Sending...', done: '✓ Request received. We will contact you soon.', error: 'Send failed. Please try again.' }
async function submit() {
if (!name || !phone) return
setStatus('sending')
const PANEL_API = import.meta.env.VITE_PANEL_API || 'http://localhost:3001'
try {
const res = await fetch(`${PANEL_API}/api/contact`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ name, phone, email }),
})
setStatus(res.ok ? 'done' : 'error')
} catch {
setStatus('error')
}
}
if (status === 'done') return (
<div style={{ background: 'rgba(7,29,73,0.06)', padding: '16px 20px', fontSize: 14, color: 'var(--ink)', fontWeight: 600, borderRight: '4px solid var(--color-blue)' }}>
{lbl.done}
</div>
)
return (
<div style={{ display: 'flex', flexDirection: 'column', gap: 12, maxWidth: 420 }}>
{(['name','phone','email'] as const).map(field => (
<input
key={field}
type={field === 'email' ? 'email' : field === 'phone' ? 'tel' : 'text'}
placeholder={lbl[field]}
value={field === 'name' ? name : field === 'phone' ? phone : email}
onChange={e => field === 'name' ? setName(e.target.value) : field === 'phone' ? setPhone(e.target.value) : setEmail(e.target.value)}
style={{
border: '1px solid var(--rule-thin)', padding: '11px 14px',
fontSize: 13, fontFamily: 'inherit', background: 'var(--paper)',
color: 'var(--ink)', outline: 'none', width: '100%',
direction: lang === 'fa' ? 'rtl' : 'ltr',
}}
/>
))}
{status === 'error' && <div style={{ fontSize: 12, color: 'var(--red)' }}>{lbl.error}</div>}
<button
onClick={submit}
disabled={status === 'sending'}
style={{
background: 'var(--color-navy)', color: '#fff', border: 'none',
padding: '13px 32px', fontSize: 13, fontWeight: 700,
fontFamily: 'inherit', cursor: status === 'sending' ? 'default' : 'pointer',
opacity: status === 'sending' ? 0.7 : 1, transition: 'opacity 150ms',
alignSelf: 'flex-start',
}}
>
{status === 'sending' ? lbl.sending : lbl.btn}
</button>
</div>
)
}
/* ─── product coverage section ──────────────────────────── */
const PRODUCT_CATEGORIES = [
{
title: 'محصولات فولادی',
items: ['مفتول', 'میلگرد', 'مقاطع', 'لوله', 'کویل نورد گرم', 'ورق', 'پوشش‌دار', 'نوار'],
},
{
title: 'فروآلیاژ فولاد',
items: ['فروبور', 'فروکروم', 'فرو منگنز', 'فرونیوبیوم', 'فروفسفر', 'فروسیلیکون', 'فروتیتانیوم', 'فرووتنگستن', 'فروواناديوم', 'کروم-سیلیکون', 'کلسیم-سیلیکون', 'سنگ کروم', 'سنگ منگنز'],
},
{
title: 'صنعت فولاد',
items: ['میله استیل', 'کویل استیل', 'لوله استیل', 'ضایعات استیل', 'فولاد بلبرینگ', 'فولاد سرد هیدینگ', 'فولاد چرخدنده', 'فولاد سیلیکون', 'فولاد سازه‌ای'],
},
{
title: 'مواد اولیه',
items: ['زغال سنگ', 'کک', 'آهن', 'سنگ آهن', 'بیلت فولادی', 'ضایعات فولادی'],
},
]
const CONTENT_SECTIONS = [
'صنعت فولاد', 'بازار سرمایه', 'فلزات و کامودیتی',
'ارزهای دیجیتال', 'بازار ارز و طلا', 'اقتصاد کلان',
]
const DATA_SOURCES = ['Platts', 'Fastmarkets', 'Bainfo China', 'Dlpibica']
function CategoryColumn({ cat }: { cat: typeof PRODUCT_CATEGORIES[0] }) {
return (
<div style={{ padding: '14px 18px' }}>
<div style={{
fontSize: 10, fontWeight: 800, color: 'var(--ink)',
marginBottom: 10, paddingBottom: 6,
borderBottom: '2px solid var(--red)',
display: 'inline-block',
}}>{cat.title}</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 5 }}>
{cat.items.map((item, ii) => (
<span key={ii} style={{
fontSize: 11, color: 'var(--ink-2)',
background: 'var(--paper-2)',
border: '1px solid var(--rule-thin)',
padding: '2px 8px',
whiteSpace: 'nowrap',
}}>{item}</span>
))}
</div>
</div>
)
}
function ProductCoverage({ lang }: { lang: 'fa' | 'en' }) {
const tx = TX[lang]
const totalCount = PRODUCT_CATEGORIES.reduce((acc, c) => acc + c.items.length, 0)
return (
<div style={{ marginBottom: 56, border: '1px solid var(--rule-thin)', overflow: 'hidden' }}>
{/* ── top header ── */}
<div style={{
background: 'var(--ink)', color: 'var(--paper)',
padding: '16px 28px',
display: 'flex', alignItems: 'center', justifyContent: 'space-between', flexWrap: 'wrap', gap: 12,
}}>
<div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
<div style={{ width: 3, height: 28, background: 'var(--red)' }} />
<div>
<div style={{ fontSize: 9, letterSpacing: '3px', color: 'rgba(255,255,255,0.4)', marginBottom: 2 }}>PRICE COVERAGE</div>
<div style={{ fontSize: 14, fontWeight: 900 }}>{tx.coverageTitle}</div>
</div>
</div>
<div style={{ display: 'flex', gap: 28 }}>
{[{ n: `${totalCount}+`, l: tx.productLabel }, { n: '۵۰۰+', l: tx.indexLabel }, { n: '۴', l: tx.sourceLabel }].map(s => (
<div key={s.l} style={{ textAlign: 'center' }}>
<div style={{ fontSize: 20, fontWeight: 900, lineHeight: 1 }}>{s.n}</div>
<div style={{ fontSize: 9, color: 'rgba(255,255,255,0.45)', marginTop: 3 }}>{s.l}</div>
</div>
))}
</div>
</div>
{/* ── main body: 2-col products + CTA sidebar ── */}
<div style={{ display: 'grid', gridTemplateColumns: '1fr 280px' }} className="max-lg:!grid-cols-1">
{/* left: 2×2 product grid */}
<div style={{ borderLeft: '1px solid var(--rule-thin)' }} className="max-lg:border-l-0">
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr' }}>
{PRODUCT_CATEGORIES.map((cat, ci) => (
<div key={ci} style={{
borderBottom: ci < 2 ? '1px solid var(--rule-thin)' : 'none',
borderLeft: ci % 2 === 1 ? '1px solid var(--rule-thin)' : 'none',
}}>
<CategoryColumn cat={cat} />
</div>
))}
</div>
</div>
{/* right: CTA sidebar */}
<div style={{
background: 'rgba(7,29,73,0.04)',
borderRight: '1px solid var(--rule-thin)',
padding: '28px 24px',
display: 'flex', flexDirection: 'column', gap: 18,
}} className="max-lg:border-r-0 max-lg:border-t max-lg:border-t-[var(--rule-thin)]">
<div>
<div style={{ fontSize: 9, fontWeight: 700, letterSpacing: '2.5px', color: 'var(--red)', marginBottom: 10 }}>MEMBERS ONLY</div>
<p style={{ fontSize: 12, color: 'var(--ink-3)', lineHeight: 1.75, margin: 0 }}>{tx.coverageDesc}</p>
</div>
<div style={{ borderTop: '1px solid var(--rule-thin)', paddingTop: 16, display: 'flex', flexDirection: 'column', gap: 9 }}>
{tx.coverageFeatures.map(f => (
<div key={f} style={{ display: 'flex', alignItems: 'center', gap: 9, fontSize: 12, color: 'var(--ink)' }}>
<span style={{ color: '#166534', fontWeight: 900, fontSize: 12 }}></span>{f}
</div>
))}
</div>
<div style={{ borderTop: '1px solid var(--rule-thin)', paddingTop: 16 }}>
<div style={{ fontSize: 9, fontWeight: 700, letterSpacing: '2px', color: 'var(--ink-4)', marginBottom: 10 }}>{tx.sectionsLabel}</div>
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
{tx.contentSections.map(s => (
<span key={s} style={{
fontSize: 10, fontWeight: 600, padding: '3px 9px',
border: '1px solid var(--rule-thin)',
color: 'var(--ink-3)',
}}>{s}</span>
))}
</div>
</div>
</div>
</div>
{/* ── full-width DATA SOURCES bar ── */}
<div style={{
background: 'var(--ink)',
color: 'var(--paper)',
padding: '36px 40px',
borderTop: '3px solid var(--red)',
display: 'grid',
gridTemplateColumns: '1fr auto',
gap: 40,
alignItems: 'center',
}} className="max-md:!grid-cols-1">
<div>
<div style={{ fontSize: 9, fontWeight: 700, letterSpacing: '3px', color: 'var(--red)', marginBottom: 10 }}>DATA SOURCES</div>
<h3 style={{ fontSize: 20, fontWeight: 900, margin: '0 0 10px', lineHeight: 1.3 }}>{tx.dsTitle}</h3>
<p style={{ fontSize: 13, color: 'rgba(255,255,255,0.6)', lineHeight: 1.85, margin: 0, maxWidth: 640 }}>{tx.dsBody}</p>
</div>
<div style={{ display: 'flex', flexDirection: 'column', gap: 10, minWidth: 180 }}>
{DATA_SOURCES.map(src => (
<div key={src} style={{
display: 'flex', alignItems: 'center', gap: 10,
padding: '10px 16px',
border: '1px solid rgba(255,255,255,0.15)',
fontSize: 13, fontWeight: 800, letterSpacing: '0.5px',
}}>
<span style={{ width: 6, height: 6, background: '#4ade80', borderRadius: '50%', flexShrink: 0 }} />
{src}
</div>
))}
</div>
</div>
</div>
)
}
export default function Pulse() {
const { lang } = useLang()
const t = T[lang]
const stats = STATS[lang]
return (
<div dir={lang === 'fa' ? 'rtl' : 'ltr'} style={{ background: 'var(--paper)', minHeight: '80vh' }}>
<div style={{ borderBottom: '3px solid var(--ink)' }}>
<div className="max-w-7xl mx-auto px-12 max-md:px-5" style={{ paddingTop: 48, paddingBottom: 40 }}>
<div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 16 }}>
<div style={{ width: 36, height: 2, background: 'var(--red)' }} />
<span style={{ fontSize: 10, fontWeight: 700, letterSpacing: '3px', textTransform: 'uppercase', color: 'var(--ink-4)' }}>{t.overline}</span>
</div>
<h1 style={{ fontSize: 'clamp(28px,4vw,52px)', fontWeight: 900, letterSpacing: '-1.5px', color: 'var(--ink)', marginBottom: 12 }}>{t.heading}</h1>
<p style={{ fontSize: 15, color: 'var(--ink-3)', lineHeight: 1.7, maxWidth: 600 }}>{t.sub}</p>
</div>
</div>
<div className="max-w-7xl mx-auto px-12 max-md:px-5" style={{ paddingTop: 48, paddingBottom: 64 }}>
<div style={{ marginBottom: 32, display: 'flex', alignItems: 'center', gap: 0, border: '1px solid var(--rule-thin)', overflow: 'hidden' }}>
<div style={{ padding: '12px 18px', borderLeft: '1px solid var(--rule-thin)', fontSize: 9, fontWeight: 700, letterSpacing: '2px', color: 'var(--ink-4)', whiteSpace: 'nowrap', background: 'var(--paper-2)' }}>
{t.statsLabel}
</div>
{stats.map((s, i) => (
<div key={i} style={{
padding: '12px 20px', borderLeft: '1px solid var(--rule-thin)',
flex: 1, display: 'flex', alignItems: 'center', gap: 12,
filter: i >= 2 ? 'blur(4px)' : 'none',
userSelect: i >= 2 ? 'none' : 'auto',
pointerEvents: i >= 2 ? 'none' : 'auto',
}}>
<div style={{ fontSize: 22, fontWeight: 900, letterSpacing: '-0.5px', color: 'var(--ink)', lineHeight: 1, fontVariantNumeric: 'tabular-nums' }}>{s.value}</div>
<div>
<div style={{ fontSize: 10, fontWeight: 700, color: 'var(--ink-3)' }}>{s.label}</div>
<div style={{ fontSize: 9, color: 'var(--ink-5)' }}>{s.unit}</div>
<div style={{ fontSize: 9, fontWeight: 700, color: s.delta.startsWith('+') ? '#2d6a4f' : s.delta.startsWith('-') ? 'var(--red)' : 'var(--ink-5)', marginTop: 2 }}>{s.delta}</div>
</div>
</div>
))}
</div>
{/* Live market snapshot */}
<div style={{ marginBottom: 48, overflow: 'hidden', border: '1px solid var(--rule-thin)' }}>
<SnapshotBar />
</div>
{/* Price table with paywall blur */}
<PriceTable blurFrom={4} lang={lang} />
{/* Slider + form side by side on desktop — form on RIGHT (col-1 in RTL) */}
<div style={{ display: 'grid', gridTemplateColumns: '320px 1fr', gap: 0, marginBottom: 48, border: '1px solid var(--rule-thin)', alignItems: 'stretch' }} className="max-md:!grid-cols-1">
<div style={{ padding: '32px 24px', background: 'var(--ink)', color: 'var(--paper)', display: 'flex', flexDirection: 'column', gap: 20, borderLeft: '1px solid rgba(255,255,255,0.08)' }}>
<div>
<div style={{ fontSize: 9, fontWeight: 700, letterSpacing: '3px', color: 'var(--red)', marginBottom: 10 }}>MEMBERS ONLY ACCESS</div>
<h3 style={{ fontSize: 16, fontWeight: 900, margin: '0 0 8px', lineHeight: 1.3 }}>{t.gateHeading}</h3>
<p style={{ fontSize: 12, color: 'rgba(255,255,255,0.55)', lineHeight: 1.7, margin: 0 }}>{t.gateSub}</p>
</div>
<div style={{ borderTop: '1px solid rgba(255,255,255,0.1)', paddingTop: 16, display: 'flex', flexDirection: 'column', gap: 8 }}>
{t.features.map(f => (
<div key={f} style={{ display: 'flex', gap: 8, fontSize: 12, color: 'rgba(255,255,255,0.8)' }}>
<span style={{ color: '#4ade80', fontWeight: 900, flexShrink: 0 }}></span>{f}
</div>
))}
</div>
<div style={{ borderTop: '1px solid rgba(255,255,255,0.1)', paddingTop: 16 }}>
<MembershipForm lang={lang} />
</div>
</div>
<div>
<ImageSlider />
</div>
</div>
{/* Product coverage */}
<ProductCoverage lang={lang} />
</div>
</div>
)
}