# الإعدادات: الأرامل والأسطر اليتيمة وموازنة الأعمدة

> القواعد التي تُبقي الأسطر والكتل معًا عند فاصل العمود، والأدوات التي تجعل كل الأعمدة تنتهي عند المستوى نفسه

- نسخة HTML: https://postext.dev/ar/docs/configuration-page-flow
- آخر تحديث: 2026-10-16
- مدة القراءة: 22 دقيقة
- لغات أخرى: [en](https://postext.dev/en/docs/configuration-page-flow.md), [es](https://postext.dev/es/docs/configuration-page-flow.md), [ca](https://postext.dev/ca/docs/configuration-page-flow.md), [de](https://postext.dev/de/docs/configuration-page-flow.md), [fr](https://postext.dev/fr/docs/configuration-page-flow.md), [it](https://postext.dev/it/docs/configuration-page-flow.md), [pt](https://postext.dev/pt/docs/configuration-page-flow.md), [zh](https://postext.dev/zh/docs/configuration-page-flow.md), [ja](https://postext.dev/ja/docs/configuration-page-flow.md)

## باختصار

تتناول هذه الصفحة كيف يقرر Postext أين ينتهي العمود أو الصفحة. لا ينبغي أن يبقى سطر واحد من فقرة وحده في أعلى العمود أو أسفله، ولا أن ينفصل عنوان عن نصه. وقد تجعل هذه القواعد عمودًا أقصر من غيره. فيُجري Postext عندئذ تغييرات صغيرة، بترتيب ثابت، حتى ينتهي كل عمود عند الارتفاع نفسه. وتسرد الصفحة كل قاعدة وكل تغيير، وطريقة معرفة ما استُعمل منها.

## الأسطر اليتيمة والأرامل والكلمات المعزولة وقواعد الإبقاء معًا

انظر [تقسيم الكلمات وضبط الأسطر](https://postext.dev/ar/docs/justification.md) لآلية نقاط الجزاء هذه. وهذا القسم هو المرجع لمفاتيح `bodyText` التي تتحكم فيها.

وإلى جانب حدود التقسيم بالواصلة والتباعد، تتيح إعدادات نص المتن القواعدَ المرنة التي تمنع الانكسارات المحرجة بنيويًا في الفقرات. وكلها تُغذّى في خوارزمية Knuth-Plass لكسر الأسطر على هيئة نقاط جزاء (demerits) — تميل بالإخراج نحو الانكسارات النظيفة دون أن تفرض قاعدة صارمة أبدًا. اضبط قيم `*Penalty` على `0` لتعطيل أيٍّ منها فعليًا.

| الخاصية | النوع | القيمة الافتراضية | الوصف |
| --- | --- | --- | --- |
| `avoidOrphans` | `boolean` | `true` | اثنِ الفقرة عن أن تنتهي بأقل من `orphanMinLines` سطرًا في أعلى العمود التالي. وعلى شبكة المحارف (`cjk.grid`) في المنطقة `japan` تكون القيمة الافتراضية `false`. |
| `orphanMinLines` | `number` | `2` | أدنى عدد من الأسطر مطلوب في أعلى العمود التالي حين تنقسم الفقرة. لا يعمل إلا حين تكون `avoidOrphans` هي `true`. |
| `orphanPenalty` | `number` | `1000` | نقاط الجزاء المضافة عند مخالفة قيد الأسطر اليتيمة. القيم الأعلى تميل بالخوارزمية أشدّ ضد الأسطر اليتيمة؛ و`0` يعطّل الجزاء. |
| `avoidOrphansInLists` | `boolean` | `true` | حين تكون `true`، تنال بنود القوائم أيضًا الحماية من الأسطر اليتيمة (لا الفقرات وحدها). لا يكون فعّالًا إلا حين تكون `avoidOrphans` هي `true`. |
| `avoidWidows` | `boolean` | `true` | اثنِ الفقرة عن أن تبدأ بأقل من `widowMinLines` سطرًا في أسفل العمود الحالي. وعلى شبكة المحارف (`cjk.grid`) تكون القيمة الافتراضية `false`: فالصفحة تحمل الأسطر التي تعدّها شبكتها. |
| `widowMinLines` | `number` | `2` | أدنى عدد من الأسطر مطلوب في أسفل العمود الحالي حين تنقسم الفقرة. لا يعمل إلا حين تكون `avoidWidows` هي `true`. |
| `widowPenalty` | `number` | `1000` | نقاط الجزاء المضافة عند مخالفة قيد الأسطر الأرامل. `0` يعطّل الجزاء. |
| `avoidWidowsInLists` | `boolean` | `true` | حين تكون `true`، تنال بنود القوائم أيضًا الحماية من الأسطر الأرامل. لا يكون فعّالًا إلا حين تكون `avoidWidows` هي `true`. |
| `shortListSplit` | `'allow' \| 'warn' \| 'avoid'` | `'allow'` | قائمة قصيرة مقسومة بين عمودين أو صفحتين: قائمة في النص الجاري لا تزيد بنودها على `shortListMaxItems`، كقائمة من ثلاثة بنود تُنضَّد 1 + 2. يُبقي `avoidOrphansInLists` و`avoidWidowsInLists` أسطر البند الواحد معًا؛ أما هذه القاعدة فتُبقي بنود القائمة الواحدة معًا. تقسم `'allow'` مثل هذه القائمة حيث ينتهي العمود، كأي قائمة أخرى. وتنضّدها `'warn'` بالطريقة نفسها وتبلّغ عن كل قائمة مقسومة (تحذير `shortListSplit`، انظر [التحذيرات في المستند](https://postext.dev/ar/docs/configuration-programmatic-usage.md#التحذيرات-في-المستند)). وتنضّد `'avoid'` القائمة كاملة: فإن لم تتسع تحت ما في العمود انتقلت إلى العمود التالي، ومعها العناوين التي فوقها مباشرة وسطر النقطتين الذي يقدّمها (`keepColonWithList`). والقائمة الأطول من عمود فارغ تُقسم كأي قائمة أخرى، ويُبلَّغ عنها. والقوائم داخل `:::callout` تتبع قواعد القطع الخاصة بالإطار، وصفوف `:::toc` ومداخل `:::index` ليست قوائم. منذ postext 1.28. |
| `shortListMaxItems` | `number` | `3` | أقصى عدد من البنود تُعدّ معه القائمة قصيرة في `shortListSplit`، وتُحسب فيه بنود قوائمها المتداخلة. عدد صحيح، 1 على الأقل. منذ postext 1.28. |
| `avoidRunts` | `boolean` | `true` | اثنِ الفقرات عن الانتهاء بسطر أخير قصير جدًا — *كلمة معزولة* (runt)، كأن تقف كلمة قصيرة واحدة وحدها. والنص غير المضبوط أيضًا، مع `optimalRagged`. والفقرة الصينية أو اليابانية أو الكورية لا تنتهي بسطر يحوي محرفًا واحدًا، وحده أو مع علامات إغلاقه (孤字): يعطيه السطر الذي فوقه محرفه الأخير حين يظل ممكنًا ضبط ذلك السطر ضمن سقف التتبّع. والسطر المحاذى إلى اليسار أو اليمين أو الموسَّط يتنازل عنه كذلك فيقصر حرفًا واحدًا؛ ومع `cjk.grid.fullLines` (ورق المخطوطات) يحتفظ بكل خاناته، وقد تنتهي الفقرة بحرف واحد. |
| `runtMinCharacters` | `number` | `20` | عتبة السطر الأخير من الفقرة، محسوبة بالمسافات بين الكلمات لا بالحروف: يكون السطر كلمة معزولة حين يكون أضيق من `runtMinCharacters × normalSpaceWidth` بكسل. المسافة بين الكلمات ربع إلى ثلث em في معظم خطوط النصوص، أي نحو نصف حرف صغير (lowercase)، فالقيمة الافتراضية 20 تلتقط الأسطر الأخيرة الأقل من 4 إلى 7 em — نحو 8 إلى 12 حرفًا. لالتقاط الأسطر الأخيرة الأقل من نحو N حرفًا، اضبطها قرب 2 × N. |
| `runtPenalty` | `number` | `1000` | رداءة مكافئة تُحقن في صيغة نقاط الجزاء التربيعية لـ Knuth–Plass (بمقياس *رداءة* السطر (badness) نفسه، التي تتشبّع عند 10000). `0` يعطّل الجزاء. |
| `gradedRuntPenalty` | `boolean` | `false` | اجعل جزاء الكلمة المعزولة متناسبًا مع مقدار قِصَر السطر الأخير: السطر الأخير الذي عرضه *w* تحت العتبة *t* يكلّف `runtPenalty × (1 − w / t)` بدلًا من الجزاء كله. فتكلّف النهاية المكوّنة من كلمتين أقل من النهاية المكوّنة من كلمة واحدة، ويُنزل الكاسر كلمة حين يستطيع سطر أعلى التخلّي عنها ('…sallies of' / 'our minds.' بدلًا من '…sallies of our' / 'minds.'). معطّل افتراضيًا: كل كلمة معزولة تكلّف القدر نفسه، ويُبقي الكاسر الأسطر الأضيق في الأعلى. |
| `avoidRuntsInLists` | `boolean` | `true` | حين تكون `true`، تنال بنود القوائم أيضًا جزاء الكلمة المعزولة. لا يكون فعّالًا إلا حين تكون `avoidRunts` هي `true`. |
| `tightenRunts` | `boolean` | `true` | حين يعجز الجزاء عن تجنّب كلمة معزولة، نضّد الفقرة بسطر أقل بدلًا من ذلك: تضيق المسافات بين الكلمات (دون تجاوز `minWordSpacing` أبدًا)، وإن لم يكفِ ذلك وحده لاستيعاب السطر، ينضمّ قليل من التتبّع السالب. ويُرفض التنضيد الأقصر، وتبقى الكلمة المعزولة، حين يمدّ سطرًا مضبوطًا إلى ما بعد `maxWordSpacing` أو، إذا كان في الفقرة أصلًا سطر مضبوط أكثر ارتخاءً، إلى ما بعد ذلك السطر، أو حين ينضّد أسطرًا غير مضبوطة (بعد 3× المسافة العادية) أكثر مما كان في الفقرة. والمسافات بين الكلمات في النص غير المضبوط تحتفظ بعرضها، فلا يشارك هناك إلا التتبّع. يتطلب `optimalLineBreaking` و`avoidRunts` (و`optimalRagged` للنص غير المضبوط). |
| `maxRuntTracking` | `number` | `10` | أقصى تتبّع يجوز أن يأخذه إصلاح الكلمة المعزولة، بأجزاء الألف من em (وحدة InDesign: 10 = 0.01 em لكل حرف)، ويُطبَّق تضييقًا. `0` يترك الإصلاح لتباعد الكلمات وحده. |
| `slackWeight` | `number` | `10` | الوزن المطبّق على الكلفة التربيعية لـ«مساحة العمود غير المستخدمة». القيم الأعلى تجعل الإخراج يفضّل ملء الأعمدة بإحكام؛ و`0` يعطّل ضغط الفراغ تمامًا. |
| `keepColonWithList` | `boolean` | `true` | حين تنتهي فقرة بنقطتين تقدّمان قائمة مباشرة، أبقِ السطر الأخير الحامل للنقطتين متصلًا بالقائمة: إن كان وضع الفقرة لن يترك متّسعًا لبدء أول بند من القائمة في العمود أو الصفحة نفسها، يُنقل السطر الأخير (أو الفقرة كلها، إن كانت سطرًا واحدًا) إلى العمود التالي مع القائمة. ومقدار المتّسع الكافي يحدّده `colonListRoom`. وحين تدفع هذه القاعدة الفقرة كلها وتسبقها مباشرة في العمود سلسلة من العناوين، تُسحب تلك العناوين معها أيضًا ليظل `headings.keepWithNext` نافذًا. |
| `colonListRoom` | `'item' \| 'line'` | `'item'` | المتّسع الذي يطلبه `keepColonWithList` تحت سطر النقطتين. `'item'`: ما تتركه قواعد الأسطر اليتيمة والأرامل للقوائم من البند الأول في أسفل العمود، سطرًا حين يجوز أن ينقسم هناك، وكلّه حين تُبقيه كاملًا (بند من سطرين، مثلًا). `'line'`: سطر واحد، كما حتى postext 1.4؛ فالبند الأول الذي تُبقيه تلك القواعد كاملًا ينتقل حينئذ إلى العمود التالي وحده ويترك سطر النقطتين في أسفل العمود. والإعدادات المخزَّنة قبل `configVersion` 6، في كتاب يقدّم قائمة بنقطتين، تُقرأ بـ `'line'` (انظر [الحزم المكتوبة بـ postext 1.4 أو ما قبله](https://postext.dev/ar/docs/configuration-bundles.md#الحزم-التي-كتبها-postext-14-أو-ما-قبله)). وأي قيمة أخرى تُقرأ `'item'`. |
| `hyphenateAcrossColumns` | `boolean \| 'withinPage'` | `true` | اسمح للعمود أو الصفحة بأن ينتهي بكلمة مقسومة بالواصلة (*Hyphenate Across Column* في InDesign). القيمة `false` تعيد كسر الفقرة التي تعبر فاصل العمود، لينتهي سطرها الأخير في العمود بكلمة كاملة؛ وتمتصّ المسافاتُ بين كلمات الأسطر التي فوقه الفرقَ، ضمن `maxWordSpacing` و`minWordSpacing`. وهو تفضيل: حيث لا يتجنّبه أي كسر ضمن تلك الحدود، تبقى الواصلة. يجرّب كل فاصل عمود في الفقرة: الأول، واللاحقة التي تقع حيث ينتهي عمود ممتلئ، في إعادة كسر واحدة؛ والفاصل اللاحق الذي يقع في موضع آخر (سطر أرملة أُبقي، أو شريط قُطع عند مستوى واحد) في إعادة كسر أخرى، من ذلك العمود، تُبقي الأسطر المنضَّدة في الأعمدة السابقة عند نقاط كسرها ولا تكسر إلا الباقي. والقيمة `'withinPage'` تحرس الأسطر التي تختم الصفحة دون غيرها: يجوز أن تُقسم الكلمة بين عمودين في الصفحة الواحدة، وينتهي السطر الأخير في الصفحة بكلمة كاملة حيثما سمحت الحدود. وهي تغيّر أسطرًا أقل مما تغيّره `false`، ولذلك وزنه في ثلاثة أعمدة أو أكثر، حيث تقع نهايتا عمودين من كل ثلاث داخل الصفحة؛ وفي العمود الواحد تعطي القيمتان الأسطر نفسها. ويختم العمود صفحته حين لا يستقبل نصًّا أيُّ عمود بعده في الصفحة: فالعمود الجانبي المخصص للعناصر العائمة لا يستقبله، ولا العمود الذي ملأه جدول أو شكل. لا تتأثر متون الأطر. ومع `optimalRagged`، يُعاد كسر الفقرة غير المضبوطة بالطريقة نفسها: تحتفظ المسافات بين كلماتها بعرضها، فلا تتحرك إلا نهايات أسطرها. وكل إعادة كسر تقيس الفقرة مرة أخرى، فالكتاب الذي فيه كثير من الواصلات في نهايات الأعمدة يُخرَج أبطأ قليلًا. يتطلب `optimalLineBreaking`، و`optimalRagged` للنص غير المضبوط. |
| `paragraphContainerSpacing` | `'collapse' \| 'add'` | `'collapse'` | المسافة تحت حاوية `:::paragraphs` التي تُغلق على فقرة، بين تلك الفقرة والكتلة التي تليها (انظر [الحاوية `:::paragraphs`](https://postext.dev/ar/docs/configuration-styles.md#الحاوية-paragraphs)). `'collapse'`: الأكبر من `spaceBetween` و`marginBottom` الخاصين بالنمط ومن تباعد الفقرات في النص المحيط بالحاوية (سطر مع `paragraphSpacing`؛ وفي الإطار، تباعد الإطار)، مدمجًا مع المسافة التي تُبقيها الكتلة التالية فوقها، كما بين فقرتين من النص الجاري: فالعنوان الواقع تحت قائمة مراجع يقع على بُعد `marginTop` الخاص به تحتها، لا ذلك الهامش مضافًا إليه تباعد المدخلات. `'add'`: كما حتى postext 1.4، تُوضع مسافة النمط وحدها تحت السطر الأخير قبل المحاذاة إلى الشبكة، وتُضاف تحتها المسافة التي تُبقيها الكتلة التالية فوقها، ويُستبعد تباعد الفقرات، فقد تقع الفقرة التالية للحاوية أقرب إليها من أي فقرة أخرى. والإعدادات المخزَّنة قبل `configVersion` 8 التي تعرّف نمط فقرة، في كتاب يحوي مثل هذه الحاوية، تُقرأ بـ `'add'` (انظر [الحزم المكتوبة بـ postext 1.4 أو ما قبله](https://postext.dev/ar/docs/configuration-bundles.md#الحزم-التي-كتبها-postext-14-أو-ما-قبله)). والقيمة السالبة لـ `marginBottom` تسحب الكتلة التالية إلى الأعلى في الحالتين. ويستطيع نمط الفقرة أن يحدّد قاعدته الخاصة لحاوياته (`containerSpacing`، منذ postext 1.28). |

**عن الكلمات المعزولة.** الكلمة المعزولة فقرةٌ سطرها الأخير أقصر من أن يبدو سطرًا حقيقيًا من النص — عادةً كلمة أو كلمتان قصيرتان منقطعتان في آخر الفقرة. ولأن الفحص يقوم على طول السطر بالبكسل نسبةً إلى عرض المسافة العادية، يتكيّف `runtMinCharacters` تلقائيًا مع حجم الخط الحالي. الكلمة القصيرة التي تكون بصريًا أعرض من `runtMinCharacters × spaceWidth` لا بأس بها؛ أما الكلمة الأضيق من ذلك (أو المنفردة فعلًا) فتستجلب جزاء الكلمة المعزولة. تحسب العتبة المسافات بين الكلمات، وعرضها نحو نصف عرض الحروف: فالقيمة الافتراضية 20 تعني سطرًا أخيرًا من نحو 8 إلى 12 حرفًا. كل كلمة معزولة تكلّف الجزاء كله، فبين نهايتين تحت العتبة يُبقي الكاسر الأسطر الأضيق في الأعلى؛ أما `gradedRuntPenalty` فيسعّر كلًّا منهما بمقدار قصورها، فتفوز النهاية الأطول. ولمن يهمّه الحساب: عند القيمة الافتراضية 1000 لـ `runtPenalty`، يغلب تجنّبُ الكلمة المعزولة أيَّ مجموعة نقاط كسر بديلة تتطلب تمدّدًا في تباعد الكلمات حتى نحو r≈2.15.

**مرنة لا صارمة.** لا تستطيع أيٌّ من هذه القواعد أن *تمنع* كسرًا — فالمحرّك سينتج إخراجًا دائمًا. إنها نقاط جزاء: تُوازن الخوارزمية بين الرداءة وكلفة التقسيم بالواصلة وسلاسة فئات الملاءمة وهذه الجزاءات البنيوية في عملية تحسين شاملة واحدة، وتختار مجموعة نقاط الكسر ذات الكلفة الإجمالية الأدنى. إن احتجت ضمانًا أشدّ، فارفع الجزاء؛ وإن كان مستند ما يُقرأ أفضل مع جزاء مخفّف، فاخفضه.

## موازنة الأعمدة

يتوقع الناشرون أن يبدأ كل عمود عند أعلى الصفحة وأن ينتهي محاذيًا لأسفلها. لكن قواعد الفصل (حماية الأسطر اليتيمة والأرامل، وإبقاء العناوين مع نصها، والأشكال التي لا تنقسم) تترك بطبيعتها أعمدة قصيرة — سطرًا فارغًا أو أكثر من شبكة خطوط الأساس في أسفلها. عند تفعيل الموازنة يفعل المحرّك ما يفعله المنضّد، فيطبّق أدواته (levers) بترتيب الأولوية التحريرية:

1. **إطار يختم العمود** — الإطار الذي ينهي عمودًا قصيرًا يُدفع إلى الأسفل بمقدار المتسع الذي تحت قاعدته بالضبط، فتقع حافته السفلى على آخر خانة في شبكة الصفحة، بمحاذاة آخر سطر في العمود المجاور. ويأخذ ذلك المتسع حتى لو كان أقل من سطر، ما دام لا ينتقل شيء إلى عمود آخر. افتراضيًا يعمل قبل كل الأدوات الأخرى ويأخذ الفجوة كلها، فقد ينتهي الإطار الذي يعلّق على الفقرة التي فوقه على بعد عدة أسطر منها؛ والقيمة `closingBox: 'last'` تترك للعناوين ونهايات القوائم وأدوات المسافات الأخرى أن تأخذ الأسطر الكاملة أولًا، ولا يأخذ الإطار إلا ما تتركه، والقيمة `closingBox: 'off'` لا تحرّكه أبدًا.
2. **الصور ذات المنطقة الآمنة** — الصورة التي لها منطقة آمنة (`Resource.safeArea`، انظر [صيغة المستند › المنطقة الآمنة](https://postext.dev/ar/docs/document-format-resources.md#المنطقة-الآمنة)) المضمّنة في العمود القصير، أو العائمة في رأسه أو أسفله وفوقه وحده، تطول بأسطر كاملة من الشبكة، مقصوصة داخل منطقتها الآمنة، حتى يمتلئ العمود أو يبلغ القصّ المنطقة الآمنة. والصورة الأطول لا تترك فجوة في الصفحة، ولذلك تعمل هذه الأداة قبل إضافة أي مسافة؛ أما العنصر العائم في رأس عمود من صفحة أو شريط تبقى رؤوس أعمدته متساوية (انظر أدناه) فلا يطول. وتُسجَّل باسم `flexFigure`. وليس لها إعداد خاص: لا تطول إلا الصورة التي يحدّد موردها منطقة آمنة.
3. **العناوين** — تُضاف أسطر كاملة من الشبكة إلى الهامش العلوي للعناوين داخل العمود القصير. وإذا احتيج إلى عدة أسطر وكان في العمود عدة عناوين، وُزّعت الأسطر عليها، مع إعطاء الحصة الكبرى دائمًا للعنوان الأهم (يتلقى `h2` أكثر مما يتلقى `h3`). العناوين الواقعة في أعلى العمود تمامًا لا تتلقى مسافة إضافية أبدًا، فتظل الأعمدة تبدأ عند أعلى الصفحة — إلا العنوان الواقع مباشرة تحت شكل أو جدول يتصدّر عموده في صفحة يستمر تدفقها إلى التالية: هنا يذهب المتسع فوق ذلك العنوان، تحت الشكل. ويأخذ العنوان بهذه الطريقة `maxLinesBeforeLoose` سطرًا على الأكثر (سطران افتراضيًا) قبل تجربة الأدوات التالية، ولا يأخذ بقية أسطره، حتى `maxLinesPerHeading`، إلا حين لا يبقى لديها ما تعطيه.
4. **نهايات القوائم** — حين لا تستطيع العناوين استيعاب الفجوة كلها، يُضاف سطر من الشبكة حيث تنتهي قائمة أو تعداد (المسافة بعد القائمة تبدو طبيعية للقارئ)، مع حد أقصى لكل نهاية قائمة.
5. **تحت المعادلات والإطارات والأشكال** — ثم يُضاف سطر من الشبكة تحت معادلة مستقلة أو إطار يُستأنف النص بعده (`stretchAfterDisplays`؛ ويُقرأ كأنه هامش العنصر نفسه)، وتحت شكل أو جدول يتصدّر العمود (`stretchAfterFloats`، بحدّ `maxLinesAfterFloat`).
6. **الفقرات المرخاة** — في آخر المطاف، يُعاد تقسيم فقرة واحدة من العمود إلى أسطر بحيث تزيد سطرًا واحدًا (`\looseness=+1` في TeX)، ويُختار أطول فقرة كي تتوزع المسافة الإضافية بين الكلمات دون أن تُلحظ. لا يُقبل الحل المرخى إلا إذا بقي كل سطر **دون `bodyText.maxWordSpacing`** — فلا تتجاوز كثافة الطباعة (type colour) الحد الذي ضبطته أصلًا. يتطلب `bodyText.optimalLineBreaking`.

في شبكة المحارف (`cjk.grid`، انظر [الإخراج الصيني › شبكة المحارف](https://postext.dev/ar/docs/chinese-layout.md#شبكة-المحارف)) يقف كل محرف في خانة عرضها em واحد، ويقع كل سطر على خطوة أسطر الشبكة، وهي أيضًا شبكة خطوط الأساس. والموازنة معطّلة هناك افتراضيًا، كما في النص العمودي: فالصفحة المنضّدة سطرًا سطرًا على شبكة، على نحو ما يعدّ GB/T 9704 الصفحة 22 سطرًا من 28 محرفًا، تترك العمود القصير قصيرًا. والإعدادات التي تضبط `enabled: true` تحصل على أدوات تحافظ على الشبكة: العناوين ونهايات القوائم والمعادلات المنفصلة والأشكال تأخذ أسطرًا كاملة من الشبكة، فينزل النص الذي تحتها بصفوف كاملة، و`gridLines: 'off'` تستبعد هذه الأدوات حين يكون المعيار لا يملك صفًّا فارغًا يتنازل عنه. ولا تطول الفقرة الصينية أو اليابانية سطرًا إلا إذا لم تتّسع أي فجوة بين محرفين من محارفها أكثر من `maxTracking`، ولا يُضاف إلى حروفها تتبّع: فالسطر الناقص محرفًا واحدًا يوزّع em كاملًا على فجواته، وهذا أبعد كثيرًا من القيمة الافتراضية 0.01 em، ولذلك لا تجد أداة الفقرات المرخاة في الغالب شيئًا على شبكة من خانات كاملة. أما الإطار الذي يختم العمود والصور ذات المنطقة الآمنة فهي خارج الشبكة عن قصد، وتعمل كما تعمل في أي مكان آخر.

لا يُوازَن العمود الأخير من الصفحة إلا إذا كان تدفق الصفحة يستمر طبيعيًا إلى التالية — فمن الطبيعي أن تنتهي الصفحة الأخيرة من الفصل قصيرة. وهذه الصفحة، وكذلك الشريط الختامي الذي يقطعه `trailing` قطعًا متساويًا، تحافظ أيضًا على تساوي رؤوس أعمدتها: لا يُضاف سطر تحت شكل أو جدول يتصدّر أحد أعمدتها (أداة ما بعد العنصر العائم)، والعنوان أو الإطار الذي يفتتح عمودًا تحت مثل هذا الشكل يبقى في رأسه، مهما كانت قيمة `stretchAfterFloats`، وكذلك العنوان الذي يلي مباشرةً افتتاحية `span: 'page'` في عمود الافتتاحية نفسه، فلا يبدأ عمود أدنى من العمود المجاور لمجرد مساواة الأسافل.

| الخاصية | النوع | الافتراضي | الوصف |
| --- | --- | --- | --- |
| `enabled` | `boolean` | `true` | هل تُوازَن أسافل الأعمدة. معطّلة افتراضيًا في النص العمودي (`layout.writingMode: 'vertical-rl'`) وفي شبكة المحارف (`cjk.grid.enabled`، منذ postext 1.25)؛ والقيمة `true` تفعّلها هناك أيضًا. |
| `maxLinesPerHeading` | `number` | `4` | الحد الأقصى لأسطر الشبكة الإضافية التي يمكن إضافتها فوق عنوان واحد. |
| `maxLinesBeforeLoose` | `number` | `2` | أسطر الشبكة التي يأخذها العنوان قبل تجربة الأدوات التالية: نهايات القوائم، والمعادلات والإطارات، والأشكال، والفقرات المرخاة. ولا يأخذ العنوان بقية أسطره، حتى `maxLinesPerHeading`، إلا حين لا يبقى لدى تلك الأدوات ما تعطيه، فلا تفتح صفحة فيها عنوان واحد أربعة أسطر فوقه وفقراتها قادرة على أن تطول سطرًا. والقيمة المساوية لـ`maxLinesPerHeading` أو الأكبر منها تعطي العناوين كل أسطرها أولًا، كما كان حتى postext 1.27؛ و`0` تجرّب الأدوات الأخرى قبل إضافة أي سطر فوق عنوان. منذ postext 1.28؛ والمستندات المحفوظة قبل ذلك تحتفظ بالترتيب السابق (`pinLegacyLooseOrder`). |
| `stretchAfterLists` | `boolean` | `true` | السماح بأسطر شبكة إضافية حيث تنتهي قائمة، حين لا تستطيع العناوين استيعاب الفجوة كلها. |
| `maxLinesAfterList` | `number` | `1` | الحد الأقصى لأسطر الشبكة الإضافية بعد نهاية قائمة واحدة. |
| `stretchAfterDisplays` | `boolean` | `true` | السماح بسطر شبكة إضافي تحت معادلة مستقلة، وتحت إطار، في العمود القصير، بعد أداة نهاية القائمة: تنزل الكتلة التي تليه سطرًا. اضبطه على `false` ليبقى الفراغ تحت المعادلات والإطارات كما تحدده هوامشها؛ فتنتقل الفجوة إلى الأدوات التالية وينتهي العمود قصيرًا إن لم تسدّها. منذ postext 1.28. |
| `stretchAfterFloats` | `boolean` | `true` | السماح بأسطر شبكة إضافية تحت شكل أو جدول يتصدّر العمود القصير (عنصر عائم علوي)، بعد أداة نهاية القائمة، فينزل النص الذي تحته بدل أن ينتهي العمود قصيرًا. لا يعمل أبدًا في صفحة لا يستمر تدفقها (الصفحة الأخيرة من فصل) ولا في شريط ختامي يقطعه `trailing` قطعًا متساويًا: هناك تبقى رؤوس الأعمدة متساوية وقد ينتهي العمود الأخير أقصر بسطر. قد تكون الكتلة الأولى تحت الشكل بقيةَ فقرة بدأت في الصفحة السابقة: تنزل هي أيضًا، بمقدار السطر الذي تركته قواعد الفصل خاليًا في أسفل العمود (سطر أبقته قاعدة الأرملة فارغًا، أو مسافة فقرة لا متسع بعدها لنص). اضبطه على `false` لإبقاء النص مباشرة تحت الشكل. وتحت عنصر عائم يمتد على عدة أعمدة تنزل الأعمدة معًا أو لا تنزل: انظر `stretchAfterWideFloats`. |
| `maxLinesAfterFloat` | `number` | `1` | الحد الأقصى لأسطر الشبكة الإضافية تحت عنصر عائم علوي واحد. |
| `stretchAfterWideFloats` | `'flush' \| 'always'` | `'flush'` | تحت شكل أو جدول يمتد على عمودين نصيين أو أكثر. مع `'flush'` لا ينزل العمود تحته إلا إذا أخذت كل الأعمدة النصية التي تحت العنصر العائم الأسطر نفسها، فتبقى رؤوسها متساوية، أو إذا أتمّت الأسطر ذلك العمود حتى أسفله؛ فلا يُضاف سطر يُنزل رأس عمود واحد ويتركه قصيرًا مع ذلك، وتنتقل الفجوة إلى الفقرات المرخاة. و`'always'` تمدّد هذا العمود كما تحت أي عنصر عائم، كما كان حتى postext 1.27. وأي قيمة أخرى تُقرأ `'flush'`. منذ postext 1.28؛ والمستندات المحفوظة قبل ذلك تحتفظ بـ`'always'` (`pinLegacyWideFloatStretch`). |
| `looseParagraphs` | `boolean` | `true` | آخر الأدوات: إعادة تقسيم فقرات العمود القصير بإرخاء يزيدها سطرًا (سطر إضافي لكل منها)، ضمن حدود `bodyText.maxWordSpacing`. |
| `maxLooseParagraphs` | `number` | `2` | عدد فقرات العمود القصير الواحد التي يجوز أن تطول سطرًا، بدءًا بالأطول. |
| `trackParagraphs` | `boolean` | `true` | حين لا يكفي تباعد الكلمات وحده لكسب السطر، يجوز للفقرة المرخاة أن تأخذ أيضًا أصغر تتبّع موجب (تباعد الحروف) يحقق ذلك. |
| `maxTracking` | `number` | `10` | الحد الأعلى لذلك التتبّع، بأجزاء الألف من em لكل حرف (10 = 0.01 em). |
| `trailing` | `boolean` | `true` | مساواة الشريط الختامي للفصل وللمستند: حين ينتهي التدفق قبل امتلاء الصفحة (عند صفحة افتتاح فصل، أو `:::part`، أو إطار `placement: 'fixed'` يختم الفصل، أو نهاية المستند) وأعمدته غير متساوية، تُقطع قطعًا متساويًا — بحد أقصى للشريط قدره `ceil(Σ used / N / grid)` سطرًا، يُحسب بعد أن تستقر الأدوات السابقة على الصفحات الأسبق — فتنتهي قائمة مراجع قصيرة على الارتفاع نفسه في كل عمود بدل أن تملأ العمود الأول وتترك الأخير نصف فارغ. يحافظ القطع على القواعد التي يحافظ عليها شريط غير مقطوع: إذا كانت كتلة لا يمكن تقسيمها عبره (ذيل فقرة يبقيه الحدّان الأدنيان لليتيمة والأرملة كاملًا، أو إطار يبقى متماسكًا) ستتجاوزه — فتفقد أسطرها الأخيرة، لأن المُخرِجات تقصّ العمود عند حدود صندوقه — أو كان عنوان سيختم عمودًا بينما يفتتح نصه العمود التالي (مع `headings.keepWithNext`، وهو الافتراضي)، يؤخذ القطع أدنى بسطر، حتى ثلاث مرات، وإلا أُلغي. الكتلة التي لا تستطيع أن تبدأ في الأسطر التي يتركها القطع تحت شكل يتصدّر عمودًا (تحتاج الفقرة هناك إلى حدها الأدنى لليتيمة) تنتقل إلى العمود التالي من الشريط، كما تفعل من عمود غير مقطوع، ويقف الشكل وحده في عموده. الأعمدة التي تختلف أسافلها بسطر شبكة واحد أو أقل تُترك كما هي: الشريط الختامي الذي ينتهي عموده الأخير أقصر بسطر هو الخاتمة المعتادة، وقطعه لن يفعل سوى نقل سطر. يذهب القطع إلى الشريط الذي قيس فيه، وكذلك القطع الذي يطلبه إطار يمتد بعرض الصفحة في منتصفها: حتى postext 1.4، حين كان أول نص في الصفحة الختامية قد عُرض أولًا على شريط لا متسع فيه له (صفحة يشغلها عنصر عائم كلها، أو الشريط الرفيع الذي يتركه إطار يمتد بعرض الصفحة في أسفل الصفحة السابقة)، كان القطع يُستهلك في ذلك الشريط وتُبقي الصفحة الختامية كل سطر في عمودها الأول. الأعمدة المختلفة العرض (تخطيط عمود ونصف فيه نص في العمودين) تُقطع بحسب المساحة، فيُرجَّح ارتفاع كل عمود بعرضه، لأن سطر العمود الضيق يتسع لقدر أقل من النص. لا يعمل إلا حين تكون قيمة `enabled` هي true. |
| `trailingStep` | `'lines' \| 'grid'` | `'lines'` | وحدة القطع المتساوي الذي يجريه `trailing` (والقطع الذي يجريه `beforeSpan` خلف إطار ينتقل إلى الصفحة التالية). `'lines'`: الشريط الذي يُضبط نصه على تباعد أسطر خاص به (فهرس، قائمة مراجع، حاوية بحرف صغير) يُقطع، ويُعاد المحاولة، بأسطر كاملة من ذلك التباعد: الارتفاع الذي تشترك فيه معظم أسطر الشريط، ما عدا العناوين والإطارات. فتنتهي أعمدته بفارق سطر على الأكثر، كما في شريط من النص الأساسي. وشريط النص الأساسي، والشريط الذي يمزج تباعدين بالتساوي، يُقطع على شبكة خطوط الأساس كما كان. وكذلك الشريط الذي تشترك أسطره في الارتفاع ويفصل بينها جزء من سطر (مراجع بين مداخلها مسافة، أو مجموعات فهرس بهامش موضوع يدويًا): يجب أن يبعد أربعة أسطر من كل خمسة في العمود الواحد عددًا صحيحًا من الأسطر بعضها عن بعض. `'grid'`: كل قطع عدد صحيح من أسطر شبكة خطوط الأساس، كما كان حتى postext 1.27، حيث كان القطع على الشبكة يُدخل سطرًا زائدًا في عمود من شريط خارج الشبكة، وكان القطع الفاشل ينزل أكثر من سطر من أسطره (أعمدة بفارق يصل إلى ثلاثة أسطر). وأي قيمة أخرى تُقرأ `'lines'`. منذ postext 1.28؛ والمستندات المحفوظة قبل ذلك تحتفظ بـ`'grid'` (`pinLegacyTrailingStep`). |
| `beforeSpan` | `boolean` | `true` | مساواة الشريط الذي تتركه كتلة تمتد بعرض الصفحة: حين لا يتسع إطار `span: 'page'` تحت الأعمدة الحالية حتى بعد قطع متساوٍ، ويجب أن ينتقل إلى الصفحة التالية أو ينقسم (`calloutStyles[].keepTogether: false`)، تُقطع الأعمدة التي يقاطعها قطعًا متساويًا — بالحد الختامي نفسه الذي يناله الشريط الختامي — بدل أن يملأ الأول الصفحة وينتهي الأخير قصيرًا. تُترك الصفحة فاصلًا صريحًا كي لا تمدّ الأدوات السابقة عمودها الأخير من جديد حتى أسفل الصفحة؛ ثم يستقر الإطار، أو الجزء الذي يتسع منه، تحت الأعمدة المتساوية. لا يعمل إلا حين تكون قيمة `enabled` هي true. |
| `closingBox` | `'first' \| 'last' \| 'off'` | `'first'` | متى يأخذ الإطار الذي يختم عمودًا قصيرًا المتسعَ الذي تحت قاعدته (الأداة 1، وتُسجَّل باسم `trailingCallout`). `'first'`: قبل أي أداة أخرى، كما كان الحال حتى postext 1.4 — يأخذ الإطار الفجوة كلها، ولو كانت عدة أسطر، ولا تنال العناوين التي فوقه شيئًا. `'last'`: بعد أدوات العناوين ونهايات القوائم والمعادلات المنفصلة والعناصر العائمة، التي تأخذ الأسطر الكاملة أولًا؛ ينزل الإطار مع النص الذي فوقه ثم لا يأخذ إلا ما تركته، وهو عادة جزء من سطر، فتلتقي قاعدته بآخر خانة في الشبكة ويبقى قريبًا من النص الذي يعلّق عليه. `'off'`: أبدًا؛ يحتفظ الإطار بالمتسع الذي تحت قاعدته، وإن كانت الأدوات الأخرى تستطيع إنزاله بأسطر كاملة حين تضيف مسافة فوقه، ويبقى جزء السطر المتروك تحته. في الصفحة الختامية، حيث الإطار هو الأداة الوحيدة التي تساوي قاعدته بالعمود المجاور، تتركه `'off'` حيث وضعه التدفق. أي قيمة أخرى تُقرأ `'first'`. أما الإطار الذي يُغلق عمود النص الوحيد في شريطه (صفحة ذات عمود واحد تنتهي مبكرًا وتبدأ كتلتها التالية الصفحة التالية) فلا يُحرَّك أبدًا: لا عمود بجانبه يُحاذى معه (منذ postext 1.19). |
| `gridLines` | `'allow' \| 'off'` | `'allow'` | في شبكة المحارف: هل يجوز أن تعمل الأدوات التي تضيف أسطرًا كاملة من الشبكة (فوق العنوان، وحيث تنتهي قائمة، وتحت معادلة منفصلة أو إطار، وتحت شكل يتصدّر العمود). وهي تُبقي كل محرف في خانته؛ و`'off'` تناسب معيارًا يعدّ أسطر الصفحة، فتترك العمود قصيرًا بدلًا من ذلك. لا أثر لها خارج الشبكة. أي قيمة أخرى تُقرأ `'allow'`. منذ postext 1.25. |

### أيّ أداة عملت

يسجّل الإخراج كل أداة طبّقها، على الكتلة التي طبّقها عليها: `block.balancing` في VDT الذي تعيده `buildDocument`. يمكن لبروفة أو اختبار أو تقرير أن يبيّن لماذا ينتهي عمود محاذيًا للأسفل — وأي الأعمدة لم تستطع أي أداة إغلاقها. الكتل التي تركتها الموازنة على حالها لا تحمل `balancing`، والمستند المبني مع `enabled: false` لا يحمل شيئًا منها.

في شبكة المحارف يبيّن المستند لماذا قد ينتهي عمود قصيرًا: تكون `doc.gridBalancing` هي `{ off: true }` حين تكون الموازنة معطّلة لأن الصفحة على شبكة والإعدادات لا تفعّلها، و`{ gridLines: 'off' }` حين تعمل بلا أدوات الأسطر الكاملة؛ والعمود الذي يبقى قصيرًا يحمل `column.gridRefused`، أي الأدوات التي منعته الشبكة منها (`'looseParagraph'` حين لا تكسب الفقرة سطرها إلا بمدّ محارفها خارج خاناتها، وأدوات الأسطر الكاملة في ظل `gridLines: 'off'`). ولا يوجد أيّ منهما خارج الشبكة.

```ts
interface VDTBalancing {
  levers: BalanceLever[]; // usually one: a paragraph after a list can take the list-end line and run a line long too
  spaceAbove: number;     // px the spacing levers added above the block (0 when only looseParagraph or flexFigure fired)
  bodyGrowth?: number;    // flexFigure: px the picture grew, cropped within its safe area
  extraLines?: number;    // looseParagraph: lines the paragraph gained
  tracking?: number;      // looseParagraph: the tracking that gained them, in thousandths of an em (0 = word spacing alone)
}
type BalanceLever = 'trailingCallout' | 'flexFigure' | 'heading' | 'listEnd' | 'afterDisplay' | 'afterFloat' | 'looseParagraph';
```

| الأداة | تُسجَّل على | ما فعلته |
| --- | --- | --- |
| `trailingCallout` | كتلة حدود الإطار | إطار يختم العمود نزل بمقدار المتسع الذي تحت قاعدته بالضبط (`spaceAbove`؛ ولا بأس بجزء من سطر). |
| `flexFigure` | كتلة الصورة (المضمّنة) أو العنصر العائم | صورة ذات منطقة آمنة طالت `bodyGrowth` px بأسطر كاملة من الشبكة، مقصوصة داخل المنطقة الآمنة. و`bodySource` في كتلة المورد هو الجزء الظاهر، و`bodyFlex.delta` هو مقدار الإطالة نفسه. |
| `heading` | العنوان | أسطر شبكة كاملة فوق العنوان، حتى `maxLinesPerHeading`. |
| `listEnd` | أول كتلة بعد القائمة | سطر شبكة حيث تنتهي قائمة، حتى `maxLinesAfterList`. |
| `afterDisplay` | الكتلة التي تلي المعادلة أو الإطار | سطر شبكة تحت معادلة منفصلة أو إطار. |
| `afterFloat` | أول كتلة في العمود | سطر شبكة بين شريط عناصر عائمة يتصدّر العمود ونصه، حتى `maxLinesAfterFloat`. |
| `looseParagraph` | الفقرة | الفقرة بعد إعادة تقسيمها أطول بمقدار `extraLines`، بأصغر تتبّع حقق ذلك (`tracking`؛ وقيمة `block.letterSpacing` هي القيمة نفسها بالبكسل). |

تُسجَّل القطوع المتساوية على الأعمدة التي قطعتها: قيمة `column.bandCapped` هي true على كل عمود قُطع قطعًا متساويًا (الشريط الذي يتركه إطار يمتد بعرض الصفحة، أو شريط ختامي)، و`column.trailingCap` تعلّم أيضًا الشريط الختامي لفصل أو للمستند (`trailing`).

```ts
import { buildDocument } from 'postext';

const doc = buildDocument(content, config);
for (const page of doc.pages) {
  page.columns.forEach((column, i) => {
    const levers: string[] = column.blocks.flatMap((block) => block.balancing?.levers ?? []);
    if (column.trailingCap) levers.push('closing band cut level');
    else if (column.bandCapped) levers.push('band cut level');
    if (levers.length > 0) console.log(`page ${page.index + 1}, column ${i + 1}: ${levers.join(', ')}`);
  });
}
// page 3, column 1: heading, heading
// page 3, column 2: listEnd, looseParagraph
```
