Refine homepage layout, typography, and component polish

- Header: replaced 3-bar masthead with slim dark meta strip + 68px main bar
  (brand · centered nav · search/CTA actions). ~60% shorter than before.
- Home: added numbered SectionLabel chapter markers (01–07) between
  sections with red accent bar; alternated paper/paper-2 backgrounds
  for clearer section separation.
- Typography: wrapped base h1–h4 and p element styles in @layer base so
  Tailwind utilities (text-white, etc.) can override defaults. Previously
  unlayered p { color: var(--ink-3) } was overriding all carousel white
  titles, making them appear grey-brown.
- Carousel: removed pagination arrows; strengthened title gradient,
  added top centered red category badge, text-shadow + generous padding
  so titles never crash into card edges. Modal hero received same
  treatment with overflow-safe inset positioning.
- PlansSection: rewrote with compact shadcn-pricing pattern; price
  reduced from 42px to 26px; featured plan elevated with translateY
  and shadow; star badge for "Popular" plan.
- TeamSection: redesigned member cards more compact (avatar 60→44px,
  reports count moved to top-end, line-clamp on bio).
- Removed inline padding overrides across all sections so Tailwind
  max-md:px-5 mobile responsiveness actually works.
This commit is contained in:
alireza 2026-05-25 17:17:16 +03:30
parent 2dd08650cf
commit 8c5d2a9739
20 changed files with 1406 additions and 1505 deletions

View File

@ -89,7 +89,7 @@ export function Footer() {
style={{ backgroundColor: 'var(--ink)', color: 'rgba(255,255,255,0.6)' }} style={{ backgroundColor: 'var(--ink)', color: 'rgba(255,255,255,0.6)' }}
> >
{/* TOP GRID */} {/* TOP GRID */}
<div style={{ padding: '64px 48px' }}> <div style={{ padding: '64px 0' }} className="max-w-7xl mx-auto w-full px-12 max-md:px-5">
<div <div
style={{ style={{
display: 'grid', display: 'grid',
@ -167,28 +167,34 @@ export function Footer() {
{/* BOTTOM ROW */} {/* BOTTOM ROW */}
<div <div
style={{ style={{
padding: '20px 48px',
borderTop: '1px solid rgba(255,255,255,0.08)', borderTop: '1px solid rgba(255,255,255,0.08)',
display: 'flex',
justifyContent: 'space-between',
alignItems: 'center',
fontSize: 10,
color: 'rgba(255,255,255,0.25)',
flexWrap: 'wrap',
gap: 12,
}} }}
> >
<span>© ۱۴۰۳ اندیشکده فولاد ایران تمام حقوق محفوظ است</span> <div
<div style={{ display: 'flex', gap: 18 }}> style={{
{['حریم خصوصی', 'شرایط استفاده', 'درگاه پرداخت', 'نقشه سایت'].map(l => ( padding: '20px 48px',
<a display: 'flex',
key={l} justifyContent: 'space-between',
href="#" alignItems: 'center',
style={{ color: 'rgba(255,255,255,0.25)', textDecoration: 'none' }} fontSize: 10,
> color: 'rgba(255,255,255,0.25)',
{l} flexWrap: 'wrap',
</a> gap: 12,
))} }}
className="max-w-7xl mx-auto w-full px-12 max-md:px-5"
>
<span>© ۱۴۰۳ اندیشکده فولاد ایران تمام حقوق محفوظ است</span>
<div style={{ display: 'flex', gap: 18 }}>
{['حریم خصوصی', 'شرایط استفاده', 'درگاه پرداخت', 'نقشه سایت'].map(l => (
<a
key={l}
href="#"
style={{ color: 'rgba(255,255,255,0.25)', textDecoration: 'none' }}
>
{l}
</a>
))}
</div>
</div> </div>
</div> </div>
</footer> </footer>

File diff suppressed because it is too large Load Diff

View File

@ -43,27 +43,14 @@ export function Carousel({
initialScroll?: number initialScroll?: number
}) { }) {
const carouselRef = useRef<HTMLDivElement>(null) const carouselRef = useRef<HTMLDivElement>(null)
const [canScrollLeft, setCanScrollLeft] = useState(false) const [currentIndex, setCurrentIndex] = useState(0)
const [canScrollRight, setCanScrollRight] = useState(true)
const [currentIndex, setCurrentIndex] = useState(0)
useEffect(() => { useEffect(() => {
if (carouselRef.current) { if (carouselRef.current) {
carouselRef.current.scrollLeft = initialScroll carouselRef.current.scrollLeft = initialScroll
checkScrollability()
} }
}, [initialScroll]) }, [initialScroll])
function checkScrollability() {
if (!carouselRef.current) return
const { scrollLeft, scrollWidth, clientWidth } = carouselRef.current
setCanScrollLeft(scrollLeft > 0)
setCanScrollRight(scrollLeft < scrollWidth - clientWidth - 1)
}
function scrollLeft() { carouselRef.current?.scrollBy({ left: -340, behavior: 'smooth' }) }
function scrollRight() { carouselRef.current?.scrollBy({ left: 340, behavior: 'smooth' }) }
function handleCardClose(index: number) { function handleCardClose(index: number) {
if (!carouselRef.current) return if (!carouselRef.current) return
const cardWidth = window.innerWidth < 768 ? 230 : 350 const cardWidth = window.innerWidth < 768 ? 230 : 350
@ -77,7 +64,6 @@ export function Carousel({
{/* Scrollable track */} {/* Scrollable track */}
<div <div
ref={carouselRef} ref={carouselRef}
onScroll={checkScrollability}
className="flex w-full overflow-x-scroll overscroll-x-auto scroll-smooth py-10 md:py-14 [scrollbar-width:none]" className="flex w-full overflow-x-scroll overscroll-x-auto scroll-smooth py-10 md:py-14 [scrollbar-width:none]"
style={{ direction: 'ltr' }} style={{ direction: 'ltr' }}
> >
@ -96,27 +82,6 @@ export function Carousel({
</div> </div>
</div> </div>
{/* Arrow buttons */}
<div className="flex justify-end gap-2 px-10 pb-6">
<button
onClick={scrollLeft}
disabled={!canScrollLeft}
className="h-10 w-10 rounded-full bg-[var(--paper-3)] border border-[var(--rule-thin)] flex items-center justify-center disabled:opacity-30 transition-opacity hover:bg-[var(--paper-2)]"
>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} className="h-5 w-5 text-[var(--ink)]">
<path strokeLinecap="round" strokeLinejoin="round" d="M15 19l-7-7 7-7" />
</svg>
</button>
<button
onClick={scrollRight}
disabled={!canScrollRight}
className="h-10 w-10 rounded-full bg-[var(--paper-3)] border border-[var(--rule-thin)] flex items-center justify-center disabled:opacity-30 transition-opacity hover:bg-[var(--paper-2)]"
>
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={2} className="h-5 w-5 text-[var(--ink)]">
<path strokeLinecap="round" strokeLinejoin="round" d="M9 5l7 7-7 7" />
</svg>
</button>
</div>
</div> </div>
</CarouselContext.Provider> </CarouselContext.Provider>
) )
@ -183,19 +148,31 @@ export function Card({
</button> </button>
{/* Hero image strip */} {/* Hero image strip */}
<div className="relative h-52 overflow-hidden" style={{ flexShrink: 0 }}> <div className="relative h-56 overflow-hidden" style={{ flexShrink: 0 }}>
<img <img
src={card.src} src={card.src}
alt={card.title} alt={card.title}
className="w-full h-full object-cover" className="w-full h-full object-cover"
/> />
<div className="absolute inset-0 bg-gradient-to-t from-black/70 to-transparent" /> {/* Stronger gradient — fully opaque at bottom for readable text */}
{/* inset-x-0 ensures text never overflows past modal edges */} <div className="absolute inset-0 bg-gradient-to-t from-black via-black/70 via-[40%] to-transparent" />
<div className="absolute bottom-0 inset-x-0 p-6">
<p className="text-white/70 text-xs font-bold tracking-widest uppercase mb-1"> {/* Category badge — red, top */}
<div className="absolute top-6 right-8 z-10">
<span
className="inline-block text-white px-3 py-1.5 text-[11px] font-bold tracking-[2px] whitespace-nowrap"
style={{ background: 'var(--red)' }}
>
{card.category} {card.category}
</p> </span>
<p className="text-white text-lg font-bold leading-snug line-clamp-2"> </div>
{/* Title — bottom, bright white with shadow for clarity */}
<div className="absolute bottom-0 inset-x-0 px-8 pb-6 pt-10">
<p
className="text-white text-xl font-extrabold leading-tight line-clamp-2"
style={{ textShadow: '0 2px 8px rgba(0,0,0,0.6)' }}
>
{card.title} {card.title}
</p> </p>
</div> </div>
@ -223,15 +200,25 @@ export function Card({
whileHover={{ scale: 1.015 }} whileHover={{ scale: 1.015 }}
transition={{ duration: 0.2 }} transition={{ duration: 0.2 }}
> >
{/* Bottom-to-top gradient so text is readable — tall enough to cover 2 lines */} {/* Strong bottom-to-top gradient — fully opaque at bottom so title pops */}
<div className="absolute inset-0 bg-gradient-to-t from-black/95 via-black/65 via-[35%] to-transparent z-20 pointer-events-none" /> <div className="absolute inset-0 bg-gradient-to-t from-black via-black/75 via-[45%] to-transparent z-20 pointer-events-none" />
{/* Text — bottom of card, small */} {/* Top centered category badge — prominent, eye-catching */}
<div className="relative z-30 p-5 w-full text-right overflow-hidden"> <div className="absolute top-6 left-1/2 -translate-x-1/2 z-30">
<p className="text-white/65 text-[10px] font-bold tracking-widest uppercase mb-1.5 truncate"> <span
className="inline-block text-white px-4 py-1.5 text-[12px] font-bold tracking-[2px] whitespace-nowrap"
style={{ background: 'var(--red)' }}
>
{card.category} {card.category}
</p> </span>
<p className="text-white text-sm font-bold leading-snug line-clamp-2"> </div>
{/* Bottom: title — bright white, readable */}
<div className="relative z-30 px-7 pb-6 pt-10 w-full text-right overflow-hidden">
<p
className="text-white text-[16px] font-extrabold leading-snug line-clamp-3"
style={{ textShadow: '0 2px 8px rgba(0,0,0,0.6)' }}
>
{card.title} {card.title}
</p> </p>
</div> </div>

View File

@ -85,63 +85,69 @@
--fs-sm: clamp(11px, 0.75vw, 13px); --fs-sm: clamp(11px, 0.75vw, 13px);
--fs-xs: clamp(9px, 0.6vw, 11px); --fs-xs: clamp(9px, 0.6vw, 11px);
/* Letter spacing */ /* Letter spacing (Persian typography uses normal spacing to keep cursive script connected) */
--ls-display: -2.5px; --ls-display: normal;
--ls-h1: -2px; --ls-h1: normal;
--ls-h2: -1px; --ls-h2: normal;
--ls-h3: -0.3px; --ls-h3: normal;
--ls-body: 0px; --ls-body: normal;
--ls-label: 1.5px; --ls-label: normal;
--ls-overline: 2.5px; --ls-overline: normal;
--ls-widest: 3px; --ls-widest: normal;
/* Line heights */ /* Line heights (increased for Persian script to prevent accent collisions and overlap) */
--lh-display: 1.04; --lh-display: 1.25;
--lh-heading: 1.12; --lh-heading: 1.3;
--lh-subhead: 1.3; --lh-subhead: 1.4;
--lh-body: 1.8; --lh-body: 1.8;
--lh-relaxed: 1.85; --lh-relaxed: 1.85;
--lh-label: 1.3; --lh-label: 1.4;
} }
/* ── Base element styles ──────────────────────── */ /* Base element styles
h1 { Inside @layer base so Tailwind utilities (text-white, text-red, etc.)
font-size: var(--fs-h1); in the @utilities layer can override these defaults. */
font-weight: 900; @layer base {
line-height: var(--lh-heading); h1 {
letter-spacing: var(--ls-h1); font-size: var(--fs-h1);
color: var(--ink); font-weight: 900;
margin: 0; line-height: var(--lh-heading);
} letter-spacing: normal;
h2 { color: var(--ink);
font-size: var(--fs-h2); margin: 0;
font-weight: 900; }
line-height: var(--lh-heading); h2 {
letter-spacing: var(--ls-h2); font-size: var(--fs-h2);
color: var(--ink); font-weight: 900;
margin: 0; line-height: var(--lh-heading);
} letter-spacing: normal;
h3 { color: var(--ink);
font-size: var(--fs-h3); margin: 0;
font-weight: 700; }
line-height: var(--lh-subhead); h3 {
letter-spacing: var(--ls-h3); font-size: var(--fs-h3);
color: var(--ink); font-weight: 700;
margin: 0; line-height: var(--lh-subhead);
} letter-spacing: normal;
h4 { color: var(--ink);
font-size: var(--fs-h4); margin: 0;
font-weight: 700; }
line-height: var(--lh-subhead); h4 {
color: var(--ink); font-size: var(--fs-h4);
margin: 0; font-weight: 700;
} line-height: var(--lh-subhead);
p { letter-spacing: normal;
font-size: var(--fs-body); color: var(--ink);
font-weight: 400; /* was 300 — too thin on most screens */ margin: 0;
line-height: var(--lh-body); }
color: var(--ink-3); p {
margin: 0; font-size: var(--fs-body);
font-weight: 400;
line-height: var(--lh-body);
letter-spacing: normal;
color: var(--ink-3);
margin: 0;
}
} }
/* /*
@ -149,6 +155,12 @@ p {
*/ */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; } *, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
/* McKinsey centered container margins (physical override of standard logical properties) */
.mx-auto {
margin-left: auto !important;
margin-right: auto !important;
}
html { scroll-behavior: smooth; direction: rtl; } html { scroll-behavior: smooth; direction: rtl; }
body { body {
@ -157,6 +169,7 @@ body {
color: var(--ink); color: var(--ink);
font-size: var(--fs-body); font-size: var(--fs-body);
line-height: var(--lh-body); line-height: var(--lh-body);
letter-spacing: normal;
overflow-x: hidden; overflow-x: hidden;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
} }
@ -180,7 +193,7 @@ body {
.t-overline { .t-overline {
font-size: var(--fs-xs); font-size: var(--fs-xs);
font-weight: 700; font-weight: 700;
letter-spacing: var(--ls-overline); letter-spacing: normal;
text-transform: uppercase; text-transform: uppercase;
line-height: var(--lh-label); line-height: var(--lh-label);
} }

View File

@ -55,14 +55,10 @@ function ReportRow({ report }: { report: (typeof reports)[0] }) {
return ( return (
<div <div
className="grid grid-cols-[64px_1fr_140px_52px_80px] max-md:grid-cols-[56px_1fr_70px] archive-row items-center border-b border-[var(--rule-thin)] min-h-[40px]"
style={{ style={{
display: 'grid',
gridTemplateColumns: '64px 1fr 140px 52px 80px',
alignItems: 'center',
borderBottom: '1px solid var(--rule-thin)',
background: hovered ? 'var(--paper-2)' : 'transparent', background: hovered ? 'var(--paper-2)' : 'transparent',
transition: 'background 100ms', transition: 'background 100ms',
minHeight: 40,
}} }}
onMouseEnter={() => setHovered(true)} onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)} onMouseLeave={() => setHovered(false)}
@ -78,7 +74,6 @@ function ReportRow({ report }: { report: (typeof reports)[0] }) {
style={{ style={{
fontSize: 9, fontSize: 9,
fontWeight: 700, fontWeight: 700,
letterSpacing: '0.8px',
color: typeColor, color: typeColor,
border: `1px solid ${typeColor}`, border: `1px solid ${typeColor}`,
padding: '2px 5px', padding: '2px 5px',
@ -116,6 +111,7 @@ function ReportRow({ report }: { report: (typeof reports)[0] }) {
borderLeft: '1px solid var(--rule-thin)', borderLeft: '1px solid var(--rule-thin)',
overflow: 'hidden', overflow: 'hidden',
}} }}
className="max-md:hidden"
> >
<span <span
style={{ style={{
@ -139,6 +135,7 @@ function ReportRow({ report }: { report: (typeof reports)[0] }) {
borderLeft: '1px solid var(--rule-thin)', borderLeft: '1px solid var(--rule-thin)',
textAlign: 'center', textAlign: 'center',
}} }}
className="max-md:hidden"
> >
<span style={{ fontSize: 11, color: 'var(--ink-5)', fontWeight: 400 }}> <span style={{ fontSize: 11, color: 'var(--ink-5)', fontWeight: 400 }}>
{report.pages.toLocaleString('fa-IR')} ص {report.pages.toLocaleString('fa-IR')} ص
@ -355,29 +352,20 @@ export default function Archive() {
{/* column headers */} {/* column headers */}
<div <div
style={{ className="grid grid-cols-[64px_1fr_140px_52px_80px] max-md:grid-cols-[56px_1fr_70px] archive-row items-center border-t-2 border-b border-[var(--ink)] mt-2 bg-[var(--paper-2)]"
display: 'grid',
gridTemplateColumns: '64px 1fr 140px 52px 80px',
alignItems: 'center',
borderTop: '2px solid var(--ink)',
borderBottom: '1px solid var(--ink)',
marginTop: 8,
background: 'var(--paper-2)',
}}
> >
{[ {[
{ label: 'نوع', style: { padding: '6px 12px', borderLeft: '1px solid var(--rule-thin)' } }, { label: 'نوع', style: { padding: '6px 12px', borderLeft: '1px solid var(--rule-thin)' } },
{ label: 'عنوان گزارش', style: { padding: '6px 16px', borderLeft: '1px solid var(--rule-thin)' } }, { label: 'عنوان گزارش', style: { padding: '6px 16px', borderLeft: '1px solid var(--rule-thin)' } },
{ label: 'نویسنده', style: { padding: '6px 12px', borderLeft: '1px solid var(--rule-thin)' } }, { label: 'نویسنده', style: { padding: '6px 12px', borderLeft: '1px solid var(--rule-thin)' }, hideMobile: true },
{ label: 'صفحه', style: { padding: '6px 10px', borderLeft: '1px solid var(--rule-thin)', textAlign: 'center' as const } }, { label: 'صفحه', style: { padding: '6px 10px', borderLeft: '1px solid var(--rule-thin)', textAlign: 'center' as const }, hideMobile: true },
{ label: 'قیمت', style: { padding: '6px 12px', textAlign: 'left' as const } }, { label: 'قیمت', style: { padding: '6px 12px', textAlign: 'left' as const } },
].map((col) => ( ].map((col) => (
<div key={col.label} style={col.style}> <div key={col.label} style={col.style} className={col.hideMobile ? "max-md:hidden" : ""}>
<span <span
style={{ style={{
fontSize: 9, fontSize: 9,
fontWeight: 700, fontWeight: 700,
letterSpacing: '1.2px',
color: 'var(--ink-4)', color: 'var(--ink-4)',
textTransform: 'uppercase', textTransform: 'uppercase',
}} }}

View File

@ -1,26 +1,123 @@
import HeroSection from './sections/HeroSection' import HeroSection from './sections/HeroSection'
import SnapshotBar from './sections/SnapshotBar' import SnapshotBar from './sections/SnapshotBar'
import GlobalScannerSection from './sections/GlobalScannerSection' import GlobalScannerSection from './sections/GlobalScannerSection'
import ReportsCarouselSection from './sections/ReportsCarouselSection' import ReportsCarouselSection from './sections/ReportsCarouselSection'
import LatestNewsBentoSection from './sections/LatestNewsBentoSection' import LatestNewsBentoSection from './sections/LatestNewsBentoSection'
import EventsSection from './sections/EventsSection' import EventsSection from './sections/EventsSection'
import RiskSection from './sections/RiskSection' import RiskSection from './sections/RiskSection'
import PlansSection from './sections/PlansSection' import TeamSection from './sections/TeamSection'
import TeamSection from './sections/TeamSection' import PlansSection from './sections/PlansSection'
import NewsletterSection from './sections/NewsletterSection' import NewsletterSection from './sections/NewsletterSection'
/* Section chapter marker
A thin full-bleed dark bar that stamps the start of every
major section creates instant, unmistakable boundaries.
*/
function SectionLabel({ n, title }: { n: string; title: string }) {
return (
<div
style={{
background: 'var(--ink)',
borderTop: '1px solid rgba(255,255,255,0.08)',
position: 'relative',
}}
>
{/* Red accent bar on the right edge (RTL → visual start) */}
<div style={{
position: 'absolute',
top: 0,
bottom: 0,
right: 0,
width: 4,
background: 'var(--red)',
}} />
<div
style={{
display: 'flex',
alignItems: 'center',
gap: 24,
}}
className="max-w-7xl mx-auto w-full px-12 py-10 max-md:px-5 max-md:py-7 max-md:gap-4"
>
<span style={{
fontSize: 36,
fontWeight: 900,
color: 'var(--red)',
letterSpacing: '-1.5px',
lineHeight: 1,
direction: 'ltr',
fontVariantNumeric: 'tabular-nums',
flexShrink: 0,
}}
className="max-md:text-[26px]"
>
{n}
</span>
<div style={{
width: 40,
height: 2,
background: 'rgba(255,255,255,0.25)',
flexShrink: 0,
}}
className="max-md:w-6"
/>
<span style={{
fontSize: 17,
fontWeight: 800,
letterSpacing: '-0.3px',
color: 'var(--paper)',
}}
className="max-md:text-[14px]"
>
{title}
</span>
</div>
</div>
)
}
/* ─── Home page ──────────────────────────────────────── */
export default function Home() { export default function Home() {
return ( return (
<div> <div>
{/* ── 00 · Hero ─────────────────────────────────── */}
<HeroSection /> <HeroSection />
{/* ── Ticker ────────────────────────────────────── */}
<SnapshotBar /> <SnapshotBar />
{/* ── 01 · اسکنر جهانی · bg: paper ─────────────── */}
<SectionLabel n="01" title="اسکنر جهانی · رصد ۲۴ ساعته" />
<GlobalScannerSection /> <GlobalScannerSection />
{/* ── 02 · تحلیل‌ها · bg: paper-2 ──────────────── */}
<SectionLabel n="02" title="تحلیل‌های اخیر" />
<ReportsCarouselSection /> <ReportsCarouselSection />
{/* ── 03 · اخبار · bg: paper ────────────────────── */}
<SectionLabel n="03" title="آخرین اخبار بازار" />
<LatestNewsBentoSection /> <LatestNewsBentoSection />
{/* ── 04 · رویدادها · bg: paper-2 ──────────────── */}
<SectionLabel n="04" title="رویدادهای پیش‌رو" />
<EventsSection /> <EventsSection />
{/* ── 05 · ریسک · bg: paper ─────────────────────── */}
<SectionLabel n="05" title="پایش ریسک · لحظه‌ای" />
<RiskSection /> <RiskSection />
{/* ── 06 · تیم · bg: paper-2 ────────────────────── */}
<SectionLabel n="06" title="تیم تحریریه" />
<TeamSection /> <TeamSection />
{/* ── 07 · اشتراک · bg: paper ───────────────────── */}
<SectionLabel n="07" title="اشتراک و دسترسی" />
<PlansSection /> <PlansSection />
{/* ── خبرنامه (last, no label) ───────────────────── */}
<NewsletterSection /> <NewsletterSection />
</div> </div>
) )

View File

@ -27,32 +27,28 @@ export default function EventsSection() {
const displayed = events.slice(0, 4) const displayed = events.slice(0, 4)
return ( return (
<section style={{ borderBottom: '2px solid var(--ink)' }}> <section style={{ borderBottom: '2px solid var(--ink)', background: 'var(--paper-2)' }}>
<div className="px-12 py-20 max-md:px-5 max-md:py-14"> <div className="max-w-7xl mx-auto px-12 py-20 max-md:px-5 max-md:py-14">
{/* Banner */} {/* Sleek top row */}
<div style={{ display: 'flex', alignItems: 'center', borderBottom: '1px solid var(--rule-thin)', marginBottom: 0 }}> <div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 24 }}>
<div style={{ background: 'var(--ink)', color: 'var(--paper)', padding: '8px 20px', fontSize: '9px', fontWeight: 700, letterSpacing: '3px', textTransform: 'uppercase' }}>رویدادهای پیشرو</div> <Link to="/events" style={{ fontSize: '10px', fontWeight: 700, textTransform: 'uppercase', color: 'var(--ink-4)', textDecoration: 'none' }}>تقویم کامل </Link>
<div style={{ flex: 1 }} />
<Link to="/events" style={{ fontSize: '10px', fontWeight: 700, letterSpacing: '1.5px', textTransform: 'uppercase', color: 'var(--ink-4)', textDecoration: 'none', padding: '8px 0' }}>تقویم کامل </Link>
</div> </div>
{/* 4-col grid */} {/* 4-col grid */}
<div <div
style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)' }} className="grid grid-cols-4 max-md:grid-cols-2 max-sm:grid-cols-1"
className="max-md:grid-cols-2 max-sm:grid-cols-1"
> >
{displayed.map((event, idx) => ( {displayed.map((event) => (
<div <div
key={event.id} key={event.id}
style={{ style={{
padding: '32px 28px', padding: '32px 28px',
borderRight: idx === 0 ? 'none' : '1px solid var(--rule-thin)',
}} }}
className="max-md:border-b max-md:border-[var(--rule-thin)] max-md:last:border-b-0" className="border-r border-[var(--rule-thin)] first:border-r-0 max-md:border-r-0 max-md:border-b max-md:border-[var(--rule-thin)] max-md:nth-child(even):border-r max-md:nth-child(even):border-[var(--rule-thin)] max-sm:border-r-0 max-sm:border-b max-sm:last:border-b-0 max-md:nth-child(3):border-b-0 max-md:nth-child(4):border-b-0"
> >
{/* Date block */} {/* Date block */}
<div style={{ borderBottom: '2px solid var(--ink)', paddingBottom: 12, marginBottom: 16 }}> <div style={{ borderBottom: '2px solid var(--ink)', paddingBottom: 12, marginBottom: 16 }}>
<div style={{ fontSize: 52, fontWeight: 900, letterSpacing: '-2px', lineHeight: 1, color: 'var(--ink)' }}> <div style={{ fontSize: 52, fontWeight: 900, lineHeight: 1, color: 'var(--ink)' }}>
{event.date.toLocaleString('fa-IR')} {event.date.toLocaleString('fa-IR')}
</div> </div>
<div style={{ fontSize: 12, color: 'var(--ink-4)', marginTop: 2 }}> <div style={{ fontSize: 12, color: 'var(--ink-4)', marginTop: 2 }}>
@ -70,7 +66,6 @@ export default function EventsSection() {
fontSize: 9, fontSize: 9,
fontWeight: 700, fontWeight: 700,
textTransform: 'uppercase', textTransform: 'uppercase',
letterSpacing: '1px',
padding: '3px 8px', padding: '3px 8px',
lineHeight: 1.4, lineHeight: 1.4,
}} }}
@ -87,11 +82,11 @@ export default function EventsSection() {
{/* CTA */} {/* CTA */}
{event.registrationOpen ? ( {event.registrationOpen ? (
<Link to="#" style={{ fontSize: 10, fontWeight: 700, letterSpacing: '2px', textTransform: 'uppercase', color: 'var(--red)', textDecoration: 'none', cursor: 'pointer' }}> <Link to="#" style={{ fontSize: 10, fontWeight: 700, textTransform: 'uppercase', color: 'var(--red)', textDecoration: 'none', cursor: 'pointer' }}>
ثبتنام ثبتنام
</Link> </Link>
) : ( ) : (
<span style={{ fontSize: 10, color: 'var(--ink-5)', letterSpacing: '1px', textTransform: 'uppercase', fontWeight: 700 }}> <span style={{ fontSize: 10, color: 'var(--ink-5)', textTransform: 'uppercase', fontWeight: 700 }}>
بهزودی بهزودی
</span> </span>
)} )}

View File

@ -56,124 +56,100 @@ export default function GlobalScannerSection() {
overflow: 'hidden', overflow: 'hidden',
}} }}
> >
{/* ── Text header ────────────────────────────────── */} <div className="max-w-7xl mx-auto w-full px-12 max-md:px-5 pb-12">
<div {/* ── Text header ────────────────────────────────── */}
style={{ textAlign: 'center' }}
className="px-12 pt-[72px] pb-12 max-md:px-5 max-md:pt-10 max-md:pb-8"
>
{/* Overline */}
<div <div
style={{ style={{ textAlign: 'center', paddingTop: 72, paddingBottom: 48 }}
display: 'inline-flex',
alignItems: 'center',
gap: 10,
marginBottom: 20,
}}
> >
<div style={{ width: 20, height: 2, background: 'var(--red)' }} /> {/* Headline */}
<span style={{ <h2 style={{
fontSize: 9, fontSize: 'clamp(28px, 3.5vw, 52px)',
fontWeight: 700, fontWeight: 900,
letterSpacing: '3px', lineHeight: 1.1,
textTransform: 'uppercase', letterSpacing: '-1.5px',
color: 'var(--red)', color: 'var(--ink)',
marginBottom: 16,
}}> }}>
اسکنر جهانی · پوشش ۲۴ ساعته تمام رویدادهای فولادی دنیا{' '}
</span> <motion.span
<div style={{ width: 20, height: 2, background: 'var(--red)' }} /> style={{ color: 'var(--ink-6)', display: 'inline' }}
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.8, delay: 0.3 }}
>
را رصد میکنیم
</motion.span>
</h2>
{/* Subhead */}
<p style={{
fontSize: 15,
lineHeight: 1.85,
fontWeight: 400,
color: 'var(--ink-3)',
maxWidth: 600,
margin: '0 auto',
}}>
از بورس دالیان چین تا گمرک بصره عراق، از تصمیمات کمیته فولاد OECD
تا ظرفیتسازیهای هند هر سیگنالی که بر رقابتپذیری ایران اثر
میگذارد، پیش از بقیه به دست شما میرسد.
</p>
</div> </div>
{/* Headline */} {/* ── World map (full width within container) ─── */}
<h2 style={{ <div className="max-md:px-0">
fontSize: 'clamp(28px, 3.5vw, 52px)', <WorldMap
fontWeight: 900, dots={ROUTES}
lineHeight: 1.1, lineColor="#9b1c1c"
letterSpacing: '-1.5px', dotColor="#c8c2bc"
color: 'var(--ink)', />
marginBottom: 16, </div>
}}>
تمام رویدادهای فولادی دنیا{' '}
<motion.span
style={{ color: 'var(--ink-6)', display: 'inline' }}
initial={{ opacity: 0 }}
whileInView={{ opacity: 1 }}
viewport={{ once: true }}
transition={{ duration: 0.8, delay: 0.3 }}
>
را رصد میکنیم
</motion.span>
</h2>
{/* Subhead */} {/* ── Stats strip ──────────────────────────────── */}
<p style={{ <div
fontSize: 15, style={{
lineHeight: 1.85, borderTop: '1px solid var(--rule-thin)',
fontWeight: 400, marginTop: 48,
color: 'var(--ink-3)', }}
maxWidth: 600, className="grid grid-cols-4 max-md:grid-cols-2 max-sm:grid-cols-1"
margin: '0 auto', >
}}> {[
از بورس دالیان چین تا گمرک بصره عراق، از تصمیمات کمیته فولاد OECD { n: '۱۸۰+', label: 'بازار رصد‌شده', sub: 'در ۵ قاره' },
تا ظرفیتسازیهای هند هر سیگنالی که بر رقابتپذیری ایران اثر { n: '۷/۲۴', label: 'پایش لحظه‌ای', sub: 'قیمت و حجم' },
میگذارد، پیش از بقیه به دست شما میرسد. { n: '۴۰+', label: 'منبع داده', sub: 'بورس‌ها و گمرک‌ها' },
</p> { n: '۱۵', label: 'کشور رقیب', sub: 'زیر ذره‌بین' },
</div> ].map((s, i) => (
<motion.div
{/* ── World map (full width, no side padding) ─── */} key={i}
<div className="px-6 max-md:px-0"> initial={{ opacity: 0, y: 12 }}
<WorldMap whileInView={{ opacity: 1, y: 0 }}
dots={ROUTES} viewport={{ once: true }}
lineColor="#9b1c1c" transition={{ duration: 0.4, delay: i * 0.08 }}
dotColor="#c8c2bc" style={{
/> padding: '28px 24px',
</div> textAlign: 'center',
}}
{/* ── Stats strip ──────────────────────────────── */} className="border-r border-[var(--rule-thin)] first:border-r-0 max-md:border-r-0 max-md:border-b max-md:border-[var(--rule-thin)] max-md:nth-child(even):border-r max-md:nth-child(even):border-[var(--rule-thin)] max-sm:border-r-0 max-sm:border-b max-sm:last:border-b-0 max-md:nth-child(3):border-b-0 max-md:nth-child(4):border-b-0"
<div >
style={{ <div style={{
borderTop: '1px solid var(--rule-thin)', fontSize: 32,
display: 'grid', fontWeight: 900,
gridTemplateColumns: 'repeat(4, 1fr)', color: 'var(--ink)',
}} lineHeight: 1,
className="max-md:grid-cols-2" marginBottom: 4,
> }}>
{[ {s.n}
{ n: '۱۸۰+', label: 'بازار رصد‌شده', sub: 'در ۵ قاره' }, </div>
{ n: '۷/۲۴', label: 'پایش لحظه‌ای', sub: 'قیمت و حجم' }, <div style={{ fontSize: 12, fontWeight: 700, color: 'var(--ink-2)', marginBottom: 2 }}>
{ n: '۴۰+', label: 'منبع داده', sub: 'بورس‌ها و گمرک‌ها' }, {s.label}
{ n: '۱۵', label: 'کشور رقیب', sub: 'زیر ذره‌بین' }, </div>
].map((s, i) => ( <div style={{ fontSize: 10, color: 'var(--ink-5)' }}>
<motion.div {s.sub}
key={i} </div>
initial={{ opacity: 0, y: 12 }} </motion.div>
whileInView={{ opacity: 1, y: 0 }} ))}
viewport={{ once: true }} </div>
transition={{ duration: 0.4, delay: i * 0.08 }}
style={{
padding: '28px 24px',
borderRight: i > 0 ? '1px solid var(--rule-thin)' : 'none',
textAlign: 'center',
}}
className="max-md:border-r-0 max-md:border-b max-md:border-[var(--rule-thin)]"
>
<div style={{
fontSize: 32,
fontWeight: 900,
color: 'var(--ink)',
letterSpacing: '-1px',
lineHeight: 1,
marginBottom: 4,
}}>
{s.n}
</div>
<div style={{ fontSize: 12, fontWeight: 700, color: 'var(--ink-2)', marginBottom: 2 }}>
{s.label}
</div>
<div style={{ fontSize: 10, color: 'var(--ink-5)' }}>
{s.sub}
</div>
</motion.div>
))}
</div> </div>
</section> </section>
) )

View File

@ -82,233 +82,231 @@ export default function HeroSection() {
</div> </div>
{/* ── Main content — anchored bottom ── */} {/* ── Main content — anchored bottom ── */}
<div style={{ <div
position: 'absolute', style={{
inset: 0, position: 'absolute',
display: 'grid', inset: 0,
gridTemplateColumns: '1fr 240px', display: 'flex',
alignItems: 'flex-end', alignItems: 'flex-end',
gap: 48, }}
}}
className="px-14 pb-[52px] max-md:grid-cols-1 max-md:px-5 max-md:pb-8"
> >
<div
{/* ── Left: headline + meta ── */} className="max-w-7xl mx-auto w-full px-14 pb-[52px] grid grid-cols-1 md:grid-cols-[1fr_240px] items-end gap-12 max-md:px-5 max-md:pb-8 max-md:gap-6"
<div>
{/* Overline */}
<motion.div
initial={{ opacity: 0, y: 10 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 20 }}
>
<div style={{ width: 24, height: 2, background: 'var(--red)', flexShrink: 0 }} />
<span style={{
fontSize: 10,
fontWeight: 700,
letterSpacing: '2.5px',
textTransform: 'uppercase',
color: 'rgba(255,255,255,0.5)',
}}>
گزارش راهبردی · تحلیل سناریو
</span>
</motion.div>
{/* Headline */}
<motion.h1
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.1 }}
style={{
fontSize: 'clamp(36px, 5vw, 72px)',
fontWeight: 900,
lineHeight: 1.04,
letterSpacing: '-2.5px',
color: 'white',
marginBottom: 24,
maxWidth: 700,
}}
>
{featured.title.split(':').map((part, i) => (
<span key={i}>
{i === 0 ? part + ':' : (
<span style={{ color: 'rgba(255,255,255,0.45)' }}>{part}</span>
)}
{i === 0 && <br />}
</span>
))}
</motion.h1>
{/* Summary — one line */}
<motion.p
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5, delay: 0.25 }}
style={{
fontSize: 14,
lineHeight: 1.8,
fontWeight: 400,
color: 'rgba(255,255,255,0.6)',
maxWidth: 580,
marginBottom: 32,
}}
>
مدلسازی کمی بر اساس دادههای تجارت ۱۵ کشور رقیب از بدبینانه تا خوشبینانه،
با توصیههای سیاستی مستقیم برای وزارت صمت و سازمان بنادر.
</motion.p>
{/* Divider */}
<div style={{ width: '100%', height: 1, background: 'rgba(255,255,255,0.12)', marginBottom: 24 }} />
{/* Author + Price + CTA in one bar */}
<motion.div
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4, delay: 0.35 }}
style={{
display: 'flex',
alignItems: 'center',
gap: 24,
flexWrap: 'wrap',
}}
>
{/* Author */}
<div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
<div style={{
width: 36, height: 36,
background: 'var(--red)',
color: 'white',
fontSize: 14, fontWeight: 900,
display: 'flex', alignItems: 'center', justifyContent: 'center',
flexShrink: 0,
}}>
{featured.authorInitial}
</div>
<div>
<div style={{ fontSize: 12, fontWeight: 700, color: 'white', lineHeight: 1.2 }}>
{featured.author}
</div>
<div style={{ fontSize: 10, color: 'rgba(255,255,255,0.4)', lineHeight: 1.3 }}>
{featured.authorRole}
</div>
</div>
</div>
{/* Separator */}
<div style={{ width: 1, height: 32, background: 'rgba(255,255,255,0.15)' }} />
{/* Price */}
<div style={{ display: 'flex', alignItems: 'baseline', gap: 5 }}>
<span style={{
fontSize: 28,
fontWeight: 900,
letterSpacing: '-1px',
color: 'white',
lineHeight: 1,
}}>
{featured.price.toLocaleString('fa-IR')}
</span>
<span style={{ fontSize: 11, color: 'rgba(255,255,255,0.4)' }}>تومان</span>
</div>
{/* Buttons */}
<div style={{ display: 'flex', gap: 10 }}>
<button
onMouseEnter={() => setBuyHov(true)}
onMouseLeave={() => setBuyHov(false)}
style={{
background: buyHov ? 'var(--paper-2)' : 'var(--paper)',
color: 'var(--ink)',
border: 'none',
padding: '11px 26px',
fontSize: 12,
fontWeight: 700,
fontFamily: 'Vazir, sans-serif',
cursor: 'pointer',
letterSpacing: '0.5px',
transition: 'background 160ms',
whiteSpace: 'nowrap',
}}
>
خرید گزارش
</button>
<button
onMouseEnter={() => setFreeHov(true)}
onMouseLeave={() => setFreeHov(false)}
style={{
background: freeHov ? 'rgba(255,255,255,0.1)' : 'transparent',
color: 'white',
border: '1px solid rgba(255,255,255,0.3)',
padding: '11px 26px',
fontSize: 12,
fontWeight: 400,
fontFamily: 'Vazir, sans-serif',
cursor: 'pointer',
letterSpacing: '0.5px',
transition: 'background 160ms',
whiteSpace: 'nowrap',
}}
>
دانلود خلاصه رایگان
</button>
</div>
</motion.div>
</div>
{/* ── Right: floating stats panel ── */}
<motion.div
initial={{ opacity: 0, x: -16 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.5, delay: 0.45 }}
style={{
background: 'rgba(255,255,255,0.06)',
backdropFilter: 'blur(12px)',
WebkitBackdropFilter: 'blur(12px)',
border: '1px solid rgba(255,255,255,0.1)',
padding: '20px',
marginBottom: 2,
}}
className="max-md:hidden"
> >
<div style={{
fontSize: 9, {/* ── Left: headline + meta ── */}
fontWeight: 700, <div>
letterSpacing: '2px', {/* Overline */}
textTransform: 'uppercase', <motion.div
color: 'rgba(255,255,255,0.35)', initial={{ opacity: 0, y: 10 }}
marginBottom: 16, animate={{ opacity: 1, y: 0 }}
paddingBottom: 10, transition={{ duration: 0.5 }}
borderBottom: '1px solid rgba(255,255,255,0.1)', style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 20 }}
}}> >
در این گزارش <div style={{ width: 24, height: 2, background: 'var(--red)', flexShrink: 0 }} />
</div> <span style={{
{STATS.map((s, i) => ( fontSize: 10,
<div fontWeight: 700,
key={i} color: 'rgba(255,255,255,0.5)',
}}>
گزارش راهبردی · تحلیل سناریو
</span>
</motion.div>
{/* Headline */}
<motion.h1
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.6, delay: 0.1 }}
style={{ style={{
display: 'flex', fontSize: 'clamp(32px, 5vw, 64px)',
justifyContent: 'space-between', fontWeight: 900,
alignItems: 'baseline', lineHeight: 1.2,
padding: '10px 0', color: 'white',
borderBottom: i < STATS.length - 1 ? '1px solid rgba(255,255,255,0.07)' : 'none', marginBottom: 24,
maxWidth: 700,
}} }}
> >
<span style={{ fontSize: 11, color: 'rgba(255,255,255,0.5)', fontWeight: 300 }}> {featured.title.split(':').map((part, i) => (
{s.label} <span key={i}>
</span> {i === 0 ? part + ':' : (
<span style={{ <span style={{ color: 'rgba(255,255,255,0.45)' }}>{part}</span>
fontSize: 22, )}
fontWeight: 900, {i === 0 && <br />}
letterSpacing: '-0.5px', </span>
color: 'white', ))}
lineHeight: 1, </motion.h1>
}}>
{s.n}
</span>
</div>
))}
</motion.div>
{/* Summary — one line */}
<motion.p
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5, delay: 0.25 }}
style={{
fontSize: 14,
lineHeight: 1.8,
fontWeight: 400,
color: 'rgba(255,255,255,0.6)',
maxWidth: 580,
marginBottom: 32,
}}
>
مدلسازی کمی بر اساس دادههای تجارت ۱۵ کشور رقیب از بدبینانه تا خوشبینانه،
با توصیههای سیاستی مستقیم برای وزارت صمت و سازمان بنادر.
</motion.p>
{/* Divider */}
<div style={{ width: '100%', height: 1, background: 'rgba(255,255,255,0.12)', marginBottom: 24 }} />
{/* Author + Price + CTA in one bar */}
<motion.div
initial={{ opacity: 0, y: 8 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.4, delay: 0.35 }}
style={{
display: 'flex',
alignItems: 'center',
gap: 24,
flexWrap: 'wrap',
}}
>
{/* Author */}
<div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
<div style={{
width: 36, height: 36,
background: 'var(--red)',
color: 'white',
fontSize: 14, fontWeight: 900,
display: 'flex', alignItems: 'center', justifyContent: 'center',
flexShrink: 0,
}}>
{featured.authorInitial}
</div>
<div>
<div style={{ fontSize: 12, fontWeight: 700, color: 'white', lineHeight: 1.2 }}>
{featured.author}
</div>
<div style={{ fontSize: 10, color: 'rgba(255,255,255,0.4)', lineHeight: 1.3 }}>
{featured.authorRole}
</div>
</div>
</div>
{/* Separator */}
<div className="max-sm:hidden" style={{ width: 1, height: 32, background: 'rgba(255,255,255,0.15)' }} />
{/* Price */}
<div style={{ display: 'flex', alignItems: 'baseline', gap: 5 }}>
<span style={{
fontSize: 28,
fontWeight: 900,
color: 'white',
lineHeight: 1,
}}>
{featured.price.toLocaleString('fa-IR')}
</span>
<span style={{ fontSize: 11, color: 'rgba(255,255,255,0.4)' }}>تومان</span>
</div>
{/* Buttons */}
<div className="flex gap-2.5 max-sm:flex-col max-sm:w-full">
<button
onMouseEnter={() => setBuyHov(true)}
onMouseLeave={() => setBuyHov(false)}
style={{
background: buyHov ? 'var(--paper-2)' : 'var(--paper)',
color: 'var(--ink)',
border: 'none',
padding: '11px 26px',
fontSize: 12,
fontWeight: 700,
fontFamily: 'Vazir, sans-serif',
cursor: 'pointer',
transition: 'background 160ms',
whiteSpace: 'nowrap',
}}
className="max-sm:w-full"
>
خرید گزارش
</button>
<button
onMouseEnter={() => setFreeHov(true)}
onMouseLeave={() => setFreeHov(false)}
style={{
background: freeHov ? 'rgba(255,255,255,0.1)' : 'transparent',
color: 'white',
border: '1px solid rgba(255,255,255,0.3)',
padding: '11px 26px',
fontSize: 12,
fontWeight: 400,
fontFamily: 'Vazir, sans-serif',
cursor: 'pointer',
transition: 'background 160ms',
whiteSpace: 'nowrap',
}}
className="max-sm:w-full"
>
دانلود خلاصه رایگان
</button>
</div>
</motion.div>
</div>
{/* ── Right: floating stats panel ── */}
<motion.div
initial={{ opacity: 0, x: -16 }}
animate={{ opacity: 1, x: 0 }}
transition={{ duration: 0.5, delay: 0.45 }}
style={{
background: 'rgba(255,255,255,0.06)',
backdropFilter: 'blur(12px)',
WebkitBackdropFilter: 'blur(12px)',
border: '1px solid rgba(255,255,255,0.1)',
padding: '20px',
marginBottom: 2,
}}
className="max-md:hidden"
>
<div style={{
fontSize: 9,
fontWeight: 700,
letterSpacing: '2px',
textTransform: 'uppercase',
color: 'rgba(255,255,255,0.35)',
marginBottom: 16,
paddingBottom: 10,
borderBottom: '1px solid rgba(255,255,255,0.1)',
}}>
در این گزارش
</div>
{STATS.map((s, i) => (
<div
key={i}
style={{
display: 'flex',
justifyContent: 'space-between',
alignItems: 'baseline',
padding: '10px 0',
borderBottom: i < STATS.length - 1 ? '1px solid rgba(255,255,255,0.07)' : 'none',
}}
>
<span style={{ fontSize: 11, color: 'rgba(255,255,255,0.5)', fontWeight: 300 }}>
{s.label}
</span>
<span style={{
fontSize: 22,
fontWeight: 900,
letterSpacing: '-0.5px',
color: 'white',
lineHeight: 1,
}}>
{s.n}
</span>
</div>
))}
</motion.div>
</div>
</div> </div>
</section> </section>
) )

View File

@ -51,27 +51,12 @@ function Accent({ color = 'var(--red)' }: { color?: string }) {
/* ─── Section ────────────────────────────────────────────── */ /* ─── Section ────────────────────────────────────────────── */
export default function LatestNewsBentoSection() { export default function LatestNewsBentoSection() {
return ( return (
<section style={{ background: 'var(--paper-2)', borderBottom: '2px solid var(--ink)' }}> <section style={{ background: 'var(--paper)', borderBottom: '2px solid var(--ink)' }}>
{/* ── Header ── */} {/* ── Header ── */}
<div className="px-12 pt-16 max-md:px-5 max-md:pt-10"> <div className="max-w-7xl mx-auto px-12 pt-8 pb-4 max-md:px-5 max-md:pt-6 flex justify-between items-center text-xs text-[var(--ink-4)]">
<div style={{ <span>رصد روزانه بازار و صنعت</span>
display: 'flex', alignItems: 'center', gap: 16, <span>بهمن ۱۴۰۳</span>
marginBottom: 32, paddingBottom: 20, borderBottom: '2px solid var(--ink)',
}}>
<div style={{
background: 'var(--ink)', color: 'var(--paper)',
fontSize: 9, fontWeight: 700, letterSpacing: '3px',
textTransform: 'uppercase', padding: '6px 16px',
}}>
آخرین اخبار
</div>
<h2 style={{ fontSize: 'clamp(16px,2vw,22px)', fontWeight: 900, letterSpacing: '-0.5px' }}>
رصد روزانه بازار و صنعت
</h2>
<div style={{ flex: 1 }} />
<span style={{ fontSize: 10, fontWeight: 500, color: 'var(--ink-5)' }}>بهمن ۱۴۰۳</span>
</div>
</div> </div>
{/* ── Bento grid ── */} {/* ── Bento grid ── */}
@ -80,7 +65,7 @@ export default function LatestNewsBentoSection() {
whileInView={{ opacity: 1, y: 0 }} whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }} viewport={{ once: true }}
transition={{ duration: 0.5 }} transition={{ duration: 0.5 }}
className="px-12 pb-14 max-md:px-5 max-md:pb-10" className="max-w-7xl mx-auto w-full px-12 pb-14 max-md:px-5 max-md:pb-10"
> >
{/* {/*
3-col grid on desktop, 1-col on mobile. 3-col grid on desktop, 1-col on mobile.

View File

@ -13,11 +13,11 @@ export default function NewsletterSection() {
} }
return ( return (
<section style={{ borderBottom: '3px solid var(--ink)' }}> <section style={{ borderBottom: '3px solid var(--ink)', background: 'var(--paper-2)' }}>
{/* Outer grid — strip inline padding, use Tailwind */} {/* Outer grid — strip inline padding, use Tailwind */}
<div <div
style={{ display: 'grid', gridTemplateColumns: '1fr 1px 1fr', minHeight: 180 }} style={{ display: 'grid', gridTemplateColumns: '1fr 1px 1fr', minHeight: 180 }}
className="px-12 max-md:px-5 max-md:grid-cols-1" className="max-w-7xl mx-auto w-full px-12 max-md:px-5 max-md:grid-cols-1"
> >
{/* Left: description */} {/* Left: description */}
<div <div

View File

@ -1,28 +1,39 @@
import { useState } from 'react' import { useState } from 'react'
import { plans } from '@/data/plans' import { plans } from '@/data/plans'
/* ─── Checkmark icon ─────────────────────────────────── */ /* ─── Star icon (for "popular" badge) ──────────────── */
function Star() {
return (
<svg width="11" height="11" viewBox="0 0 16 16" fill="currentColor" style={{ flexShrink: 0 }}>
<path d="M8 1l2.09 4.23L14.78 6l-3.39 3.31.8 4.69L8 11.77 3.81 14l.8-4.69L1.22 6l4.69-.77L8 1z" />
</svg>
)
}
/* ─── Check icon ──────────────────────────────────── */
function Check({ featured }: { featured: boolean }) { function Check({ featured }: { featured: boolean }) {
return ( return (
<svg <svg
width="16" height="16" viewBox="0 0 16 16" fill="none" width="14" height="14" viewBox="0 0 16 16" fill="none"
style={{ flexShrink: 0, marginTop: 1 }} style={{ flexShrink: 0, marginTop: 3 }}
> >
<circle
cx="8" cy="8" r="7.5"
stroke={featured ? 'rgba(255,255,255,0.35)' : 'var(--rule-thin)'}
fill={featured ? 'rgba(255,255,255,0.1)' : 'transparent'}
/>
<path <path
d="M5 8l2 2 4-4" d="M3 8.5l3 3 7-7"
stroke={featured ? '#f4efe7' : 'var(--green-ink)'} stroke={featured ? 'rgba(244,239,231,0.85)' : 'var(--ink)'}
strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round" strokeWidth="1.75" strokeLinecap="round" strokeLinejoin="round"
/> />
</svg> </svg>
) )
} }
/* ─── Individual plan card ───────────────────────────── */ /* ─── Plan tagline lookup ─────────────────────────── */
const TAGLINE: Record<string, string> = {
individual: 'برای کارشناسان و محققان',
organizational: 'برای شرکت‌ها و سازمان‌ها',
ministry: 'برای نهادهای دولتی',
}
/* ─── Individual plan card ────────────────────────── */
function PlanCard({ plan, isMiddle }: { plan: (typeof plans)[0]; isMiddle: boolean }) { function PlanCard({ plan, isMiddle }: { plan: (typeof plans)[0]; isMiddle: boolean }) {
const [hovered, setHovered] = useState(false) const [hovered, setHovered] = useState(false)
const featured = plan.featured const featured = plan.featured
@ -30,148 +41,152 @@ function PlanCard({ plan, isMiddle }: { plan: (typeof plans)[0]; isMiddle: boole
return ( return (
<div <div
style={{ style={{
background: featured ? 'var(--ink)' : 'white', position: 'relative',
border: featured ? 'none' : '1px solid var(--rule-thin)', background: featured ? 'var(--ink)' : 'var(--paper)',
borderTop: featured ? 'none' : '1px solid var(--rule-thin)', border: '1px solid var(--rule-thin)',
padding: '32px 28px', display: 'flex',
display: 'flex',
flexDirection: 'column', flexDirection: 'column',
position: 'relative', boxShadow: isMiddle ? '0 12px 40px rgba(26,23,18,0.14)' : 'none',
boxShadow: isMiddle ? '0 8px 40px rgba(26,23,18,0.12)' : 'none', zIndex: isMiddle ? 1 : 0,
zIndex: isMiddle ? 1 : 0, transform: isMiddle ? 'translateY(-4px)' : 'none',
}} }}
> >
{/* Badge */} {/* "Popular" badge — top right */}
{plan.badge && ( {plan.badge && (
<div style={{ <div style={{
position: 'absolute', position: 'absolute',
top: -12, top: 12,
right: '50%', right: 12,
transform: 'translateX(50%)', background: 'var(--red)',
background: 'var(--red)', color: 'white',
color: 'white', padding: '5px 10px',
fontSize: 9, fontSize: 10,
fontWeight: 700, fontWeight: 700,
letterSpacing: '2px', letterSpacing: '1.5px',
textTransform: 'uppercase', display: 'flex',
padding: '4px 14px', alignItems: 'center',
whiteSpace: 'nowrap', gap: 5,
zIndex: 10,
}}> }}>
<Star />
{plan.badge} {plan.badge}
</div> </div>
)} )}
{/* Plan name */} {/* Header */}
<div style={{ <div style={{
fontSize: 11, background: featured ? 'rgba(255,255,255,0.04)' : 'var(--paper-2)',
fontWeight: 700, borderBottom: featured ? '1px solid rgba(255,255,255,0.08)' : '1px solid var(--rule-thin)',
letterSpacing: '1.5px', padding: '20px 22px',
textTransform: 'uppercase',
color: featured ? 'rgba(244,239,231,0.5)' : 'var(--ink-5)',
marginBottom: 8,
}}> }}>
{plan.name} <div style={{
</div> fontSize: 15,
fontWeight: 800,
{/* Tagline */} color: featured ? 'var(--paper)' : 'var(--ink)',
<div style={{ marginBottom: 4,
fontSize: 13,
color: featured ? 'rgba(244,239,231,0.55)' : 'var(--ink-4)',
marginBottom: 24,
fontWeight: 300,
}}>
{plan.id === 'individual' && 'برای کارشناسان و محققان'}
{plan.id === 'organizational' && 'برای شرکت‌ها و سازمان‌ها'}
{plan.id === 'ministry' && 'برای نهادهای دولتی'}
</div>
{/* Price */}
<div style={{ marginBottom: 6 }}>
<span style={{
fontSize: 42,
fontWeight: 900,
letterSpacing: '-2px',
lineHeight: 1,
color: featured ? 'var(--paper)' : 'var(--ink)',
fontVariantNumeric: 'tabular-nums',
}}> }}>
{plan.price === 0 ? 'تماس' : plan.price.toLocaleString('fa-IR')} {plan.name}
</span> </div>
{plan.price > 0 && ( <p style={{
fontSize: 12,
color: featured ? 'rgba(244,239,231,0.55)' : 'var(--ink-4)',
marginBottom: 14,
fontWeight: 400,
lineHeight: 1.5,
}}>
{TAGLINE[plan.id]}
</p>
<div style={{ display: 'flex', alignItems: 'baseline', gap: 6 }}>
<span style={{ <span style={{
fontSize: 13, fontSize: 26,
fontWeight: 400, fontWeight: 900,
color: featured ? 'rgba(244,239,231,0.5)' : 'var(--ink-4)', letterSpacing: '-0.8px',
marginRight: 6, lineHeight: 1,
color: featured ? 'var(--paper)' : 'var(--ink)',
fontVariantNumeric: 'tabular-nums',
}}> }}>
تومان {plan.price === 0 ? 'تماس' : plan.price.toLocaleString('fa-IR')}
</span> </span>
)} {plan.price > 0 ? (
<span style={{
fontSize: 11,
color: featured ? 'rgba(244,239,231,0.55)' : 'var(--ink-4)',
fontWeight: 500,
}}>
تومان / {plan.period}
</span>
) : (
<span style={{
fontSize: 11,
color: featured ? 'rgba(244,239,231,0.55)' : 'var(--ink-4)',
fontWeight: 500,
}}>
· {plan.period}
</span>
)}
</div>
</div> </div>
<div style={{
fontSize: 11,
color: featured ? 'rgba(244,239,231,0.4)' : 'var(--ink-5)',
marginBottom: 28,
}}>
{plan.period}
</div>
{/* CTA button */}
<button
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
style={{
width: '100%',
padding: '12px',
border: featured
? 'none'
: hovered ? 'none' : '1px solid var(--ink)',
background: featured
? hovered ? 'var(--paper-2)' : 'var(--paper)'
: hovered ? 'var(--ink)' : 'transparent',
color: featured
? 'var(--ink)'
: hovered ? 'var(--paper)' : 'var(--ink)',
fontSize: 12,
fontWeight: 700,
fontFamily: 'Vazir, sans-serif',
cursor: 'pointer',
borderRadius: 0,
marginBottom: 28,
letterSpacing: '0.5px',
transition: 'background 180ms, color 180ms, border 180ms',
}}
>
{plan.ctaLabel}
</button>
{/* Divider */}
<div style={{
borderTop: featured ? '1px solid rgba(244,239,231,0.12)' : '1px solid var(--rule-thin)',
marginBottom: 24,
}} />
{/* Features */} {/* Features */}
<ul style={{ listStyle: 'none', display: 'flex', flexDirection: 'column', gap: 12 }}> <div style={{
padding: '18px 22px',
display: 'flex',
flexDirection: 'column',
gap: 10,
flex: 1,
}}>
{plan.features.map(f => ( {plan.features.map(f => (
<li key={f} style={{ display: 'flex', alignItems: 'flex-start', gap: 10, textAlign: 'right' }}> <div key={f} style={{ display: 'flex', alignItems: 'flex-start', gap: 9 }}>
<Check featured={featured} /> <Check featured={featured} />
<span style={{ <span style={{
fontSize: 13, fontSize: 12,
lineHeight: 1.5, lineHeight: 1.55,
color: featured ? 'rgba(244,239,231,0.75)' : 'var(--ink-3)', color: featured ? 'rgba(244,239,231,0.8)' : 'var(--ink-3)',
fontWeight: 300, fontWeight: 400,
}}> }}>
{f} {f}
</span> </span>
</li> </div>
))} ))}
</ul> </div>
{/* CTA */}
<div style={{
borderTop: featured ? '1px solid rgba(255,255,255,0.08)' : '1px solid var(--rule-thin)',
padding: '12px 22px 14px',
}}>
<button
onMouseEnter={() => setHovered(true)}
onMouseLeave={() => setHovered(false)}
style={{
width: '100%',
padding: '10px',
border: featured
? 'none'
: hovered ? 'none' : '1px solid var(--ink)',
background: featured
? hovered ? 'var(--paper-2)' : 'var(--paper)'
: hovered ? 'var(--ink)' : 'transparent',
color: featured
? 'var(--ink)'
: hovered ? 'var(--paper)' : 'var(--ink)',
fontSize: 12,
fontWeight: 700,
fontFamily: 'Vazir, sans-serif',
cursor: 'pointer',
borderRadius: 0,
letterSpacing: '0.5px',
transition: 'background 180ms, color 180ms, border 180ms',
}}
>
{plan.ctaLabel}
</button>
</div>
</div> </div>
) )
} }
/* ─── Enterprise bottom card ─────────────────────────── */ /* ─── Enterprise bottom card ─────────────────────── */
const enterpriseFeatures = [ const enterpriseFeatures = [
'پروژه‌های نامحدود', 'پروژه‌های نامحدود',
'پشتیبانی تیمی اختصاصی', 'پشتیبانی تیمی اختصاصی',
@ -190,34 +205,35 @@ const enterpriseFeatures = [
function EnterpriseCard() { function EnterpriseCard() {
const [hov, setHov] = useState(false) const [hov, setHov] = useState(false)
return ( return (
<div style={{ <div
border: '1px solid var(--rule-thin)', style={{
background: 'white', border: '1px solid var(--rule-thin)',
padding: '36px 40px', background: 'var(--paper)',
display: 'grid', padding: '28px 32px',
gridTemplateColumns: '1fr 1fr', display: 'grid',
gap: '40px', gridTemplateColumns: '1fr 1fr',
alignItems: 'start', gap: '32px',
}} alignItems: 'start',
className="max-md:grid-cols-1 max-md:gap-6" }}
className="max-md:grid-cols-1 max-md:gap-6 max-md:p-6"
> >
{/* Left: description */} {/* Left: description */}
<div> <div>
<div style={{ <div style={{
fontSize: 11, fontWeight: 700, letterSpacing: '2px', fontSize: 10, fontWeight: 700, letterSpacing: '1.5px',
textTransform: 'uppercase', color: 'var(--ink-5)', marginBottom: 10, textTransform: 'uppercase', color: 'var(--ink-5)', marginBottom: 8,
}}> }}>
وزارتخانه / سازمان دولتی وزارتخانه / سازمان دولتی
</div> </div>
<h3 style={{ <h3 style={{
fontSize: 22, fontWeight: 900, letterSpacing: '-0.5px', fontSize: 18, fontWeight: 900, letterSpacing: '-0.4px',
color: 'var(--ink)', marginBottom: 12, color: 'var(--ink)', marginBottom: 10,
}}> }}>
راهکار سازمانی کامل راهکار سازمانی کامل
</h3> </h3>
<p style={{ <p style={{
fontSize: 13, lineHeight: 1.8, color: 'var(--ink-3)', fontSize: 12, lineHeight: 1.75, color: 'var(--ink-3)',
fontWeight: 300, marginBottom: 24, fontWeight: 400, marginBottom: 20,
}}> }}>
به راهکارهای سفارشی، پشتیبانی اختصاصی یا قیمتگذاری حجمی نیاز دارید؟ به راهکارهای سفارشی، پشتیبانی اختصاصی یا قیمتگذاری حجمی نیاز دارید؟
با کارشناسان ما درباره پلن منحصربهفرد سازمانتان صحبت کنید. با کارشناسان ما درباره پلن منحصربهفرد سازمانتان صحبت کنید.
@ -226,15 +242,15 @@ function EnterpriseCard() {
onMouseEnter={() => setHov(true)} onMouseEnter={() => setHov(true)}
onMouseLeave={() => setHov(false)} onMouseLeave={() => setHov(false)}
style={{ style={{
padding: '13px 28px', padding: '11px 24px',
border: '1px solid var(--ink)', border: '1px solid var(--ink)',
background: hov ? 'var(--ink)' : 'transparent', background: hov ? 'var(--ink)' : 'transparent',
color: hov ? 'var(--paper)' : 'var(--ink)', color: hov ? 'var(--paper)' : 'var(--ink)',
fontSize: 12, fontWeight: 700, fontSize: 12, fontWeight: 700,
fontFamily: 'Vazir, sans-serif', fontFamily: 'Vazir, sans-serif',
cursor: 'pointer', cursor: 'pointer',
borderRadius: 0, borderRadius: 0,
transition: 'background 180ms, color 180ms', transition: 'background 180ms, color 180ms',
letterSpacing: '0.5px', letterSpacing: '0.5px',
}} }}
> >
@ -246,12 +262,12 @@ function EnterpriseCard() {
<div style={{ <div style={{
display: 'grid', display: 'grid',
gridTemplateColumns: '1fr 1fr', gridTemplateColumns: '1fr 1fr',
gap: '10px 20px', gap: '8px 18px',
}}> }}>
{enterpriseFeatures.map(f => ( {enterpriseFeatures.map(f => (
<div key={f} style={{ display: 'flex', alignItems: 'center', gap: 8 }}> <div key={f} style={{ display: 'flex', alignItems: 'center', gap: 7 }}>
<Check featured={false} /> <Check featured={false} />
<span style={{ fontSize: 12, color: 'var(--ink-3)', lineHeight: 1.4, fontWeight: 300 }}> <span style={{ fontSize: 11, color: 'var(--ink-3)', lineHeight: 1.4, fontWeight: 400 }}>
{f} {f}
</span> </span>
</div> </div>
@ -261,39 +277,37 @@ function EnterpriseCard() {
) )
} }
/* ─── Section ────────────────────────────────────────── */ /* ─── Section ────────────────────────────────────── */
export default function PlansSection() { export default function PlansSection() {
const allThree = plans
return ( return (
<section style={{ <section style={{
background: 'var(--paper-2)', background: 'var(--paper)',
borderBottom: '2px solid var(--ink)', borderBottom: '2px solid var(--ink)',
}}> }}>
<div className="px-12 py-20 max-md:px-5 max-md:py-14"> <div className="max-w-6xl mx-auto px-12 py-16 max-md:px-5 max-md:py-12">
{/* Header */} {/* Header */}
<div style={{ textAlign: 'center', marginBottom: 56 }}> <div style={{ textAlign: 'center', marginBottom: 40 }}>
<div style={{ <div style={{
fontSize: 9, fontWeight: 700, letterSpacing: '3px', fontSize: 10, fontWeight: 700, letterSpacing: '2.5px',
textTransform: 'uppercase', color: 'var(--red)', textTransform: 'uppercase', color: 'var(--red)',
marginBottom: 14, marginBottom: 12,
}}> }}>
اشتراک و دسترسی اشتراک و دسترسی
</div> </div>
<h2 style={{ <h2 style={{
fontSize: 'clamp(26px, 3vw, 40px)', fontSize: 'clamp(22px, 2.4vw, 32px)',
fontWeight: 900, fontWeight: 900,
letterSpacing: '-1.5px', letterSpacing: '-1px',
color: 'var(--ink)', color: 'var(--ink)',
marginBottom: 12, marginBottom: 10,
}}> }}>
پلن مناسب خود را انتخاب کنید پلن مناسب خود را انتخاب کنید
</h2> </h2>
<p style={{ <p style={{
fontSize: 14, lineHeight: 1.8, fontSize: 13, lineHeight: 1.7,
color: 'var(--ink-4)', fontWeight: 300, color: 'var(--ink-4)', fontWeight: 400,
maxWidth: 480, margin: '0 auto', maxWidth: 460, margin: '0 auto',
}}> }}>
از دسترسی پایه برای پژوهشگران تا راهکار کامل برای وزارتخانهها از دسترسی پایه برای پژوهشگران تا راهکار کامل برای وزارتخانهها
هر سطحی از نیاز را پوشش میدهیم. هر سطحی از نیاز را پوشش میدهیم.
@ -301,16 +315,17 @@ export default function PlansSection() {
</div> </div>
{/* 3-col plan cards */} {/* 3-col plan cards */}
<div style={{ <div
display: 'grid', style={{
gridTemplateColumns: 'repeat(3, 1fr)', display: 'grid',
gap: 0, gridTemplateColumns: 'repeat(3, 1fr)',
marginBottom: 32, gap: 16,
position: 'relative', marginBottom: 20,
}} alignItems: 'stretch',
className="max-md:grid-cols-1 max-md:gap-0" }}
className="max-md:grid-cols-1 max-md:gap-4"
> >
{allThree.map((plan, idx) => ( {plans.map((plan, idx) => (
<PlanCard <PlanCard
key={plan.id} key={plan.id}
plan={plan} plan={plan}
@ -325,10 +340,10 @@ export default function PlansSection() {
{/* Money-back note */} {/* Money-back note */}
<div style={{ <div style={{
textAlign: 'center', textAlign: 'center',
marginTop: 20, marginTop: 18,
fontSize: 11, fontSize: 11,
color: 'var(--ink-5)', color: 'var(--ink-5)',
fontWeight: 300, fontWeight: 400,
}}> }}>
&nbsp; ضمانت بازگشت وجه ۱۴ روزه &nbsp;·&nbsp; بدون قرارداد اجباری &nbsp; ضمانت بازگشت وجه ۱۴ روزه &nbsp;·&nbsp; بدون قرارداد اجباری
</div> </div>

View File

@ -236,33 +236,9 @@ export default function ReportsCarouselSection() {
)) ))
return ( return (
<section style={{ borderBottom: '2px solid var(--ink)' }}> <section style={{ borderBottom: '2px solid var(--ink)', background: 'var(--paper-2)', paddingBottom: 40 }}>
{/* Header */} {/* Legend & Link Row */}
<div className="px-12 max-md:px-5"> <div className="max-w-7xl mx-auto px-12 pt-10 max-md:px-5 flex items-center justify-between flex-wrap gap-4">
<div style={{
display: 'flex', alignItems: 'center',
borderBottom: '1px solid var(--rule-thin)', paddingTop: 52,
}}>
<div style={{
background: 'var(--ink)', color: 'var(--paper)',
padding: '8px 20px', fontSize: 9, fontWeight: 700,
letterSpacing: '3px', textTransform: 'uppercase',
}}>
تحلیلهای اخیر
</div>
<div style={{ flex: 1 }} />
<Link to="/reports" style={{
fontSize: 10, fontWeight: 700, letterSpacing: '1.5px',
textTransform: 'uppercase', color: 'var(--ink-4)',
textDecoration: 'none', padding: '8px 0',
}}>
همه گزارشها
</Link>
</div>
</div>
{/* Legend */}
<div className="px-12 pt-[14px] max-md:px-5">
<div style={{ display: 'flex', gap: 16, flexWrap: 'wrap' }}> <div style={{ display: 'flex', gap: 16, flexWrap: 'wrap' }}>
{Object.entries(typeLabel).map(([key, label]) => ( {Object.entries(typeLabel).map(([key, label]) => (
<div key={key} style={{ display: 'flex', alignItems: 'center', gap: 5 }}> <div key={key} style={{ display: 'flex', alignItems: 'center', gap: 5 }}>
@ -271,9 +247,18 @@ export default function ReportsCarouselSection() {
</div> </div>
))} ))}
</div> </div>
<Link to="/reports" style={{
fontSize: 10, fontWeight: 700, letterSpacing: '1.5px',
textTransform: 'uppercase', color: 'var(--ink-4)',
textDecoration: 'none',
}}>
همه گزارشها
</Link>
</div> </div>
<Carousel items={cardElements} /> <div className="max-w-7xl mx-auto w-full px-12 max-md:px-5 mt-6">
<Carousel items={cardElements} />
</div>
</section> </section>
) )
} }

View File

@ -90,51 +90,10 @@ export default function RiskSection() {
}, []) }, [])
return ( return (
<section style={{ borderBottom: '2px solid var(--ink)', background: 'var(--paper-2)' }}> <section style={{ borderBottom: '2px solid var(--ink)', background: 'var(--paper)' }}>
<div className="px-12 pt-14 max-md:px-5 max-md:pt-10"> {/* ── Legend, active count, and link row ── */}
<div className="max-w-7xl mx-auto px-12 pt-8 pb-2 max-md:px-5 max-md:pt-6 flex justify-between items-center flex-wrap gap-4 text-xs">
{/* ── Header bar ── */} <div style={{ display: 'flex', gap: 20, flexWrap: 'wrap' }}>
<div style={{
display: 'flex',
alignItems: 'center',
borderBottom: '1px solid var(--rule-thin)',
}}>
<div style={{
background: 'var(--red)',
color: 'white',
padding: '8px 20px',
fontSize: 9,
fontWeight: 700,
letterSpacing: '3px',
textTransform: 'uppercase',
}}>
پایش ریسک · لحظهای
</div>
<div style={{
marginRight: 16,
fontSize: 10,
color: 'var(--ink-5)',
fontWeight: 600,
letterSpacing: '0.5px',
}}>
{riskItems.length} سیگنال فعال
</div>
<div style={{ flex: 1 }} />
<Link to="/risks" style={{
fontSize: 10,
fontWeight: 700,
letterSpacing: '1.5px',
textTransform: 'uppercase',
color: 'var(--ink-4)',
textDecoration: 'none',
padding: '8px 0',
}}>
همه ریسکها
</Link>
</div>
{/* ── Legend ── */}
<div style={{ display: 'flex', gap: 20, flexWrap: 'wrap', padding: '14px 0 0' }}>
{[ {[
{ color: '#7f1d1d', label: 'بحرانی' }, { color: '#7f1d1d', label: 'بحرانی' },
{ color: '#9b1c1c', label: 'بالا' }, { color: '#9b1c1c', label: 'بالا' },
@ -148,6 +107,19 @@ export default function RiskSection() {
</div> </div>
))} ))}
</div> </div>
<div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
<span style={{ color: 'var(--ink-5)', fontWeight: 600 }}>{riskItems.length} سیگنال فعال</span>
<Link to="/risks" style={{
fontSize: 10,
fontWeight: 700,
letterSpacing: '1.5px',
textTransform: 'uppercase',
color: 'var(--ink-4)',
textDecoration: 'none',
}}>
همه ریسکها
</Link>
</div>
</div> </div>
{/* ── Auto-scroll ticker ── */} {/* ── Auto-scroll ticker ── */}

View File

@ -13,11 +13,10 @@ export default function SnapshotBar() {
> >
<div <div
style={{ style={{
padding: '0 48px',
display: 'grid', display: 'grid',
gridTemplateColumns: 'repeat(4, 1fr)', gridTemplateColumns: 'repeat(4, 1fr)',
}} }}
className="max-md:grid-cols-2 max-md:px-6" className="max-w-7xl mx-auto w-full px-12 max-md:px-6 max-md:grid-cols-2"
> >
{prices.map((price, idx) => { {prices.map((price, idx) => {
const isLast = idx === prices.length - 1 const isLast = idx === prices.length - 1

View File

@ -1,48 +1,215 @@
import { useState } from 'react'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import { team } from '@/data/team' import { team } from '@/data/team'
function MemberCard({ member, idx }: { member: (typeof team)[0]; idx: number }) { function MemberCard({ member }: { member: (typeof team)[0] }) {
const borderRight = idx % 2 === 0 ? '1px solid var(--rule-thin)' : 'none' const [hovered, setHovered] = useState(false)
const borderTop = idx >= 2 ? '1px solid var(--rule-thin)' : 'none'
return ( return (
<div <div
style={{ padding: '40px', borderRight, borderTop, cursor: 'pointer', transition: 'background 200ms' }} onMouseEnter={() => setHovered(true)}
onMouseEnter={e => (e.currentTarget.style.background = 'var(--paper-2)')} onMouseLeave={() => setHovered(false)}
onMouseLeave={e => (e.currentTarget.style.background = 'transparent')} style={{
className="max-md:border-r-0 max-md:border-t max-md:border-[var(--rule-thin)] max-md:first:border-t-0 max-md:p-6" background: hovered ? 'var(--paper-2)' : 'var(--paper)',
display: 'flex',
flexDirection: 'column',
transition: 'background 150ms ease',
position: 'relative',
}}
className="p-6 max-md:p-5 cursor-pointer border border-[var(--rule-thin)]"
> >
<div style={{ width: 56, height: 56, background: 'var(--paper-3)', border: '1px solid var(--rule-thin)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 22, fontWeight: 900, color: 'var(--ink)', marginBottom: 16 }}> {/* Top row: avatar + name/role + reports stat */}
{member.initial} <div style={{ display: 'flex', alignItems: 'flex-start', gap: 12 }}>
{/* Avatar */}
<div
style={{
width: 44,
height: 44,
background: 'var(--ink)',
color: 'var(--paper)',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
fontSize: 16,
fontWeight: 900,
borderRadius: '50%',
flexShrink: 0,
}}
>
{member.initial}
</div>
{/* Name + role */}
<div style={{ flex: 1, minWidth: 0 }}>
<h3
style={{
fontSize: 14,
fontWeight: 800,
color: 'var(--ink)',
lineHeight: 1.3,
marginBottom: 2,
letterSpacing: '-0.2px',
}}
>
{member.name}
</h3>
<span
style={{
fontSize: 10,
fontWeight: 700,
color: 'var(--red)',
letterSpacing: '1px',
textTransform: 'uppercase',
}}
>
{member.role}
</span>
</div>
{/* Report count — top left (RTL → visual end) */}
<div style={{ textAlign: 'left', flexShrink: 0 }}>
<div
style={{
fontSize: 18,
fontWeight: 900,
color: 'var(--ink)',
lineHeight: 1,
fontVariantNumeric: 'tabular-nums',
}}
>
{member.reportCount.toLocaleString('fa-IR')}
</div>
<div
style={{
fontSize: 9,
color: 'var(--ink-5)',
marginTop: 3,
fontWeight: 500,
}}
>
گزارش
</div>
</div>
</div> </div>
<div style={{ fontSize: 15, fontWeight: 800, color: 'var(--ink)', letterSpacing: '-0.3px', marginBottom: 3 }}>{member.name}</div>
<div style={{ fontSize: 10, fontWeight: 700, letterSpacing: '1.5px', textTransform: 'uppercase', color: 'var(--red)', marginBottom: 12 }}>{member.role}</div> {/* Bio */}
<p style={{ fontSize: 13, color: 'var(--ink-3)', lineHeight: 1.75, fontWeight: 400, marginBottom: 14 }}>{member.bio}</p> <p
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 5, marginBottom: 14 }}> style={{
{member.expertise.slice(0, 4).map(tag => ( fontSize: 12,
<span key={tag} style={{ fontSize: 9, padding: '2px 7px', background: 'var(--paper-3)', color: 'var(--ink-4)', fontWeight: 600, letterSpacing: '0.5px' }}>{tag}</span> color: 'var(--ink-3)',
lineHeight: 1.7,
fontWeight: 400,
marginTop: 14,
marginBottom: 14,
display: '-webkit-box',
WebkitLineClamp: 3,
WebkitBoxOrient: 'vertical',
overflow: 'hidden',
}}
>
{member.bio}
</p>
{/* Tags — max 3 */}
<div style={{ display: 'flex', flexWrap: 'wrap', gap: 5, marginBottom: 12 }}>
{member.expertise.slice(0, 3).map(tag => (
<span
key={tag}
style={{
fontSize: 10,
padding: '2px 8px',
color: 'var(--ink-4)',
border: '1px solid var(--rule-thin)',
fontWeight: 500,
whiteSpace: 'nowrap',
}}
>
{tag}
</span>
))} ))}
</div> </div>
<div style={{ paddingTop: 12, borderTop: '1px solid var(--rule-thin)', fontSize: 11, color: 'var(--ink-5)' }}>
<strong style={{ fontSize: 20, fontWeight: 900, color: 'var(--ink)', marginLeft: 4 }}>{member.reportCount}</strong> {/* Footer: email */}
گزارش منتشرشده {member.email && (
</div> <div
style={{
paddingTop: 10,
borderTop: '1px solid var(--rule-thin)',
marginTop: 'auto',
}}
>
<a
href={`mailto:${member.email}`}
style={{
fontSize: 10,
color: 'var(--ink-5)',
textDecoration: 'none',
fontWeight: 500,
direction: 'ltr',
fontFamily: 'ui-monospace, monospace',
}}
>
{member.email}
</a>
</div>
)}
</div> </div>
) )
} }
export default function TeamSection() { export default function TeamSection() {
const displayedMembers = team.slice(0, 4)
return ( return (
<section style={{ borderBottom: '2px solid var(--ink)' }}> <section style={{ borderBottom: '2px solid var(--ink)', background: 'var(--paper-2)' }}>
<div className="px-12 py-20 max-md:px-5 max-md:py-14"> <div className="max-w-6xl mx-auto px-12 py-16 max-md:px-5 max-md:py-12">
<div style={{ display: 'flex', alignItems: 'center', borderBottom: '1px solid var(--rule-thin)', marginBottom: '40px' }}> {/* Editorial sub-bar */}
<div style={{ background: 'var(--ink)', color: 'var(--paper)', padding: '8px 20px', fontSize: '9px', fontWeight: 700, letterSpacing: '3px', textTransform: 'uppercase' }}>تیم تحریریه</div> <div
<div style={{ flex: 1 }} /> style={{
<Link to="/team" style={{ fontSize: '10px', fontWeight: 700, letterSpacing: '1.5px', textTransform: 'uppercase', color: 'var(--ink-4)', textDecoration: 'none', padding: '8px 0' }}>همه کارشناسان </Link> display: 'flex',
alignItems: 'center',
justifyContent: 'space-between',
borderBottom: '1px solid var(--rule-thin)',
paddingBottom: 14,
marginBottom: 24,
}}
className="flex-wrap gap-3"
>
<span
style={{
fontSize: 12,
fontWeight: 400,
color: 'var(--ink-4)',
fontStyle: 'italic',
}}
>
اعضای هیئت تحریریه و متخصصان راهبردی
</span>
<Link
to="/team"
style={{
fontSize: 11,
fontWeight: 700,
letterSpacing: '1px',
color: 'var(--red)',
textDecoration: 'none',
}}
>
همه کارشناسان
</Link>
</div> </div>
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr' }} className="max-md:grid-cols-1">
{team.slice(0, 4).map((member, idx) => ( {/* 2x2 grid on desktop, single column on mobile */}
<MemberCard key={member.id} member={member} idx={idx} /> <div
style={{
display: 'grid',
gridTemplateColumns: 'repeat(2, 1fr)',
gap: 12,
}}
className="max-md:grid-cols-1"
>
{displayedMembers.map(member => (
<MemberCard key={member.id} member={member} />
))} ))}
</div> </div>
</div> </div>

View File

@ -161,21 +161,15 @@ function ComparisonTool() {
{/* Side-by-side comparison */} {/* Side-by-side comparison */}
<div <div
style={{ className="grid grid-cols-[1fr_auto_1fr] max-md:grid-cols-1 border border-[var(--rule-thin)]"
display: 'grid',
gridTemplateColumns: '1fr auto 1fr',
gap: 0,
border: '1px solid var(--rule-thin)',
}}
> >
<div style={{ padding: 32, textAlign: 'center' }}> <div className="max-md:border-b max-md:border-[var(--rule-thin)]" style={{ padding: 32, textAlign: 'center' }}>
<p style={{ fontSize: 13, color: 'var(--ink-3)', marginBottom: 8 }}>{itemA.name}</p> <p style={{ fontSize: 13, color: 'var(--ink-3)', marginBottom: 8 }}>{itemA.name}</p>
<p <p
style={{ style={{
fontSize: 32, fontSize: 32,
fontWeight: 900, fontWeight: 900,
color: 'var(--ink)', color: 'var(--ink)',
letterSpacing: '-1px',
lineHeight: 1, lineHeight: 1,
}} }}
> >
@ -214,13 +208,9 @@ function ComparisonTool() {
{/* VS divider */} {/* VS divider */}
<div <div
style={{ style={{
borderRight: '1px solid var(--rule-thin)',
borderLeft: '1px solid var(--rule-thin)',
width: 60, width: 60,
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
}} }}
className="max-md:hidden border-r border-l border-[var(--rule-thin)] flex items-center justify-center"
> >
<span <span
style={{ style={{
@ -242,7 +232,6 @@ function ComparisonTool() {
fontSize: 32, fontSize: 32,
fontWeight: 900, fontWeight: 900,
color: 'var(--ink)', color: 'var(--ink)',
letterSpacing: '-1px',
lineHeight: 1, lineHeight: 1,
}} }}
> >
@ -526,13 +515,7 @@ export default function Market() {
subtitle="قیمت بازار داخلی — تومان به کیلوگرم / دلار به تن" subtitle="قیمت بازار داخلی — تومان به کیلوگرم / دلار به تن"
/> />
<div <div
style={{ className="grid grid-cols-4 max-lg:grid-cols-2 max-sm:grid-cols-1 border-t border-r border-[var(--rule-thin)] price-grid"
display: 'grid',
gridTemplateColumns: 'repeat(4, 1fr)',
borderTop: '1px solid var(--rule-thin)',
borderRight: '1px solid var(--rule-thin)',
}}
className="price-grid"
> >
{marketPrices.map((item) => ( {marketPrices.map((item) => (
<PriceCard key={item.id} item={item} /> <PriceCard key={item.id} item={item} />

View File

@ -126,95 +126,97 @@ export default function Risks() {
ماتریس ریسکهای کلیدی ماتریس ریسکهای کلیدی
</h2> </h2>
<div style={{ border: '1px solid var(--ink)', overflow: 'hidden' }}> <div className="overflow-x-auto border border-[var(--ink)]">
{/* Table Header */} <div style={{ minWidth: 768 }}>
<div {/* Table Header */}
style={{ <div
display: 'grid', style={{
gridTemplateColumns: '48px 1fr 100px 100px 120px 130px', display: 'grid',
background: 'var(--ink)', gridTemplateColumns: '48px 1fr 100px 100px 120px 130px',
color: 'var(--paper)', background: 'var(--ink)',
padding: '12px 16px', color: 'var(--paper)',
gap: '0', padding: '12px 16px',
}} gap: '0',
> }}
{['#', 'عنوان ریسک', 'دسته', 'احتمال', 'شدت تأثیر', 'سطح ریسک'].map((col, i) => ( >
<div {['#', 'عنوان ریسک', 'دسته', 'احتمال', 'شدت تأثیر', 'سطح ریسک'].map((col, i) => (
key={i}
style={{
fontSize: '12px',
fontWeight: 700,
letterSpacing: '0.05em',
padding: '0 8px',
borderRight: i > 0 ? '1px solid rgba(255,255,255,0.12)' : 'none',
}}
>
{col}
</div>
))}
</div>
{/* Table Rows */}
{riskMatrix.map((risk, idx) => {
const cfg = levelConfig[risk.level as RiskLevel];
return (
<div
key={risk.id}
style={{
display: 'grid',
gridTemplateColumns: '48px 1fr 100px 100px 120px 130px',
background: idx % 2 === 0 ? 'var(--paper)' : 'var(--paper-2)',
borderTop: '1px solid var(--rule-thin)',
padding: '14px 16px',
alignItems: 'center',
}}
>
{/* # */}
<div style={{ fontSize: '13px', color: 'var(--ink-5)', fontWeight: 600, padding: '0 8px' }}>
{risk.id}
</div>
{/* Title */}
<div style={{ fontSize: '14px', fontWeight: 600, color: 'var(--ink)', padding: '0 8px', borderRight: '1px solid var(--rule-thin)' }}>
{risk.title}
</div>
{/* Category */}
<div style={{ fontSize: '12px', color: 'var(--ink-4)', padding: '0 8px', borderRight: '1px solid var(--rule-thin)' }}>
{risk.category}
</div>
{/* Probability */}
<div style={{ fontSize: '12px', color: 'var(--ink-3)', padding: '0 8px', borderRight: '1px solid var(--rule-thin)' }}>
{risk.probability}
</div>
{/* Impact */}
<div style={{ fontSize: '12px', color: 'var(--ink-3)', padding: '0 8px', borderRight: '1px solid var(--rule-thin)' }}>
{risk.impact}
</div>
{/* Level */}
<div <div
key={i}
style={{ style={{
display: 'flex', fontSize: '12px',
alignItems: 'center', fontWeight: 700,
gap: '8px', letterSpacing: '0.05em',
padding: '0 8px', padding: '0 8px',
borderRight: '1px solid var(--rule-thin)', borderRight: i > 0 ? '1px solid rgba(255,255,255,0.12)' : 'none',
}} }}
> >
{col}
</div>
))}
</div>
{/* Table Rows */}
{riskMatrix.map((risk, idx) => {
const cfg = levelConfig[risk.level as RiskLevel];
return (
<div
key={risk.id}
style={{
display: 'grid',
gridTemplateColumns: '48px 1fr 100px 100px 120px 130px',
background: idx % 2 === 0 ? 'var(--paper)' : 'var(--paper-2)',
borderTop: '1px solid var(--rule-thin)',
padding: '14px 16px',
alignItems: 'center',
}}
>
{/* # */}
<div style={{ fontSize: '13px', color: 'var(--ink-5)', fontWeight: 600, padding: '0 8px' }}>
{risk.id}
</div>
{/* Title */}
<div style={{ fontSize: '14px', fontWeight: 600, color: 'var(--ink)', padding: '0 8px', borderRight: '1px solid var(--rule-thin)' }}>
{risk.title}
</div>
{/* Category */}
<div style={{ fontSize: '12px', color: 'var(--ink-4)', padding: '0 8px', borderRight: '1px solid var(--rule-thin)' }}>
{risk.category}
</div>
{/* Probability */}
<div style={{ fontSize: '12px', color: 'var(--ink-3)', padding: '0 8px', borderRight: '1px solid var(--rule-thin)' }}>
{risk.probability}
</div>
{/* Impact */}
<div style={{ fontSize: '12px', color: 'var(--ink-3)', padding: '0 8px', borderRight: '1px solid var(--rule-thin)' }}>
{risk.impact}
</div>
{/* Level */}
<div <div
style={{ style={{
width: '9px', display: 'flex',
height: '9px', alignItems: 'center',
borderRadius: '50%', gap: '8px',
background: cfg.color, padding: '0 8px',
flexShrink: 0, borderRight: '1px solid var(--rule-thin)',
}} }}
/> >
<span style={{ fontSize: '12px', fontWeight: 700, color: cfg.color }}> <div
{cfg.label} style={{
</span> width: '9px',
height: '9px',
borderRadius: '50%',
background: cfg.color,
flexShrink: 0,
}}
/>
<span style={{ fontSize: '12px', fontWeight: 700, color: cfg.color }}>
{cfg.label}
</span>
</div>
</div> </div>
</div> );
); })}
})} </div>
</div> </div>
</div> </div>
@ -244,12 +246,8 @@ export default function Risks() {
<Link <Link
key={report.id} key={report.id}
to={`/reports/${report.id}`} to={`/reports/${report.id}`}
className="grid grid-cols-[90px_1fr_120px_140px_140px] max-md:grid-cols-1 max-md:p-5 max-md:gap-3 p-4 items-center"
style={{ style={{
display: 'grid',
gridTemplateColumns: '90px 1fr 120px 140px 140px',
gap: '0',
alignItems: 'center',
padding: '16px 0',
borderBottom: '1px solid var(--rule-thin)', borderBottom: '1px solid var(--rule-thin)',
background: idx % 2 === 0 ? 'var(--paper)' : 'var(--paper-2)', background: idx % 2 === 0 ? 'var(--paper)' : 'var(--paper-2)',
textDecoration: 'none', textDecoration: 'none',
@ -257,7 +255,7 @@ export default function Risks() {
}} }}
> >
{/* Type badge */} {/* Type badge */}
<div style={{ padding: '0 0 0 12px' }}> <div style={{ padding: '0 0 0 12px' }} className="max-md:p-0">
<span <span
style={{ style={{
fontSize: '10px', fontSize: '10px',
@ -265,7 +263,6 @@ export default function Risks() {
color: 'var(--paper)', color: 'var(--paper)',
background: '#7f1d1d', background: '#7f1d1d',
padding: '3px 8px', padding: '3px 8px',
letterSpacing: '0.06em',
}} }}
> >
ریسک ریسک
@ -277,9 +274,8 @@ export default function Risks() {
fontSize: '14px', fontSize: '14px',
fontWeight: 600, fontWeight: 600,
color: 'var(--ink)', color: 'var(--ink)',
borderRight: '1px solid var(--rule-thin)',
padding: '0 16px',
}} }}
className="border-r border-[var(--rule-thin)] px-4 max-md:border-r-0 max-md:p-0"
> >
{report.title} {report.title}
</div> </div>
@ -288,9 +284,8 @@ export default function Risks() {
style={{ style={{
fontSize: '12px', fontSize: '12px',
color: 'var(--ink-5)', color: 'var(--ink-5)',
borderRight: '1px solid var(--rule-thin)',
padding: '0 16px',
}} }}
className="border-r border-[var(--rule-thin)] px-4 max-md:border-r-0 max-md:p-0"
> >
{report.publishDate} {report.publishDate}
</div> </div>
@ -299,9 +294,8 @@ export default function Risks() {
style={{ style={{
fontSize: '12px', fontSize: '12px',
color: 'var(--ink-5)', color: 'var(--ink-5)',
borderRight: '1px solid var(--rule-thin)',
padding: '0 16px',
}} }}
className="border-r border-[var(--rule-thin)] px-4 max-md:border-r-0 max-md:p-0"
> >
{report.pages} صفحه {report.pages} صفحه
</div> </div>
@ -312,9 +306,8 @@ export default function Risks() {
alignItems: 'center', alignItems: 'center',
justifyContent: 'flex-end', justifyContent: 'flex-end',
gap: '12px', gap: '12px',
borderRight: '1px solid var(--rule-thin)',
padding: '0 16px',
}} }}
className="border-r border-[var(--rule-thin)] px-4 max-md:border-r-0 max-md:p-0 max-md:justify-start"
> >
<span style={{ fontSize: '13px', fontWeight: 700, color: 'var(--ink)' }}> <span style={{ fontSize: '13px', fontWeight: 700, color: 'var(--ink)' }}>
{formatPrice(report.price)} {formatPrice(report.price)}

View File

@ -43,7 +43,7 @@ function formatNumber(n: number): string {
return n.toLocaleString('fa-IR'); return n.toLocaleString('fa-IR');
} }
function PriceTicker({ item, col, row, totalCols, totalRows }: { item: MarketPrice; col: number; row: number; totalCols: number; totalRows: number }) { function PriceTicker({ item }: { item: MarketPrice }) {
const isUp = item.trend === 'up'; const isUp = item.trend === 'up';
const isDown = item.trend === 'down'; const isDown = item.trend === 'down';
const trendArrow = isUp ? '▲' : isDown ? '▼' : '—'; const trendArrow = isUp ? '▲' : isDown ? '▼' : '—';
@ -54,8 +54,6 @@ function PriceTicker({ item, col, row, totalCols, totalRows }: { item: MarketPri
<div <div
style={{ style={{
padding: '24px 20px', padding: '24px 20px',
borderLeft: col < totalCols - 1 ? '1px solid var(--rule-thin)' : 'none',
borderBottom: row < totalRows - 1 ? '1px solid var(--rule-thin)' : 'none',
background: 'var(--paper)', background: 'var(--paper)',
}} }}
> >
@ -136,8 +134,6 @@ function PriceTicker({ item, col, row, totalCols, totalRows }: { item: MarketPri
export default function Scanner() { export default function Scanner() {
// Use first 6 prices for the grid // Use first 6 prices for the grid
const gridPrices = marketPrices.slice(0, 6); const gridPrices = marketPrices.slice(0, 6);
const COLS = 3;
const ROWS = Math.ceil(gridPrices.length / COLS);
// For CSS bar chart: find max price in globalComparison for proportional width // For CSS bar chart: find max price in globalComparison for proportional width
// Filter to USD-only for a fair comparison (exclude IRR) // Filter to USD-only for a fair comparison (exclude IRR)
@ -237,25 +233,17 @@ export default function Scanner() {
<div <div
style={{ style={{
border: '2px solid var(--ink)', border: '2px solid var(--ink)',
display: 'grid', background: 'var(--rule-thin)',
gridTemplateColumns: 'repeat(3, 1fr)', gap: 1,
}} }}
className="max-md:grid-cols-1" className="grid grid-cols-3 max-lg:grid-cols-2 max-sm:grid-cols-1"
> >
{gridPrices.map((item, idx) => { {gridPrices.map((item) => (
const col = idx % COLS; <PriceTicker
const row = Math.floor(idx / COLS); key={item.id}
return ( item={item}
<PriceTicker />
key={item.id} ))}
item={item}
col={col}
row={row}
totalCols={COLS}
totalRows={ROWS}
/>
);
})}
</div> </div>
</div> </div>
@ -364,8 +352,7 @@ export default function Scanner() {
</div> </div>
<div <div
style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '16px' }} className="grid grid-cols-3 max-lg:grid-cols-2 max-sm:grid-cols-1 gap-4"
className="max-md:grid-cols-1"
> >
{riskAlerts.map((alert) => { {riskAlerts.map((alert) => {
const level = alert.level as AlertLevel; const level = alert.level as AlertLevel;

View File

@ -330,8 +330,7 @@ export default function Special() {
</div> </div>
<div <div
className="max-md:grid-cols-1" className="grid grid-cols-2 max-md:grid-cols-1 gap-6"
style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: '24px' }}
> >
{specialReports.map((report) => ( {specialReports.map((report) => (
<SpecialCard key={report.id} report={report} /> <SpecialCard key={report.id} report={report} />
@ -369,8 +368,7 @@ export default function Special() {
</div> </div>
<div <div
className="max-md:grid-cols-1" className="grid grid-cols-3 max-lg:grid-cols-2 max-md:grid-cols-1 gap-5"
style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: '20px' }}
> >
{otherReports.map((report) => ( {otherReports.map((report) => (
<CompactCard key={report.id} report={report} /> <CompactCard key={report.id} report={report} />