# Pagination — Figma alignment fix spec (X.4.2 batch)

## Inputs (✓ all read)

- figma cache: `figma-data/normalized/figma-mcp-cache/pagination.tsx` (249 lines, 3 type variants × ~5–7 sub-frames each)
- canonical: `src/components/Pagination/Pagination.vue` (326 lines, ~140 CSS lines)
- figma styles: `figma-data/normalized/figma-styles.json` (Text/Effect Style + scale tokens)
- aliases: `token-aliases.ts`, `prop-aliases.md`, `icon-aliases.ts`
- variables: `src/tokens/variables.css`

Variant axes (from figma `PaginationProps`):

- `type` axis: `"Classic" | "Simple" | "Small"`
- `showPageSize` boolean (canonical alias `showPageSizeSelector`)
- `showTotal` boolean (identity)

## Mismatches by dimension

### Spacing mismatches

- Figma root `Classic` outer container uses `gap-[var(--spacing/l,24px)]` = `var(--sp-l)`; canonical `.pagination` uses raw `gap: 24px` → **Fix:** `gap: var(--sp-l)`.
- Figma `Classic` page-button group (`node 4907:6724`) uses `gap-[8px]` = `var(--sp-xs)`; canonical `.pg-main` uses raw `gap: 24px` (also wrong — figma 是 24px on outer, 8px between page buttons). Canonical conflates outer + inner → **Fix:** introduce a dedicated inner page-list container with `gap: var(--sp-xs)`, keep outer at `var(--sp-l)`.
- Figma `Small` page-button group (`node 4907:6742`) uses `gap-[var(--spacing/xxs,4px)]` = `var(--sp-xxs)`; canonical small variant has no override (inherits `gap: 24px`) → **Fix:** add `.pagination--small .pg-page-list { gap: var(--sp-xxs); }`.
- Figma `Simple` `Btn/Previous + Btn/Next` container (`node 4907:6731`) uses `flex justify-between` with fixed `w-[80px]` (no gap — distance is via `justify-between` on a width-locked frame); canonical small/simple share `.pg-main` with `gap: 16px` (override) which breaks the figma layout → **Fix:** new `.pagination--simple .pg-arrow-pair` container with `width: var(--pagination-simple-nav-width); justify-content: space-between` (see new domain token).
- Figma `Btn/Previous` / `Btn/Next` size = `size-[32px]` (`32px × 32px`); canonical `.pg-btn` uses `min-width: 32px; height: 32px` ✓ acceptable but page-buttons need `width: 32px` not `min-width` (figma is fixed not min) → **Fix:** classic / simple variants → `width: 32px` for arrows + page buttons; small variant → `width: 32px` (figma keeps 32px even in flat).
- Figma page button paddingless (icon centred via flex); canonical `.pg-btn` uses `padding: 0 8px` → harmless for digit buttons (still 32px) but not figma-faithful → **Fix:** drop horizontal padding, rely on `width: 32px`.
- Figma page-size `select box/filled` `data-name` (`node 4884:7205`) uses `gap-[8px] px-[12px] py-[8px] h-[32px] w-[120px] rounded-[4px]` = `var(--sp-xs)` / `var(--sp-s)` / `var(--sp-xs)` / `var(--r-s)`; canonical delegates to `<Select size="m">` and pins width via `:deep(.select-wrap) { width: 120px; }` → **Fix:** replace raw `120px` with `var(--pagination-pagesize-selector-width)` (new domain token, value 120px).
- Figma jumper `input box/filled` `node 4907:6727` `h-[32px] w-[64px] px-[12px] py-[8px] rounded-[4px]`; canonical uses `:deep(.tvu-input) { width: 64px; }` → **Fix:** replace with `var(--pagination-jumper-input-width)` (new domain token, 64px).
- Figma `Go to` label segment `node 4907:6725` `gap-[var(--spacing/xs,8px)]` = `var(--sp-xs)`; canonical `.pg-jumper { gap: 8px }` → **Fix:** `gap: var(--sp-xs)`.

### Color mismatches

- Figma active page `Page/1` bg = `var(--ux/brand/brand,#2fb54e)` = `--brand`; canonical `.pg-btn--active { background: var(--brand) }` ✓.
- Figma inactive page `Page/2..5` bg = `var(--color-type/background/layer_4,#353535)` = `--bg-layer4`; canonical `.pg-btn` background = `transparent` → **Fix (Classic only):** `.pagination--classic .pg-btn { background: var(--bg-layer4); border-color: transparent; }` — figma 真源 page buttons in Classic 都有 layer4 底色，不是透明。
- Figma `Btn/Previous` / `Btn/Next` bg = `var(--color-type/background/layer_4,#353535)` = `--bg-layer4` (Classic + Simple); canonical `.pg-arrow` 仅 Simple variant override `background: var(--bg-layer4)` → **Fix:** Classic variant arrow 也应为 `--bg-layer4`，不应只 Simple — current `.pg-arrow { border-color: var(--line-deep); color: var(--text-tips); }` 缺背景色对 Classic.
- Figma inactive page text = `var(--color-type/text/text_2,#ccc)` = `--text-2`; canonical `.pg-btn { color: var(--text-2) }` ✓.
- Figma active page text = `var(--color-type/text/heading-&-button,white)` = `--text-heading`; canonical `.pg-btn--active { color: var(--text-primary-btn) }` → primary-btn 在 dark 也是 `#ffffff` 等价 — but **figma alias is `--text-heading`**, semantic mismatch. → **Fix:** swap to `var(--text-heading)` to match figma alias.
- Figma `Small` active page text uses `var(--ux/brand/brand,#2fb54e)` = `--brand`; canonical `.pg-btn--text-active { color: var(--brand) }` ✓.
- Figma `Small` inactive page text = `var(--color-type/text/text_2,#ccc)` = `--text-2`; canonical inherits ✓.
- Figma `Small` `select box/line` border = `var(--ux/grey/grey-8-#595959,#595959)` = `--color-grey-8` → maps to `--line-border` (which is grey-8 in dark). For canonical Select consumer this is encapsulated in `<Select variant="line">`, so no canonical CSS change needed — but documentation: ensure `<Select variant="line">` uses `--line-border` not raw value (cross-component, out of scope here, log only).
- Figma `Go to` label text = `var(--color-type/text/tips,#9e9e9e)` = `--text-tips`; canonical `.pg-extra__label { color: var(--text-tips) }` ✓.
- Figma `pg-total` text = `var(--color-type/text/tips,#9e9e9e)` = `--text-tips`; canonical `.pg-total { color: var(--text-tips) }` ✓.
- Figma jumper `input box/filled` bg = `var(--color-type/line/deep-divider,#353535)` = `--line-deep` (figma 真源 用 line-deep 作为 input filled bg) → canonical 通过 `<Input variant="filled">` 处理；within Pagination canonical no extra CSS, OK.

### Typography mismatches (use `--text-style-*` composite tokens or atomic)

- Figma all text uses `Roboto/14 body` (size 14, line-height 1.5 ≈ 21px, weight 400) — maps to `--text-style-body`.
- Canonical `.pg-total`, `.pg-btn`, `.pg-ellipsis`, `.pg-extra__label` all hardcode `font-size: 14px` (+ partial `line-height: 21px`) → **Fix:** replace with `font: var(--text-style-body)` shorthand on each rule, drop hardcoded `font-size` / `line-height`. (Use atomic `--font-size-body` / `--line-height-body` if shorthand collides with other declarations.)
- Canonical `.pg-btn--active { font-weight: 600 }` — **figma 真源 active state 用 weight 400** (`Roboto Regular`), not 600. → **Fix:** drop `font-weight: 600` on `.pg-btn--active` (use default `--font-weight-regular` 400).

### Effect mismatches (use `--shadow-l*` / `--mask-overlay`)

- Figma Pagination 真源 **没有 shadow / overlay**（pagination 是 inline content 不是 floating surface）。
- Canonical also has no box-shadow ✓.
- No mismatch.

### Composition mismatches (canonical import vs figma data-name)

- Figma `data-name="select box/filled"` (Classic + Simple page-size) and `select box/line` (Small page-size) → maps via `prop-aliases.md` Sub-component Composition Aliases 表 A to `<Select variant="filled">` / `<Select variant="line">`. Canonical uses `<Select :variant="pageControlVariant">` where `pageControlVariant = isClassic ? 'filled' : 'line'`. **Issue:** figma Classic AND Simple both use `select box/filled` — but Simple type doesn't render the page-size selector at all per figma cache (line 23: `["Classic", "Simple"].includes(type) && showPageSize` — actually figma supports page-size for both Classic + Simple)... however figma Simple variant cache (line 183+) does NOT show page-size segment. Re-checking: line 23 condition includes Simple, but the Simple variant block (line 183) does not branch into a page-size sub-tree. Conclusion: page-size selector is rendered ONLY when `["Classic","Simple"].includes(type) && showPageSize` AND we observe the visual only in Classic variant cache → effectively `Classic + showPageSize=true` and `Small + showPageSize=true` (line 104). **Simple has no page-size visually** (figma 真源 Simple 没 page-size box). → **Fix:** canonical should gate `pg-pagesize` to `(isClassic || isSmall) && resolvedShowPageSizeSelector` — drop Simple. Update `pageControlVariant` to be `isSmall ? 'line' : 'filled'` (Classic = filled, Small = line, no Simple branch).
- Figma `data-name="input box/filled"` (Classic + Simple jumper) and `input box/line` (Small jumper) → `<Input variant="filled">` / `<Input variant="line">`. Canonical uses `<Input :variant="pageControlVariant">` ✓ for jumper, but `pageControlVariant` is shared with page-size selector — for Small jumper variant should be `line` and page-size also `line` (consistent). **Verify:** With fixed `pageControlVariant = isSmall ? 'line' : 'filled'`, both Classic jumper = filled, Small jumper = line, Simple jumper = filled → all match figma ✓.
- Figma `data-name="icon/Arrow/Previous"` / `icon/Arrow/Next` → `<Icon name="previous">` / `<Icon name="next">` per icon-aliases.ts. Canonical uses `<Icon name="previous">` / `<Icon name="next">` ✓.
- Figma `data-name="Btn/Previous"` / `Btn/Next` / `Page/<N>` → BRIDGE-Tier3 deferred: should be `<Button>` once Tier3 mega ready (per prop-aliases.md 表 C). Canonical uses native `<button>` ✓ acceptable as documented blocker.

### Variant coverage gaps (per axis value)

- `type=Classic`: canonical via `isClassic` computed + `.pagination--classic` modifier (currently inferred via class `pagination--${type.toLowerCase()}`). **Coverage:** ✓ rendered, but missing dedicated CSS rules that distinguish Classic from default — bg/border on page buttons is shared. Add `.pagination--classic .pg-btn { background: var(--bg-layer4); border-color: transparent; }`.
- `type=Simple`: canonical via `.pagination--simple` modifier — ✓ exists, but `.pagination--simple .pg-main { gap: 16px }` is wrong (figma outer gap is `var(--sp-l)` = 24px between previous/next pair and Go-to segment; the 80px inner is figma `w-[80px]`). → **Fix:** drop `gap: 16px` override; use Simple-specific `.pg-arrow-pair { width: var(--pagination-simple-nav-width); justify-content: space-between; gap: 0; }`.
- `type=Small`: canonical via `.pg-btn--flat` + `.pagination--small` — ✓ rendered. **Coverage:** OK, but need to ensure `--sp-xxs` gap on the page-button row (added above), and active page text uses `--brand` (already correct via `.pg-btn--text-active`).
- `showTotal=true|false`: ✓ canonical `v-if="resolvedShowTotal"`.
- `showPageSize=true|false` (canonical `showPageSizeSelector`): ✓ canonical `v-if="resolvedShowPageSizeSelector"`, but condition needs gating to non-Simple (see above).
- `showJumper`: figma 默认 always show in Classic / Simple / Small — canonical adds `showJumper` runtime bool (per prop-aliases.md "runtime addition"). ✓ documented, no fix.

## Token usage summary

### Existing canonical tokens used

- Spacing: `--sp-xxs`, `--sp-xs`, `--sp-s`, `--sp-l`
- Color: `--brand`, `--bg-layer4`, `--text-2`, `--text-heading`, `--text-tips`, `--line-deep`, `--line-border`
- Radius: `--r-s`
- Typography: `--text-style-body`, `--font-size-body`, `--line-height-body`, `--font-weight-regular`

### New domain tokens proposed

| Token | Value | Rationale |
| --- | --- | --- |
| `--pagination-pagesize-selector-width` | `120px` | figma 真源 select box width 固定 120px (Classic + Small)；scale tokens 无 120px 等价 |
| `--pagination-jumper-input-width` | `64px` | figma 真源 input box width 固定 64px；scale tokens 无 64px 等价 |
| `--pagination-simple-nav-width` | `80px` | figma 真源 Simple variant `Btn/Previous + Btn/Next` flex container `w-[80px]` |

> 这三个域 token 应加到 `src/tokens/variables.css` "Derived aliases for component compatibility" 段。

### BRIDGE-Tier3 deferred items

- `<button class="pg-btn">` / `<button class="pg-arrow">` → should become `<Button>` once BRIDGE-Tier3 mega-button matrix is ready (figma `Btn/Previous`, `Btn/Next`, `Page/<N>` data-names). Currently log via prop-aliases.md 表 C. **No fix this batch.**

## Refactor scope

### Template changes

- Wrap page-button row in dedicated `<div class="pg-page-list">` (between arrow buttons) so page-list can have its own `gap: var(--sp-xs)` (Classic) / `var(--sp-xxs)` (Small) without affecting outer `.pg-main` gap.
- Wrap Simple variant arrow pair in `<div class="pg-arrow-pair">` with the new width token + `space-between`.
- Tighten `v-if` on `pg-pagesize`: `(isClassic || isSmall) && resolvedShowPageSizeSelector`.
- Update `pageControlVariant` computed: `isSmall ? 'line' : 'filled'`.

### CSS changes

- Replace raw px gaps/font/colors with token references (per dimensions above).
- Add Classic-specific rules: `.pagination--classic .pg-btn { background: var(--bg-layer4); border-color: transparent; }` and `.pagination--classic .pg-arrow { background: var(--bg-layer4); }`.
- Drop `.pg-btn--active { font-weight: 600 }`.
- Drop `.pagination--simple .pg-main { gap: 16px }`; replace with arrow-pair rule.
- Add `.pagination--small .pg-page-list { gap: var(--sp-xxs); }`.
- Replace `:deep(.select-wrap) { width: 120px }` with `var(--pagination-pagesize-selector-width)` (and similarly for jumper).

### Estimated diff

- Template: ~6 lines added (wrapper divs + computed update), ~2 lines removed.
- CSS: ~20 lines added (new variant-specific rules + token swaps), ~8 lines removed (raw px / wrong gap / font-weight 600).
- Tokens: 3 new domain tokens added to `variables.css` (~4 lines).
- Total: **~30 lines added, ~10 lines removed**.

## Blockers / open decisions

- New domain tokens (`--pagination-pagesize-selector-width`, `--pagination-jumper-input-width`, `--pagination-simple-nav-width`) need plan-owner approval before adding to `variables.css`. Suggest adding under existing "Derived aliases" section.
- Cross-component verification: `<Select variant="line">` and `<Input variant="filled">` / `<Input variant="line">` internal styling alignment with figma is out of scope here but transitively affects Pagination visual fidelity. Log as separate audit in those components' own batches.
- BRIDGE-Tier3 button refactor (5 native button sites) deferred — no action.
