import { useState, useEffect, useRef, useMemo, useCallback } from 'react';
import { TeknavData } from './teknav-data.js';
import {
useNav, useToast, useAuth,
AuthorAvatar, CategoryBadge, TypeBadge, StatusBadge, EmptyState, Header, ReadingProgress,
ReadingListModal,
inputStyle, pillBtn, iconBtnStyle, useViewportPrefetch,
} from './teknav-ui.jsx';
import { LazyDiagram } from './src/components/lazy-diagram.jsx';
import { ArticleCard } from './teknav-home.jsx';
import { contentApi } from './src/lib/content-api.js';
import { engagementApi } from './src/lib/engagement-api.js';
import { QuoteSharer } from './src/components/QuoteSharer.jsx';
import { iconNode } from './src/lib/icon.jsx';
import crownIcon from './src/assets/icons/crown.svg';
import thumbsUpIcon from './src/assets/icons/thumbs-up.svg';
import starIcon from './src/assets/icons/star.svg';
import heartIcon from './src/assets/icons/heart.svg';
import flameIcon from './src/assets/icons/flame.svg';
import lightbulbIcon from './src/assets/icons/lightbulb.svg';
function articleDateValue(article) {
return article?.dateEn || article?.publishedAt || article?.date || '';
}
function articleDateLabel(article) {
return article?.date || (typeof article?.publishedAt === 'string' ? article.publishedAt.slice(0, 10) : '') || article?.dateEn || '';
}
const TEKRAG_SLUG = 'tekrag-persian-data-centric-rag-benchmark';
const isTekRagArticle = (articleOrSlug) => (typeof articleOrSlug === 'string' ? articleOrSlug : articleOrSlug?.slug) === TEKRAG_SLUG;
function numberLabel(value, english = false) {
return Number(value ?? 0).toLocaleString(english ? 'en-US' : 'fa-IR');
}
function ArticleRow({ article, idx }) {
const { navigate } = useNav();
const [vis, setVis] = useState(false);
const ref = useRef();
useViewportPrefetch(ref, article.slug);
const cat = TeknavData.categories.find(c => c.id === article.category);
const author = TeknavData.authors.find(a => a.id === article.authorId);
useEffect(() => {
const obs = new IntersectionObserver(([e]) => { if (e.isIntersecting) setVis(true); }, { threshold: 0.05 });
if (ref.current) obs.observe(ref.current);
return () => obs.disconnect();
}, []);
return (
navigate('/article/' + article.slug)}
onMouseEnter={e => { e.currentTarget.style.opacity = '0.85'; }}
onMouseLeave={e => { e.currentTarget.style.opacity = '1'; }}>
{articleDateLabel(article)}
·
{article.title}
{article.subtitle &&
{article.subtitle}
}
{author?.specialty && · }
{author?.specialty && {author.specialty}}
{article.summary}
{article.type}
·
{article.readTime} دقیقه مطالعه
·
{(article.views || 0).toLocaleString('fa')} بازدید
{article.tags?.slice(0, 2).map(t => (
{t}
))}
);
}
function FilterBar({ filters, onChange }) {
const cats = [{ id: '', name: 'همه' }, ...TeknavData.categories];
const types = ['همه', 'تحلیل عمیق', 'راهنمای فنی', 'دادهنما', 'پژوهش', 'راستیآزماییشده', 'پرونده'];
const sorts = [{ v: 'latest', l: 'جدیدترین' }, { v: 'popular', l: 'پربازدیدترین' }, { v: 'readtime', l: 'زمان مطالعه' }];
const chip = (active) => ({
border: active ? '1.5px solid #0F6B73' : '1px solid #E4DDD2',
background: active ? '#0F6B7312' : '#fff',
color: active ? '#0F6B73' : '#5F6B6D',
padding: '5px 12px', borderRadius: 20, fontSize: 12, cursor: 'pointer',
fontFamily: 'Vazirmatn,sans-serif', fontWeight: active ? 700 : 400,
transition: 'all 0.15s', whiteSpace: 'nowrap',
});
return (
دسته:
{cats.map(c => (
))}
نوع:
{types.map(t => (
))}
مرتبسازی:
{sorts.map(s => (
))}
{filters.q && (
جستجو: «{filters.q}»
)}
);
}
function ArticleListPage({ initQ = '' }) {
const [filters, setFilters] = useState({ cat: '', type: '', sort: 'latest', q: initQ });
const [searchInput, setSearchInput] = useState(initQ);
const [page, setPage] = useState(1);
const [allArticles, setAllArticles] = useState(() => contentApi.fallbackArticles());
const PER = 8;
useEffect(() => {
let cancelled = false;
contentApi.listArticles({ limit: 100 })
.then((res) => { if (!cancelled) setAllArticles(res.items ?? []); })
.catch(() => {});
return () => { cancelled = true; };
}, []);
const filtered = useMemo(() => {
let list = allArticles;
if (filters.q) {
const q = filters.q.toLowerCase();
list = list.filter(a => a.title.toLowerCase().includes(q) || a.summary.toLowerCase().includes(q) || a.authorName?.toLowerCase().includes(q) || a.categoryName?.toLowerCase().includes(q));
}
if (filters.cat) list = list.filter(a => a.category === filters.cat);
if (filters.type) list = list.filter(a => a.type === filters.type);
if (filters.sort === 'popular') list = [...list].sort((a, b) => b.views - a.views);
else if (filters.sort === 'readtime') list = [...list].sort((a, b) => b.readTime - a.readTime);
else list = [...list].sort((a, b) => articleDateValue(b).localeCompare(articleDateValue(a)));
return list;
}, [filters, allArticles]);
const visible = filtered.slice(0, page * PER);
const hasMore = visible.length < filtered.length;
const doSearch = (e) => { e.preventDefault(); setFilters(f => ({ ...f, q: searchInput })); setPage(1); };
return (
همه مقالهها
{filtered.length} مقاله یافت شد
{ setFilters(f); setPage(1); }} />
{visible.length === 0 ? (
) : (
<>
{visible.map((a, i) => )}
{hasMore && (
)}
>
)}
);
}
function TableOfContents({ headings, english = false }) {
const [active, setActive] = useState(null);
useEffect(() => {
const obs = new IntersectionObserver(entries => {
entries.forEach(e => { if (e.isIntersecting) setActive(e.target.id); });
}, { rootMargin: '-20% 0px -70% 0px' });
headings.forEach(h => { const el = document.getElementById(h.id); if (el) obs.observe(el); });
return () => obs.disconnect();
}, [headings]);
return (
);
}
function EmbeddedDiagramCard({ title, subtitle, type, english = false }) {
return (
{title}
{subtitle &&
{subtitle}
}
);
}
function ArticleEmbeddedDiagrams({ slug }) {
if (isTekRagArticle(slug)) {
return null;
}
if (slug === 'ai-clean-data') {
return (
);
}
if (slug === 'ai-agents-2026' || slug === 'agentic-ai-production') {
return (
);
}
return null;
}
function SeriesNavBanner({ series, currentSlug }) {
const { navigate } = useNav();
const idx = series.articles.findIndex(a => a.slug === currentSlug);
const prev = idx > 0 ? series.articles[idx - 1] : null;
const next = idx < series.articles.length - 1 ? series.articles[idx + 1] : null;
if (!prev && !next) return null;
const btnBase = {
background: 'transparent', border: '1px solid #0F6B7330', borderRadius: 8,
padding: '10px 16px', cursor: 'pointer', fontFamily: 'Vazirmatn,sans-serif',
color: '#0F6B73', fontSize: 13, fontWeight: 600, maxWidth: 280, textAlign: 'right',
transition: 'all 0.15s', lineHeight: 1.5,
};
return (
{prev ? (
) :
}
{next ? (
) :
}
);
}
function ArticleQaSection({ slug, english = false }) {
const { user } = useAuth();
const [items, setItems] = useState([]);
const [loading, setLoading] = useState(true);
const [body, setBody] = useState('');
const [replyTo, setReplyTo] = useState(null);
const toast = useToast();
const load = useCallback(() => {
setLoading(true);
engagementApi.listQa(slug)
.then(res => setItems(res.items ?? []))
.finally(() => setLoading(false));
}, [slug]);
useEffect(() => { load(); }, [load]);
const submit = async (e) => {
e.preventDefault();
if (!body.trim()) return;
try {
if (replyTo) await engagementApi.postAnswer(replyTo.id, body);
else await engagementApi.postQuestion(slug, body);
setBody('');
setReplyTo(null);
toast(english ? 'Submitted' : 'ثبت شد');
load();
} catch {
toast(english ? 'Submission failed' : 'خطا در ثبت', 'error');
}
};
return (
{english ? 'Questions and Answers' : 'پرسش و پاسخ'}
{user ? (
) : {english ? 'Sign in to ask a question.' : 'برای پرسیدن سوال وارد شوید.'}
}
{loading ? {english ? 'Loading...' : 'در حال بارگذاری...'}
: (
{items.length === 0 &&
{english ? 'No questions yet.' : 'هنوز پرسشی ثبت نشده است.'}
}
{items.map(q => (
{q.author?.name}
{q.time}
{q.body}
{q.answers?.map(a => (
{a.author?.name}
{a.body}
))}
))}
)}
);
}
function ArticleCommentSection({ article, onTotal, english = false }) {
const { user } = useAuth();
const { navigate } = useNav();
const toast = useToast();
const [items, setItems] = useState([]);
const [body, setBody] = useState('');
const [replyTo, setReplyTo] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(false);
const refresh = useCallback(() => {
setLoading(true);
setError(false);
return engagementApi.listComments(article.slug)
.then(res => {
setItems(res?.items ?? []);
onTotal?.(res?.total ?? 0);
})
.catch(() => { setItems([]); setError(true); })
.finally(() => setLoading(false));
}, [article.slug, onTotal]);
useEffect(() => { refresh(); }, [refresh]);
const submit = async (e) => {
e.preventDefault();
if (!body.trim()) return;
try {
await engagementApi.postComment(article.slug, body, replyTo?.id);
setBody('');
setReplyTo(null);
toast(english ? 'Comment submitted' : 'نظر شما ثبت شد');
refresh();
} catch {
toast(english ? 'Comment submission failed' : 'ثبت نظر ناموفق بود', 'error');
}
};
const upvote = async (id) => {
try {
const res = await engagementApi.upvoteComment(id);
setItems(current => current.map(comment => {
if (comment.id === id) return { ...comment, upvotedByMe: res.upvoted, upvoteCount: res.upvoteCount };
return { ...comment, replies: (comment.replies ?? []).map(reply => reply.id === id ? { ...reply, upvotedByMe: res.upvoted, upvoteCount: res.upvoteCount } : reply) };
}));
} catch {
toast(english ? 'Sign in to vote' : 'برای رأی دادن ابتدا وارد شوید', 'warning');
}
};
const flag = async (id) => {
try {
await engagementApi.flagComment(id);
toast(english ? 'Report submitted' : 'گزارش نظر ثبت شد');
refresh();
} catch {
toast(english ? 'Sign in to report a comment' : 'برای گزارش نظر ابتدا وارد شوید', 'warning');
}
};
const like = async (id) => {
try {
const res = await engagementApi.likeComment(id);
setItems(current => current.map(comment => {
if (comment.id === id) return { ...comment, likedByMe: res.liked, likeCount: res.likeCount };
return { ...comment, replies: (comment.replies ?? []).map(reply => reply.id === id ? { ...reply, likedByMe: res.liked, likeCount: res.likeCount } : reply) };
}));
} catch {
toast(english ? 'Sign in to like a comment' : 'برای پسندیدن نظر ابتدا وارد شوید', 'warning');
}
};
const renderComment = (comment, child = false) => (
@{comment.author?.username ?? 'user'} · {comment.time}
{comment.body}
{user && !child && }
{comment.replies?.map(reply => renderComment(reply, true))}
);
return (
{english ? 'Comments' : 'نظرها'}
{user ? (
) : (
{english ? 'Sign in to comment.' : 'برای نظر دادن وارد شوید.'}
)}
{loading && {english ? 'Loading comments...' : 'در حال بارگذاری نظرها...'}
}
{error && }
{!loading && !error && items.length === 0 && }
{!loading && !error && items.map(comment => renderComment(comment))}
);
}
function PremiumGateCard({ navigate, user }) {
return (
این مقاله برای اعضای ویژه
برای مطالعه کامل این مقاله، عضو ویژه تکناو شوید
{[
'✓ دسترسی به همه مقالات ویژه',
'✓ تجربه بدون تبلیغ',
'✓ حمایت مستقیم از تکناو',
].map((item) => (
- {item}
))}
{!user && (
)}
);
}
function ArticleDetail({ slug }) {
const { navigate } = useNav();
const { user } = useAuth();
const toast = useToast();
const contentRef = useRef(null);
const canonicalSlug = slug === 'ai-agents-2026' ? 'agentic-ai-production' : slug;
const [saved, setSaved] = useState(false);
const [listModalOpen, setListModalOpen] = useState(false);
const [reacted, setReacted] = useState({});
const [article, setArticle] = useState(() => contentApi.fallbackArticles().find(a => a.slug === canonicalSlug));
const [related, setRelated] = useState([]);
const [commentTotal, setCommentTotal] = useState(0);
const processedContent = useMemo(() => {
if (!article?.content) return '';
let hidx = 0;
const withLead = article.content.includes('class="lead"')
? article.content
: article.content.replace(/]*class=)([^>]*)>/, '
');
return withLead.replace(/]*>([^<]+)<\/h\1>/g, (_, lvl, txt) => {
const id = 'h-' + hidx++;
return `${txt}`;
});
}, [article?.content]);
useEffect(() => {
let cancelled = false;
if (slug !== canonicalSlug && typeof window !== 'undefined') {
window.history.replaceState({}, '', `/article/${canonicalSlug}`);
}
const fallback = contentApi.fallbackArticles().find(a => a.slug === canonicalSlug);
setArticle(fallback);
setRelated(fallback ? contentApi.fallbackArticles().filter(a => a.category === fallback.category && a.id !== fallback.id).slice(0, 3) : []);
setSaved(false);
setReacted({});
contentApi.getArticle(canonicalSlug)
.then((res) => {
if (cancelled) return;
setArticle(res.article);
setRelated(res.related ?? []);
setSaved(!!res.saved);
setReacted(res.reactions ?? {});
})
.catch(() => {});
return () => { cancelled = true; };
}, [canonicalSlug]);
useEffect(() => {
if (!article?.id) return;
const h = () => {
const el = document.documentElement;
const progress = (el.scrollTop || document.body.scrollTop) / (el.scrollHeight - el.clientHeight);
if (progress > 0.05) {
engagementApi.recordHistory(article.id, Math.min(progress, 1)).catch(() => {});
}
};
window.addEventListener('scroll', h);
return () => window.removeEventListener('scroll', h);
}, [article?.id]);
useEffect(() => {
if (!processedContent) return;
document.querySelectorAll('.article-content pre').forEach((pre) => {
if (pre.querySelector('.code-copy-btn')) return;
const code = pre.querySelector('code');
const lang = code?.className?.match(/language-(\w+)/)?.[1];
if (lang) pre.setAttribute('data-lang', lang);
const btn = document.createElement('button');
btn.className = 'code-copy-btn';
btn.textContent = 'کپی';
btn.onclick = () => {
navigator.clipboard?.writeText(code?.textContent ?? '').then(() => {
btn.textContent = '✓ کپی شد';
setTimeout(() => { btn.textContent = 'کپی'; }, 2000);
}).catch(() => {});
};
pre.appendChild(btn);
});
}, [processedContent]);
if (!article) return (
);
const author = article.author || TeknavData.authors.find(a => a.id === article.authorId);
const cat = TeknavData.categories.find(c => c.id === article.category);
const tekRag = isTekRagArticle(article);
const authorName = tekRag ? 'Arsam Sabbagh' : (author?.name || article.authorName);
const authorSpecialty = tekRag ? 'AI and Data Engineering Researcher' : author?.specialty;
const authorBio = tekRag ? 'Arsam Sabbagh is an AI and data engineering researcher focused on retrieval-augmented generation, data-centric AI, Persian technical content systems, and evaluation of grounded language-model applications.' : author?.bio;
const categoryName = tekRag ? 'Data Science' : article.categoryName;
const articleType = tekRag ? 'Research Article' : article.type;
const displayDate = tekRag ? 'May 8, 2026' : articleDateLabel(article);
const statusLabel = tekRag ? 'Published' : article.status;
const layoutDirection = tekRag ? 'ltr' : 'rtl';
const metaLocaleEnglish = tekRag;
const discoverImage = null;
const headings = [];
const h2re = /]*>([^<]+)<\/h2>/g;
const h3re = /]*>([^<]+)<\/h3>/g;
let m;
while ((m = h2re.exec(article.content || '')) !== null) headings.push({ id: 'h-' + headings.length, text: m[1], level: 2 });
while ((m = h3re.exec(article.content || '')) !== null) headings.push({ id: 'h-' + headings.length, text: m[1], level: 3 });
const handleSave = async () => {
try {
const res = await contentApi.toggleSaved(article.id);
setSaved(!!res.saved);
if (res.saved) setListModalOpen(true);
toast(tekRag ? (res.saved ? 'Saved to reading list' : 'Removed from saved articles') : (res.saved ? 'در لیست مطالعه ذخیره شد' : 'از ذخیرهشدهها حذف شد'));
} catch {
toast(tekRag ? 'Sign in to save this article' : 'برای ذخیره مقاله ابتدا وارد شوید', 'warning');
}
};
const handleShare = (channel = 'copy') => {
const url = window.location.href;
const text = article.title;
contentApi.trackEvent({
type: 'share_clicked',
articleId: article.id,
topic: article.category,
metadata: { channel },
}).catch(() => {});
if (channel === 'telegram') {
window.open(`https://t.me/share/url?url=${encodeURIComponent(url)}&text=${encodeURIComponent(text)}`, '_blank', 'noopener,noreferrer');
return;
}
if (channel === 'whatsapp') {
window.open(`https://wa.me/?text=${encodeURIComponent(`${text} ${url}`)}`, '_blank', 'noopener,noreferrer');
return;
}
if (channel === 'x') {
window.open(`https://twitter.com/intent/tweet?url=${encodeURIComponent(url)}&text=${encodeURIComponent(text)}`, '_blank', 'noopener,noreferrer');
return;
}
if (channel === 'linkedin') {
window.open(`https://www.linkedin.com/sharing/share-offsite/?url=${encodeURIComponent(url)}`, '_blank', 'noopener,noreferrer');
return;
}
navigator.clipboard?.writeText(url).catch(() => {});
toast('لینک مقاله کپی شد');
};
const handleReact = async (type) => {
try {
const res = await contentApi.toggleReaction(article.id, type);
setReacted(r => ({ ...r, [type]: !!res.active }));
if (res.active) toast(tekRag ? 'Reaction saved' : 'واکنش شما ثبت شد');
} catch {
toast(tekRag ? 'Sign in to react' : 'برای ثبت واکنش ابتدا وارد شوید', 'warning');
}
};
return (
›
›
{article.title.slice(0, 40)}…
{tekRag ? (
{statusLabel}
) : }
{article.sponsored && Promoted Content}
{article.premiumOnly && Premium}
{article.title}
{article.subtitle && {article.subtitle}
}
{author && (
{authorSpecialty}
)}
·
{articleType}
·
{tekRag ? `${article.readTime} min read` : `${article.readTime} دقیقه مطالعه`}
·
{tekRag ? `${numberLabel(commentTotal, true)} comments` : `${numberLabel(commentTotal)} نظر`}
{article.series && (
سری مقاله
{article.series.title}
{article.series.articles?.length > 0 && (
قسمت {article.series.position} از {article.series.articles.length}
)}
)}
{discoverImage && (
)}
{(article.correctionNotice || article.corrections?.length > 0) && (
اصلاحیه و بهروزرسانی
{article.correctionNotice && {article.correctionNotice}
}
{article.corrections?.length > 0 && (
{article.corrections.map(item => - {item.date || new Date(item.createdAt).toLocaleDateString('fa-IR')}: {item.note}
)}
)}
)}
{!tekRag && (
نمودار تعاملی — با موس روی عناصر بروید
)}
{!article.premiumLocked && !tekRag && (
)}
{article.premiumLocked && }
{tekRag ? 'Was this article useful?' : 'واکنش شما به این مقاله؟'}
{(tekRag ? [
['helpful', 'Helpful', thumbsUpIcon],
['star', 'Excellent', starIcon],
['heart', 'Valuable', '♡'],
['fire', 'Important', '●'],
['thinking', 'Thought-provoking', '?'],
] : [
['helpful', 'مفید', thumbsUpIcon],
['star', 'عالی', starIcon],
['heart', 'عاشقانه', heartIcon],
['fire', 'داغ', flameIcon],
['thinking', 'تأملبرانگیز', lightbulbIcon],
]).map(([type, label, icon]) => (
))}
{article.series?.articles?.length > 1 && (
)}
{article.tags?.length > 0 && (
{tekRag ? 'Keywords:' : 'برچسبها:'}
{article.tags.map(t => (
))}
)}
{author && (
{tekRag ? 'AUTHOR' : 'نویسنده'}
{authorSpecialty}
{authorBio}
{Object.entries(author.social || {}).map(([k, v]) => (
{k}
))}
)}
{!tekRag && related.length > 0 && (
)}
{!tekRag && (() => {
const relatedComparisons = (TeknavData.comparisons ?? []).filter((c) =>
(c.relatedArticles || []).includes(article.slug) ||
(article.tags || []).some((t) => [c.item1.slug, c.item2.slug, ...(c.tags || [])].some((ct) => ct.toLowerCase() === t.toLowerCase())),
).slice(0, 3);
if (!relatedComparisons.length) return null;
return (
مقایسههای مرتبط
{relatedComparisons.map((c) => (
navigate(`/compare/${c.slug}`)}
style={{ background: '#F8F5F0', border: '1px solid #E4DDD2', borderRadius: 8, padding: '12px 16px', cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 12 }}
>
{c.title}
{c.item1.name}
در برابر
{c.item2.name}
←
))}
);
})()}
{listModalOpen &&
setListModalOpen(false)} />}
);
}
const articleContentStyle = {
fontSize: 16, lineHeight: 2, color: '#263238', direction: 'rtl',
fontFamily: 'Vazirmatn,sans-serif',
};
const articleCSS = `
article h2 { font-size: 22px; font-weight: 800; color: #263238; margin: 40px 0 16px; padding-bottom: 8px; border-bottom: 2px solid #E4DDD2; font-family: Vazirmatn,sans-serif; }
article h3 { font-size: 18px; font-weight: 700; color: #263238; margin: 32px 0 12px; font-family: Vazirmatn,sans-serif; }
article p { margin: 0 0 20px; }
article .lead { font-size: 18px; line-height: 2.05; color: #1A3035; font-weight: 500; background: #FFFFFF; border: 1px solid #E4DDD2; border-right: 4px solid #0F6B73; border-radius: 12px; padding: 20px 22px; margin: 0 0 30px; }
article blockquote { border-right: 4px solid #D49A2A; margin: 28px 0; padding: 16px 20px; background: #D49A2A0A; border-radius: 0 8px 8px 0; font-size: 16px; color: #263238; font-style: normal; }
article blockquote.security-quote { border-right-color: #C94C4D; background: #C94C4D08; }
article strong { color: #263238; font-weight: 700; }
article em { color: #0F6B73; font-style: normal; font-weight: 600; }
article pre { background: #131F22; border-radius: 10px; padding: 40px 18px 18px; margin: 24px 0; overflow-x: auto; position: relative; border: 1px solid #1E3035; direction: ltr; }
article pre::before { content: attr(data-lang); position: absolute; top: 10px; right: 14px; font-size: 10px; color: #4A7A82; font-family: monospace; letter-spacing: 0.08em; text-transform: uppercase; font-weight: 600; }
article pre code { background: none !important; border: none !important; padding: 0 !important; color: #A8D8DC; font-family: 'Courier New', Consolas, monospace; font-size: 13.5px; line-height: 1.85; display: block; direction: ltr; text-align: left; white-space: pre; }
article code:not(pre code) { background: #0F6B7316; border: 1px solid #0F6B7328; border-radius: 4px; padding: 1px 6px; font-family: 'Courier New', Consolas, monospace; font-size: 13px; color: #0A5060; direction: ltr; unicode-bidi: isolate; display: inline; white-space: nowrap; }
.code-copy-btn { position: absolute; top: 8px; left: 10px; background: #1E3035; border: 1px solid #2A4048; color: #6AACB5; border-radius: 6px; padding: 4px 10px; font-size: 11px; cursor: pointer; font-family: Vazirmatn, sans-serif; z-index: 1; transition: all 0.15s; line-height: 1.4; }
.code-copy-btn:hover { background: #2A4048; color: #A8D8DC; }
article ul { padding-right: 0; list-style: none; margin: 16px 0 24px; display: grid; gap: 6px; }
article ul li { position: relative; padding-right: 22px; color: #263238; line-height: 1.9; }
article ul li::before { content: '›'; position: absolute; right: 4px; color: #0F6B73; font-weight: 900; font-size: 17px; line-height: 1.6; }
article ol { padding-right: 0; counter-reset: art-counter; list-style: none; margin: 16px 0 24px; display: grid; gap: 8px; }
article ol li { counter-increment: art-counter; position: relative; padding-right: 38px; color: #263238; line-height: 1.9; padding-top: 2px; }
article ol li::before { content: counter(art-counter); position: absolute; right: 0; top: 2px; width: 24px; height: 24px; background: #0F6B73; color: #fff; border-radius: 50%; display: flex; align-items: center; justify-content: center; font-size: 11px; font-weight: 800; }
article ul li code, article ol li code { font-size: 12px; }
article ul li strong, article ol li strong { color: #0A5060; }
article .ltr { direction: ltr; unicode-bidi: isolate; display: inline-block; font-family: Inter, Arial, sans-serif; letter-spacing: 0; }
article .metric-grid { display: grid; grid-template-columns: repeat(auto-fit,minmax(150px,1fr)); gap: 12px; margin: 28px 0; }
article .metric-card { background: #fff; border: 1px solid #E4DDD2; border-top: 3px solid #0F6B73; border-radius: 10px; padding: 14px 16px; }
article .metric-value { color: #0F6B73; font-weight: 900; font-size: 22px; line-height: 1.2; }
article .metric-label { color: #5F6B6D; font-size: 12px; line-height: 1.7; margin-top: 6px; }
article table { width: 100%; border-collapse: collapse; margin: 24px 0; background: #fff; border: 1px solid #E4DDD2; border-radius: 10px; overflow: hidden; display: block; max-width: 100%; overflow-x: auto; }
article th, article td { border-bottom: 1px solid #E4DDD2; padding: 12px 14px; text-align: right; vertical-align: top; min-width: 130px; }
article th { background: #F4EFE6; color: #263238; font-weight: 800; }
article tr:last-child td { border-bottom: 0; }
article .comparison-template { background: #fffaf1; border: 1px solid #E4DDD2; border-radius: 12px; padding: 18px; margin: 24px 0; }
article .risk-box { background: #C46A4D10; border: 1px solid #C46A4D35; border-radius: 12px; padding: 18px 22px; margin: 28px 0; }
article .agent-steps { counter-reset: agentStep; display: grid; gap: 10px; margin: 24px 0; }
article .agent-step { counter-increment: agentStep; background: #fff; border: 1px solid #E4DDD2; border-radius: 10px; padding: 14px 48px 14px 16px; position: relative; }
article .agent-step::before { content: counter(agentStep); position: absolute; top: 14px; right: 14px; width: 24px; height: 24px; border-radius: 50%; background: #0F6B73; color: #fff; display: grid; place-items: center; font-size: 12px; font-weight: 800; }
.article-diagram-card { background: linear-gradient(135deg,#F4EFE6 0%,#FFFFFF 100%); border: 1px solid #E4DDD2; border-radius: 12px; padding: 22px; overflow: hidden; box-shadow: 0 12px 34px rgba(15,42,46,0.06); }
.tekrag-diagram-card { background: #FAFAFA; border: 1px solid #E8E8E8; border-radius: 8px; padding: 16px; box-shadow: 0 2px 8px rgba(0,0,0,0.06); }
.insight-box { background: #0F6B7310; border: 1px solid #0F6B7330; border-radius: 10px; padding: 20px 24px; margin: 28px 0; }
.insight-box .insight-title { font-size: 13px; font-weight: 700; color: #0F6B73; margin-bottom: 8px; }
.insight-box p { margin: 0; font-size: 14px; line-height: 1.8; }
.footnote-box { background: #F4EFE6; border-radius: 8px; padding: 16px 20px; margin-top: 32px; font-size: 12px; color: #5F6B6D; line-height: 1.7; }
.cve-summary-card { background: linear-gradient(135deg, #EEF6F7 0%, #E8F3F4 100%); border: 1px solid rgba(15,107,115,0.18); border-radius: 12px; padding: 20px 24px; margin: 0 0 32px; display: grid; grid-template-columns: repeat(auto-fit, minmax(120px, 1fr)); gap: 16px; direction: rtl; }
.cve-summary-card .cve-item { display: flex; flex-direction: column; gap: 5px; border-left: 1px solid rgba(15,107,115,0.15); padding-left: 16px; }
.cve-summary-card .cve-item:last-child { border-left: none; padding-left: 0; }
.cve-summary-card .cve-label { font-size: 10px; color: #0F6B73; font-weight: 700; letter-spacing: 0.06em; text-transform: uppercase; }
.cve-summary-card .cve-value { font-size: 14px; font-weight: 800; color: #1A3035; }
.cve-summary-card .cve-score { font-size: 28px; font-weight: 900; color: #C0392B; line-height: 1; }
.cve-summary-card .cve-critical { color: #C0392B; }
.cve-summary-card .cve-patched { color: #1A7A50; font-size: 13px; }
.security-alert { background: #C94C4D0A; border: 1px solid #C94C4D30; border-right: 4px solid #C94C4D; border-radius: 0 10px 10px 0; padding: 16px 20px; margin: 28px 0; }
.security-alert .alert-title { font-size: 13px; font-weight: 800; color: #C94C4D; margin-bottom: 6px; }
.security-alert p, .security-alert li { font-size: 14px; line-height: 1.8; color: #3A1A1A; margin: 0; }
@media (max-width: 640px) {
article pre {
padding: 32px 12px 12px !important;
margin: 20px 0 !important;
font-size: 12px !important;
max-width: calc(100vw - 32px) !important;
}
article code:not(pre code) {
font-size: 11px !important;
padding: 1px 4px !important;
word-break: break-all !important;
}
.cve-summary-card {
grid-template-columns: 1fr !important;
padding: 16px !important;
gap: 12px !important;
}
.cve-summary-card .cve-item {
border-left: none !important;
border-bottom: 1px solid rgba(15,107,115,0.15) !important;
padding-left: 0 !important;
padding-bottom: 12px !important;
}
.cve-summary-card .cve-item:last-child {
border-bottom: none !important;
padding-bottom: 0 !important;
}
article table { font-size: 13px !important; }
article table td, article table th { padding: 6px 8px !important; min-width: 80px !important; }
article .metric-grid { grid-template-columns: 1fr !important; }
article .lead { font-size: 16px !important; padding: 16px !important; }
}
`;
const styleEl = document.createElement('style');
styleEl.textContent = articleCSS;
document.head.appendChild(styleEl);
export { ArticleRow, FilterBar, ArticleListPage, TableOfContents, ArticleDetail };