// LawsView.jsx — محرك البحث القانوني: الأنظمة واللوائح (مربوط بكوربوس «أمل» عبر /api/laws) // // ⛔ صفر هلوسة: كل نص يُعرض هنا يأتي من الكوربوس حرفياً. المتن وحواشي التعديل تُصيَّر بدالة // renderDocMd المنسوخة حرفياً من عارض «أمل» (lexa-render.js)، ثم يُعاد ترتيب ناتجها فقط: // المربعات تتحول إلى شارات قابلة للنقر، ولا تُمس كلمة من النص. // التنسيق وحده (حذف النقطتين في آخر عنوان المادة، الألوان، الترتيب البصري) من عمل الواجهة. /* ========================================================= ثوابت وأدوات عامة ========================================================= */ const LX_KIND_COLORS = { 'نظام': { fg: '#9cc3e8', bg: 'rgba(143,184,224,.14)' }, 'لائحة': { fg: '#8fd9b0', bg: 'rgba(45,155,98,.16)' }, 'قواعد وضوابط': { fg: '#e8c27a', bg: 'rgba(212,154,30,.16)' }, 'قرار': { fg: '#c9c2b3', bg: 'rgba(239,231,214,.08)' }, 'تعديل': { fg: '#ffb08f', bg: 'rgba(224,122,82,.16)' }, 'اتفاقية': { fg: '#c7b2ec', bg: 'rgba(160,130,220,.16)' }, }; const LX_STATUS = { 'ساري': { fg: '#8fd9b0', bg: 'rgba(45,155,98,.16)', dot: '#3fbf7f', label: 'ساري' }, 'ملغى': { fg: '#ff9d94', bg: 'rgba(194,65,65,.18)', dot: '#e05a5a', label: 'ملغى' }, 'تاريخي': { fg: '#c9c2b3', bg: 'rgba(239,231,214,.08)', dot: '#9a988f', label: 'نسخة تاريخية' }, }; const LX_BUCKETS = [ ['amendments', 'التعديلات', 'أدوات عدّلت هذا النظام'], ['executive_regs', 'اللوائح التنفيذية', 'اللوائح الصادرة لتنفيذه'], ['rules', 'القواعد والضوابط', 'قواعد وضوابط وأدلة مرتبطة'], ['subsidiary', 'القرارات التابعة', 'قرارات صادرة استناداً إليه'], ['related', 'وثائق مرتبطة', 'وثائق ذات صلة موضوعية'], ['superseded', 'الملغاة والنسخ التاريخية', 'نسخ سابقة وأدوات لم تعد نافذة'], ]; const LX_POPULAR = ['نظام العمل', 'المادة 77 من نظام العمل', 'نظام الشركات', 'نظام المعاملات المدنية', 'نظام الإثبات', 'نظام الأحوال الشخصية', 'نظام المرور', 'حماية البيانات الشخصية']; const LX_NOTE_META = { amend: { label: 'معدلة', ic: '✎', dot: '#c96442' }, add: { label: 'مضافة', ic: '+', dot: '#2d9b62' }, cancel: { label: 'ملغاة', ic: '⊘', dot: '#c24141' }, rename: { label: 'إحلال مسمى', ic: '⇄', dot: '#8fb8e0' }, note: { label: 'ملاحظة', ic: 'ℹ', dot: '#87867f' }, }; function lxApiBase() { return (window.api && window.api.baseUrl) || ''; } async function lxGet(path) { // نصوصُ القاعدة للمشتركين: الطلبُ يحملُ رمزَ الدخول، و402 يفتحُ صفحةَ الاشتراكات const tok = window.api && window.api.getToken && window.api.getToken(); let r; try { r = await fetch(lxApiBase() + path, tok ? { headers: { Authorization: 'Bearer ' + tok } } : undefined); } catch (e) { // au1: انقطاعُ الشبكة لا يظهرُ «TypeError: Failed to fetch» const err = new Error('تعذّر الاتصال بالخادم — تحقّق من اتصالك وأعد المحاولة.'); err.status = 0; throw err; } if (!r.ok) { let msg = 'تعذّر تنفيذ الطلب — أعد المحاولة.'; try { const j = await r.json(); // 422 مصفوفةُ تحقّق، وبعضُ التفاصيلِ إنجليزيّة — لا «[object Object]» ولا رسائلَ إنجليزيّة (au1) if (typeof j.detail === 'string' && /[؀-ۿ]/.test(j.detail)) msg = j.detail; else if (r.status === 422) msg = 'صيغةُ البحث غير مقبولة — اختصر العبارة أو عدّل التصفية.'; else if (r.status === 404) msg = 'العنصر المطلوب غير موجود.'; else if (r.status === 429) msg = 'طلباتٌ كثيرةٌ في وقتٍ قصير — انتظر قليلاً ثمّ أعد المحاولة.'; else if (r.status >= 500) msg = 'الخادم مشغولٌ الآن — حاول بعد قليل.'; } catch (e) {} // الاقتراحاتُ أثناء الكتابة والبحثُ بالمعنى طلباتٌ خلفيّة: لا تنقلُ المستخدمَ لصفحةِ الاشتراكات وهو يكتب (au1) const quiet = /^\/api\/laws\/(suggest|semantic)\b/.test(path); if (r.status === 402 && window.lexaPaywall && !quiet) window.lexaPaywall(msg); if (r.status === 401) msg = 'انتهت جلستك — سجّل الدخول من جديد.'; const err = new Error(msg); err.status = r.status; throw err; } return r.json(); } const lxDocCache = new Map(); function lxGetDoc(did) { if (!lxDocCache.has(did)) { const p = lxGet('/api/laws/doc/' + encodeURIComponent(did)); p.catch(() => lxDocCache.delete(did)); lxDocCache.set(did, p); if (lxDocCache.size > 12) lxDocCache.delete(lxDocCache.keys().next().value); } return lxDocCache.get(did); } function lxEsc(s) { return String(s == null ? '' : s).replace(/&/g, '&').replace(//g, '>'); } // الأرقام بالصيغة الغربية كبقية المنصة والتواريخ الهجرية في الكوربوس function lxNum(n) { return (n || 0).toLocaleString('en-US'); } // مطابقةُ العددِ للمعدود: ٣–١٠ جمع («أيام»)، ١١–٩٩ مفردٌ منصوب («يوماً»)، ١٠٠+ بحسبِ آخرِ رقمين function lxCountWord(n, one, two, plural, acc) { const r = Math.abs(n) % 100; if (n === 1) return one; if (n === 2) return two; if (r >= 3 && r <= 10) return plural; if (r >= 11 && r <= 99) return acc; return one; // ١٠٠، ٢٠٠، ١٠١… مفردٌ مجرور } const LX_TREATY_SECTOR = 'العلاقات الدولية والمعاهدات'; // ترتيبُ شبكةِ المجالات بعددِ الكروت — إلا المعاهدات: كروتُها حاويات، فوزنُها بوثائقِها function lxSectorWeight(s) { return s.name === LX_TREATY_SECTOR ? Math.round((s.docs || 0) / 8) : s.cards; } function lxCount(n, one, two, plural, acc) { return n === 2 ? two : lxNum(n) + ' ' + lxCountWord(n, one, two, plural, acc); } // عنوان المادة للعرض: بلا نقطتين في آخره («المادة الأولى :» ← «المادة الأولى») function lxHead(s) { return String(s || '').replace(/[📝🚫🆕]/g, '').replace(/\s*[::]\s*$/, '').replace(/\s+/g, ' ').trim(); } function lxHeadHtml(h) { return String(h || '').replace(/\s*[📝🚫🆕]\s*/g, ' ').replace(/\s*[::]\s*(<\/[^>]+>\s*)*$/, '$1').trim(); } function lxQs(o) { const p = new URLSearchParams(); Object.entries(o).forEach(([k, v]) => { if (v !== undefined && v !== null && v !== '' && v !== false) p.set(k, v === true ? '1' : v); }); return p.toString(); } // تخزين المتصفح: تفضيلات القارئ وآخر ما قُرئ فقط — ويعمل الموقع كاملاً بدونه function lxLoad(k, d) { try { const v = localStorage.getItem(k); return v ? JSON.parse(v) : d; } catch (e) { return d; } } function lxSave(k, v) { try { localStorage.setItem(k, JSON.stringify(v)); } catch (e) {} } function lxToast(msg) { window.dispatchEvent(new CustomEvent('lx:toast', { detail: msg })); } function lxCopy(txt, okMsg) { const done = () => lxToast(okMsg); // au1: إن رُفضت الحافظةُ نجرّبُ طريقةَ execCommand قبل نافذةِ النسخِ اليدويّ const legacy = () => { try { const ta = document.createElement('textarea'); ta.value = txt; ta.style.position = 'fixed'; ta.style.opacity = '0'; document.body.appendChild(ta); ta.select(); const ok = document.execCommand('copy'); ta.remove(); if (ok) { done(); return; } } catch (e) {} prompt('انسخ:', txt); }; try { if (navigator.clipboard && window.isSecureContext) { navigator.clipboard.writeText(txt).then(done, legacy); return; } } catch (e) {} legacy(); } /* ── الحالة في الرابط: ?screen=search&q=…&doc=…&art=… ── */ const LX_ROUTE_KEYS = ['country', 'q', 'doc', 'art', 'an', 'sector', 'sub', 'kind', 'status', 'sort', 'page', 'where', 'exact', 'amended', 'yf', 'yt', 'browse', 'scope', 'tab', 'sec', 'court', 'law', 'item', 'topic', 'stage', 'outcome', 'region']; function lxReadRoute() { const p = new URLSearchParams(location.search); const r = {}; LX_ROUTE_KEYS.forEach(k => { const v = p.get(k); if (v !== null && v !== '') r[k] = v; }); return r; } function lxWriteRoute(r, replace) { const p = new URLSearchParams(location.search); LX_ROUTE_KEYS.forEach(k => p.delete(k)); Object.entries(r).forEach(([k, v]) => { if (v !== undefined && v !== null && v !== '' && v !== false) p.set(k, v === true ? '1' : v); }); const url = location.pathname + '?' + p.toString(); if (replace) history.replaceState(null, '', url); else history.pushState(null, '', url); } // مصدر تاريخ الإصدار حين مُلئ في حملة التواريخ (_fill_dates.py) — يُعرض ليعرف القارئ من أين جاء const LX_DATE_SRC = { S1_catalog: 'من سجل الوثيقة', S2_own_preamble: 'من ديباجة الوثيقة', S2b_own_header: 'من ترويسة الوثيقة', S2b_uqn_header: 'من ترويسة الوثيقة في أم القرى', S3_qanoniah: 'من بطاقة الوثيقة في قانونية', S4_title_year: 'السنة من عنوان الوثيقة', }; function lxPub(s) { const m = String(s || '').match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/); return m ? m[1] + '/' + m[2].padStart(2, '0') + '/' + m[3].padStart(2, '0') + 'هـ' : s; } function lxDaysBetween(a, b) { return Math.round((b - a) / 86400000); } function lxParseGreg(s) { if (!s) return null; let m = s.match(/^(\d{4})-(\d{1,2})-(\d{1,2})$/); if (m) return new Date(+m[1], +m[2] - 1, +m[3]); m = s.match(/^(\d{1,2})-(\d{1,2})-(\d{4})$/); if (m) return new Date(+m[3], +m[2] - 1, +m[1]); return null; } function lxDaysLeft(u) { const obs = lxParseGreg((u.observed || {}).greg); if (!obs || u.days_left_at_observation == null) return null; const today = new Date(); today.setHours(0, 0, 0, 0); return lxDaysBetween(today, new Date(obs.getTime() + u.days_left_at_observation * 86400000)); } /* ── «المادة 77 من نظام العمل» ← رقم المادة + اسم النظام ── */ // الرقم يُحل بدالة _xrKey المنسوخة من «أمل» (تفهم «السابعة والسبعون» و«77» و«٧٧») function lxParseArticleQuery(q) { if (!window.LexaRender) return null; const m = String(q || '').match(/^\s*(?:ال)?ماد[ةه]\s+(?:رقم\s*)?\(?\s*(.+?)\s*\)?\s+(?:من\s+)?((?:ال)?(?:نظام|لائحة|لائحه|تنظيم)\s.+)$/); if (!m) return null; const an = window.LexaRender.xrKey(m[1]); return an ? { an, law: m[2].trim(), label: m[1] } : null; } /* ── فرق الكلمات بين النص السابق والحالي (عرض فقط: كلا النصين حرفي) ── */ function lxWordDiff(a, b) { const tok = (s) => String(s || '').replace(/\*\*/g, '').split(/(\s+|[،؛:.,()«»"])/).filter(x => x !== '' && x !== undefined); const A = tok(a), B = tok(b); const n = A.length, m = B.length; if (n * m > 4000000) return null; // نصان ضخمان: يُعرضان منفصلين const W = m + 1; const dp = new Uint32Array((n + 1) * (m + 1)); for (let i = n - 1; i >= 0; i--) for (let j = m - 1; j >= 0; j--) dp[i * W + j] = A[i] === B[j] ? dp[(i + 1) * W + j + 1] + 1 : Math.max(dp[(i + 1) * W + j], dp[i * W + j + 1]); const out = []; let i = 0, j = 0; const push = (t, s) => { const l = out[out.length - 1]; if (l && l.t === t) l.s += s; else out.push({ t, s }); }; while (i < n && j < m) { if (A[i] === B[j]) { push('=', A[i]); i++; j++; } else if (dp[(i + 1) * W + j] >= dp[i * W + j + 1]) { push('-', A[i]); i++; } else { push('+', B[j]); j++; } } while (i < n) push('-', A[i++]); while (j < m) push('+', B[j++]); return out; } /* ── تفكيك ناتج renderDocMd إلى مواد ── */ // كل رأس h3/h4 يبدأ كتلة جديدة، وترتيبه (ord) يطابق ترتيب الرؤوس في الفهرس على الخادم. // مربعات التعديل (div.amend-note) تتبع متن مادتها، فتُلحق بآخر كتلة مفتوحة. // ⛔ لا «\b» هنا: حدود الكلمة في جافاسكربت لاتينية فقط، فـ«الفصل\b» لا يطابق «الفصل الأول» أبداً — // وكان ذلك يعدّ ألفي فصلٍ «مواد فارغة» ويسقطها من شجرة الفهرس (قِيس ٢٦ سبتمبر ٢٠٢٦). const LX_SEC_RX = /^\s*(?:الباب|الفصل|القسم|الفرع|الجزء|الكتاب|المبحث|المطلب)(?=[\s::\-–(]|$)/; function lxParseBlocks(html, pops) { const box = document.createElement('div'); box.innerHTML = html; const blocks = []; let cur = { type: 'pre', ord: 0, parts: [], notes: [], text: 'مقدمة الوثيقة' }; let ord = 0; for (const el of Array.from(box.childNodes)) { if (el.nodeType === 1 && (el.tagName === 'H3' || el.tagName === 'H4')) { blocks.push(cur); ord++; el.querySelectorAll('.art-cp').forEach(b => b.remove()); const cls = el.className || ''; const raw = el.textContent || ''; const text = lxHead(raw.replace(/⚖️.*$/, '')); const isSec = /sec-hd|doc-hd/.test(cls) || LX_SEC_RX.test(text); cur = { type: isSec ? 'sec' : 'art', lvl: el.tagName === 'H3' ? 1 : 2, ord, text, headHtml: lxHeadHtml(el.innerHTML), dataArt: el.getAttribute('data-art') || '', amd: /art-amd/.test(cls), cancel: /art-cancel/.test(cls), ref: /art-ref/.test(cls), added: /🆕/.test(raw), parts: [], notes: [], }; } else if (el.nodeType === 1 && /\bamend-note\b/.test(el.className || '')) { let idx = -1; const btn = el.querySelector('.amd-pop-btn'); if (btn) { const m = (btn.getAttribute('onclick') || '').match(/openAmendFloat\((\d+)\)/); if (m) idx = +m[1]; btn.remove(); } let href = null, hrefLabel = null; const a = el.querySelector('a.amd-src'); if (a) { href = a.getAttribute('href'); hrefLabel = (a.textContent || '').replace(/^📄\s*/, '').replace(/\s*↗\s*$/, ''); (a.closest('.amd-src-w') || a).remove(); } const pop = idx >= 0 ? pops[idx] : null; const cls = el.className; const firstB = (el.querySelector('b') || {}).textContent || ''; let kind = 'note'; if (/cancel/.test(cls)) kind = 'cancel'; else if (/\badd\b/.test(cls)) kind = 'add'; else if (/إحلال/.test(firstB)) kind = 'rename'; else if (pop && (pop.before || pop.circular || /تعديل|عُدّلت/.test(firstB))) kind = 'amend'; else if (/تعديل|عُدّلت|تحديث/.test(firstB)) kind = 'amend'; cur.notes.push({ kind, html: el.innerHTML.trim(), pop, href, hrefLabel, label: firstB.replace(/[::]\s*$/, '') }); } else if (el.nodeType === 1 && /art-cancelled/.test(el.className || '')) { cur.cancelNotice = true; } else if (el.nodeType === 1) { cur.parts.push(el.outerHTML); } else if (el.nodeType === 3 && el.textContent.trim()) { cur.parts.push(lxEsc(el.textContent)); } } blocks.push(cur); return blocks.filter(b => b.type !== 'pre' || b.parts.length || b.notes.length); } /* ========================================================= طبقة التنسيق (حملة ٢٦ سبتمبر ٢٠٢٦) ⛔ القاعدة: لا يُضاف حرف ولا يُحذف حرف من النص. المسموح فقط: - إدراج فواصل أسطر (
) ووسوم عرض حول نص موجود، - إزالة علامات الماركداون المتسرّبة («#» في أول عنوان ملتصق، و«**» اليتيمة)، - تغيير طريقة عرض الكتلة (عنوان طويل يُعرض فقرة). وبوّابة المقابلة تقيس ذلك: حروف النص قبل التنسيق وبعده متطابقة بعد طرح «#» و«*». ========================================================= */ const LX_ORD_WORDS = ['أولاً', 'ثانياً', 'ثالثاً', 'رابعاً', 'خامساً', 'سادساً', 'سابعاً', 'ثامناً', 'تاسعاً', 'عاشراً']; const LX_LETTERS = ['أ', 'ب', 'ج', 'د', 'ه', 'و', 'ز', 'ح', 'ط', 'ي']; function lxNormOrd(s) { return String(s).replace(/[ًٌٍَُِّْ]/g, '').replace(/[إأآ]/g, 'ا').replace(/ا$/, '').replace(/اً$/, ''); } const LX_ORD_N = LX_ORD_WORDS.map(lxNormOrd); function lxArDigit(s) { return String(s).replace(/[٠-٩]/g, d => '٠١٢٣٤٥٦٧٨٩'.indexOf(d)); } // رقم المادة من عنوانها — طبقة احتياط فوق _xrKey المنسوخة (التي لا تفهم «مادة 1» بلا «ال» ولا «المئتان») function lxArtNum(text) { const X = window.LexaRender && window.LexaRender.xrKey; if (!X) return 0; let t = String(text || '').replace(/[()\[\]{}«»]/g, ' ').replace(/\s+/g, ' ').trim(); if (!/^(?:ال)?ماد[ةه]/.test(t)) return 0; t = t.replace(/^(?:ال)?ماد[ةه]\s*(?:رقم\s*)?/, '').replace(/^[\s\-–:.]+/, '').replace(/\s*_\s*/g, ' ').replace(/الواحد[ةه]\s+و/, 'الحادية و').replace(/م[ئي]ت/g, 'مائت').replace(/م[ئي]ة|م[ئي]ه/g, 'مائة'); // رقم في الصدر لا يتلوه رقم آخر ولا شرطة مائلة (تاريخ «1440/5/2» ليس رقم مادة) const lead = lxArDigit(t).match(/^(\d{1,3})(?![\d])(?!\s*[\/.]\s*\d)/); if (lead) return +lead[1]; const head = t.split(/\s*[::\-–*]\s*/)[0].trim(); let k = X('المادة ' + head) || X(head); if (k) return k; // «الثالثة السبعون» — واو ساقطة في المصدر بين الآحاد والعشرات const two = head.match(/^(\S+)\s+(ال\S+(?:ون|ين))$/); if (two) { k = X('المادة ' + two[1] + ' و' + two[2]); if (k) return k; } // المئات فوق المائتين: «الثلاثمائة»، «الخامسة بعد الثلاثمائة» const H = { 'ثلاث': 300, 'أربع': 400, 'اربع': 400, 'خمس': 500, 'ست': 600, 'سبع': 700, 'ثمان': 800, 'تسع': 900 }; const hm = head.match(/^(?:(.*?)\s+بعد\s+)?ال(ثلاث|أربع|اربع|خمس|ست|سبع|ثمان|تسع)\s*م[اأ]?[ئي]?[ةه]$/); if (hm) { const r = hm[1] ? X('المادة ' + hm[1]) : 0; if (!hm[1] || r) return H[hm[2]] + r; } // عنوان يتبعه وصف بلا فاصل: «المادة الأولى اسم المعهد ومقره» — أطول بادئة تُقرأ رقماً const ws = head.split(' '); for (let n = Math.min(5, ws.length - 1); n >= 1; n--) { k = X('المادة ' + ws.slice(0, n).join(' ')); if (k) return k; } return 0; } // مواضع بداية البنود المتسلسلة في نص سطر: 1←2←3… أو أ←ب←ج… أو أولاً←ثانياً… function lxEnumBreaks(T) { const out = []; const chainOf = (cands, need, isStart) => { // cands: [{i, v}] بالترتيب. كل «1» يفتح سلسلة جديدة (قوائم متتالية أو متداخلة: بنود «أ» ثم بنود «ب»)، // وكل عنصر يلحق بالسلسلة المفتوحة إن كان تاليها. تُقبل السلاسل التي بلغت الحد. const chains = []; let cur = null; for (const c of cands) { if (c.v === 0) { if (cur) chains.push(cur); cur = [c]; } else if (cur && c.v === cur[cur.length - 1].v + 1) cur.push(c); } if (cur) chains.push(cur); return chains.filter(ch => ch.length >= need || (ch.length >= 2 && isStart(ch[0]))).flat(); }; const atStart = (c) => T.slice(0, c.i).trim() === ''; // أرقام: «1 -» «1-» «1)» «(1)» — مسبوقة ببداية السطر أو فراغ أو علامة ترقيم، لا بشرطة مائلة (تاريخ) const nums = []; for (const m of T.matchAll(/(^|[\s.،؛:])(\(?)([0-9]{1,2}|[١-٩][٠-٩]?)\s*(?:\)\s*[-–]?|[-–])\s*(?=\S)/g)) { nums.push({ i: m.index + m[1].length, v: +lxArDigit(m[3]) - 1 }); } // حروف: «أ -» «ب-» «ج)» … const lets = []; for (const m of T.matchAll(/(^|[\s.،؛:])\(?(أ|ب|ج|د|هـ|ه|و|ز|ح|ط|ي)\s*(?:\)|[-–])\s*(?=\S)/g)) { const L = m[2] === 'هـ' ? 'ه' : m[2]; lets.push({ i: m.index + m[1].length, v: LX_LETTERS.indexOf(L) }); } // «أولاً:» «ثانياً -» const ords = []; for (const m of T.matchAll(/(^|[\s.،؛])((?:أ|ا)ول[اً]*|ثاني[اً]*|ثالث[اً]*|رابع[اً]*|خامس[اً]*|سادس[اً]*|سابع[اً]*|ثامن[اً]*|تاسع[اً]*|عاشر[اً]*)\s*[::\-–]/g)) { ords.push({ i: m.index + m[1].length, v: LX_ORD_N.indexOf(lxNormOrd(m[2])) }); } for (const [cands, need] of [[nums, 3], [lets, 3], [ords, 2]]) { const ch = chainOf(cands.filter(c => c.v >= 0), need, atStart); ch.forEach((c, k) => { if (!(k === 0 && atStart(c))) out.push(c.i); }); } return [...new Set(out)].sort((a, b) => a - b); } // إدراج عناصر في مواضع نصية داخل عنصر DOM (يمر على عقد النص فلا يكسر الوسوم) function lxInsertAt(el, positions, make) { if (!positions.length) return; const walker = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null); const nodes = []; let n; while ((n = walker.nextNode())) nodes.push(n); let base = 0, pi = 0; for (const node of nodes) { const len = node.textContent.length; const local = []; while (pi < positions.length && positions[pi] <= base + len) { if (positions[pi] >= base && positions[pi] > 0) local.push(positions[pi] - base); pi++; } for (let k = local.length - 1; k >= 0; k--) { const off = local[k]; if (off > 0 && off <= len) { const rest = node.splitText(off); node.parentNode.insertBefore(make(), rest); } else if (off === 0) node.parentNode.insertBefore(make(), node); } base += len; } } // عنوان سطري للمواد داخل كتلة بلا عناوين: «المادة الأولى:» «مادة (3) -» «أولاً:» في أول السطر const LX_INLINE_ART = /^\s*((?:ال)?ماد[ةه]\s*(?:رقم\s*)?\(?\s*[^\s()::\-–]{1,20}(?:\s+(?:و?[^\s()::\-–]{2,14}|عشر[ةه]?|بعد\s+\S+)){0,3}\s*\)?)\s*(?=[::\-–]|$)/; // «أولاً» و«أولًا» و«اولا» سواء: التشكيل اختياري بين الحروف وبعدها const LX_INLINE_ORD = new RegExp('^\\s*((?:' + ['أولا', 'اولا', 'ثانيا', 'ثالثا', 'رابعا', 'خامسا', 'سادسا', 'سابعا', 'ثامنا', 'تاسعا', 'عاشرا'] .map(w => w.split('').join('[\\u064B-\\u0652]*')).join('|') + ')[\\u064B-\\u0652]*)\\s*(?=[::\\-–])'); function lxFormatBlocks(blocks) { let anchorSeq = 0; // وثيقة بلا أي عنوان: كتلتها الوحيدة هي النص كله لا «مقدمة» if (blocks.length === 1 && blocks[0].type === 'pre') blocks[0].text = 'نص الوثيقة'; const artLike = (b) => b && b.type !== 'pre' && (/^\s*\(?\s*(?:ال)?ماد[ةه]/.test(b.text) || /^\s*[(\[]?\s*[0-9٠-٩]{1,3}\s*[)\]\-–.:]/.test(b.text)); blocks.forEach((b, i) => { if (b.type !== 'art') return; // جملة من المتن صارت عنواناً («بناء على المادة…»، «بعد الاطلاع…»): تُعرض نصاً if (/^\s*(?:و?بناء|و?بناءً|و?بعد\s+الاطلاع|استناد|نظراً|نظرا|وحيث|حيث\s+إن|إشارة)/.test(b.text)) b.longHead = true; // عنوان بلا متن يليه عنوان مادة = عنوان قسم («(الفصل الثاني) البدلات»، «أحكام عامة»، «أحكام ختامية») else if (!b.parts.length && !b.notes.length && !b.cancel && !artLike(b) && artLike(blocks[i + 1])) b.type = 'sec'; // «(الفصل الثاني) …» بين قوسين else if (/^\s*[(\[]\s*(?:الباب|الفصل|القسم|الفرع|المبحث)/.test(b.text) && !b.parts.length) b.type = 'sec'; }); for (const b of blocks) { // ٠) مادة نصها كله في سطر العنوان («المادة التاسعة : تتولى وزارة الداخلية…») ومتنها فارغ: // العنوان رقم المادة، والباقي متن. النقطتان تبقيان في DOM (مخفيتين) فلا يسقط حرف. if (b.type === 'art' && !b.parts.length && !b.cancel) { const sm = b.text.match(/^((?:ال)?ماد[ةه]\s*[^::]{1,40}?)\s*([::])\s*(\S.{24,})$/); if (sm && lxArtNum(sm[1])) { b.headHtml = lxEsc(sm[1]) + '' + sm[2] + ''; b.parts = ['
' + lxEsc(sm[3]) + '
']; b.text = sm[1].trim(); b.splitHead = true; } } // ١) فقرة كاملة صارت عنواناً: تُعرض نصاً، ويظهر في الفهرس أولها فقط if (b.type !== 'pre' && b.text.length > 140) { b.longHead = true; b.tocText = b.text.slice(0, 70).replace(/\s+\S*$/, '') + '…'; if (b.type === 'sec') b.type = 'art'; } b.num = +b.dataArt || lxArtNum(b.text); if (!b.parts.length) continue; const box = document.createElement('div'); box.innerHTML = b.parts.join(''); const lines = box.querySelectorAll('.art-line'); const bodyLen = box.textContent.length; const wantAnchors = b.type === 'pre' || bodyLen > 5000; b.anchors = []; lines.forEach(el => { // ٢) «**» يتيمة لم يلتقطها المحوّل (تُترك سلاسل النجوم الطويلة فقد تكون جزءاً من النص) const w = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null); let tn; while ((tn = w.nextNode())) { if (/(^|[^*])\*\*(?!\*)/.test(tn.textContent)) tn.textContent = tn.textContent.replace(/(^|[^*])\*\*(?!\*)/g, '$1'); } // ٣) عنوان ملتصق بالسطر: «… النظام". ### الفصل الثالث: الأجور» const T0 = el.textContent; const hm = T0.match(/(^|\s)(#{2,6})\s+(\S[^#]{0,120})$/); if (hm) { const at = hm.index + hm[1].length; const w2 = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null); let t2, base = 0; while ((t2 = w2.nextNode())) { const L = t2.textContent.length; if (at >= base && at < base + L) { const off = at - base; const s = t2.textContent; const markEnd = off + hm[2].length + (s.slice(off + hm[2].length).match(/^\s+/) || [''])[0].length; const head = document.createElement('span'); head.className = 'lx-inhead'; head.textContent = s.slice(markEnd); t2.textContent = s.slice(0, off); t2.parentNode.insertBefore(document.createElement('br'), t2.nextSibling); t2.parentNode.insertBefore(head, t2.nextSibling.nextSibling); // ما بعد العقدة نفسها (إن وُجد) يلحق بالعنوان كما هو let sib = head.nextSibling; while (sib) { const nx = sib.nextSibling; head.appendChild(sib); sib = nx; } break; } base += L; } b.fixedHeads = (b.fixedHeads || 0) + 1; } else if (/(^|\s)#{2,6}\s+\S/.test(T0)) { // علامة عنوان في وسط السطر: تُحذف العلامة وحدها ويبدأ ما بعدها سطراً const w3 = document.createTreeWalker(el, NodeFilter.SHOW_TEXT, null); let t3; while ((t3 = w3.nextNode())) { if (/(^|\s)#{2,6}\s+/.test(t3.textContent)) { const parts = t3.textContent.split(/(?:^|\s)#{2,6}\s+/); const frag = document.createDocumentFragment(); parts.forEach((p, i) => { if (i) { frag.appendChild(document.createElement('br')); } frag.appendChild(document.createTextNode(p)); }); t3.parentNode.replaceChild(frag, t3); break; } } } // ٤) بنود متسلسلة ملتصقة: كل بند في سطر const T = el.textContent; if (T.length > 80) { const pos = lxEnumBreaks(T); if (pos.length) { lxInsertAt(el, pos, () => { const br = document.createElement('br'); br.className = 'lx-ebr'; return br; }); b.enumFixed = (b.enumFixed || 0) + pos.length; } } // ٥) فهرسة داخلية للكتل الضخمة بلا عناوين: «المادة الأولى:» «أولاً:» في أول كل سطر مرئي // (أول الفقرة، وبعد كل فاصل بنود أُدرج في الخطوة ٤) if (wantAnchors) { const tryAnchor = (txt, place) => { const ma = txt.match(LX_INLINE_ART); // «المادة المشعة:» تعريفٌ لا رأس مادة — لا يُفهرس «المادة …» إلا برقم مقروء const m = (ma && lxArtNum(ma[1]) ? ma : null) || txt.match(LX_INLINE_ORD); if (!m) return; const id = 'lx-a-' + b.ord + '-' + (++anchorSeq); place(id); b.anchors.push({ id, label: m[1].replace(/\s+/g, ' ').trim(), num: lxArtNum(m[1]) }); }; tryAnchor(el.textContent, id => { el.id = id; el.classList.add('lx-anchor'); }); // عنوانُ قسمٍ مرقَّم في الأدلة والعقود («1. المقدمة» · «2.3 نطاق التطبيق»): سطرٌ قصيرٌ بلا ختامِ جملة، // تليه فقرةٌ أطول — لا بندُ قائمة. يُفهرَس ولا يُمسّ نصُّه. if (!el.id) { const t = el.textContent.trim(); const nx = el.nextElementSibling; const m = t.match(/^((?:[0-9]{1,2}|[١-٩][٠-٩]?)(?:[.\-][0-9٠-٩]{1,2}){0,3})\s*[-.)–]?\s+(\S[^.:؛،]{2,70})$/); if (m && t.length <= 80 && nx && (nx.textContent || '').trim().length > 60) { const id = 'lx-a-' + b.ord + '-' + (++anchorSeq); el.id = id; el.classList.add('lx-anchor'); b.anchors.push({ id, label: t, num: 0 }); } } el.querySelectorAll('br.lx-ebr').forEach(br => { let s = '', n = br.nextSibling; while (n && s.length < 90) { s += n.textContent || ''; n = n.nextSibling; } tryAnchor(s, id => { const sp = document.createElement('span'); sp.id = id; sp.className = 'lx-anchor'; br.parentNode.insertBefore(sp, br.nextSibling); }); }); } }); // «**» يتيمة خارج أسطر المتن أيضاً (خلايا الجداول والاقتباسات) const wAll = document.createTreeWalker(box, NodeFilter.SHOW_TEXT, null); let tnA; while ((tnA = wAll.nextNode())) { if (/(^|[^*])\*\*(?!\*)/.test(tnA.textContent)) tnA.textContent = tnA.textContent.replace(/(^|[^*])\*\*(?!\*)/g, '$1'); } b.parts = [box.innerHTML]; } return blocks; } function lxRenderDoc(doc, mode) { let text = doc.text || ''; if (mode === 'before') text = window.LexaRender.reconstructBefore(text); window.AMEND_LINKS[doc.did] = doc.amend_links || {}; window._AMENDPOPS = []; const html = window.LexaRender.renderDocMd(text, doc.did); return lxFormatBlocks(lxParseBlocks(html, (window._AMENDPOPS || []).slice())); } // المادة برقمها: الأخيرة ذات الرقم (كما في «أمل»: المادة المكررة في آخر الوثيقة هي النافذة) function lxFindArt(blocks, an) { const s = String(an); return (blocks || []).filter(b => b.type === 'art' && (b.dataArt === s || (!b.dataArt && b.num === +an))).slice(-1)[0] || null; } function lxBlockKinds(b) { const k = new Set(b.notes.map(n => n.kind)); if (b.cancel) k.add('cancel'); return k; } /* ── نقاط اتصال الشفرة المنسوخة من «أمل» (onclick داخل HTML المصيَّر) ── */ window.xrefGo = function (el, tgt, art) { window.dispatchEvent(new CustomEvent('lx:xref', { detail: { tgt: tgt || '', art: +art || 0 } })); return false; }; window.artCopy = function () { return false; }; window.openAmendFloat = function () { return false; }; /* ── آخر ما قُرئ ── */ function lxRememberDoc(doc) { const list = lxLoad('lx-recent', []).filter(x => x.did !== doc.did); list.unshift({ did: doc.did, title: doc.title, kind: doc.kind }); lxSave('lx-recent', list.slice(0, 8)); } /* ========================================================= التنسيقات ========================================================= */ const LX_CSS = ` .lx-root{--ink:#efe7d6;--ink2:#c9c2b3;--ink3:#a8a69e;--mute:#9a9384;--paper:#16211d;--bg2:#1d2a25;--line:rgba(239,231,214,.10);--line2:rgba(239,231,214,.06); --bg:#0f1715;--card:#16211d;--soft:#1d2a25;--brand:#c96442;--brand-d:#ffb08f;--brand-s:rgba(224,122,82,0.16); --sheet:#16211d;--sheet-ink:#ebe4d4;--sheet-line:rgba(239,231,214,.08);--fs:17px;--lh:2.05; --read:'Noto Naskh Arabic','Amiri',serif;font-family:'IBM Plex Sans Arabic',sans-serif;color:var(--ink);direction:rtl;height:100%;} .lx-root *{box-sizing:border-box} .lx-root[data-theme=white]{--sheet:#1d2a25;--sheet-ink:#f4eedf} .lx-root[data-theme=night]{--sheet:#1e1e1c;--sheet-ink:#e8e5da;--sheet-line:rgba(255,255,255,.08)} .lx-page{max-width:1180px;margin:0 auto;padding:28px 28px 60px} .lx-sections{display:flex;gap:6px;background:var(--soft);padding:5px;border-radius:14px;width:max-content;max-width:100%;overflow:auto;margin:0 auto} .lx-sec-btn{border:0;background:transparent;padding:9px 18px;border-radius:10px;font:inherit;font-size:14px;font-weight:500;color:var(--ink2);cursor:pointer;display:flex;align-items:center;gap:8px;white-space:nowrap;transition:all .18s} .lx-sec-btn:hover{color:var(--ink)} .lx-sec-btn.on{background:var(--card);color:var(--ink);box-shadow:0 1px 3px rgba(0,0,0,.08),0 0 0 1px var(--line)} .lx-soon{font-size:10.5px;background:var(--brand-s);color:var(--brand-d);padding:1px 7px;border-radius:20px;font-weight:600} .lx-kbd{font-family:'JetBrains Mono',monospace;font-size:11px;background:var(--soft);border-radius:5px;padding:1px 6px;color:var(--ink3);box-shadow:inset 0 -1px 0 rgba(0,0,0,.12)} .lx-hero{text-align:center;padding:40px 0 22px} .lx-hero.lx-hero-compact{padding:18px 0 8px} .lx-cat.lx-cat-treaty{box-shadow:0 0 0 1.5px rgba(143,184,224,.35);background:linear-gradient(180deg,rgba(143,184,224,.10),#16211d)} .lx-save-doc{margin-inline-start:auto;border:0;background:var(--brand-s);color:var(--brand-d);border-radius:20px;padding:4px 12px;font:inherit;font-size:12.5px;font-weight:600;cursor:pointer} .lx-save-doc:hover{background:#d49a1e;color:#0f1715} .lx-ai-cta{display:flex;align-items:center;gap:12px;width:100%;margin:0 0 14px;padding:12px 16px;border:1px dashed rgba(201,100,66,.45);background:linear-gradient(90deg,rgba(201,100,66,.07),rgba(201,100,66,.02));border-radius:14px;font:inherit;font-size:13.5px;color:var(--ink);cursor:pointer;text-align:start} .lx-ai-cta:hover{border-style:solid;background:rgba(201,100,66,.09)} .lx-ai-cta .ic,.lx-ai-h .ic{width:30px;height:30px;border-radius:9px;display:grid;place-items:center;background:#c96442;color:#fff;font-size:14px;flex-shrink:0} .lx-ai-cta b{margin-inline-end:6px} .lx-ai-cta .go{margin-inline-start:auto;color:#ffb08f;font-weight:600;white-space:nowrap} .lx-ai{margin:0 0 16px;border-radius:16px;background:var(--paper);color:var(--ink);box-shadow:0 0 0 1px rgba(201,100,66,.28),0 6px 22px rgba(201,100,66,.08);overflow:hidden} .lx-ai.is-run{box-shadow:0 0 0 1px rgba(201,100,66,.45),0 6px 22px rgba(201,100,66,.12)} .lx-ai-h{display:flex;align-items:center;gap:10px;padding:10px 14px;border-bottom:1px solid rgba(239,231,214,.07);font-size:14px} .lx-ai-h .sp{flex:1} .lx-ai-h button{white-space:nowrap} .lx-rhead>*{min-width:0} .lx-ai-h button{border:0;background:rgba(239,231,214,.06);border-radius:8px;padding:5px 10px;font:inherit;font-size:12.5px;cursor:pointer;color:var(--ink2)} .lx-ai-h button:hover{background:rgba(201,100,66,.12);color:#ffb08f} .lx-ai-tag{font-size:12px;color:var(--mute,#87867f)} .lx-ai-b{padding:12px 16px 14px;font-size:14.5px;line-height:1.95;white-space:pre-wrap} .lx-ai-err{color:#ff8a8a;font-size:13.5px} .lx-ai-wait{display:flex;gap:5px;align-items:center;color:var(--mute,#87867f);font-size:13px} .lx-ai-wait i{width:6px;height:6px;border-radius:50%;background:#c96442;animation:lxAiP 1s ease-in-out infinite} .lx-ai-wait i:nth-child(2){animation-delay:.15s}.lx-ai-wait i:nth-child(3){animation-delay:.3s;margin-inline-end:6px} @keyframes lxAiP{0%,100%{opacity:.25}50%{opacity:1}} .lx-sem{margin:18px 0 8px;padding:14px;border-radius:14px;background:rgba(134,160,150,.08);border:1px solid rgba(239,231,214,.06)} .lx-sem.is-top{margin-top:4px} .lx-sem-h{display:flex;gap:10px;align-items:baseline;flex-wrap:wrap;margin-bottom:10px;font-size:14px} .lx-sem-h span{font-size:12.5px;color:var(--mute,#87867f)} .lx-sem-list{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,260px),1fr));gap:8px} .lx-sem-i{display:flex;flex-direction:column;gap:4px;text-align:start;border:0;background:var(--paper);color:var(--ink);border-radius:10px;padding:10px 12px;font:inherit;cursor:pointer;box-shadow:0 0 0 1px rgba(239,231,214,.07);min-width:0} .lx-sem-i:hover{box-shadow:0 0 0 1px rgba(201,100,66,.4)} .lx-sem-i .t{font-size:13.5px;font-weight:600;color:var(--ink)} .lx-sem-i .t small{font-weight:400;color:var(--mute,#87867f)} .lx-sem-i .x{font-size:12.5px;color:var(--ink2);line-height:1.75;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;overflow:hidden} .lx-explain{margin:10px 0 4px;border-radius:12px;background:rgba(201,100,66,.05);box-shadow:0 0 0 1px rgba(201,100,66,.22);padding:0 14px 12px;font-size:14.5px;line-height:1.9;white-space:pre-wrap} .lx-explain .lx-ai-h{white-space:normal} .lx-explain .lx-ai-h{padding:10px 0;margin-bottom:6px} .lx-und{margin:6px 0 12px} .lx-und-row{display:flex;flex-wrap:wrap;align-items:center;gap:8px 14px;font-size:13px;color:var(--ink2)} .lx-und-i{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap} .lx-und-i b{font-weight:600;color:var(--ink)} .lx-und-soft{color:var(--ink3)} .lx-und-law{border:0;background:var(--brand-s);color:var(--brand-d);border-radius:20px;padding:2px 10px;font:inherit;font-size:12.5px;font-weight:600;cursor:pointer} .lx-und-sug{border:0;background:none;color:var(--brand);font:inherit;font-weight:700;cursor:pointer;padding:0;text-decoration:underline} .lx-ask{margin-inline-start:auto;border:0;background:var(--brand);color:#fff;border-radius:20px;padding:5px 14px;font:inherit;font-size:13px;font-weight:600;cursor:pointer} .lx-jump{background:var(--card);border-radius:12px;padding:12px 16px;margin-bottom:10px;box-shadow:0 0 0 1.5px var(--brand-s);cursor:pointer} .lx-jump .lbl{font-weight:700;color:var(--brand-d);margin-bottom:6px} .lx-jump .tx{font-size:14px;line-height:1.9;color:var(--ink)} .lx-jump .go{display:inline-block;margin-top:6px;font-size:13px;color:var(--brand);font-weight:600} .lx-country {display: flex;flex-wrap: wrap;align-items: center;gap: 6px;margin: 10px 0 4px;} .lx-country-lbl {font-size: 13px;color: var(--ink2);font-weight: 600;} .lx-country-box {position: relative;} .lx-country-pop {position: absolute;top: calc(100% + 6px);inset-inline-start: 0;z-index: 30;width: 280px;max-width: 86vw;background: var(--card);border: 1px solid var(--line);border-radius: 12px;box-shadow: 0 10px 30px rgba(0,0,0,.12);padding: 8px;} .lx-country-in {width: 100%;box-sizing: border-box;border: 1px solid var(--line);border-radius: 8px;padding: 7px 10px;font: inherit;font-size: 13.5px;color:var(--ink);margin-bottom: 6px;background: transparent;color: inherit;} .lx-country-list {max-height: 300px;overflow-y: auto;display: flex;flex-direction: column;} .lx-country-it {display: flex;justify-content: space-between;gap: 8px;text-align: start;background: none;border: 0;padding: 6px 8px;border-radius: 7px;font: inherit;font-size: 13.5px;color: inherit;cursor: pointer;} .lx-country-it:hover, .lx-country-it.on {background: var(--soft);} .lx-country-it.bloc span {font-weight: 600;} .lx-country-it small {color: var(--ink3);} .lx-country-empty {padding: 8px;font-size: 13px;color: var(--ink3);} .lx-chip-sm {font-size: 12.5px;padding: 3px 9px;} .lx-hero-compact h1{margin-bottom:6px} .lx-stats-line{display:flex;justify-content:center;gap:8px 18px;flex-wrap:wrap;margin-top:14px;font-size:13px;color:var(--ink3)} .lx-stats-line b{color:var(--ink);font-weight:700;margin-left:4px} .lx-recent-strip{display:flex;align-items:center;gap:8px;overflow-x:auto;white-space:nowrap;margin:14px 0 4px;padding:8px 12px;background:#16211d;border-radius:12px;box-shadow:0 0 0 1px var(--line)} .lx-recent-strip .lbl{font-size:12px;font-weight:700;color:var(--ink3);flex-shrink:0;padding-left:4px} .lx-recent-strip button{border:0;background:var(--bg2);border-radius:20px;padding:5px 12px;font:inherit;font-size:13px;color:var(--ink);cursor:pointer;max-width:260px;overflow:hidden;text-overflow:ellipsis;flex-shrink:0} .lx-recent-strip button:hover{background:var(--brand-s);color:var(--brand-d)} .lx-hero h1{font-family:'Noto Kufi Arabic',sans-serif;font-size:34px;font-weight:700;letter-spacing:-.3px;margin:22px 0 10px} .lx-hero p{color:var(--ink3);font-size:15.5px;margin:0 0 26px} .lx-sbox{position:relative;max-width:780px;margin:0 auto} .lx-sfield{display:flex;align-items:center;gap:10px;background:var(--card);border-radius:16px;padding:6px 8px 6px 16px; box-shadow:0 0 0 1px var(--line),0 8px 30px rgba(0,0,0,.06);transition:box-shadow .2s} .lx-sfield:focus-within{box-shadow:0 0 0 2px var(--brand),0 8px 30px rgba(201,100,66,.12)} .lx-sfield input{flex:1;border:0;outline:0;background:transparent;font:inherit;font-size:17px;padding:12px 4px;color:var(--ink);min-width:0} .lx-sfield.sm input{font-size:15px;padding:8px 2px} .lx-sbtn{border:0;background:var(--brand);color:#fff;font:inherit;font-weight:600;font-size:15px;padding:11px 22px;border-radius:11px;cursor:pointer;transition:background .15s} .lx-sbtn:hover{background:#e07a52} .lx-sfield.sm .lx-sbtn{padding:8px 16px;font-size:14px} .lx-sugg{position:absolute;top:calc(100% + 6px);inset-inline:0;background:var(--card);border-radius:14px;box-shadow:0 0 0 1px var(--line),0 16px 40px rgba(0,0,0,.12);z-index:40;overflow:hidden;text-align:right} .lx-sugg-i{display:flex;align-items:center;gap:10px;padding:11px 16px;cursor:pointer;font-size:14.5px} .lx-sugg-i:hover,.lx-sugg-i.on{background:var(--soft)} .lx-sugg-i .t{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap} .lx-sugg-i .d{font-size:12px;color:var(--mute)} .lx-sugg-art{background:linear-gradient(90deg,#1d2a25,#16211d);border-bottom:1px solid var(--line2)} .lx-sugg-foot{padding:9px 16px;font-size:12.5px;color:var(--ink3);border-top:1px solid var(--line2);cursor:pointer;display:flex;gap:8px;align-items:center} .lx-sugg-foot:hover{background:var(--soft)} mark{background:rgba(244,212,122,0.3);color:inherit;padding:0 1px;border-radius:3px} .lx-chips{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;margin-top:16px} /* بطلُ البحث الداكن — بروحِ الصفحةِ الرئيسيّة (القائمةُ المنسدلةُ تخرجُ منه فلا overflow:hidden) */ .lx-hero-dark{position:relative;background:#0d1412;color:#efe7d6;border-radius:26px;padding:30px clamp(16px,4vw,40px) 24px!important;margin-top:16px;box-shadow:0 22px 60px rgba(13,20,18,.2)} .lx-hero-dark:before{content:"";position:absolute;inset:0;border-radius:inherit;pointer-events:none;opacity:.75;background:linear-gradient(135deg,transparent 48%,rgba(239,231,214,.035) 48% 52%,transparent 52%) 0 0/42px 42px,linear-gradient(45deg,transparent 48%,rgba(239,231,214,.035) 48% 52%,transparent 52%) 0 0/42px 42px,radial-gradient(520px 300px at 85% 0%,rgba(31,138,138,.28),transparent 70%),radial-gradient(420px 260px at 10% 100%,rgba(224,122,82,.22),transparent 70%)} .lx-hero-dark>*{position:relative} .lx-hero-dark h1{color:#efe7d6;margin-top:6px!important} .lx-hero-dark p{color:#c9c2b3!important} .lx-hero-dark .lx-sfield{box-shadow:0 0 0 1px rgba(239,231,214,.14),0 14px 40px rgba(0,0,0,.35)} .lx-hero-dark .lx-sfield:focus-within{box-shadow:0 0 0 2px #e07a52,0 14px 40px rgba(224,122,82,.25)} .lx-hero-dark .lx-chip{color:#c9c2b3;box-shadow:0 0 0 1px rgba(239,231,214,.16);background:rgba(239,231,214,.04)} .lx-hero-dark .lx-chip:hover{color:#fff;background:rgba(224,122,82,.2);box-shadow:0 0 0 1px rgba(224,122,82,.6)} .lx-hero-dark .lx-stats-line{color:#8f9a94} .lx-hero-dark .lx-stats-line b{color:#efe7d6;font-family:'JetBrains Mono',monospace;font-weight:500} .lx-hero-dark .lx-sugg{color:#efe7d6} .lx-hero-dark .lx-sugg .t,.lx-hero-dark .lx-sugg-foot{color:#efe7d6} .lx-hero-dark .lx-sugg .d{color:#8f9a94} .lx-hero-dark .lx-sfield input{color:#efe7d6} .lx-chip{border:0;background:transparent;box-shadow:0 0 0 1px var(--line);padding:6px 13px;border-radius:30px;font:inherit;font-size:13px;color:var(--ink2);cursor:pointer;transition:all .15s} .lx-chip:hover{box-shadow:0 0 0 1px var(--brand);color:var(--brand-d);background:var(--brand-s)} .lx-hint{font-size:12.5px;color:var(--mute);margin-top:12px} .lx-stats{display:flex;justify-content:center;gap:40px;margin:30px 0 4px;flex-wrap:wrap} .lx-stat b{display:block;font-size:24px;font-weight:700;font-family:'Noto Kufi Arabic',sans-serif} .lx-stat span{font-size:12.5px;color:var(--mute)} .lx-h2{display:flex;align-items:baseline;gap:10px;margin:38px 0 14px} .lx-h2 h2{font-size:19px;font-weight:700;margin:0} .lx-h2 span{font-size:13px;color:var(--mute)} .lx-recent{display:flex;gap:10px;overflow:auto;padding-bottom:4px} .lx-recent button{flex-shrink:0;max-width:280px;border:0;background:var(--card);box-shadow:0 0 0 1px var(--line);border-radius:12px;padding:10px 14px;font:inherit;text-align:right;cursor:pointer;display:flex;flex-direction:column;gap:6px;transition:box-shadow .15s} .lx-recent button:hover{box-shadow:0 0 0 1px var(--brand)} .lx-recent b{font-size:13.5px;font-weight:600;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} .lx-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(210px,1fr));gap:12px} .lx-cat{background:var(--card);border-radius:14px;padding:16px;box-shadow:0 0 0 1px var(--line);cursor:pointer;transition:all .18s;text-align:right;border:0;font:inherit;color:inherit} .lx-cat:hover{box-shadow:0 0 0 1px var(--brand),0 6px 18px rgba(0,0,0,.06);transform:translateY(-1px)} .lx-cat .ic{font-size:22px} .lx-cat .nm{font-weight:600;font-size:14.5px;margin:8px 0 4px} .lx-cat .ct{font-size:12.5px;color:var(--mute)} .lx-two{display:grid;grid-template-columns:1fr 1fr;gap:16px} @media(max-width:900px){.lx-two{grid-template-columns:1fr}} .lx-panel{background:var(--card);border-radius:16px;box-shadow:0 0 0 1px var(--line);padding:6px 0} .lx-panel-h{padding:14px 18px 8px;font-weight:700;font-size:15px;display:flex;align-items:center;gap:8px;flex-wrap:wrap} .lx-panel-h small{font-weight:400;color:var(--mute);font-size:12px} .lx-row{display:flex;align-items:center;gap:12px;padding:11px 18px;cursor:pointer;border-top:1px solid var(--line2);transition:background .12s} .lx-row:hover{background:var(--soft)} .lx-row .t{flex:1;font-size:14px;font-weight:500} .lx-row .s{font-size:12px;color:var(--mute)} .lx-count{min-width:62px;text-align:center;background:var(--brand-s);color:var(--brand-d);border-radius:10px;padding:5px 6px;font-size:12px;font-weight:600;line-height:1.3} .lx-count b{display:block;font-size:17px} .lx-badge{display:inline-flex;align-items:center;gap:5px;font-size:11.5px;font-weight:600;padding:3px 9px;border-radius:20px;white-space:nowrap} .lx-dot{width:6px;height:6px;border-radius:50%;display:inline-block;flex-shrink:0} /* ── النتائج ── */ .lx-rhead{display:flex;align-items:center;gap:14px;padding:14px 28px;border-bottom:1px solid var(--line);background:rgba(15,23,21,.9);backdrop-filter:blur(8px);position:sticky;top:0;z-index:20} .lx-back{border:0;background:transparent;font:inherit;color:var(--ink2);cursor:pointer;display:flex;align-items:center;gap:6px;padding:7px 10px;border-radius:9px;font-size:13.5px;white-space:nowrap} .lx-back:hover{background:var(--soft);color:var(--ink)} .lx-rbody{display:grid;grid-template-columns:250px 1fr;gap:28px;max-width:1240px;margin:0 auto;padding:22px 28px 60px} .lx-ftoggle{display:none} .lx-filters{position:sticky;top:78px;align-self:start;max-height:calc(100vh - 160px);overflow:auto;padding-left:4px} .lx-fgroup{margin-bottom:20px} .lx-fgroup h4{font-size:12.5px;color:var(--mute);font-weight:600;margin:0 0 8px} .lx-fopt{display:flex;align-items:center;gap:8px;width:100%;border:0;background:transparent;font:inherit;font-size:13.5px;color:var(--ink2);padding:6px 9px;border-radius:8px;cursor:pointer;text-align:right} .lx-fopt:hover{background:var(--soft)} .lx-fopt.on{background:var(--brand-s);color:var(--brand-d);font-weight:600} .lx-fopt .n{margin-inline-start:auto;font-size:11.5px;color:var(--mute)} .lx-fopt.sub{padding-inline-start:26px;font-size:13px} .lx-seg{display:flex;background:var(--soft);border-radius:10px;padding:3px;gap:2px} .lx-seg button{flex:1;border:0;background:transparent;font:inherit;font-size:12.5px;padding:6px 8px;border-radius:8px;cursor:pointer;color:var(--ink2);white-space:nowrap} .lx-seg button.on{background:var(--card);color:var(--ink);box-shadow:0 1px 2px rgba(0,0,0,.1)} .lx-toggle{display:flex;align-items:center;gap:8px;font-size:13px;color:var(--ink2);cursor:pointer;padding:5px 2px} .lx-toggle input{accent-color:var(--brand)} .lx-year{display:flex;gap:6px} .lx-year input{width:100%;border:0;box-shadow:0 0 0 1px var(--line);border-radius:8px;padding:7px 8px;font:inherit;font-size:13px;background:var(--card);color:var(--ink)} .lx-rmeta{display:flex;align-items:center;justify-content:space-between;gap:12px;margin-bottom:14px;flex-wrap:wrap} .lx-rmeta .c{font-size:14px;color:var(--ink2)} .lx-rmeta .c b{color:var(--ink)} .lx-select{border:0;box-shadow:0 0 0 1px var(--line);border-radius:9px;padding:7px 10px;font:inherit;font-size:13px;background:var(--card);color:var(--ink)} .lx-active{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:12px} .lx-active button{border:0;background:var(--brand-s);color:var(--brand-d);box-shadow:0 0 0 1px rgba(224,122,82,.35);font:inherit;font-size:12px;padding:4px 10px;border-radius:20px;cursor:pointer} .lx-card{position:relative;background:var(--card);border-radius:16px;box-shadow:0 0 0 1px var(--line);padding:18px 22px;margin-bottom:12px;transition:box-shadow .18s;overflow:hidden} .lx-card:before{content:'';position:absolute;right:0;top:0;bottom:0;width:3px;background:var(--kc,transparent)} .lx-card:hover{box-shadow:0 0 0 1px rgba(201,100,66,.45),0 8px 24px rgba(0,0,0,.05)} .lx-card-top{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:8px} .lx-card-t{font-size:17.5px;font-weight:700;line-height:1.55;cursor:pointer;color:var(--ink);margin:0} .lx-card-t:hover{color:var(--brand-d)} .lx-card-m{display:flex;flex-wrap:wrap;gap:4px 14px;font-size:12.5px;color:var(--ink3);margin-top:6px} .lx-card-p{font-size:12.5px;color:var(--ink3);margin-top:6px} .lx-card-p a{color:var(--brand-d);cursor:pointer;text-decoration:none;font-weight:500} .lx-card-p a:hover{text-decoration:underline} .lx-card-s{display:flex;gap:16px;flex-wrap:wrap;margin-top:12px;padding-top:12px;border-top:1px dashed var(--line);font-size:12.5px;color:var(--ink2)} .lx-card-s b{color:var(--ink)} .lx-snips{margin-top:12px;display:flex;flex-direction:column;gap:8px} .lx-snip{background:#1d2a25;border-radius:11px;padding:10px 14px;cursor:pointer;transition:background .12s} .lx-snip:hover{background:var(--brand-s)} .lx-snip .h{font-size:12.5px;font-weight:700;color:var(--brand-d);margin-bottom:3px} .lx-snip .h small{font-weight:400;color:var(--mute)} .lx-snip .b{font-family:var(--read);font-size:14.5px;line-height:1.9;color:var(--ink2)} .lx-more{font-size:12.5px;color:var(--brand-d);cursor:pointer;margin-top:4px;display:inline-block} .lx-best{background:linear-gradient(135deg,#16211d 0%,#22302a 100%);border-radius:18px;box-shadow:0 0 0 1px rgba(201,100,66,.35),0 10px 30px rgba(201,100,66,.08);padding:22px 24px;margin-bottom:16px} .lx-best .lbl{font-size:11.5px;font-weight:700;color:var(--brand-d);letter-spacing:.3px;margin-bottom:6px} .lx-best h3{font-family:'Noto Kufi Arabic',sans-serif;font-size:22px;margin:4px 0 8px;cursor:pointer} .lx-best h3:hover{color:var(--brand-d)} .lx-best-acts{display:flex;gap:8px;flex-wrap:wrap;margin-top:14px;align-items:center} .lx-best-acts input{border:0;box-shadow:0 0 0 1px var(--line);border-radius:9px;padding:7px 10px;font:inherit;font-size:13px;width:150px;background:#16211d;color:var(--ink)} .lx-direct{background:var(--card);border-radius:18px;box-shadow:0 0 0 2px var(--brand),0 12px 34px rgba(201,100,66,.12);padding:20px 24px;margin-bottom:18px} .lx-direct .lbl{font-size:11.5px;font-weight:700;color:var(--brand-d);margin-bottom:4px} .lx-direct h3{font-size:18px;margin:2px 0 4px} .lx-direct .law{font-size:13px;color:var(--ink3);margin-bottom:10px} .lx-direct .body{font-family:var(--read);font-size:16px;line-height:2;color:#efe7d6;max-height:340px;overflow:auto;padding-left:6px} .lx-direct .body .art-line{margin:0 0 4px} .lx-pager{display:flex;gap:6px;justify-content:center;margin-top:24px;flex-wrap:wrap} .lx-pager button{border:0;min-width:38px;height:38px;border-radius:10px;background:var(--card);box-shadow:0 0 0 1px var(--line);font:inherit;cursor:pointer;color:var(--ink2)} .lx-pager button.on{background:var(--brand);color:#fff;box-shadow:none} .lx-pager button:disabled{opacity:.4;cursor:default} .lx-empty{text-align:center;padding:60px 20px;color:var(--ink3)} .lx-empty b{display:block;font-size:17px;color:var(--ink);margin-bottom:6px} .lx-skel{height:120px;border-radius:16px;background:linear-gradient(90deg,#1d2a25 0%,#24332d 50%,#1d2a25 100%);background-size:200% 100%;animation:lxsk 1.2s infinite;margin-bottom:12px} @keyframes lxsk{0%{background-position:200% 0}100%{background-position:-200% 0}} /* ── القارئ ── */ .lx-reader{display:flex;flex-direction:column;height:100%;background:var(--bg)} .lx-rtop{position:relative;display:flex;align-items:center;gap:10px;padding:9px 22px;border-bottom:1px solid var(--line);background:var(--bg);flex-shrink:0;min-height:52px} .lx-rtop .crumb{font-size:13px;color:var(--mute);overflow:hidden;text-overflow:ellipsis;white-space:nowrap;flex:1} .lx-rtop .crumb a{color:var(--ink2);cursor:pointer} .lx-rtop .crumb a:hover{color:var(--brand-d)} .lx-rtop .mini{flex:1;display:flex;align-items:center;gap:10px;overflow:hidden;animation:lxin .2s ease-out} .lx-rtop .mini b{font-family:'Noto Kufi Arabic',sans-serif;font-size:15px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis} .lx-rtop .mini span{font-size:12.5px;color:var(--brand-d);white-space:nowrap;overflow:hidden;text-overflow:ellipsis} .lx-prog{position:absolute;bottom:-1px;right:0;height:2px;background:var(--brand);transition:width .12s linear} .lx-ibtn{border:0;background:transparent;box-shadow:0 0 0 1px var(--line);font:inherit;font-size:12.5px;color:var(--ink2);padding:6px 11px;border-radius:9px;cursor:pointer;display:inline-flex;align-items:center;gap:6px;white-space:nowrap;text-decoration:none;background:var(--card)} .lx-ibtn:hover{box-shadow:0 0 0 1px var(--brand);color:var(--brand-d)} .lx-ibtn.on{background:var(--brand);color:#fff;box-shadow:none} .lx-ibtn.pri{background:var(--brand);color:#fff;box-shadow:none} .lx-ibtn.pri:hover{background:#e07a52;color:#fff} .lx-rscroll{flex:1;overflow:auto;min-height:0;scroll-behavior:auto} .lx-dhead{max-width:1240px;margin:0 auto;padding:24px 28px 0} .lx-dcard{background:var(--card);border-radius:18px;box-shadow:0 0 0 1px var(--line);padding:22px 26px} .lx-dtitle{font-family:'Noto Kufi Arabic',sans-serif;font-size:26px;font-weight:700;line-height:1.55;margin:10px 0 12px} .lx-facts{display:flex;flex-wrap:wrap;gap:8px 26px;font-size:13.5px;color:var(--ink2)} .lx-facts span{color:var(--mute);margin-left:6px;font-size:12.5px} .lx-facts b{font-weight:600;color:var(--ink)} .lx-strip{display:flex;gap:8px;flex-wrap:wrap;margin-top:16px;padding-top:14px;border-top:1px solid var(--line2)} .lx-strip button{border:0;font:inherit;font-size:12.5px;padding:6px 12px;border-radius:10px;cursor:pointer;display:inline-flex;align-items:center;gap:7px;background:var(--soft);color:var(--ink2);transition:all .15s} .lx-strip button b{font-size:14px;color:var(--ink)} .lx-strip button:hover{background:var(--brand-s);color:var(--brand-d)} .lx-upc{margin-top:14px;background:linear-gradient(90deg,#1d2a25,rgba(201,100,66,.10));border-radius:12px;padding:12px 16px;display:flex;align-items:center;gap:14px;box-shadow:0 0 0 1px rgba(201,100,66,.25)} .lx-upc .big{font-family:'Noto Kufi Arabic',sans-serif;font-size:26px;font-weight:700;color:var(--brand-d);line-height:1;text-align:center} .lx-upc .tx{font-size:13px;color:var(--ink2);line-height:1.7} .lx-tabs{display:flex;gap:4px;margin-top:16px;border-bottom:1px solid var(--line);align-items:flex-end;flex-wrap:wrap} .lx-tab{border:0;background:transparent;font:inherit;font-size:14px;padding:11px 16px;cursor:pointer;color:var(--ink3);border-bottom:2px solid transparent;margin-bottom:-1px;display:flex;align-items:center;gap:7px} .lx-root .lx-tab{flex:0 0 auto;min-width:auto;flex-direction:row;justify-content:flex-start;align-items:center;gap:7px;line-height:1.5;font-family:inherit} /* ↑ يحمي تبويبات القارئ من قاعدة .lx-tab العامة لشريط التنقل السفلي في lexa-theme.css */ .lx-tab:hover{color:var(--ink)} .lx-tab.on{color:var(--ink);border-bottom-color:var(--brand);font-weight:600} .lx-tab .n{font-size:11px;background:var(--soft);padding:1px 7px;border-radius:10px;color:var(--ink3)} .lx-dbody{max-width:1240px;margin:0 auto;padding:18px 28px 90px} .lx-textwrap{display:grid;grid-template-columns:272px 1fr;gap:24px} .lx-textwrap.focus{grid-template-columns:1fr;max-width:900px;margin:0 auto} .lx-textwrap.focus .lx-toc{display:none} .lx-toc{position:sticky;top:10px;align-self:start;max-height:calc(100vh - 150px);display:flex;flex-direction:column;background:var(--card);border-radius:14px;box-shadow:0 0 0 1px var(--line)} .lx-toc-h{padding:12px 12px 8px;display:flex;flex-direction:column;gap:8px;border-bottom:1px solid var(--line2)} .lx-toc-h .r{display:flex;align-items:center;gap:8px;font-size:13px;font-weight:700} .lx-toc-h input{flex:1;border:0;box-shadow:0 0 0 1px var(--line);border-radius:8px;padding:6px 9px;font:inherit;font-size:12.5px;background:var(--bg);min-width:0;color:var(--ink)} .lx-tfilt{display:flex;gap:4px;flex-wrap:wrap} .lx-tfilt button{border:0;font:inherit;font-size:11.5px;padding:3px 9px;border-radius:14px;cursor:pointer;background:var(--soft);color:var(--ink2);display:inline-flex;gap:5px;align-items:center} .lx-tfilt button.on{background:var(--brand);color:#fff} .lx-toc-l{overflow:auto;padding:6px 6px 10px} .lx-toc-i{display:flex;align-items:center;gap:7px;width:100%;border:0;background:transparent;font:inherit;text-align:right;padding:5px 9px;border-radius:7px;cursor:pointer;font-size:12.8px;color:var(--ink2);line-height:1.5} .lx-toc-i:hover{background:var(--soft)} .lx-toc-i.sec{font-weight:700;color:var(--ink);font-size:12.5px;margin-top:6px} .lx-toc-i.art{padding-inline-start:22px} .lx-toc-i.sub{padding-inline-start:34px;font-size:12px;color:var(--ink3)} .lx-art-b .lx-inhead{display:inline-block;font-family:'Noto Kufi Arabic',sans-serif;font-size:15px;font-weight:700;color:var(--brand-d);margin-top:14px} .lx-art-b .lx-longhead{font-weight:600} .lx-hcolon{display:none} .lx-art-b .lx-anchor{scroll-margin-top:90px} .lx-art-b .lx-anchor:target,.lx-art-b .lx-anchor.flash{background:rgba(245,182,66,.16)} .lx-toc-i.on{background:var(--brand-s);color:var(--brand-d)} .lx-toc-i .mk{width:7px;height:7px;border-radius:50%;flex-shrink:0;margin-inline-start:auto} .lx-toc-i .car{font-size:10px;color:var(--mute);width:12px;text-align:center} .lx-tools{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:14px;background:var(--card);border-radius:12px;box-shadow:0 0 0 1px var(--line),0 6px 16px rgba(0,0,0,.04);padding:7px 10px;position:sticky;top:8px;z-index:12} .lx-find{display:flex;align-items:center;gap:6px;flex:1;min-width:200px} .lx-find input{flex:1;border:0;background:var(--bg);border-radius:8px;padding:7px 10px;font:inherit;font-size:13px;min-width:0;outline:0;color:var(--ink)} .lx-find input:focus{box-shadow:0 0 0 1px var(--brand)} .lx-find .cnt{font-size:12px;color:var(--mute);white-space:nowrap} mark.lx-fm{background:rgba(212,154,30,.30);color:inherit} mark.lx-fm.cur{background:rgba(212,154,30,.6);color:#fff;box-shadow:0 0 0 2px #d49a1e} .lx-prefs{position:relative} .lx-prefs-pop{position:absolute;top:calc(100% + 8px);left:0;background:var(--card);border-radius:12px;box-shadow:0 0 0 1px var(--line),0 14px 34px rgba(0,0,0,.14);padding:12px;z-index:30;width:250px;display:flex;flex-direction:column;gap:10px;font-size:12.5px;color:var(--ink3)} .lx-resume{display:flex;align-items:center;gap:10px;flex-wrap:wrap;background:rgba(143,184,224,.08);border-radius:12px;padding:9px 14px;margin-bottom:12px;font-size:13px;color:#b9d3ee;box-shadow:0 0 0 1px rgba(143,184,224,.2)} .lx-resume button{margin-inline-start:auto} .lx-sheet{background:var(--sheet);border-radius:18px;box-shadow:0 0 0 1px var(--line),0 10px 30px rgba(0,0,0,.03);overflow:hidden;color:var(--sheet-ink)} .lx-sechd{font-family:'Noto Kufi Arabic',sans-serif;font-size:16px;font-weight:700;color:var(--brand-d);padding:26px 40px 12px;border-top:1px solid var(--sheet-line);scroll-margin-top:84px;display:flex;align-items:center;gap:12px} .lx-sechd:before{content:'';width:18px;height:2px;background:var(--brand);border-radius:2px;flex-shrink:0} .lx-sechd.l1{font-size:18px;padding-top:30px} .lx-sheet > :first-child{border-top:0} .lx-art{padding:20px 40px 22px;border-top:1px solid var(--sheet-line);scroll-margin-top:84px;transition:background .6s;position:relative} .lx-art:hover{background:rgba(201,100,66,.022)} .lx-art.flash{background:rgba(245,182,66,.16)} .lx-art-path{font-size:11.5px;color:var(--mute);margin-bottom:4px} .lx-art-h{display:flex;align-items:center;gap:8px;flex-wrap:wrap} .lx-art-h h3{font-size:16.5px;font-weight:700;margin:0;color:inherit} .lx-art.is-cancel .lx-art-h h3{color:#ff8f86;text-decoration:line-through;text-decoration-color:rgba(255,143,134,.5)} .lx-art-h .sp{flex:1} .lx-art-act{opacity:0;transition:opacity .15s;display:flex;gap:2px} .lx-art:hover .lx-art-act,.lx-art:focus-within .lx-art-act{opacity:1} @media(hover:none){.lx-art-act{opacity:1}} .lx-art-act button{border:0;background:transparent;cursor:pointer;font-size:12px;color:var(--ink3);padding:4px 8px;border-radius:6px;font-family:inherit} .lx-art-act button:hover{background:var(--soft);color:var(--ink)} .lx-art-act .lx-act-ai{color:#ffb08f;font-weight:600} .lx-art-act .lx-act-ai .lx-cost{font-weight:500;opacity:.75;font-size:11px} .lx-art-b{font-family:var(--read);font-size:var(--fs);line-height:var(--lh);margin-top:6px} .lx-art-b .art-line{margin:0 0 4px} .lx-art-b .sub-hd{font-family:'IBM Plex Sans Arabic',sans-serif;font-size:14px;font-weight:700;margin:10px 0 4px} .lx-art-b .src-quote{border-right:3px solid var(--line);margin:8px 0;padding:4px 14px;background:rgba(239,231,214,.025);border-radius:6px} .lx-art-b .doc-hd{font-family:'Noto Kufi Arabic',sans-serif;font-size:18px;margin:6px 0 10px} .lx-art-b del.canc{color:#ff8f86;text-decoration:line-through} .lx-art-b .md-hr{border:0;border-top:1px solid var(--line);margin:12px 0} .lx-root a.xref{color:#8fb8e0;text-decoration:none;border-bottom:1px dotted #8fb8e0;cursor:pointer} .lx-root[data-theme=night] a.xref{color:#8fb8e0;border-color:#8fb8e0} .lx-root a.xref:hover{background:rgba(143,184,224,.12)} .lx-root .tlink{border:0;background:rgba(143,184,224,.14);color:#9cc3e8;border-radius:6px;cursor:pointer;font-family:inherit;padding:2px 7px} .md-tbl{border-collapse:collapse;width:100%;margin:10px 0;font-family:'IBM Plex Sans Arabic',sans-serif;font-size:13.5px;line-height:1.7;display:block;overflow-x:auto} .md-tbl th,.md-tbl td{border:1px solid var(--line);padding:7px 10px;vertical-align:top} .md-tbl th{background:rgba(239,231,214,.04);font-weight:600} .lx-cancel-note{font-family:'IBM Plex Sans Arabic',sans-serif;font-size:13px;color:#ffb4ab;background:rgba(194,65,65,.12);box-shadow:inset 3px 0 0 #c24141;border-radius:8px;padding:7px 12px;margin-top:8px} .lx-achips{display:flex;gap:6px;flex-wrap:wrap} .lx-achip{border:0;font:inherit;font-size:11.5px;font-weight:600;padding:4px 10px;border-radius:20px;cursor:pointer;display:inline-flex;align-items:center;gap:5px;transition:all .15s} .lx-achip.amend{background:rgba(224,122,82,.16);color:#ffb08f} .lx-achip.add{background:rgba(45,155,98,.16);color:#8fd9b0} .lx-achip.cancel{background:rgba(194,65,65,.18);color:#ff9d94} .lx-achip.rename{background:rgba(143,184,224,.14);color:#9cc3e8} .lx-achip.note{background:rgba(239,231,214,.08);color:var(--ink2)} .lx-achip:hover{filter:brightness(1.15)} .lx-achip.open{box-shadow:0 0 0 1.5px currentColor} .lx-achip .ar{font-size:9px;transition:transform .2s} .lx-achip.open .ar{transform:rotate(180deg)} .lx-apanel{--ac:#e07a52;margin-top:12px;border-radius:14px;background:linear-gradient(180deg,rgba(224,122,82,.07),rgba(224,122,82,.025)),#131c19;box-shadow:0 0 0 1px rgba(224,122,82,.26),0 8px 24px rgba(0,0,0,.25);overflow:hidden;animation:lxin .18s ease-out;color:var(--ink);border-inline-start:3px solid var(--ac);font-family:'IBM Plex Sans Arabic',sans-serif} .lx-apanel.add{--ac:#3fbf7f;background:linear-gradient(180deg,rgba(45,155,98,.08),rgba(45,155,98,.025)),#131c19;box-shadow:0 0 0 1px rgba(45,155,98,.26),0 8px 24px rgba(0,0,0,.25)} .lx-apanel.cancel{--ac:#e05a5a;background:linear-gradient(180deg,rgba(194,65,65,.09),rgba(194,65,65,.03)),#131c19;box-shadow:0 0 0 1px rgba(194,65,65,.28),0 8px 24px rgba(0,0,0,.25)} .lx-apanel.rename,.lx-apanel.note{--ac:#8fb8e0;background:linear-gradient(180deg,rgba(143,184,224,.07),rgba(143,184,224,.02)),#131c19;box-shadow:0 0 0 1px rgba(143,184,224,.22),0 8px 24px rgba(0,0,0,.25)} .lx-ap-h .k{display:inline-flex;align-items:center;gap:6px;color:var(--ac);background:color-mix(in srgb,var(--ac) 16%,transparent);padding:3px 10px;border-radius:20px;font-size:12.5px} .lx-ap-cite{display:inline-flex;align-items:center;gap:6px;flex-wrap:wrap;color:var(--ink);font-weight:600;font-size:13px;line-height:1.6} .lx-ap-cite .ic{opacity:.75} .lx-ap-cite .dt{color:var(--ink2);font-weight:500} .lx-ap-h a{display:inline-flex;align-items:center;gap:4px;padding:4px 10px;border-radius:8px;background:rgba(239,231,214,.06)} .lx-ap-h a:hover{background:rgba(224,122,82,.16)} .lx-ap-cmp{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,300px),1fr));gap:10px} .lx-ap-box{border-radius:11px;padding:10px 14px 12px;min-width:0} .lx-ap-box .lb{display:flex;align-items:center;gap:6px;font-family:'IBM Plex Sans Arabic',sans-serif;font-size:12px;font-weight:700;margin-bottom:6px;letter-spacing:0} .lx-ap-box .lb i{width:8px;height:8px;border-radius:50%;display:inline-block} .lx-ap-box.bef{background:rgba(194,65,65,.09);box-shadow:inset 0 0 0 1px rgba(194,65,65,.22)} .lx-ap-box.bef .lb{color:#ff9d94}.lx-ap-box.bef .lb i{background:#e05a5a} .lx-ap-box.bef .lx-ap-txt{color:#d9cfc0} .lx-ap-box.aft{background:rgba(45,155,98,.09);box-shadow:inset 0 0 0 1px rgba(45,155,98,.24)} .lx-ap-box.aft .lb{color:#8fd9b0}.lx-ap-box.aft .lb i{background:#3fbf7f} .lx-ap-box.aft .lx-ap-txt{color:var(--ink)} .lx-ap-box.dif{background:rgba(239,231,214,.03);box-shadow:inset 0 0 0 1px var(--line)} .lx-ap-box.dif .lb{color:var(--ink2)} @keyframes lxin{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}} .lx-ap-h{display:flex;align-items:center;gap:8px 10px;flex-wrap:wrap;padding:11px 14px;border-bottom:1px solid rgba(239,231,214,.07);font-size:13px;background:rgba(0,0,0,.12)} .lx-ap-h .k{font-weight:700} .lx-ap-h .sp{flex:1} .lx-ap-h a{color:var(--brand-d);font-size:12.5px;text-decoration:none;font-weight:600} .lx-ap-h a:hover{text-decoration:underline} .lx-ap-b{padding:12px 16px 14px} .lx-ap-txt{font-family:var(--read);font-size:15.5px;line-height:2;color:var(--ink);white-space:pre-wrap;overflow-wrap:anywhere} .lx-ap-note{font-size:13.5px;line-height:1.9;color:var(--ink2)} .lx-ap-note b{color:var(--ink)} .lx-diff .d{background:rgba(194,65,65,.24);color:#ffb4ab;text-decoration:line-through;text-decoration-color:rgba(255,180,171,.6);border-radius:3px;padding:0 2px} .lx-diff .i{background:rgba(45,155,98,.24);color:#b5ecc9;border-radius:3px;padding:0 2px} .lx-ap-leg{display:flex;gap:14px;font-size:11.5px;color:var(--mute);margin-bottom:8px} .lx-ap-leg span{display:inline-flex;align-items:center;gap:5px} .lx-ap-leg i{width:12px;height:8px;border-radius:2px;display:inline-block} .lx-ap-src{margin-top:10px;font-size:12px;color:var(--mute)} .lx-ap-src summary{cursor:pointer} .lx-ap-src div{margin-top:6px;font-size:12.5px;line-height:1.8;color:var(--ink2);background:rgba(0,0,0,.15);border-radius:8px;padding:8px 12px} .lx-state{background:rgba(143,184,224,.07);border-radius:12px;box-shadow:0 0 0 1px rgba(143,184,224,.2);margin-bottom:14px} .lx-state summary{padding:11px 16px;cursor:pointer;font-size:13px;font-weight:600;color:#b9d3ee} .lx-state .in{padding:4px 18px 14px;font-size:13px;line-height:1.9;color:var(--ink2)} .lx-state .in p{margin:0 0 8px} .lx-pop{position:fixed;z-index:60;width:440px;max-width:92vw;max-height:340px;overflow:auto;background:var(--card);border-radius:14px;box-shadow:0 0 0 1px var(--line),0 20px 50px rgba(0,0,0,.2);padding:14px 18px;animation:lxin .14s ease-out} .lx-pop .h{font-size:12.5px;font-weight:700;color:var(--brand-d);margin-bottom:6px;display:flex;gap:8px;align-items:center} .lx-pop .h a{margin-inline-start:auto;font-weight:600;cursor:pointer;color:#8fb8e0} .lx-pop .b{font-family:var(--read);font-size:15px;line-height:1.95;color:#efe7d6} .lx-pop .b .art-line{margin:0 0 3px} .lx-pal-bg{position:fixed;inset:0;background:rgba(5,9,8,.6);z-index:80;display:flex;justify-content:center;align-items:flex-start;padding-top:12vh;animation:lxin .12s} .lx-pal{width:560px;max-width:92vw;background:var(--card);border-radius:16px;box-shadow:0 24px 60px rgba(0,0,0,.3);overflow:hidden} .lx-pal input{width:100%;border:0;outline:0;font:inherit;font-size:16px;padding:16px 18px;border-bottom:1px solid var(--line2);background:transparent;color:var(--ink)} .lx-pal input:focus-visible{box-shadow:inset 0 -2px 0 var(--brand)} .lx-pal-l{max-height:50vh;overflow:auto;padding:6px} .lx-pal-i{display:flex;align-items:center;gap:10px;padding:9px 12px;border-radius:9px;cursor:pointer;font-size:14px} .lx-pal-i.on,.lx-pal-i:hover{background:var(--brand-s)} .lx-pal-i small{color:var(--mute);font-size:12px;margin-inline-start:auto;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:45%} .lx-pal-f{padding:8px 14px;font-size:11.5px;color:var(--mute);border-top:1px solid var(--line2);display:flex;gap:12px} .lx-info{display:grid;grid-template-columns:1fr 1fr;gap:16px} @media(max-width:900px){.lx-info{grid-template-columns:1fr}} .lx-kv{display:grid;grid-template-columns:150px 1fr;border-top:1px solid var(--line2)} .lx-kv:first-of-type{border-top:0} .lx-kv span{padding:11px 18px;font-size:13px;color:var(--mute);background:rgba(239,231,214,.03)} .lx-kv div{padding:11px 18px;font-size:14px;line-height:1.8} .lx-kv a{color:var(--brand-d)} .lx-famtools{display:flex;gap:10px;align-items:center;flex-wrap:wrap;margin-bottom:16px} .lx-famtools input{flex:1;min-width:min(220px,100%);max-width:380px;border:0;box-shadow:0 0 0 1px var(--line);border-radius:10px;padding:9px 12px;font:inherit;font-size:13.5px;background:var(--card);color:var(--ink)} .lx-famgrid{display:grid;grid-template-columns:repeat(auto-fill,minmax(min(100%,440px),1fr));gap:16px;align-items:start} @media(max-width:560px){.lx-famgrid{grid-template-columns:1fr}} .lx-fam-b{background:var(--card);border-radius:16px;box-shadow:0 0 0 1px var(--line);padding:6px 0 8px} .lx-fam-b h3{font-size:15px;font-weight:700;margin:0;padding:12px 16px 8px;display:flex;align-items:center;gap:8px} .lx-fam-b h3 small{font-weight:400;color:var(--mute);font-size:12px} .lx-fam-b h3 .n{margin-inline-start:auto;font-size:12px;background:var(--soft);padding:1px 9px;border-radius:10px;color:var(--ink3)} .lx-fam-i{display:flex;align-items:center;gap:10px;padding:9px 16px;cursor:pointer;border-top:1px solid var(--line2);transition:background .12s} .lx-fam-i:hover{background:var(--soft)} .lx-fam-i.cur{background:var(--brand-s)} .lx-fam-i .t{flex:1;font-size:13.5px;font-weight:500;line-height:1.6} .lx-fam-i .d{font-size:11.5px;color:var(--mute);white-space:nowrap} .lx-fam-n{padding-right:26px;background:rgba(239,231,214,.025)} .lx-fam-n .lx-fam-i{border-top:1px dashed var(--line2);padding:7px 16px} .lx-fam-more{display:block;width:100%;border:0;background:transparent;font:inherit;font-size:12.5px;color:var(--brand-d);padding:9px;cursor:pointer;border-top:1px solid var(--line2)} .lx-tl{position:relative;padding-right:26px;max-width:820px} .lx-tl:before{content:'';position:absolute;right:8px;top:6px;bottom:6px;width:2px;background:var(--line)} .lx-tl-y{font-family:'Noto Kufi Arabic',sans-serif;font-size:14px;font-weight:700;color:var(--ink3);margin:18px -26px 8px 0;padding-right:0} .lx-tl-i{position:relative;margin-bottom:12px;background:var(--card);border-radius:12px;box-shadow:0 0 0 1px var(--line);padding:12px 16px;cursor:pointer} .lx-tl-i:hover{box-shadow:0 0 0 1px var(--brand)} .lx-tl-i:before{content:'';position:absolute;right:-24px;top:16px;width:12px;height:12px;border-radius:50%;background:var(--card);box-shadow:0 0 0 2px var(--brand)} .lx-tl-i.origin:before{background:var(--brand)} .lx-tl-i.fam:before{box-shadow:0 0 0 2px #9a988f} .lx-tl-i .d{font-size:12.5px;font-weight:700;color:var(--brand-d)} .lx-tl-i.fam .d{color:var(--ink3)} .lx-tl-i .t{font-size:14px;margin-top:3px;line-height:1.6} .lx-tl-i .o{font-size:12px;color:var(--mute);margin-top:3px} .lx-warn{font-size:12.5px;color:#e8c27a;background:rgba(212,154,30,.10);box-shadow:0 0 0 1px rgba(212,154,30,.22);border-radius:10px;padding:9px 14px;margin:8px 0 14px;line-height:1.8} .lx-en{background:var(--card);border-radius:18px;box-shadow:0 0 0 1px var(--line);padding:26px 40px;font-family:Georgia,serif;font-size:15.5px;line-height:1.85;color:#efe7d6} .lx-en h4{font-family:'IBM Plex Sans Arabic',sans-serif;font-size:15px;margin:22px 0 6px} .lx-en p{margin:0 0 8px} .lx-en .lx-en-mk{display:inline-block;font-family:'IBM Plex Sans Arabic',sans-serif;font-size:12px;line-height:1.5;color:#d9b36c;border:1px solid rgba(217,179,108,.4);border-radius:8px;padding:2px 9px;margin:0 0 8px} .lx-en .lx-en-mk.doc{display:block;color:#b9b2a3;border-color:var(--line)} .lx-soonbox{max-width:760px;margin:40px auto;text-align:center} .lx-chip.on{box-shadow:0 0 0 1px var(--brand);color:#fff;background:var(--brand)} .lx-lib-hero{text-align:center;padding:14px 0 6px} .lx-lib-hero h1{font-size:30px;margin:6px 0 6px} .lx-lib-hero p{color:var(--ink3);margin:0 auto;max-width:720px;font-size:14px;line-height:1.8} .lx-lib-chips{justify-content:center;margin:12px 0 4px} .lx-lib-chips small{opacity:.7;font-size:11px} .lx-lib-topic{background:rgba(45,155,98,.14);color:#8fd9b0} .lx-lib-card{cursor:pointer;transition:box-shadow .15s} .lx-lib-card:hover{box-shadow:0 0 0 1px var(--brand),0 4px 14px rgba(0,0,0,.06)} .lx-lib-sec{font-family:'IBM Plex Sans Arabic',sans-serif;font-size:18px;color:var(--brand-d);margin:26px 0 10px;padding-bottom:6px;border-bottom:1px solid var(--line)} .lx-lib-search{display:flex;gap:8px;max-width:720px;margin:18px auto 12px;background:#16211d;border-radius:14px;box-shadow:0 0 0 1.5px rgba(224,122,82,.3),0 4px 14px rgba(0,0,0,.05);padding:6px} .lx-lib-search input{flex:1;border:0;outline:0;font:inherit;font-size:15px;padding:10px 12px;background:transparent;min-width:0;color:var(--ink)} .lx-lib-search:focus-within{box-shadow:0 0 0 2px var(--brand)} .lx-lib-search button{border:0;border-radius:10px;background:var(--brand);color:#fff;font:inherit;font-weight:700;padding:0 22px;cursor:pointer} .lx-lib-filters{display:flex;gap:8px;justify-content:center;flex-wrap:wrap;margin-top:10px} .lx-lib-kind{background:rgba(224,122,82,.14);color:#ffb08f} .lx-lib-doc{background:#16211d;border-radius:16px;box-shadow:0 0 0 1px var(--line);padding:28px 32px;margin:16px 0 40px} .lx-lib-title{font-size:24px;line-height:1.5;margin:10px 0 6px} .lx-lib-body{margin-top:18px;font-family:'Noto Naskh Arabic','IBM Plex Sans Arabic',serif;font-size:17px;line-height:2;color:var(--ink)} .lx-lib-p{margin:0 0 14px;white-space:pre-wrap} .lx-lib-h{font-family:'IBM Plex Sans Arabic',sans-serif;margin:24px 0 10px;color:var(--ink)} .lx-lib-h.l1{font-size:21px}.lx-lib-h.l2{font-size:19px}.lx-lib-h.l3,.lx-lib-h.l4{font-size:17px} .lx-lib-tbl{white-space:pre-wrap;font-size:13px;background:rgba(239,231,214,.04);border-radius:8px;padding:10px;overflow:auto} @media (max-width:767px){.lx-lib-doc{padding:18px 16px}.lx-lib-title{font-size:20px}.lx-lib-body{font-size:16px}} .lx-soonbox .ic{font-size:44px} .lx-soonbox h2{font-family:'Noto Kufi Arabic',sans-serif;font-size:24px;margin:14px 0 10px} .lx-soonbox p{color:var(--ink3);line-height:1.9;font-size:15px} .lx-feat{display:grid;grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:12px;margin-top:26px;text-align:right} .lx-feat div{background:var(--card);border-radius:14px;box-shadow:0 0 0 1px var(--line);padding:16px} .lx-feat b{display:block;margin-bottom:6px;font-size:14px} .lx-feat span{font-size:13px;color:var(--ink3);line-height:1.8} .lx-err{max-width:640px;margin:60px auto;background:rgba(194,65,65,.10);border-radius:14px;padding:20px 24px;box-shadow:0 0 0 1px rgba(194,65,65,.3);color:#ffb4ab;line-height:1.9} @media(max-width:980px){ .lx-rbody{grid-template-columns:1fr;padding:16px}.lx-filters{position:static!important;max-height:none;display:none}.lx-filters.show{display:block} .lx-ftoggle{display:inline-flex}.lx-rhead{padding:10px 14px}.lx-page{padding:18px 16px 40px} .lx-dhead,.lx-dbody{padding-left:14px;padding-right:14px}.lx-hero h1{font-size:26px} .lx-textwrap{grid-template-columns:minmax(0,1fr)}.lx-textwrap>div{min-width:0}.lx-toc{display:none}.lx-art,.lx-sechd{padding-left:20px;padding-right:20px} .lx-famgrid{grid-template-columns:1fr}.lx-dtitle{font-size:21px} } /* ── الجوال: قارئ النظام ── */ .lx-toc-btn{display:none} .lx-toc-x,.lx-toc-scrim{display:none} @media(max-width:980px){ .lx-toc-btn{display:inline-flex} .lx-toc.open{display:flex;position:fixed;inset:auto 0 0 0;max-height:78vh;max-height:78dvh;z-index:95;border-radius:18px 18px 0 0;box-shadow:0 -18px 50px rgba(0,0,0,.5),0 0 0 1px var(--line);padding-bottom:env(safe-area-inset-bottom);animation:lxup .2s ease-out} .lx-toc.open .lx-toc-x{display:inline-flex;margin-inline-start:auto;border:0;background:var(--soft);color:var(--ink2);width:34px;height:34px;border-radius:10px;align-items:center;justify-content:center;font-size:16px;cursor:pointer} .lx-toc.open .lx-toc-i{padding:9px 10px;font-size:14px} .lx-toc.open .lx-tfilt button{padding:6px 12px;font-size:13px} .lx-toc-scrim.open{display:block;position:fixed;inset:0;background:rgba(5,9,8,.6);z-index:94} } @keyframes lxup{from{transform:translateY(30px);opacity:0}to{transform:none;opacity:1}} @media(max-width:767px){ .lx-rtop{padding:8px 10px;gap:6px;min-height:48px} .lx-rtop .crumb{white-space:normal;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;line-height:1.45;font-size:12.5px;min-width:0} .lx-rtop .crumb .lx-cr-p{display:none} .lx-rtop .crumb .lx-cr-t{color:var(--ink)!important;font-weight:600} .lx-rtop .lx-print{display:none} .lx-rtop .lx-ibtn{padding:6px 9px} .lx-rtop .lx-back{padding:7px 6px} .lx-rtop .mini span{display:none} .lx-tabs{flex-wrap:nowrap;overflow-x:auto;scrollbar-width:none;gap:0;margin-top:12px} .lx-tabs::-webkit-scrollbar{display:none} .lx-root .lx-tab{padding:10px 11px;font-size:13.5px;white-space:nowrap;flex-shrink:0} .lx-tabs .lx-seg{width:auto!important;flex-shrink:0;margin:0 6px 6px 0!important} .lx-tools{top:0;padding:6px 8px;gap:6px;border-radius:10px;flex-wrap:nowrap} .lx-find{min-width:0} .lx-tools .lx-kbd,.lx-sfield .lx-kbd{display:none} .lx-tools .lx-go-lbl{display:none} .lx-tools .lx-openall{display:none} .lx-dcard{padding:16px} .lx-dhead{padding-top:14px} .lx-dbody{padding-top:12px} .lx-art,.lx-sechd{padding-left:16px;padding-right:16px} .lx-art{scroll-margin-top:70px} .lx-art-h{gap:6px} .lx-art-act{width:100%;order:9;flex-wrap:wrap;gap:4px;margin-top:4px} .lx-art-act button{background:rgba(239,231,214,.05);padding:6px 10px;font-size:12.5px} .lx-art-h .sp{display:none} .lx-ap-h{padding:10px 12px} .lx-ap-b{padding:10px 12px 12px} .lx-ap-txt{font-size:15px} .lx-seg button{padding:7px 6px} .lx-facts{gap:6px 16px} .lx-kv{grid-template-columns:110px 1fr} .lx-kv span,.lx-kv div{padding:9px 12px} .lx-en{padding:18px 16px} .lx-hero-dark{border-radius:18px;padding:22px 14px 18px!important} .lx-hero h1{font-size:22px;line-height:1.5} .lx-hero p{font-size:14px;margin-bottom:18px} .lx-sfield{padding:4px 4px 4px 10px;border-radius:13px} .lx-sbtn{padding:10px 14px;font-size:14px} .lx-sfield input,.lx-sfield.sm input,.lx-find input,.lx-toc-h input,.lx-year input,.lx-select,.lx-best-acts input,.lx-famtools input,.lx-lib-search input,.lx-country-in,.lx-pal input{font-size:16px} .lx-card{padding:14px 14px 14px 16px} .lx-card-t{font-size:16px} .lx-best{padding:16px} .lx-best h3{font-size:18px} .lx-best-acts input{width:100%} .lx-direct{padding:16px} .lx-rhead{gap:8px} .lx-rmeta > div:last-child{flex-wrap:wrap} .lx-ai-cta{flex-wrap:wrap} .lx-ai-cta .go{margin-inline-start:0} .lx-ai-b{padding:10px 12px 12px} .lx-ai-h{flex-wrap:wrap;padding:10px 12px;gap:8px} .lx-ai-h .lx-ai-tag{display:none} .lx-rhead .lx-back{padding:7px 4px} .lx-rhead .lx-sfield{padding-inline-start:12px} .lx-country-pop{position:fixed;inset-inline:12px;width:auto;max-width:none;top:auto} .lx-pop{left:12px!important;right:12px;width:auto} .lx-strip button{padding:7px 11px} } @media(hover:none){.lx-prefs-pop{box-shadow:0 0 0 1px var(--line),0 14px 34px rgba(0,0,0,.5)}} .lx-root .lx-main,.lx-root .lx-card,.lx-root .lx-art-b,.lx-root .lx-ai-b,.lx-root .lx-sem-i{overflow-wrap:anywhere} @media(prefers-reduced-motion:reduce){.lx-root *{animation:none!important;transition:none!important}} /* au1: الطباعةُ تُخرجُ نصَّ الوثيقة وحدَه، بخلفيّةٍ بيضاء وحبرٍ أسود — بلا قائمةِ المنصّة ولا شريطِها، وبلا قصٍّ لارتفاعِ الحاويات */ @media print{@page{margin:14mm}html,body{background:#fff!important;height:auto!important;overflow:visible!important}body *{visibility:hidden!important}.lx-reader,.lx-reader *{visibility:visible!important}.lx-reader{position:absolute!important;top:0;left:0;right:0;height:auto!important;overflow:visible!important;background:#fff!important}.lx-reader *{overflow:visible!important;max-height:none!important}.lx-toc,.lx-tools,.lx-rtop,.lx-tabs,.lx-art-act,.lx-achips,.lx-strip,.lx-resume,.lx-toast{display:none!important}.lx-textwrap{display:block!important}.lx-sheet{max-width:none!important;box-shadow:none!important}.lx-rscroll{overflow:visible!important}.lx-reader [class*=lx-d],.lx-reader .lx-sheet,.lx-reader .lx-art,.lx-reader .lx-apanel{background:#fff!important;box-shadow:none!important}.lx-reader,.lx-reader *{color:#111!important}.lx-reader .lx-apanel{border:1px solid #bbb!important}.lx-art{break-inside:avoid-page}} `; /* ========================================================= مكونات صغيرة ========================================================= */ function LxKind({ kind }) { const c = LX_KIND_COLORS[kind] || LX_KIND_COLORS['قرار']; return {kind}; } function LxStatus({ status }) { const c = LX_STATUS[status]; if (!c) return status ? {status} : null; return {c.label}; } function LxSearchBar({ initial, onSearch, onOpenDoc, small, autoFocus, hotkey }) { const [v, setV] = React.useState(initial || ''); const [items, setItems] = React.useState([]); const [open, setOpen] = React.useState(false); const [hi, setHi] = React.useState(-1); const tRef = React.useRef(null); const inRef = React.useRef(null); React.useEffect(() => { setV(initial || ''); }, [initial]); React.useEffect(() => { if (!hotkey) return; const h = (e) => { if (e.key === '/' && !/INPUT|TEXTAREA/.test((document.activeElement || {}).tagName || '')) { e.preventDefault(); inRef.current && inRef.current.focus(); } }; window.addEventListener('keydown', h); return () => window.removeEventListener('keydown', h); }, [hotkey]); const art = lxParseArticleQuery(v); React.useEffect(() => { clearTimeout(tRef.current); const q = (art ? art.law : v).trim(); if (q.length < 2) { setItems([]); return; } tRef.current = setTimeout(() => { lxGet('/api/laws/suggest?' + lxQs({ q })).then(r => { setItems(r.items || []); setHi(-1); }).catch(() => {}); }, 170); return () => clearTimeout(tRef.current); }, [v]); const submit = () => { setOpen(false); if (v.trim()) onSearch(v.trim()); }; const pick = (it) => { setOpen(false); art ? onOpenDoc(it.did, 0, art.an) : onOpenDoc(it.did); }; const onKey = (e) => { if (e.key === 'ArrowDown') { e.preventDefault(); setOpen(true); setHi(h => Math.min(items.length - 1, h + 1)); } else if (e.key === 'ArrowUp') { e.preventDefault(); setHi(h => Math.max(-1, h - 1)); } else if (e.key === 'Enter') { e.preventDefault(); if (open && hi >= 0 && items[hi]) pick(items[hi]); else submit(); } else if (e.key === 'Escape') setOpen(false); }; return (
setTimeout(() => setOpen(false), 160)}>
{ setV(e.target.value); setOpen(true); }} onFocus={() => setOpen(true)} onKeyDown={onKey} /> {!small && hotkey && !v && /}
{open && items.length > 0 && (
{items.map((it, i) => (
pick(it)}> {art ? المادة {lxNum(art.an)} من : null} {it.status !== 'ساري' && } {it.date}
))}
ابحث عن «{v}» في العناوين ونصوص المواد ←Enter
)}
); } function LxSections({ section, onSection }) { const S = [ ['laws', 'الأنظمة واللوائح', null], ['treaties', 'المعاهدات والاتفاقيات الدولية', null], ['cases', 'السوابق القضائية', null], // الكتبُ والشروحُ والمقالاتُ ليست قسماً عامّاً (تحتاجُ مراجعةً وتوثيقاً) — يستأنسُ بها المساعدُ ويذكرُ مؤلّفَها وناشرَها (books2) ]; return (
{S.map(([id, label, soon]) => ( ))}
); } /* ========================================================= الصفحة الرئيسية للبحث ========================================================= */ // تاريخُ النفاذ (ميلاديّ YYYY-MM-DD): صريحٌ من الجدول، أو رصدُ أم القرى + الأيّامُ المتبقّية function lxEffDate(u) { if (!u) return ''; if (u.effective) return String(u.effective).slice(0, 10); const g = ((u.observed || {}).greg || '').slice(0, 10); if (!g || u.days_left_at_observation == null) return ''; const d = new Date(g + 'T00:00:00Z'); if (isNaN(d)) return ''; d.setUTCDate(d.getUTCDate() + Number(u.days_left_at_observation || 0)); return d.toISOString().slice(0, 10); } function LxUpcoming({ items, onOpen }) { if (!items || !items.length) return null; const rows = items.map(u => ({ ...u, left: lxDaysLeft(u) })).filter(u => u.left == null || u.left >= 0); if (!rows.length) return null; const obsDate = (items[0].observed || {}).hijri; return (
⏳ صدرت ولم يبدأ نفاذها {obsDate ? بحسب رصد جريدة أم القرى في {obsDate}هـ : null}
{rows.slice(0, 6).map(u => (
onOpen(u.did)}>
{u.left == null ? '—' : lxNum(u.left)}{u.left == null ? 'يوماً' : lxCountWord(u.left, 'يوم', 'يومان', 'أيام', 'يوماً')}
{u.title}
نُشر في {String(u.published_hijri || '').replace(/-/g, '/')}هـ
))}
); } function LxHome({ meta, metaErr, onSearch, onOpenDoc, onBrowse }) { const recent = lxLoad('lx-recent', []); if (metaErr) return
تعذر تحميل قاعدة الأنظمة.
{metaErr}
; const c = (meta && meta.counts) || {}; return (

الأنظمة واللوائح السعودية

النصوص النافذة بعد تطبيق تعديلاتها، ومعها سجل كل تعديل ونصه السابق ومصدره الرسمي

{LX_POPULAR.map(p => )}
{meta && (
{lxNum(c.cards - ((((meta.sectors || []).find(s => s.name === LX_TREATY_SECTOR)) || {}).cards || 0))} نظاماً ولائحة رئيسية {lxNum(c.docs - (((meta.sectors || []).find(s => s.name === LX_TREATY_SECTOR) || {}).docs || 0))} وثيقة مصنفة {lxNum(c.units)} مادة قابلة للبحث
)}
{recent.length > 0 && (
تابع القراءة {recent.map(r => ( ))}
)} {!meta ?
: ( <>

تصفح حسب المجال

{lxCount(meta.sectors.filter(s => s.cards && s.name !== LX_TREATY_SECTOR).length, 'مجال رئيسي', 'مجالان رئيسيان', 'مجالات رئيسية', 'مجالاً رئيسياً')}
{meta.sectors.filter(s => s.cards && s.name !== LX_TREATY_SECTOR).sort((a, b) => (a.name === 'غير مصنّف') - (b.name === 'غير مصنّف') || b.cards - a.cards).map(s => { // المعاهدات: كروتُها حاوياتٌ (20) تضمُّ ~1,300 وثيقة — العدُّ والفتحُ على الوثائقِ نفسِها const treaty = s.name === LX_TREATY_SECTOR; return ( ); })}

المستجدات

✏️ آخر الأنظمة المعدلة بتاريخ آخر أداة تعديل على النظام نفسه
{(meta.recently_amended || []).map(r => (
onOpenDoc(r.did, 0, 0, 'timeline')}>
{r.title}
آخر تعديل {r.last_amend} · {lxNum(r.n_amend_instr)} أداة تعديل
))}
)}
); } /* ========================================================= المكتبة: السوابق القضائية + الكتب والشروحات والمقالات (/api/library) ========================================================= */ const LX_LIB_CFG = { cases: { title: 'السوابق القضائية', ic: '⚖️', sub: 'أحكام المحكمة التجارية والمحكمة العليا المنشورة من وزارة العدل — مصنفة حسب موضوع الدعوى ونتيجتها', unit: 'حكماً', ph: 'ابحث في نصوص الأحكام… مثل: فسخ عقد توريد، شيك بدون رصيد', }, books: { title: 'الكتب والشروحات والمقالات', ic: '📚', sub: 'شروح الأنظمة الرسمية، والكتب القانونية المتخصصة، ومقالات مجلة العدل — مصنفة حسب المجال', unit: 'مصدراً', ph: 'ابحث في الكتب والشروح والمقالات…', }, }; const LX_OUTCOME_COLOR = { 'إلزام': ['rgba(45,155,98,.16)', '#8fd9b0'], 'تأييد الحكم': ['rgba(45,155,98,.16)', '#8fd9b0'], 'رفض الدعوى': ['rgba(194,65,65,.18)', '#ff9d94'], 'نقض الحكم': ['rgba(194,65,65,.18)', '#ff9d94'], 'عدم قبول': ['rgba(212,154,30,.16)', '#e8c27a'], 'عدم اختصاص': ['rgba(212,154,30,.16)', '#e8c27a'], 'صرف النظر': ['rgba(239,231,214,.08)', '#c9c2b3'], }; function LxOutcome({ v }) { if (!v) return null; const [bg, fg] = LX_OUTCOME_COLOR[v] || ['rgba(239,231,214,.08)', '#c9c2b3']; return {v}; } // أقسامُ الحكم القضائي تُعرَض عناوين: الوقائع · الأسباب · نص الحكم · منطوق الحكم · نص الاستئناف const LX_CASE_HEAD = /^\(?\s*(الوقائع|الأسباب|نص الحكم|منطوق الحكم|لذلك|الحكم|المرافعة|نص الاستئناف|أسباب الاستئناف|المدعي|المدعى عليه)\s*\)?\s*:?\s*$/; function lxLibParas(text, isCase) { const out = []; let buf = []; const flush = (k) => { if (buf.length) { out.push(

{buf.join('\n').replace(/\*\*/g, '')}

); buf = []; } }; String(text || '').split('\n').forEach((line, i) => { const t = line.trim(); if (!t) { flush(i); return; } const m = t.replace(/^-+\s*|\s*-+$/g, '').trim(); if (isCase && LX_CASE_HEAD.test(m)) { flush(i); out.push(

{m.replace(/[():]/g, '').trim()}

); return; } const h = t.match(/^(#{1,4})\s+(.+)$/); if (h) { flush(i); out.push(

{h[2].replace(/\*\*/g, '')}

); return; } if (t.startsWith('|')) { flush(i); out.push(
{t}
); return; } buf.push(t); }); flush('end'); return out; } function LxLibReader({ id, onBack }) { const [d, setD] = React.useState(null); const [err, setErr] = React.useState(null); React.useEffect(() => { let alive = true; setD(null); setErr(null); lxGet('/api/library/item/' + encodeURIComponent(id)).then(r => alive && setD(r)).catch(e => alive && setErr(e.message)); return () => { alive = false; }; }, [id]); const isCase = d && d.kind === 'precedent'; return (
{err &&
{err}
} {!d && !err &&
} {d && (
{d.kind_label} {d.topic && d.topic !== 'أخرى' && d.topic !== 'عام' && {d.topic}} {isCase && d.stage === 'مستأنف' && مستأنف}

{d.title}

{d.subtitle &&
{d.subtitle}
} {d.url && /^https?:/.test(d.url) && ( )}
{lxLibParas(d.text, isCase)}
)}
); } function LxLibFacetChips({ items, value, onPick, allLabel, max = 14 }) { if (!items || !items.length) return null; const total = items.reduce((a, x) => a + x.n, 0); return (
{items.slice(0, max).map(x => ( ))}
); } function LxLibSelect({ items, value, onPick, allLabel }) { if (!items || !items.length) return null; return ( ); } function LxLibrary({ section, route, go }) { const cfg = LX_LIB_CFG[section]; const FKEYS = ['q', 'kind', 'topic', 'court', 'stage', 'outcome', 'region', 'law', 'yf', 'yt']; const cur = {}; FKEYS.forEach(k => { if (route[k]) cur[k] = route[k]; }); const lgo = (patch) => go({ sec: section, ...patch }); const set = (patch) => lgo({ ...cur, ...patch, page: undefined }); const [meta, setMeta] = React.useState(null); const [data, setData] = React.useState(null); const [err, setErr] = React.useState(null); const [loading, setLoading] = React.useState(true); const [qIn, setQIn] = React.useState(route.q || ''); const page = +(route.page || 1); React.useEffect(() => { setQIn(route.q || ''); }, [route.q]); React.useEffect(() => { lxGet('/api/library/meta').then(setMeta).catch(() => {}); }, []); const qs = lxQs({ section, ...cur, page: page > 1 ? page : undefined }); React.useEffect(() => { if (route.item) return; let alive = true; setLoading(true); setErr(null); lxGet('/api/library/search?' + qs).then(r => { if (alive) { setData(r); setLoading(false); } }) .catch(e => { if (alive) { setErr(e.message); setLoading(false); } }); return () => { alive = false; }; }, [qs, route.item]); if (route.item) { const back = { ...route }; delete back.item; return go(back)} />; } const f = (data && data.facets) || {}; const pages = data ? Math.ceil(data.total / data.size) : 0; const pgBtns = []; if (pages > 1) { const from = Math.max(1, Math.min(page - 3, pages - 6)); for (let p = from; p <= Math.min(pages, from + 6); p++) pgBtns.push(p); } const counts = (meta && meta.counts) || {}; const totalSec = Object.entries(counts).filter(([k]) => k.startsWith(section + '/')).reduce((a, [, v]) => a + v, 0); const submit = (e) => { e && e.preventDefault(); set({ q: qIn.trim() || undefined }); }; const years = meta && meta.years && meta.years[0] ? Array.from({ length: meta.years[1] - meta.years[0] + 1 }, (_, i) => meta.years[1] - i) : []; const active = Object.keys(cur).filter(k => k !== 'q').length > 0; return (

{cfg.ic} {cfg.title}

{cfg.sub}{totalSec ? ' — ' + lxNum(totalSec) + ' ' + cfg.unit : ''}

setQIn(e.target.value)} placeholder={cfg.ph} aria-label="بحث" />
{section === 'books' && set({ kind: v, law: undefined })} />} set({ topic: v })} />
{section === 'cases' && <> set({ outcome: v })} /> set({ stage: v })} /> set({ court: v })} /> set({ region: v })} /> {years.length > 0 && ( )} } {section === 'books' && set({ law: v, kind: v ? 'sharh' : route.kind })} />} {active && }
{loading ? 'جارٍ البحث…' : data ? (route.q ? <>{lxNum(data.total)} نتيجة لـ «{route.q}» : <>{lxNum(data.total)} {cfg.unit}) : ''}
{err &&
{err}
} {loading && !data && [1, 2, 3].map(i =>
)} {data && !loading && data.hits.length === 0 && (
لا توجد نتائج مطابقةجرّب كلمات أقل أو ألغِ عوامل التصفية.
)}
{data && data.hits.map(h => (
lgo({ ...route, item: h.id })}>
{h.kind_label} {h.topic && h.topic !== 'أخرى' && h.topic !== 'عام' && section === 'books' && {h.topic}} {h.stage === 'مستأنف' && مستأنف} {h.law && {h.law}}

{h.title}

{h.subtitle &&
{h.subtitle}
} {h.snippet &&
}
))}
{pages > 1 && (
{pgBtns.map(p => )}
)}
); } function LxComingSoon({ section }) { const cfg = section === 'cases' ? { ic: '⚖️', t: 'السوابق القضائية', p: 'قسم للأحكام والمبادئ القضائية، مربوط بالمواد النظامية التي استندت إليها. يجري إعداده، وسيُطلق بعد اكتمال التحقق من مصادره الرسمية.', f: [['من المادة إلى الحكم', 'من كل مادة تنتقل إلى الأحكام التي طبقتها، ومن كل حكم إلى نصوصه.'], ['تصنيف دقيق', 'حسب المحكمة ونوع القضية وسنة الحكم والمبدأ المستخلص.'], ['بحث في الأسباب والمنطوق', 'بحث نصي في أسباب الحكم ومنطوقه.']], } : { ic: '📚', t: 'الكتب والشروحات والمقالات', p: 'مكتبة المصادر الثانوية: شروح الأنظمة والكتب المتخصصة والمقالات والدراسات، مربوطة بالمواد التي تتناولها.', f: [['الشرح بجانب المادة', 'تظهر الشروحات ذات الصلة عند قراءة كل مادة.'], ['مصادر موثقة', 'لكل شرح مؤلفه ومصدره وتاريخه.'], ['قراءات في الجديد', 'مقالات عن التعديلات فور صدورها.']], }; return (
{cfg.ic}

{cfg.t}

{cfg.p}

{cfg.f.map(([b, s]) =>
{b}{s}
)}
); } /* ========================================================= النتائج ========================================================= */ function LxFilters({ route, meta, facets, go, show }) { const set = (patch) => go({ ...route, ...patch, page: undefined }); const sectors = (meta && meta.sectors) || []; const sel = sectors.find(s => s.name === route.sector); const kinds = ['نظام', 'لائحة', 'قواعد وضوابط', 'قرار', 'تعديل', 'اتفاقية']; const fk = (facets && facets.kind) || {}; const fs = (facets && facets.status) || {}; const fsec = (facets && facets.sector) || {}; const [yf, setYf] = React.useState(route.yf || ''); const [yt, setYt] = React.useState(route.yt || ''); React.useEffect(() => { setYf(route.yf || ''); setYt(route.yt || ''); }, [route.yf, route.yt]); return ( ); } // إجابة مباشرة: «المادة 77 من نظام العمل» ← نص المادة نفسها من الكوربوس /* ── «فهمنا سؤالك»: النظامُ المكتشَف · الألفاظُ المضافة · بحثٌ تقريبيّ · هل تقصد · اسأل ليكسا ── */ function lxAskLexa(q) { try { localStorage.setItem('lexa-ask', q); } catch (_) {} location.href = location.pathname + '?screen=assistant'; } /* ── الذكاء الاصطناعيّ في البحث ────────────────────────────────────────── LxAiSummary «خلاصة ليكسا» فوق النتائج: تبدأ تلقائيّاً إن كان البحثُ سؤالاً، وإلّا بزرّ (/ai/search-summary) LxSemantic «قريبة بالمعنى»: موادُّ تقاربُ معنى البحثِ ولو بلا كلمةٍ مشتركة (/api/laws/semantic) LxExplain «اشرحها ببساطة» تحت المادّة في القارئ (/ai/explain) */ const LX_QWORDS = ['هل', 'كيف', 'ما', 'ماذا', 'ماهي', 'ماهو', 'متى', 'متي', 'كم', 'لماذا', 'أين', 'اين', 'يحق', 'يجوز', 'يلزم', 'حقي', 'حقوقي', 'عقوبة', 'شروط', 'إجراءات', 'اجراءات', 'مدة', 'ايش', 'وش', 'عايز', 'عاوز', 'ابغى', 'ابي']; function lxLooksLikeQuestion(q) { q = String(q || '').trim(); if (!q) return false; if (/[؟?]$/.test(q)) return true; const w = q.split(/\s+/); return w.slice(0, 3).some(x => LX_QWORDS.includes(x)) || w.length >= 6; } function lxAiErr(e) { return e && e.status === 401 ? 'سجّل الدخول لتظهر لك خلاصة ليكسا' : ((e && e.message) || 'تعذّر الآن'); } // au1: الخلاصةُ تخصمُ نقاطاً — تُحفَظُ لكلِّ عبارةٍ في الجلسة فلا يُعادُ خصمُها عند الرجوع للنتائج أو تقليبِ الصفحات const lxSumCache = new Map(); function lxSumInit(q) { const c = lxSumCache.get(q); // الخلاصةُ بضغطةٍ فقط (تستهلكُ نقاطاً) — لا تشغيلَ تلقائيّ return c ? { phase: 'done', text: c, err: '' } : { phase: 'idle', text: '', err: '' }; } function LxAiSummary({ q }) { const [st, setSt] = React.useState(() => lxSumInit(q)); const [open, setOpen] = React.useState(true); React.useEffect(() => { setSt(lxSumInit(q)); setOpen(true); }, [q]); React.useEffect(() => { if (st.phase !== 'run' || !window.api || !window.api.ai) return; const ac = new AbortController(); let acc = ''; window.api.ai.searchSummary(q, (ev) => { if (ev.type === 'delta') { acc += ev.text; setSt(s => ({ ...s, text: acc })); } else if (ev.type === 'done') { if (ev.text) { lxSumCache.set(q, ev.text); if (lxSumCache.size > 30) lxSumCache.delete(lxSumCache.keys().next().value); } setSt({ phase: ev.text ? 'done' : 'empty', text: ev.text, err: '' }); } else if (ev.type === 'error') setSt({ phase: 'err', text: '', err: ev.text }); }, ac.signal).catch(e => { if (e.name !== 'AbortError') setSt({ phase: 'err', text: '', err: lxAiErr(e) }); }); return () => ac.abort(); }, [st.phase === 'run', q]); if (st.phase === 'empty') return null; if (st.phase === 'idle') return ( ); const Answer = typeof LexaAnswer === 'function' ? LexaAnswer : null; return (
✨خلاصة ليكسا {st.phase === 'run' ? 'تكتب الآن من نصوص الأنظمة…' : 'من نصوص الأنظمة · مع الإحالات'} {st.phase === 'done' && }
{open && (
{st.phase === 'err' &&
{st.err}
} {st.phase === 'run' && !st.text &&
أقرأ أقرب الموادّ إلى بحثك…
} {st.text && (Answer ? :
{st.text}
)}
)}
); } function LxSemantic({ q, exclude, onOpenDoc, prominent }) { const [st, setSt] = React.useState(null); React.useEffect(() => { let alive = true; setSt(null); lxGet('/api/laws/semantic?' + lxQs({ q, k: prominent ? 8 : 5, exclude: (exclude || []).join(',') })) .then(r => { if (alive) setSt(r); }).catch(() => { if (alive) setSt({ hits: [] }); }); return () => { alive = false; }; }, [q, (exclude || []).join(',')]); if (!st || !(st.hits || []).length) return null; return (
🧠 قريبة بالمعنىموادّ تتناول ما تبحث عنه ولو بألفاظ مختلفة
{st.hits.map(h => ( ))}
); } function LxExplain({ did, ord, onClose }) { const [st, setSt] = React.useState({ phase: 'run', text: '', err: '' }); React.useEffect(() => { if (!window.api || !window.api.ai) return; const ac = new AbortController(); let acc = ''; window.api.ai.explain(did, ord, (ev) => { if (ev.type === 'delta') { acc += ev.text; setSt({ phase: 'run', text: acc, err: '' }); } else if (ev.type === 'done') setSt({ phase: 'done', text: ev.text, err: '', free: !!ev.free, cost: ev.cost }); else if (ev.type === 'error') setSt({ phase: 'err', text: '', err: ev.text }); }, ac.signal).catch(e => { if (e.name !== 'AbortError') setSt({ phase: 'err', text: '', err: lxAiErr(e) }); }); return () => ac.abort(); }, [did, ord]); const Answer = typeof LexaAnswer === 'function' ? LexaAnswer : null; return (
✨ببساطة{st.phase === 'run' ? 'تكتب الآن…' : st.phase === 'done' && /⟦sharh:/.test(st.text) ? '📘 مستندٌ إلى الشرح الرسمي' + (st.free ? ' — فتحتَه من قبل، بلا نقاط' : '') : st.phase === 'done' && st.free ? 'شرحٌ فتحتَه من قبل — بلا نقاط' : 'شرحٌ مبسّط لنصّ المادة'}
{st.phase === 'err' &&
{st.err}
} {st.phase === 'run' && !st.text &&
أقرأ المادة…
} {st.text && (Answer ? :
{st.text}
)}
); } function LxUnderstood({ data, q, go, onOpenDoc, direct, route }) { const u = data.understood || {}; const laws = u.laws || []; const jump = !direct && data.jump; return (
{jump && (
onOpenDoc(jump.did, jump.ord, jump.an)}>
📍 {jump.heading.replace(/[::]\s*$/, '')} — {jump.title}
{jump.snippet}
افتح المادة ←
)}
{laws.length > 0 && ( 🧭 فهمنا أنّ سؤالك في: {laws.map(l => )} )} {(u.expand || []).length > 0 && ( 🔁 بحثنا أيضاً عن: {u.expand.slice(0, 6).join(' · ')} )} {u.relaxed && النتائج لا تحوي كلَّ كلماتك — رتّبناها بالأقرب} {data.suggestion && ( 💡 هل تقصد: ؟ )}
); } function LxDirectArticle({ query, onOpenDoc }) { const pq = lxParseArticleQuery(query); const [st, setSt] = React.useState({ loading: true }); React.useEffect(() => { if (!pq) return; let alive = true; setSt({ loading: true }); (async () => { const s = await lxGet('/api/laws/suggest?' + lxQs({ q: pq.law })); const cands = (s.items || []).slice(0, 4); for (const c of cands) { const doc = await lxGetDoc(c.did); if (!doc.text) continue; const b = lxFindArt(lxRenderDoc(doc, 'current'), pq.an); if (b) { if (alive) setSt({ doc, b, others: cands.filter(x => x.did !== c.did) }); return; } } if (alive) setSt({ none: true, cands }); })().catch(() => alive && setSt({ none: true, cands: [] })); return () => { alive = false; }; }, [query]); if (!pq) return null; if (st.loading) return
; if (st.none) return (
بحث عن مادة
لم نجد المادة ({lxNum(pq.an)}) في «{pq.law}» بين الوثائق الأقرب لهذا الاسم. النتائج أدناه من البحث النصي.
); const { doc, b } = st; const kinds = [...lxBlockKinds(b)]; return (
إجابة مباشرة

{b.text}

من {doc.title}{doc.num ? ' — ' + (doc.instrument || '') + ' رقم ' + doc.num : ''} {kinds.map(k => {LX_NOTE_META[k].label})}
— لا نص —' }} />
{kinds.includes('amend') && } {st.others && st.others.length > 0 && ليس هذا المقصود؟ {st.others.slice(0, 2).map(o => onOpenDoc(o.did, 0, pq.an)}>{o.title})}}
); } // أفضل تطابق: عنوان النتيجة الأولى يطابق البحث ← بطاقة بارزة واختصارات function LxBestMatch({ h, onOpenDoc }) { const [art, setArt] = React.useState(''); const goArt = () => { const k = window.LexaRender && window.LexaRender.xrKey(art); if (k) onOpenDoc(h.did, 0, k); }; return (
أفضل تطابق
{h.sector && {h.sector}}

onOpenDoc(h.did)}>{h.title}

{h.instrument && {h.instrument}{h.num ? ' رقم ' + h.num : ''}} {h.date_fmt && بتاريخ {h.date_fmt}} {h.n_art > 0 && {lxNum(h.n_art)} مادة} {h.last_amend && آخر تعديل {h.last_amend}}
{h.n_family > 0 && } {h.n_amend_instr > 0 && } {h.n_art > 0 && <> setArt(e.target.value)} onKeyDown={e => e.key === 'Enter' && goArt()} /> }
); } function LxResultCard({ h, onOpen }) { const [more, setMore] = React.useState(false); const sn = h.snippets || []; const kc = (LX_KIND_COLORS[h.kind] || {}).fg; return (
{h.upcoming && لم يبدأ نفاذه} {h.sector && {h.sector}{h.sub ? ' › ' + h.sub : ''}}

onOpen(h.did)} dangerouslySetInnerHTML={{ __html: h.title_html || lxEsc(h.title) }} />
{h.instrument && {h.instrument}{h.num ? ' رقم ' + h.num : ''}} {!h.instrument && h.num && رقم {h.num}} {h.date_fmt && بتاريخ {h.date_fmt}} {!h.date_fmt && h.pub_hijri && نُشر في أم القرى {lxPub(h.pub_hijri)}}
{!h.is_card && h.parent_title && ( )} {(h.n_art > 0 || h.n_amend_instr > 0 || h.n_family > 0) && (
{h.n_art > 0 && {lxNum(h.n_art)} مادة} {h.n_amended > 0 && {lxNum(h.n_amended)} مادة معدلة} {h.n_amend_instr > 0 && {lxNum(h.n_amend_instr)} أداة تعديل{h.last_amend ? ' · آخرها ' + h.last_amend : ''}} {h.n_family > 0 && {lxNum(h.n_family)} وثيقة مرتبطة}
)} {sn.length > 0 && (
{(more ? sn : sn.slice(0, 2)).map((s, i) => (
onOpen(h.did, s.ord)}>
{s.path ? — {s.path} : null}
))} {(sn.length > 2 || h.n_unit_hits > sn.length) && ( (sn.length > 2 && !more) ? setMore(true) : onOpen(h.did, sn[0].ord)}> {sn.length > 2 && !more ? 'عرض مطابقات أخرى' : 'تطابق في ' + lxNum(h.n_unit_hits) + ' موضعاً — افتح الوثيقة'} )}
)}
); } function lxNormTitle(s) { return String(s || '').replace(/[\u064B-\u065F\u0640]/g, '').replace(/[أإآ]/g, 'ا').replace(/ة/g, 'ه').replace(/ى/g, 'ي').replace(/\s+/g, ' ').trim(); } function LxResults({ route, meta, go, onOpenDoc, domain = 'laws', top = null }) { const [data, setData] = React.useState(null); const [err, setErr] = React.useState(null); const [loading, setLoading] = React.useState(true); const [showF, setShowF] = React.useState(false); const scRef = React.useRef(null); const page = +(route.page || 1); const qs = lxQs({ q: route.q, exact: route.exact ? 'true' : undefined, where: route.where, sector: route.sector, sub: route.sub, kind: route.kind, status: route.status, year_from: route.yf, year_to: route.yt, scope: route.scope, amended: route.amended ? 'true' : undefined, sort: route.sort, page: page > 1 ? page : undefined, domain, country: route.country, }); React.useEffect(() => { let alive = true; setLoading(true); setErr(null); lxGet('/api/laws/search?' + qs).then(r => { if (alive) { setData(r); setLoading(false); } }) .catch(e => { if (alive) { setErr(e.message); setLoading(false); } }); if (scRef.current) scRef.current.scrollTop = 0; return () => { alive = false; }; }, [qs]); const pages = data ? Math.ceil(data.total / data.size) : 0; const act = []; if (route.sector) act.push(['sector', route.sector + (route.sub ? ' › ' + route.sub : '')]); if (route.kind) act.push(['kind', route.kind]); if (route.status) act.push(['status', LX_STATUS[route.status] ? LX_STATUS[route.status].label : route.status]); if (route.yf || route.yt) act.push(['yf', 'السنة ' + (route.yf || '…') + '–' + (route.yt || '…')]); if (route.amended) act.push(['amended', 'عليه تعديلات']); const drop = (k) => { const n = { ...route, page: undefined }; delete n[k]; if (k === 'sector') delete n.sub; if (k === 'yf') delete n.yt; go(n); }; const pgBtns = []; if (pages > 1) { const from = Math.max(1, Math.min(page - 3, pages - 6)), to = Math.min(pages, from + 6); for (let p = from; p <= to; p++) pgBtns.push(p); } const direct = route.q && page === 1 && lxParseArticleQuery(route.q); let best = null; if (route.q && page === 1 && !direct && data && data.hits[0] && (!route.sort || route.sort === 'relevance')) { const nt = lxNormTitle(data.hits[0].title), nq = lxNormTitle(route.q); if (nt === nq || nt === 'نظام ' + nq || nt.replace(/\s*لعام.*$/, '') === nq) best = data.hits[0]; } const hits = data ? data.hits.filter(h => h !== best) : []; return (
{top}
{!top && }
go({ q })} onOpenDoc={onOpenDoc} hotkey />
{loading ? 'جارٍ البحث…' : data ? ( route.q ? <>{lxNum(data.total)} نتيجة لـ «{route.q}» : <>{lxNum(data.total)} {route.scope === 'all' ? 'وثيقة' : 'نظاماً ولائحة رئيسية'}{route.sector ? ' في ' + route.sector : ''} ) : ''}
{route.q && data && }
{act.length > 0 &&
{act.map(([k, l]) => )}
} {data && route.q && } {data && route.q && !direct && page <= 1 && } {direct && } {err &&
{err}
} {loading && !data && [1, 2, 3, 4].map(i =>
)} {data && !loading && data.hits.length === 0 && (
لا توجد نتائج مطابقةجرّب كلمات أقل، أو ألغِ بعض عوامل التصفية، أو ابحث في «نص المواد».
)} {data && !loading && route.q && !direct && data.hits.length === 0 && }
{best && } {hits.map(h => )}
{data && !loading && route.q && !direct && page <= 1 && hits.length > 0 && h.did)} onOpenDoc={onOpenDoc} />} {pages > 1 && (
{pgBtns.map(p => )}
)}
); } /* ========================================================= قارئ الوثيقة ========================================================= */ function LxAmendPanel({ note }) { const p = note.pop || {}; const hasBefore = !!(p.before && !p.circular && note.kind !== 'add'); const [mode, setMode] = React.useState('cmp'); const diff = React.useMemo(() => (hasBefore && p.after && mode === 'diff') ? lxWordDiff(p.before, p.after) : null, [mode]); const kindLbl = { amend: 'تعديل', add: 'مادة مضافة', cancel: 'إلغاء', rename: 'إحلال مسمى', note: note.label || 'ملاحظة' }[note.kind]; const kindIc = (LX_NOTE_META[note.kind] || {}).ic; const afterTxt = String(p.after || '').replace(/\*\*/g, ''); const befLbl = note.kind === 'cancel' ? 'النص قبل الإلغاء' : 'قبل التعديل'; return (
{kindIc && }{kindLbl} {(p.decree || p.date) && ( {p.decree ? 'بموجب ' + p.decree : ''}{p.date && {p.decree ? ' — ' : ''}وتاريخ {p.date}} )} {note.href && مستند التعديل ↗}
{hasBefore ? ( <> {p.after && (
)} {mode === 'diff' && diff && (
حُذفأُضيف
{diff.map((x, i) => x.t === '=' ? x.s : {x.s})}
)} {mode === 'diff' && !diff &&
النصان طويلان جداً للمقارنة كلمة بكلمة؛ اعرض «قبل / بعد».
} {(mode === 'cmp' || !p.after) && (
{befLbl}
{p.before}
{p.after &&
بعد التعديل (النص النافذ)
{afterTxt}
}
)}
نص الحاشية كما ورد في المصدر
) : (
)}
); } function LxNoteChip({ note, open, onClick }) { const p = note.pop || {}; const m = LX_NOTE_META[note.kind]; const base = note.kind === 'note' ? (note.label || m.label) : m.label; // اختصار للشارة فقط؛ الصيغة الكاملة في اللوحة عند الفتح const dec = (p.decree || '').replace(/^(?:ال)?مرسوم\s*(?:ال)?ملكي\s*(?:رقم\s*)?/, '').replace(/^قرار\s*مجلس\s*الوزراء\s*(?:رقم\s*)?/, 'قرار مجلس الوزراء ') .replace(/^\((.*)\)$/, '$1').replace(/\s*\/\s*/g, '/'); return ( ); } const LxArticle = React.memo(function LxArticle({ b, path, openAll, onCopy, flash, onSharh }) { const [open, setOpen] = React.useState({}); const [explain, setExplain] = React.useState(null); // did الوثيقة حين يُطلبُ الشرحُ المبسّط React.useEffect(() => { if (openAll === null) return; const o = {}; b.notes.forEach((_, i) => { o[i] = openAll; }); setOpen(o); }, [openAll]); const toggle = (i) => setOpen(o => ({ ...o, [i]: !o[i] })); const secHd = b.type === 'sec' &&
; if (b.type === 'sec' && !b.parts.length && !b.notes.length) return secHd; if (b.type === 'sec') { // قسم تحته نص مباشر (تمهيد الباب أو حاشية عليه): يُعرض النص بعد رأس القسم ولا يُسقط return ( <> {secHd}
{b.notes.length > 0 &&
{b.notes.map((n, i) => toggle(i)} />)}
} {b.parts.length > 0 &&
} {b.notes.map((n, i) => open[i] ? : null)}
); } // عنوان هو في الحقيقة فقرة كاملة: يُعرض نصاً في المتن const body = (b.longHead ? '
' + b.headHtml + '
' : '') + b.parts.join(''); const chips = b.notes.length > 0 && (
{b.notes.map((n, i) => toggle(i)} />)}
); return (
{path &&
{path}
}
{b.type === 'pre' ?

{b.text}

: b.longHead ? null :

} {chips} {b.type !== 'pre' && (
{onSharh && }
)}

{body &&
} {b.cancelNotice &&
أُلغيت هذه المادة — اضغط شارة «ملغاة» لعرض نصها قبل الإلغاء.
} {b.notes.map((n, i) => open[i] ? : null)} {explain && setExplain(null)} />}
); }); function lxStateHtml(md) { // ملاحظات الإفصاح على مستوى الوثيقة: أسطر «> …» تُعرض كما هي (غامق فقط) return String(md || '').split('\n').map(l => l.replace(/^\s*>\s?/, '').trim()).filter(Boolean) .map(l => '

' + (window.LexaRender ? window.LexaRender.mdInline(l) : lxEsc(l)) + '

').join(''); } // نافذة «اذهب إلى المادة» — Ctrl+K function LxJumpPalette({ toc, onJump, onClose }) { const [q, setQ] = React.useState(''); const [hi, setHi] = React.useState(0); const k = q.trim() && window.LexaRender ? window.LexaRender.xrKey(q.trim()) : 0; const items = React.useMemo(() => { const t = q.trim(); if (!t) return toc.filter(x => !x.sec).slice(0, 40); const byNum = k ? toc.filter(x => x.an === String(k)) : []; const byText = toc.filter(x => x.text.includes(t) && !byNum.includes(x)); return byNum.concat(byText).slice(0, 40); }, [q]); React.useEffect(() => setHi(0), [q]); const go = (it) => { if (it) { onJump(it); onClose(); } }; return (
e.stopPropagation()}> setQ(e.target.value)} onKeyDown={e => { if (e.key === 'ArrowDown') { e.preventDefault(); setHi(h => Math.min(items.length - 1, h + 1)); } else if (e.key === 'ArrowUp') { e.preventDefault(); setHi(h => Math.max(0, h - 1)); } else if (e.key === 'Enter') go(items[hi]); else if (e.key === 'Escape') onClose(); }} />
{items.length === 0 &&
لا توجد مادة مطابقة.
} {items.map((it, i) => (
setHi(i)} onClick={() => go(it)}> {it.sec ? {it.text} : {it.text}} {it.mk && } {it.path && {it.path}}
))}
↑↓ تنقلEnter انتقالEsc إغلاق
); } function LxDocText({ doc, target, onTargetDone, viewMode, prefs, onActive, onOpenDoc, onlyReq, onCounts, sharhArts }) { const sharhSet = React.useMemo(() => new Set(sharhArts || []), [sharhArts]); const [openAll, setOpenAll] = React.useState(null); const [tocOpen, setTocOpen] = React.useState(false); const [tocQ, setTocQ] = React.useState(''); const [only, setOnly] = React.useState('all'); const [findQ, setFindQ] = React.useState(''); const [findN, setFindN] = React.useState(0); const [findI, setFindI] = React.useState(0); const [activeOrd, setActiveOrd] = React.useState(0); const [collapsed, setCollapsed] = React.useState({}); const [flashOrd, setFlashOrd] = React.useState(0); const [pal, setPal] = React.useState(false); const [pop, setPop] = React.useState(null); const [resume, setResume] = React.useState(null); const contentRef = React.useRef(null); // دفتري: يُعادُ تلوينُ ما ظلّله المستخدمُ في هذه الوثيقة React.useEffect(() => { const t = setTimeout(() => { if (window.LexaNote && contentRef.current) window.LexaNote.paintRef(contentRef.current, 'law:' + doc.did); }, 350); return () => clearTimeout(t); }, [doc && doc.did, viewMode, only]); const popT = React.useRef(null); const blocks = React.useMemo(() => window.LexaRender ? lxRenderDoc(doc, viewMode) : null, [doc.did, viewMode]); // المسار (الباب › الفصل) لكل مادة، وشجرة المحتويات const { paths, toc, counts } = React.useMemo(() => { const paths = {}; const toc = []; let secs = []; const counts = { amend: 0, cancel: 0, add: 0 }; // رتبة القسم بمعناه لا بعدد علامات «#» — وترتيب الأنواع من الوثيقة نفسها: النوع الذي يظهر أولاً // هو الأعلى. أغلب الأنظمة «باب ← فصل»، وبعض اللوائح «فصل ← باب» (الفصل الثالث يحوي الباب الأول)، // وافتراض ترتيب ثابت كان يسقط الفصل من مسار كل مادة تحت أبوابه. const SEC_KIND = /^\s*\(?\s*(الكتاب|الباب|الفصل|الفرع|القسم|الجزء|المبحث|المطلب)/; const kindOrder = []; (blocks || []).forEach(b => { if (b.type === 'sec') { const m = b.text.match(SEC_KIND); if (m && !kindOrder.includes(m[1])) kindOrder.push(m[1]); } }); const rank = (b) => { const m = b.text.match(SEC_KIND); return m ? kindOrder.indexOf(m[1]) : kindOrder.length + b.lvl; }; let lastSec = null; (blocks || []).forEach(b => { if (b.type === 'sec') { const r = rank(b); secs = secs.filter(s => s.rank < r); secs.push({ rank: r, text: b.text }); lastSec = { key: 'o' + b.ord, ord: b.ord, text: b.text, sec: true, path: secs.slice(0, -1).map(s => s.text).join(' › ') }; toc.push(lastSec); } else { paths[b.ord] = secs.map(s => s.text).join(' › '); const ks = lxBlockKinds(b); ks.forEach(k => { if (counts[k] !== undefined) counts[k]++; }); toc.push({ key: 'o' + b.ord, ord: b.ord, text: b.tocText || b.text, sec: false, an: String(b.num || b.dataArt || ''), kinds: ks, path: paths[b.ord], mk: ks.has('cancel') ? '#c24141' : ks.has('add') ? '#2d9b62' : ks.has('amend') ? '#c96442' : null, parentSec: lastSec }); // فهرسة داخلية: عناوين سطرية داخل الكتل الضخمة (b.anchors || []).forEach(a => toc.push({ key: a.id, ord: b.ord, elId: a.id, text: a.label, sec: false, sub: true, an: a.num ? String(a.num) : '', kinds: new Set(), path: paths[b.ord], parentSec: lastSec })); } }); return { paths, toc, counts }; }, [blocks]); // qa1: رأسُ الوثيقة يعرضُ العدّاتِ نفسَها التي في المحتويات (المتنُ المعروض) — لا عدّاتِ علاماتِ العناوين في التصدير React.useEffect(() => { if (onCounts && blocks && viewMode === 'current') onCounts({ did: doc.did, ...counts }); }, [counts]); const shown = React.useMemo(() => { if (only === 'all') return blocks || []; const keep = new Set(toc.filter(t => !t.sec && t.kinds.has(only)).map(t => t.ord)); return (blocks || []).filter(b => keep.has(b.ord)); }, [blocks, only]); const scrollTo = (ord, flash, elId) => { const el = document.getElementById(elId || ('lx-o-' + ord)); if (!el) return false; el.scrollIntoView({ block: 'start' }); if (flash) { setFlashOrd(ord); setTimeout(() => setFlashOrd(0), 1800); } return true; }; // القفز ثم إعادة التثبيت بعد تحميل الخطوط: خط القراءة يتأخر فيطول المتن ويزيح المادة عن موضعها const anchorTo = (ord, elId) => { if (only !== 'all' && !shown.some(b => b.ord === ord)) setOnly('all'); setTimeout(() => { scrollTo(ord, true, elId); const again = () => scrollTo(ord, false, elId); if (document.fonts && document.fonts.ready) document.fonts.ready.then(() => setTimeout(again, 30)); setTimeout(again, 700); }, 60); }; const jumpItem = (t) => { setTocOpen(false); anchorTo(t.ord, t.elId); }; // شريط «N معدلة / ملغاة / مضافة» في رأس الوثيقة: يصفّي المتن على النوع المطلوب React.useEffect(() => { if (!onlyReq || !blocks) return; const k = onlyReq.k; setOnly(k && toc.some(t => !t.sec && t.kinds.has(k)) ? k : 'all'); setTimeout(() => { const el = contentRef.current && contentRef.current.closest('.lx-textwrap'); if (el) el.scrollIntoView({ block: 'start' }); }, 60); }, [onlyReq, blocks]); React.useEffect(() => { if (!tocOpen) return; const h = (e) => { if (e.key === 'Escape') setTocOpen(false); }; window.addEventListener('keydown', h); return () => window.removeEventListener('keydown', h); }, [tocOpen]); // القفز إلى المادة المطلوبة (من نتيجة بحث أو إحالة أو رابط) React.useEffect(() => { if (!target || !blocks) return; if (target.ord) anchorTo(target.ord); else if (target.an) { const hit = lxFindArt(blocks, target.an); // احتياط: مادة مفهرسة داخل كتلة بلا عناوين const sub = !hit && toc.find(t => t.elId && t.an === String(target.an)); if (hit) anchorTo(hit.ord); else if (sub) jumpItem(sub); else lxToast('لم توجد المادة (' + target.an + ') في هذه الوثيقة'); } onTargetDone && onTargetDone(); }, [target, blocks]); // «تابع من حيث توقفت» React.useEffect(() => { if (target) return; const pos = lxLoad('lx-pos', {})[doc.did]; if (pos && pos > 3) { const t = toc.find(x => x.ord === pos); if (t) setResume(t); } }, [doc.did]); // تتبع المادة الظاهرة + حفظ الموضع React.useEffect(() => { const root = contentRef.current; if (!root) return; const sc = root.closest('.lx-rscroll'); const io = new IntersectionObserver((ents) => { const vis = ents.filter(e => e.isIntersecting).map(e => +e.target.dataset.ord).sort((a, b) => a - b); if (vis.length) setActiveOrd(vis[0]); }, { root: sc, rootMargin: '-80px 0px -70% 0px' }); root.querySelectorAll('[data-ord]').forEach(el => io.observe(el)); return () => io.disconnect(); }, [shown]); React.useEffect(() => { if (!activeOrd) return; const t = toc.find(x => x.ord === activeOrd); onActive && onActive(t ? (t.sec ? t.text : t.text) : ''); const el = document.querySelector('.lx-toc-i[data-o="' + activeOrd + '"]'); if (el && el.scrollIntoViewIfNeeded) el.scrollIntoViewIfNeeded(false); const h = setTimeout(() => { const p = lxLoad('lx-pos', {}); p[doc.did] = activeOrd; lxSave('lx-pos', p); }, 800); return () => clearTimeout(h); }, [activeOrd]); // Ctrl+K React.useEffect(() => { const h = (e) => { if ((e.ctrlKey || e.metaKey) && (e.key === 'k' || e.key === 'K' || e.key === 'ك')) { e.preventDefault(); setPal(true); } }; window.addEventListener('keydown', h); return () => window.removeEventListener('keydown', h); }, []); // معاينة الإحالة عند المرور: نص المادة المحال إليها دون مغادرة الموضع const onOver = (e) => { const a = e.target.closest && e.target.closest('a.xref'); if (!a) return; const m = (a.getAttribute('onclick') || '').match(/xrefGo\(this,'([^']*)',(\d+)\)/); if (!m) return; clearTimeout(popT.current); const r = a.getBoundingClientRect(); const pos = { top: Math.min(window.innerHeight - 360, r.bottom + 8), left: Math.max(12, Math.min(window.innerWidth - 460, r.left + r.width / 2 - 220)) }; const tgt = m[1], an = +m[2]; popT.current = setTimeout(async () => { if (!tgt || tgt === doc.did) { const b = lxFindArt(blocks, an); if (b) setPop({ ...pos, title: b.text, law: '', html: b.parts.join(''), ord: b.ord }); return; } setPop({ ...pos, title: 'جارٍ التحميل…', html: '' }); try { const d2 = await lxGetDoc(tgt); const b = lxFindArt(lxRenderDoc(d2, 'current'), an); setPop(b ? { ...pos, title: b.text, law: d2.title, html: b.parts.join(''), tgt, an } : { ...pos, title: 'لم توجد المادة في ' + d2.title, html: '' }); } catch (err) { setPop(null); } }, 280); }; const onOut = (e) => { const a = e.target.closest && e.target.closest('a.xref'); if (!a) return; clearTimeout(popT.current); popT.current = setTimeout(() => setPop(null), 300); }; // البحث داخل الوثيقة: إبراز في DOM دون المساس بالنص React.useEffect(() => { const root = contentRef.current; if (!root) return; root.querySelectorAll('mark.lx-fm').forEach(m => { const t = document.createTextNode(m.textContent); m.replaceWith(t); }); root.normalize(); const q = findQ.trim(); if (q.length < 2) { setFindN(0); return; } const nq = q.replace(/[\u064B-\u065F\u0670\u0640]/g, '').replace(/[أإآٱ]/g, 'ا'); const pat = new RegExp(Array.from(nq).map(ch => (ch === 'ا' ? '[اأإآٱ]' : ch === 'ه' ? '[هة]' : ch === 'ي' ? '[يى]' : ch.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'))).join('[\u064B-\u065F\u0670\u0640]*'), 'g'); const walker = document.createTreeWalker(root, NodeFilter.SHOW_TEXT, null); const nodes = []; let n; while ((n = walker.nextNode())) { if (n.parentElement && !n.parentElement.closest('button,.lx-achips')) nodes.push(n); } let cnt = 0; nodes.forEach(node => { const s = node.textContent; pat.lastIndex = 0; if (!pat.test(s)) return; pat.lastIndex = 0; const frag = document.createDocumentFragment(); let last = 0, m; while ((m = pat.exec(s))) { frag.appendChild(document.createTextNode(s.slice(last, m.index))); const mk = document.createElement('mark'); mk.className = 'lx-fm'; mk.textContent = m[0]; frag.appendChild(mk); last = m.index + m[0].length; cnt++; } frag.appendChild(document.createTextNode(s.slice(last))); node.replaceWith(frag); }); setFindN(cnt); setFindI(0); }, [findQ, shown]); React.useEffect(() => { const root = contentRef.current; if (!root || !findN) return; const ms = root.querySelectorAll('mark.lx-fm'); ms.forEach(m => m.classList.remove('cur')); const m = ms[findI]; if (m) { m.classList.add('cur'); m.scrollIntoView({ block: 'center' }); } }, [findI, findN]); const onCopy = (b, what) => { if (what === 'link') { lxCopy(location.origin + location.pathname + '?' + lxQs({ screen: 'search', doc: doc.did, art: b.ord }), 'نُسخ رابط المادة'); } else { const body = (document.getElementById('lx-o-' + b.ord)?.querySelector('.lx-art-b')?.innerText || '').trim(); lxCopy(b.text + '\n' + body + '\n— ' + doc.title, 'نُسخ نص المادة'); } }; if (!window.LexaRender) return
تعذّر عرض نص الوثيقة الآن. أعد تحميل الصفحة بعد قليل.
; if (!doc.text) return
لا يتوفر نص لهذه الوثيقة في المصادر المتاحة لنابياناتها الوصفية وعلاقاتها متاحة في التبويبات الأخرى.
; const tq = tocQ.trim(); const tocShown = toc.filter(t => { if (only !== 'all') return !t.sec && t.kinds.has(only); if (tq) return t.text.includes(tq); if (!t.sec && t.parentSec && collapsed[t.parentSec.ord]) return false; return true; }); const hasSecs = toc.some(t => t.sec); return (
setTocOpen(false)} />
setFindQ(e.target.value)} onKeyDown={e => { if (e.key === 'Enter' && findN) setFindI(i => e.shiftKey ? (i - 1 + findN) % findN : (i + 1) % findN); }} /> {findQ.trim().length >= 2 && {findN ? lxNum(findI + 1) + ' من ' + lxNum(findN) : 'لا نتائج'}} {findN > 1 && <> }
{viewMode !== 'before' && counts.amend > 0 && ( )}
{resume && (
توقفت في المرة السابقة عند «{resume.text}»
)} {viewMode === 'before' && (
تعرض هذه النسخة النص قبل التعديلات، مُعاداً بناؤه من النصوص السابقة المقتبسة في حواشي التعديل. المادة التي لم يُنقل نصها السابق تظهر بنصها الحالي. للنص النافذ اختر «النص النافذ».
)} {only !== 'all' && (
تعرض المواد {LX_NOTE_META[only].label === 'معدلة' ? 'المعدلة' : LX_NOTE_META[only].label === 'ملغاة' ? 'الملغاة' : 'المضافة'} فقط ({lxNum(shown.length)}).
)}
{shown.map(b => window.lxOpenArticle({ kind: 'sharh', did: doc.did, an: +(b.dataArt || b.num) }) : null} />)}
{pal && setPal(false)} />} {pop && (
clearTimeout(popT.current)} onMouseLeave={() => setPop(null)}>
)}
); } function LxDocInfo({ doc }) { const urls = doc.urls || {}; const uqn = doc.uqn || []; const scope = doc.scope || {}; const srcName = { boe: 'هيئة الخبراء بمجلس الوزراء', ncar: 'المركز الوطني للوثائق والمحفوظات', uqn: 'جريدة أم القرى', moj: 'وزارة العدل' }; const rows = [ ['نوع الوثيقة', doc.kind], ['أداة الإصدار', doc.instrument], ['رقم الأداة', doc.num], ['تاريخ الإصدار', (doc.date_fmt || doc.date) ? (doc.date_fmt || doc.date) + (LX_DATE_SRC[doc.date_src] ? ' — ' + LX_DATE_SRC[doc.date_src] : '') : ''], ['النشر في أم القرى', doc.pub_hijri ? lxPub(doc.pub_hijri) + (doc.pub_greg ? ' (' + doc.pub_greg + 'م)' : '') : ''], ['الحالة', LX_STATUS[doc.status] ? LX_STATUS[doc.status].label : doc.status], ['آخر تعديل على الوثيقة', doc.last_amend ? doc.last_amend + (doc.n_amend_instr ? ' (' + lxNum(doc.n_amend_instr) + ' أداة تعديل)' : '') : ''], ['آخر تعديل في العائلة', doc.fam_last_amend && doc.fam_last_amend !== doc.last_amend ? doc.fam_last_amend + ' — على لائحة أو وثيقة تابعة' : ''], ['المجال', doc.sector ? doc.sector + (doc.sub ? ' › ' + doc.sub : '') : ''], ['عدد المواد', doc.n_art ? lxNum(doc.n_art) + (doc.n_amended ? ' — منها ' + lxNum(doc.n_amended) + ' معدلة' : '') + (doc.n_cancelled ? ' و' + lxNum(doc.n_cancelled) + ' ملغاة' : '') + (doc.n_added ? ' و' + lxNum(doc.n_added) + ' مضافة' : '') : ''], ].filter(r => r[1]); return (
{rows.map(([k, v]) =>
{k}
{v}
)} {uqn[0] &&
جريدة أم القرى
العدد {uqn[0]}{uqn[1] ? ' بتاريخ ' + uqn[1] : ''}{uqn[2] ? <> — عرض في الجريدة ↗ : null}
}
المصادر الرسمية
{Object.entries(urls).map(([k, u]) => )} {doc.pdf &&
الوثيقة الأصلية
} {!Object.keys(urls).length && !doc.pdf &&
—
لا توجد روابط مصدر مسجلة لهذه الوثيقة.
}
{(doc.nafad || Object.keys(scope).length > 0) && (
{doc.nafad &&
نص النفاذ
{doc.nafad}
} {Object.entries(scope).map(([k, v]) =>
{k}
{typeof v === 'string' ? v : JSON.stringify(v)}
)}
)}
); } function LxFamily({ doc, onOpen }) { const fam = doc.family; const [q, setQ] = React.useState(''); const [more, setMore] = React.useState({}); if (!fam) return
لا توجد وثائق مرتبطة مسجلة
; const nq = lxNormTitle(q); const match = (it) => !nq || lxNormTitle(it.title).includes(nq) || (it.nested || []).some(s => lxNormTitle(s.title).includes(nq)); const total = Object.values(fam.buckets || {}).reduce((a, b) => a + b.length, 0); return (
{!doc.is_card && doc.parent && (
هذه الوثيقة ضمن عائلة onOpen(doc.parent.did)}>{doc.parent.title} {doc.host_doc ? <> — وهي تعديل على «{doc.host_doc.title}» : null}
)} {total > 8 && (
setQ(e.target.value)} />
)}
{LX_BUCKETS.map(([k, label, desc]) => { const items = ((fam.buckets || {})[k] || []).filter(match); if (!items.length) return null; const sorted = items.slice().sort((a, b) => (b.hkey || 0) - (a.hkey || 0)); const lim = more[k] || nq ? sorted.length : 8; return (

{label} {desc}{lxNum(items.length)}

{sorted.slice(0, lim).map(it => (
onOpen(it.did)}> {it.title} {it.status !== 'ساري' && } {it.date || 'بلا تاريخ'}{!it.has_text ? ' · بلا نص' : ''}
{it.nested && it.nested.length > 0 && (
{it.nested.map(s => (
onOpen(s.did)}> ✎ {s.title} {s.date || 'بلا تاريخ'}
))}
)}
))} {sorted.length > lim && }
); })}
); } function LxTimeline({ doc, onOpen }) { const tl = doc.timeline || {}; const hasNested = [...(tl.dated || []), ...(tl.undated || [])].some(r => r.type === 'nested'); const [scope, setScope] = React.useState('own'); const keep = r => scope === 'all' || r.type !== 'nested'; const rows = (tl.dated || []).filter(keep), und = (tl.undated || []).filter(keep); const head = hasNested && (
); if (!rows.length && !und.length) return
{head}
لا توجد أدوات تعديل مسجلة على هذه الوثيقة
; let lastY = null; return (
{head}
{(tl.origin || {}).date || 'بلا تاريخ مسجل'}
الإصدار — {doc.title}
{(tl.origin || {}).instrument}{(tl.origin || {}).num ? ' رقم ' + tl.origin.num : ''}
{rows.map(r => { const y = Math.floor((r.hkey || 0) / 10000); const showY = y && y !== lastY; lastY = y; return ( {showY &&
{y}هـ
}
onOpen(r.did)}>
{r.date}{r.num ? ' · رقم ' + r.num : ''}
{r.title}
{r.on &&
على: {r.on}
}
); })}
{und.length > 0 && ( <>
{lxNum(und.length)} أداة بلا تاريخ مسجل — وُضعت في آخر القائمة ولم تُرتب في موضع تخميني.
{und.map(r => (
onOpen(r.did)}>
بلا تاريخ{r.num ? ' · رقم ' + r.num : ''}
{r.title}
{r.on &&
على: {r.on}
}
))}
)}
); } // النص الإنجليزي: عناوين وفقرات، دون تغيير في الكلمات function LxEnglish({ text }) { const html = String(text || '').split('\n').map(l => l.trim()).filter(Boolean).map(l => { const m = l.match(/^#{1,6}\s+(.*)$/); const k = l.match(/^_\[(.+)\]_$/); // en1: علامةُ مصدرِ المادة (ترجمة ليكسا / رسمية) أو تنويهُ الوثيقة if (k) return '
' + lxEsc(k[1]) + '
'; return m ? '

' + lxEsc(m[1]) + '

' : '

' + lxEsc(l).replace(/\*\*(.+?)\*\*/g, '$1') + '

'; }).join(''); return
; } function LxPrefs({ prefs, setPrefs }) { const [open, setOpen] = React.useState(false); const set = (p) => { const n = { ...prefs, ...p }; setPrefs(n); lxSave('lx-prefs', n); }; const boxRef = React.useRef(null); React.useEffect(() => { if (!open) return; const h = (e) => { if (boxRef.current && !boxRef.current.contains(e.target)) setOpen(false); }; const k = (e) => { if (e.key === 'Escape') setOpen(false); }; document.addEventListener('pointerdown', h); window.addEventListener('keydown', k); return () => { document.removeEventListener('pointerdown', h); window.removeEventListener('keydown', k); }; }, [open]); return (
{open && (
حجم الخط
{[[15, 'صغير'], [17, 'متوسط'], [19, 'كبير'], [21, 'أكبر']].map(([v, l]) => )}
لون الصفحة
{[['paper', 'الأساسي'], ['white', 'أفتح'], ['night', 'ليلي']] /* au1: الألوانُ الثلاثةُ داكنة — «فاتح/ورقي» كانا مضلِّلين */.map(([v, l]) => )}
)}
); } function LxDocReader({ route, go, onOpenDoc, onBack, prefs, setPrefs }) { const did = route.doc; const [doc, setDoc] = React.useState(null); const [err, setErr] = React.useState(null); const [tab, setTab] = React.useState(route.tab || 'text'); const [viewMode, setViewMode] = React.useState('current'); const [en, setEn] = React.useState(null); const [target, setTarget] = React.useState(route.art || route.an ? { ord: +route.art || 0, an: +route.an || 0 } : null); const [prog, setProg] = React.useState(0); const [compact, setCompact] = React.useState(false); const [activeLbl, setActiveLbl] = React.useState(''); const [liveN, setLiveN] = React.useState(null); // qa1: عدّاتُ المعدّلة/الملغاة/المضافة من المتن المعروض const [gd, setGd] = React.useState(null); // guides1: الشروحُ والأدلّةُ الرسميّة + الموادُّ التي لها شرحٌ رسميّ const scRef = React.useRef(null); React.useEffect(() => { let alive = true; setGd(null); lxGet('/api/laws/guides/' + encodeURIComponent(did)).then(r => alive && setGd(r)).catch(() => {}); return () => { alive = false; }; }, [did]); React.useEffect(() => { let alive = true; setDoc(null); setErr(null); setEn(null); setViewMode('current'); setCompact(false); setProg(0); lxGetDoc(did).then(d => { if (alive) { setDoc(d); lxRememberDoc(d); } }).catch(e => alive && setErr(e.message)); if (scRef.current) scRef.current.scrollTop = 0; return () => { alive = false; }; }, [did]); React.useEffect(() => { setTab(route.tab || 'text'); }, [did, route.tab]); React.useEffect(() => { if (route.art || route.an) { setTarget({ ord: +route.art || 0, an: +route.an || 0 }); setTab('text'); } }, [route.art, route.an, did]); // الإحالات داخل المتن (xrefGo في الشفرة المنسوخة) React.useEffect(() => { const h = (e) => { const { tgt, art } = e.detail || {}; if (!tgt || tgt === did) setTarget({ ord: 0, an: art }); else onOpenDoc(tgt, 0, art); }; window.addEventListener('lx:xref', h); return () => window.removeEventListener('lx:xref', h); }, [did]); const onScroll = (e) => { const el = e.currentTarget; const p = el.scrollHeight > el.clientHeight ? el.scrollTop / (el.scrollHeight - el.clientHeight) : 0; setProg(p); setCompact(el.scrollTop > 240); }; const toggleEn = () => { if (viewMode === 'en') { setViewMode('current'); return; } if (en) { setViewMode('en'); return; } lxGet('/api/laws/doc/' + encodeURIComponent(did) + '/en').then(r => { setEn(r.text); setViewMode('en'); setTab('text'); }).catch(() => lxToast('لا توجد ترجمة إنجليزية')); }; const setTabR = (t) => { setTab(t); go({ doc: did, tab: t === 'text' ? undefined : t }, true); }; const [onlyReq, setOnlyReq] = React.useState(null); const focusText = (only) => { if (viewMode !== 'current') setViewMode('current'); setTabR('text'); setOnlyReq({ k: only || 'all', n: Date.now() }); }; if (err) return
تعذر فتح الوثيقة.
{err}
; if (!doc) return
; const fam = doc.family; const famCount = fam ? Object.values(fam.buckets || {}).reduce((a, b) => a + b.length, 0) : 0; const tl = doc.timeline || {}; const tlCount = [...(tl.dated || []), ...(tl.undated || [])].filter(r => r.type !== 'nested').length; const upc = doc.upcoming; const upLeft = upc ? lxDaysLeft(upc) : null; const execN = fam && doc.is_card ? ((fam.buckets || {}).executive_regs || []).length : 0; const ln = liveN && liveN.did === doc.did ? liveN : null; // qa1 const nAm = ln ? ln.amend : doc.n_amended, nCa = ln ? ln.cancel : doc.n_cancelled, nAd = ln ? ln.add : doc.n_added; return (
{compact ? (
{doc.title}{tab === 'text' && activeLbl && › {activeLbl}}
) : ( )} {tab === 'text' && } {doc.has_en && }
{(doc.sources || []).length > 0 && المصادر: {doc.sources.join(' · ')}}

{doc.title}

{doc.instrument &&
أداة الإصدار{doc.instrument}{doc.num ? ' رقم ' + doc.num : ''}
} {!doc.instrument && doc.num &&
الرقم{doc.num}
} {(doc.date_fmt || doc.date) &&
الإصدار{doc.date_fmt || doc.date}
} {doc.pub_hijri &&
النشر في أم القرى{lxPub(doc.pub_hijri)}
} {doc.last_amend &&
آخر تعديل{doc.last_amend}
} {doc.execreg_parent_doc && } {!doc.is_card && doc.parent && }
{upc && (upLeft == null || upLeft >= 0) && (
{upLeft != null && upLeft >= 0 &&
{lxNum(upLeft)}
يوماً
}
نُشر هذا النظام في جريدة أم القرى بتاريخ {String(upc.published_hijri || '').replace(/-/g, '/')}هـ ولم يبدأ نفاذه بعد{lxEffDate(upc) ? '؛ يبدأ العمل به في ' + lxEffDate(upc) : ''}. {upLeft != null && upLeft >= 0 && (upc.observed || {}).hijri ? ' المدة المتبقية محسوبة من رصد الجريدة في ' + upc.observed.hijri + 'هـ.' : ''} {upc.url && <> الصفحة في الجريدة ↗}
)} {(doc.n_art > 0 || execN > 0 || tlCount > 0) && (
{doc.n_art > 0 && } {nAm > 0 && } {nCa > 0 && } {nAd > 0 && } {execN > 0 && } {tlCount > 0 && }
)}
{gd && gd.guides.length > 0 && } {tab === 'text' && doc.n_amended > 0 && viewMode !== 'en' && (
)}
{tab === 'text' && viewMode === 'en' && } {tab === 'text' && viewMode !== 'en' && setTarget(null)} viewMode={viewMode} prefs={prefs} onActive={setActiveLbl} onOpenDoc={onOpenDoc} onlyReq={onlyReq} onCounts={setLiveN} sharhArts={gd && gd.sharh_arts} />} {tab === 'guides' && gd && } {tab === 'info' && } {tab === 'family' && } {tab === 'timeline' && }
); } /* ========================================================= الجذر ========================================================= */ function LxToast() { const [msg, setMsg] = React.useState(''); React.useEffect(() => { let t; const h = (e) => { setMsg(e.detail); clearTimeout(t); t = setTimeout(() => setMsg(''), 1900); }; window.addEventListener('lx:toast', h); return () => window.removeEventListener('lx:toast', h); }, []); if (!msg) return null; return
{msg}
; } /* ========================================================= المعاهدات والاتفاقيات الدولية — قسمٌ مستقلٌّ (domain=treaties) ========================================================= */ function LxTreaties({ route, meta, go, onOpenDoc, onSection }) { const tgo = (r, replace) => go({ sec: 'treaties', ...r }, replace); const ts = meta && (meta.sectors || []).find(s => s.name === LX_TREATY_SECTOR); const subs = ts ? ts.subs.filter(x => x.docs).sort((a, b) => b.docs - a.docs) : []; const r = { ...route, scope: 'all', sort: route.sort || (route.q ? undefined : 'newest') }; const pick = (sub) => tgo({ q: route.q, country: route.country, sub: sub || undefined, sector: sub ? LX_TREATY_SECTOR : undefined }); // الدولةُ الطرف — قائمةٌ بعدّاتها (تتبع التصنيفَ المختار) const [countries, setCountries] = React.useState([]); const [cq, setCq] = React.useState(''); const [open, setOpen] = React.useState(false); React.useEffect(() => { let alive = true; lxGet('/api/laws/treaty-countries' + (route.sub ? '?sub=' + encodeURIComponent(route.sub) : '')) .then(x => { if (alive) setCountries(x.items || []); }).catch(() => {}); return () => { alive = false; }; }, [route.sub]); const pickCountry = (c) => { setOpen(false); setCq(''); tgo({ q: route.q, sub: route.sub, sector: route.sector, country: c || undefined }); }; const nz = (t) => String(t || '').replace(/[أإآ]/g, 'ا').replace(/ة/g, 'ه').replace(/ى/g, 'ي').replace(/[ُ]/g, ''); const BLOCS = ['مجلس التعاون الخليجي', 'جامعة الدول العربية', 'منظمة التعاون الإسلامي', 'الأمم المتحدة ووكالاتها', 'متعددة الأطراف (دولية)']; const shown = countries.filter(c => !cq || nz(c.name).includes(nz(cq))); const quick = countries.filter(c => !BLOCS.includes(c.name)).slice(0, 10); const top = (

🌍 المعاهدات والاتفاقيات الدولية

الاتفاقيات الثنائية والخليجية والعربية والإسلامية والأممية التي انضمت إليها المملكة، وقرارات الموافقة عليها{ts ? ' — ' + lxNum(ts.docs) + ' وثيقة' : ''}

🏳️ الدولة / الجهة الطرف:
{open && (
setOpen(false)}> setCq(e.target.value)} />
{shown.map(c => ( ))} {!shown.length &&
لا توجد دولة بهذا الاسم
}
)}
{!route.country && quick.map(c => ( ))} {route.country && }
{subs.length > 0 && (
{subs.map(x => ( ))}
)}
); return ; } /* ── sheet1: لوحةُ المادّة — إحالةُ المساعد/الخلاصة تفتحُ المادّةَ هنا، لا تبويبٌ جديدٌ ولا إعادةُ تحميلٍ للمنصّة. تجلبُ المادّةَ وحدَها (/api/laws/article — بضعةُ كيلوبايتات بدلَ الوثيقة كلِّها)، وزرُّ «رجوع» الجهازِ يُغلقُها، و«الوثيقة كاملة» تنتقلُ داخلَ المنصّة ويُرجعُ «رجوع» إلى الشاشةِ السابقة. ── */ const LX_SHEET_CSS = ` .lxas-bd{position:fixed;inset:0;z-index:9000;background:rgba(5,9,8,.62);display:flex;align-items:flex-end;justify-content:center;animation:lxasFade .16s ease both} .lxas{position:relative;width:min(760px,100%);height:min(88vh,860px);background:#16211d;border-radius:18px 18px 0 0;display:flex;flex-direction:column;overflow:hidden; box-shadow:0 -10px 40px rgba(0,0,0,.45);animation:lxasUp .22s cubic-bezier(.2,.8,.2,1) both;direction:rtl} @media (min-width:769px){.lxas-bd{align-items:center}.lxas{border-radius:18px;height:min(82vh,820px)}} .lxas-grip{width:38px;height:4px;border-radius:4px;background:rgba(239,231,214,.18);margin:8px auto 0;flex-shrink:0} .lxas-h{display:flex;align-items:flex-start;gap:10px;padding:10px 16px 10px;border-bottom:1px solid rgba(239,231,214,.08);flex-shrink:0} .lxas-h .t{flex:1;min-width:0} .lxas-h .doc{font-size:12.5px;color:#a8a69e;line-height:1.6;overflow:hidden;text-overflow:ellipsis;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical} .lxas-h .par{font-size:11.5px;color:#8f9a94} .lxas-x{border:0;background:rgba(239,231,214,.07);color:#efe7d6;width:36px;height:36px;border-radius:10px;font-size:18px;cursor:pointer;flex-shrink:0} .lxas-b{flex:1;overflow:auto;-webkit-overflow-scrolling:touch;overscroll-behavior:contain;padding:6px 14px 18px} .lxas-b .lx-root{height:auto} .lxas-f{display:flex;gap:8px;padding:10px 14px calc(10px + env(safe-area-inset-bottom));border-top:1px solid rgba(239,231,214,.08);flex-shrink:0;background:#16211d} .lxas-f button{border:0;border-radius:11px;padding:10px 12px;font:inherit;font-size:13.5px;cursor:pointer;background:rgba(239,231,214,.07);color:#efe7d6} .lxas-f button:disabled{opacity:.35;cursor:default} .lxas-f .full{margin-inline-start:auto;background:#c96442;color:#fff;font-weight:600} .lxas-sk{height:14px;border-radius:7px;margin:14px 0;background:linear-gradient(90deg,rgba(239,231,214,.05),rgba(239,231,214,.11),rgba(239,231,214,.05));background-size:200% 100%;animation:lxsk 1.2s linear infinite} .lxas-msg{margin:28px 6px;color:#c9c2b3;font-size:14px;text-align:center} .lxas-badge{display:inline-block;font-size:11.5px;font-weight:700;color:#9cc3e8;background:rgba(143,184,224,.12);border-radius:20px;padding:1px 9px;margin-bottom:3px} .lxas-f .sharh{background:rgba(143,184,224,.14);color:#9cc3e8;font-weight:600} .lxas-src{margin-inline-start:auto;align-self:center;color:#ffb08f;font-size:13.5px;text-decoration:none} .lxas-lib{padding:8px 4px;font-family:'Noto Naskh Arabic','IBM Plex Sans Arabic',serif;font-size:16.5px;line-height:2} .lx-guides{max-width:860px;margin:0 auto;padding:6px 0 30px} .lx-guides-note{color:#a8a69e;font-size:13.5px;margin:4px 2px 14px} .lx-guide{display:flex;align-items:center;gap:12px;padding:12px 14px;margin-bottom:8px;border-radius:14px;background:#16211d;box-shadow:0 0 0 1px rgba(239,231,214,.08)} .lx-guide .t{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px} .lx-guide .t b{font-size:14.5px;color:#efe7d6;line-height:1.6} .lx-guide .t span{font-size:12.5px;color:#8f9a94} .lx-guide .a{display:flex;align-items:center;gap:10px;flex-shrink:0} .lx-guide .a button{border:0;border-radius:10px;padding:8px 14px;font:inherit;font-size:13px;font-weight:600;cursor:pointer;background:rgba(143,184,224,.14);color:#9cc3e8} .lx-guide .a a{color:#ffb08f;font-size:12.5px;text-decoration:none} @media (max-width:768px){.lx-guide{flex-direction:column;align-items:stretch}.lx-guide .a{justify-content:space-between}} .lx-root .lx-act-sharh{background:rgba(143,184,224,.14)!important;color:#9cc3e8!important} .lxas-toast{position:absolute;bottom:72px;left:50%;transform:translateX(-50%);background:#efe7d6;color:#0f1715;border-radius:20px;padding:6px 14px;font-size:13px;font-weight:600} @keyframes lxasFade{from{opacity:0}} @keyframes lxasUp{from{transform:translateY(40px);opacity:.4}} @media (prefers-reduced-motion:reduce){.lxas-bd,.lxas{animation:none}} `; const lxArticleCache = new Map(); function lxGetArticle(did, art, an) { const k = did + '|' + (art || '') + '|' + (an || ''); if (!lxArticleCache.has(k)) { const p = lxGet('/api/laws/article/' + encodeURIComponent(did) + '?' + lxQs({ art: art || undefined, an: an || undefined })); p.catch(() => lxArticleCache.delete(k)); lxArticleCache.set(k, p); if (lxArticleCache.size > 40) lxArticleCache.delete(lxArticleCache.keys().next().value); } return lxArticleCache.get(k); } // «الوثيقة كاملة»: انتقالٌ داخلَ المنصّة — والمدخلُ الحاليُّ في السجلّ يحفظُ الشاشةَ السابقة ليعيدَها «رجوع» function lxOpenFullDoc(did, ord) { try { history.replaceState({ ...(history.state || {}), lxSheet: 0, lxScreen: window.__lxScreen || 'assistant' }, ''); } catch (_) {} history.pushState({ lxScreen: 'search' }, '', location.pathname + '?' + lxQs({ screen: 'search', doc: did, art: ord })); window.dispatchEvent(new PopStateEvent('popstate', { state: { lxScreen: 'search' } })); } // guides1: اللوحةُ نفسُها بثلاثةِ أوضاع — مادّة · شرحُها الرسميّ (kind:'sharh') · دليلٌ رسميٌّ كامل (kind:'guide') function lxSheetLoad(cur) { if (cur.kind === 'sharh') return lxGet('/api/laws/sharh/' + encodeURIComponent(cur.did) + '?' + lxQs({ an: cur.an })); if (cur.kind === 'guide') return lxGet('/api/laws/guide?' + lxQs({ id: cur.id })); return lxGetArticle(cur.did, cur.art, cur.an); } function LxArticleSheet({ req, onClose }) { const [cur, setCur] = React.useState(req); const [st, setSt] = React.useState({ loading: true }); const [toast, setToast] = React.useState(''); const bodyRef = React.useRef(null); const kind = cur.kind || 'article'; React.useEffect(() => { let alive = true; setSt(s => ({ ...s, loading: true, err: null })); lxSheetLoad(cur).then(d => { if (!alive) return; let b = null; if (kind === 'article') { window.AMEND_LINKS = window.AMEND_LINKS || {}; const blocks = window.LexaRender ? lxRenderDoc({ did: d.did, text: d.md, amend_links: d.amend_links }, 'current') : []; b = blocks.find(x => x.type === 'art') || blocks.find(x => x.parts.length || x.notes.length) || null; } setSt({ d, b, kind }); if (bodyRef.current) bodyRef.current.scrollTop = 0; }).catch(e => alive && setSt({ err: (e && e.message) || 'تعذّر الفتح', kind })); return () => { alive = false; }; }, [cur.kind, cur.did, cur.art, cur.an, cur.id]); React.useEffect(() => { const k = (e) => { if (e.key === 'Escape') onClose(); }; const t = (e) => { setToast(e.detail || ''); setTimeout(() => setToast(''), 1600); }; window.addEventListener('keydown', k); window.addEventListener('lx:toast', t); const ov = document.body.style.overflow; document.body.style.overflow = 'hidden'; return () => { window.removeEventListener('keydown', k); window.removeEventListener('lx:toast', t); document.body.style.overflow = ov; }; }, []); const d = st.kind === kind ? st.d : null; const step = (k) => d && (kind === 'sharh' ? setCur({ kind: 'sharh', did: cur.did, an: d.an + k, back: cur.back }) : setCur({ did: d.did, art: d.ord + k })); const onCopy = (b, what) => { if (!d) return; if (what === 'link') lxCopy(location.origin + location.pathname + '?' + lxQs({ screen: 'search', doc: d.did, art: d.ord }), 'نُسخ رابط المادة'); else lxCopy((d.heading || '') + '\n' + ((bodyRef.current && bodyRef.current.querySelector('.lx-art-b') || {}).innerText || '').trim() + '\n— ' + d.title, 'نُسخ نص المادة'); }; const head = kind === 'article' ? <>
{d ? d.title : (cur.label || '…')}
{d && d.parent &&
ضمن: {d.parent.title}
} : <>
📘 {kind === 'sharh' ? 'الشرح الرسمي' : 'دليلٌ رسمي'}
{d ? d.title : (cur.label || '…')}
{d && d.issuer &&
{d.issuer}{kind === 'sharh' ? ' — المادة ' + d.an : ''}
}; let body; if (st.err) body =
{st.err}
; else if (!d) body =
; else if (kind === 'article') body = !st.b ?
لا يتوفّر نصٌّ لهذه المادة.
:
; else body =
{lxLibParas(d.md)}
; return (
{ if (e.target === e.currentTarget) onClose(); }} role="dialog" aria-modal="true" aria-label={(d && (d.heading || d.title)) || cur.label || 'المادة'}>
); } // guides1: تبويبُ «الشروح والأدلة الرسمية» في قارئ النظام function LxGuides({ gd }) { const perArt = gd.sharh_arts && gd.sharh_arts.length; return (

شروحٌ وأدلّةٌ صادرةٌ عن الجهاتِ المختصّة لهذا النظام.{perArt ? ' ولكلّ مادّةٍ مشروحةٍ زرُّ «📘 الشرح الرسمي» في النصّ.' : ''}

{gd.guides.map(g => (
{g.title}{g.issuer}{g.n_arts ? ' · مشروحٌ مادّةً مادّة (' + lxNum(g.n_arts) + ' مادة)' : ''}
{g.n_arts > 0 && g.parts > 1 ? : } {g.url && المصدر ↗}
))}
); } function LxArticleSheetHost({ req }) { const [open, setOpen] = React.useState(true); React.useEffect(() => { // مدخلٌ في السجلّ: زرُّ «رجوع» في الجوال يُغلقُ اللوحةَ بدلَ مغادرةِ الشاشة try { if (!(history.state && history.state.lxSheet)) history.pushState({ ...(history.state || {}), lxSheet: 1 }, ''); } catch (_) {} const onPop = () => { if (!(history.state && history.state.lxSheet)) setOpen(false); }; window.addEventListener('popstate', onPop); return () => window.removeEventListener('popstate', onPop); }, []); if (!open) return null; return { if (history.state && history.state.lxSheet) history.back(); else setOpen(false); }} />; } let lxSheetRoot = null, lxSheetSeq = 0; window.lxOpenArticle = function (req) { if (!req || !(req.did || req.id)) return false; let host = document.getElementById('lx-art-sheet'); if (!host) { host = document.createElement('div'); host.id = 'lx-art-sheet'; document.body.appendChild(host); lxSheetRoot = ReactDOM.createRoot(host); } lxSheetRoot.render(); return true; }; function LawsView() { const [route, setRoute] = React.useState(() => lxReadRoute()); const lxSec = (s) => (s && s !== 'books' ? s : 'laws'); const [section, setSection] = React.useState(() => lxSec(lxReadRoute().sec)); const [meta, setMeta] = React.useState(null); const [metaErr, setMetaErr] = React.useState(null); const [prefs, setPrefs] = React.useState(() => ({ fs: 17, theme: 'paper', focus: false, ...lxLoad('lx-prefs', {}) })); React.useEffect(() => { lxGet('/api/laws/meta').then(setMeta).catch(e => setMetaErr(e.message)); const f = () => { const r = lxReadRoute(); setRoute(r); setSection(lxSec(r.sec)); }; window.addEventListener('popstate', f); return () => window.removeEventListener('popstate', f); }, []); const go = (next, replace) => { lxWriteRoute(next, replace); setRoute(next); }; const openDoc = (did, ord, an, tab) => go({ doc: did, art: ord || undefined, an: an || undefined, tab: tab || undefined }); const search = (q) => go({ q }); const browse = (f) => go({ browse: '1', ...f }); const onSection = (s) => { setSection(s); go(s === 'laws' ? {} : { sec: s }); }; let body; if (route.doc) body = history.length > 1 ? history.back() : go({})} />; else if (section === 'treaties') body = ; else if (section !== 'laws') body =
; else if (route.q || route.browse) body = ; else body = (
); return (
{body}
); } window.LawsView = LawsView;