Color ramps
The brand orange, warm cream, and warm ink. Components never touch these directly: semantic tokens only. The big ruling: brand orange is a fill, not a text color.
Semantic roles
What components are allowed to reference, with both theme resolutions. Every pairing is contrast-checked on build: run npm run verify.
| Token | Light | Dark | Role |
|---|---|---|---|
| color.bg.primary | #F7F3E7 | #000000 | Page background. |
| color.bg.secondary | #EFE9D8 | #141414 | Sunken wells, alt rows. Doubles as the hover wash on outline/ghost interactive surfaces. |
| color.bg.pressed | #FFFDF9 | #414141 | Pressed wash on outline/ghost interactive surfaces. |
| color.bg.elevated | #FFFDF9 | #141414 | Overlay surfaces that float above the page: menus, popovers. Pairs with shadow.overlay. |
| color.bg.positive | #3A7846 | #3A7846 | Success toast surface. Theme-constant; carries text.on-status. |
| color.bg.negative | #C13937 | #C13937 | Error toast surface. Theme-constant; carries text.on-status. |
| color.bg.info | #213944 | #213944 | Informational banner surface, the recovered broadcast blue. Theme-constant; carries text.on-status. |
| color.bg.scrim | #23252B80 | #23252B80 | The overlay wash behind modals and sheets — the old .Scrim (#23252B at 50%), token, not a component. Theme-constant. |
| color.bg.inverse | #000000 | #F7F3E7 | Inverse blocks. |
| color.border.subtle | #D4CBAF | #414141 | Quiet outlines on interactive surfaces that carry their own text contrast. Decorative, not contracted. |
| color.border.strong | #6A6450 | #777777 | Control boundaries that must read on their own (checkbox boxes, radio rings, switch tracks). Contracted at the 3:1 UI floor. |
| color.text.primary | #000000 | #FFFDF9 | Reading text. |
| color.text.secondary | #6A6450 | #BBBBBB | Captions, metadata. |
| color.text.disabled | #736D57 | #777777 | Disabled — visible but muted. FIXED from the old 1.7:1. |
| color.text.positive | #3A7846 | #5BBE70 | Good news in text: airtimes, new episodes, a strong password. |
| color.text.negative | #C13937 | #CC5D5B | Errors and destructive actions, in text. |
| color.text.warning | #A43F06 | #D25108 | The Orange AA, not brand orange. |
| color.text.link | #000000 | #FFFDF9 | Links rest in the reading color. Orange is earned on hover. |
| color.text.link-hover | #A43F06 | #FF640A | Link hover: the Orange AA on light, brand orange on dark. |
| color.text.link-active | #762D04 | #FF8036 | FIXED from raw brand orange (2.8:1) to the deep AA step. |
| color.text.on-inverse | #FFFDF9 | #000000 | Text on bg.inverse surfaces (inverse buttons, inverse blocks). |
| color.text.on-media | #FFFDF9 | #FFFDF9 | Glyphs and labels over artwork and the scrim (thumbnail play icon, duration chip). Artwork is always dark, so this does not flip with the theme. |
| color.text.entry | #000000 | #FFFDF9 | User-entered values in inputs. Robin's ruling: entered text reads white on dark (cream.50), one step brighter than reading text — your words stand out from the chrome. |
| color.text.on-status | #FFFDF9 | #FFFDF9 | Text and glyphs on the status surfaces (bg.positive/negative/info). Theme-constant white. |
| color.accent.base | #FF640A | #FF640A | Brand orange. A FILL color, not a text color: it fails 3:1 on cream (2.7), so on light it appears only as filled surfaces carrying ink text, or as large decorative marks. |
| color.accent.hover | #FF8036 | #FF8036 | Accent fill on hover — lifts, does not darken. Same in both themes; ink text holds 8.4:1. |
| color.accent.pressed | #D25108 | #D25108 | Accent fill pressed. Ink text holds 4.9:1. |
| color.accent.on-accent | #000000 | #000000 | Text on brand-orange fills (base, hover, and pressed). Ink, not white — white on orange is 2.9:1. This is why Crunchyroll buttons have dark text. |
| color.accent.text | #A43F06 | #FF640A | Brand-colored text on quiet surfaces (brand outline/ghost buttons). The Orange AA on light, raw orange on dark. NOT the reference's hover value — orange.450 on the tint wash measured 2.2:1 and died at the gate. |
| color.accent.text-pressed | #762D04 | #FF8036 | Brand-colored text, pressed. |
| color.accent.wash | #FFEFE5 | #481B02 | Brand tint wash behind hovered/pressed brand outline/ghost buttons. |
Type ramp
Twelve utilities welded from 68 tripled styles. Headlines carry the Atyp metrics in DM Sans Bold until the display face surfaces; bold UI text keeps the -3% brand tightening.
Space
8pt scale with half-steps where components earned them. The scale is the law.
Radius & elevation
Pill actions, tight surfaces. Three shadow levels only: raised, overlay, modal. Dark separation leans on surface color, not shadow.