diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md
index c6443bf..79a86d8 100644
--- a/ARCHITECTURE.md
+++ b/ARCHITECTURE.md
@@ -50,9 +50,9 @@
移除,DOM 回到 pass 前狀態(至少邏輯等價)。
- **I7 邊界感知**:跨樣式行內元素的鄰接(如 `是A`)須能識別並
正確處理——由核心 finder 統一提供,各 pass 不自行重複造輪。
-- **I8 向下相容 v1**:既有 `createCjkAutospace(options).apply(root)` 消費端
- (build.sh 單檔串接、Nvim peek、Claude 模板)**不得 break、無功能倒退**。行為
- **不要求與 v1 完全一致**,但須等價可用;以相容層達成(見 §3.5)。
+- **I8 向下相容 v1(已退役)**:相容層曾保障 v1 消費端(build.sh 單檔串接、Nvim
+ peek、Claude 模板)過渡期不 break;消費端遷移 v2 API 完成後相容層已移除(見
+ §3.5),此不變量隨之退役、編號保留不復用。
- **I9 遍歷聚合**:邏輯上「一功能一 pass」,但執行上**相容之 pass 共享單次遍歷**
(見 §3.4),以減少全樹走訪次數;聚合不得犧牲 I6(冪等可還原)與逐功能開關。
- **I10 作用域與分塊**:作用範圍可由 `scope.include` 選擇器限定(opt-in);功能集
@@ -175,27 +175,13 @@ for phase in phases:
> 只是 P1 諸 pass 的 `collect` 在同一走訪內完成。若某 pass 不相容(需獨立走訪),
> 退化為自跑一次,不影響正確性。
-### 3.5 v1 向下相容層(I8,`src/compat/v1.ts`)
+### 3.5 v1 向下相容層 — 已移除(I8 退役)
-導出 `createCjkAutospace(options)`,把 v1 API 映射到 `createJuzhen`,**保證不
-break、無功能倒退**,行為等價但不要求完全一致:
-
-| v1 選項/行為 | 映射 |
-|---|---|
-| `.apply(root)` | → `.render(root)` |
-| `pillSelector` | → pill 鄰接處理 + avoid |
-| `styleInlines`/`blockTags`/`skipTags` | → finder 設定 |
-| `autospaceClass`(預設 `cjk-autospace`) | → 套用於 `jz-hws` 之 class,使既有
- `.cjk-autospace{…}` CSS 仍命中間隙元素 |
-| `skipAttribute`/`isSkipped` | → avoid 判定 |
-| `longWordWrap` | → `longWord` |
-| `punctuationSqueeze`(v1 halt 句內半角) | → `jiya`(margin 開明/全角;行為近似,
- 非逐位等同——符合「不要求完全一致」) |
-
-IIFE 構建額外掛 `globalThis.createCjkAutospace` 別名,使
-`globalThis.createCjkAutospace` 之消費端(Nvim peek/模板)零改動可跑。相容層之
-差異(間隙元素由 `span.cjk-autospace` 變為 `jz-hws[class]`、擠壓由 halt 變 margin)
-於 README 明列。
+相容層(`src/compat/v1.ts`:`createCjkAutospace` 導出、IIFE 之全域別名、
+`autospaceClass` 選項)曾把 v1 API 映射到 `createJuzhen`,服務 build.sh 單檔串接/
+Nvim peek/Claude 模板等 v1 消費端之過渡期。**最後一批 v1 消費端遷移 v2 API 完成後
+已整體移除**(`autospaceClass` 經查從未被任何 pass 讀取,屬死選項,一併刪)。v1
+原始碼保存於 `v1-autospace` 分支。
### 3.6 作用域與分塊功能選擇(I10)
@@ -248,9 +234,31 @@ IIFE 構建額外掛 `globalThis.createCjkAutospace` 別名,使
設計要點:finder 不知道任何具體排版規則;它只提供「在何處、跨何種邊界、對哪些
字元」的遍歷與安全變更原語。規則由各 pass 以 unicode 表 + 回呼注入。
+**行內元素三分類(下游問題六後確立)**:行內元素對排版有且僅有三種口徑,所有遍歷
+原語(`collectRuns`/`adjacentLogicalChar`/`eachTextNode`、`jiyaAdjacency` 之相鄰
+掃描、`core/split` 之可切判定、orphan 之實義字收集)共用同一判定:
+
+- **透明**(`styleInlines` + wrap 類 `jz-*`)——穿越、run 延續、禁則可克隆切分。
+- **隔離**(`isolateSelector`,預設 `mark`)——邊界斷 run/斷相鄰/不可切分、兩端
+ 補隙(同 pill),**內部照常處理**(自成脈絡)。典型:帶背景色之 ``(切分
+ 背景盒有可見接縫,故亦自 `SPLITTABLE` 白名單移除)。
+- **整體**(`pillSelector`)——原子單位:內部對一切 pass **不可見**(`eachTextNode`
+ 過濾 `insidePill`,不 charify/不插間隙/不切分/不下潛),禁則時作為原子鄰字
+ 單位**整體綁入** `jz-jinze`。典型:`code`/`kbd`、行內公式 `.katex`。
+
+判定**以元素為準、非標籤名**(`transparentInline(el)`,先排除 pill/isolate/
+avoid 再查標籤集):KaTeX 全樹皆 ``,舊版按標籤名判透明曾令 `canSplit`/
+`descend` 整棵下潛——禁則把公式內側末字連同完整殼層逐層克隆切出(`splitoff`),
+上標漂移錯位(下游問題六);`pillSelector`/`skipAttribute`/`scope.avoid` 三層
+防護全被刺穿。同根修復:**avoid 以自身判定**(`avoidsSelf(el)`——`isAvoided` 僅查
+祖先鏈,元素自身命中 avoid 時曾被穿越);`adjacentLogicalChar` 之 `descend` 改三態
+(邊界字/無內容續找兄弟/**blocked** 終止——遇 pill/isolate/avoid 不可跳過續找
+更遠之字,否則重蹈「越過 `jz-char` 取更前字 → 誤隙」之同型錯誤);`core/split` 之
+`canSplit` 諮詢 finder(pill/isolate/avoid 一律不可切、退化整綁)。
+
**「行內透明」原則之一致性(下游 Bug 修復)**:「邏輯文本應透明穿越之行內元素」一語
須在所有遍歷原語中**口徑一致**,否則同一段文本在不同原語下被切成不同邏輯串、生成相
-互矛盾之結果。`isTransparentInline` 為單一真相源,列入:樣式行內標籤、`jz-hws`/
+互矛盾之結果。`transparentInline` 為單一真相源,列入:樣式行內標籤、`jz-hws`/
`jz-jinze`(wrap 群組)、**`jz-char`/`jz-inner`(標點原子)**。後者必須透明,否則
`adjacentLogicalChar` 之 `descend` 遇標點原子既不進入亦不終止、而是**跳過**它續找更前
之兄弟——`漢字。` 經禁則綁定後,pill 之左鄰字應為「。」(標點,非 pill 鄰字、不
@@ -360,11 +368,13 @@ class 約定:`bd`(標點)、`bd-open/close/cop/stop/sep/liga`、`cjk`、`j
- **copy-clean(I1,較 Han 更純)**:間隙為純視覺 margin,`textContent` 不增不減
語義字元,剪貼板得緊湊原文。
- **切片**:涵蓋 v1 Pass A、Pass B(pill `code/kbd` 邊界亦走同一機制——左字或
- pill 元素包入 `jz-hws`;pill 由 avoid 與鄰接判定處理)。
+ pill 元素包入 `jz-hws`;pill 由 avoid 與鄰接判定處理)。Pass B 之邊界選擇器為
+ **pill ∪ isolate**(§4.1 三分類:隔離元素兩端補隙口徑與 pill 一致,差異僅在
+ 內部處理;巢於 pill 內者跳過)。
- **邊界正規化一致性(下游回饋 1a/1b 修)**:
- **1a pill 穿越 jz-jinze**:jinze(order 40)先於 spacing(order 50),會把尾隨
標點之 pill 納入 `jz-jinze`。`adjacentLogicalChar` 須**透明穿越 `jz-jinze`**
- (與 `jz-hws`、樣式行內同列,見 `finder.isTransparentInline`),否則 pill 左鄰字
+ (與 `jz-hws`、樣式行內同列,見 `finder.transparentInline`),否則 pill 左鄰字
不可達、左緣間隙與作者空格剝除雙失。
- **1b CJK↔CJK 贅餘空格**:中文不用詞間空格,故 CJK 表意字之間的單一 ASCII 作者
空格(含跨樣式行內標籤,`collectRuns` 已透明合併)一律**剝除、不留隙**(以
@@ -458,7 +468,8 @@ class 約定:`bd`(標點)、`bd-open/close/cop/stop/sep/liga`、`cjk`、`j
(pause 右空白 + open 左空白)兩側皆收 → 全角式與開明式皆合占 1em;`。」`(stop 右空白;
」左為墨)只收 `。`→ 全角式 1.5em/開明式 1em(」baseline 已半);`·—`(皆無指向對方之
空白)皆不收 → 兩式皆 2em(不宜挤之例外)。多標點鏈逐對處理。`jiyaAdjacencyPass` 以**從 root 之透明遍歷**(穿越 strong/
- em… 等樣式行內;block 邊界與 avoid 子樹斷相鄰;jz-char 為原子不下探)取代原「同 parent
+ em… 等樣式行內;block/pill/avoid(自身判定)斷相鄰且不下探,isolate 斷相鄰但內部
+ 自成脈絡照常配對——§4.1 三分類;jz-char 為原子不下探)取代原「同 parent
直接兄弟」掃描,使**跨 inline 邊界**之連續標點亦正確配對(原漏致跨 strong/em 之標點對未挤、
達 2em)。
- **`margin` 後備模式(.feedback 增補)**:消費端字型未必含 `halt`(多數系統字型、
@@ -497,7 +508,11 @@ class 約定:`bd`(標點)、`bd-open/close/cop/stop/sep/liga`、`cjk`、`j
把邊界詞元剝入一個淺克隆(保留標籤/class/style/lang,去 id),只綁該克隆(最小綁定),
原元素其餘部分留原位、渲染視覺無縫。克隆標 `data-jz-kind="splitoff"`,`revertPass` 之**延後
階段**(先解包 wrap、後併 splitoff,確保前兄弟為原元素而非 wrap 殼)併回原元素、還原一致
- (I6)。僅純樣式標籤白名單可切;`a`/`abbr`/`ruby`/帶 id 者退化為整元素綁定(安全)。
+ (I6)。僅純樣式標籤白名單可切,且 `canSplit` **諮詢 finder 三分類**(§4.1):`a`/`abbr`/
+ `ruby`/帶 id 者,以及 **pill(整體)/isolate(隔離)/avoid 自身命中者**,一律退化為
+ 整元素綁定(安全)——pill 即「作為原子鄰字單位整體綁入 `jz-jinze`」之期望行為(下游問題六:
+ KaTeX 全樹皆 SPAN,舊版僅憑標籤白名單曾整棵下潛肢解公式);isolate(如背景色 `mark`)切分
+ 有可見接縫故整綁;`MARK` 並自白名單移除。
- **切片**:切片 1 完成行首行末避頭尾(閉類/點號避頭、開類避尾);行首縮排聯動、
更細之禁則對象列後續,沿用同一 `jz-jinze` 結構。
- **已知交互(待瀏覽器精修)**:`lineedge` 之行端偵測需跨 `jz-jinze` 群組邊界向上
diff --git a/README.md b/README.md
index 5bfff1d..687f14e 100644
--- a/README.md
+++ b/README.md
@@ -8,8 +8,8 @@
倉庫名仍為 `cjk-autospace`;公開 API 為 `createJuzhen` / 全域 `Juzhen`;注入之
自訂元素前綴 `jz-`。完整設計見 [`ARCHITECTURE.md`](./ARCHITECTURE.md)。
-> 本版(2.x)為從零重寫。v1 之 `createCjkAutospace` API 由相容層保留(見下),
-> 既有消費端不需改碼即可運行;v1 原始碼保存於 `v1-autospace` 分支。
+> 本版(2.x)為從零重寫。v1 之 `createCjkAutospace` 相容層**已移除**(最後一批
+> v1 消費端已遷移 v2 API);v1 原始碼保存於 `v1-autospace` 分支。
---
@@ -65,12 +65,12 @@ jz.render(document.querySelector("main"));
| 功能 | 說明 |
|---|---|
-| **中西間隙** `spacing` | CJK↔西文邊界插入 copy-clean 之 `jz-hws`(`user-select:none`,剪貼板跳過)。「西文」涵蓋拉丁(含擴充 A/B,拼音聲調 `ā ǎ ē`)、希臘、西里爾、數字、貨幣(`€ ₩ ₿`)、數學運算符等;CJK 標點(`。,「」()……` 等)不誤判為西文、不生隙。含跨樣式行內邊界與 `code`/`kbd` pill 邊界(pill 緊鄰標點時穿越 `jz-jinze` 仍補間隙;pill 跨行右隙、間隙落行末之自我應驗皆已修)。**pill 之邏輯鄰字為標點時(如 `漢字。`)不誤加間隙**(標點非 pill 鄰字;`jz-char`/`jz-inner` 透明穿越,與 `collectRuns` 一致)。贅餘作者空格一律正規化:CJK↔西文吸收為受管間隙、CJK↔CJK(含跨 inline 標籤)剝除不留隙。 |
+| **中西間隙** `spacing` | CJK↔西文邊界插入 copy-clean 之 `jz-hws`(`user-select:none`,剪貼板跳過)。「西文」涵蓋拉丁(含擴充 A/B,拼音聲調 `ā ǎ ē`)、希臘、西里爾、數字、貨幣(`€ ₩ ₿`)、數學運算符等;CJK 標點(`。,「」()……` 等)不誤判為西文、不生隙。含跨樣式行內邊界與 pill/隔離元素邊界(`code`/`kbd`/`.katex` 與 `mark`,兩端補隙口徑一致;pill 緊鄰標點時穿越 `jz-jinze` 仍補間隙;pill 跨行右隙、間隙落行末之自我應驗皆已修)。**pill 之邏輯鄰字為標點時(如 `漢字。`)不誤加間隙**(標點非 pill 鄰字;`jz-char`/`jz-inner` 透明穿越,與 `collectRuns` 一致)。贅餘作者空格一律正規化:CJK↔西文吸收為受管間隙、CJK↔CJK(含跨 inline 標籤)剝除不留隙。 |
| **長英文詞** `longWord` | `[A-Za-z]{6,}` 包入 ``,配合 CSS `hyphens:auto` 原生斷詞(DOM 無連字符 → 複製不污染)。 |
| **標點擠壓** `jiya` | 標點 charify 為 `jz-char`+`bd-*` class。三機制:①baseline 政策(全角式不擠/開明式擠句內點號+括號引號/半角式全擠);②行內連續擠壓(相鄰標點**雙側獨立**收——各標點若其有空白之側緊鄰另一標點即收半,故 `,「` 全角式與開明式皆 1em、`。」` 全角式 1.5em/開明式 1em;透明穿越 `strong`/`em` 等行內邊界);③行端擠壓(`lineedge` layout pass)。半形預設以字型 `halt` 渲染(按字形正確定位,居中字形如 `!?`/繁體 `。,` 不重疊;不依賴 `text-spacing-trim`)。**字型缺 `halt` 時可切 `margin` 後備模式**(見下節)。 |
-| **禁則** `jinze` | 行首行末避頭尾:閉類/點號綁前一字(不置行首)、開類綁後一字(不置行末),只隔離邊界字故長引文中段仍可斷。亦為 `justify` 綁定載體。邊界字落於行內樣式元素(`strong`/`em`/`span` 等)內時**克隆切分**只綁邊界詞元(避免整個元素入 `nowrap` 致行末整體掉行、上行留巨大空隙),切出之克隆標 `data-jz-kind="splitoff"`、`revert` 時自動併回原元素;不可切元素(`a`/`abbr`/`ruby`/帶 `id`)退化為整元素綁定。 |
+| **禁則** `jinze` | 行首行末避頭尾:閉類/點號綁前一字(不置行首)、開類綁後一字(不置行末),只隔離邊界字故長引文中段仍可斷。亦為 `justify` 綁定載體。邊界字落於**透明**行內樣式元素(`strong`/`em` 等)內時**克隆切分**只綁邊界詞元(避免整個元素入 `nowrap` 致行末整體掉行、上行留巨大空隙),切出之克隆標 `data-jz-kind="splitoff"`、`revert` 時自動併回原元素;不可切元素(`a`/`abbr`/`ruby`/帶 `id`,以及 **pill/隔離/avoid**——見「行內元素三分類」)退化為**整元素綁定**——pill(如行內公式 `.katex`)即作為原子鄰字單位整體綁入 `jz-jinze`,絕不下潛肢解其內部。 |
| **垂懸字避免** `orphan` | 段末行 CJK 實義字 ≥ N(預設 2;標點/符號不計)。方案 C(斷行層、無測量):把段末「第 N 個實義字起至段末」包入 `jz-orphan`(`white-space:nowrap`),整體不可斷 → 末行恒含之 ⇒ 末行實義字 ≥ N,任意寬度/字型成立。單行段無害。邊界字落於行內元素內時同樣**克隆切分**(只綁末 N 字、避免整個長元素入 `nowrap` 溢出容器;機制同禁則)。**預設開**(`orphan:false` 關,`{chars:n}` 調)。段落級功能。 |
-| ~~**標點懸掛** `hanging`~~ | **已評估停用**(§6.5.6):純負 margin 機制不可行(墨色不出版心/滿凸拉升後字重疊/resize 重排錯亂),原生 `hanging-punctuation` 為正解但 Chrome 不支援。`hanging` 選項仍被接受但**無任何效果**;程式碼休眠待原生支援成熟。 |
+| ~~**標點懸掛** `hanging`~~ | **已移除**(§6.5.6):純負 margin 機制為機制級死路(寬度守恆矛盾,CSS 接觸不到斷行器),原生 `hanging-punctuation` 為唯一正解但僅 Safari 支援、且與本庫 inline-block 原子互斥。`hanging` 選項仍被接受(API 相容)但**無任何效果**;相關程式碼/CSS 已全數刪除,原生路徑屬遠期「原生管線」新功能。 |
| **功能分級** `level` | 功能分文本級(中西間隙、標點擠壓——任意文本片段適用)與段落級(禁則、垂懸字、懸掛、長詞——需行/段布局)。塊級元素預設全功能;`data-jz-level="text"` 子樹或選項 `level:{text:"選擇器"}`(如標題/按鈕)僅跑文本級。 |
| **justify 單份間距** | 每個 `jz-char` 為 `inline-block` 原子項,句末標點只貢獻一份對齊伸縮量。 |
@@ -96,8 +96,10 @@ createJuzhen({
jiya: true, // 或物件:{ halfWidth: "halt" | "margin", bias }
jinze: true,
orphan: true, // 垂懸字避免(預設開);或 { chars: 2 };false 關
- // hanging:已停用、無效果(見「標點懸掛」一節)
+ // hanging:已移除、無效果(見「標點懸掛」一節)
level: { text: "h1,h2,h3,button,.ui" }, // 此選擇器子樹僅跑文本級功能(見下)
+ pillSelector: "code, kbd, .katex", // 整體(pill)元素(見「行內元素三分類」)
+ isolateSelector: "mark", // 內外隔離元素(預設 mark;"" 停用)
justifyAtoms: true, // jz-char/jz-jinze 以 inline-block 作對齊原子;
// 分頁器(Paged.js)下設 false 改 inline(見下)
blocks: [ // 分塊功能選擇
@@ -106,6 +108,28 @@ createJuzhen({
});
```
+### 行內元素三分類:透明/隔離/整體
+
+行內元素對排版有且僅有三種口徑,**所有遍歷原語共用同一判定**(中西間隙、擠壓相鄰、
+禁則綁定、垂懸字、克隆切分皆一致):
+
+| 分類 | 選擇器 | 邊界 | 內部 | 典型 |
+|---|---|---|---|---|
+| **透明** | `styleInlines`(預設常見樣式標籤) | 穿越——間隙/相鄰/run 皆延續 | 照常處理;禁則可**克隆切分**(最小綁定) | `strong`/`em`/`b`/`i`/`a`/`span` |
+| **隔離** | `isolateSelector`(預設 `"mark"`) | 斷 run/斷相鄰/不可切分;**兩端**與 CJK/西文相鄰時補 `jz-hws` 間隙 | **照常處理**(自成脈絡:內部標點照擠、內部中西照補隙) | 帶背景色之 ``、badge 類盒樣式行內 |
+| **整體** | `pillSelector`(預設 `"code, kbd"`) | 同隔離(邊界斷、兩端補隙) | **完全不可見**——不 charify、不插間隙、不切分、不下潛 | `code`/`kbd`、行內公式 `.katex`、引用標 `.cite-ref` |
+
+要點:
+
+- **判定以元素為準、非標籤名**:KaTeX 全樹皆 ``,但 `.katex` 命中 `pillSelector`
+ 即為整體邊界——舊版按標籤名判透明曾整棵下潛、把公式內側末字連同殼層克隆切出(肢解)。
+- **禁則之整體綁定**:pill 緊鄰禁則標點時(`…$公式$,`),整個 pill 作為原子鄰字單位
+ 綁入 `jz-jinze`(公式本不可斷,無額外代價);隔離元素同樣整綁(切分背景盒有可見接縫)。
+- **`scope.avoid`/`skipAttribute`/`data-jz-skip` 以自身判定**:命中元素自身即邊界、
+ 內外皆不處理(舊版僅查祖先,元素自身命中時仍被穿越)。
+- **行內公式/夾注引用宜列為 pill**:`pillSelector: "code, kbd, .katex, .cite-ref"`——
+ 獨立行內單位以 pill 邊界邏輯統一處理(兩側補隙、吸收作者空格、整體綁定)。
+
### 分頁器(Paged.js 等)相容:`justifyAtoms`
預設 `jz-char`/`jz-jinze` 為 `inline-block`,作 `justify` 之單一對齊原子(句末標點
@@ -351,21 +375,12 @@ createJuzhen({
---
-## v1 向下相容
+## v1 向下相容 — 已移除
-```js
-// 既有消費端零改動:
-const cjk = createCjkAutospace({ pillSelector: "code, kbd" });
-cjk.apply(document.body);
-```
-
-IIFE 構建另掛 `globalThis.createCjkAutospace` 別名。**與 v1 之差異**(行為等價、
-不要求逐位一致):
-
-- 間隙標記由 `` 變為 ``
- (仍帶原 class,既有 `.cjk-autospace{user-select:none}` CSS 仍命中)。
-- 標點擠壓改由 `juzhen.css` 託管(須引入),預設仍以字型 `halt` 渲染半形——與 v1
- 消費端 `font-feature-settings:"halt"` 同機制;缺 `halt` 之字型可切 `margin` 後備。
+v1 相容層(`createCjkAutospace` 導出、IIFE 之 `globalThis.createCjkAutospace`
+別名、`autospaceClass` 選項)**已隨最後一批 v1 消費端遷移完成而移除**。既有消費端
+請改用 `createJuzhen(options).render(root)` v2 API;v1 原始碼保存於 `v1-autospace`
+分支。
---
diff --git a/build.mjs b/build.mjs
index f366042..8515813 100644
--- a/build.mjs
+++ b/build.mjs
@@ -2,8 +2,7 @@
// 另行產出(見 package.json scripts)。
//
// dist/juzhen.mjs ESM,供打包器/TypeScript/jsdom 測試。
-// dist/juzhen.iife.js IIFE,全域 `Juzhen`,原生