{"id":"l-css-1-5","courseId":"css-mastery","lang":"ar","kind":"lesson","summary":"اكتب أنماط الـ components بالـ nesting الأصلي في CSS، واستخدم :has() لتنسيق عنصر بحسب ما يحتويه، بما في ذلك فلتر للجدول لا يحتاج إلى JavaScript.","html":"<p>أمران يزعجان كل من يصون CSS البطاقات في Waypoint. قواعد البطاقة مبعثرة: القاعدة الأساسية هنا، وحالة المرور بعدها بعشرين سطرًا، وتجاوز الوضع الداكن في ملف آخر. وفريق التصميم لا يتوقّف عن طلب أنماط تعتمد على ما <em>داخل</em> البطاقة («إن كانت الجلسة ممتلئة، اجعلها باهتة»)، وهذا كان يعني سابقًا تبديل class بـ JavaScript.</p>\n<p>الـ nesting الأصلي (التداخل) يحلّ الأمر الأول، و<code dir=\"ltr\">:has()</code> تحلّ الثاني.</p>\n<h2 id=\"sec-1\" tabindex=\"-1\">الـ nesting الأصلي</h2>\n<p>تستطيع الآن أن تضع القواعد داخل القواعد، في CSS عادية، دون أيّ خطوة بناء:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">session-card.css</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  padding</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  border</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> solid</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> #e5e7eb</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  border-radius</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">12</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#116329;--shiki-dark:#7EE787\">  h2</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    margin-block</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 0.5</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    font-size</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1.125</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  }</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#116329;--shiki-dark:#7EE787\">  &#x26;</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">:hover</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    border-color</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">#a78bfa</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  }</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  .featured</span><span style=\"color:#116329;--shiki-dark:#7EE787\"> &#x26;</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    border-width</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">2</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  }</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">  @media</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> (</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">width</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\"> >=</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 48</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">    padding</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1.5</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p><code dir=\"ltr\">&amp;</code> تمثّل الـ selector الأب. <code dir=\"ltr\">&amp;:hover</code> تعني «هذه البطاقة حين يمرّ المؤشّر فوقها»، و<code dir=\"ltr\">.featured &amp;</code> تعني «هذه البطاقة داخل <code dir=\"ltr\">.featured</code>». والـ selector المتداخل بلا <code dir=\"ltr\">&amp;</code>، مثل <code dir=\"ltr\">h2</code>، يُعامَل كعنصر داخلي: <code dir=\"ltr\">.session-card h2</code>. وقواعد <code dir=\"ltr\">@media</code> و<code dir=\"ltr\">@container</code> المتداخلة تنطبق على الـ selector الأب، فيعيش تغيير الـ padding بجوار الـ padding نفسه.</p>\n<p>يمكن أن تبدأ الـ selectors المتداخلة باسم عنصر (<code dir=\"ltr\">h2</code> لا <code dir=\"ltr\">&amp; h2</code>). كانت التطبيقات الأولى تشترط أن يأتي رمز أولًا؛ أما الآن فكل المتصفّحات الحالية تدعم الصيغة المرنة، والـ nesting ضمن Baseline منذ ديسمبر 2023 (ومتاح على نطاق واسع منذ منتصف 2026).</p>\n<aside class=\"callout callout-mistake\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3\"/><path d=\"M12 9v4\"/><path d=\"M12 17h.01\"/></svg><span><span class=\"callout-kind\">خطأ شائع</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>كتابة لواحق على طريقة Sass</span></p>\n<p><code dir=\"ltr\">&amp;__title</code> و<code dir=\"ltr\">&amp;--featured</code> تلصقان السلاسل النصية في Sass. الـ nesting الأصلي يعمل على الـ selectors لا على النص، لذا لا يستطيع بناء <code dir=\"ltr\">.session-card__title</code>. إن كنت تستخدم BEM فاكتب تلك الـ classes كاملة.</p>\n</aside>\n<p>قاعدتان أخريان تحافظان على صحّة الـ nesting. في العمق، تتصرّف <code dir=\"ltr\">&amp;</code> كأنها <code dir=\"ltr\">:is()</code> ملفوفة حول قائمة الأب، لذا فإن <code dir=\"ltr\">#keynote, .session-card { h2 { … } }</code> تعطي <em>كل</em> قاعدة <code dir=\"ltr\">h2</code> متداخلة specificity بمستوى ID. وتوقّف عند مستويين من العمق: الـ selector الذي لا تستطيع قراءته بنظرة واحدة لن تستطيع تجاوزه بنظرة واحدة.</p>\n<h2 id=\"sec-2\" tabindex=\"-1\"><code dir=\"ltr\">:has()</code>: نسّق العنصر بحسب ما يحتويه</h2>\n<p>تأخذ <code dir=\"ltr\">:has()</code> selector نسبيًا وتطابق العنصر إن وجد ذلك الـ selector شيئًا:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"1\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* A card that contains a speaker photo gets a two-column layout */</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-card:has</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#116329;--shiki-dark:#7EE787\">img</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  display</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">grid</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  grid-template-columns</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">64</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> 1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">fr</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  gap</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">1</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">rem</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* Dim sold-out sessions */</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-card:has</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.badge-full</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  opacity</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0.6</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* A label whose following input is invalid after the user typed */</span></span>\n<span class=\"line\"><span style=\"color:#116329;--shiki-dark:#7EE787\">label</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">:has</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">+</span><span style=\"color:#116329;--shiki-dark:#7EE787\"> input</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">:</span><span style=\"color:#116329;--shiki-dark:#7EE787\">user-invalid</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  color</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">#b91c1c</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>المثال الأخير يُظهر أن <code dir=\"ltr\">:has()</code> أكثر من مجرد «selector للعنصر الأب»: <code dir=\"ltr\">+ input</code> تنظر إلى <em>الشقيق التالي</em>، فيستطيع عنصر سابق أن يتفاعل مع عنصر لاحق. و<code dir=\"ltr\">:user-invalid</code> هي القريبة المهذّبة لـ <code dir=\"ltr\">:invalid</code>؛ فهي لا تطابق إلا بعد أن يتفاعل المستخدم مع الحقل، فلا يُحمَّل نموذج فارغ مغطّى بالأحمر.</p>\n<p>لـ <code dir=\"ltr\">:has()</code> حدّان يستحقّان المعرفة قبل أن تصطدم بهما. لا يمكنك وضع <code dir=\"ltr\">:has()</code> داخل <code dir=\"ltr\">:has()</code> أخرى، ولا وضع pseudo-elements مثل <code dir=\"ltr\">::before</code> بداخلها. والـ specificity الخاصة بها تتبع قاعدة <code dir=\"ltr\">:is()</code> التي رأيناها سابقًا في هذا القسم: أدقّ وسيط هو الذي يُحسب، لذا فإن <code dir=\"ltr\">.session-card:has(#keynote-badge)</code> تحمل وزن ID.</p>\n<h2 id=\"sec-3\" tabindex=\"-1\">شريط فلاتر بلا JavaScript</h2>\n<p>هنا تغيّر <code dir=\"ltr\">:has()</code> طريقة بنائك للأشياء. شريط الفلاتر في Waypoint مجموعة من مربّعات الاختيار. ولأن مربّعات الاختيار والبطاقات تشترك في سلف واحد هو <code dir=\"ltr\">.schedule</code>، تستطيع حالة مربّع الاختيار أن تقود البطاقات:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"html\" data-index=\"2\"><div class=\"code-head\"><span class=\"code-title\">HTML</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">section</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> class</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"schedule\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">div</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> class</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"filters\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">    &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">label</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">input</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> type</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"checkbox\"</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> id</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"hide-full\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">> Hide sold-out&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">label</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  &#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">div</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">article</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> class</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"session-card\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>…&#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">span</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> class</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"badge-full\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>Sold out&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">span</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">article</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">  &#x3C;</span><span style=\"color:#116329;--shiki-dark:#7EE787\">article</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> class</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">=</span><span style=\"color:#0A3069;--shiki-dark:#A5D6FF\">\"session-card\"</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">>…&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">article</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">&#x3C;/</span><span style=\"color:#116329;--shiki-dark:#7EE787\">section</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">></span></span></code></pre></div>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"3\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.schedule:has</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">#hide-full:checked</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-card:has</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.badge-full</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  display</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">none</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">;</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n<p>اقرأها من اليمين إلى اليسار: أخفِ البطاقة التي تحتوي على شارة «ممتلئة»، حين تكون داخل جدول يحتوي على مربّع <code dir=\"ltr\">#hide-full</code> مُفعَّل. ويعيد المتصفّح تقييمها لحظة تغيّر مربّع الاختيار.</p>\n<aside class=\"callout callout-why\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><circle cx=\"12\" cy=\"12\" r=\"10\"/><circle cx=\"12\" cy=\"12\" r=\"6\"/><circle cx=\"12\" cy=\"12\" r=\"2\"/></svg><span><span class=\"callout-kind\">لماذا يهمّ هذا</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>لماذا يهمّ هذا</span></p>\n<p>الحالة التي تعيش في الـ DOM (مربّعات اختيار مُفعَّلة، و<code dir=\"ltr\">&lt;details&gt;</code> مفتوحة، و<code dir=\"ltr\">[aria-expanded]</code>، وحقل عليه الـ focus) أصبحت شيئًا تستطيع CSS قراءته مباشرةً. وتبديل classes أقل في JavaScript يعني أماكن أقل يمكن أن تختلف فيها الواجهة عن الحالة.</p>\n</aside>\n<aside class=\"callout callout-tip\" role=\"note\"><p class=\"callout-title\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><path d=\"M15 14c.2-1 .7-1.7 1.5-2.5 1-.9 1.5-2.2 1.5-3.5A6 6 0 0 0 6 8c0 1 .2 2.2 1.5 3.5.7.7 1.3 1.5 1.5 2.5\"/><path d=\"M9 18h6\"/><path d=\"M10 22h4\"/></svg><span><span class=\"callout-kind\">نصيحة</span><span class=\"callout-sep\" aria-hidden=\"true\"> · </span>اجعل نقطة الارتكاز ضيّقة</span></p>\n<p><code dir=\"ltr\">:has()</code> سريعة في المحرّكات الحديثة، لكن <code dir=\"ltr\">body:has(...)</code> أو <code dir=\"ltr\">*:has(...)</code> تطلب من المتصفّح أن يعيد فحص جزء كبير من الصفحة كلما تغيّر أيّ شيء بداخلها. ارتكز على أقرب سلف مشترك، <code dir=\"ltr\">.schedule</code> بدل <code dir=\"ltr\">body</code>، متى استطعت. و<code dir=\"ltr\">:has()</code> نفسها متاحة على نطاق واسع حسب Baseline.</p>\n</aside>\n<h2 id=\"sec-4\" tabindex=\"-1\">ثلاثة selectors أخرى تحلّ محلّ JavaScript</h2>\n<p>تحظى <code dir=\"ltr\">:has()</code> بالاهتمام، لكن بضعة selectors أهدأ تستحق مكانها في صفحة Waypoint أيضًا:</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"4\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* Highlight the whole filter bar while any control inside it has focus */</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.filters:focus-within</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">outline</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">2</span><span style=\"color:#CF222E;--shiki-dark:#FF7B72\">px</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> solid</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\"> #a78bfa</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* Every card except sold-out and cancelled ones */</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-card:not</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.is-full</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">, </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.is-cancelled</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">) { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">cursor</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">pointer</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span>\n<span class=\"line\"></span>\n<span class=\"line\"><span style=\"color:#6E7781;--shiki-dark:#8B949E\">/* Stripe only the visible cards, skipping hidden ones */</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-card:nth-child</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">(</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">even</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> of :</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">n</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">ot([hidde</span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">n</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">])) { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">background</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">#f9fafb</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span></code></pre></div>\n<p><code dir=\"ltr\">:focus-within</code> تطابق العنصر حين يكون عليه أو على أيّ شيء بداخله الـ focus. و<code dir=\"ltr\">:not()</code> تقبل قائمة كاملة، فلم تعد تحتاج إلى سلسلة <code dir=\"ltr\">:not(.a):not(.b)</code>. وصيغة <code dir=\"ltr\">of S</code> في <code dir=\"ltr\">:nth-child()</code> لا تعدّ إلا الأشقّاء المطابقين لـ <code dir=\"ltr\">S</code>، وهذا يصلح التلوين المتناوب للصفوف الذي ينكسر لحظة يخفي الفلتر أحدها. والثلاثة تعمل في كل المتصفّحات الحالية.</p>\n<h2 id=\"sec-5\" tabindex=\"-1\">دورك الآن</h2>\n<p>في التمرين ستعيد كتابة أنماط البطاقة بالـ nesting، ثم تضيف قاعدتين بـ <code dir=\"ltr\">:has()</code>: واحدة تخفي الجلسات الممتلئة حين يُفعَّل مربّع الفلتر، وأخرى تُبرز البطاقة حين يُفعَّل مربّع «الحفظ» فيها. وبهذا يكتمل قسم الـ cascade؛ وبعده ستنتقل من <em>أيّ</em> الأنماط ينطبق إلى <em>أين تذهب الأشياء</em>، بدءًا بـ flexbox.</p>\n","toc":[{"id":"sec-1","text":"الـ nesting الأصلي","level":2},{"id":"sec-2","text":":has(): نسّق العنصر بحسب ما يحتويه","level":2},{"id":"sec-3","text":"شريط فلاتر بلا JavaScript","level":2},{"id":"sec-4","text":"ثلاثة selectors أخرى تحلّ محلّ JavaScript","level":2},{"id":"sec-5","text":"دورك الآن","level":2}],"takeaways":["الـ nesting الأصلي يجمع حالات الـ component وأبناءه والـ media queries الخاصة به داخل قاعدته، و<code dir=\"ltr\">&amp;</code> تمثّل الـ selector الأب.","الـ selector المتداخل يأخذ specificity <code dir=\"ltr\">:is()</code> مطبّقةً على قائمة الأب، لذا إن احتوت قائمة الأب على ID أصبحت كل قاعدة متداخلة ثقيلة بوزن ID.","الـ nesting في CSS لا يلصق السلاسل النصية كما يفعل Sass، لذا لن تُنتج <code dir=\"ltr\">&amp;__title</code> أبدًا <code dir=\"ltr\">.card__title</code>.","<code dir=\"ltr\">:has()</code> تطابق العنصر حين يطابق الـ selector النسبي داخلها، ما يتيح لعنصر أب، أو لعنصر شقيق سابق، أن يتفاعل مع أبنائه أو مع أشقّائه اللاحقين."],"further":[{"title":"Using CSS nesting (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/Guides/Nesting/Using"},{"title":":has() (MDN)","url":"https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Selectors/:has"},{"title":"Nesting (web.dev Learn CSS)","url":"https://web.dev/learn/css/nesting"}],"quiz":[{"q":"<p>ما الـ selector الذي تُنتجه هذه القاعدة المتداخلة؟</p>\n<div class=\"code-block\" dir=\"ltr\" data-lang=\"css\" data-index=\"0\"><div class=\"code-head\"><span class=\"code-title\">CSS</span><span class=\"code-actions\"><button type=\"button\" class=\"code-btn\" data-action=\"copy\" aria-label=\"نسخ الكود\"><svg class=\"icon \" viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2\" stroke-linecap=\"round\" stroke-linejoin=\"round\" aria-hidden=\"true\" focusable=\"false\"><rect width=\"14\" height=\"14\" x=\"8\" y=\"8\" rx=\"2\" ry=\"2\"/><path d=\"M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2\"/></svg><span>نسخ</span></button></span></div><pre class=\"shiki\" tabindex=\"0\"><code><span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">.session-card</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> {</span></span>\n<span class=\"line\"><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">  .speaker</span><span style=\"color:#116329;--shiki-dark:#7EE787\"> &#x26;</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\"> { </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">padding</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">: </span><span style=\"color:#0550AE;--shiki-dark:#79C0FF\">0</span><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">; }</span></span>\n<span class=\"line\"><span style=\"color:#1F2328;--shiki-dark:#E6EDF3\">}</span></span></code></pre></div>\n","options":[{"text":"<code dir=\"ltr\">.session-card .speaker</code>","why":"هذا ما ستحصل عليه دون <code dir=\"ltr\">&amp;</code>، أو مع <code dir=\"ltr\">&amp; .speaker</code>. هنا تأتي <code dir=\"ltr\">&amp;</code> في النهاية، فتكون البطاقة هي العنصر المتداخل."},{"text":"<code dir=\"ltr\">.speaker .session-card</code>","why":"صحيح. <code dir=\"ltr\">&amp;</code> تحدّد موضع الـ selector الأب؛ ووضعها في النهاية يعني بطاقة جلسة داخل <code dir=\"ltr\">.speaker</code>."},{"text":"<code dir=\"ltr\">.session-card.speaker</code>","why":"هذا يتطلّب <code dir=\"ltr\">&amp;.speaker</code> دون مسافة بينهما."},{"text":"غير صالح، لأن <code dir=\"ltr\">&amp;</code> يجب أن تأتي أولًا.","why":"يمكن أن تظهر <code dir=\"ltr\">&amp;</code> في أيّ موضع من الـ selector المتداخل، بما في ذلك نهايته."}],"answer":1},{"q":"<p>أيّ selector ينسّق بطاقة الجلسة فقط حين تحتوي على صورة؟</p>","options":[{"text":"<code dir=\"ltr\">.session-card img</code>","why":"هذا يحدّد الصورة نفسها، لا البطاقة."},{"text":"<code dir=\"ltr\">.session-card &gt; img:parent</code>","why":"لا توجد pseudo-class اسمها <code dir=\"ltr\">:parent</code> في CSS؛ <code dir=\"ltr\">:has()</code> هي طريقة التحديد بحسب العناصر الداخلية."},{"text":"<code dir=\"ltr\">.session-card:has(img)</code>","why":"صحيح. تطابق البطاقة حين يجد الـ selector النسبي <code dir=\"ltr\">img</code> عنصرًا بداخلها."}],"answer":2},{"q":"<p>أيّ قاعدة تخفي كل بطاقة ليست من مسار design حين يُفعَّل مربّع الاختيار <code dir=\"ltr\">#only-design</code> الموجود داخل <code dir=\"ltr\">.schedule</code>؟</p>","options":[{"text":"<code dir=\"ltr\">.schedule:has(#only-design:checked) .session-card:not(.track-design) { display: none; }</code>","why":"صحيح. <code dir=\"ltr\">:has()</code> تحوّل حالة مربّع الاختيار إلى شرط على السلف المشترك، وبقية الـ selector تستهدف البطاقات."},{"text":"<code dir=\"ltr\">#only-design:checked .session-card:not(.track-design) { display: none; }</code>","why":"هذا يبحث عن بطاقات داخل مربّع الاختيار، وعناصر input لا يمكن أن يكون لها أبناء."},{"text":"<code dir=\"ltr\">#only-design:checked + .session-card:not(.track-design) { display: none; }</code>","why":"الرابط <code dir=\"ltr\">+</code> لا يصل إلا إلى الشقيق الوحيد الذي يلي مربّع الاختيار مباشرةً، لا إلى البطاقات في مواضع أخرى من الجدول."}],"answer":0},{"q":"<p>كتبت <code dir=\"ltr\">.card { &amp;__title { font-weight: 700; } }</code> بحكم العادة من Sass. ماذا يحدث؟</p>","options":[{"text":"تنسّق العناصر التي تحمل الـ class <code dir=\"ltr\">card__title</code>.","why":"الـ nesting الأصلي لا يلصق السلاسل النصية؛ <code dir=\"ltr\">&amp;</code> تمثّل selector، لا نصًا يُلصق به شيء."},{"text":"لا تنسّق <code dir=\"ltr\">.card__title</code>؛ فالـ selector المتداخل لا يعني ما يعنيه في Sass.","why":"صحيح. لتنسيق عنصر BEM بالـ nesting الأصلي تكتب الـ class كاملًا، مثل <code dir=\"ltr\">.card__title</code> في المستوى الأعلى."},{"text":"يتوقّف المتصفّح عن تحليل بقية ملف الأنماط.","why":"معالجة الأخطاء في CSS تُسقط ما لا تستطيع استخدامه وتكمل؛ ولا تتخلّى عن ملف الأنماط أبدًا."}],"answer":1}],"exercise":{"kind":"web","mode":"dom","starter":{"html":"<section class=\"schedule\">\n  <div class=\"filters\">\n    <label><input type=\"checkbox\" id=\"hide-full\"> Hide sold-out sessions</label>\n  </div>\n  <article class=\"session-card\" id=\"c1\">\n    <h2>Shipping View Transitions</h2>\n    <label class=\"save-label\"><input type=\"checkbox\" class=\"save\"> Save</label>\n  </article>\n  <article class=\"session-card\" id=\"c2\">\n    <h2>Grid Layout Workshop</h2>\n    <span class=\"badge-full\">Sold out</span>\n    <label class=\"save-label\"><input type=\"checkbox\" class=\"save\"> Save</label>\n  </article>\n  <article class=\"session-card\" id=\"c3\">\n    <h2>Color Spaces for Humans</h2>\n    <label class=\"save-label\"><input type=\"checkbox\" class=\"save\"> Save</label>\n  </article>\n</section>","css":".session-card {\n  margin-block-end: 12px;\n  padding: 12px 16px;\n  border: 2px solid #e5e7eb;\n  border-radius: 12px;\n}\n.session-card h2 {\n  margin: 0 0 8px;\n  font-size: 1.05rem;\n}\n.session-card:hover {\n  background: #faf5ff;\n}\n.badge-full {\n  display: inline-block;\n  padding: 0.1em 0.6em;\n  border-radius: 999px;\n  background: #fee2e2;\n  color: #991b1b;\n}\n\n/* 1. Rewrite the three .session-card rules above as one nested rule. */\n/* 2. Hide sold-out cards when #hide-full is checked. */\n/* 3. Give a card a #6d28d9 border when its .save box is checked. */\n"},"solution":{"html":"<section class=\"schedule\">\n  <div class=\"filters\">\n    <label><input type=\"checkbox\" id=\"hide-full\"> Hide sold-out sessions</label>\n  </div>\n  <article class=\"session-card\" id=\"c1\">\n    <h2>Shipping View Transitions</h2>\n    <label class=\"save-label\"><input type=\"checkbox\" class=\"save\"> Save</label>\n  </article>\n  <article class=\"session-card\" id=\"c2\">\n    <h2>Grid Layout Workshop</h2>\n    <span class=\"badge-full\">Sold out</span>\n    <label class=\"save-label\"><input type=\"checkbox\" class=\"save\"> Save</label>\n  </article>\n  <article class=\"session-card\" id=\"c3\">\n    <h2>Color Spaces for Humans</h2>\n    <label class=\"save-label\"><input type=\"checkbox\" class=\"save\"> Save</label>\n  </article>\n</section>","css":".session-card {\n  margin-block-end: 12px;\n  padding: 12px 16px;\n  border: 2px solid #e5e7eb;\n  border-radius: 12px;\n\n  h2 {\n    margin: 0 0 8px;\n    font-size: 1.05rem;\n  }\n\n  &:hover {\n    background: #faf5ff;\n  }\n\n  &:has(.save:checked) {\n    border-color: #6d28d9;\n  }\n}\n\n.badge-full {\n  display: inline-block;\n  padding: 0.1em 0.6em;\n  border-radius: 999px;\n  background: #fee2e2;\n  color: #991b1b;\n}\n\n.schedule:has(#hide-full:checked) .session-card:has(.badge-full) {\n  display: none;\n}\n"},"checks":[{"id":"uses-nesting","test":"const all = []; const walk = (rules) => { for (const r of rules) { all.push(r); if (r.cssRules) walk(r.cssRules); } }; for (const s of document.styleSheets) walk(s.cssRules); return all.some((r) => r instanceof CSSStyleRule && r.selectorText === '.session-card' && [...r.cssRules].some((c) => c instanceof CSSStyleRule));"},{"id":"all-visible","test":"return $$('.session-card').every((c) => style(c, 'display') !== 'none');"},{"id":"hides-sold-out","test":"const box = $('#hide-full'); if (!box.checked) await click(box); const ok = style('#c2', 'display') === 'none' && style('#c1', 'display') !== 'none' && style('#c3', 'display') !== 'none'; await click(box); return ok;"},{"id":"shows-again","test":"return !$('#hide-full').checked && style('#c2', 'display') !== 'none';"},{"id":"saved-highlight","test":"const save = $('#c1 .save'); if (!save.checked) await click(save); const ok = style('#c1', 'border-top-color') === 'rgb(109, 40, 217)' && style('#c3', 'border-top-color') === 'rgb(229, 231, 235)'; await click(save); return ok;"}],"title":"اجمع أنماط البطاقة بالـ nesting وصفِّ الجلسات بـ :has()","prompt":"<p>ثلاث مهام، كلها في CSS:</p>\n<ol>\n<li>أعد كتابة قواعد <code dir=\"ltr\">.session-card</code> الثلاث (الأساسية و<code dir=\"ltr\">h2</code> و<code dir=\"ltr\">:hover</code>) على شكل <strong>قاعدة متداخلة واحدة</strong> على <code dir=\"ltr\">.session-card</code>.</li>\n<li>حين يُفعَّل مربّع الاختيار <code dir=\"ltr\">#hide-full</code>، أخفِ (<code dir=\"ltr\">display: none</code>) كل <code dir=\"ltr\">.session-card</code> تحتوي على <code dir=\"ltr\">.badge-full</code>.</li>\n<li>حين يُفعَّل مربّع <code dir=\"ltr\">.save</code> في بطاقة ما، أعطِ تلك البطاقة لون حدّ <code dir=\"ltr\">#6d28d9</code>.</li>\n</ol>\n<p>لا تضف JavaScript ولا تغيّر الـ HTML.</p>\n","hints":["داخل قاعدة <code dir=\"ltr\">.session-card</code>، تحلّ <code dir=\"ltr\">h2 { … }</code> و<code dir=\"ltr\">&amp;:hover { … }</code> محلّ القاعدتين المنفصلتين.","للفلتر، ابدأ من السلف الذي يحتوي على مربّع الاختيار والبطاقات معًا: <code dir=\"ltr\">.schedule:has(#hide-full:checked)</code>.","<code dir=\"ltr\">.schedule:has(#hide-full:checked) .session-card:has(.badge-full) { display: none; }</code>، وداخل البطاقة متداخلةً: <code dir=\"ltr\">&amp;:has(.save:checked) { border-color: #6d28d9; }</code>."],"explanation":"<p>الـ nesting يُبقي كل حالات البطاقة في كتلة واحدة: تصبح <code dir=\"ltr\">h2</code> قاعدة لعنصر داخلي، وتُلحق <code dir=\"ltr\">&amp;:hover</code> الـ pseudo-class بالبطاقة نفسها. ويعمل الفلتر لأن <code dir=\"ltr\">.schedule</code> تحتوي على مربّع الاختيار والبطاقات معًا: <code dir=\"ltr\">:has(#hide-full:checked)</code> تحوّل حالة مربّع الاختيار إلى شرط على ذلك السلف المشترك، و<code dir=\"ltr\">.session-card:has(.badge-full)</code> تنتقي البطاقات الممتلئة. وإبراز الحفظ هو الفكرة نفسها بمستوى أدنى: تطابق البطاقة <code dir=\"ltr\">:has(.save:checked)</code> لحظة تفعيل مربّعها، ويعيد المتصفّح تقييم القاعدتين عند كل تغيير، دون JavaScript.</p>\n","checkLabels":{"uses-nesting":"أنماط البطاقة تستخدم الـ nesting الأصلي","all-visible":"كل البطاقات ظاهرة قبل التصفية","hides-sold-out":"تفعيل الفلتر يخفي البطاقة الممتلئة وحدها","shows-again":"إلغاء تفعيل الفلتر يُظهرها من جديد","saved-highlight":"البطاقة المحفوظة تأخذ حدًّا بنفسجيًا"}},"words":653,"readMinutes":4}