# Tokens delta: RJ Laravel Admin (brand-006) against the DTC kit

**Direction:** 4b·R, HQ Lockup with the labelled rail. Frank picked it in chat on 2026-10-18.
**Baseline:** `projects/pina/brands/brand-005-rj-dtc-admin/phase-2/kit/tokens.css`, kit v3 **as it is today** (2026-10-18, before the DTC recolour).
**File:** `phase-0/tokens-delta.css`. Load it after the DTC `tokens.css`. Every token not listed here is inherited by name.
**Source:** `phase-1/final/src/tokens_delta.py`. It checks every "DTC today" value below against the DTC file and fails if one has drifted. Rerun it after any change to the DTC kit.

**Count:** 38 tokens differ from DTC: 20 changed values and 18 new names. On top of that, the comfortable density mode overrides 8 tokens, and 22 navy tokens are pinned (see below).

## What stays exactly DTC

The sidebar and every primary action keep the Satin Lapel navy:
- `--sidebar` and `--primary` are `#0E1729`
- the satin sheen is `#131D33 → #0E1729 → #0C1425`, with its bloom
- the active rail is `#9FB4E2` and the active icon is `#B7C7EA`
- the menu text is `#C9CEDA`

Frank's reason: "the Laravel app is the parent app, so it gets the choice." Round 2's steel shift in the sidebar (rail `#8EA8DC`, icon `#C4D2EE`) is **dropped**.

Steel `#2C4B86` stays for **selection and focus only**: `--accent`, `--selected-row`, `--ring`, `--steel` and the tape ticks. That does not conflict with the navy, because steel never touches the sidebar or a primary action.

## The delta

| Group | Token | DTC today | Laravel admin | Why |
|---|---|---|---|---|
| Ground and selection | `--background` | `#FFFFFF` | `#EDF0F4` | grey page ground; containers stay white (--card #FFFFFF inherited) |
| Ground and selection | `--muted` | `#F4F5F8` | `#F5F6F9` | table head, wells, hover: one step off the grey ground |
| Ground and selection | `--border` | `#E4E7ED` | `#E2E6EC` | hairlines tuned to the grey ground |
| Ground and selection | `--accent` | `#EBEEF6` | `#E9EEF8` | selection / active filter: steel tint (2b) |
| Ground and selection | `--ring` | `#3F5FA6` | `#2C4B86` | focus = steel (2b); no conflict with the exact DTC navy, which stays on sidebar + primary |
| Ground and selection | `--steel` | (none) | `#2C4B86` | NEW. Selection rail, focus, tape ticks, sorted column. Never the sidebar, never a primary action |
| Ground and selection | `--selected-row` | (none) | `#E9EEF8` | NEW. Selected table row ground |
| Density · compact (default, 2b ultra) | `--text-body` | `13px` | `12.5px` | 2b ultra body |
| Density · compact (default, 2b ultra) | `--text-small` | `12px` | `11.5px` | meta, table secondary |
| Density · compact (default, 2b ultra) | `--text-page` | `26px` | `20px` | page title at density |
| Density · compact (default, 2b ultra) | `--text-btn` | `13.5px` | `13px` | button label |
| Density · compact (default, 2b ultra) | `--text-nav` | (none) | `13px` | NEW name. Menu item (DTC draws its menu at 13.5px) |
| Density · compact (default, 2b ultra) | `--row` | `44px` | `30px` | table row: compact is the default |
| Density · compact (default, 2b ultra) | `--row-th` | `36px` | `30px` | table header row |
| Density · compact (default, 2b ultra) | `--row-compact` | `36px` | `30px` | kept equal to --row so DTC components that ask for compact get 30px |
| Density · compact (default, 2b ultra) | `--control-h` | `40px` | `30px` | button, input, select (desktop) |
| Density · compact (default, 2b ultra) | `--control-h-sm` | `34px` | `26px` | small button, row actions |
| Density · compact (default, 2b ultra) | `--page-pad` | (none) | `20px` | NEW name. Page gutter (DTC uses a 24px literal) |
| Shell | `--topbar-h` | `56px` | `48px` | white header; the HQ corner is the same height |
| Shell | `--rail-w` | (none) | `76px` | NEW. Collapsed rail, labelled (2b HQ Rail b form). Expanded stays --sidebar-w 232px (inherited) |
| Shell | `--rail-item-w` | (none) | `66px` | NEW. Rail item: icon over label |
| Shell | `--rail-item-min-h` | (none) | `48px` | NEW. Grows if a label wraps to its second line; never truncates |
| Shell | `--text-rail` | (none) | `10px` | NEW. Rail label (Archivo 500; 600 when active), up to 2 lines |
| Shell | `--hq-corner-bg` | (none) | `#FFFFFF` | NEW. The white 'RJ HQ · Master admin' corner joining the header |
| Shell | `--hq-corner-fg` | (none) | `#0E1729` | NEW. 'HQ' wordmark ink (= DTC navy, pinned) |
| Shell | `--hq-corner-sub` | (none) | `#505A70` | NEW. 'Master admin' line (= --muted-foreground) |
| Shell | `--brand-mark` | `linear-gradient(145deg,#EEF1F8,#CBD5EA)` | `#0E1729` | the RJ tile sits on the WHITE corner, so it inverts to a navy tile |
| Shell | `--brand-mark-foreground` | `#0E1729` | `#FAFAF8` | RJ initials on the navy tile |
| Shell | `--e-brand-mark` | `0 0 12px -4px rgba(150,175,225,.22)` | `none` | no glow on the white corner |
| Tape measure (light touch) | `--tape-color` | (none) | `var(--steel)` | NEW. Ticks under the header + HQ corner, on the sorted column, on progress |
| Tape measure (light touch) | `--tape-minor` | (none) | `8px` | NEW. Minor tick pitch |
| Tape measure (light touch) | `--tape-major` | (none) | `80px` | NEW. Major tick pitch |
| Tape measure (light touch) | `--tape-h` | (none) | `6px` | NEW. Major tick height (minor = 3px) |
| Tape measure (light touch) | `--tape-opacity` | (none) | `.55` | NEW. Kept quiet |
| Icons | `--icon-stroke` | (none) | `1.5` | NEW name. DTC's contract is 1.75 (comment only); lighter at density |
| Type · CJK | `--font-cjk` | (none) | `'PingFang SC', 'Noto Sans SC', 'Microsoft YaHei'` | NEW. mainland staff; zh-Hans |
| Type · CJK | `--font-title` | `'Archivo', system-ui, sans-serif` | `'Archivo', var(--font-cjk), system-ui, sans-serif` | Archivo first, CJK falls through to the CJK stack |
| Type · CJK | `--font-ui` | `'IBM Plex Sans', system-ui, sans-serif` | `'IBM Plex Sans', var(--font-cjk), system-ui, sans-serif` | same for reading text |

**Density mode.** Compact (2b ultra) is the default and is written into `:root`. Comfortable is the opt-in mode, set with `[data-density="comfortable"]`: `--text-body` 13px · `--text-small` 12px · `--text-page` 20px · `--row` 34px · `--row-th` 32px · `--row-compact` 34px · `--control-h` 32px · `--control-h-sm` 28px. It is remembered per person in the UI only, so no API is needed.

**Shell structure.** These are not tokens, but the frontend team needs them:
- The expanded menu is 232px of navy satin (`--sidebar-w`, inherited).
- Collapsed, it is a 76px rail. Each item shows its icon with the `/me/menu` label underneath, at 10px. Labels are never invented or shortened. A long label wraps to a second line.
- The collapse toggle sits at the left edge of the white header and stays in the same place in both states (⌘B).
- The white HQ corner is `--topbar-h` tall and joins the header into one white bar. The tape runs under both.
- Expanded, the corner reads: navy RJ tile, then **HQ**, then *Master admin*.
- Collapsed, it reads: RJ tile, then **HQ**, inside 76px.

## Pin these when DTC is recoloured

Today the Laravel admin gets its navy from the DTC kit **by name**. Once the DTC admin is recoloured, that inheritance would quietly repaint the parent app. So the Laravel admin's own token layer must restate these 22 values literally. Section 3 of `tokens-delta.css` already does this. Each value equals DTC today, and the script asserts that:

| Token | Pinned value | Note |
|---|---|---|
| `--primary` | `#0E1729` | every primary action |
| `--primary-foreground` | `#FAFAF8` |  |
| `--primary-hover` | `#1A2540` |  |
| `--secondary-foreground` | `#0E1729` | outlined button text |
| `--accent-foreground` | `#0E1729` | text on selection |
| `--foreground` | `#0F1626` | navy-ink body text |
| `--card-foreground` | `#0F1626` |  |
| `--popover-foreground` | `#0F1626` |  |
| `--sidebar` | `#0E1729` | the expanded menu + rail |
| `--sidebar-foreground` | `#C9CEDA` | menu text (--rj-mist) |
| `--sidebar-primary` | `#9FB4E2` | active rail + icon tint (2b's steel #8EA8DC is NOT used) |
| `--sidebar-primary-foreground` | `#0E1729` |  |
| `--sidebar-accent` | `#1B2744` |  |
| `--sidebar-accent-foreground` | `#FAFAF8` |  |
| `--sidebar-border` | `#253049` |  |
| `--sidebar-ring` | `#9FB4E2` |  |
| `--sidebar-sheen` | `linear-gradient(180deg, #131D33 0%, #0E1729 52%, #0C1425 100%)` | the satin |
| `--sidebar-sheen-light` | `radial-gradient(closest-side, rgba(130,160,220,.11), transparent)` | the bloom |
| `--e-sidebar-edge` | `inset -1px 0 0 rgba(201,206,218,.07)` |  |
| `--sidebar-item-on` | `rgba(255,255,255,.07)` | active item ground |
| `--e-sidebar-item-on` | `inset 0 0 0 1px rgba(201,206,218,.09),0 6px 18px -12px rgba(110,140,210,.22)` |  |
| `--sidebar-item-on-icon` | `#B7C7EA` | active icon (2b's #C4D2EE is NOT used) |

`--sidebar-background` is pinned as `var(--sidebar)`. Tokens that are built on `--primary`, such as `--e-rail` and `--e-rail-strong`, follow the pin automatically. The shadows (`--e-*`) and `--scrim` use `rgba(14,23,41,…)`. Those are navy-tinted literals, not names, so a recolour cannot reach them.

**Rule for the recolour agent:** change the DTC file only. Do not edit `tokens-delta.css` to "follow" it. After the recolour, rerun `tokens_delta.py`. Its pin asserts will then fail. That is expected: update the "DTC today" baseline column, but keep the pinned values exactly as they are.
