# 1.15.0 — per-word highlight SIZE (`--keyword-size` / `--highlight-size` / `hlSize`)

Minor release. The keyword-highlight system gains a per-word **size** dimension —
the exact sibling of the per-card *color* that already existed. Emphasized words
can now be **bigger**, not just recolored, straight from the engine. Output is
**byte-identical** whenever the new option is not used.

## The problem it solves

TikTok-style captions enlarge the punch word, they don't only tint it. Until now
that meant a post-pass script (Niche_PC's `apply_keyword_highlight.py`) rewriting
the spans the engine had just built. With size native to the highlight pipeline,
that custom script can be retired.

## Highlights

- 🔠 **`TextHighlight.size`** — optional per-span font size (points). Carried by the
  emphasis span only; base/gap spans keep the caption's base size (lean path) or
  the cloned style's size (`--clone-style` path), exactly as before.
- ⌨️ **`add-text --keyword-size <n>`** — size the highlighted word/range; combines
  freely with `--keyword` / `--keyword-range` / `--keyword-color`.
- 📦 **`import-captions --highlight-size <n>`** — global default for every `hl` card;
  the new per-card **`hlSize`** JSON field wins over the flag (same precedence as
  `color` over `--highlight-color`). `--keyword-size` is accepted as an alias
  (mirroring the `--keyword-color` alias); `--highlight-size` wins when both are given.
- 🧬 **Clone-style aware.** With `--clone-style`, the size override rides ON the
  photocopied style block: font, strokes and shadows survive next to the bigger size.
- 🛡️ **Validation everywhere a size enters.** `--keyword-size`/`--highlight-size`
  AND the per-card `hlSize` field must be a finite number > 0 — NaN, `0`, negatives,
  `Infinity` and strings die with a clear per-card message instead of corrupting
  the draft.
- 🔒 **Byte-identity locked.** Two new oracle tests freeze the size-less lean and
  clone outputs to the exact 1.14.1 byte strings; independently differential-tested
  against the published 1.14.1 npm dist (21k+ fuzzed cases, 0 divergences).
- 🧪 **478 tests** (+14). Typecheck clean; lint baseline unchanged.

## Usage

```
# one-shot caption: color AND enlarge the keyword
$ capcut-david add-text <draft> 0 2s "THE EYES ARE WATCHING ME." \
    --keyword WATCHING --keyword-color "#8C6CFF" --keyword-size 28

# batch captions: 28pt highlights everywhere, 34pt on the hero card
$ cat cards.json
[
  { "text": "le PC",    "start": 0,      "end": 500000,  "hl": [3, 5], "hlSize": 34 },
  { "text": "est mort", "start": 500000, "end": 1200000, "hl": [4, 8] }
]
$ capcut-david import-captions <draft> cards.json --highlight-size 28
```

## Compatibility

- No size option → **byte-identical** output to 1.14.1 (oracle-locked, both span paths).
- `--highlight-color` / per-card `color` keep working unchanged alongside the size.
- ⚠️ A pre-existing `hlSize` key in old card JSONs **becomes active** — it was an
  unknown, silently-ignored field in ≤ 1.14.1. Audit legacy card files before re-importing.
- ⚠️ `restyle` preserves each span's `fill` + `range` only and grafts the preset's
  `size` on top — a per-span size override does **not** survive a later `restyle`;
  re-apply sizes afterwards.
- On `import-captions`, `--keyword-size` works as an alias for `--highlight-size`
  (exactly like the `--keyword-color` → `--highlight-color` alias); the
  `--highlight-*` spelling wins when both are given.
- No schema, dependency or behavior change anywhere else; read commands untouched.
