Skill: yinin2005/minimax-docx-yinin (version 1.0.0)

--- AIGC: ContentProducer: Minimax Agent AI ContentPropagator: Minimax Agent AI Label: AIGC ProduceID: 9d5a8b3d82a01e0f24fae0fc2985a5c1 PropagateID: 9d5a8b3d82a01e0f24fae0fc2985a5c1 ReservedCode1: 304402202866606e6ad9dc0e4f624c67e85f82e9617260f7346116caa0a1fdb9f128680c02202f46fdfd4daab5f6da467fd0b323b4512ec66ce0e30cab8379ef68787ac95abb ReservedCode2: 304502206044c98043ad51077bc4cfd8d35829415d3883454a872d97e808b06c66e75a1d022100c6eec4cff27ee43cc2783b3e9a1af0b6b9812219bf6af5c78897f8e67f13540c description: | Professional DOCX document creation, editing, and formatting using OpenXML SDK (.NET). Three pipelines: (A) create new documents from scratch, (B) fill/edit content in existing documents, (C) apply template formatting with XSD validation gate-check. MUST use this skill whenever the user wants to produce, modify, or format a Word document — including when they say "write a report", "draft a proposal", "make a contract", "fill in this form", "reformat to match this template", or any task whose final output is a .docx file. Even if the user doesn't mention "docx" explicitly, if the task implies a printable/formal document, use this skill. license: MIT metadata: author: MiniMaxAI category: document-processing sources: - ECMA-376 Office Open XML File Formats - GB/T 9704-2012 Layout Standard for Official Documents - IEEE / ACM / APA / MLA / Chicago / Turabian Style Guides - Springer LNCS / Nature / HBR Document Templates version: 1.0.0 name: minimax-docx triggers: - Word - docx - document - 文档 - Word文档 - 报告 - 合同 - 公文 - 排版 - 套模板 --- # minimax-docx Create, edit, and format DOCX documents via CLI tools or direct C# scripts built on OpenXML SDK (.NET). ## Setup **First time:** `bash scripts/setup.sh` (or `powershell scripts/setup.ps1` on Windows, `--minimal` to skip optional deps). **First operation in session:** `scripts/env_check.sh` — do not proceed if `NOT READY`. (Skip on subsequent operations within the same session.) ## Quick Start: Direct C# Path When the task requires structural document manipulation (custom styles, complex tables, multi-section layouts, headers/footers, TOC, images), write C# directly instead of wrestling with CLI limitations. Use this scaffold: ```csharp // File: scripts/dotnet/task.csx (or a new .cs in a Console project) // dotnet run --project scripts/dotnet/MiniMaxAIDocx.Cli -- run-script task.csx #r "nuget: DocumentFormat.OpenXml, 3.2.0" using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Packaging; using DocumentFormat.OpenXml.Wordprocessing; using var doc = WordprocessingDocument.Create("output.docx", WordprocessingDocumentType.Document); var mainPart = doc.AddMainDocumentPart(); mainPart.Document = new Document(new Body()); // --- Your logic here --- // Read the relevant Samples/*.cs file FIRST for tested patterns. // See Samples/ table in References section below. ``` **Before writing any C#, read the relevant `Samples/*.cs` file** — they contain compilable, SDK-version-verified patterns. The Samples table in the References section below maps topics to files. ## CLI shorthand All CLI commands below use `$CLI` as shorthand for: ```bash dotnet run --project scripts/dotnet/MiniMaxAIDocx.Cli -- ``` ## Pipeline routing Route by checking: does the user have an input .docx file? ``` User task ├─ No input file → Pipeline A: CREATE │ signals: "write", "create", "draft", "generate", "new", "make a report/proposal/memo" │ → Read references/scenario_a_create.md │ └─ Has input .docx ├─ Replace/fill/modify content → Pipeline B: FILL-EDIT │ signals: "fill in", "replace", "update", "change text", "add section", "edit" │ → Read references/scenario_b_edit_content.md │ └─ Reformat/apply style/template → Pipeline C: FORMAT-APPLY signals: "reformat", "apply template", "restyle", "match this format", "套模板", "排版" ├─ Template is pure style (no content) → C-1: OVERLAY (apply styles to source) └─ Template has structure (cover/TOC/example sections) → C-2: BASE-REPLACE (use template as base, replace example content with user content) → Read references/scenario_c_apply_template.md ``` If the request spans multiple pipelines, run them sequentially (e.g., Create then Format-Apply). ## Pre-processing Convert `.doc` → `.docx` if needed: `scripts/doc_to_docx.sh input.doc output_dir/` Preview before editing (avoids reading raw XML): `scripts/docx_preview.sh document.docx` Analyze structure for editing scenarios: `$CLI analyze --input document.docx` ## Scenario A: Create Read `references/scenario_a_create.md`, `references/typography_guide.md`, and `references/design_principles.md` first. Pick an aesthetic recipe from `Samples/AestheticRecipeSamples.cs` that matches the document type — do not invent formatting values. For CJK, also read `references/cjk_typography.md`. **Choose your path:** - **Simple** (plain text, minimal formatting): use CLI — `$CLI create --type report --output out.docx --config content.json` - **Structural** (custom styles, multi-section, TOC, images, complex tables): write C# directly. Read the relevant `Samples/*.cs` first. CLI options: `--type` (report|letter|memo|academic), `--title`, `--author`, `--page-size` (letter|a4|legal|a3), `--margins` (standard|narrow|wide), `--header`, `--footer`, `--page-numbers`, `--toc`, `--content-json`. Then run the **validation pipeline** (below). ## Scenario B: Edit / Fill Read `references/scenario_b_edit_content.md` first. Preview → analyze → edit → validate. **Choose your path:** - **Simple** (text replacement, placeholder fill): use CLI subcommands. - **Structural** (add/reorganize sections, modify styles, manipulate tables, insert images): write C# directly. Read `references/openxml_element_order.md` and the relevant `Samples/*.cs`. Available CLI edit subcommands: - `replace-text --find "X" --replace "Y"` - `fill-placeholders --data '{"key":"value"}'` - `fill-table --data table.json` - `insert-section`, `remove-section`, `update-header-footer` ```bash $CLI edit replace-text --input in.docx --output out.docx --find "OLD" --replace "NEW" $CLI edit fill-placeholders --input in.docx --output out.docx --data '{"name":"John"}' ``` Then run the **validation pipeline**. Also run diff to verify minimal changes: ```bash $CLI diff --before in.docx --after out.docx ``` ## Scenario C: Apply Template Read `references/scenario_c_apply_template.md` first. Preview and analyze both source and template. ```bash $CLI apply-template --input source.docx --template template.docx --output out.docx ``` For complex template operations (multi-template merge, per-section headers/footers, style merging), write C# directly — see Critical Rules below for required patterns. Run the **validation pipeline**, then the **hard gate-check**: ```bash $CLI validate --input out.docx --gate-check assets/xsd/business-rules.xsd ``` Gate-check is a **hard requirement**. Do NOT deliver until it passes. If it fails: diagnose, fix, re-run. Also diff to verify content preservation: `$CLI diff --before source.docx --after out.docx` ## Validation pipeline Run after every write operation. For Scenario C the full pipeline is **mandatory**; for A/B it is **recommended** (skip only if the operation was trivially simple). ```bash $CLI merge-runs --input doc.docx # 1. consolidate runs $CLI validate --input doc.docx --xsd assets/xsd/wml-subset.xsd # 2. XSD structure $CLI validate --input doc.docx --business # 3. business rules ``` If XSD fails, auto-repair and retry: ```bash $CLI fix-order --input doc.docx $CLI validate --input doc.docx --xsd assets/xsd/wml-subset.xsd ``` If XSD still fails, fall back to business rules + preview: ```bash $CLI validate --input doc.docx --business scripts/docx_preview.sh doc.docx # Verify: font contamination=0, table count correct, drawing count correct, sectPr count correct ``` Final preview: `scripts/docx_preview.sh doc.docx` ## Critical rules These prevent file corruption — OpenXML is strict about element ordering. **Element order** (properties always first): | Parent | Order | |--------|-------| | `w:p` | `pPr` → runs | | `w:r` | `rPr` → `t`/`br`/`tab` | | `w:tbl`| `tblPr` → `tblGrid` → `tr` | | `w:tr` | `trPr` → `tc` | | `w:tc` | `tcPr` → `p` (min 1 `<w:p/>`) | | `w:body` | block content → `sectPr` (LAST child) | **Direct format contamination:** When copying content from a source document, inline `rPr` (fonts, color) and `pPr` (borders, shading, spacing) override template styles. Always strip direct formatting — keep only `pStyle` reference and `t` text. Clean tables too (including `pPr/rPr` inside cells). **Track changes:** `<w:del>` uses `<w:delText>`, never `<w:t>`. `<w:ins>` uses `<w:t>`, never `<w:delText>`. **Font size:** `w:sz` = points × 2 (12pt → `sz="24"`). Margins/spacing in DXA (1 inch = 1440, 1cm ≈ 567). **Heading styles MUST have OutlineLevel:** When defining heading styles (Heading1, ThesisH1, etc.), always include `new OutlineLevel { Val = N }` in `StyleParagraphProperties` (H1→0, H2→1, H3→2). Without this, Word sees them as plain styled text — TOC and navigation pane won't work. **Multi-template merge:** When given multiple template files (font, heading, breaks), read `references/scenario_c_apply_template.md` section "Multi-Template Merge" FIRST. Key rules: - Merge styles from all templates into one styles.xml. Structure (sections/breaks) comes from the breaks template. - Each content paragraph must appear exactly ONCE — never duplicate when inserting section breaks. - NEVER insert empty/blank paragraphs as padding or section separators. Output paragraph count must equal input. Use section break properties (`w:sectPr` inside `w:pPr`) and style spacing (`w:spacing` before/after) for visual separation. - Insert oddPage section breaks before EVERY chapter heading, not just the first. Even if a chapter has dual-column content, it MUST start with oddPage; use a second continuous break after the heading for column switching. - Dual-column chapters need THREE section breaks: (1) oddPage in preceding para's pPr, (2) continuous+cols=2 in the chapter HEADING's pPr, (3) continuous+cols=1 in the last body para's pPr to revert. - Copy `titlePg` settings from the breaks template for EACH section. Abstract and TOC sections typically need `titlePg=true`. **Multi-section headers/footers:** Templates with 10+ sections (e.g., Chinese thesis) have DIFFERENT headers/footers per section (Roman vs Arabic page numbers, different header text per zone). Rules: - Use C-2 Base-Replace: copy the TEMPLATE as output base, then replace body content. This preserves all sections, headers, footers, and titlePg settings automatically. - NEVER recreate headers/footers from scratch — copy template header/footer XML byte-for-byte. - NEVER add formatting (borders, alignment, font size) not present in the template header XML. - Non-cover sections MUST have header/footer XML files (at least empty header + page number footer). - See `references/scenario_c_apply_template.md` section "Multi-Section Header/Footer Transfer". ## References Load as needed — don't load all at once. Pick the most relevant files for the task. **The C# samples and design references below are the project's knowledge base ("encyclopedia").** When writing OpenXML code, ALWAYS read the relevant sample file first — it contains compilable, SDK-version-verified patterns that prevent common errors. When making aesthetic decisions, read the design principles and recipe files — they encode tested, harmonious parameter sets from authoritative sources (IEEE, ACM, APA, Nature, etc.), not guesses. ### Scenario guides (read first for each pipeline) | File | When | |------|------| | `references/scenario_a_create.md` | Pipeline A: creating from scratch | | `references/scenario_b_edit_content.md` | Pipeline B: editing existing content | | `references/scenario_c_apply_template.md` | Pipeline C: applying template formatting | ### C# code samples (compilable, heavily commented — read when writing code) | File | Topic | |------|-------| | `Samples/DocumentCreationSamples.cs` | Document lifecycle: create, open, save, streams, doc defaults, settings, properties, page setup, multi-section | | `Samples/StyleSystemSamples.cs` | Styles: Normal/Heading chain, character/table/list styles, DocDefaults, latentStyles, CJK 公文, APA 7th, import, resolve inheritance | | `Samples/CharacterFormattingSamples.cs` | RunProperties: fonts, size, bold/italic, all underlines, color, highlight, strike, sub/super, caps, spacing, shading, border, emphasis marks | | `Samples/ParagraphFormattingSamples.cs` | ParagraphProperties: justification, indentation, line/paragraph spacing, keep/widow, outline level, borders, tabs, numbering, bidi, frame | | `Samples/TableSamples.cs` | Tables: borders, grid, cell props, margins, row height, header repeat, merge (H+V), nested, floating, three-line 三线表, zebra striping | | `Samples/HeaderFooterSamples.cs` | Headers/footers: page numbers, "Page X of Y", first/even/odd, logo image, table layout, 公文 "-X-", per-section | | `Samples/ImageSamples.cs` | Images: inline, floating, text wrapping, border, alt text, in header/table, replace, SVG fallback, dimension calc | | `Samples/ListAndNumberingSamples.cs` | Numbering: bullets, multi-level decimal, custom symbols, outline→headings, legal, Chinese 一/（一）/1./(1), restart/continue | | `Samples/FieldAndTocSamples.cs` | Fields: TOC, SimpleField vs complex field, DATE/PAGE/REF/SEQ/MERGEFIELD/IF/STYLEREF, TOC styles | | `Samples/FootnoteAndCommentSamples.cs` | Footnotes, endnotes, comments (4-file system), bookmarks, hyperlinks (internal + external) | | `Samples/TrackChangesSamples.cs` | Revisions: insertions (w:t), deletions (w:delText!), formatting changes, accept/reject all, move tracking | | `Samples/AestheticRecipeSamples.cs` | 13 aesthetic recipes from authoritative sources: ModernCorporate, AcademicThesis, ExecutiveBrief, ChineseGovernment (GB/T 9704), MinimalModern, IEEE Conference, ACM sigconf, APA 7th, MLA 9th, Chicago/Turabian, Springer LNCS, Nature, HBR — each with exact values from official style guides | Note: `Samples/` path is relative to `scripts/dotnet/MiniMaxAIDocx.Core/`. ### Markdown references (read when you need specifications or design rules) | File | When | |------|------| | `references/openxml_element_order.md` | XML element ordering rules (prevents corruption) | | `references/openxml_units.md` | Unit conversion: DXA, EMU, half-points, eighth-points | | `references/openxml_encyclopedia_part1.md` | Detailed C# encyclopedia: document creation, styles, character & paragraph formatting | | `references/openxml_encyclopedia_part2.md` | Detailed C# encyclopedia: page setup, tables, headers/footers, sections, doc properties | | `references/openxml_encyclopedia_part3.md` | Detailed C# encyclopedia: TOC, footnotes, fields, track changes, comments, images, math, numbering, protection | | `references/typography_guide.md` | Font pairing, sizes, spacing, page layout, table design, color schemes | | `references/cjk_typography.md` | CJK fonts, 字号 sizes, RunFonts mapping, GB/T 9704 公文 standard | | `references/cjk_university_template_guide.md` | Chinese university thesis templates: numeric styleIds (1/2/3 vs Heading1), document zone structure (cover→abstract→TOC→body→references), font expectations, common mistakes | | `references/design_principles.md` | **Aesthetic foundations**: 6 design principles (white space, contrast/scale, proximity, alignment, repetition, hierarchy) — teaches WHY, not just WHAT | | `references/design_good_bad_examples.md` | **Good vs Bad comparisons**: 10 categories of typography mistakes with OpenXML values, ASCII mockups, and fixes | | `references/track_changes_guide.md` | Revision marks deep dive | | `references/troubleshooting.md` | **Symptom-driven fixes**: 13 common problems indexed by what you SEE (headings wrong, images missing, TOC broken, etc.) — search by symptom, find the fix | fix |

path: _meta.json
content: id: 380332020064802
name: minimax-docx
platform: minimax
skill_id: 1893
updated_at: 1774407535046
version: 1.0.0

path: assets/styles/academic_styles.xml
content: <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
          xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
          xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">

  <!-- Document Defaults -->
  <w:docDefaults>
    <w:rPrDefault>
      <w:rPr>
        <w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" w:eastAsia="SimSun" w:cs="Times New Roman" />
        <w:sz w:val="24" />
        <w:szCs w:val="24" />
        <w:lang w:val="en-US" w:eastAsia="zh-CN" w:bidi="ar-SA" />
      </w:rPr>
    </w:rPrDefault>
    <w:pPrDefault>
      <w:pPr>
        <w:spacing w:after="0" w:line="480" w:lineRule="auto" />
      </w:pPr>
    </w:pPrDefault>
  </w:docDefaults>

  <w:latentStyles w:defLockedState="0" w:defUIPriority="99" w:defSemiHidden="0" w:defUnhideWhenUsed="0" w:defQFormat="0" w:count="376" />

  <!-- Normal — Times New Roman 12pt, double spaced, first line indent -->
  <w:style w:type="paragraph" w:default="1" w:styleId="Normal">
    <w:name w:val="Normal" />
    <w:qFormat />
    <w:pPr>
      <w:spacing w:after="0" w:line="480" w:lineRule="auto" />
      <w:ind w:firstLine="720" />
    </w:pPr>
    <w:rPr>
      <w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman" />
      <w:sz w:val="24" />
      <w:szCs w:val="24" />
    </w:rPr>
  </w:style>

  <!-- Default Paragraph Font -->
  <w:style w:type="character" w:default="1" w:styleId="DefaultParagraphFont">
    <w:name w:val="Default Paragraph Font" />
    <w:uiPriority w:val="1" />
    <w:semiHidden />
    <w:unhideWhenUsed />
  </w:style>

  <!-- Heading 1 — Bold, 14pt, no color, no indent -->
  <w:style w:type="paragraph" w:styleId="Heading1">
    <w:name w:val="heading 1" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="9" />
    <w:pPr>
      <w:keepNext />
      <w:keepLines />
      <w:spacing w:before="480" w:after="240" w:line="480" w:lineRule="auto" />
      <w:ind w:firstLine="0" />
      <w:jc w:val="center" />
      <w:outlineLvl w:val="0" />
    </w:pPr>
    <w:rPr>
      <w:b />
      <w:sz w:val="28" />
      <w:szCs w:val="28" />
    </w:rPr>
  </w:style>

  <!-- Heading 2 — Bold, 13pt -->
  <w:style w:type="paragraph" w:styleId="Heading2">
    <w:name w:val="heading 2" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="9" />
    <w:pPr>
      <w:keepNext />
      <w:keepLines />
      <w:spacing w:before="360" w:after="120" w:line="480" w:lineRule="auto" />
      <w:ind w:firstLine="0" />
      <w:outlineLvl w:val="1" />
    </w:pPr>
    <w:rPr>
      <w:b />
      <w:sz w:val="26" />
      <w:szCs w:val="26" />
    </w:rPr>
  </w:style>

  <!-- Heading 3 — Bold, 12pt -->
  <w:style w:type="paragraph" w:styleId="Heading3">
    <w:name w:val="heading 3" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="9" />
    <w:pPr>
      <w:keepNext />
      <w:keepLines />
      <w:spacing w:before="240" w:after="80" w:line="480" w:lineRule="auto" />
      <w:ind w:firstLine="0" />
      <w:outlineLvl w:val="2" />
    </w:pPr>
    <w:rPr>
      <w:b />
      <w:sz w:val="24" />
      <w:szCs w:val="24" />
    </w:rPr>
  </w:style>

  <!-- Title — Centered, bold, 14pt (academic title page) -->
  <w:style w:type="paragraph" w:styleId="Title">
    <w:name w:val="Title" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="10" />
    <w:pPr>
      <w:spacing w:after="480" w:line="480" w:lineRule="auto" />
      <w:ind w:firstLine="0" />
      <w:jc w:val="center" />
    </w:pPr>
    <w:rPr>
      <w:b />
      <w:sz w:val="28" />
      <w:szCs w:val="28" />
    </w:rPr>
  </w:style>

  <!-- Subtitle -->
  <w:style w:type="paragraph" w:styleId="Subtitle">
    <w:name w:val="Subtitle" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="11" />
    <w:pPr>
      <w:spacing w:after="240" w:line="480" w:lineRule="auto" />
      <w:ind w:firstLine="0" />
      <w:jc w:val="center" />
    </w:pPr>
    <w:rPr>
      <w:sz w:val="24" />
      <w:szCs w:val="24" />
    </w:rPr>
  </w:style>

  <!-- Quote — Block quote, indented 0.5 inch on both sides -->
  <w:style w:type="paragraph" w:styleId="Quote">
    <w:name w:val="Quote" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="29" />
    <w:pPr>
      <w:spacing w:before="240" w:after="240" w:line="480" w:lineRule="auto" />
      <w:ind w:left="720" w:right="720" w:firstLine="0" />
    </w:pPr>
  </w:style>

  <!-- Table Normal -->
  <w:style w:type="table" w:default="1" w:styleId="TableNormal">
    <w:name w:val="Normal Table" />
    <w:uiPriority w:val="99" />
    <w:semiHidden />
    <w:unhideWhenUsed />
    <w:tblPr>
      <w:tblInd w:w="0" w:type="dxa" />
      <w:tblCellMar>
        <w:top w:w="0" w:type="dxa" />
        <w:left w:w="108" w:type="dxa" />
        <w:bottom w:w="0" w:type="dxa" />
        <w:right w:w="108" w:type="dxa" />
      </w:tblCellMar>
    </w:tblPr>
  </w:style>

  <!-- Table Grid — Simple borders, no color -->
  <w:style w:type="table" w:styleId="TableGrid">
    <w:name w:val="Table Grid" />
    <w:basedOn w:val="TableNormal" />
    <w:uiPriority w:val="39" />
    <w:tblPr>
      <w:tblBorders>
        <w:top w:val="single" w:sz="4" w:space="0" w:color="auto" />
        <w:left w:val="single" w:sz="4" w:space="0" w:color="auto" />
        <w:bottom w:val="single" w:sz="4" w:space="0" w:color="auto" />
        <w:right w:val="single" w:sz="4" w:space="0" w:color="auto" />
        <w:insideH w:val="single" w:sz="4" w:space="0" w:color="auto" />
        <w:insideV w:val="single" w:sz="4" w:space="0" w:color="auto" />
      </w:tblBorders>
    </w:tblPr>
  </w:style>

  <!-- Header -->
  <w:style w:type="paragraph" w:styleId="Header">
    <w:name w:val="header" />
    <w:basedOn w:val="Normal" />
    <w:uiPriority w:val="99" />
    <w:semiHidden />
    <w:unhideWhenUsed />
    <w:pPr>
      <w:tabs>
        <w:tab w:val="center" w:pos="4680" />
        <w:tab w:val="right" w:pos="9360" />
      </w:tabs>
      <w:spacing w:after="0" w:line="240" w:lineRule="auto" />
      <w:ind w:firstLine="0" />
    </w:pPr>
    <w:rPr>
      <w:sz w:val="24" />
      <w:szCs w:val="24" />
    </w:rPr>
  </w:style>

  <!-- Footer -->
  <w:style w:type="paragraph" w:styleId="Footer">
    <w:name w:val="footer" />
    <w:basedOn w:val="Normal" />
    <w:uiPriority w:val="99" />
    <w:semiHidden />
    <w:unhideWhenUsed />
    <w:pPr>
      <w:tabs>
        <w:tab w:val="center" w:pos="4680" />
        <w:tab w:val="right" w:pos="9360" />
      </w:tabs>
      <w:spacing w:after="0" w:line="240" w:lineRule="auto" />
      <w:ind w:firstLine="0" />
      <w:jc w:val="center" />
    </w:pPr>
    <w:rPr>
      <w:sz w:val="24" />
      <w:szCs w:val="24" />
    </w:rPr>
  </w:style>

  <!-- Hyperlink -->
  <w:style w:type="character" w:styleId="Hyperlink">
    <w:name w:val="Hyperlink" />
    <w:uiPriority w:val="99" />
    <w:unhideWhenUsed />
    <w:rPr>
      <w:color w:val="0563C1" />
      <w:u w:val="single" />
    </w:rPr>
  </w:style>

</w:styles>


path: assets/styles/corporate_styles.xml
content: <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
          xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
          xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">

  <!-- Document Defaults -->
  <w:docDefaults>
    <w:rPrDefault>
      <w:rPr>
        <w:rFonts w:ascii="Calibri" w:hAnsi="Calibri" w:eastAsia="Microsoft YaHei" w:cs="Arial" />
        <w:color w:val="333333" />
        <w:sz w:val="22" />
        <w:szCs w:val="22" />
        <w:lang w:val="en-US" w:eastAsia="zh-CN" w:bidi="ar-SA" />
      </w:rPr>
    </w:rPrDefault>
    <w:pPrDefault>
      <w:pPr>
        <w:spacing w:after="160" w:line="259" w:lineRule="auto" />
      </w:pPr>
    </w:pPrDefault>
  </w:docDefaults>

  <w:latentStyles w:defLockedState="0" w:defUIPriority="99" w:defSemiHidden="0" w:defUnhideWhenUsed="0" w:defQFormat="0" w:count="376" />

  <!-- Normal -->
  <w:style w:type="paragraph" w:default="1" w:styleId="Normal">
    <w:name w:val="Normal" />
    <w:qFormat />
    <w:pPr>
      <w:spacing w:after="160" w:line="240" w:lineRule="auto" />
    </w:pPr>
    <w:rPr>
      <w:rFonts w:ascii="Calibri" w:hAnsi="Calibri" />
      <w:color w:val="333333" />
      <w:sz w:val="22" />
      <w:szCs w:val="22" />
    </w:rPr>
  </w:style>

  <!-- Default Paragraph Font -->
  <w:style w:type="character" w:default="1" w:styleId="DefaultParagraphFont">
    <w:name w:val="Default Paragraph Font" />
    <w:uiPriority w:val="1" />
    <w:semiHidden />
    <w:unhideWhenUsed />
  </w:style>

  <!-- Heading 1 — Dark Blue -->
  <w:style w:type="paragraph" w:styleId="Heading1">
    <w:name w:val="heading 1" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="9" />
    <w:pPr>
      <w:keepNext />
      <w:keepLines />
      <w:spacing w:before="480" w:after="240" w:line="240" w:lineRule="auto" />
      <w:outlineLvl w:val="0" />
    </w:pPr>
    <w:rPr>
      <w:rFonts w:ascii="Calibri Light" w:hAnsi="Calibri Light" />
      <w:b />
      <w:color w:val="1F3864" />
      <w:sz w:val="56" />
      <w:szCs w:val="56" />
    </w:rPr>
  </w:style>

  <!-- Heading 2 -->
  <w:style w:type="paragraph" w:styleId="Heading2">
    <w:name w:val="heading 2" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="9" />
    <w:pPr>
      <w:keepNext />
      <w:keepLines />
      <w:spacing w:before="360" w:after="120" w:line="240" w:lineRule="auto" />
      <w:outlineLvl w:val="1" />
    </w:pPr>
    <w:rPr>
      <w:rFonts w:ascii="Calibri Light" w:hAnsi="Calibri Light" />
      <w:b />
      <w:color w:val="1F3864" />
      <w:sz w:val="48" />
      <w:szCs w:val="48" />
    </w:rPr>
  </w:style>

  <!-- Heading 3 -->
  <w:style w:type="paragraph" w:styleId="Heading3">
    <w:name w:val="heading 3" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="9" />
    <w:pPr>
      <w:keepNext />
      <w:keepLines />
      <w:spacing w:before="240" w:after="80" w:line="240" w:lineRule="auto" />
      <w:outlineLvl w:val="2" />
    </w:pPr>
    <w:rPr>
      <w:rFonts w:ascii="Calibri Light" w:hAnsi="Calibri Light" />
      <w:b />
      <w:color w:val="1F3864" />
      <w:sz w:val="36" />
      <w:szCs w:val="36" />
    </w:rPr>
  </w:style>

  <!-- Heading 4 -->
  <w:style w:type="paragraph" w:styleId="Heading4">
    <w:name w:val="heading 4" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="9" />
    <w:pPr>
      <w:keepNext />
      <w:keepLines />
      <w:spacing w:before="160" w:after="80" w:line="240" w:lineRule="auto" />
      <w:outlineLvl w:val="3" />
    </w:pPr>
    <w:rPr>
      <w:rFonts w:ascii="Calibri Light" w:hAnsi="Calibri Light" />
      <w:b />
      <w:i />
      <w:color w:val="1F3864" />
      <w:sz w:val="28" />
      <w:szCs w:val="28" />
    </w:rPr>
  </w:style>

  <!-- Title -->
  <w:style w:type="paragraph" w:styleId="Title">
    <w:name w:val="Title" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="10" />
    <w:pPr>
      <w:spacing w:after="240" w:line="240" w:lineRule="auto" />
      <w:jc w:val="center" />
    </w:pPr>
    <w:rPr>
      <w:rFonts w:ascii="Calibri Light" w:hAnsi="Calibri Light" />
      <w:color w:val="1F3864" />
      <w:sz w:val="72" />
      <w:szCs w:val="72" />
    </w:rPr>
  </w:style>

  <!-- Subtitle -->
  <w:style w:type="paragraph" w:styleId="Subtitle">
    <w:name w:val="Subtitle" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="11" />
    <w:pPr>
      <w:spacing w:after="360" w:line="240" w:lineRule="auto" />
      <w:jc w:val="center" />
    </w:pPr>
    <w:rPr>
      <w:i />
      <w:color w:val="595959" />
      <w:sz w:val="32" />
      <w:szCs w:val="32" />
    </w:rPr>
  </w:style>

  <!-- Table Grid — Corporate with blue header -->
  <w:style w:type="table" w:default="1" w:styleId="TableNormal">
    <w:name w:val="Normal Table" />
    <w:uiPriority w:val="99" />
    <w:semiHidden />
    <w:unhideWhenUsed />
    <w:tblPr>
      <w:tblInd w:w="0" w:type="dxa" />
      <w:tblCellMar>
        <w:top w:w="0" w:type="dxa" />
        <w:left w:w="108" w:type="dxa" />
        <w:bottom w:w="0" w:type="dxa" />
        <w:right w:w="108" w:type="dxa" />
      </w:tblCellMar>
    </w:tblPr>
  </w:style>

  <w:style w:type="table" w:styleId="TableGrid">
    <w:name w:val="Table Grid" />
    <w:basedOn w:val="TableNormal" />
    <w:uiPriority w:val="39" />
    <w:tblPr>
      <w:tblBorders>
        <w:top w:val="single" w:sz="4" w:space="0" w:color="BFBFBF" />
        <w:left w:val="single" w:sz="4" w:space="0" w:color="BFBFBF" />
        <w:bottom w:val="single" w:sz="4" w:space="0" w:color="BFBFBF" />
        <w:right w:val="single" w:sz="4" w:space="0" w:color="BFBFBF" />
        <w:insideH w:val="single" w:sz="4" w:space="0" w:color="BFBFBF" />
        <w:insideV w:val="single" w:sz="4" w:space="0" w:color="BFBFBF" />
      </w:tblBorders>
    </w:tblPr>
    <w:tblStylePr w:type="firstRow">
      <w:rPr>
        <w:b />
        <w:color w:val="FFFFFF" />
      </w:rPr>
      <w:tcPr>
        <w:shd w:val="clear" w:color="auto" w:fill="2F5496" />
        <w:tcBorders>
          <w:top w:val="single" w:sz="4" w:space="0" w:color="2F5496" />
          <w:left w:val="single" w:sz="4" w:space="0" w:color="2F5496" />
          <w:bottom w:val="single" w:sz="4" w:space="0" w:color="2F5496" />
          <w:right w:val="single" w:sz="4" w:space="0" w:color="2F5496" />
          <w:insideH w:val="single" w:sz="4" w:space="0" w:color="3A6BC5" />
          <w:insideV w:val="single" w:sz="4" w:space="0" w:color="3A6BC5" />
        </w:tcBorders>
      </w:tcPr>
    </w:tblStylePr>
    <w:tblStylePr w:type="band1Horz">
      <w:tcPr>
        <w:shd w:val="clear" w:color="auto" w:fill="D9E2F3" />
      </w:tcPr>
    </w:tblStylePr>
  </w:style>

  <!-- Header -->
  <w:style w:type="paragraph" w:styleId="Header">
    <w:name w:val="header" />
    <w:basedOn w:val="Normal" />
    <w:uiPriority w:val="99" />
    <w:semiHidden />
    <w:unhideWhenUsed />
    <w:pPr>
      <w:tabs>
        <w:tab w:val="center" w:pos="4680" />
        <w:tab w:val="right" w:pos="9360" />
      </w:tabs>
      <w:spacing w:after="0" w:line="240" w:lineRule="auto" />
    </w:pPr>
    <w:rPr>
      <w:sz w:val="18" />
      <w:szCs w:val="18" />
      <w:color w:val="808080" />
    </w:rPr>
  </w:style>

  <!-- Footer -->
  <w:style w:type="paragraph" w:styleId="Footer">
    <w:name w:val="footer" />
    <w:basedOn w:val="Normal" />
    <w:uiPriority w:val="99" />
    <w:semiHidden />
    <w:unhideWhenUsed />
    <w:pPr>
      <w:tabs>
        <w:tab w:val="center" w:pos="4680" />
        <w:tab w:val="right" w:pos="9360" />
      </w:tabs>
      <w:spacing w:after="0" w:line="240" w:lineRule="auto" />
    </w:pPr>
    <w:rPr>
      <w:sz w:val="18" />
      <w:szCs w:val="18" />
      <w:color w:val="808080" />
    </w:rPr>
  </w:style>

  <!-- Hyperlink -->
  <w:style w:type="character" w:styleId="Hyperlink">
    <w:name w:val="Hyperlink" />
    <w:uiPriority w:val="99" />
    <w:unhideWhenUsed />
    <w:rPr>
      <w:color w:val="0563C1" />
      <w:u w:val="single" />
    </w:rPr>
  </w:style>

</w:styles>


path: assets/styles/default_styles.xml
content: <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:styles xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
          xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
          xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006">

  <!-- Document Defaults -->
  <w:docDefaults>
    <w:rPrDefault>
      <w:rPr>
        <w:rFonts w:ascii="Calibri" w:hAnsi="Calibri" w:eastAsia="SimSun" w:cs="Arial" />
        <w:sz w:val="22" />
        <w:szCs w:val="22" />
        <w:lang w:val="en-US" w:eastAsia="zh-CN" w:bidi="ar-SA" />
      </w:rPr>
    </w:rPrDefault>
    <w:pPrDefault>
      <w:pPr>
        <w:spacing w:after="160" w:line="259" w:lineRule="auto" />
      </w:pPr>
    </w:pPrDefault>
  </w:docDefaults>

  <!-- Latent Styles -->
  <w:latentStyles w:defLockedState="0" w:defUIPriority="99" w:defSemiHidden="0" w:defUnhideWhenUsed="0" w:defQFormat="0" w:count="376" />

  <!-- Normal (Default Paragraph Style) -->
  <w:style w:type="paragraph" w:default="1" w:styleId="Normal">
    <w:name w:val="Normal" />
    <w:qFormat />
    <w:pPr>
      <w:spacing w:after="160" w:line="240" w:lineRule="auto" />
    </w:pPr>
    <w:rPr>
      <w:rFonts w:ascii="Calibri" w:hAnsi="Calibri" />
      <w:sz w:val="22" />
      <w:szCs w:val="22" />
    </w:rPr>
  </w:style>

  <!-- Default Paragraph Font -->
  <w:style w:type="character" w:default="1" w:styleId="DefaultParagraphFont">
    <w:name w:val="Default Paragraph Font" />
    <w:uiPriority w:val="1" />
    <w:semiHidden />
    <w:unhideWhenUsed />
  </w:style>

  <!-- Heading 1 -->
  <w:style w:type="paragraph" w:styleId="Heading1">
    <w:name w:val="heading 1" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="9" />
    <w:pPr>
      <w:keepNext />
      <w:keepLines />
      <w:spacing w:before="480" w:after="240" w:line="240" w:lineRule="auto" />
      <w:outlineLvl w:val="0" />
    </w:pPr>
    <w:rPr>
      <w:rFonts w:ascii="Calibri Light" w:hAnsi="Calibri Light" />
      <w:b />
      <w:color w:val="2F5496" />
      <w:sz w:val="56" />
      <w:szCs w:val="56" />
    </w:rPr>
  </w:style>

  <!-- Heading 2 -->
  <w:style w:type="paragraph" w:styleId="Heading2">
    <w:name w:val="heading 2" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="9" />
    <w:pPr>
      <w:keepNext />
      <w:keepLines />
      <w:spacing w:before="360" w:after="120" w:line="240" w:lineRule="auto" />
      <w:outlineLvl w:val="1" />
    </w:pPr>
    <w:rPr>
      <w:rFonts w:ascii="Calibri Light" w:hAnsi="Calibri Light" />
      <w:b />
      <w:color w:val="2F5496" />
      <w:sz w:val="48" />
      <w:szCs w:val="48" />
    </w:rPr>
  </w:style>

  <!-- Heading 3 -->
  <w:style w:type="paragraph" w:styleId="Heading3">
    <w:name w:val="heading 3" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="9" />
    <w:pPr>
      <w:keepNext />
      <w:keepLines />
      <w:spacing w:before="240" w:after="80" w:line="240" w:lineRule="auto" />
      <w:outlineLvl w:val="2" />
    </w:pPr>
    <w:rPr>
      <w:rFonts w:ascii="Calibri Light" w:hAnsi="Calibri Light" />
      <w:b />
      <w:color w:val="2F5496" />
      <w:sz w:val="36" />
      <w:szCs w:val="36" />
    </w:rPr>
  </w:style>

  <!-- Heading 4 -->
  <w:style w:type="paragraph" w:styleId="Heading4">
    <w:name w:val="heading 4" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="9" />
    <w:pPr>
      <w:keepNext />
      <w:keepLines />
      <w:spacing w:before="160" w:after="80" w:line="240" w:lineRule="auto" />
      <w:outlineLvl w:val="3" />
    </w:pPr>
    <w:rPr>
      <w:rFonts w:ascii="Calibri Light" w:hAnsi="Calibri Light" />
      <w:b />
      <w:i />
      <w:color w:val="2F5496" />
      <w:sz w:val="28" />
      <w:szCs w:val="28" />
    </w:rPr>
  </w:style>

  <!-- Heading 5 -->
  <w:style w:type="paragraph" w:styleId="Heading5">
    <w:name w:val="heading 5" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="9" />
    <w:pPr>
      <w:keepNext />
      <w:keepLines />
      <w:spacing w:before="160" w:after="80" w:line="240" w:lineRule="auto" />
      <w:outlineLvl w:val="4" />
    </w:pPr>
    <w:rPr>
      <w:rFonts w:ascii="Calibri Light" w:hAnsi="Calibri Light" />
      <w:b />
      <w:color w:val="2F5496" />
      <w:sz w:val="24" />
      <w:szCs w:val="24" />
    </w:rPr>
  </w:style>

  <!-- Heading 6 -->
  <w:style w:type="paragraph" w:styleId="Heading6">
    <w:name w:val="heading 6" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="9" />
    <w:pPr>
      <w:keepNext />
      <w:keepLines />
      <w:spacing w:before="160" w:after="80" w:line="240" w:lineRule="auto" />
      <w:outlineLvl w:val="5" />
    </w:pPr>
    <w:rPr>
      <w:rFonts w:ascii="Calibri Light" w:hAnsi="Calibri Light" />
      <w:b />
      <w:i />
      <w:color w:val="2F5496" />
      <w:sz w:val="22" />
      <w:szCs w:val="22" />
    </w:rPr>
  </w:style>

  <!-- Title -->
  <w:style w:type="paragraph" w:styleId="Title">
    <w:name w:val="Title" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="10" />
    <w:pPr>
      <w:spacing w:after="240" w:line="240" w:lineRule="auto" />
      <w:jc w:val="center" />
    </w:pPr>
    <w:rPr>
      <w:rFonts w:ascii="Calibri Light" w:hAnsi="Calibri Light" />
      <w:color w:val="2F5496" />
      <w:sz w:val="72" />
      <w:szCs w:val="72" />
    </w:rPr>
  </w:style>

  <!-- Subtitle -->
  <w:style w:type="paragraph" w:styleId="Subtitle">
    <w:name w:val="Subtitle" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="11" />
    <w:pPr>
      <w:spacing w:after="360" w:line="240" w:lineRule="auto" />
      <w:jc w:val="center" />
    </w:pPr>
    <w:rPr>
      <w:i />
      <w:color w:val="595959" />
      <w:sz w:val="32" />
      <w:szCs w:val="32" />
    </w:rPr>
  </w:style>

  <!-- Quote -->
  <w:style w:type="paragraph" w:styleId="Quote">
    <w:name w:val="Quote" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="29" />
    <w:pPr>
      <w:spacing w:before="240" w:after="240" />
      <w:ind w:left="720" w:right="720" />
    </w:pPr>
    <w:rPr>
      <w:i />
      <w:color w:val="404040" />
    </w:rPr>
  </w:style>

  <!-- Intense Quote -->
  <w:style w:type="paragraph" w:styleId="IntenseQuote">
    <w:name w:val="Intense Quote" />
    <w:basedOn w:val="Normal" />
    <w:next w:val="Normal" />
    <w:qFormat />
    <w:uiPriority w:val="30" />
    <w:pPr>
      <w:spacing w:before="240" w:after="240" />
      <w:ind w:left="720" w:right="720" />
      <w:pBdr>
        <w:left w:val="single" w:sz="18" w:space="12" w:color="2F5496" />
      </w:pBdr>
    </w:pPr>
    <w:rPr>
      <w:b />
      <w:i />
      <w:color w:val="2F5496" />
    </w:rPr>
  </w:style>

  <!-- TOC Heading -->
  <w:style w:type="paragraph" w:styleId="TOCHeading">
    <w:name w:val="TOC Heading" />
    <w:basedOn w:val="Heading1" />
    <w:next w:val="Normal" />
    <w:uiPriority w:val="39" />
    <w:semiHidden />
    <w:unhideWhenUsed />
    <w:pPr>
      <w:outlineLvl w:val="9" />
    </w:pPr>
  </w:style>

  <!-- TOC 1 -->
  <w:style w:type="paragraph" w:styleId="TOC1">
    <w:name w:val="toc 1" />
    <w:basedOn w:val="Normal" />
    <w:uiPriority w:val="39" />
    <w:semiHidden />
    <w:unhideWhenUsed />
    <w:pPr>
      <w:spacing w:before="120" w:after="0" />
    </w:pPr>
    <w:rPr>
      <w:b />
    </w:rPr>
  </w:style>

  <!-- TOC 2 -->
  <w:style w:type="paragraph" w:styleId="TOC2">
    <w:name w:val="toc 2" />
    <w:basedOn w:val="Normal" />
    <w:uiPriority w:val="39" />
    <w:semiHidden />
    <w:unhideWhenUsed />
    <w:pPr>
      <w:spacing w:after="0" />
      <w:ind w:left="240" />
    </w:pPr>
  </w:style>

  <!-- TOC 3 -->
  <w:style w:type="paragraph" w:styleId="TOC3">
    <w:name w:val="toc 3" />
    <w:basedOn w:val="Normal" />
    <w:uiPriority w:val="39" />
    <w:semiHidden />
    <w:unhideWhenUsed />
    <w:pPr>
      <w:spacing w:after="0" />
      <w:ind w:left="480" />
    </w:pPr>
  </w:style>

  <!-- List Bullet -->
  <w:style w:type="paragraph" w:styleId="ListBullet">
    <w:name w:val="List Bullet" />
    <w:basedOn w:val="Normal" />
    <w:uiPriority w:val="36" />
    <w:pPr>
      <w:spacing w:after="0" />
      <w:ind w:left="720" w:hanging="360" />
      <w:contextualSpacing />
    </w:pPr>
  </w:style>

  <!-- List Number -->
  <w:style w:type="paragraph" w:styleId="ListNumber">
    <w:name w:val="List Number" />
    <w:basedOn w:val="Normal" />
    <w:uiPriority w:val="36" />
    <w:pPr>
      <w:spacing w:after="0" />
      <w:ind w:left="720" w:hanging="360" />
      <w:contextualSpacing />
    </w:pPr>
  </w:style>

  <!-- Table Normal -->
  <w:style w:type="table" w:default="1" w:styleId="TableNormal">
    <w:name w:val="Normal Table" />
    <w:uiPriority w:val="99" />
    <w:semiHidden />
    <w:unhideWhenUsed />
    <w:tblPr>
      <w:tblInd w:w="0" w:type="dxa" />
      <w:tblCellMar>
        <w:top w:w="0" w:type="dxa" />
        <w:left w:w="108" w:type="dxa" />
        <w:bottom w:w="0" w:type="dxa" />
        <w:right w:w="108" w:type="dxa" />
      </w:tblCellMar>
    </w:tblPr>
  </w:style>

  <!-- Table Grid -->
  <w:style w:type="table" w:styleId="TableGrid">
    <w:name w:val="Table Grid" />
    <w:basedOn w:val="TableNormal" />
    <w:uiPriority w:val="39" />
    <w:tblPr>
      <w:tblBorders>
        <w:top w:val="single" w:sz="4" w:space="0" w:color="auto" />
        <w:left w:val="single" w:sz="4" w:space="0" w:color="auto" />
        <w:bottom w:val="single" w:sz="4" w:space="0" w:color="auto" />
        <w:right w:val="single" w:sz="4" w:space="0" w:color="auto" />
        <w:insideH w:val="single" w:sz="4" w:space="0" w:color="auto" />
        <w:insideV w:val="single" w:sz="4" w:space="0" w:color="auto" />
      </w:tblBorders>
    </w:tblPr>
  </w:style>

  <!-- Header -->
  <w:style w:type="paragraph" w:styleId="Header">
    <w:name w:val="header" />
    <w:basedOn w:val="Normal" />
    <w:uiPriority w:val="99" />
    <w:semiHidden />
    <w:unhideWhenUsed />
    <w:pPr>
      <w:tabs>
        <w:tab w:val="center" w:pos="4680" />
        <w:tab w:val="right" w:pos="9360" />
      </w:tabs>
      <w:spacing w:after="0" w:line="240" w:lineRule="auto" />
    </w:pPr>
    <w:rPr>
      <w:sz w:val="18" />
      <w:szCs w:val="18" />
      <w:color w:val="808080" />
    </w:rPr>
  </w:style>

  <!-- Footer -->
  <w:style w:type="paragraph" w:styleId="Footer">
    <w:name w:val="footer" />
    <w:basedOn w:val="Normal" />
    <w:uiPriority w:val="99" />
    <w:semiHidden />
    <w:unhideWhenUsed />
    <w:pPr>
      <w:tabs>
        <w:tab w:val="center" w:pos="4680" />
        <w:tab w:val="right" w:pos="9360" />
      </w:tabs>
      <w:spacing w:after="0" w:line="240" w:lineRule="auto" />
    </w:pPr>
    <w:rPr>
      <w:sz w:val="18" />
      <w:szCs w:val="18" />
      <w:color w:val="808080" />
    </w:rPr>
  </w:style>

  <!-- Hyperlink -->
  <w:style w:type="character" w:styleId="Hyperlink">
    <w:name w:val="Hyperlink" />
    <w:uiPriority w:val="99" />
    <w:unhideWhenUsed />
    <w:rPr>
      <w:color w:val="0563C1" />
      <w:u w:val="single" />
    </w:rPr>
  </w:style>

  <!-- Comment Text -->
  <w:style w:type="paragraph" w:styleId="CommentText">
    <w:name w:val="annotation text" />
    <w:basedOn w:val="Normal" />
    <w:semiHidden />
    <w:unhideWhenUsed />
    <w:pPr>
      <w:spacing w:line="240" w:lineRule="auto" />
    </w:pPr>
    <w:rPr>
      <w:sz w:val="20" />
      <w:szCs w:val="20" />
    </w:rPr>
  </w:style>

  <!-- Comment Reference -->
  <w:style w:type="character" w:styleId="CommentReference">
    <w:name w:val="annotation reference" />
    <w:semiHidden />
    <w:unhideWhenUsed />
    <w:rPr>
      <w:sz w:val="16" />
      <w:szCs w:val="16" />
    </w:rPr>
  </w:style>

</w:styles>


path: references/cjk_typography.md
content: # CJK Typography & Mixed-Script Guide

Rules for Chinese, Japanese, and Korean text in DOCX documents.

## Table of Contents

1. [Font Selection](#font-selection)
2. [Font Size Names (CJK)](#font-size-names)
3. [RunFonts Mapping](#runfonts-mapping)
4. [Punctuation & Line Breaking](#punctuation--line-breaking)
5. [Paragraph Indentation](#paragraph-indentation)
6. [Line Spacing for CJK](#line-spacing)
7. [Chinese Government Standard (GB/T 9704)](#gbt-9704)
8. [Mixed CJK + Latin Best Practices](#mixed-script)
9. [OpenXML Quick Reference](#openxml-quick-reference)

---

## Font Selection

### Recommended CJK Fonts

| Language | Serif (正文) | Sans (标题) | Notes |
|----------|-------------|-------------|-------|
| **Simplified Chinese** | 宋体 (SimSun) | 微软雅黑 (Microsoft YaHei) | YaHei for screen, SimSun for print |
| **Simplified Chinese** | 仿宋 (FangSong) | 黑体 (SimHei) | Government documents |
| **Traditional Chinese** | 新細明體 (PMingLiU) | 微軟正黑體 (Microsoft JhengHei) | Taiwan standard |
| **Japanese** | MS 明朝 (MS Mincho) | MS ゴシック (MS Gothic) | Classic pairing |
| **Japanese** | 游明朝 (Yu Mincho) | 游ゴシック (Yu Gothic) | Modern, Windows 10+ |
| **Korean** | 바탕 (Batang) | 맑은 고딕 (Malgun Gothic) | Standard pairing |

### Government Document Fonts (公文)

| Element | Font | Size |
|---------|------|------|
| 标题 (title) | 小标宋 (FZXiaoBiaoSong-B05S) | 二号 (22pt) |
| 一级标题 | 黑体 (SimHei) | 三号 (16pt) |
| 二级标题 | 楷体_GB2312 (KaiTi_GB2312) | 三号 (16pt) |
| 三级标题 | 仿宋_GB2312 加粗 | 三号 (16pt) |
| 正文 (body) | 仿宋_GB2312 (FangSong_GB2312) | 三号 (16pt) |
| 附注/页码 | 宋体 (SimSun) | 四号 (14pt) |

---

## Font Size Names

CJK uses named sizes. Map to points and `w:sz` half-point values:

| 字号 | Points | `w:sz` | Common Use |
|------|--------|--------|------------|
| 初号 | 42pt | 84 | Display title |
| 小初 | 36pt | 72 | Large title |
| 一号 | 26pt | 52 | Chapter heading |
| 小一 | 24pt | 48 | Major heading |
| 二号 | 22pt | 44 | Document title (公文) |
| 小二 | 18pt | 36 | Western H1 equivalent |
| 三号 | 16pt | 32 | CJK heading / 公文 body |
| 小三 | 15pt | 30 | Sub-heading |
| 四号 | 14pt | 28 | CJK subheading |
| 小四 | 12pt | 24 | Standard body (CJK) |
| 五号 | 10.5pt | 21 | Compact CJK body |
| 小五 | 9pt | 18 | Footnotes |
| 六号 | 7.5pt | 15 | Fine print |

---

## RunFonts Mapping

OpenXML uses four font slots to handle multilingual text:

```xml
<w:rFonts
  w:ascii="Calibri"        <!-- Latin characters (U+0000–U+007F) -->
  w:hAnsi="Calibri"        <!-- Latin extended, Greek, Cyrillic -->
  w:eastAsia="SimSun"      <!-- CJK Unified Ideographs, Kana, Hangul -->
  w:cs="Arial"             <!-- Arabic, Hebrew, Thai, Devanagari -->
/>
```

**Word's character classification logic:**

1. Character is in CJK range → uses `w:eastAsia` font
2. Character is in complex script range → uses `w:cs` font
3. Character is basic Latin (ASCII) → uses `w:ascii` font
4. Everything else → uses `w:hAnsi` font

**Key**: `w:eastAsia` is the **only** way to set CJK fonts. Setting just `w:ascii` will NOT affect CJK characters. Mixed text within a single run auto-switches fonts at the character level — no need for separate runs.

### Document Defaults

```xml
<w:docDefaults>
  <w:rPrDefault>
    <w:rPr>
      <w:rFonts w:ascii="Calibri" w:hAnsi="Calibri" w:eastAsia="SimSun" w:cs="Arial" />
      <w:sz w:val="22" />
      <w:szCs w:val="22" />
      <w:lang w:val="en-US" w:eastAsia="zh-CN" />
    </w:rPr>
  </w:rPrDefault>
</w:docDefaults>
```

`w:lang w:eastAsia` helps Word resolve ambiguous characters (e.g., punctuation shared between CJK and Latin).

---

## Punctuation & Line Breaking

### Full-Width vs Half-Width

CJK text uses full-width punctuation:

| Type | CJK | Latin |
|------|-----|-------|
| Period | 。(U+3002) | . |
| Comma | ，(U+FF0C) 、(U+3001) | , |
| Colon | ：(U+FF1A) | : |
| Semicolon | ；(U+FF1B) | ; |
| Quotes | 「」『』 or ""'' | "" '' |
| Parentheses | （）(U+FF08/09) | () |

In mixed text, use the punctuation style of the **surrounding language context**.

### OpenXML Controls

```xml
<w:pPr>
  <w:adjustRightInd w:val="true" />   <!-- Adjust right indent for CJK punctuation -->
  <w:snapToGrid w:val="true" />        <!-- Align to document grid -->
  <w:kinsoku w:val="true" />           <!-- Enable CJK line breaking rules -->
  <w:overflowPunct w:val="true" />     <!-- Allow punctuation to overflow margins -->
</w:pPr>
```

### Kinsoku Rules (禁則処理)

Prevents certain characters from appearing at the start or end of a line:
- **Cannot start a line**: `）」』】〉》。、，！？；：` and closing brackets
- **Cannot end a line**: `（「『【〈《` and opening brackets

Word applies these automatically when `w:kinsoku` is enabled.

### Line Breaking

- CJK characters can break between **any two characters** (no word boundaries needed)
- Latin words within CJK text still follow word-boundary breaking
- `w:wordWrap w:val="false"` enables CJK-style breaking (break anywhere)

---

## Paragraph Indentation

### Chinese Standard: 2-Character Indent

Chinese body text conventionally uses a 2-character first-line indent:

```xml
<w:ind w:firstLineChars="200" />  <!-- 200 = 2 characters × 100 -->
```

Preferred over `w:firstLine` with fixed DXA because `firstLineChars` scales with font size.

| Indent | Value |
|--------|-------|
| 1 character | `w:firstLineChars="100"` |
| 2 characters | `w:firstLineChars="200"` |
| 3 characters | `w:firstLineChars="300"` |

---

## Line Spacing

- CJK characters are taller than Latin characters at the same point size
- Default `1.0` line spacing may feel cramped with CJK text
- Recommended: `1.15–1.5` for mixed CJK+Latin, `1.0` with fixed 28pt for 公文

### Auto Spacing

```xml
<w:pPr>
  <w:autoSpaceDE w:val="true"/>  <!-- auto space between CJK and Latin -->
  <w:autoSpaceDN w:val="true"/>  <!-- auto space between CJK and numbers -->
</w:pPr>
```

Adds ~¼ em spacing between CJK and non-CJK characters automatically. **Recommended: always enable.**

---

## GB/T 9704

Chinese government document standard (党政机关公文格式). These are **strict requirements**, not suggestions.

### Page Setup

| Parameter | Value | OpenXML |
|-----------|-------|---------|
| Page size | A4 (210×297mm) | Width=11906, Height=16838 |
| Top margin | 37mm | 2098 DXA |
| Bottom margin | 35mm | 1984 DXA |
| Left margin | 28mm | 1588 DXA |
| Right margin | 26mm | 1474 DXA |
| Characters/line | 28 | |
| Lines/page | 22 | |
| Line spacing | Fixed 28pt | `line="560"` lineRule="exact" |

### Document Structure

```
┌─────────────────────────────────┐
│     发文机关标志 (红头)           │  ← 小标宋 or 红色大字
│     ══════════════════ (红线)    │  ← Red #FF0000, 2pt
├─────────────────────────────────┤
│  发文字号: X机发〔2025〕X号      │  ← 仿宋 三号, centered
│                                 │
│  标题 (Title)                   │  ← 小标宋 二号, centered
│                                 │     可分多行，回行居中
│  主送机关:                      │  ← 仿宋 三号
│                                 │
│  正文 (Body)...                 │  ← 仿宋_GB2312 三号
│  一、一级标题                    │  ← 黑体 三号
│  （一）二级标题                  │  ← 楷体 三号
│  1. 三级标题                    │  ← 仿宋 三号 加粗
│  (1) 四级标题                   │  ← 仿宋 三号
│                                 │
│  附件: 1. xxx                   │  ← 仿宋 三号
│                                 │
│  发文机关署名                    │  ← 仿宋 三号
│  成文日期                       │  ← 仿宋 三号, 小写中文数字
├─────────────────────────────────┤
│  ══════════════════ (版记线)     │
│  抄送: xxx                      │  ← 仿宋 四号
│  印发机关及日期                   │  ← 仿宋 四号
└─────────────────────────────────┘
```

### Numbering System

```
一、        ← 黑体 (SimHei), no indentation
（一）      ← 楷体 (KaiTi), indented 2 chars
1.          ← 仿宋加粗 (FangSong Bold), indented 2 chars
(1)         ← 仿宋 (FangSong), indented 2 chars
```

### Colors

| Element | Color | Requirement |
|---------|-------|-------------|
| All body text | Black #000000 | Mandatory |
| 红头 (agency name) | Red #FF0000 | Mandatory |
| 红线 (separator) | Red #FF0000 | Mandatory |
| 公章 (official seal) | Red | Mandatory |

### Page Numbers

- Position: bottom center
- Format: `-X-` (dash-number-dash)
- Font: 宋体 四号 (SimSun 14pt, `sz="28"`)
- No page number on cover page if present

---

## Mixed Script

### Font Size Harmony

CJK characters appear larger than Latin characters at the same point size. Compensation:

- If body is Calibri 11pt, pair with CJK at 11pt (same size — CJK looks slightly larger but acceptable)
- If precise visual match needed, CJK can be set 0.5–1pt smaller
- In practice, same point size is standard — don't over-optimize

### Bold and Italic

- **Chinese/Japanese have no true italic.** Word synthesizes a slant which looks poor
- Use **bold** for emphasis in CJK text
- Use 着重号 (emphasis dots) for traditional emphasis: `<w:em w:val="dot"/>` on RunProperties

---

## OpenXML Quick Reference

### Set EastAsia Font (C#)

```csharp
new Run(
    new RunProperties(
        new RunFonts { EastAsia = "SimSun", Ascii = "Calibri", HighAnsi = "Calibri" },
        new FontSize { Val = "32" }  // 三号 = 16pt = sz 32
    ),
    new Text("这是正文内容")
);
```

### Document Defaults (C#)

```csharp
new DocDefaults(new RunPropertiesDefault(new RunPropertiesBaseStyle(
    new RunFonts {
        Ascii = "Calibri", HighAnsi = "Calibri",
        EastAsia = "Microsoft YaHei"
    },
    new Languages { Val = "en-US", EastAsia = "zh-CN" }
)));
```

### 公文 Style Definitions (C#)

```csharp
// Title style — 小标宋 二号 centered
new Style(
    new StyleName { Val = "GongWen Title" },
    new BasedOn { Val = "Normal" },
    new StyleRunProperties(
        new RunFonts { EastAsia = "FZXiaoBiaoSong-B05S" },
        new FontSize { Val = "44" },  // 二号 = 22pt
        new Bold()
    ),
    new StyleParagraphProperties(
        new Justification { Val = JustificationValues.Center },
        new SpacingBetweenLines { Line = "560", LineRule = LineSpacingRuleValues.Exact }
    )
) { Type = StyleValues.Paragraph, StyleId = "GongWenTitle" };

// Body style — 仿宋_GB2312 三号
new Style(
    new StyleName { Val = "GongWen Body" },
    new StyleRunProperties(
        new RunFonts { EastAsia = "FangSong_GB2312", Ascii = "FangSong_GB2312" },
        new FontSize { Val = "32" }  // 三号 = 16pt
    ),
    new StyleParagraphProperties(
        new SpacingBetweenLines { Line = "560", LineRule = LineSpacingRuleValues.Exact }
    )
) { Type = StyleValues.Paragraph, StyleId = "GongWenBody" };
```

### Emphasis Dots (着重号)

```csharp
new RunProperties(new Emphasis { Val = EmphasisMarkValues.Dot });
```

### East Asian Text Layout

```xml
<!-- Snap to grid (align CJK chars to character grid) -->
<w:snapToGrid w:val="true"/>

<!-- Two-lines-in-one (双行合一) -->
<w:eastAsianLayout w:id="1" w:combine="true"/>

<!-- Vertical text in a cell -->
<w:textDirection w:val="tbRl"/>
```


path: references/cjk_university_template_guide.md
content: # Chinese University Thesis Template Guide (中国高校论文模板指南)

## Why This Guide Exists

Chinese university thesis templates (.docx) have structural patterns that differ significantly
from Western templates. Agents that assume Western conventions (Heading1/Heading2/Normal) will
fail repeatedly. This guide documents the ACTUAL patterns found in Chinese templates.

## Common StyleId Patterns

### Pattern A: Numeric IDs (most common in Chinese Word templates)

| Style Purpose | styleId | w:name | w:basedOn |
|--------------|---------|--------|-----------|
| Normal body | `a` | "Normal" | — |
| Default paragraph font | `a0` | "Default Paragraph Font" | — |
| Heading 1 (章标题) | `1` | "heading 1" | `a` |
| Heading 2 (节标题) | `2` | "heading 2" | `a` |
| Heading 3 (小节标题) | `3` | "heading 3" | `a` |
| TOC 1 | `11` | "toc 1" | `a` |
| TOC 2 | `21` | "toc 2" | `a` |
| TOC 3 | `31` | "toc 3" | `a` |
| Header | `a3` | "header" | `a` |
| Footer | `a4` | "footer" | `a` |
| Table of Contents heading | `10` | "TOC Heading" | `1` |

### Pattern B: English IDs (less common, usually from international templates)
Standard Heading1/Heading2/Heading3/Normal — these follow the Western pattern.

### Pattern C: Mixed (some Chinese, some English)
Some templates define custom styles with Chinese names:
| Style Purpose | styleId | w:name |
|--------------|---------|--------|
| 论文标题 | `lunwenbiaoti` | "论文标题" |
| 章标题 | `zhangbiaoti` | "章标题" |
| 正文 | `zhengwen` | "正文" |

### How to Identify Which Pattern

```bash
# Extract all styleIds from the template
$CLI analyze --input template.docx --styles-only

# Or manually:
# unzip template.docx word/styles.xml
# Search for w:styleId= in the extracted file
```

Look at the first few styleIds. If you see `1`, `2`, `3`, `a`, `a0` → Pattern A.
If you see `Heading1`, `Normal` → Pattern B.

## Standard Thesis Structure

Chinese university theses follow a highly standardized structure:

```
┌─────────────────────────────────────┐
│ 封面 (Cover Page)                    │  ← Usually 1-2 pages
│   - 校名、校徽                       │
│   - 论文题目 (title)                  │
│   - 作者、导师、院系、日期             │
├─────────────────────────────────────┤
│ 学术诚信承诺书 / 独创性声明            │  ← 1 page
│   (Academic Integrity Declaration)   │
├─────────────────────────────────────┤
│ 中文摘要 (Chinese Abstract)          │  ← 1-2 pages
│   - "摘 要" heading                  │
│   - Abstract body                    │
│   - "关键词：" line                  │
├─────────────────────────────────────┤
│ 英文摘要 (English Abstract)          │  ← 1-2 pages
│   - "ABSTRACT" heading              │
│   - Abstract body                    │
│   - "Keywords:" line                 │
├─────────────────────────────────────┤
│ 目录 (Table of Contents)             │  ← 1-3 pages
│   - Often inside SDT block           │
│   - Static example entries           │
│   - TOC field code                   │
├─────────────────────────────────────┤
│ 正文 (Body)                          │  ← Main content
│   第1章 绪论                          │
│   1.1 研究背景                        │
│   1.2 研究目的和意义                   │
│   第2章 文献综述                       │
│   ...                                │
│   第N章 结论与展望                     │
├─────────────────────────────────────┤
│ 参考文献 (References)                │  ← Styled differently
├─────────────────────────────────────┤
│ 致谢 (Acknowledgments)              │  ← Optional
├─────────────────────────────────────┤
│ 附录 (Appendices)                    │  ← Optional
└─────────────────────────────────────┘
```

## Identifying Zone Boundaries in Templates

Templates contain EXAMPLE content that must be replaced. Here's how to find the zones:

### Zone A (Front matter) — KEEP from template
- Starts at: paragraph 0
- Ends at: the paragraph BEFORE the first chapter heading
- Contains: cover, declaration, abstracts, TOC
- How to detect end: search for first paragraph with style `1` (or Heading1) containing "第1章" or "绪论"

### Zone B (Body content) — REPLACE with user content
- Starts at: first chapter heading ("第1章...")
- Ends at: "参考文献" heading (inclusive) or last body paragraph before acknowledgments
- How to detect:
  ```python
  for i, el in enumerate(body_elements):
      text = get_text(el)
      style = get_style(el)
      if style in ('1', 'Heading1') and ('第1章' in text or '绪论' in text):
          zone_b_start = i
      if '参考文献' in text:
          zone_b_end = i
  ```

### Zone C (Back matter) — KEEP from template (or remove)
- Starts after: 参考文献
- Contains: 致谢, 附录, final sectPr

## Font Expectations in Chinese Thesis Templates

| Element | Font | Size (字号) | Size (pt) | w:sz |
|---------|------|------------|-----------|------|
| 论文标题 | 华文中宋 or 黑体 | 二号 or 小二 | 22pt or 18pt | 44 or 36 |
| 章标题 (H1) | 黑体 | 三号 | 16pt | 32 |
| 节标题 (H2) | 黑体 | 四号 | 14pt | 28 |
| 小节标题 (H3) | 黑体 | 小四 | 12pt | 24 |
| 正文 | 宋体 | 小四 | 12pt | 24 |
| 页眉 | 宋体 | 五号 | 10.5pt | 21 |
| 页脚/页码 | 宋体 | 五号 | 10.5pt | 21 |
| 表格内容 | 宋体 | 五号 | 10.5pt | 21 |
| 参考文献条目 | 宋体 | 五号 | 10.5pt | 21 |

## RunFonts for CJK Body Text

```xml
<w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman"
          w:eastAsia="宋体" w:cs="Times New Roman"/>
```

For headings:
```xml
<w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman"
          w:eastAsia="黑体" w:cs="Times New Roman"/>
```

IMPORTANT: When cleaning direct formatting, ALWAYS preserve w:eastAsia.
Removing it causes Chinese text to fall back to the wrong font.

## Common Mistakes with Chinese Templates

1. **Searching for `Heading1`** — Chinese templates use `1`, not `Heading1`
2. **Clearing all rFonts** — Must keep eastAsia font declarations
3. **Assuming "第1章" is the first paragraph** — It's typically paragraph 100+ after cover/abstract/TOC
4. **Ignoring SDT blocks in TOC** — The TOC is wrapped in an SDT, not just field codes
5. **Wrong line spacing** — Chinese theses typically use fixed 20pt (line="400") or 22pt (line="440"), not the 28pt used in government documents
6. **Missing section breaks** — Each zone (abstract, TOC, body) usually has its own sectPr for different headers/footers

## Style Mapping Quick Reference

When source document uses Western IDs and template uses Chinese numeric IDs:

```json
{
  "Heading1": "1",
  "Heading2": "2",
  "Heading3": "3",
  "Heading4": "3",
  "Normal": "a",
  "BodyText": "a",
  "ListParagraph": "a",
  "Caption": "a",
  "TOC1": "11",
  "TOC2": "21",
  "TOC3": "31"
}
```

When source uses Chinese numeric IDs and template uses Western IDs — reverse the mapping.


path: references/comments_guide.md
content: # Comments System Guide (4-File Architecture)

## Overview

Word comments require coordination across **four XML files** plus references in `document.xml`, `[Content_Types].xml`, and `document.xml.rels`.

---

## The Four Comment Files

### 1. `word/comments.xml` — Main Comment Content

Contains the actual comment text:

```xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w:comments xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
            xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships">
  <w:comment w:id="1" w:author="Alice" w:date="2026-03-21T09:00:00Z" w:initials="A">
    <w:p>
      <w:pPr><w:pStyle w:val="CommentText" /></w:pPr>
      <w:r>
        <w:rPr><w:rStyle w:val="CommentReference" /></w:rPr>
        <w:annotationRef />
      </w:r>
      <w:r>
        <w:t>This needs clarification.</w:t>
      </w:r>
    </w:p>
  </w:comment>
</w:comments>
```

Key attributes: `w:id` (unique integer), `w:author`, `w:date` (ISO 8601), `w:initials`.

### 2. `word/commentsExtended.xml` — W15 Extensions

Links comments to paragraphs and tracks resolved status:

```xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w15:commentsEx xmlns:w15="http://schemas.microsoft.com/office/word/2012/wordml">
  <w15:commentEx w15:paraId="1A2B3C4D" w15:done="0" />
</w15:commentsEx>
```

- `w15:paraId` — matches the `w14:paraId` of the comment's paragraph in `comments.xml`
- `w15:done` — `"0"` = open, `"1"` = resolved

### 3. `word/commentsIds.xml` — Persistent ID Mapping

Provides durable IDs that survive copy/paste across documents:

```xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w16cid:commentsIds xmlns:w16cid="http://schemas.microsoft.com/office/word/2016/wordml/cid">
  <w16cid:commentId w16cid:paraId="1A2B3C4D" w16cid:durableId="12345678" />
</w16cid:commentsIds>
```

- `w16cid:paraId` — same as `w15:paraId`
- `w16cid:durableId` — globally unique identifier (8-digit hex)

### 4. `word/commentsExtensible.xml` — W16 Extensions

Modern comment extensions (used in newer Word versions):

```xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<w16cex:commentsExtensible xmlns:w16cex="http://schemas.microsoft.com/office/word/2018/wordml/cex">
  <w16cex:commentExtensible w16cex:durableId="12345678" w16cex:dateUtc="2026-03-21T09:00:00Z" />
</w16cex:commentsExtensible>
```

---

## Document.xml References

Comments are anchored in document content using three elements:

```xml
<w:p>
  <w:commentRangeStart w:id="1" />
  <w:r><w:t>This text has a comment.</w:t></w:r>
  <w:commentRangeEnd w:id="1" />
  <w:r>
    <w:rPr><w:rStyle w:val="CommentReference" /></w:rPr>
    <w:commentReference w:id="1" />
  </w:r>
</w:p>
```

- `w:commentRangeStart` — marks where the commented text begins
- `w:commentRangeEnd` — marks where the commented text ends
- `w:commentReference` — the visible comment marker (superscript number), placed in a run after the range end

The `w:id` on all three must match the `w:id` in `comments.xml`.

---

## Content Types Registration

Add to `[Content_Types].xml`:

```xml
<Override PartName="/word/comments.xml"
          ContentType="application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml" />
<Override PartName="/word/commentsExtended.xml"
          ContentType="application/vnd.ms-word.commentsExtended+xml" />
<Override PartName="/word/commentsIds.xml"
          ContentType="application/vnd.ms-word.commentsIds+xml" />
<Override PartName="/word/commentsExtensible.xml"
          ContentType="application/vnd.ms-word.commentsExtensible+xml" />
```

---

## Relationship Registration

Add to `word/_rels/document.xml.rels`:

```xml
<Relationship Id="rId20" Type="http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"
              Target="comments.xml" />
<Relationship Id="rId21" Type="http://schemas.microsoft.com/office/2011/relationships/commentsExtended"
              Target="commentsExtended.xml" />
<Relationship Id="rId22" Type="http://schemas.microsoft.com/office/2016/09/relationships/commentsIds"
              Target="commentsIds.xml" />
<Relationship Id="rId23" Type="http://schemas.microsoft.com/office/2018/08/relationships/commentsExtensible"
              Target="commentsExtensible.xml" />
```

---

## Step-by-Step: Adding a New Comment

1. **Choose a unique comment ID** (scan existing `w:id` values, use max + 1)
2. **Generate a paraId** (8-character hex, e.g., `"1A2B3C4D"`) and durableId (8-digit hex)
3. **Add to `comments.xml`**: Create `w:comment` element with content
4. **Add to `commentsExtended.xml`**: Create `w15:commentEx` with `paraId`, `done="0"`
5. **Add to `commentsIds.xml`**: Create `w16cid:commentId` with `paraId` and `durableId`
6. **Add to `commentsExtensible.xml`**: Create `w16cex:commentExtensible` with `durableId` and `dateUtc`
7. **Add to `document.xml`**: Insert `w:commentRangeStart`, `w:commentRangeEnd`, and `w:commentReference` around target text
8. **Verify `[Content_Types].xml`** and `document.xml.rels` have entries for all 4 files

---

## Step-by-Step: Adding a Reply

Replies are comments whose paragraph's `w14:paraId` links to a parent comment:

1. Create a new `w:comment` in `comments.xml` with a new `w:id`
2. In `commentsExtended.xml`, add `w15:commentEx` with:
   - `w15:paraId` = new paragraph ID
   - `w15:paraIdParent` = the `paraId` of the comment being replied to
   - `w15:done="0"`
3. Add entries in `commentsIds.xml` and `commentsExtensible.xml`
4. In `document.xml`, the reply does NOT need its own range markers — it shares the parent's range

```xml
<!-- In commentsExtended.xml -->
<w15:commentEx w15:paraId="5E6F7A8B" w15:paraIdParent="1A2B3C4D" w15:done="0" />
```

---

## Step-by-Step: Resolving a Comment

Set `w15:done="1"` on the comment's `w15:commentEx` entry:

```xml
<!-- Before -->
<w15:commentEx w15:paraId="1A2B3C4D" w15:done="0" />

<!-- After -->
<w15:commentEx w15:paraId="1A2B3C4D" w15:done="1" />
```

This marks the comment (and all its replies) as resolved. The comment remains visible but appears grayed out in Word.

---

## Minimum Viable Comment

At minimum, a working comment requires:
1. `comments.xml` with the `w:comment` element
2. `document.xml` with range markers and reference
3. Relationship in `document.xml.rels`
4. Content type in `[Content_Types].xml`

The extended files (`commentsExtended`, `commentsIds`, `commentsExtensible`) are optional but recommended for full compatibility with modern Word.


path: references/design_good_bad_examples.md
content: # GOOD vs BAD Document Design — Concrete OpenXML Examples

A side-by-side reference showing common design mistakes and their fixes, with exact OpenXML parameter values. Use this to develop an intuitive sense of what makes a document look professional versus amateur.

Format: Each comparison shows the **BAD** version first (the mistake), then the **GOOD** version (the fix), with OpenXML markup and a short explanation.

---

## 1. Font Size Disasters

### 1a. No Hierarchy — Everything the Same Size

**BAD: Body=12pt, H1=12pt bold**
```
┌──────────────────────────────────┐
│ INTRODUCTION                     │  ← 12pt bold... same visual weight
│ This is the body text of the     │  ← 12pt regular
│ report. It discusses findings    │
│ from the quarterly review.       │
│ METHODOLOGY                      │  ← Where does the section start?
│ We collected data from three     │
│ sources across the enterprise.   │
└──────────────────────────────────┘
```
```xml
<!-- H1: bold but same size as body — no visual separation -->
<w:rPr><w:b/><w:sz w:val="24"/></w:rPr>
<!-- Body -->
<w:rPr><w:sz w:val="24"/></w:rPr>
```

**GOOD: Modular scale — body=11pt, H3=13pt, H2=16pt, H1=20pt**
```
┌──────────────────────────────────┐
│                                  │
│ Introduction                     │  ← 20pt, clearly a title
│                                  │
│ This is the body text of the     │  ← 11pt, comfortable reading size
│ report. It discusses findings    │
│ from the quarterly review.       │
│                                  │
│ Methodology                      │  ← 20pt, section break is obvious
│                                  │
│ We collected data from three     │
│ sources across the enterprise.   │
└──────────────────────────────────┘
```
```xml
<!-- H1: 20pt = w:sz 40 -->
<w:rPr><w:rFonts w:ascii="Calibri Light"/><w:sz w:val="40"/></w:rPr>
<!-- H2: 16pt = w:sz 32 -->
<w:rPr><w:rFonts w:ascii="Calibri Light"/><w:sz w:val="32"/></w:rPr>
<!-- H3: 13pt = w:sz 26, bold -->
<w:rPr><w:rFonts w:ascii="Calibri"/><w:b/><w:sz w:val="26"/></w:rPr>
<!-- Body: 11pt = w:sz 22 -->
<w:rPr><w:rFonts w:ascii="Calibri"/><w:sz w:val="22"/></w:rPr>
```
**Why better:** A clear size progression (ratio ~1.25x per step) lets readers instantly identify structure without reading a word.

---

### 1b. Too Much Contrast — Children's Book Look

**BAD: H1=28pt with body=10pt (ratio 2.8x)**
```
┌──────────────────────────────────┐
│                                  │
│ QUARTERLY REPORT                 │  ← 28pt, dominates the page
│                                  │
│ This is body text set very small │  ← 10pt, straining to read
│ and the contrast with the title  │
│ makes it feel like a poster.     │
└──────────────────────────────────┘
```
```xml
<w:rPr><w:b/><w:sz w:val="56"/></w:rPr>  <!-- 28pt heading -->
<w:rPr><w:sz w:val="20"/></w:rPr>         <!-- 10pt body -->
```

**GOOD: H1=20pt with body=11pt (ratio ~1.8x)**
```xml
<w:rPr><w:sz w:val="40"/></w:rPr>  <!-- 20pt heading -->
<w:rPr><w:sz w:val="22"/></w:rPr>  <!-- 11pt body -->
```
**Why better:** A heading-to-body ratio between 1.5x and 2.0x reads as "structured" rather than "shouting."

---

## 2. Spacing Crimes

### 2a. Wall of Text — No Paragraph or Line Spacing

**BAD: Single line spacing, 0pt between paragraphs**
```
┌──────────────────────────────────┐
│The findings indicate a strong    │
│correlation between training hours│
│and performance metrics.          │
│Further analysis revealed that    │  ← No gap — where does the new
│departments with higher budgets   │     paragraph start?
│achieved better outcomes in all   │
│measured categories.              │
└──────────────────────────────────┘
```
```xml
<w:pPr>
  <w:spacing w:line="240" w:lineRule="auto"/>  <!-- 1.0 spacing (240/240) -->
  <w:spacing w:after="0"/>                     <!-- no paragraph gap -->
</w:pPr>
```

**GOOD: 1.15x line spacing, 8pt after each paragraph**
```
┌──────────────────────────────────┐
│The findings indicate a strong    │
│correlation between training      │  ← Slightly more air between lines
│hours and performance metrics.    │
│                                  │  ← 8pt gap signals new paragraph
│Further analysis revealed that    │
│departments with higher budgets   │
│achieved better outcomes in all   │
│measured categories.              │
└──────────────────────────────────┘
```
```xml
<w:pPr>
  <w:spacing w:line="276" w:lineRule="auto"/>  <!-- 1.15x (276/240) -->
  <w:spacing w:after="160"/>                   <!-- 8pt = 160 twips -->
</w:pPr>
```
**Why better:** Line spacing gives each line room to breathe; paragraph spacing separates ideas without wasting a full blank line.

---

### 2b. Floating Headings — Same Space Above and Below

**BAD: 12pt before and 12pt after heading**
```
┌──────────────────────────────────┐
│ ...end of previous section.      │
│                                  │  ← 12pt gap
│ Section Two                      │  ← Heading floats in the middle
│                                  │  ← 12pt gap
│ Start of section two content.    │
└──────────────────────────────────┘
```
```xml
<w:pPr>
  <w:spacing w:before="240" w:after="240"/>  <!-- 12pt both sides -->
</w:pPr>
```

**GOOD: 24pt before, 8pt after heading**
```
┌──────────────────────────────────┐
│ ...end of previous section.      │
│                                  │
│                                  │  ← 24pt gap — clear section break
│ Section Two                      │  ← Heading is close to its content
│                                  │  ← 8pt gap
│ Start of section two content.    │
└──────────────────────────────────┘
```
```xml
<w:pPr>
  <w:spacing w:before="480" w:after="160"/>  <!-- 24pt before, 8pt after -->
</w:pPr>
```
**Why better:** Proximity principle: a heading belongs to the text that follows it, so more space above and less space below anchors it to its content.

---

### 2c. Wasteful Gaps — Huge Spacing Everywhere

**BAD: 24pt after every paragraph, including body text**
```
┌──────────────────────────────────┐
│ First paragraph of text here.    │
│                                  │
│                                  │  ← 24pt gap after every paragraph
│                                  │
│ Second paragraph of text here.   │
│                                  │
│                                  │
│                                  │
│ Third paragraph.                 │  ← Document looks mostly white space
└──────────────────────────────────┘
```
```xml
<w:spacing w:after="480"/>  <!-- 24pt = 480 twips after every paragraph -->
```

**GOOD: Proportional spacing — body=8pt, H2=6pt after, H1=10pt after**
```xml
<!-- Body paragraph -->
<w:spacing w:after="160"/>   <!-- 8pt after body -->
<!-- H1 -->
<w:spacing w:before="480" w:after="200"/>  <!-- 24pt before, 10pt after -->
<!-- H2 -->
<w:spacing w:before="320" w:after="120"/>  <!-- 16pt before, 6pt after -->
```
**Why better:** Spacing should vary by element role, creating a visual rhythm rather than uniform gaps.

---

## 3. Margin Mistakes

### 3a. Cramped Margins — Text Running to the Edge

**BAD: 0.5in margins all around**
```
┌────────────────────────────────────────────────┐
│Text starts almost at the paper edge and runs   │
│all the way across making extremely long lines  │
│that are hard to track from end back to start.  │
│The eye loses its place on every line return.   │
└────────────────────────────────────────────────┘
```
```xml
<w:pgMar w:top="720" w:right="720" w:bottom="720" w:left="720"/>
<!-- 720 twips = 0.5in — line length ~7.5in on letter paper -->
```

**GOOD: 1in margins (standard)**
```xml
<w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440"/>
<!-- 1440 twips = 1.0in — line length ~6.5in, ideal for 11pt body -->
```
**Why better:** Optimal line length is 60-75 characters. At 11pt Calibri, 6.5in width achieves roughly 70 characters per line.

---

### 3b. Over-Padded Margins — Looks Like the Content is Hiding

**BAD: 2in margins on a short document**
```xml
<w:pgMar w:top="2880" w:right="2880" w:bottom="2880" w:left="2880"/>
<!-- 2880 twips = 2.0in — only 4.5in of text width, looks padded -->
```

**GOOD: 1in standard, or 1.25in for formal documents**
```xml
<!-- Standard -->
<w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440"/>
<!-- Formal / bound documents with gutter -->
<w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1800" w:gutter="0"/>
<!-- 1800 twips = 1.25in left for binding margin -->
```
**Why better:** Margins should frame the content, not overwhelm it. 1-1.25in works for virtually all business and academic documents.

---

## 4. Table Ugliness

### 4a. Prison Grid — Full Borders on Every Cell

**BAD: Every cell with 1pt borders on all four sides**
```
┌───────┬───────┬───────┬───────┐
│ Name  │ Dept  │ Score │ Grade │
├───────┼───────┼───────┼───────┤
│ Alice │ Eng   │ 92    │ A     │
├───────┼───────┼───────┼───────┤
│ Bob   │ Sales │ 85    │ B     │
├───────┼───────┼───────┼───────┤
│ Carol │ Eng   │ 78    │ C+    │
└───────┴───────┴───────┴───────┘
```
```xml
<w:tcBorders>
  <w:top w:val="single" w:sz="4" w:color="000000"/>
  <w:left w:val="single" w:sz="4" w:color="000000"/>
  <w:bottom w:val="single" w:sz="4" w:color="000000"/>
  <w:right w:val="single" w:sz="4" w:color="000000"/>
</w:tcBorders>
```

**GOOD: Three-line table (三线表) — top thick, header-bottom medium, table-bottom thick**
```
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━  ← 1.5pt top border
  Name    Dept    Score   Grade
──────────────────────────────────  ← 0.75pt header separator
  Alice   Eng     92      A
  Bob     Sales   85      B
  Carol   Eng     78      C+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━  ← 1.5pt bottom border
```
```xml
<!-- Top border of header row cells -->
<w:top w:val="single" w:sz="12" w:color="000000"/>    <!-- 1.5pt -->
<w:left w:val="nil"/><w:right w:val="nil"/>
<w:bottom w:val="single" w:sz="6" w:color="000000"/>  <!-- 0.75pt -->

<!-- Data row cells: no left/right/top borders -->
<w:top w:val="nil"/><w:left w:val="nil"/><w:right w:val="nil"/>
<w:bottom w:val="nil"/>

<!-- Last row bottom border -->
<w:bottom w:val="single" w:sz="12" w:color="000000"/> <!-- 1.5pt -->
```
**Why better:** Removing inner borders lets the eye scan data freely. Three lines provide structure without visual clutter.

---

### 4b. Text Touching Borders — No Cell Padding

**BAD: Zero cell margins**
```
┌──────────┬──────────┐
│Name      │Department│  ← Text cramped against borders
├──────────┼──────────┤
│Alice     │Engineering│
└──────────┴──────────┘
```
```xml
<w:tcMar>
  <w:top w:w="0" w:type="dxa"/>
  <w:start w:w="0" w:type="dxa"/>
  <w:bottom w:w="0" w:type="dxa"/>
  <w:end w:w="0" w:type="dxa"/>
</w:tcMar>
```

**GOOD: 0.08in vertical, 0.12in horizontal padding**
```xml
<w:tcMar>
  <w:top w:w="115" w:type="dxa"/>      <!-- ~0.08in = 115 twips -->
  <w:start w:w="173" w:type="dxa"/>    <!-- ~0.12in = 173 twips -->
  <w:bottom w:w="115" w:type="dxa"/>
  <w:end w:w="173" w:type="dxa"/>
</w:tcMar>
```
**Why better:** Padding gives text breathing room inside cells, making every value easier to read.

---

### 4c. Invisible Headers — Header Row Same Style as Data

**BAD: Header row indistinguishable from data**
```xml
<!-- Header cell run properties — identical to data -->
<w:rPr><w:sz w:val="22"/></w:rPr>
```

**GOOD: Bold header text, subtle background fill, bottom border**
```xml
<!-- Header cell run properties -->
<w:rPr><w:b/><w:sz w:val="22"/><w:color w:val="333333"/></w:rPr>

<!-- Header cell shading -->
<w:tcPr>
  <w:shd w:val="clear" w:color="auto" w:fill="F2F2F2"/>  <!-- light gray bg -->
  <w:tcBorders>
    <w:bottom w:val="single" w:sz="8" w:color="666666"/>  <!-- 1pt separator -->
  </w:tcBorders>
</w:tcPr>

<!-- Mark row as header (repeats on page break) -->
<w:trPr><w:tblHeader/></w:trPr>
```
**Why better:** Distinct header styling lets readers instantly locate column meanings, especially in long tables that span pages. The `w:tblHeader` element ensures the header row repeats on every page.

---

## 5. Font Pairing Failures

### 5a. Visual Chaos — Too Many Fonts

**BAD: 4+ fonts in one document**
```xml
<!-- H1 in Impact -->
<w:rPr><w:rFonts w:ascii="Impact"/><w:sz w:val="40"/></w:rPr>
<!-- H2 in Georgia -->
<w:rPr><w:rFonts w:ascii="Georgia"/><w:sz w:val="32"/></w:rPr>
<!-- Body in Verdana -->
<w:rPr><w:rFonts w:ascii="Verdana"/><w:sz w:val="22"/></w:rPr>
<!-- Captions in Courier New -->
<w:rPr><w:rFonts w:ascii="Courier New"/><w:sz w:val="18"/></w:rPr>
```

**GOOD: One font family with weight variation, or two complementary families**
```xml
<!-- H1: Calibri Light (thin weight of Calibri family) -->
<w:rPr><w:rFonts w:ascii="Calibri Light"/><w:sz w:val="40"/></w:rPr>
<!-- H2: Calibri Light -->
<w:rPr><w:rFonts w:ascii="Calibri Light"/><w:sz w:val="32"/></w:rPr>
<!-- Body: Calibri (regular weight) -->
<w:rPr><w:rFonts w:ascii="Calibri"/><w:sz w:val="22"/></w:rPr>
<!-- Captions: Calibri -->
<w:rPr><w:rFonts w:ascii="Calibri"/><w:sz w:val="18"/></w:rPr>
```
**Why better:** Limiting to one or two font families creates visual coherence. Vary by size and weight, not by font.

---

### 5b. Mismatched Personality — Comic Sans Meets Times New Roman

**BAD:**
```xml
<w:rPr><w:rFonts w:ascii="Comic Sans MS"/><w:sz w:val="36"/></w:rPr>  <!-- heading -->
<w:rPr><w:rFonts w:ascii="Times New Roman"/><w:sz w:val="24"/></w:rPr> <!-- body -->
```

**GOOD: Fonts with compatible character**
```xml
<w:rPr><w:rFonts w:ascii="Calibri Light"/><w:sz w:val="36"/></w:rPr>   <!-- heading -->
<w:rPr><w:rFonts w:ascii="Calibri"/><w:sz w:val="22"/></w:rPr>          <!-- body -->
```
**Why better:** Paired fonts should share a similar level of formality and geometric character. Comic Sans is playful/informal; Times New Roman is formal/traditional. They clash.

---

### 5c. Everything Bold — Nothing Stands Out

**BAD: Bold on body, headings, captions, everything**
```xml
<w:rPr><w:b/><w:sz w:val="40"/></w:rPr>  <!-- heading: bold -->
<w:rPr><w:b/><w:sz w:val="22"/></w:rPr>  <!-- body: also bold -->
<w:rPr><w:b/><w:sz w:val="18"/></w:rPr>  <!-- caption: still bold -->
```

**GOOD: Bold reserved for headings and key terms only**
```xml
<w:rPr><w:b/><w:sz w:val="40"/></w:rPr>   <!-- H1: bold -->
<w:rPr><w:sz w:val="32"/></w:rPr>          <!-- H2: size alone is enough -->
<w:rPr><w:sz w:val="22"/></w:rPr>          <!-- body: regular weight -->
<w:rPr><w:b/><w:sz w:val="22"/></w:rPr>    <!-- key term inline: bold -->
<w:rPr><w:sz w:val="18"/></w:rPr>          <!-- caption: regular, small -->
```
**Why better:** When everything is emphasized, nothing is emphasized. Bold should be a signal, not a default.

---

## 6. Color Abuse

### 6a. Rainbow Headings

**BAD: Each heading level a different bright color**
```xml
<w:rPr><w:color w:val="FF0000"/><w:sz w:val="40"/></w:rPr>  <!-- H1: red -->
<w:rPr><w:color w:val="00AA00"/><w:sz w:val="32"/></w:rPr>  <!-- H2: green -->
<w:rPr><w:color w:val="0000FF"/><w:sz w:val="26"/></w:rPr>  <!-- H3: blue -->
```

**GOOD: Single accent color for headings, black or dark gray for body**
```xml
<!-- All headings use the same muted accent -->
<w:rPr><w:color w:val="1F4E79"/><w:sz w:val="40"/></w:rPr>  <!-- H1: dark blue -->
<w:rPr><w:color w:val="1F4E79"/><w:sz w:val="32"/></w:rPr>  <!-- H2: same blue -->
<w:rPr><w:color w:val="1F4E79"/><w:sz w:val="26"/></w:rPr>  <!-- H3: same blue -->
<!-- Body in near-black -->
<w:rPr><w:color w:val="333333"/><w:sz w:val="22"/></w:rPr>
```
**Why better:** A single accent color establishes brand consistency. Multiple bright colors compete for attention and look unprofessional.

---

### 6b. Low Contrast — Light Gray on White

**BAD: #CCCCCC text on white background**
```xml
<w:rPr><w:color w:val="CCCCCC"/></w:rPr>
<!-- Contrast ratio: ~1.6:1 — fails WCAG AA (minimum 4.5:1) -->
```

**GOOD: #333333 text on white**
```xml
<w:rPr><w:color w:val="333333"/></w:rPr>
<!-- Contrast ratio: ~12:1 — passes WCAG AAA -->
```
**Why better:** Sufficient contrast is not just an accessibility requirement; it makes text physically easier to read for everyone, especially in printed documents.

---

### 6c. Bright Body Text

**BAD: Body text in a saturated color**
```xml
<w:rPr><w:color w:val="0066FF"/><w:sz w:val="22"/></w:rPr>  <!-- blue body text -->
```

**GOOD: Color reserved for headings and inline accents only**
```xml
<!-- Body: neutral dark -->
<w:rPr><w:color w:val="333333"/><w:sz w:val="22"/></w:rPr>
<!-- Hyperlink: color is functional here -->
<w:rPr><w:color w:val="0563C1"/><w:u w:val="single"/></w:rPr>
```
**Why better:** Colored body text causes eye fatigue over long reading. Reserve color for elements that need to attract attention (headings, links, warnings).

---

## 7. List Formatting Issues

### 7a. Bullet at the Margin — No Indent

**BAD: List items start at the left margin**
```
┌──────────────────────────────────┐
│Here is a paragraph of text.     │
│• First item                      │  ← Bullet at margin, no indent
│• Second item                     │
│• Third item                      │
│Next paragraph continues here.    │
└──────────────────────────────────┘
```
```xml
<w:pPr>
  <w:ind w:left="0" w:hanging="0"/>
</w:pPr>
```

**GOOD: 0.25in left indent with hanging indent for the bullet**
```
┌──────────────────────────────────┐
│Here is a paragraph of text.     │
│   • First item                   │  ← Indented, clearly a list
│   • Second item                  │
│   • Third item                   │
│Next paragraph continues here.    │
└──────────────────────────────────┘
```
```xml
<w:pPr>
  <w:ind w:left="360" w:hanging="360"/>  <!-- 0.25in = 360 twips -->
  <w:numPr>
    <w:ilvl w:val="0"/>
    <w:numId w:val="1"/>
  </w:numPr>
</w:pPr>
```
For nested lists, increment by 360 twips per level:
```xml
<!-- Level 1 -->
<w:ind w:left="720" w:hanging="360"/>   <!-- 0.5in left -->
<!-- Level 2 -->
<w:ind w:left="1080" w:hanging="360"/>  <!-- 0.75in left -->
```
**Why better:** Indentation visually separates lists from body text and makes nesting levels clear.

---

### 7b. List Items with Full Paragraph Spacing

**BAD: List items have the same 8-10pt spacing as body paragraphs**
```
┌──────────────────────────────────┐
│   • First item                   │
│                                  │  ← 10pt gap — looks like separate
│   • Second item                  │     paragraphs, not a list
│                                  │
│   • Third item                   │
└──────────────────────────────────┘
```
```xml
<w:spacing w:after="200"/>  <!-- 10pt after each list item -->
```

**GOOD: Tight spacing between list items (2-4pt)**
```
┌──────────────────────────────────┐
│   • First item                   │
│   • Second item                  │  ← 2pt gap — cohesive list
│   • Third item                   │
└──────────────────────────────────┘
```
```xml
<w:spacing w:after="40" w:line="276" w:lineRule="auto"/>  <!-- 2pt after -->
<!-- Or 4pt: -->
<w:spacing w:after="80"/>
```
**Why better:** Tight spacing groups list items as a single unit, matching how readers expect a list to behave.

---

## 8. Header/Footer Problems

### 8a. Header Text Too Large — Competes with Body

**BAD: Header in 12pt, same as body**
```
┌──────────────────────────────────┐
│ Quarterly Report - Q3 2025       │  ← 12pt header, same as body
│──────────────────────────────────│
│ Introduction                     │
│ This is the body text...         │  ← 12pt body — header distracts
└──────────────────────────────────┘
```
```xml
<!-- Header paragraph -->
<w:rPr><w:sz w:val="24"/></w:rPr>  <!-- 12pt, same as body -->
```

**GOOD: Header in 9pt, gray color, subtle**
```
┌──────────────────────────────────┐
│ Quarterly Report - Q3 2025       │  ← 9pt, gray — present but quiet
│──────────────────────────────────│
│ Introduction                     │
│ This is the body text...         │  ← Body stands out as primary
└──────────────────────────────────┘
```
```xml
<!-- Header paragraph -->
<w:rPr>
  <w:sz w:val="18"/>                <!-- 9pt -->
  <w:color w:val="808080"/>         <!-- medium gray -->
</w:rPr>
<w:pPr>
  <w:pBdr>
    <w:bottom w:val="single" w:sz="4" w:color="D9D9D9"/>  <!-- subtle separator -->
  </w:pBdr>
</w:pPr>
```
**Why better:** Headers are reference information, not primary content. They should be legible but visually subordinate.

---

### 8b. No Page Numbers on a Long Document

**BAD: 20-page document with no page numbers**
```xml
<!-- Footer section: empty or missing -->
```

**GOOD: Page numbers in footer, right-aligned or centered**
```xml
<!-- Footer paragraph with page number field -->
<w:p>
  <w:pPr>
    <w:jc w:val="center"/>
    <w:rPr><w:sz w:val="18"/><w:color w:val="808080"/></w:rPr>
  </w:pPr>
  <w:r>
    <w:rPr><w:sz w:val="18"/><w:color w:val="808080"/></w:rPr>
    <w:fldChar w:fldCharType="begin"/>
  </w:r>
  <w:r>
    <w:instrText> PAGE </w:instrText>
  </w:r>
  <w:r>
    <w:fldChar w:fldCharType="separate"/>
  </w:r>
  <w:r>
    <w:t>1</w:t>
  </w:r>
  <w:r>
    <w:fldChar w:fldCharType="end"/>
  </w:r>
</w:p>
```
**Why better:** Page numbers are essential for navigation in any document over ~3 pages. Readers need to reference specific pages, and printed documents need an ordering mechanism.

---

## 9. CJK-Specific Mistakes

### 9a. Using Italic for Chinese Emphasis

**BAD: Italic applied to Chinese text**
```xml
<w:rPr>
  <w:i/>
  <w:rFonts w:eastAsia="SimSun"/>
  <w:sz w:val="24"/>
</w:rPr>
```
CJK glyphs have no true italic form. The renderer applies a synthetic slant that looks broken and ugly — characters appear to lean awkwardly.

**GOOD: Use bold or emphasis dots (着重号) for Chinese emphasis**
```xml
<!-- Option A: Bold emphasis -->
<w:rPr>
  <w:b/>
  <w:rFonts w:eastAsia="SimHei"/>  <!-- Switch to bold-capable font -->
  <w:sz w:val="24"/>
</w:rPr>

<!-- Option B: Emphasis marks (dots under characters) -->
<w:rPr>
  <w:em w:val="dot"/>
  <w:rFonts w:eastAsia="SimSun"/>
  <w:sz w:val="24"/>
</w:rPr>
```
**Why better:** Chinese typography has its own emphasis traditions. Bold and emphasis dots are native CJK conventions; italic is a Latin-script concept that does not translate.

---

### 9b. Latin Font for Chinese Characters

**BAD: Only ASCII font set, no EastAsia font specified**
```xml
<w:rPr>
  <w:rFonts w:ascii="Arial"/>  <!-- No eastAsia attribute -->
  <w:sz w:val="24"/>
</w:rPr>
<!-- Word falls back to a random font. Chinese characters may render
     with wrong metrics, inconsistent stroke widths, or missing glyphs. -->
```

**GOOD: Explicit EastAsia font alongside ASCII font**
```xml
<w:rPr>
  <w:rFonts w:ascii="Calibri" w:hAnsi="Calibri" w:eastAsia="Microsoft YaHei"/>
  <w:sz w:val="22"/>
</w:rPr>
```
For formal/academic Chinese documents:
```xml
<w:rPr>
  <w:rFonts w:ascii="Times New Roman" w:hAnsi="Times New Roman"
            w:eastAsia="SimSun"/>
  <w:sz w:val="24"/>  <!-- 小四 12pt -->
</w:rPr>
```
**Why better:** Setting `w:eastAsia` ensures Chinese characters render in a font designed for CJK glyphs, with correct stroke widths, spacing, and metrics.

---

### 9c. English Line Spacing for Dense CJK Text

**BAD: 1.15x line spacing for Chinese body text**
```xml
<w:spacing w:line="276" w:lineRule="auto"/>  <!-- 1.15x — too tight for CJK -->
```
CJK characters are taller and denser than Latin letters. At 1.15x, lines of Chinese text feel cramped and hard to read.

**GOOD: 1.5x line spacing or fixed 28pt for CJK body at 12pt (小四)**
```xml
<!-- Option A: 1.5x proportional -->
<w:spacing w:line="360" w:lineRule="auto"/>  <!-- 360/240 = 1.5x -->

<!-- Option B: Fixed 28pt (standard for 小四/12pt CJK body) -->
<w:spacing w:line="560" w:lineRule="exact"/>  <!-- 28pt = 560 twips -->
```
For 公文 (government documents) at 三号/16pt body:
```xml
<w:spacing w:line="580" w:lineRule="exact"/>  <!-- 29pt fixed line spacing -->
```
**Why better:** CJK characters occupy a full em square with no ascenders/descenders providing natural gaps. Extra line spacing compensates, improving readability of dense text blocks.

---

## 10. Overall Document Feel

### Student Homework vs Professional Document

**BAD: "Student homework" — every setting is Word's default, no intentional choices**
```xml
<!-- Default everything: Calibri 11pt, no heading styles, 1.08 spacing -->
<w:rPr><w:rFonts w:ascii="Calibri"/><w:sz w:val="22"/></w:rPr>
<w:pPr><w:spacing w:after="160" w:line="259" w:lineRule="auto"/></w:pPr>
<!-- Headings: just bold body text, no style applied -->
<w:rPr><w:b/><w:sz w:val="22"/></w:rPr>
<!-- No section breaks, no headers/footers, no page numbers -->
<!-- Tables with default full grid borders -->
<!-- No intentional color or spacing variations -->
```

**GOOD: Intentional design at every level**
```xml
<!-- Theme fonts defined -->
<w:rFonts w:asciiTheme="minorHAnsi" w:hAnsiTheme="minorHAnsi"/>

<!-- H1: Calibri Light 20pt, dark blue, generous spacing -->
<w:pPr>
  <w:pStyle w:val="Heading1"/>
  <w:spacing w:before="480" w:after="200"/>
</w:pPr>
<w:rPr>
  <w:rFonts w:ascii="Calibri Light"/>
  <w:color w:val="1F4E79"/>
  <w:sz w:val="40"/>
</w:rPr>

<!-- H2: Calibri Light 16pt, same blue -->
<w:pPr>
  <w:pStyle w:val="Heading2"/>
  <w:spacing w:before="320" w:after="120"/>
</w:pPr>
<w:rPr>
  <w:rFonts w:ascii="Calibri Light"/>
  <w:color w:val="1F4E79"/>
  <w:sz w:val="32"/>
</w:rPr>

<!-- Body: Calibri 11pt, dark gray, 1.15 spacing, 8pt after -->
<w:pPr>
  <w:spacing w:after="160" w:line="276" w:lineRule="auto"/>
</w:pPr>
<w:rPr>
  <w:rFonts w:ascii="Calibri"/>
  <w:color w:val="333333"/>
  <w:sz w:val="22"/>
</w:rPr>

<!-- Tables: three-line style, padded cells, repeated headers -->
<!-- Headers/footers: 9pt gray with page numbers -->
<!-- Margins: 1in all around -->
<w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440"/>
```
**Why better:** Professional documents result from deliberate, consistent choices across all design dimensions. Each element reinforces the same visual language. The reader may not consciously notice good typography, but they feel the difference in credibility and readability.

---

## Quick Reference: Safe Defaults

A cheat sheet of values that produce a professional result for most Western business documents:

| Element | Value | OpenXML |
|---------|-------|---------|
| Body font | Calibri 11pt | `w:sz="22"` |
| H1 | Calibri Light 20pt | `w:sz="40"` |
| H2 | Calibri Light 16pt | `w:sz="32"` |
| H3 | Calibri 13pt bold | `w:sz="26"`, `w:b` |
| Body color | #333333 | `w:color="333333"` |
| Heading color | #1F4E79 | `w:color="1F4E79"` |
| Line spacing | 1.15x | `w:line="276" w:lineRule="auto"` |
| Para spacing after | 8pt | `w:after="160"` |
| H1 spacing | 24pt before, 10pt after | `w:before="480" w:after="200"` |
| H2 spacing | 16pt before, 6pt after | `w:before="320" w:after="120"` |
| Margins | 1in all around | `w:pgMar` all `"1440"` |
| Table cell padding | 0.08in / 0.12in | `w:w="115"` / `w:w="173"` |
| Header/footer size | 9pt gray | `w:sz="18" w:color="808080"` |
| List indent | 0.25in per level | `w:left="360" w:hanging="360"` |
| List item spacing | 2pt after | `w:after="40"` |

For CJK documents, adjust: body font to SimSun/YaHei, line spacing to 1.5x (`w:line="360"`), and set `w:eastAsia` on all `w:rFonts`.


path: references/design_principles.md
content: # Design Principles for Document Typography

WHY certain typographic choices look good -- the perceptual and psychological
reasons behind professional document design. Use this to make judgment calls
when exact specs are not provided.

## Table of Contents

1. [White Space & Breathing Room](#1-white-space--breathing-room)
2. [Contrast & Scale](#2-contrast--scale)
3. [Proximity & Grouping](#3-proximity--grouping)
4. [Alignment & Grid](#4-alignment--grid)
5. [Repetition & Consistency](#5-repetition--consistency)
6. [Visual Hierarchy & Flow](#6-visual-hierarchy--flow)

---

## 1. White Space & Breathing Room

### Why It Works

The human eye does not read continuously. It jumps in saccades, fixating on
small clusters of words. White space provides landing zones for these fixations
and gives the reader's peripheral vision a "frame" that makes each text block
feel manageable. When a page is packed to the edges, every glance returns more
text than working memory can buffer, triggering fatigue and avoidance.

Research on content density consistently shows:

- **60-70% content coverage** feels comfortable and professional.
- **80%+** starts to feel dense and bureaucratic.
- **90%+** feels oppressive -- the reader unconsciously rushes or skips.
- **Below 50%** feels wasteful or pretentious (unless intentional, like poetry).

Wider margins also carry cultural signals. Academic and luxury documents use
generous margins (1.25-1.5 inches). Internal memos and drafts use narrower
margins (0.75-1.0 inches). The margin width tells the reader how much care
went into the document before they read a single word.

Line spacing has a direct physiological basis: the eye must track back to the
start of the next line after each line break. If lines are too close, the eye
"slips" to the wrong line. If too far apart, the eye loses its sense of
continuity. The sweet spot is 120-145% of the font size.

**Rule of thumb: when in doubt, add more space, not less.**

### Good Example

```
Margins: 1 inch (1440 twips) all sides for business documents.
Line spacing: 1.15 (276 twips at 240 twips-per-line = 115%).
Paragraph spacing after: 8pt (160 twips) between body paragraphs.
```

```xml
<!-- Page margins: 1 inch = 1440 twips on all sides -->
<w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440"
         w:header="720" w:footer="720" w:gutter="0"/>

<!-- Body paragraph: 1.15 line spacing, 8pt after -->
<w:pPr>
  <w:spacing w:after="160" w:line="276" w:lineRule="auto"/>
</w:pPr>
```

This produces a page where content occupies roughly 65% of the area. The
reader sees clear top/bottom breathing room, and paragraphs are distinct
without feeling disconnected.

```
  Page layout (good):
  +----------------------------------+
  |           1" margin              |
  |   +------------------------+    |
  |   | Heading                |    |
  |   |                        |    |
  |   | Body text here with    |    |
  |   | comfortable spacing    |    |
  |   | between lines.         |    |
  |   |                        |    |  <- visible gap between paragraphs
  |   | Another paragraph of   |    |
  |   | body text follows.     |    |
  |   |                        |    |
  |   +------------------------+    |
  |           1" margin              |
  +----------------------------------+
```

### Bad Example

```xml
<!-- Cramped margins: 0.5 inch = 720 twips -->
<w:pgMar w:top="720" w:right="720" w:bottom="720" w:left="720"
         w:header="360" w:footer="360" w:gutter="0"/>

<!-- No paragraph spacing, single line spacing -->
<w:pPr>
  <w:spacing w:after="0" w:line="240" w:lineRule="auto"/>
</w:pPr>
```

This fills ~85% of the page. Text runs edge-to-edge with no visual rest stops.
The reader sees a wall of text.

```
  Page layout (bad):
  +----------------------------------+
  | Heading                          |
  | Body text crammed right up to    |
  | the margins with no spacing      |
  | between lines or paragraphs.     |
  | Another paragraph starts here    |
  | and the reader cannot tell where |
  | one idea ends and another begins |
  | because everything blurs into a  |
  | single dense block of text.      |
  +----------------------------------+
```

### Quick Test

1. Zoom out to 50% in your document viewer. If you cannot see clear "channels"
   of white between text blocks, the spacing is too tight.
2. Print a test page. Hold it at arm's length. The text area should look like
   a rectangle floating in white, not filling the page.
3. Check: is the line spacing value at least 264 (`w:line` for 1.1x) for body
   text? If it is 240 (single), it is too tight for anything over 10pt.

---

## 2. Contrast & Scale

### Why It Works

The brain processes visual hierarchy through relative difference, not absolute
size. A 20pt heading above 11pt body text creates a clear "this is important"
signal. But if every heading is 20pt and every sub-heading is 19pt, the brain
cannot distinguish them -- they merge into the same level.

The key insight is **modular scale**: font sizes that grow by a consistent
ratio. This mirrors natural proportions and feels harmonious for the same
reason musical intervals do.

Common scales and their character:

| Ratio | Name           | Character                       | Example progression (from 11pt) |
|-------|----------------|---------------------------------|---------------------------------|
| 1.200 | Minor third    | Subtle, refined                 | 11 → 13.2 → 15.8 → 19.0       |
| 1.250 | Major third    | Balanced, professional          | 11 → 13.75 → 17.2 → 21.5      |
| 1.333 | Perfect fourth | Strong, authoritative           | 11 → 14.7 → 19.5 → 26.0       |
| 1.414 | Augmented 4th  | Dramatic, presentation-style    | 11 → 15.6 → 22.0 → 31.1       |

For most business documents, 1.25 (major third) works best:

```
Body  = 11pt  (w:sz="22")
H3    = 13pt  (w:sz="26")   -- 11 * 1.25 ≈ 13.75, round to 13
H2    = 16pt  (w:sz="32")   -- 13 * 1.25 ≈ 16.25, round to 16
H1    = 20pt  (w:sz="40")   -- 16 * 1.25 = 20
```

Beyond size, **weight contrast** creates hierarchy without consuming vertical
space. Regular (400) vs Bold (700) is visible at any size. Semi-bold (600) vs
Regular is subtle and best avoided unless you also vary size or color.

**Color contrast** adds a third dimension. Dark blue headings (#1F3864) against
softer dark gray body text (#333333) signals "heading" without needing a huge
size jump. Pure black (#000000) body text is harsher than necessary on white
backgrounds -- #333333 or #2D2D2D reduces glare without losing legibility.

### Good Example

```xml
<!-- H1: 20pt, bold, dark navy -->
<w:rPr>
  <w:b/>
  <w:sz w:val="40"/>
  <w:color w:val="1F3864"/>
</w:rPr>

<!-- H2: 16pt, bold, dark navy -->
<w:rPr>
  <w:b/>
  <w:sz w:val="32"/>
  <w:color w:val="1F3864"/>
</w:rPr>

<!-- H3: 13pt, bold, dark navy -->
<w:rPr>
  <w:b/>
  <w:sz w:val="26"/>
  <w:color w:val="1F3864"/>
</w:rPr>

<!-- Body: 11pt, regular, dark gray -->
<w:rPr>
  <w:sz w:val="22"/>
  <w:color w:val="333333"/>
</w:rPr>
```

```
  Visual hierarchy (good):

  [████████████████████]        <- H1: 20pt bold navy (clearly dominant)
                                   (generous space)
  [██████████████]              <- H2: 16pt bold navy (distinct step down)
                                   (moderate space)
  [████████████]                <- H3: 13pt bold navy (smaller but still bold)
  [░░░░░░░░░░░░░░░░░░░░░░]    <- Body: 11pt regular gray
  [░░░░░░░░░░░░░░░░░░░░░░]
  [░░░░░░░░░░░░░░░░░░░░░░]
```

Each level is visually distinct from its neighbors. You can identify the
hierarchy even in peripheral vision.

### Bad Example

```xml
<!-- H1: 14pt bold black -->
<w:rPr>
  <w:b/>
  <w:sz w:val="28"/>
  <w:color w:val="000000"/>
</w:rPr>

<!-- H2: 13pt bold black -->
<w:rPr>
  <w:b/>
  <w:sz w:val="26"/>
  <w:color w:val="000000"/>
</w:rPr>

<!-- H3: 12pt bold black -->
<w:rPr>
  <w:b/>
  <w:sz w:val="24"/>
  <w:color w:val="000000"/>
</w:rPr>

<!-- Body: 12pt regular black -->
<w:rPr>
  <w:sz w:val="24"/>
  <w:color w:val="000000"/>
</w:rPr>
```

Problems:
- H3 (12pt bold) and body (12pt regular) differ only by weight -- too subtle.
- H1 (14pt) to H2 (13pt) is a 1pt step -- invisible at reading distance.
- Everything is pure black so color provides no differentiating signal.
- The ratio between levels is ~1.07, far too flat.

### Quick Test

1. **The squint test**: blur your eyes or step back from the screen. Can you
   count the number of heading levels? If two levels merge, their contrast
   is insufficient.
2. **Ratio check**: divide each heading size by the next smaller size. If any
   ratio is below 1.15, the levels will look too similar.
3. **Color check**: do headings look distinct from body text when you glance
   at the page? If everything is the same color, you are relying solely on
   size/weight, which limits your hierarchy to ~3 effective levels.

---

## 3. Proximity & Grouping

### Why It Works

The Gestalt principle of proximity: items that are close together are perceived
as belonging to the same group. In document typography, this means a heading
must be **closer to the content it introduces** than to the content above it.

If a heading sits equidistant between two paragraphs, it looks orphaned -- the
reader's eye does not know if it belongs to the text above or below. The fix
is asymmetric spacing: **large space before the heading, small space after**.

The recommended ratio is 2:1 or 3:1 (space-before : space-after).

This same principle applies to:
- **List items**: spacing between items should be less than spacing between
  paragraphs. Items in a list are a group and should visually cluster.
- **Captions**: a figure caption should be close to its figure, not floating
  in the middle between the figure and the next paragraph.
- **Table titles**: the title sits close above the table, with more space
  separating the title from preceding text.

### Good Example

```xml
<!-- H2: 18pt before, 6pt after (3:1 ratio) -->
<w:pPr>
  <w:pStyle w:val="Heading2"/>
  <w:spacing w:before="360" w:after="120"/>
</w:pPr>

<!-- Body paragraph: 0pt before, 8pt after -->
<w:pPr>
  <w:spacing w:before="0" w:after="160"/>
</w:pPr>

<!-- List item: 0pt before, 2pt after (tight grouping) -->
<w:pPr>
  <w:pStyle w:val="ListParagraph"/>
  <w:spacing w:before="0" w:after="40"/>
</w:pPr>
```

```
  Proximity (good):

  ...end of previous section text.
                                        <- 18pt gap (w:before="360")
  ## Section Heading
                                        <- 6pt gap (w:after="120")
  First paragraph of new section
  continues here with content.
                                        <- 8pt gap (w:after="160")
  Second paragraph follows.

  The heading clearly "belongs to" the text below it.
```

```
  List grouping (good):

  Consider these factors:
    - First item                        <- 2pt gap between items
    - Second item                       <- items cluster as a group
    - Third item
                                        <- 8pt gap after list
  The next paragraph starts here.
```

### Bad Example

```xml
<!-- H2: 12pt before, 12pt after (1:1 ratio -- orphaned heading) -->
<w:pPr>
  <w:pStyle w:val="Heading2"/>
  <w:spacing w:before="240" w:after="240"/>
</w:pPr>

<!-- List item: same spacing as body (10pt after) -->
<w:pPr>
  <w:pStyle w:val="ListParagraph"/>
  <w:spacing w:before="0" w:after="200"/>
</w:pPr>
```

```
  Proximity (bad):

  ...end of previous section text.
                                        <- 12pt gap
  ## Section Heading
                                        <- 12pt gap (same!)
  First paragraph of new section.

  The heading floats between sections. It is unclear what it belongs to.
```

```
  List grouping (bad):

  Consider these factors:
                                        <- 10pt gap
    - First item
                                        <- 10pt gap (same as paragraphs)
    - Second item
                                        <- 10pt gap
    - Third item
                                        <- 10pt gap
  Next paragraph.

  The list does not feel like a group. Each item looks like a
  separate paragraph that happens to have a bullet.
```

### Quick Test

1. **Cover test**: cover the heading text. Looking only at the whitespace,
   can you tell which block of text the heading belongs to? If the gaps above
   and below are equal, the answer is "no."
2. **Number check**: `w:before` on headings should be at least 2x `w:after`.
   Common good values: before=360 / after=120, or before=240 / after=80.
3. **List check**: `w:after` on list items should be less than half of
   `w:after` on body paragraphs. If body uses 160, list items should use
   40-60.

---

## 4. Alignment & Grid

### Why It Works

Alignment creates invisible lines that the eye follows down the page. When
elements share the same left edge, the reader perceives order and intention.
When elements are slightly misaligned (off by a few twips), the page looks
sloppy even if the reader cannot consciously identify why.

**Left-align vs Justify:**

- **Left-aligned** (ragged right) is best for English and other Latin-script
  languages. The uneven right edge actually helps reading because each line
  has a unique silhouette, making it easier for the eye to find the next line.
  Justified text forces uneven word spacing that creates distracting "rivers"
  of white running vertically through paragraphs.

- **Justified** is best for CJK text. Chinese, Japanese, and Korean characters
  are monospaced by design -- each occupies the same cell in an invisible grid.
  Justification preserves this grid perfectly. Ragged right in CJK text breaks
  the grid and looks untidy.

**Indentation rule:** Use first-line indent OR paragraph spacing to separate
paragraphs -- never both. They serve the same purpose (marking paragraph
boundaries). Using both wastes space and creates visual stutter.

- Western convention: paragraph spacing (no indent) is more modern.
- CJK convention: first-line indent of 2 characters is standard.
- Academic convention: first-line indent of 0.5 inch is traditional.

### Good Example

```xml
<!-- English body: left-aligned, paragraph spacing, no indent -->
<w:pPr>
  <w:jc w:val="left"/>
  <w:spacing w:after="160" w:line="276" w:lineRule="auto"/>
  <!-- No w:ind firstLine -->
</w:pPr>

<!-- CJK body: justified, first-line indent 2 chars, no paragraph spacing -->
<w:pPr>
  <w:jc w:val="both"/>
  <w:spacing w:after="0" w:line="360" w:lineRule="auto"/>
  <w:ind w:firstLineChars="200"/>
</w:pPr>

<!-- Tab stops creating aligned columns -->
<w:pPr>
  <w:tabs>
    <w:tab w:val="left" w:pos="2880"/>   <!-- 2 inches -->
    <w:tab w:val="right" w:pos="9360"/>  <!-- 6.5 inches (right margin) -->
  </w:tabs>
</w:pPr>
```

```
  English paragraph separation (good -- spacing, no indent):

  This is the first paragraph with some text
  that wraps to a second line naturally.

  This is the second paragraph. The gap above
  clearly marks the boundary.


  CJK paragraph separation (good -- indent, no spacing):

  　　第一段正文内容从这里开始，使用两个字符
  的首行缩进来标记段落边界。
  　　第二段紧跟其后，没有段间距，但首行缩进
  清晰地标识了新段落的开始。
```

### Bad Example

```xml
<!-- English body: justified (creates word-spacing rivers) -->
<w:pPr>
  <w:jc w:val="both"/>
  <w:spacing w:after="160" w:line="276" w:lineRule="auto"/>
  <w:ind w:firstLine="720"/>  <!-- BOTH indent AND spacing: redundant -->
</w:pPr>

<!-- CJK body: left-aligned (breaks character grid) -->
<w:pPr>
  <w:jc w:val="left"/>
  <w:spacing w:after="200" w:line="276" w:lineRule="auto"/>
  <!-- No indent, using spacing instead -- unidiomatic for CJK -->
</w:pPr>
```

Problems:
- Justified English text with narrow columns creates uneven word gaps.
- Using both first-line indent AND paragraph spacing is redundant.
- Left-aligned CJK breaks the character grid that CJK readers expect.
- CJK with spacing-based separation looks like translated western layout.

### Quick Test

1. **River test**: in justified English text, squint and look for vertical
   white streaks running through the paragraph. If you see them, switch to
   left-align or increase the column width.
2. **Double signal check**: does the document use BOTH first-line indent AND
   paragraph spacing? If yes, remove one. Choose indent for CJK/academic,
   spacing for modern western.
3. **Tab alignment**: if you use tabs for columns, do all tab stops across
   the document use the same positions? Inconsistent tab stops create jagged
   invisible grid lines.

---

## 5. Repetition & Consistency

### Why It Works

Consistency is a trust signal. When a reader sees that every H2 looks the same,
every table follows the same pattern, and every page number sits in the same
spot, they unconsciously trust that the document was crafted with care. A single
inconsistency -- one H2 that is 15pt instead of 14pt, one table with different
borders -- breaks that trust and makes the reader question the content.

Consistency also reduces cognitive load. Once the reader learns "bold dark blue
= section heading," they stop spending mental effort on identifying structure
and focus entirely on content. Every inconsistency forces them to re-evaluate:
"Is this a different kind of heading, or did someone just forget to apply the
style?"

The implementation rule is simple: **use named styles, not direct formatting.**
If you define Heading2 as a style and apply it everywhere, consistency is
automatic. If you manually set font size, bold, and color on each heading
individually, inconsistency is inevitable.

### Good Example

```xml
<!-- Define styles once in styles.xml -->
<w:style w:type="paragraph" w:styleId="Heading2">
  <w:name w:val="heading 2"/>
  <w:basedOn w:val="Normal"/>
  <w:next w:val="Normal"/>
  <w:pPr>
    <w:keepNext/>
    <w:keepLines/>
    <w:spacing w:before="360" w:after="120"/>
    <w:outlineLvl w:val="1"/>
  </w:pPr>
  <w:rPr>
    <w:rFonts w:asciiTheme="majorHAnsi" w:hAnsiTheme="majorHAnsi"/>
    <w:b/>
    <w:sz w:val="32"/>
    <w:color w:val="1F3864"/>
  </w:rPr>
</w:style>

<!-- Apply consistently: every H2 references the style -->
<w:p>
  <w:pPr>
    <w:pStyle w:val="Heading2"/>
    <!-- No direct formatting overrides -->
  </w:pPr>
  <w:r><w:t>Market Analysis</w:t></w:r>
</w:p>
```

When using a table style, define it once and reference it for every table:

```xml
<!-- All tables reference the same style -->
<w:tblPr>
  <w:tblStyle w:val="GridTable4Accent1"/>
  <w:tblW w:w="0" w:type="auto"/>
</w:tblPr>
```

### Bad Example

```xml
<!-- First H2: manually formatted -->
<w:p>
  <w:pPr>
    <w:spacing w:before="360" w:after="120"/>
  </w:pPr>
  <w:r>
    <w:rPr>
      <w:b/>
      <w:sz w:val="32"/>
      <w:color w:val="1F3864"/>
    </w:rPr>
    <w:t>Market Analysis</w:t>
  </w:r>
</w:p>

<!-- Second H2: slightly different (16pt instead of 16pt?  No, 15pt!) -->
<w:p>
  <w:pPr>
    <w:spacing w:before="240" w:after="160"/>  <!-- different spacing! -->
  </w:pPr>
  <w:r>
    <w:rPr>
      <w:b/>
      <w:sz w:val="30"/>   <!-- 15pt instead of 16pt! -->
      <w:color w:val="2E74B5"/>  <!-- different shade of blue! -->
    </w:rPr>
    <w:t>Financial Overview</w:t>
  </w:r>
</w:p>
```

Problems:
- No style references -- everything is direct formatting.
- Second H2 has different size (30 vs 32), color, and spacing.
- If there are 20 headings, each could drift slightly differently.
- Changing the design later means editing every heading individually.

### Quick Test

1. **Style audit**: does every paragraph reference a `w:pStyle`? If you find
   paragraphs with only direct formatting and no style, that is a consistency
   risk.
2. **Search for variance**: search the XML for all `w:sz` values used with
   `w:b` (bold). If you find three different sizes for what should be the same
   heading level, there is an inconsistency.
3. **Table check**: do all tables in the document reference the same
   `w:tblStyle`? If some tables have manual border definitions while others
   use a style, the document will look patchy.
4. **Page numbers**: check that header/footer content is defined in the
   default section properties and inherited by all sections, not redefined
   inconsistently in each section.

---

## 6. Visual Hierarchy & Flow

### Why It Works

A well-designed document guides the reader's eye in a predictable path:
title at the top, subtitle below it, section headings as signposts, body text
as the main content, footnotes and captions as supporting details. This flow
mirrors reading priority -- the most important information is the most visually
prominent.

Each level in the hierarchy must be **distinguishable from its adjacent
levels**. It is not enough for H1 to differ from body text; H1 must also
clearly differ from H2, and H2 from H3. If any two adjacent levels are too
similar, the hierarchy collapses at that point.

Effective hierarchy uses **multiple simultaneous signals**:

| Level    | Size  | Weight  | Color   | Spacing above |
|----------|-------|---------|---------|---------------|
| Title    | 26pt  | Bold    | #1F3864 | 0 (top)       |
| Subtitle | 15pt  | Regular | #4472C4 | 4pt           |
| H1       | 20pt  | Bold    | #1F3864 | 24pt          |
| H2       | 16pt  | Bold    | #1F3864 | 18pt          |
| H3       | 13pt  | Bold    | #1F3864 | 12pt          |
| Body     | 11pt  | Regular | #333333 | 0pt           |
| Caption  | 9pt   | Italic  | #666666 | 4pt           |
| Footnote | 9pt   | Regular | #666666 | 0pt           |

Notice how each level differs from its neighbors on at least two dimensions
(size + weight, or size + color, or weight + style). Single-dimension
differences are fragile and can be missed.

**Section breaks** create rhythm in long documents. A page break before each
major section (H1) gives the reader a mental reset. Within sections, consistent
heading + body patterns create a predictable cadence that makes long documents
less intimidating.

### Good Example

```xml
<!-- Title: large, bold, navy, centered -->
<w:style w:type="paragraph" w:styleId="Title">
  <w:pPr>
    <w:jc w:val="center"/>
    <w:spacing w:after="80"/>
  </w:pPr>
  <w:rPr>
    <w:b/>
    <w:sz w:val="52"/>
    <w:color w:val="1F3864"/>
  </w:rPr>
</w:style>

<!-- Subtitle: medium, regular weight, lighter blue, centered -->
<w:style w:type="paragraph" w:styleId="Subtitle">
  <w:pPr>
    <w:jc w:val="center"/>
    <w:spacing w:after="320"/>
  </w:pPr>
  <w:rPr>
    <w:sz w:val="30"/>
    <w:color w:val="4472C4"/>
  </w:rPr>
</w:style>

<!-- H1: page break before, large bold navy -->
<w:style w:type="paragraph" w:styleId="Heading1">
  <w:pPr>
    <w:pageBreakBefore/>
    <w:keepNext/>
    <w:keepLines/>
    <w:spacing w:before="480" w:after="160"/>
    <w:outlineLvl w:val="0"/>
  </w:pPr>
  <w:rPr>
    <w:b/>
    <w:sz w:val="40"/>
    <w:color w:val="1F3864"/>
  </w:rPr>
</w:style>

<!-- Caption: small, italic, gray -->
<w:style w:type="paragraph" w:styleId="Caption">
  <w:pPr>
    <w:spacing w:before="80" w:after="200"/>
  </w:pPr>
  <w:rPr>
    <w:i/>
    <w:sz w:val="18"/>
    <w:color w:val="666666"/>
  </w:rPr>
</w:style>
```

```
  Visual flow (good):

  +----------------------------------+
  |                                  |
  |     ANNUAL REPORT 2025           |  <- Title: 26pt bold navy centered
  |     Acme Corporation             |  <- Subtitle: 15pt regular blue
  |                                  |
  |                                  |
  +----------------------------------+

  +----------------------------------+
  |                                  |
  |  1. Executive Summary            |  <- H1: 20pt bold navy (page break)
  |                                  |
  |  Body text introducing the       |  <- Body: 11pt regular gray
  |  main findings of the year.      |
  |                                  |
  |  1.1 Revenue Highlights          |  <- H2: 16pt bold navy
  |                                  |
  |  Revenue grew by 23% year        |  <- Body
  |  over year, driven by...         |
  |                                  |
  |  Figure 1: Revenue Growth        |  <- Caption: 9pt italic gray
  |                                  |
  +----------------------------------+

  Each level is immediately identifiable. The eye flows naturally
  from title -> heading -> body -> caption.
```

### Bad Example

```xml
<!-- All headings same color as body, minimal size difference -->
<w:style w:type="paragraph" w:styleId="Heading1">
  <w:rPr>
    <w:b/>
    <w:sz w:val="28"/>       <!-- 14pt -- only 3pt above body -->
    <w:color w:val="000000"/> <!-- same color as body -->
  </w:rPr>
</w:style>

<!-- Caption same size as body, not italic -->
<w:style w:type="paragraph" w:styleId="Caption">
  <w:rPr>
    <w:sz w:val="22"/>        <!-- same 11pt as body! -->
    <w:color w:val="000000"/> <!-- same color as body -->
  </w:rPr>
</w:style>

<!-- No page breaks between major sections -->
<!-- H1 has no pageBreakBefore, keepNext, or keepLines -->
```

Problems:
- H1 at 14pt is too close to body at 11pt (ratio 1.27 -- acceptable in
  isolation but with black color matching body, the hierarchy is weak).
- Caption is indistinguishable from body text.
- No page breaks means major sections bleed into each other with no
  visual rhythm.
- Everything is black, so color provides zero hierarchy signal.

### Quick Test

1. **The squint test**: blur your eyes while looking at a full page. You
   should see 3-4 distinct "weight levels" of gray. If the page looks like
   one uniform shade, the hierarchy is too flat.
2. **The scan test**: flip through pages quickly. Can you identify section
   boundaries in under one second per page? If yes, the visual hierarchy is
   working. If pages blur together, you need stronger differentiation at H1.
3. **Adjacent level test**: for each heading level, check that it differs
   from the next level on at least 2 of: size, weight, color, style (italic).
   Single-dimension differences get lost.
4. **Rhythm test**: in a document over 10 pages, do major sections (H1) start
   on new pages? If not, long documents will feel like an undifferentiated
   stream. Add `w:pageBreakBefore` to Heading1.

---

## Summary: Decision Checklist

When you are unsure about a typographic choice, run through these checks:

| Principle | Question | If No... |
|-----------|----------|----------|
| White Space | Does the page have at least 30% white space? | Increase margins or spacing |
| Contrast | Can I count heading levels by squinting? | Increase size ratios (target 1.25x) |
| Proximity | Does each heading clearly belong to text below it? | Make space-before > space-after (2:1) |
| Alignment | Is English left-aligned and CJK justified? | Switch alignment mode |
| Repetition | Do all same-level elements use the same style? | Replace direct formatting with styles |
| Hierarchy | Can I see the document structure at arm's length? | Add more differentiation signals |

**When two principles conflict, prioritize in this order:**

1. **Readability** (white space, line spacing) -- always wins
2. **Hierarchy** (contrast, scale) -- readers must find what they need
3. **Consistency** (repetition) -- builds trust
4. **Aesthetics** (alignment, grouping) -- the finishing touch


path: references/openxml_element_order.md
content: # OpenXML Child Element Ordering Rules

Element ordering in OpenXML is defined by the XSD schema. Incorrect ordering produces invalid documents that Word may refuse to open or silently repair (potentially losing data).

> **Key rule**: Properties elements (`*Pr`) must always be the **first child** of their parent.

---

## w:document

```
Children in order:
1. w:background       [0..1]  — page background color/fill
2. w:body              [0..1]  — document content container
```

---

## w:body

```
Children in order (repeating group):
1. w:p                 [0..*]  — paragraph
2. w:tbl               [0..*]  — table
3. w:sdt               [0..*]  — structured document tag (content control)
4. w:sectPr            [0..1]  — LAST child: final section properties
```

Note: `w:p`, `w:tbl`, and `w:sdt` are interleaved in document order. The only strict rule is that `w:sectPr` must be the **last child** of `w:body`.

---

## w:p (Paragraph)

```
Children in order:
1. w:pPr               [0..1]  — paragraph properties (MUST be first)

Then any mix of (interleaved in document order):
- w:r                  [0..*]  — run
- w:hyperlink          [0..*]  — hyperlink wrapper
- w:ins                [0..*]  — tracked insertion
- w:del                [0..*]  — tracked deletion
- w:bookmarkStart      [0..*]  — bookmark anchor start
- w:bookmarkEnd        [0..*]  — bookmark anchor end
- w:commentRangeStart  [0..*]  — comment range start
- w:commentRangeEnd    [0..*]  — comment range end
- w:proofErr           [0..*]  — proofing error marker
- w:fldSimple          [0..*]  — simple field
- w:sdt                [0..*]  — inline content control
- w:smartTag           [0..*]  — smart tag
```

**Practical note**: After `w:pPr`, the remaining children appear in document reading order. Runs, hyperlinks, bookmarks, and comment ranges intermix freely based on their position in the text.

---

## w:pPr (Paragraph Properties)

```
Children in order:
1.  w:pStyle            [0..1]  — paragraph style reference
2.  w:keepNext          [0..1]  — keep with next paragraph
3.  w:keepLines         [0..1]  — keep lines together
4.  w:pageBreakBefore   [0..1]  — page break before paragraph
5.  w:framePr           [0..1]  — text frame properties
6.  w:widowControl      [0..1]  — widow/orphan control
7.  w:numPr             [0..1]  — numbering properties
8.  w:suppressLineNumbers [0..1]
9.  w:pBdr              [0..1]  — paragraph borders
10. w:shd               [0..1]  — shading
11. w:tabs              [0..1]  — tab stops
12. w:suppressAutoHyphens [0..1]
13. w:kinsoku           [0..1]  — CJK kinsoku settings
14. w:wordWrap           [0..1]
15. w:overflowPunct     [0..1]
16. w:topLinePunct      [0..1]
17. w:autoSpaceDE       [0..1]
18. w:autoSpaceDN       [0..1]
19. w:bidi              [0..1]  — right-to-left paragraph
20. w:adjustRightInd    [0..1]
21. w:snapToGrid        [0..1]
22. w:spacing            [0..1]  — line and paragraph spacing
23. w:ind               [0..1]  — indentation
24. w:contextualSpacing [0..1]
25. w:mirrorIndents     [0..1]
26. w:suppressOverlap   [0..1]
27. w:jc                [0..1]  — justification (left/center/right/both)
28. w:textDirection     [0..1]
29. w:textAlignment     [0..1]
30. w:outlineLvl        [0..1]  — outline level
31. w:divId             [0..1]
32. w:rPr               [0..1]  — run properties for paragraph mark
33. w:sectPr            [0..1]  — section break (section ends at this paragraph)
34. w:pPrChange         [0..1]  — tracked paragraph property change
```

---

## w:r (Run)

```
Children in order:
1. w:rPr               [0..1]  — run properties (MUST be first)

Then any of (one per run, typically):
- w:t                  [0..*]  — text content
- w:br                 [0..*]  — break (line, page, column)
- w:tab                [0..*]  — tab character
- w:cr                 [0..*]  — carriage return
- w:sym               [0..*]  — symbol character
- w:drawing            [0..*]  — DrawingML object (images)
- w:pict               [0..*]  — VML picture (legacy)
- w:fldChar            [0..*]  — complex field character
- w:instrText          [0..*]  — field instruction text
- w:delText            [0..*]  — deleted text (inside w:del)
- w:footnoteReference  [0..*]
- w:endnoteReference   [0..*]
- w:commentReference   [0..*]
- w:lastRenderedPageBreak [0..*]
```

---

## w:rPr (Run Properties)

```
Children in order:
1.  w:rStyle            [0..1]  — character style reference
2.  w:rFonts            [0..1]  — font specification
3.  w:b                 [0..1]  — bold
4.  w:bCs               [0..1]  — complex script bold
5.  w:i                 [0..1]  — italic
6.  w:iCs               [0..1]  — complex script italic
7.  w:caps              [0..1]  — all capitals
8.  w:smallCaps         [0..1]  — small capitals
9.  w:strike            [0..1]  — strikethrough
10. w:dstrike           [0..1]  — double strikethrough
11. w:outline           [0..1]
12. w:shadow            [0..1]
13. w:emboss            [0..1]
14. w:imprint           [0..1]
15. w:noProof           [0..1]  — suppress proofing
16. w:snapToGrid        [0..1]
17. w:vanish            [0..1]  — hidden text
18. w:color             [0..1]  — text color
19. w:spacing            [0..1]  — character spacing
20. w:w                 [0..1]  — character width scaling
21. w:kern              [0..1]  — font kerning
22. w:position          [0..1]  — vertical position (raise/lower)
23. w:sz                [0..1]  — font size (half-points)
24. w:szCs              [0..1]  — complex script font size
25. w:highlight         [0..1]  — text highlight color
26. w:u                 [0..1]  — underline
27. w:effect            [0..1]  — text effect (animated)
28. w:bdr               [0..1]  — run border
29. w:shd               [0..1]  — run shading
30. w:vertAlign         [0..1]  — superscript/subscript
31. w:rtl               [0..1]  — right-to-left
32. w:cs                [0..1]  — complex script
33. w:lang              [0..1]  — language
34. w:rPrChange         [0..1]  — tracked run property change
```

---

## w:tbl (Table)

```
Children in order:
1. w:tblPr              [1..1]  — table properties (REQUIRED, must be first)
2. w:tblGrid            [1..1]  — column width definitions (REQUIRED)
3. w:tr                 [1..*]  — table row(s)
```

---

## w:tblPr (Table Properties)

```
Children in order:
1.  w:tblStyle           [0..1]  — table style reference
2.  w:tblpPr             [0..1]  — table positioning
3.  w:tblOverlap         [0..1]
4.  w:bidiVisual         [0..1]  — right-to-left table
5.  w:tblStyleRowBandSize [0..1]
6.  w:tblStyleColBandSize [0..1]
7.  w:tblW               [0..1]  — preferred table width
8.  w:jc                 [0..1]  — table alignment
9.  w:tblCellSpacing     [0..1]
10. w:tblInd             [0..1]  — table indent from margin
11. w:tblBorders         [0..1]  — table borders
12. w:shd                [0..1]  — table shading
13. w:tblLayout          [0..1]  — fixed or autofit
14. w:tblCellMar         [0..1]  — default cell margins
15. w:tblLook            [0..1]  — conditional formatting flags
16. w:tblCaption         [0..1]  — accessibility caption
17. w:tblDescription     [0..1]  — accessibility description
18. w:tblPrChange        [0..1]  — tracked table property change
```

---

## w:tr (Table Row)

```
Children in order:
1. w:trPr               [0..1]  — row properties (must be first)
2. w:tc                  [1..*]  — table cell(s)
```

---

## w:trPr (Table Row Properties)

```
Children in order:
1.  w:cnfStyle           [0..1]  — conditional formatting
2.  w:divId              [0..1]
3.  w:gridBefore         [0..1]  — grid columns before first cell
4.  w:gridAfter          [0..1]  — grid columns after last cell
5.  w:wBefore            [0..1]
6.  w:wAfter             [0..1]
7.  w:cantSplit          [0..1]  — don't split row across pages
8.  w:trHeight           [0..1]  — row height
9.  w:tblHeader          [0..1]  — repeat as header row
10. w:tblCellSpacing     [0..1]
11. w:jc                 [0..1]  — row alignment
12. w:hidden             [0..1]
13. w:ins                [0..1]  — tracked row insertion
14. w:del                [0..1]  — tracked row deletion
15. w:trPrChange         [0..1]  — tracked row property change
```

---

## w:tc (Table Cell)

```
Children in order:
1. w:tcPr               [0..1]  — cell properties (must be first)
2. w:p                   [1..*]  — paragraph(s) — at least one required
3. w:tbl                 [0..*]  — nested table(s)
```

---

## w:tcPr (Table Cell Properties)

```
Children in order:
1.  w:cnfStyle           [0..1]
2.  w:tcW                [0..1]  — cell width
3.  w:gridSpan           [0..1]  — horizontal merge (column span)
4.  w:hMerge             [0..1]  — legacy horizontal merge
5.  w:vMerge             [0..1]  — vertical merge
6.  w:tcBorders          [0..1]  — cell borders
7.  w:shd                [0..1]  — cell shading
8.  w:noWrap             [0..1]
9.  w:tcMar              [0..1]  — cell margins
10. w:textDirection      [0..1]
11. w:tcFitText          [0..1]
12. w:vAlign             [0..1]  — vertical alignment
13. w:hideMark           [0..1]
14. w:tcPrChange         [0..1]  — tracked cell property change
```

---

## w:sectPr (Section Properties)

```
Children in order:
1.  w:headerReference    [0..*]  — header references (type: default/first/even)
2.  w:footerReference    [0..*]  — footer references
3.  w:endnotePr          [0..1]
4.  w:footnotePr         [0..1]
5.  w:type               [0..1]  — section break type (nextPage/continuous/evenPage/oddPage)
6.  w:pgSz               [0..1]  — page size
7.  w:pgMar              [0..1]  — page margins
8.  w:paperSrc           [0..1]
9.  w:pgBorders          [0..1]  — page borders
10. w:lnNumType          [0..1]  — line numbering
11. w:pgNumType          [0..1]  — page numbering
12. w:cols               [0..1]  — column definitions
13. w:formProt           [0..1]
14. w:vAlign             [0..1]  — vertical alignment of page
15. w:noEndnote          [0..1]
16. w:titlePg            [0..1]  — different first page header/footer
17. w:textDirection      [0..1]
18. w:bidi               [0..1]
19. w:rtlGutter          [0..1]
20. w:docGrid            [0..1]  — document grid
21. w:sectPrChange       [0..1]  — tracked section property change
```

---

## w:hdr (Header) / w:ftr (Footer)

```
Children (same structure as w:body content):
1. w:p                   [0..*]  — paragraph(s)
2. w:tbl                 [0..*]  — table(s)
3. w:sdt                 [0..*]  — content controls
```

Headers and footers are essentially mini-documents. They follow the same content model as `w:body` but without a final `w:sectPr`.


path: references/openxml_encyclopedia_part2.md
content: # OpenXML SDK 3.x Complete Reference Encyclopedia — Part 2

**Target:** DocumentFormat.OpenXml 3.x / .NET 8+ / C# 12
**Last Updated:** 2026-03-22

This document covers page setup, tables, headers/footers, section breaks, document properties, and printing/compatibility settings. Every code block is ready to copy-paste.

---

## Namespace Aliases Used Throughout

```csharp
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using A = DocumentFormat.OpenXml.Drawing;
using DW = DocumentFormat.OpenXml.Drawing.Wordprocessing;
using PIC = DocumentFormat.OpenXml.Drawing.Pictures;
```

---

## Table of Contents

1. [Page Setup](#1-page-setup)
2. [Tables — Comprehensive](#2-tables--comprehensive)
3. [Headers, Footers & Page Numbers](#3-headers-footers--page-numbers)
4. [Section Breaks & Multi-Section](#4-section-breaks--multi-section)
5. [Document Properties](#5-document-properties)
6. [Printing & Compatibility Settings](#6-printing--compatibility-settings)

---

## 1. Page Setup

Page setup is controlled via `SectionProperties`, which is placed as the **last child element** of `Body` for the final (or only) section, or inside `ParagraphProperties` for mid-document section breaks.

### 1.1 PageSize — Standard Paper Sizes

```csharp
// =============================================================================
// PAGE SIZE — STANDARD PAPER SIZES
// =============================================================================
// PageSize Width and Height are specified in DXA (twentieths of a point).
// 1 inch = 1440 DXA.  1 cm ≈ 567 DXA.  1 mm ≈ 56.7 DXA.
//
// Common paper sizes (portrait orientation):
//   Letter:  12240 × 15840  (8.5" × 11")
//   A4:      11906 × 16838  (210mm × 297mm)
//   Legal:   12240 × 20160  (8.5" × 14")
//   A3:      16838 × 23811  (297mm × 420mm)
//   B5:      10318 × 14570  (182mm × 257mm)
//   16K:      10318 × 14570 (approximate, varies by region)

var sectionProps = new SectionProperties();

// --- Letter (US default) ---
sectionProps.AppendChild(new PageSize
{
    Width = 12240U,   // 8.5 inches
    Height = 15840U   // 11 inches
});
// Produces XML: <w:pgSz w:w="12240" w:h="15840" />

// --- A4 (ISO default) ---
var a4Size = new PageSize
{
    Width = 11906U,   // 210mm
    Height = 16838U   // 297mm
};

// --- Legal ---
var legalSize = new PageSize
{
    Width = 12240U,   // 8.5 inches
    Height = 20160U   // 14 inches
};

// --- A3 ---
var a3Size = new PageSize
{
    Width = 16838U,   // 297mm
    Height = 23811U   // 420mm
};

body.AppendChild(sectionProps);
```

### 1.2 PageOrientation — CRITICAL Landscape Handling

```csharp
// =============================================================================
// PAGE ORIENTATION — LANDSCAPE
// =============================================================================
// CRITICAL GOTCHA: Setting Orient = Landscape is NOT enough!
// You MUST ALSO swap Width and Height values. Word uses the numeric dimensions
// to determine actual page size; Orient only controls the print driver rotation.
//
// If you set Orient = Landscape but don't swap dimensions, Word will
// display portrait but print rotated — a confusing bug.

// --- Portrait (default, explicit) ---
var portraitSize = new PageSize
{
    Width = 12240U,
    Height = 15840U
    // Orient is omitted for portrait (it's the default)
};
// Produces XML: <w:pgSz w:w="12240" w:h="15840" />

// --- Landscape — CORRECT way ---
var landscapeSize = new PageSize
{
    Width = 15840U,                                      // SWAPPED: was Height
    Height = 12240U,                                     // SWAPPED: was Width
    Orient = PageOrientationValues.Landscape              // AND set Orient
};
// Produces XML: <w:pgSz w:w="15840" w:h="12240" w:orient="landscape" />

// --- Helper method for safe orientation switching ---
static PageSize CreatePageSize(uint shortEdge, uint longEdge, bool landscape)
{
    return landscape
        ? new PageSize
        {
            Width = longEdge,       // Long edge becomes width
            Height = shortEdge,     // Short edge becomes height
            Orient = PageOrientationValues.Landscape
        }
        : new PageSize
        {
            Width = shortEdge,
            Height = longEdge
        };
}

// Usage:
var letterLandscape = CreatePageSize(12240, 15840, landscape: true);
var a4Portrait = CreatePageSize(11906, 16838, landscape: false);
```

### 1.3 PageMargin — Common Presets

```csharp
// =============================================================================
// PAGE MARGIN — ALL PROPERTIES
// =============================================================================
// All margin values are in DXA (twentieths of a point). 1 inch = 1440 DXA.
//
// Properties:
//   Top, Bottom    — signed Int32 (can be negative for overlap)
//   Left, Right    — unsigned UInt32
//   Header, Footer — unsigned UInt32 (distance from page edge to header/footer)
//   Gutter         — unsigned UInt32 (extra margin for binding; added to Left
//                    unless GutterAtTop is set in Settings)

// --- Normal / Standard (1" all around) ---
var normalMargins = new PageMargin
{
    Top = 1440,         // 1 inch
    Bottom = 1440,      // 1 inch
    Left = 1440U,       // 1 inch
    Right = 1440U,      // 1 inch
    Header = 720U,      // 0.5 inch (distance from page edge)
    Footer = 720U,      // 0.5 inch
    Gutter = 0U         // No binding gutter
};
// Produces XML:
// <w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440"
//          w:header="720" w:footer="720" w:gutter="0" />

// --- Narrow (0.5" all around) ---
var narrowMargins = new PageMargin
{
    Top = 720,
    Bottom = 720,
    Left = 720U,
    Right = 720U,
    Header = 720U,
    Footer = 720U,
    Gutter = 0U
};

// --- Moderate (1" top/bottom, 0.75" left/right) ---
var moderateMargins = new PageMargin
{
    Top = 1440,
    Bottom = 1440,
    Left = 1080U,     // 0.75 inch
    Right = 1080U,    // 0.75 inch
    Header = 720U,
    Footer = 720U,
    Gutter = 0U
};

// --- Wide (1" top/bottom, 2" left/right) ---
var wideMargins = new PageMargin
{
    Top = 1440,
    Bottom = 1440,
    Left = 2880U,     // 2 inches
    Right = 2880U,    // 2 inches
    Header = 720U,
    Footer = 720U,
    Gutter = 0U
};

// --- Chinese Government Document 公文 standard (GB/T 9704-2012) ---
// Top: 37mm (2098 DXA), Bottom: 35mm (1984 DXA)
// Left: 28mm (1588 DXA), Right: 26mm (1474 DXA)
var chineseGovMargins = new PageMargin
{
    Top = 2098,        // 37mm
    Bottom = 1984,     // 35mm
    Left = 1588U,      // 28mm
    Right = 1474U,     // 26mm
    Header = 851U,     // 15mm
    Footer = 567U,     // 10mm (approx)
    Gutter = 0U
};

// --- With binding gutter (e.g., for book printing) ---
var gutterMargins = new PageMargin
{
    Top = 1440,
    Bottom = 1440,
    Left = 1440U,
    Right = 1440U,
    Header = 720U,
    Footer = 720U,
    Gutter = 720U      // 0.5 inch added to left margin for binding
};
```

### 1.4 PageBorders

```csharp
// =============================================================================
// PAGE BORDERS
// =============================================================================
// PageBorders defines borders around the entire page.
// OffsetFrom controls whether border distance is from page edge or text margin.
//   PageBorderOffsetValues.Page = from page edge
//   PageBorderOffsetValues.Text = from text margin
//
// Each border: Val (style), Size (eighth-points: 4=0.5pt, 8=1pt, 12=1.5pt),
//              Color (hex RGB), Space (distance in points from text/page edge)

var pageBorders = new PageBorders
{
    OffsetFrom = PageBorderOffsetValues.Page
};

// Top border: single line, 1pt, black
pageBorders.AppendChild(new TopBorder
{
    Val = BorderValues.Single,
    Size = 8U,               // 8 eighth-points = 1pt
    Color = "000000",
    Space = 24U              // 24 points from page edge
});

// Bottom border
pageBorders.AppendChild(new BottomBorder
{
    Val = BorderValues.Single,
    Size = 8U,
    Color = "000000",
    Space = 24U
});

// Left border
pageBorders.AppendChild(new LeftBorder
{
    Val = BorderValues.Single,
    Size = 8U,
    Color = "000000",
    Space = 24U
});

// Right border
pageBorders.AppendChild(new RightBorder
{
    Val = BorderValues.Single,
    Size = 8U,
    Color = "000000",
    Space = 24U
});

// --- Double border example ---
var doubleBorder = new TopBorder
{
    Val = BorderValues.Double,   // Double line
    Size = 4U,                   // 0.5pt per line
    Color = "0000FF",            // Blue
    Space = 24U
};

// --- Common BorderValues ---
// Single, Double, Triple, DotDash, Dashed, Dotted, Thick, ThinThickSmallGap,
// ThickThinSmallGap, Wave, DoubleWave, BasicBlackDots, None

sectionProps.AppendChild(pageBorders);
```

### 1.5 Columns — Multi-Column Layout

```csharp
// =============================================================================
// COLUMNS — MULTI-COLUMN LAYOUTS
// =============================================================================
// Columns element defines the column layout within a section.
// Space is measured in DXA. EqualWidth=true makes all columns equal.

// --- 2 equal columns ---
var twoCols = new Columns
{
    EqualWidth = true,
    ColumnCount = 2,
    Space = "720"          // 0.5 inch gap between columns
};
// Produces XML: <w:cols w:num="2" w:space="720" w:equalWidth="1" />

// --- 3 equal columns with separator ---
var threeColsSep = new Columns
{
    EqualWidth = true,
    ColumnCount = 3,
    Space = "360",         // 0.25 inch gap
    Separator = true       // Vertical line between columns
};
// Produces XML: <w:cols w:num="3" w:space="360" w:equalWidth="1" w:sep="1" />

// --- Custom unequal columns (e.g., 2/3 + 1/3 of content width) ---
// When using unequal widths, EqualWidth must be false and you define
// each column explicitly with Column elements.
// For Letter page with 1" margins: content width = 12240 - 1440 - 1440 = 9360 DXA
// Column 1: 6000 DXA wide, 360 DXA space after
// Column 2: 3000 DXA wide (6000 + 360 + 3000 = 9360)

var unequalCols = new Columns { EqualWidth = false };
unequalCols.AppendChild(new Column
{
    Width = "6000",
    Space = "360"
});
unequalCols.AppendChild(new Column
{
    Width = "3000"
    // No Space on last column
});
// Produces XML:
// <w:cols w:equalWidth="0">
//   <w:col w:w="6000" w:space="360" />
//   <w:col w:w="3000" />
// </w:cols>

sectionProps.AppendChild(unequalCols);
```

### 1.6 LineNumbering

```csharp
// =============================================================================
// LINE NUMBERING
// =============================================================================
// LineNumbering adds line numbers in the margin. Useful for legal/academic docs.
// CountBy = show every Nth number (1 = every line, 5 = every 5th)
// Start = starting number
// Distance = distance from text in DXA
// Restart: NewPage, NewSection, Continuous

var lineNums = new LineNumbering
{
    CountBy = 5,                                         // Show every 5th line number
    Start = 1,                                           // Start at line 1
    Distance = 360U,                                     // 0.25 inch from text
    Restart = LineNumberRestartValues.NewPage             // Restart each page
};
// Produces XML:
// <w:lnNumType w:countBy="5" w:start="1" w:distance="360" w:restart="newPage" />

sectionProps.AppendChild(lineNums);
```

### 1.7 DocGrid — CJK Document Grid

```csharp
// =============================================================================
// DOCUMENT GRID — CJK LAYOUT
// =============================================================================
// DocGrid specifies a document grid (character grid) primarily for CJK documents.
// Type: Default (no grid), Lines (line grid), LinesAndChars (line+char grid),
//       SnapToChars (snap to character grid)
// LinePitch = distance between lines in DXA (e.g., 312 for standard Chinese docs)
// CharacterSpace = extra spacing between characters in DXA

// --- Chinese document grid: 28 lines × 28 chars per line (common for 公文) ---
var cjkGrid = new DocGrid
{
    Type = DocGridValues.LinesAndChars,
    LinePitch = 579,          // DXA between lines (≈ 28 lines on A4 with std margins)
    CharacterSpace = 0        // Default character spacing
};
// Produces XML:
// <w:docGrid w:type="linesAndChars" w:linePitch="579" w:charSpace="0" />

// --- Simple line-only grid ---
var lineGrid = new DocGrid
{
    Type = DocGridValues.Lines,
    LinePitch = 360            // Standard line pitch
};

sectionProps.AppendChild(cjkGrid);
```

### 1.8 VerticalTextAlignmentOnPage

```csharp
// =============================================================================
// VERTICAL TEXT ALIGNMENT ON PAGE
// =============================================================================
// Controls vertical alignment of text within the page (above bottom margin).
// Values: Top (default), Center, Both (justified), Bottom

var vertAlign = new VerticalTextAlignmentOnPage
{
    Val = VerticalJustificationValues.Center
};
// Produces XML: <w:vAlign w:val="center" />
// Use case: Title pages, certificate pages

sectionProps.AppendChild(vertAlign);
```

### 1.9 Complete Page Setup Example

```csharp
// =============================================================================
// COMPLETE PAGE SETUP — PUTTING IT ALL TOGETHER
// =============================================================================
// A4 portrait, moderate margins, 2-column layout with separator

using var doc = WordprocessingDocument.Create(
    "PageSetupDemo.docx", WordprocessingDocumentType.Document);

var mainPart = doc.MainDocumentPart!;
var body = mainPart.Document.Body!;

// Add content paragraphs ...
body.AppendChild(new Paragraph(
    new Run(new Text("This is a two-column document on A4 paper."))));

// Section properties — MUST be last child of Body
var sectPr = new SectionProperties();

// Page size: A4 portrait
sectPr.AppendChild(new PageSize
{
    Width = 11906U,
    Height = 16838U
});

// Margins: moderate
sectPr.AppendChild(new PageMargin
{
    Top = 1440, Bottom = 1440,
    Left = 1080U, Right = 1080U,
    Header = 720U, Footer = 720U, Gutter = 0U
});

// 2-column with separator
sectPr.AppendChild(new Columns
{
    EqualWidth = true,
    ColumnCount = 2,
    Space = "720",
    Separator = true
});

// Line grid for CJK
sectPr.AppendChild(new DocGrid
{
    Type = DocGridValues.Lines,
    LinePitch = 312
});

body.AppendChild(sectPr);
mainPart.Document.Save();
```

---

## 2. Tables — Comprehensive

### 2.1 TableProperties — Width, Layout, Alignment, Indent

```csharp
// =============================================================================
// TABLE PROPERTIES — WIDTH, LAYOUT, ALIGNMENT
// =============================================================================
// Table width can be specified in three ways:
//   Pct:  percentage of page width. 5000 = 100%. (multiply % by 50)
//   Dxa:  absolute width in DXA (twentieths of a point). 1 inch = 1440 DXA.
//   Auto: table auto-sizes to content.
//
// TableLayout:
//   Fixed: columns maintain exact widths. Required for complex cell sizing.
//   Autofit: columns adjust to content (default).
//
// TableJustification: Left (default), Center, Right

var table = new Table();

var tblProps = new TableProperties();

// --- Width: 100% of page ---
tblProps.AppendChild(new TableWidth
{
    Width = "5000",                           // 5000 = 100%
    Type = TableWidthUnitValues.Pct
});
// Produces XML: <w:tblW w:w="5000" w:type="pct" />

// --- Width: fixed DXA ---
// var tblWidth = new TableWidth { Width = "9360", Type = TableWidthUnitValues.Dxa };

// --- Width: auto ---
// var tblWidth = new TableWidth { Width = "0", Type = TableWidthUnitValues.Auto };

// Layout: fixed column widths
tblProps.AppendChild(new TableLayout
{
    Type = TableLayoutValues.Fixed
});

// Center the table on the page
tblProps.AppendChild(new TableJustification
{
    Val = TableRowAlignmentValues.Center
});

// Table indent (left offset when not centered) — in DXA
// tblProps.AppendChild(new TableIndentation
// {
//     Width = 720,                           // 0.5 inch indent
//     Type = TableWidthUnitValues.Dxa
// });

table.AppendChild(tblProps);
```

### 2.2 TableBorders — All Border Properties

```csharp
// =============================================================================
// TABLE BORDERS
// =============================================================================
// TableBorders defines default borders for the entire table.
// Each border has:
//   Val   — BorderValues enum (Single, Double, Dotted, Dashed, None, etc.)
//   Size  — in eighth-points: 4 = 0.5pt, 8 = 1pt, 12 = 1.5pt, 16 = 2pt, 24 = 3pt
//   Color — hex RGB string (e.g., "000000" for black, "FF0000" for red)
//   Space — space between border and content in points
//
// Border types: TopBorder, BottomBorder, LeftBorder, RightBorder,
//               InsideHorizontalBorder, InsideVerticalBorder

var tblBorders = new TableBorders();

// Top border: single, 1pt, black
tblBorders.AppendChild(new TopBorder
{
    Val = BorderValues.Single,
    Size = 8U,           // 1pt (8 eighth-points)
    Color = "000000",
    Space = 0U
});

// Bottom border
tblBorders.AppendChild(new BottomBorder
{
    Val = BorderValues.Single,
    Size = 8U,
    Color = "000000",
    Space = 0U
});

// Left border
tblBorders.AppendChild(new LeftBorder
{
    Val = BorderValues.Single,
    Size = 8U,
    Color = "000000",
    Space = 0U
});

// Right border
tblBorders.AppendChild(new RightBorder
{
    Val = BorderValues.Single,
    Size = 8U,
    Color = "000000",
    Space = 0U
});

// Inside horizontal borders (between rows)
tblBorders.AppendChild(new InsideHorizontalBorder
{
    Val = BorderValues.Single,
    Size = 4U,           // 0.5pt — thinner than outer borders
    Color = "000000",
    Space = 0U
});

// Inside vertical borders (between columns)
tblBorders.AppendChild(new InsideVerticalBorder
{
    Val = BorderValues.Single,
    Size = 4U,
    Color = "000000",
    Space = 0U
});

// Produces XML:
// <w:tblBorders>
//   <w:top w:val="single" w:sz="8" w:color="000000" w:space="0" />
//   <w:bottom w:val="single" w:sz="8" w:color="000000" w:space="0" />
//   <w:left w:val="single" w:sz="8" w:color="000000" w:space="0" />
//   <w:right w:val="single" w:sz="8" w:color="000000" w:space="0" />
//   <w:insideH w:val="single" w:sz="4" w:color="000000" w:space="0" />
//   <w:insideV w:val="single" w:sz="4" w:color="000000" w:space="0" />
// </w:tblBorders>

tblProps.AppendChild(tblBorders);
```

### 2.3 TableGrid — Column Definitions

```csharp
// =============================================================================
// TABLE GRID — COLUMN WIDTH DEFINITIONS
// =============================================================================
// TableGrid defines the column structure of the table. Each GridColumn
// specifies the width in DXA. The number of GridColumn elements determines
// the number of columns.
//
// IMPORTANT: GridColumn widths should sum to the table width.
// For a 100% table on Letter with 1" margins: 12240 - 1440 - 1440 = 9360 DXA

var tableGrid = new TableGrid();

// 3 columns: 3000 + 3000 + 3360 = 9360 DXA
tableGrid.AppendChild(new GridColumn { Width = "3000" });
tableGrid.AppendChild(new GridColumn { Width = "3000" });
tableGrid.AppendChild(new GridColumn { Width = "3360" });

// Produces XML:
// <w:tblGrid>
//   <w:gridCol w:w="3000" />
//   <w:gridCol w:w="3000" />
//   <w:gridCol w:w="3360" />
// </w:tblGrid>

table.AppendChild(tableGrid);
```

### 2.4 TableCellProperties — Width, Alignment, Direction, Shading

```csharp
// =============================================================================
// TABLE CELL PROPERTIES
// =============================================================================
// TableCellProperties controls individual cell appearance.

var cellProps = new TableCellProperties();

// Cell width — should match the GridColumn width
cellProps.AppendChild(new TableCellWidth
{
    Width = "3000",
    Type = TableWidthUnitValues.Dxa
});

// Vertical alignment within cell: Top (default), Center, Bottom
cellProps.AppendChild(new TableCellVerticalAlignment
{
    Val = TableVerticalAlignmentValues.Center
});

// Text direction (for vertical text in CJK, etc.)
// Values: LefToRight (default), TopToBottom (text rotated 90° CW),
//         TopToBottomV (vertical CJK), BottomToTopV
cellProps.AppendChild(new TextDirection
{
    Val = TextDirectionValues.TopToBottom
});

// NoWrap — prevents text from wrapping within the cell
cellProps.AppendChild(new NoWrap());

// Cell shading (background color)
cellProps.AppendChild(new Shading
{
    Val = ShadingPatternValues.Clear,
    Color = "auto",
    Fill = "D9E2F3"          // Light blue background
});
// Produces XML: <w:shd w:val="clear" w:color="auto" w:fill="D9E2F3" />
```

### 2.5 TableCellMargin — Table-Level Default vs Per-Cell Override

```csharp
// =============================================================================
// TABLE CELL MARGINS
// =============================================================================
// There are TWO levels of cell margin control:
//   1. Table-level default: TableCellMarginDefault (inside TableProperties)
//   2. Per-cell override:   TableCellMargin (inside TableCellProperties)
//
// All values are in DXA. Default Word cell margins are approximately:
//   Top: 0, Bottom: 0, Left: 108 (0.075"), Right: 108

// --- Table-level default margins ---
var defaultMargins = new TableCellMarginDefault();
defaultMargins.AppendChild(new TopMargin
{
    Width = "72",                             // ~0.05 inch
    Type = TableWidthUnitValues.Dxa
});
defaultMargins.AppendChild(new BottomMargin
{
    Width = "72",
    Type = TableWidthUnitValues.Dxa
});
defaultMargins.AppendChild(new StartMargin
{
    Width = "108",                            // ~0.075 inch (default)
    Type = TableWidthUnitValues.Dxa
});
defaultMargins.AppendChild(new EndMargin
{
    Width = "108",
    Type = TableWidthUnitValues.Dxa
});

tblProps.AppendChild(defaultMargins);
// Produces XML:
// <w:tblCellMar>
//   <w:top w:w="72" w:type="dxa" />
//   <w:bottom w:w="72" w:type="dxa" />
//   <w:start w:w="108" w:type="dxa" />
//   <w:end w:w="108" w:type="dxa" />
// </w:tblCellMar>

// --- Per-cell override (larger padding for a specific cell) ---
var cellMarginOverride = new TableCellMargin();
cellMarginOverride.AppendChild(new TopMargin
{
    Width = "144",                            // 0.1 inch
    Type = TableWidthUnitValues.Dxa
});
cellMarginOverride.AppendChild(new BottomMargin
{
    Width = "144",
    Type = TableWidthUnitValues.Dxa
});
cellMarginOverride.AppendChild(new StartMargin
{
    Width = "216",                            // 0.15 inch
    Type = TableWidthUnitValues.Dxa
});
cellMarginOverride.AppendChild(new EndMargin
{
    Width = "216",
    Type = TableWidthUnitValues.Dxa
});

cellProps.AppendChild(cellMarginOverride);
```

### 2.6 Row Height

```csharp
// =============================================================================
// TABLE ROW HEIGHT
// =============================================================================
// TableRowHeight is set inside TableRowProperties.
// Val = height in DXA
// HeightRuleType:
//   Exact:   row is exactly this height (content may be clipped)
//   AtLeast: row is at least this height, grows for content (default behavior)
//   Auto:    height determined by content

var rowProps = new TableRowProperties();

// Row height: at least 0.5 inch
rowProps.AppendChild(new TableRowHeight
{
    Val = 720U,                                // 0.5 inch in DXA
    HeightRule = HeightRuleValues.AtLeast
});
// Produces XML: <w:trHeight w:val="720" w:hRule="atLeast" />

// Exact height (content may clip):
// rowProps.AppendChild(new TableRowHeight
// {
//     Val = 720U,
//     HeightRule = HeightRuleValues.Exact
// });

var row = new TableRow();
row.AppendChild(rowProps);
```

### 2.7 Header Row Repeat (Repeat on Every Page)

```csharp
// =============================================================================
// HEADER ROW REPEAT
// =============================================================================
// TableHeader on TableRowProperties marks a row to repeat at the top
// of each page when the table spans multiple pages.
// IMPORTANT: Only works for rows at the TOP of the table (contiguous from first row).
// You cannot repeat a row in the middle of a table.

var headerRowProps = new TableRowProperties();
headerRowProps.AppendChild(new TableHeader());  // No value needed — presence = true

// Produces XML:
// <w:trPr>
//   <w:tblHeader />
// </w:trPr>

var headerRow = new TableRow();
headerRow.AppendChild(headerRowProps);
// ... add cells to headerRow ...
```

### 2.8 Per-Cell Border Override

```csharp
// =============================================================================
// PER-CELL BORDER OVERRIDE
// =============================================================================
// TableCellBorders inside TableCellProperties overrides table-level borders
// for a specific cell. Useful for special formatting, merging visual areas, etc.

var cellBorders = new TableCellBorders();

// Remove bottom border on this cell
cellBorders.AppendChild(new BottomBorder
{
    Val = BorderValues.None,
    Size = 0U,
    Color = "auto",
    Space = 0U
});

// Add thick right border
cellBorders.AppendChild(new RightBorder
{
    Val = BorderValues.Single,
    Size = 24U,          // 3pt thick
    Color = "FF0000",    // Red
    Space = 0U
});

// Produces XML:
// <w:tcBorders>
//   <w:bottom w:val="none" w:sz="0" w:color="auto" w:space="0" />
//   <w:right w:val="single" w:sz="24" w:color="FF0000" w:space="0" />
// </w:tcBorders>

cellProps.AppendChild(cellBorders);
```

### 2.9 Horizontal Merge (GridSpan)

```csharp
// =============================================================================
// HORIZONTAL MERGE — GRIDSPAN
// =============================================================================
// To merge cells horizontally, use GridSpan on the first cell's properties.
// The cell spans across multiple grid columns. You do NOT add extra cells
// for the spanned columns — only one cell covers the span.
//
// Example: 3-column table, first row merges columns 1+2

var mergedRow = new TableRow();

// Cell spanning columns 1 and 2
var spanCell = new TableCell();
var spanCellProps = new TableCellProperties();
spanCellProps.AppendChild(new GridSpan { Val = 2 });      // Span 2 columns
spanCellProps.AppendChild(new TableCellWidth
{
    Width = "6000",                                        // Combined width: 3000 + 3000
    Type = TableWidthUnitValues.Dxa
});
spanCell.AppendChild(spanCellProps);
spanCell.AppendChild(new Paragraph(new Run(new Text("Spans columns 1-2"))));
mergedRow.AppendChild(spanCell);

// Cell in column 3 (normal)
var normalCell = new TableCell();
normalCell.AppendChild(new TableCellProperties(
    new TableCellWidth { Width = "3360", Type = TableWidthUnitValues.Dxa }));
normalCell.AppendChild(new Paragraph(new Run(new Text("Column 3"))));
mergedRow.AppendChild(normalCell);

// Produces XML for the merged cell:
// <w:tc>
//   <w:tcPr>
//     <w:gridSpan w:val="2" />
//     <w:tcW w:w="6000" w:type="dxa" />
//   </w:tcPr>
//   <w:p><w:r><w:t>Spans columns 1-2</w:t></w:r></w:p>
// </w:tc>
```

### 2.10 Vertical Merge

```csharp
// =============================================================================
// VERTICAL MERGE
// =============================================================================
// To merge cells vertically across rows, use VerticalMerge:
//   First row: VerticalMerge with Val = Restart  (starts the merge)
//   Subsequent rows: VerticalMerge with Val = Continue (or omit Val — Continue is default)
//
// Each row still needs the cell placeholder, but continue cells should contain
// an empty paragraph only.

// Row 1: start of vertical merge
var vRow1 = new TableRow();
var vCell1 = new TableCell();
var vCellProps1 = new TableCellProperties();
vCellProps1.AppendChild(new VerticalMerge { Val = MergedCellValues.Restart });
vCellProps1.AppendChild(new TableCellWidth { Width = "3000", Type = TableWidthUnitValues.Dxa });
vCell1.AppendChild(vCellProps1);
vCell1.AppendChild(new Paragraph(new Run(new Text("Merged vertically"))));
vRow1.AppendChild(vCell1);
// ... add remaining cells in row 1

// Row 2: continue the vertical merge
var vRow2 = new TableRow();
var vCell2 = new TableCell();
var vCellProps2 = new TableCellProperties();
vCellProps2.AppendChild(new VerticalMerge());  // Val omitted = Continue
vCellProps2.AppendChild(new TableCellWidth { Width = "3000", Type = TableWidthUnitValues.Dxa });
vCell2.AppendChild(vCellProps2);
vCell2.AppendChild(new Paragraph());           // Empty paragraph required — cell must have content
vRow2.AppendChild(vCell2);
// ... add remaining cells in row 2

// Row 3: if no VerticalMerge, the merge stops and this cell is independent.

// Produces XML:
// Row 1 cell: <w:tcPr><w:vMerge w:val="restart" /></w:tcPr>
// Row 2 cell: <w:tcPr><w:vMerge /></w:tcPr>  (continue is the default)
```

### 2.11 Nested Tables

```csharp
// =============================================================================
// NESTED TABLES
// =============================================================================
// A table can be nested inside a table cell. Simply add a Table element
// as a child of a TableCell (alongside the required Paragraph).
// IMPORTANT: Every TableCell MUST contain at least one Paragraph, even if
// it also contains a nested table. The Paragraph should come AFTER the table.

var outerTable = new Table();
// ... outer table properties and grid ...

var containerCell = new TableCell();
containerCell.AppendChild(new TableCellProperties(
    new TableCellWidth { Width = "6000", Type = TableWidthUnitValues.Dxa }));

// Build inner (nested) table
var innerTable = new Table();
var innerProps = new TableProperties();
innerProps.AppendChild(new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct });
innerProps.AppendChild(new TableBorders(
    new TopBorder { Val = BorderValues.Single, Size = 4U, Color = "999999" },
    new BottomBorder { Val = BorderValues.Single, Size = 4U, Color = "999999" },
    new LeftBorder { Val = BorderValues.Single, Size = 4U, Color = "999999" },
    new RightBorder { Val = BorderValues.Single, Size = 4U, Color = "999999" },
    new InsideHorizontalBorder { Val = BorderValues.Single, Size = 4U, Color = "999999" },
    new InsideVerticalBorder { Val = BorderValues.Single, Size = 4U, Color = "999999" }
));
innerTable.AppendChild(innerProps);

var innerGrid = new TableGrid(
    new GridColumn { Width = "2500" },
    new GridColumn { Width = "2500" });
innerTable.AppendChild(innerGrid);

var innerRow = new TableRow(
    new TableCell(
        new TableCellProperties(new TableCellWidth { Width = "2500", Type = TableWidthUnitValues.Dxa }),
        new Paragraph(new Run(new Text("Inner A")))),
    new TableCell(
        new TableCellProperties(new TableCellWidth { Width = "2500", Type = TableWidthUnitValues.Dxa }),
        new Paragraph(new Run(new Text("Inner B"))))
);
innerTable.AppendChild(innerRow);

// Add inner table to container cell
containerCell.AppendChild(innerTable);
// MUST have a paragraph after nested table
containerCell.AppendChild(new Paragraph());
```

### 2.12 Table Positioning (Floating Table)

```csharp
// =============================================================================
// TABLE POSITIONING — FLOATING TABLE
// =============================================================================
// TablePositionProperties makes a table "float" at a specific position
// on the page, allowing text to wrap around it.
// All position values are in DXA.

var floatProps = new TablePositionProperties
{
    VerticalAnchor = VerticalAnchorValues.Page,
    HorizontalAnchor = HorizontalAnchorValues.Page,
    TablePositionX = 2880,           // 2 inches from left page edge
    TablePositionY = 4320,           // 3 inches from top page edge
    LeftFromText = 180,              // 0.125 inch gap from text on left
    RightFromText = 180,
    TopFromText = 0,
    BottomFromText = 0
};

tblProps.AppendChild(floatProps);
// Produces XML:
// <w:tblpPr w:vertAnchor="page" w:horzAnchor="page"
//           w:tblpX="2880" w:tblpY="4320"
//           w:leftFromText="180" w:rightFromText="180"
//           w:topFromText="0" w:bottomFromText="0" />
```

### 2.13 TableLook — Conditional Formatting Flags

```csharp
// =============================================================================
// TABLE LOOK — CONDITIONAL FORMATTING FLAGS
// =============================================================================
// TableLook controls which conditional formatting bands are applied from
// the table style. These flags tell Word which "special" formatting to use.
//
// Val is a hex bitmask. Common values:
//   0x04A0 = FirstRow + LastRow + NoHBand (typical for styled tables)
//   0x0000 = no conditional formatting
//
// Individual boolean flags can also be set:

var tableLook = new TableLook
{
    Val = "04A0",
    FirstRow = true,        // Apply first-row (header) formatting
    LastRow = true,         // Apply last-row (totals) formatting
    FirstColumn = false,
    LastColumn = false,
    NoHorizontalBand = true,  // Don't apply horizontal banding
    NoVerticalBand = true     // Don't apply vertical banding
};

tblProps.AppendChild(tableLook);
// Produces XML:
// <w:tblLook w:val="04A0" w:firstRow="1" w:lastRow="1"
//            w:firstColumn="0" w:lastColumn="0"
//            w:noHBand="1" w:noVBand="1" />
```

### 2.14 Complete Styled Table — Header + Data + Totals + Zebra Striping

```csharp
// =============================================================================
// COMPLETE STYLED TABLE
// =============================================================================
// Builds a professional table with:
//   - Header row (dark background, white text, repeats on page break)
//   - Data rows with alternating zebra-stripe shading
//   - Totals row (bold, top border)
//   - Full 100% width on Letter page

static Table CreateStyledTable(string[][] data, bool hasHeaderRow = true, bool hasTotalsRow = true)
{
    int cols = data[0].Length;
    // For Letter page with 1" margins: 12240 - 2 * 1440 = 9360
    int totalWidth = 9360;
    int colWidth = totalWidth / cols;

    var table = new Table();

    // --- Table Properties ---
    var tblPr = new TableProperties(
        new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
        new TableLayout { Type = TableLayoutValues.Fixed },
        new TableBorders(
            new TopBorder { Val = BorderValues.Single, Size = 8U, Color = "000000" },
            new BottomBorder { Val = BorderValues.Single, Size = 8U, Color = "000000" },
            new LeftBorder { Val = BorderValues.Single, Size = 4U, Color = "BFBFBF" },
            new RightBorder { Val = BorderValues.Single, Size = 4U, Color = "BFBFBF" },
            new InsideHorizontalBorder { Val = BorderValues.Single, Size = 4U, Color = "BFBFBF" },
            new InsideVerticalBorder { Val = BorderValues.Single, Size = 4U, Color = "BFBFBF" }
        ),
        new TableLook
        {
            Val = "04A0", FirstRow = true, LastRow = true,
            FirstColumn = false, LastColumn = false,
            NoHorizontalBand = true, NoVerticalBand = true
        }
    );
    table.AppendChild(tblPr);

    // --- Table Grid ---
    var grid = new TableGrid();
    for (int c = 0; c < cols; c++)
    {
        int w = (c == cols - 1) ? totalWidth - colWidth * (cols - 1) : colWidth;
        grid.AppendChild(new GridColumn { Width = w.ToString() });
    }
    table.AppendChild(grid);

    // --- Rows ---
    for (int r = 0; r < data.Length; r++)
    {
        bool isHeader = hasHeaderRow && r == 0;
        bool isTotals = hasTotalsRow && r == data.Length - 1;
        bool isOddDataRow = !isHeader && !isTotals && (r % 2 == 1);

        var row = new TableRow();

        // Row properties
        var trPr = new TableRowProperties();
        trPr.AppendChild(new TableRowHeight
        {
            Val = isHeader ? 480U : 360U,
            HeightRule = HeightRuleValues.AtLeast
        });
        if (isHeader)
        {
            trPr.AppendChild(new TableHeader());   // Repeat header on each page
        }
        row.AppendChild(trPr);

        // Cells
        for (int c = 0; c < cols; c++)
        {
            int w = (c == cols - 1) ? totalWidth - colWidth * (cols - 1) : colWidth;
            var cell = new TableCell();
            var tcPr = new TableCellProperties();
            tcPr.AppendChild(new TableCellWidth
            {
                Width = w.ToString(),
                Type = TableWidthUnitValues.Dxa
            });
            tcPr.AppendChild(new TableCellVerticalAlignment
            {
                Val = TableVerticalAlignmentValues.Center
            });

            // Header: dark blue background
            if (isHeader)
            {
                tcPr.AppendChild(new Shading
                {
                    Val = ShadingPatternValues.Clear,
                    Color = "auto",
                    Fill = "2F5496"     // Dark blue
                });
            }
            // Zebra stripe: light gray on odd data rows
            else if (isOddDataRow)
            {
                tcPr.AppendChild(new Shading
                {
                    Val = ShadingPatternValues.Clear,
                    Color = "auto",
                    Fill = "F2F2F2"     // Light gray
                });
            }
            // Totals row: top border emphasis
            if (isTotals)
            {
                tcPr.AppendChild(new TableCellBorders(
                    new TopBorder
                    {
                        Val = BorderValues.Single,
                        Size = 12U,    // 1.5pt
                        Color = "000000"
                    }
                ));
            }
            cell.AppendChild(tcPr);

            // Paragraph with text
            var runProps = new RunProperties();
            if (isHeader)
            {
                runProps.AppendChild(new Bold());
                runProps.AppendChild(new Color { Val = "FFFFFF" });   // White text
                runProps.AppendChild(new FontSize { Val = "22" });    // 11pt
            }
            else if (isTotals)
            {
                runProps.AppendChild(new Bold());
            }

            var para = new Paragraph(
                new ParagraphProperties(
                    new Justification
                    {
                        Val = (c > 0) ? JustificationValues.Right : JustificationValues.Left
                    }
                ),
                new Run(runProps, new Text(data[r][c]))
            );
            cell.AppendChild(para);
            row.AppendChild(cell);
        }
        table.AppendChild(row);
    }
    return table;
}

// --- Usage ---
string[][] salesData =
[
    ["Product",  "Q1",    "Q2",    "Q3",    "Q4"   ],
    ["Widget A", "1,200", "1,350", "1,100", "1,500"],
    ["Widget B", "800",   "920",   "870",   "1,010"],
    ["Widget C", "2,100", "2,300", "2,150", "2,400"],
    ["Total",    "4,100", "4,570", "4,120", "4,910"]
];

var styledTable = CreateStyledTable(salesData, hasHeaderRow: true, hasTotalsRow: true);
body.AppendChild(styledTable);
body.AppendChild(new Paragraph());  // Empty paragraph after table
```

### 2.15 Three-Line Table (学术三线表)

```csharp
// =============================================================================
// THREE-LINE TABLE (学术三线表)
// =============================================================================
// Academic/scientific table style common in Chinese academic publishing:
//   - Top border: THICK (1.5pt)
//   - Border below header: THIN (0.75pt)
//   - Bottom border: THICK (1.5pt)
//   - NO vertical borders, NO other horizontal borders
//
// This is achieved by:
// 1. Setting table borders to None (removes all defaults)
// 2. Using per-cell borders on the header row (bottom) and first/last rows (top/bottom)

static Table CreateThreeLineTable(string[] headers, string[][] rows)
{
    int cols = headers.Length;
    int totalWidth = 9360;
    int colWidth = totalWidth / cols;

    var table = new Table();

    // Table properties: NO borders by default
    var tblPr = new TableProperties(
        new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
        new TableJustification { Val = TableRowAlignmentValues.Center },
        new TableLayout { Type = TableLayoutValues.Fixed },
        new TableBorders(
            new TopBorder { Val = BorderValues.None, Size = 0U },
            new BottomBorder { Val = BorderValues.None, Size = 0U },
            new LeftBorder { Val = BorderValues.None, Size = 0U },
            new RightBorder { Val = BorderValues.None, Size = 0U },
            new InsideHorizontalBorder { Val = BorderValues.None, Size = 0U },
            new InsideVerticalBorder { Val = BorderValues.None, Size = 0U }
        )
    );
    table.AppendChild(tblPr);

    // Table grid
    var grid = new TableGrid();
    for (int c = 0; c < cols; c++)
    {
        int w = (c == cols - 1) ? totalWidth - colWidth * (cols - 1) : colWidth;
        grid.AppendChild(new GridColumn { Width = w.ToString() });
    }
    table.AppendChild(grid);

    // --- Header row ---
    var headerRow = new TableRow();
    headerRow.AppendChild(new TableRowProperties(new TableHeader()));

    for (int c = 0; c < cols; c++)
    {
        int w = (c == cols - 1) ? totalWidth - colWidth * (cols - 1) : colWidth;
        var cell = new TableCell();
        var tcPr = new TableCellProperties(
            new TableCellWidth { Width = w.ToString(), Type = TableWidthUnitValues.Dxa },
            new TableCellBorders(
                // Top: THICK line (1.5pt = 12 eighth-points)
                new TopBorder { Val = BorderValues.Single, Size = 12U, Color = "000000", Space = 0U },
                // Bottom: THIN line (0.75pt = 6 eighth-points)
                new BottomBorder { Val = BorderValues.Single, Size = 6U, Color = "000000", Space = 0U }
            ),
            new TableCellVerticalAlignment { Val = TableVerticalAlignmentValues.Center }
        );
        cell.AppendChild(tcPr);
        cell.AppendChild(new Paragraph(
            new ParagraphProperties(
                new Justification { Val = JustificationValues.Center }),
            new Run(
                new RunProperties(new Bold()),
                new Text(headers[c]))));
        cell.AppendChild(cell);     // Fix: should be row.AppendChild
        headerRow.AppendChild(cell);
    }
    table.AppendChild(headerRow);

    // --- Data rows ---
    for (int r = 0; r < rows.Length; r++)
    {
        var dataRow = new TableRow();
        bool isLastRow = (r == rows.Length - 1);

        for (int c = 0; c < cols; c++)
        {
            int w = (c == cols - 1) ? totalWidth - colWidth * (cols - 1) : colWidth;
            var cell = new TableCell();
            var tcPr = new TableCellProperties(
                new TableCellWidth { Width = w.ToString(), Type = TableWidthUnitValues.Dxa }
            );

            // Last data row: add THICK bottom border
            if (isLastRow)
            {
                tcPr.AppendChild(new TableCellBorders(
                    new BottomBorder
                    {
                        Val = BorderValues.Single,
                        Size = 12U,      // 1.5pt thick
                        Color = "000000",
                        Space = 0U
                    }
                ));
            }

            tcPr.AppendChild(new TableCellVerticalAlignment
            {
                Val = TableVerticalAlignmentValues.Center
            });
            cell.AppendChild(tcPr);
            cell.AppendChild(new Paragraph(
                new ParagraphProperties(
                    new Justification { Val = JustificationValues.Center }),
                new Run(new Text(rows[r][c]))));
            dataRow.AppendChild(cell);
        }
        table.AppendChild(dataRow);
    }

    return table;
}

// --- Usage ---
string[] columnHeaders = ["Variable", "Mean", "SD", "p-value"];
string[][] dataRows =
[
    ["Age",    "45.2", "12.3", "0.032"],
    ["BMI",    "26.8", "4.1",  "0.001"],
    ["SBP",    "132",  "18.5", "< 0.001"],
    ["HR",     "72.1", "11.2", "0.145"]
];

var threeLineTable = CreateThreeLineTable(columnHeaders, dataRows);
body.AppendChild(threeLineTable);
```

---

## 3. Headers, Footers & Page Numbers

Headers and footers are stored in separate XML parts (HeaderPart, FooterPart) linked to SectionProperties via HeaderReference and FooterReference.

### 3.1 Creating HeaderPart and FooterPart

```csharp
// =============================================================================
// CREATING HEADER AND FOOTER PARTS
// =============================================================================
// Headers and footers are separate parts within the package, each containing
// their own XML document tree rooted at <w:hdr> or <w:ftr>.
// They are linked to sections via HeaderReference/FooterReference.
//
// Steps:
// 1. Add a HeaderPart/FooterPart to the MainDocumentPart
// 2. Set the part's root element (Header/Footer)
// 3. Add content (paragraphs, tables, images) to the root element
// 4. Create a HeaderReference/FooterReference in SectionProperties

var mainPart = doc.MainDocumentPart!;

// --- Create a header part ---
var headerPart = mainPart.AddNewPart<HeaderPart>();
string headerPartId = mainPart.GetIdOfPart(headerPart);

// Build header content
headerPart.Header = new Header(
    new Paragraph(
        new ParagraphProperties(
            new Justification { Val = JustificationValues.Center }),
        new Run(
            new RunProperties(
                new FontSize { Val = "18" },      // 9pt — typical header size
                new Color { Val = "808080" }),     // Gray
            new Text("Company Confidential"))
    )
);
headerPart.Header.Save();

// --- Create a footer part ---
var footerPart = mainPart.AddNewPart<FooterPart>();
string footerPartId = mainPart.GetIdOfPart(footerPart);

footerPart.Footer = new Footer(
    new Paragraph(
        new ParagraphProperties(
            new Justification { Val = JustificationValues.Center }),
        new Run(
            new RunProperties(new FontSize { Val = "18" }),
            new Text("Footer text here"))
    )
);
footerPart.Footer.Save();
```

### 3.2 HeaderReference and FooterReference — Types

```csharp
// =============================================================================
// HEADER/FOOTER REFERENCE — LINKING TO SECTION
// =============================================================================
// HeaderReference/FooterReference types:
//   Default — used on all pages (unless First/Even overrides)
//   First   — used on the first page of the section (requires TitlePage)
//   Even    — used on even-numbered pages (requires EvenAndOddHeaders setting)
//
// A section can have up to 3 headers and 3 footers (Default + First + Even).

var sectPr = body.Elements<SectionProperties>().FirstOrDefault()
    ?? body.AppendChild(new SectionProperties());

// Default header (all pages)
sectPr.AppendChild(new HeaderReference
{
    Type = HeaderFooterValues.Default,
    Id = headerPartId
});

// Default footer (all pages)
sectPr.AppendChild(new FooterReference
{
    Type = HeaderFooterValues.Default,
    Id = footerPartId
});

// Produces XML:
// <w:sectPr>
//   <w:headerReference w:type="default" r:id="rId4" />
//   <w:footerReference w:type="default" r:id="rId5" />
// </w:sectPr>
```

### 3.3 Different First Page (TitlePage)

```csharp
// =============================================================================
// DIFFERENT FIRST PAGE — TITLEPAGE
// =============================================================================
// To have a different header/footer on the first page, you must:
// 1. Add a TitlePage element to SectionProperties
// 2. Create separate HeaderPart/FooterPart for the first page
// 3. Add HeaderReference/FooterReference with Type = First

// Enable different first page
sectPr.AppendChild(new TitlePage());
// Produces XML: <w:titlePg />

// Create first-page header (e.g., empty / no header on cover page)
var firstHeaderPart = mainPart.AddNewPart<HeaderPart>();
string firstHeaderId = mainPart.GetIdOfPart(firstHeaderPart);
firstHeaderPart.Header = new Header(new Paragraph()); // Empty header
firstHeaderPart.Header.Save();

// Create first-page footer
var firstFooterPart = mainPart.AddNewPart<FooterPart>();
string firstFooterId = mainPart.GetIdOfPart(firstFooterPart);
firstFooterPart.Footer = new Footer(new Paragraph()); // Empty footer
firstFooterPart.Footer.Save();

// Link to section
sectPr.AppendChild(new HeaderReference
{
    Type = HeaderFooterValues.First,
    Id = firstHeaderId
});
sectPr.AppendChild(new FooterReference
{
    Type = HeaderFooterValues.First,
    Id = firstFooterId
});
```

### 3.4 Even and Odd Page Headers

```csharp
// =============================================================================
// EVEN AND ODD PAGE HEADERS/FOOTERS
// =============================================================================
// For different headers on even vs. odd pages (e.g., book-style layout):
// 1. Set EvenAndOddHeaders in DocumentSettingsPart
// 2. Create separate parts for Even pages
// 3. "Default" type becomes the ODD page header/footer

// Enable even/odd in Settings
var settingsPart = mainPart.DocumentSettingsPart
    ?? mainPart.AddNewPart<DocumentSettingsPart>();
if (settingsPart.Settings == null)
    settingsPart.Settings = new Settings();

settingsPart.Settings.AppendChild(new EvenAndOddHeaders());
settingsPart.Settings.Save();
// Produces XML in settings.xml: <w:evenAndOddHeaders />

// Create even-page header
var evenHeaderPart = mainPart.AddNewPart<HeaderPart>();
string evenHeaderId = mainPart.GetIdOfPart(evenHeaderPart);
evenHeaderPart.Header = new Header(
    new Paragraph(
        new ParagraphProperties(
            new Justification { Val = JustificationValues.Left }),
        new Run(new Text("Chapter Title"))   // Left-aligned on even pages
    )
);
evenHeaderPart.Header.Save();

// Link: "Default" = odd pages, "Even" = even pages
sectPr.AppendChild(new HeaderReference
{
    Type = HeaderFooterValues.Even,
    Id = evenHeaderId
});
// The existing Default header is now used only on odd pages.
```

### 3.5 SimpleField — PAGE, NUMPAGES, SECTIONPAGES

```csharp
// =============================================================================
// SIMPLE FIELDS — PAGE NUMBERS AND TOTALS
// =============================================================================
// SimpleField inserts a field code that Word evaluates at render time.
// Common field codes:
//   PAGE         — current page number
//   NUMPAGES     — total pages in document
//   SECTIONPAGES — total pages in current section
//   DATE         — current date
//   TIME         — current time
//
// The Instruction property contains the field code string.
// A child Run with text is used for the "cached" display value (optional but
// recommended for non-Word renderers).

// --- Simple page number field ---
var pageField = new SimpleField { Instruction = " PAGE " };
pageField.AppendChild(new Run(new Text("1")));  // Cached display value
// Produces XML: <w:fldSimple w:instr=" PAGE "><w:r><w:t>1</w:t></w:r></w:fldSimple>

// --- Total page count ---
var totalField = new SimpleField { Instruction = " NUMPAGES " };
totalField.AppendChild(new Run(new Text("1")));

// --- Section page count ---
var sectionPagesField = new SimpleField { Instruction = " SECTIONPAGES " };
sectionPagesField.AppendChild(new Run(new Text("1")));
```

### 3.6 "Page X of Y" Footer

```csharp
// =============================================================================
// "PAGE X OF Y" FOOTER
// =============================================================================
// Combines text runs with SimpleField elements in a single paragraph.

var pageXofYFooter = mainPart.AddNewPart<FooterPart>();
string pageXofYId = mainPart.GetIdOfPart(pageXofYFooter);

var footerPara = new Paragraph(
    new ParagraphProperties(
        new Justification { Val = JustificationValues.Center })
);

// "Page "
footerPara.AppendChild(new Run(
    new RunProperties(new FontSize { Val = "18" }),   // 9pt
    new Text("Page ") { Space = SpaceProcessingModeValues.Preserve }
));

// PAGE field
var pgField = new SimpleField { Instruction = " PAGE " };
pgField.AppendChild(new Run(
    new RunProperties(new FontSize { Val = "18" }),
    new Text("1")));
footerPara.AppendChild(pgField);

// " of "
footerPara.AppendChild(new Run(
    new RunProperties(new FontSize { Val = "18" }),
    new Text(" of ") { Space = SpaceProcessingModeValues.Preserve }
));

// NUMPAGES field
var npField = new SimpleField { Instruction = " NUMPAGES " };
npField.AppendChild(new Run(
    new RunProperties(new FontSize { Val = "18" }),
    new Text("1")));
footerPara.AppendChild(npField);

pageXofYFooter.Footer = new Footer(footerPara);
pageXofYFooter.Footer.Save();

// Link to section
sectPr.AppendChild(new FooterReference
{
    Type = HeaderFooterValues.Default,
    Id = pageXofYId
});
```

### 3.7 Header with Logo Image

```csharp
// =============================================================================
// HEADER WITH LOGO IMAGE
// =============================================================================
// To add an image to a header:
// 1. Add an ImagePart to the HeaderPart (not MainDocumentPart)
// 2. Build the Drawing/Inline/Graphic elements in the header paragraph
// 3. Image sizing uses EMUs (English Metric Units): 1 inch = 914400 EMU

var logoHeaderPart = mainPart.AddNewPart<HeaderPart>();
string logoHeaderId = mainPart.GetIdOfPart(logoHeaderPart);

// Add image to header part
var imagePart = logoHeaderPart.AddImagePart(ImagePartType.Png);
using (var stream = File.OpenRead("logo.png"))
{
    imagePart.FeedData(stream);
}
string imageRelId = logoHeaderPart.GetIdOfPart(imagePart);

// Image dimensions in EMU (e.g., 1.5 inch wide × 0.5 inch tall)
long widthEmu = 1371600;    // 1.5 * 914400
long heightEmu = 457200;    // 0.5 * 914400

// Build the inline drawing element
var drawing = new Drawing(
    new DW.Inline(
        new DW.Extent { Cx = widthEmu, Cy = heightEmu },
        new DW.EffectExtent { LeftEdge = 0L, TopEdge = 0L, RightEdge = 0L, BottomEdge = 0L },
        new DW.DocProperties { Id = 1U, Name = "Logo" },
        new DW.NonVisualGraphicFrameDrawingProperties(
            new A.GraphicFrameLocks { NoChangeAspect = true }),
        new A.Graphic(
            new A.GraphicData(
                new PIC.Picture(
                    new PIC.NonVisualPictureProperties(
                        new PIC.NonVisualDrawingProperties { Id = 1U, Name = "logo.png" },
                        new PIC.NonVisualPictureDrawingProperties()),
                    new PIC.BlipFill(
                        new A.Blip { Embed = imageRelId },
                        new A.Stretch(new A.FillRectangle())),
                    new PIC.ShapeProperties(
                        new A.Transform2D(
                            new A.Offset { X = 0L, Y = 0L },
                            new A.Extents { Cx = widthEmu, Cy = heightEmu }),
                        new A.PresetGeometry(new A.AdjustValueList())
                        { Preset = A.ShapeTypeValues.Rectangle })
                )
            ) { Uri = "http://schemas.openxmlformats.org/drawingml/2006/picture" }
        )
    )
    {
        DistanceFromTop = 0U,
        DistanceFromBottom = 0U,
        DistanceFromLeft = 0U,
        DistanceFromRight = 0U
    }
);

logoHeaderPart.Header = new Header(
    new Paragraph(new Run(drawing))
);
logoHeaderPart.Header.Save();
```

### 3.8 Table-Layout Header (Logo Left, Text Center, Page Right)

```csharp
// =============================================================================
// TABLE-LAYOUT HEADER
// =============================================================================
// A common professional header pattern: 3-column invisible table
//   Left cell:   Company logo
//   Center cell: Document title
//   Right cell:  Page number
// The table has no borders, giving a clean three-zone layout.

var tblHeaderPart = mainPart.AddNewPart<HeaderPart>();
string tblHeaderId = mainPart.GetIdOfPart(tblHeaderPart);

// Content width for Letter with 1" margins = 9360 DXA
var headerTable = new Table(
    new TableProperties(
        new TableWidth { Width = "5000", Type = TableWidthUnitValues.Pct },
        new TableLayout { Type = TableLayoutValues.Fixed },
        new TableBorders(
            new TopBorder { Val = BorderValues.None },
            new BottomBorder { Val = BorderValues.Single, Size = 4U, Color = "000000" },
            new LeftBorder { Val = BorderValues.None },
            new RightBorder { Val = BorderValues.None },
            new InsideHorizontalBorder { Val = BorderValues.None },
            new InsideVerticalBorder { Val = BorderValues.None }
        )
    ),
    new TableGrid(
        new GridColumn { Width = "3120" },   // ~1/3
        new GridColumn { Width = "3120" },   // ~1/3
        new GridColumn { Width = "3120" }    // ~1/3
    )
);

// Left cell: logo placeholder (or image Drawing)
var leftCell = new TableCell(
    new TableCellProperties(
        new TableCellWidth { Width = "3120", Type = TableWidthUnitValues.Dxa },
        new TableCellVerticalAlignment { Val = TableVerticalAlignmentValues.Center }),
    new Paragraph(
        new ParagraphProperties(
            new Justification { Val = JustificationValues.Left }),
        new Run(
            new RunProperties(new Bold(), new FontSize { Val = "18" }),
            new Text("ACME Corp")))
);

// Center cell: document title
var centerCell = new TableCell(
    new TableCellProperties(
        new TableCellWidth { Width = "3120", Type = TableWidthUnitValues.Dxa },
        new TableCellVerticalAlignment { Val = TableVerticalAlignmentValues.Center }),
    new Paragraph(
        new ParagraphProperties(
            new Justification { Val = JustificationValues.Center }),
        new Run(
            new RunProperties(new FontSize { Val = "18" }),
            new Text("Technical Specification v2.0")))
);

// Right cell: page number
var pageFieldRight = new SimpleField { Instruction = " PAGE " };
pageFieldRight.AppendChild(new Run(
    new RunProperties(new FontSize { Val = "18" }),
    new Text("1")));

var rightCell = new TableCell(
    new TableCellProperties(
        new TableCellWidth { Width = "3120", Type = TableWidthUnitValues.Dxa },
        new TableCellVerticalAlignment { Val = TableVerticalAlignmentValues.Center }),
    new Paragraph(
        new ParagraphProperties(
            new Justification { Val = JustificationValues.Right }),
        new Run(
            new RunProperties(new FontSize { Val = "18" }),
            new Text("Page ") { Space = SpaceProcessingModeValues.Preserve }),
        pageFieldRight)
);

headerTable.AppendChild(new TableRow(leftCell, centerCell, rightCell));

tblHeaderPart.Header = new Header(headerTable, new Paragraph());
tblHeaderPart.Header.Save();
```

### 3.9 Chinese Government Document Page Numbers (公文页码)

```csharp
// =============================================================================
// CHINESE GOVERNMENT DOCUMENT PAGE NUMBERS (公文页码)
// =============================================================================
// Standard: bottom center, format "-X-" (em-dash surrounding page number)
// Font: 宋体 (SimSun) 四号 (14pt = "28" half-points)
// Per GB/T 9704-2012

var govFooterPart = mainPart.AddNewPart<FooterPart>();
string govFooterId = mainPart.GetIdOfPart(govFooterPart);

var govFooterPara = new Paragraph(
    new ParagraphProperties(
        new Justification { Val = JustificationValues.Center })
);

// Run properties for 宋体四号
RunProperties GovPageRunProps() => new RunProperties(
    new RunFonts
    {
        Ascii = "SimSun",
        HighAnsi = "SimSun",
        EastAsia = "SimSun"
    },
    new FontSize { Val = "28" },           // 14pt = 四号
    new FontSizeComplexScript { Val = "28" }
);

// "—" (em-dash before page number)
govFooterPara.AppendChild(new Run(
    GovPageRunProps(),
    new Text("\u2014") { Space = SpaceProcessingModeValues.Preserve }
));

// PAGE field
var govPageField = new SimpleField { Instruction = " PAGE " };
govPageField.AppendChild(new Run(GovPageRunProps(), new Text("1")));
govFooterPara.AppendChild(govPageField);

// "—" (em-dash after page number)
govFooterPara.AppendChild(new Run(
    GovPageRunProps(),
    new Text("\u2014") { Space = SpaceProcessingModeValues.Preserve }
));

govFooterPart.Footer = new Footer(govFooterPara);
govFooterPart.Footer.Save();

// Link to section
sectPr.AppendChild(new FooterReference
{
    Type = HeaderFooterValues.Default,
    Id = govFooterId
});
```

### 3.10 Multi-Section with Different Headers

```csharp
// =============================================================================
// MULTI-SECTION WITH DIFFERENT HEADERS
// =============================================================================
// Each section can have its own set of header/footer parts.
// To change headers mid-document, create a section break and attach
// different HeaderReference/FooterReference to each SectionProperties.
// See Section 4 for full section break mechanics.

// Section 1 header
var sec1Header = mainPart.AddNewPart<HeaderPart>();
string sec1HeaderId = mainPart.GetIdOfPart(sec1Header);
sec1Header.Header = new Header(
    new Paragraph(new Run(new Text("Chapter 1: Introduction"))));
sec1Header.Header.Save();

// Section 2 header
var sec2Header = mainPart.AddNewPart<HeaderPart>();
string sec2HeaderId = mainPart.GetIdOfPart(sec2Header);
sec2Header.Header = new Header(
    new Paragraph(new Run(new Text("Chapter 2: Methods"))));
sec2Header.Header.Save();

// Section 1 content + section break
body.AppendChild(new Paragraph(new Run(new Text("Section 1 content..."))));

// Mid-document section properties (in last paragraph of section 1)
var sec1Break = new Paragraph(
    new ParagraphProperties(
        new SectionProperties(
            new PageSize { Width = 12240U, Height = 15840U },
            new PageMargin
            {
                Top = 1440, Bottom = 1440,
                Left = 1440U, Right = 1440U,
                Header = 720U, Footer = 720U, Gutter = 0U
            },
            new SectionType { Val = SectionMarkValues.NextPage },
            new HeaderReference { Type = HeaderFooterValues.Default, Id = sec1HeaderId }
        )
    )
);
body.AppendChild(sec1Break);

// Section 2 content
body.AppendChild(new Paragraph(new Run(new Text("Section 2 content..."))));

// Final section properties (last child of Body)
var sec2Props = new SectionProperties(
    new PageSize { Width = 12240U, Height = 15840U },
    new PageMargin
    {
        Top = 1440, Bottom = 1440,
        Left = 1440U, Right = 1440U,
        Header = 720U, Footer = 720U, Gutter = 0U
    },
    new HeaderReference { Type = HeaderFooterValues.Default, Id = sec2HeaderId }
);
body.AppendChild(sec2Props);
```

---

## 4. Section Breaks & Multi-Section

### 4.1 Section Properties Placement Rules

```csharp
// =============================================================================
// SECTION PROPERTIES PLACEMENT
// =============================================================================
// There are exactly TWO places SectionProperties can appear:
//
// 1. FINAL SECTION: As the last child element of <w:body>.
//    This controls the last (or only) section of the document.
//    body.AppendChild(new SectionProperties(...));
//
// 2. MID-DOCUMENT SECTION BREAK: Inside ParagraphProperties of the
//    LAST paragraph of a section. This paragraph acts as the section divider.
//    The paragraph's text content belongs to the PREVIOUS section.
//
// IMPORTANT: Mid-document SectionProperties goes inside pPr, NOT as a child
// of Body. This is the #1 mistake when creating multi-section documents.

// --- Final section (last child of Body) ---
var finalSectPr = new SectionProperties(
    new PageSize { Width = 12240U, Height = 15840U },
    new PageMargin
    {
        Top = 1440, Bottom = 1440,
        Left = 1440U, Right = 1440U,
        Header = 720U, Footer = 720U, Gutter = 0U
    }
);
body.AppendChild(finalSectPr);  // MUST be last child

// --- Mid-document section break ---
// This paragraph ends section 1 and starts section 2
var sectionBreakPara = new Paragraph(
    new ParagraphProperties(
        new SectionProperties(
            new PageSize { Width = 12240U, Height = 15840U },
            new PageMargin
            {
                Top = 1440, Bottom = 1440,
                Left = 1440U, Right = 1440U,
                Header = 720U, Footer = 720U, Gutter = 0U
            },
            new SectionType { Val = SectionMarkValues.NextPage }
        )
    )
);
// Produces XML:
// <w:p>
//   <w:pPr>
//     <w:sectPr>
//       <w:pgSz w:w="12240" w:h="15840" />
//       <w:pgMar ... />
//       <w:type w:val="nextPage" />
//     </w:sectPr>
//   </w:pPr>
// </w:p>
```

### 4.2 SectionType Values

```csharp
// =============================================================================
// SECTION TYPE VALUES
// =============================================================================
// SectionType controls how the section break behaves:
//
//   NextPage    — new section starts on next page (most common)
//   Continuous  — new section starts on same page (used for column changes)
//   EvenPage    — new section starts on next even page (inserts blank if needed)
//   OddPage     — new section starts on next odd page (inserts blank if needed)
//
// If SectionType is omitted, the default is NextPage.

// Next page break (explicit)
var nextPageBreak = new SectionType { Val = SectionMarkValues.NextPage };

// Continuous — same page (e.g., switch from 1-column to 2-column)
var continuousBreak = new SectionType { Val = SectionMarkValues.Continuous };

// Even page — for chapters that must start on left page (in book layout)
var evenPageBreak = new SectionType { Val = SectionMarkValues.EvenPage };

// Odd page — for chapters that must start on right page
var oddPageBreak = new SectionType { Val = SectionMarkValues.OddPage };
```

### 4.3 Per-Section Page Setup

```csharp
// =============================================================================
// PER-SECTION PAGE SETUP
// =============================================================================
// Each section independently controls its own:
//   - PageSize (portrait vs landscape, paper size)
//   - PageMargin
//   - Columns
//   - Headers/Footers
//   - PageNumberType (restart numbering)
//   - LineNumbering
//   - DocGrid

// Example: Section with landscape A4 and narrow margins
var landscapeSection = new SectionProperties(
    new PageSize
    {
        Width = 16838U,    // A4 long edge (landscape: swap W/H)
        Height = 11906U,   // A4 short edge
        Orient = PageOrientationValues.Landscape
    },
    new PageMargin
    {
        Top = 720, Bottom = 720,
        Left = 720U, Right = 720U,
        Header = 720U, Footer = 720U, Gutter = 0U
    },
    new SectionType { Val = SectionMarkValues.NextPage }
);
```

### 4.4 PageNumberType — Restart Numbering

```csharp
// =============================================================================
// PAGE NUMBER TYPE — RESTART AND FORMAT
// =============================================================================
// PageNumberType controls page numbering within a section.
//   Start  — starting page number (restarts counting)
//   Format — numbering format (Decimal, UpperRoman, LowerRoman,
//            UpperLetter, LowerLetter)
//
// Common pattern: front matter uses i, ii, iii; body restarts at 1.

// Restart at page 1 (e.g., after front matter)
var restartNumbering = new PageNumberType
{
    Start = 1,
    Format = NumberFormatValues.Decimal
};
// Produces XML: <w:pgNumType w:start="1" w:fmt="decimal" />

// Roman numeral numbering for front matter
var romanNumbering = new PageNumberType
{
    Start = 1,
    Format = NumberFormatValues.LowerRoman
};
// Produces XML: <w:pgNumType w:start="1" w:fmt="lowerRoman" />

// Add to section properties
landscapeSection.AppendChild(restartNumbering);
```

### 4.5 Complete Example: Portrait, Landscape, Portrait

```csharp
// =============================================================================
// COMPLETE MULTI-SECTION EXAMPLE
// =============================================================================
// Document with three sections:
//   Section 1: Letter portrait (cover + intro)
//   Section 2: Letter landscape (wide table)
//   Section 3: Letter portrait (conclusion), page numbers restart at 1
//
// Each section has its own header.

using var doc = WordprocessingDocument.Create(
    "MultiSection.docx", WordprocessingDocumentType.Document);

var mainPart = doc.MainDocumentPart!;
var body = mainPart.Document.Body!;

// --- Create headers for each section ---
HeaderPart CreateSimpleHeader(string text)
{
    var hp = mainPart.AddNewPart<HeaderPart>();
    hp.Header = new Header(
        new Paragraph(
            new ParagraphProperties(
                new ParagraphBorders(
                    new BottomBorder
                    {
                        Val = BorderValues.Single, Size = 4U,
                        Color = "999999", Space = 1U
                    }),
                new Justification { Val = JustificationValues.Right }),
            new Run(
                new RunProperties(
                    new FontSize { Val = "18" },
                    new Color { Val = "999999" }),
                new Text(text)))
    );
    hp.Header.Save();
    return hp;
}

var header1 = CreateSimpleHeader("Introduction");
var header2 = CreateSimpleHeader("Data Tables");
var header3 = CreateSimpleHeader("Conclusion");

// --- Create "Page X of Y" footer (shared) ---
var sharedFooter = mainPart.AddNewPart<FooterPart>();
var fPara = new Paragraph(
    new ParagraphProperties(new Justification { Val = JustificationValues.Center }));
fPara.AppendChild(new Run(
    new RunProperties(new FontSize { Val = "18" }),
    new Text("Page ") { Space = SpaceProcessingModeValues.Preserve }));
var pf = new SimpleField { Instruction = " PAGE " };
pf.AppendChild(new Run(new RunProperties(new FontSize { Val = "18" }), new Text("1")));
fPara.AppendChild(pf);
fPara.AppendChild(new Run(
    new RunProperties(new FontSize { Val = "18" }),
    new Text(" of ") { Space = SpaceProcessingModeValues.Preserve }));
var npf = new SimpleField { Instruction = " NUMPAGES " };
npf.AppendChild(new Run(new RunProperties(new FontSize { Val = "18" }), new Text("1")));
fPara.AppendChild(npf);
sharedFooter.Footer = new Footer(fPara);
sharedFooter.Footer.Save();
string sharedFooterId = mainPart.GetIdOfPart(sharedFooter);

// =================== SECTION 1: Portrait ===================
body.AppendChild(new Paragraph(
    new ParagraphProperties(
        new Justification { Val = JustificationValues.Center }),
    new Run(
        new RunProperties(new Bold(), new FontSize { Val = "48" }),
        new Text("Annual Report 2025"))));

body.AppendChild(new Paragraph(new Run(new Text("Introduction content goes here..."))));

// Section 1 break (inside pPr of last paragraph)
body.AppendChild(new Paragraph(
    new ParagraphProperties(
        new SectionProperties(
            new PageSize { Width = 12240U, Height = 15840U },
            new PageMargin
            {
                Top = 1440, Bottom = 1440,
                Left = 1440U, Right = 1440U,
                Header = 720U, Footer = 720U, Gutter = 0U
            },
            new SectionType { Val = SectionMarkValues.NextPage },
            new HeaderReference
            {
                Type = HeaderFooterValues.Default,
                Id = mainPart.GetIdOfPart(header1)
            },
            new FooterReference
            {
                Type = HeaderFooterValues.Default,
                Id = sharedFooterId
            }
        )
    )
));

// =================== SECTION 2: Landscape ===================
body.AppendChild(new Paragraph(new Run(
    new RunProperties(new Bold(), new FontSize { Val = "28" }),
    new Text("Wide Data Table"))));

body.AppendChild(new Paragraph(new Run(
    new Text("This section uses landscape orientation for a wide table."))));

// Section 2 break
body.AppendChild(new Paragraph(
    new ParagraphProperties(
        new SectionProperties(
            new PageSize
            {
                Width = 15840U,     // SWAPPED for landscape
                Height = 12240U,    // SWAPPED for landscape
                Orient = PageOrientationValues.Landscape
            },
            new PageMargin
            {
                Top = 1440, Bottom = 1440,
                Left = 1440U, Right = 1440U,
                Header = 720U, Footer = 720U, Gutter = 0U
            },
            new SectionType { Val = SectionMarkValues.NextPage },
            new HeaderReference
            {
                Type = HeaderFooterValues.Default,
                Id = mainPart.GetIdOfPart(header2)
            },
            new FooterReference
            {
                Type = HeaderFooterValues.Default,
                Id = sharedFooterId
            }
        )
    )
));

// =================== SECTION 3: Portrait (restart page numbers) ===================
body.AppendChild(new Paragraph(new Run(
    new RunProperties(new Bold(), new FontSize { Val = "28" }),
    new Text("Conclusion"))));

body.AppendChild(new Paragraph(new Run(
    new Text("Final section content with restarted page numbering."))));

// Final section properties — last child of Body
body.AppendChild(new SectionProperties(
    new PageSize { Width = 12240U, Height = 15840U },
    new PageMargin
    {
        Top = 1440, Bottom = 1440,
        Left = 1440U, Right = 1440U,
        Header = 720U, Footer = 720U, Gutter = 0U
    },
    new PageNumberType
    {
        Start = 1,                                         // Restart at page 1
        Format = NumberFormatValues.Decimal
    },
    new HeaderReference
    {
        Type = HeaderFooterValues.Default,
        Id = mainPart.GetIdOfPart(header3)
    },
    new FooterReference
    {
        Type = HeaderFooterValues.Default,
        Id = sharedFooterId
    }
));

mainPart.Document.Save();
```

---

## 5. Document Properties

### 5.1 CoreFilePropertiesPart (Dublin Core Metadata)

```csharp
// =============================================================================
// CORE FILE PROPERTIES (DUBLIN CORE)
// =============================================================================
// Core properties map to the Dublin Core metadata standard.
// They appear in File > Properties > Summary in Word.
// The underlying XML is stored in docProps/core.xml.
//
// Available properties: Title, Subject, Creator (Author), Keywords,
// Description, LastModifiedBy, Revision, Created, Modified, Category,
// ContentStatus, ContentType, Identifier, Language, Version

using var doc = WordprocessingDocument.Create(
    "PropertiesDemo.docx", WordprocessingDocumentType.Document);

// Core properties are accessed via the package-level properties
// Use the OpenXml Packaging API:
var corePart = doc.CoreFilePropertiesPart
    ?? doc.AddCoreFilePropertiesPart();

// The core properties use the OpenXmlPart's XML directly.
// You can set properties via the PackageProperties interface:
doc.PackageProperties.Title = "Quarterly Financial Report";
doc.PackageProperties.Subject = "Q4 2025 Financial Summary";
doc.PackageProperties.Creator = "Jane Smith";
doc.PackageProperties.Keywords = "finance, quarterly, report, 2025";
doc.PackageProperties.Description = "Comprehensive financial report for Q4 2025";
doc.PackageProperties.LastModifiedBy = "John Doe";
doc.PackageProperties.Revision = "3";
doc.PackageProperties.Created = DateTime.UtcNow;
doc.PackageProperties.Modified = DateTime.UtcNow;
doc.PackageProperties.Category = "Financial Reports";
doc.PackageProperties.ContentStatus = "Final";
doc.PackageProperties.Language = "en-US";
doc.PackageProperties.Version = "2.0";

// Produces docProps/core.xml:
// <cp:coreProperties>
//   <dc:title>Quarterly Financial Report</dc:title>
//   <dc:subject>Q4 2025 Financial Summary</dc:subject>
//   <dc:creator>Jane Smith</dc:creator>
//   <cp:keywords>finance, quarterly, report, 2025</cp:keywords>
//   <dc:description>Comprehensive financial report...</dc:description>
//   <cp:lastModifiedBy>John Doe</cp:lastModifiedBy>
//   <cp:revision>3</cp:revision>
//   <dcterms:created>2025-12-01T00:00:00Z</dcterms:created>
//   <dcterms:modified>2025-12-01T00:00:00Z</dcterms:modified>
//   <cp:category>Financial Reports</cp:category>
//   <cp:contentStatus>Final</cp:contentStatus>
// </cp:coreProperties>
```

### 5.2 ExtendedFilePropertiesPart (Application Properties)

```csharp
// =============================================================================
// EXTENDED FILE PROPERTIES (APPLICATION PROPERTIES)
// =============================================================================
// Extended properties are stored in docProps/app.xml.
// They include application-specific metadata like Company, Manager, etc.

using DocumentFormat.OpenXml.ExtendedProperties;

var extPart = doc.ExtendedFilePropertiesPart
    ?? doc.AddExtendedFilePropertiesPart();

extPart.Properties = new DocumentFormat.OpenXml.ExtendedProperties.Properties();

// Company name
extPart.Properties.AppendChild(
    new DocumentFormat.OpenXml.ExtendedProperties.Company("ACME Corporation"));

// Manager
extPart.Properties.AppendChild(
    new DocumentFormat.OpenXml.ExtendedProperties.Manager("Alice Johnson"));

// Application name
extPart.Properties.AppendChild(
    new DocumentFormat.OpenXml.ExtendedProperties.Application("Custom Document Generator"));

// Application version
extPart.Properties.AppendChild(
    new DocumentFormat.OpenXml.ExtendedProperties.ApplicationVersion("1.0.0"));

// Total editing time in minutes
extPart.Properties.AppendChild(
    new DocumentFormat.OpenXml.ExtendedProperties.TotalTime("0"));

// Pages, Words, Characters (these are hints; Word recalculates them)
extPart.Properties.AppendChild(
    new DocumentFormat.OpenXml.ExtendedProperties.Pages("1"));
extPart.Properties.AppendChild(
    new DocumentFormat.OpenXml.ExtendedProperties.Words("0"));
extPart.Properties.AppendChild(
    new DocumentFormat.OpenXml.ExtendedProperties.Characters("0"));

extPart.Properties.Save();

// Produces docProps/app.xml:
// <Properties>
//   <Company>ACME Corporation</Company>
//   <Manager>Alice Johnson</Manager>
//   <Application>Custom Document Generator</Application>
//   <AppVersion>1.0.0</AppVersion>
//   <TotalTime>0</TotalTime>
//   <Pages>1</Pages>
// </Properties>
```

### 5.3 CustomFilePropertiesPart (Custom Key-Value Properties)

```csharp
// =============================================================================
// CUSTOM FILE PROPERTIES (KEY-VALUE PAIRS)
// =============================================================================
// Custom properties allow arbitrary key-value metadata.
// Stored in docProps/custom.xml. Useful for document management systems,
// workflow tracking, template variables, etc.
//
// Supported value types: Text (string), Number (int), Date (DateTime),
// Boolean (bool), Filetime

using DocumentFormat.OpenXml.CustomProperties;
using DocumentFormat.OpenXml.VariantTypes;

var customPart = doc.CustomFilePropertiesPart
    ?? doc.AddCustomFilePropertiesPart();

customPart.Properties = new DocumentFormat.OpenXml.CustomProperties.Properties();

// Property IDs must start at 2 and increment
int propertyId = 2;

// --- String property ---
customPart.Properties.AppendChild(new CustomDocumentProperty
{
    FormatId = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}",
    PropertyId = propertyId++,
    Name = "Department",
    VTLPWSTR = new VTLPWSTR("Engineering")
});

// --- Integer property ---
customPart.Properties.AppendChild(new CustomDocumentProperty
{
    FormatId = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}",
    PropertyId = propertyId++,
    Name = "DocumentVersion",
    VTInt32 = new VTInt32("5")
});

// --- Boolean property ---
customPart.Properties.AppendChild(new CustomDocumentProperty
{
    FormatId = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}",
    PropertyId = propertyId++,
    Name = "Approved",
    VTBool = new VTBool("true")
});

// --- DateTime property ---
customPart.Properties.AppendChild(new CustomDocumentProperty
{
    FormatId = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}",
    PropertyId = propertyId++,
    Name = "ApprovalDate",
    VTFileTime = new VTFileTime(DateTime.UtcNow.ToString("yyyy-MM-ddTHH:mm:ssZ"))
});

// --- Double/Float property ---
customPart.Properties.AppendChild(new CustomDocumentProperty
{
    FormatId = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}",
    PropertyId = propertyId++,
    Name = "ConfidenceScore",
    VTDouble = new VTDouble("0.95")
});

customPart.Properties.Save();

// Produces docProps/custom.xml:
// <Properties>
//   <property fmtid="{D5CDD505-...}" pid="2" name="Department">
//     <vt:lpwstr>Engineering</vt:lpwstr>
//   </property>
//   <property fmtid="{D5CDD505-...}" pid="3" name="DocumentVersion">
//     <vt:i4>5</vt:i4>
//   </property>
//   <property fmtid="{D5CDD505-...}" pid="4" name="Approved">
//     <vt:bool>true</vt:bool>
//   </property>
//   ...
// </Properties>
```

### 5.4 Reading and Modifying Existing Properties

```csharp
// =============================================================================
// READING AND MODIFYING EXISTING PROPERTIES
// =============================================================================

using var existingDoc = WordprocessingDocument.Open("existing.docx", isEditable: true);

// --- Read core properties ---
string? title = existingDoc.PackageProperties.Title;
string? author = existingDoc.PackageProperties.Creator;
DateTime? modified = existingDoc.PackageProperties.Modified;

// --- Modify core properties ---
existingDoc.PackageProperties.Title = "Updated Title";
existingDoc.PackageProperties.Modified = DateTime.UtcNow;

// --- Read custom properties ---
var customProps = existingDoc.CustomFilePropertiesPart?.Properties;
if (customProps != null)
{
    foreach (var prop in customProps.Elements<CustomDocumentProperty>())
    {
        string name = prop.Name!;
        // Value is in one of the VT* child elements
        string? textValue = prop.VTLPWSTR?.Text;
        string? intValue = prop.VTInt32?.Text;
        string? boolValue = prop.VTBool?.Text;
        // Use whichever is non-null
    }
}

// --- Update a specific custom property ---
var deptProp = customProps?.Elements<CustomDocumentProperty>()
    .FirstOrDefault(p => p.Name == "Department");
if (deptProp != null)
{
    deptProp.VTLPWSTR = new VTLPWSTR("Marketing");
    customProps!.Save();
}
```

---

## 6. Printing & Compatibility Settings

### 6.1 DocumentSettingsPart — Zoom, TabStop, ProofState

```csharp
// =============================================================================
// DOCUMENT SETTINGS — ZOOM, TAB STOPS, PROOF STATE
// =============================================================================
// DocumentSettingsPart (settings.xml) contains document-wide settings.
// These control behavior in Word's UI and rendering.

var mainPart2 = doc.MainDocumentPart!;
var settingsPart2 = mainPart2.DocumentSettingsPart
    ?? mainPart2.AddNewPart<DocumentSettingsPart>();
settingsPart2.Settings ??= new Settings();
var settings = settingsPart2.Settings;

// --- Zoom level ---
// Val = percentage (100 = 100%). Percent is a string.
settings.AppendChild(new Zoom
{
    Percent = "120",                                      // 120% zoom
    Val = PresetZoomValues.BestFit                        // Or: None, FullPage, BestFit, TextFit
});
// Produces XML: <w:zoom w:percent="120" w:val="bestFit" />

// --- Default Tab Stop ---
// Distance in DXA for default tab stops. Standard is 720 (0.5 inch).
settings.AppendChild(new DefaultTabStop
{
    Val = 720                                             // 0.5 inch
});
// Produces XML: <w:defaultTabStop w:val="720" />

// For Chinese documents, common default tab stop is 420 (about 2 characters wide)
// settings.AppendChild(new DefaultTabStop { Val = 420 });

// --- Proof State ---
// Tells Word the spell/grammar check status. Setting both to "clean"
// prevents Word from showing the "Proofing" notification on open.
settings.AppendChild(new ProofState
{
    Spelling = ProofingStateValues.Clean,
    Grammar = ProofingStateValues.Clean
});
// Produces XML: <w:proofState w:spelling="clean" w:grammar="clean" />

// --- Character Spacing Control ---
// CompressWhitespace: whether to compress whitespace at line edges (CJK)
settings.AppendChild(new CharacterSpacingControl
{
    Val = CharacterSpacingValues.DoNotCompress
});

// --- Remove personal information on save ---
settings.AppendChild(new RemovePersonalInformation());
// Produces XML: <w:removePersonalInformation />

settings.Save();
```

### 6.2 Compatibility Settings

```csharp
// =============================================================================
// COMPATIBILITY SETTINGS
// =============================================================================
// Compatibility settings control how Word renders the document,
// providing backward compatibility with older Word versions.
// CompatibilityMode is the most important setting.

var compat = new Compatibility();

// --- Compatibility Mode ---
// 15 = Word 2013+ mode (current standard)
// 14 = Word 2010 mode
// 12 = Word 2007 mode
// Omitted or 0 = oldest compatibility
compat.AppendChild(new CompatibilitySetting
{
    Name = CompatSettingNameValues.CompatibilityMode,
    Uri = "http://schemas.microsoft.com/office/word",
    Val = "15"                                            // Word 2013+ mode
});

// --- Override page break rules ---
// Useful compatibility flags for consistent rendering:

// UseWord2002TableStyleRules: use newer table style rules
compat.AppendChild(new CompatibilitySetting
{
    Name = CompatSettingNameValues.OverrideTableStyleFontSizeAndJustification,
    Uri = "http://schemas.microsoft.com/office/word",
    Val = "1"
});

// EnableOpenTypeFeatures: enable advanced typography
compat.AppendChild(new CompatibilitySetting
{
    Name = CompatSettingNameValues.EnableOpenTypeFeatures,
    Uri = "http://schemas.microsoft.com/office/word",
    Val = "1"
});

// DifferentiateMultirowTableHeaders
compat.AppendChild(new CompatibilitySetting
{
    Name = CompatSettingNameValues.DifferentiateMultirowTableHeaders,
    Uri = "http://schemas.microsoft.com/office/word",
    Val = "1"
});

// UseWord2013TrackBottomHyphenation
compat.AppendChild(new CompatibilitySetting
{
    Name = CompatSettingNameValues.UseWord2013TrackBottomHyphenation,
    Uri = "http://schemas.microsoft.com/office/word",
    Val = "0"
});

settings.AppendChild(compat);
settings.Save();

// Produces XML:
// <w:compat>
//   <w:compatSetting w:name="compatibilityMode"
//     w:uri="http://schemas.microsoft.com/office/word" w:val="15" />
//   <w:compatSetting w:name="overrideTableStyleFontSizeAndJustification"
//     w:uri="http://schemas.microsoft.com/office/word" w:val="1" />
//   ...
// </w:compat>
```

### 6.3 MirrorMargins, GutterAtTop, BookFoldPrinting

```csharp
// =============================================================================
// MIRROR MARGINS, GUTTER, BOOK FOLD
// =============================================================================
// These settings are for documents intended for double-sided printing or
// book binding.

// --- Mirror Margins ---
// When enabled, Left/Right margins become Inside/Outside.
// On even pages, margins are swapped so the binding edge stays consistent.
settings.AppendChild(new MirrorMargins());
// Produces XML: <w:mirrorMargins />
// After this, PageMargin.Left = inside margin, PageMargin.Right = outside margin.
// Even pages automatically flip them.

// --- Gutter at Top ---
// By default, gutter is added to the left (or inside with MirrorMargins).
// GutterAtTop moves the gutter to the top margin instead.
// Used for calendar-style or top-bound documents.
settings.AppendChild(new GutterAtTop());
// Produces XML: <w:gutterAtTop />

// --- Book Fold Printing ---
// Enables booklet printing (2 pages per sheet, folded in half).
// Word reorders pages for saddle-stitch binding.
settings.AppendChild(new BookFoldPrinting());
// Produces XML: <w:bookFoldPrinting />

// Optional: sheets per booklet (for thick documents split into signatures)
// Default 0 = all pages in one booklet
settings.AppendChild(new BookFoldPrintingSheets { Val = 16 });
// Produces XML: <w:bookFoldPrintingSheets w:val="16" />
// 16 sheets = 64 pages per booklet signature

// --- Book Fold Reversed ---
// For right-to-left booklets (Hebrew, Arabic, Japanese right-bound)
// settings.AppendChild(new BookFoldRevPrinting());

settings.Save();
```

### 6.4 Additional Document Settings

```csharp
// =============================================================================
// ADDITIONAL DOCUMENT SETTINGS
// =============================================================================

// --- Update Fields on Open ---
// Forces Word to recalculate all fields (TOC, page numbers, etc.) on open.
settings.AppendChild(new UpdateFieldsOnOpen { Val = true });
// Produces XML: <w:updateFields w:val="true" />
// WARNING: This causes a dialog popup in some Word versions.

// --- Do Not Track Moves ---
// Prevents move tracking in track changes (shows as delete + insert instead).
// settings.AppendChild(new DoNotTrackMoves());

// --- Do Not Track Formatting ---
// Prevents formatting changes from being tracked.
// settings.AppendChild(new DoNotTrackFormatting());

// --- Default Zoom for Print Preview ---
// PrintTwoOnOne: print 2 pages per sheet
// settings.AppendChild(new PrintTwoOnOne());

// --- Document protection (read-only, forms-only, etc.) ---
// DocumentProtection can enforce read-only, allow only comments,
// restrict to form fields, etc.
// settings.AppendChild(new DocumentProtection
// {
//     Edit = DocumentProtectionValues.ReadOnly,
//     Enforcement = true
// });

// --- Even and Odd Headers (setting-level flag) ---
// Must be set here for the EvenPage header/footer references to work.
// settings.AppendChild(new EvenAndOddHeaders());

settings.Save();
```

### 6.5 Complete Settings Setup

```csharp
// =============================================================================
// COMPLETE SETTINGS SETUP — PRODUCTION-READY
// =============================================================================
// A comprehensive settings configuration suitable for most documents.

static void ConfigureDocumentSettings(WordprocessingDocument doc)
{
    var mainPart = doc.MainDocumentPart!;
    var settingsPart = mainPart.DocumentSettingsPart
        ?? mainPart.AddNewPart<DocumentSettingsPart>();
    settingsPart.Settings = new Settings();
    var s = settingsPart.Settings;

    // Zoom to 100%
    s.AppendChild(new Zoom
    {
        Percent = "100",
        Val = PresetZoomValues.None
    });

    // Default tab stop: 0.5 inch
    s.AppendChild(new DefaultTabStop { Val = 720 });

    // Mark spell/grammar as clean
    s.AppendChild(new ProofState
    {
        Spelling = ProofingStateValues.Clean,
        Grammar = ProofingStateValues.Clean
    });

    // Character spacing control
    s.AppendChild(new CharacterSpacingControl
    {
        Val = CharacterSpacingValues.DoNotCompress
    });

    // Compatibility: Word 2013+ mode with useful features
    var compat = new Compatibility();
    foreach (var (name, val) in new[]
    {
        (CompatSettingNameValues.CompatibilityMode, "15"),
        (CompatSettingNameValues.OverrideTableStyleFontSizeAndJustification, "1"),
        (CompatSettingNameValues.EnableOpenTypeFeatures, "1"),
        (CompatSettingNameValues.DifferentiateMultirowTableHeaders, "1"),
        (CompatSettingNameValues.UseWord2013TrackBottomHyphenation, "0"),
    })
    {
        compat.AppendChild(new CompatibilitySetting
        {
            Name = name,
            Uri = "http://schemas.microsoft.com/office/word",
            Val = val
        });
    }
    s.AppendChild(compat);

    s.Save();
}

// Usage:
ConfigureDocumentSettings(doc);
```

---

## Quick Reference: Unit Conversions

| Unit | Full Name | Relation |
|------|-----------|----------|
| DXA | Twentieths of a point | 1 inch = 1440 DXA; 1 cm = 567 DXA; 1 pt = 20 DXA |
| Half-point | Half a typographic point | Font size: 24 = 12pt. 1 pt = 2 half-points |
| Eighth-point | Eighth of a point | Border size: 8 = 1pt. 1 pt = 8 eighth-points |
| EMU | English Metric Unit | 1 inch = 914400 EMU; 1 cm = 360000 EMU; 1 pt = 12700 EMU |
| Pct (table width) | Fiftieths of a percent | 5000 = 100%. Multiply percentage by 50 |

## Quick Reference: Common PageSize Values

| Paper | Width (DXA) | Height (DXA) | Inches | mm |
|-------|-------------|--------------|--------|-----|
| Letter | 12240 | 15840 | 8.5 x 11 | 216 x 279 |
| A4 | 11906 | 16838 | -- | 210 x 297 |
| Legal | 12240 | 20160 | 8.5 x 14 | 216 x 356 |
| A3 | 16838 | 23811 | -- | 297 x 420 |
| B5 | 10318 | 14570 | -- | 182 x 257 |

## Quick Reference: Common Margin Presets (DXA)

| Preset | Top | Bottom | Left | Right |
|--------|-----|--------|------|-------|
| Normal | 1440 | 1440 | 1440 | 1440 |
| Narrow | 720 | 720 | 720 | 720 |
| Moderate | 1440 | 1440 | 1080 | 1080 |
| Wide | 1440 | 1440 | 2880 | 2880 |
| Chinese 公文 | 2098 | 1984 | 1588 | 1474 |


path: references/openxml_namespaces.md
content: # OpenXML Namespaces, Relationship Types, and Content Types

## Core Namespaces

| Prefix | URI | Used In |
|--------|-----|---------|
| `w` | `http://schemas.openxmlformats.org/wordprocessingml/2006/main` | document.xml, styles.xml, numbering.xml, headers, footers |
| `r` | `http://schemas.openxmlformats.org/officeDocument/2006/relationships` | Relationship references (r:id) |
| `wp` | `http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing` | Image/drawing placement in document |
| `a` | `http://schemas.openxmlformats.org/drawingml/2006/main` | DrawingML core (shapes, images, themes) |
| `pic` | `http://schemas.openxmlformats.org/drawingml/2006/picture` | Picture element in DrawingML |
| `v` | `urn:schemas-microsoft-com:vml` | VML (legacy shapes, watermarks) |
| `o` | `urn:schemas-microsoft-com:office:office` | Office VML extensions |
| `m` | `http://schemas.openxmlformats.org/officeDocument/2006/math` | Math equations (OMML) |
| `mc` | `http://schemas.openxmlformats.org/markup-compatibility/2006` | Markup compatibility (Ignorable, AlternateContent) |

## Extended Namespaces

| Prefix | URI | Purpose |
|--------|-----|---------|
| `w14` | `http://schemas.microsoft.com/office/word/2010/wordml` | Word 2010 extensions (contentPart, etc.) |
| `w15` | `http://schemas.microsoft.com/office/word/2012/wordml` | Word 2013 extensions (commentEx, etc.) |
| `w16cid` | `http://schemas.microsoft.com/office/word/2016/wordml/cid` | Comment IDs (durable IDs) |
| `w16cex` | `http://schemas.microsoft.com/office/word/2018/wordml/cex` | Comment extensible |
| `w16se` | `http://schemas.microsoft.com/office/word/2015/wordml/symex` | Symbol extensions |
| `wps` | `http://schemas.microsoft.com/office/word/2010/wordprocessingShape` | WordprocessingML shapes |
| `wpc` | `http://schemas.microsoft.com/office/word/2010/wordprocessingCanvas` | Drawing canvas |

## Relationship Types

| Relationship | Type URI |
|-------------|----------|
| Document | `http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument` |
| Styles | `http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles` |
| Numbering | `http://schemas.openxmlformats.org/officeDocument/2006/relationships/numbering` |
| Font Table | `http://schemas.openxmlformats.org/officeDocument/2006/relationships/fontTable` |
| Settings | `http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings` |
| Theme | `http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme` |
| Image | `http://schemas.openxmlformats.org/officeDocument/2006/relationships/image` |
| Hyperlink | `http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink` |
| Header | `http://schemas.openxmlformats.org/officeDocument/2006/relationships/header` |
| Footer | `http://schemas.openxmlformats.org/officeDocument/2006/relationships/footer` |
| Comments | `http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments` |
| CommentsExtended | `http://schemas.microsoft.com/office/2011/relationships/commentsExtended` |
| CommentsIds | `http://schemas.microsoft.com/office/2016/09/relationships/commentsIds` |
| CommentsExtensible | `http://schemas.microsoft.com/office/2018/08/relationships/commentsExtensible` |
| Footnotes | `http://schemas.openxmlformats.org/officeDocument/2006/relationships/footnotes` |
| Endnotes | `http://schemas.openxmlformats.org/officeDocument/2006/relationships/endnotes` |
| Glossary | `http://schemas.openxmlformats.org/officeDocument/2006/relationships/glossaryDocument` |
| Web Settings | `http://schemas.openxmlformats.org/officeDocument/2006/relationships/webSettings` |

## Content Types (`[Content_Types].xml`)

### Default Extensions

```xml
<Default Extension="rels" ContentType="application/vnd.openxmlformats-package.relationships+xml" />
<Default Extension="xml" ContentType="application/xml" />
<Default Extension="png" ContentType="image/png" />
<Default Extension="jpeg" ContentType="image/jpeg" />
<Default Extension="gif" ContentType="image/gif" />
<Default Extension="emf" ContentType="image/x-emf" />
```

### Part Overrides

| Part | Content Type |
|------|-------------|
| `/word/document.xml` | `application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml` |
| `/word/styles.xml` | `application/vnd.openxmlformats-officedocument.wordprocessingml.styles+xml` |
| `/word/numbering.xml` | `application/vnd.openxmlformats-officedocument.wordprocessingml.numbering+xml` |
| `/word/settings.xml` | `application/vnd.openxmlformats-officedocument.wordprocessingml.settings+xml` |
| `/word/fontTable.xml` | `application/vnd.openxmlformats-officedocument.wordprocessingml.fontTable+xml` |
| `/word/theme/theme1.xml` | `application/vnd.openxmlformats-officedocument.theme+xml` |
| `/word/header1.xml` | `application/vnd.openxmlformats-officedocument.wordprocessingml.header+xml` |
| `/word/footer1.xml` | `application/vnd.openxmlformats-officedocument.wordprocessingml.footer+xml` |
| `/word/comments.xml` | `application/vnd.openxmlformats-officedocument.wordprocessingml.comments+xml` |
| `/word/commentsExtended.xml` | `application/vnd.ms-word.commentsExtended+xml` |
| `/word/commentsIds.xml` | `application/vnd.ms-word.commentsIds+xml` |
| `/word/commentsExtensible.xml` | `application/vnd.ms-word.commentsExtensible+xml` |
| `/word/footnotes.xml` | `application/vnd.openxmlformats-officedocument.wordprocessingml.footnotes+xml` |
| `/word/endnotes.xml` | `application/vnd.openxmlformats-officedocument.wordprocessingml.endnotes+xml` |


path: references/openxml_units.md
content: # OpenXML Unit Conversion Quick Reference

## Master Conversion Table

| Unit | 1 inch | 1 cm | 1 mm | 1 pt | Description |
|------|--------|------|------|------|-------------|
| DXA (twips) | 1440 | 567 | 56.7 | 20 | 1/20 of a point. Used for margins, indents, spacing, page size. |
| EMU | 914400 | 360000 | 36000 | 12700 | English Metric Unit. Used for images, drawings, shapes. |
| Half-points | 144 | 56.7 | 5.67 | 2 | Used for font sizes (`w:sz`, `w:szCs`). |
| Points | 72 | 28.35 | 2.835 | 1 | Standard typographic unit. Not used directly in most attributes. |
| Eighths of a point | 576 | 226.8 | 22.68 | 8 | Used for `w:spacing` character spacing. |

## Common Page Sizes

| Size | Width (DXA) | Height (DXA) | Width (mm) | Height (mm) |
|------|-------------|--------------|------------|-------------|
| A4 | 11906 | 16838 | 210 | 297 |
| Letter | 12240 | 15840 | 215.9 | 279.4 |
| Legal | 12240 | 20160 | 215.9 | 355.6 |
| A3 | 16838 | 23811 | 297 | 420 |
| A5 | 8391 | 11906 | 148 | 210 |

## Common Margin Values

| Margin | DXA | Inches | cm |
|--------|-----|--------|----|
| 0.5 inch | 720 | 0.5 | 1.27 |
| 0.75 inch | 1080 | 0.75 | 1.91 |
| 1 inch | 1440 | 1.0 | 2.54 |
| 1.25 inch | 1800 | 1.25 | 3.18 |
| 1.5 inch | 2160 | 1.5 | 3.81 |

## Font Size Values (`w:sz`)

| Display Size | w:sz value | Notes |
|-------------|-----------|-------|
| 8pt | 16 | |
| 9pt | 18 | |
| 10pt | 20 | |
| 10.5pt | 21 | Common CJK body size |
| 11pt | 22 | Default Calibri body |
| 12pt | 24 | Default TNR body |
| 14pt | 28 | Small heading |
| 16pt | 32 | |
| 18pt | 36 | |
| 20pt | 40 | |
| 24pt | 48 | |
| 28pt | 56 | |
| 36pt | 72 | |

## Line Spacing Values

Line spacing in `w:spacing` uses the `w:line` attribute in 240ths of a line (when `w:lineRule="auto"`):

| Spacing | w:line value | w:lineRule |
|---------|-------------|-----------|
| Single | 240 | auto |
| 1.15 (Word default) | 276 | auto |
| 1.5 | 360 | auto |
| Double | 480 | auto |
| Exact 12pt | 240 | exact |
| At least 12pt | 240 | atLeast |

Note: When `lineRule="exact"` or `"atLeast"`, `w:line` is in **twips** (DXA), not 240ths. So `line="240"` with `lineRule="exact"` means exactly 12pt (240/20 = 12pt).

## Conversion Formulas

```
DXA     = inches × 1440  = cm × 567     = pt × 20
EMU     = inches × 914400 = cm × 360000 = pt × 12700
sz      = pt × 2          (half-points)
```


path: references/track_changes_guide.md
content: # Track Changes Guide

## Overview

Track Changes in OpenXML uses revision markup elements to record insertions, deletions, and formatting changes. Each revision has a unique ID, author, and timestamp.

---

## Insertion: `<w:ins>`

Wraps runs that were inserted during tracking:

```xml
<w:ins w:id="1" w:author="John Smith" w:date="2026-03-21T10:30:00Z">
  <w:r>
    <w:rPr>
      <w:rFonts w:ascii="Calibri" w:hAnsi="Calibri" />
      <w:sz w:val="22" />
    </w:rPr>
    <w:t>This text was inserted.</w:t>
  </w:r>
</w:ins>
```

- `w:id` — unique revision ID (integer, must be unique across document)
- `w:author` — free text string identifying the author
- `w:date` — ISO 8601 format with timezone: `YYYY-MM-DDTHH:MM:SSZ`
- Content inside is normal runs (`w:r`) with optional formatting

---

## Deletion: `<w:del>`

Wraps runs that were deleted during tracking:

```xml
<w:del w:id="2" w:author="John Smith" w:date="2026-03-21T10:31:00Z">
  <w:r>
    <w:rPr>
      <w:rFonts w:ascii="Calibri" w:hAnsi="Calibri" />
      <w:sz w:val="22" />
    </w:rPr>
    <w:delText xml:space="preserve">This text was deleted.</w:delText>
  </w:r>
</w:del>
```

**CRITICAL**: Inside `<w:del>`, text MUST use `<w:delText>`, NOT `<w:t>`. Using `<w:t>` inside a deletion is invalid and will cause corruption or unexpected behavior. Word may silently repair it, but other consumers will fail.

---

## Formatting Change: `<w:rPrChange>`

Records that a run's formatting was changed. Placed inside `w:rPr`, it stores the **previous** formatting:

```xml
<w:r>
  <w:rPr>
    <w:b />  <!-- Current: bold -->
    <w:rPrChange w:id="3" w:author="Jane Doe" w:date="2026-03-21T11:00:00Z">
      <w:rPr>
        <!-- Previous: not bold (empty rPr means no formatting) -->
      </w:rPr>
    </w:rPrChange>
  </w:rPr>
  <w:t>This text was made bold.</w:t>
</w:r>
```

The outer `w:rPr` holds the **new** (current) formatting. The `w:rPrChange` child holds the **old** (previous) formatting.

---

## Paragraph Property Change: `<w:pPrChange>`

Records paragraph-level formatting changes (alignment, spacing, style):

```xml
<w:pPr>
  <w:jc w:val="center" />  <!-- Current: centered -->
  <w:pPrChange w:id="4" w:author="Jane Doe" w:date="2026-03-21T11:05:00Z">
    <w:pPr>
      <w:jc w:val="left" />  <!-- Previous: left-aligned -->
    </w:pPr>
  </w:pPrChange>
</w:pPr>
```

---

## Revision ID Management

- Every revision element (`w:ins`, `w:del`, `w:rPrChange`, `w:pPrChange`, `w:tblPrChange`, etc.) requires a `w:id` attribute
- IDs must be **unique integers** across the entire document
- IDs should be **monotonically increasing** (not strictly required, but expected by Word)
- When adding revisions, scan for the current maximum `w:id` and increment from there

```
Existing max ID: 47
New insertion: w:id="48"
New deletion: w:id="49"
```

---

## Author and Date

- **Author**: Free text. Use consistent strings (e.g., `"MiniMaxAI"` for all automated edits)
- **Date**: ISO 8601 with UTC timezone marker: `2026-03-21T10:30:00Z`
  - Must include the `T` separator and `Z` suffix (or `+HH:MM` offset)
  - Omitting the date is allowed but not recommended

---

## Operations

### Propose Insertion

Add `<w:ins>` wrapper around new content at the target location:

```xml
<w:p>
  <w:r><w:t>Existing text. </w:t></w:r>
  <w:ins w:id="5" w:author="MiniMaxAI" w:date="2026-03-21T12:00:00Z">
    <w:r><w:t>Proposed new text. </w:t></w:r>
  </w:ins>
  <w:r><w:t>More existing text.</w:t></w:r>
</w:p>
```

### Propose Deletion

Wrap existing content in `<w:del>` and change `<w:t>` to `<w:delText>`:

```xml
<w:p>
  <w:r><w:t>Keep this. </w:t></w:r>
  <w:del w:id="6" w:author="MiniMaxAI" w:date="2026-03-21T12:01:00Z">
    <w:r>
      <w:rPr><w:b /></w:rPr>
      <w:delText>Remove this.</w:delText>
    </w:r>
  </w:del>
  <w:r><w:t> Keep this too.</w:t></w:r>
</w:p>
```

### Accept a Tracked Change

- **Accept insertion**: Remove the `<w:ins>` wrapper, keep the inner runs as normal content
- **Accept deletion**: Remove the entire `<w:del>` element and its content

### Reject a Tracked Change

- **Reject insertion**: Remove the entire `<w:ins>` element and its content
- **Reject deletion**: Remove the `<w:del>` wrapper, change `<w:delText>` back to `<w:t>`

---

## Cross-Paragraph Operations

### Deleting a Paragraph Break (Merging Paragraphs)

When tracked deletion spans a paragraph boundary, use `<w:pPrChange>` on the merged paragraph:

```xml
<w:p>
  <w:pPr>
    <w:pPrChange w:id="7" w:author="MiniMaxAI" w:date="2026-03-21T12:05:00Z">
      <w:pPr>
        <w:pStyle w:val="Normal" />
      </w:pPr>
    </w:pPrChange>
  </w:pPr>
  <w:r><w:t>First paragraph text. </w:t></w:r>
  <w:del w:id="8" w:author="MiniMaxAI" w:date="2026-03-21T12:05:00Z">
    <w:r><w:delText> </w:delText></w:r>
  </w:del>
  <w:r><w:t>Second paragraph text (now merged).</w:t></w:r>
</w:p>
```

### Inserting a New Paragraph

The entire new paragraph is wrapped in `<w:ins>`:

```xml
<w:p>
  <w:pPr>
    <w:rPr>
      <w:ins w:id="9" w:author="MiniMaxAI" w:date="2026-03-21T12:10:00Z" />
    </w:rPr>
  </w:pPr>
  <w:ins w:id="10" w:author="MiniMaxAI" w:date="2026-03-21T12:10:00Z">
    <w:r><w:t>Entirely new paragraph.</w:t></w:r>
  </w:ins>
</w:p>
```

The paragraph mark itself is marked as inserted via `w:ins` inside `w:pPr > w:rPr`.


path: scripts/doc_to_docx.sh
content: #!/usr/bin/env bash
set -euo pipefail

usage() {
  echo "Usage: $(basename "$0") <file.doc> [output_directory]"
  echo "Convert .doc to .docx using LibreOffice."
  exit 1
}

if [ $# -lt 1 ]; then
  usage
fi

INPUT="$1"
OUTDIR="${2:-.}"

if [ ! -f "$INPUT" ]; then
  echo "Error: File not found: $INPUT"
  exit 1
fi

if ! command -v soffice &>/dev/null; then
  echo "Error: soffice (LibreOffice) is required for .doc conversion but not found."
  echo "Install LibreOffice: brew install --cask libreoffice"
  exit 1
fi

BASENAME=$(basename "$INPUT" .doc)
mkdir -p "$OUTDIR"

echo "Converting: $INPUT -> $OUTDIR/$BASENAME.docx"
soffice --headless --convert-to docx --outdir "$OUTDIR" "$INPUT" >/dev/null 2>&1

OUTPUT="$OUTDIR/$BASENAME.docx"
if [ ! -f "$OUTPUT" ]; then
  echo "Error: Conversion failed. Output file not created: $OUTPUT"
  exit 1
fi

echo "Success: $OUTPUT"


path: scripts/docx_preview.sh
content: #!/usr/bin/env bash
set -euo pipefail

usage() {
  echo "Usage: $(basename "$0") <file.docx>"
  echo "Preview DOCX content as plain text."
  exit 1
}

if [ $# -lt 1 ]; then
  usage
fi

INPUT="$1"

if [ ! -f "$INPUT" ]; then
  echo "Error: File not found: $INPUT"
  exit 1
fi

FILE_SIZE=$(du -h "$INPUT" | cut -f1)
echo "=== DOCX Preview: $(basename "$INPUT") ==="
echo "File size: $FILE_SIZE"

if command -v pandoc &>/dev/null; then
  CONTENT=$(pandoc -f docx -t plain "$INPUT" 2>/dev/null)
  WORD_COUNT=$(echo "$CONTENT" | wc -w | tr -d ' ')
  EST_PAGES=$(( (WORD_COUNT + 249) / 250 ))
  echo "Word count: $WORD_COUNT"
  echo "Estimated pages: $EST_PAGES"
  echo "---"
  echo "$CONTENT"
else
  echo "(pandoc not available, falling back to raw XML extract)"
  echo "---"
  unzip -p "$INPUT" word/document.xml 2>/dev/null | head -100
fi


Security scan verdicts — ClawScan: suspicious | static analysis: clean | VirusTotal: clean | SkillSpector: suspicious (CRITICAL)