@trading-game/design-intelligence-layer 1.0.6 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +3 -3
- package/dist/index.cjs +42 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +42 -12
- package/dist/index.js.map +1 -1
- package/docs/components/badge.md +21 -4
- package/docs/components/item.md +25 -7
- package/docs/components/stepper.md +9 -6
- package/docs/foundations/colors.md +3 -3
- package/docs/foundations/shape-layout.md +2 -2
- package/docs/foundations/typography.md +12 -0
- package/guides/brand-voice/trading-game-brand-voice.md +10 -11
- package/package.json +1 -1
- package/src/styles.css +7 -7
- package/guides/rules/design-system-consuming-project.mdc +0 -366
package/docs/components/badge.md
CHANGED
|
@@ -21,7 +21,7 @@ Non-interactive status pill — emphasis (solid or tint) crossed with meaning (b
|
|
|
21
21
|
| Prop | Type | Default | Notes |
|
|
22
22
|
| --- | --- | --- | --- |
|
|
23
23
|
| `variant` | `"solid" \| "solid-demo" \| "solid-neutral" \| "solid-success" \| "solid-fail" \| "solid-warning" \| "tint" \| "tint-demo" \| "tint-neutral" \| "tint-success" \| "tint-fail" \| "tint-warning"` | `"solid"` | Emphasis + meaning grid; brand is the unsuffixed default. |
|
|
24
|
-
| `size` | `"xs" \| "sm" \| "md" \| "lg"` | `"md"` | Heights 20 / 24 / 32 / 40. |
|
|
24
|
+
| `size` | `"xs" \| "sm" \| "md" \| "lg" \| "count"` | `"md"` | Heights 20 / 24 / 32 / 40. |
|
|
25
25
|
| `asChild` | `boolean` | `false` | Render onto a caller element. Badges are read-only markers — no hover states exist (interactive pills are Chips). |
|
|
26
26
|
|
|
27
27
|
The `glass` variant was removed (breaking change); there is no replacement — use `tint` on imagery-free surfaces.
|
|
@@ -46,11 +46,29 @@ import { Badge } from "@trading-game/design-intelligence-layer"
|
|
|
46
46
|
| `md` | 32px | `px-3 py-1` | 14/20 |
|
|
47
47
|
| `lg` | 40px | `px-4 py-1.5` | 16/24 |
|
|
48
48
|
|
|
49
|
+
### `count`
|
|
50
|
+
|
|
51
|
+
`size="count"` is a shape, not a step on the xs/sm/md/lg rail: an 18px disc whose minimum
|
|
52
|
+
width equals its height, so one digit is a circle and more digits grow it into a pill at the
|
|
53
|
+
same height. `tabular-nums` fixes the digit width, so a ticking count only resizes when the
|
|
54
|
+
number of digits changes, not on every update.
|
|
55
|
+
|
|
56
|
+
Conventions the caller owns, not the component: hide the badge at zero, and cap above 99 as
|
|
57
|
+
`99+`. Pinning it over other chrome needs a knockout ring in the colour of whatever is
|
|
58
|
+
behind it — Badge cannot know that, so the caller adds it:
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
<Badge aria-hidden size="count"
|
|
62
|
+
className="absolute -top-0.5 -right-0.5 ring-2 ring-background-primary-canvas">
|
|
63
|
+
{count > 99 ? "99+" : count}
|
|
64
|
+
</Badge>
|
|
65
|
+
```
|
|
66
|
+
|
|
49
67
|
## Tokens
|
|
50
68
|
|
|
51
69
|
**Colour (semantic):**
|
|
52
70
|
- Solid: `background-brand-default` + `text-on-brand-static`; `background-demo-solid`; `background-inverse-surface` + `text-prominent-inverse`; `background-success-solid` / `background-error-solid` / `background-warning-solid`, all with `text-on-status-static`.
|
|
53
|
-
- Tint:
|
|
71
|
+
- Tint: `background-brand-selected` + `text-brand-selected` (the theme-aware selection family, same recipe as Calendar's range band); `background-demo-default` + `text-demo-default`; `background-secondary-surface` + `text-prominent-default`; `background-success/error/warning-default` + matching `text-*` status tokens. All tints are borderless — the tinted fill alone carries the meaning.
|
|
54
72
|
- The `tint-demo` / `tint-success` / `tint-fail` / `tint-warning` fills are one family by construction: a light `-50` step in light, and the hue's base step at **24% over the canvas** in dark. `tint-demo` gained its dark override so it stops reading as a light chip beside Won/Lost/Pending; note ember's base step is 500, not 600, because it is a game accent rather than a status colour.
|
|
55
73
|
- Focus: `ring-focus-strong`.
|
|
56
74
|
|
|
@@ -59,8 +77,7 @@ import { Badge } from "@trading-game/design-intelligence-layer"
|
|
|
59
77
|
## Behaviour
|
|
60
78
|
|
|
61
79
|
- Status solids use the bright 600 fills with shared static white ink (`text-on-status-static`) — deliberately below AA on green and amber; a style call, not an oversight.
|
|
62
|
-
- `tint` (brand)
|
|
63
|
-
- `tint` (brand) is the one tint that stays light in dark, because `--background-brand-container` is a deliberately static icy panel shared with Calendar's selection. It sits outside the status/demo tint family on purpose.
|
|
80
|
+
- `tint` (brand) flips with the theme like every other tint: `blue-600 @ 10%` over white in light, `blue-400 @ 24%` over the canvas in dark, with `blue-200` ink. It was the last variant on the static `--background-brand-container`; that token now has no consumers.
|
|
64
81
|
- No hover states — badges are read-only markers; if it needs to be clickable, it's a [Chip](./chip.md).
|
|
65
82
|
- `rounded-full`, `border-transparent` on every variant — no outlines, no shadow.
|
|
66
83
|
|
package/docs/components/item.md
CHANGED
|
@@ -13,7 +13,7 @@ Generic list row — media, title/description, and actions in one flex shell, wi
|
|
|
13
13
|
|
|
14
14
|
- `ItemGroup` — `role="list"` column; auto-divider mode on by default. `data-slot="item-group"`, `data-divider`.
|
|
15
15
|
- `ItemSeparator` — manual hairline (`Separator`). `data-slot="item-separator"`.
|
|
16
|
-
- `Item` — the row (`rounded-
|
|
16
|
+
- `Item` — the row (`rounded-2xl`, transparent hairline border for state changes). `data-slot="item"`, `data-variant`, `data-size`.
|
|
17
17
|
- `ItemMedia` — leading icon/image slot; top-aligns itself when a description is present. `data-slot="item-media"`, `data-variant`.
|
|
18
18
|
- `ItemContent` — flex-1 column for title + description. `data-slot="item-content"`.
|
|
19
19
|
- `ItemTitle` — 14/medium/20 prominent ink. `data-slot="item-title"`.
|
|
@@ -27,13 +27,13 @@ Generic list row — media, title/description, and actions in one flex shell, wi
|
|
|
27
27
|
|
|
28
28
|
| Prop | Type | Default | Notes |
|
|
29
29
|
| --- | --- | --- | --- |
|
|
30
|
-
| `divider` | `boolean` | `true` | Draws a 1px `border-default-default` line (inset `inset-x-4`) after each non-last **default-variant** Item, in a 4px gap. `outline`/`muted` items are skipped so borders don't double. Pass `false` for flush stacks or manual `ItemSeparator`. |
|
|
30
|
+
| `divider` | `boolean` | `true` | Draws a 1px `border-default-default` line (inset `inset-x-4`) after each non-last **default-variant** Item, in a 4px gap. `outline`/`fill`/`muted` items are skipped so borders don't double. Pass `false` for flush stacks or manual `ItemSeparator`. |
|
|
31
31
|
|
|
32
32
|
### Item
|
|
33
33
|
|
|
34
34
|
| Prop | Type | Default | Notes |
|
|
35
35
|
| --- | --- | --- | --- |
|
|
36
|
-
| `variant` | `"default" \| "outline" \| "muted"` | `"default"` | default transparent; outline = hairline `border-border-default-default` + hover fill; muted = `bg-background-secondary-surface
|
|
36
|
+
| `variant` | `"default" \| "outline" \| "fill" \| "muted"` | `"default"` | default transparent; outline = hairline `border-border-default-default` + hover glaze, no fill; **fill** = solid `bg-background-primary-surface` + the same hairline, hover steps to `background-secondary-surface`; muted = `bg-background-secondary-surface`, no border. |
|
|
37
37
|
| `size` | `"default" \| "sm"` | `"default"` | default `gap-4 p-4`; sm `gap-2.5 px-4 py-3`. |
|
|
38
38
|
| `asChild` | `boolean` | `false` | Render as link/button via Radix Slot; anchors get `hover:bg-background-hover-default`. |
|
|
39
39
|
|
|
@@ -73,11 +73,29 @@ import { BellIcon } from "lucide-react"
|
|
|
73
73
|
</ItemGroup>
|
|
74
74
|
```
|
|
75
75
|
|
|
76
|
+
### Picking between `outline` and `fill`
|
|
77
|
+
|
|
78
|
+
Both draw the same hairline. They differ only on a **non-white** background:
|
|
79
|
+
|
|
80
|
+
- On a Card, Sheet or Popover they are identical at rest — pick either.
|
|
81
|
+
- On `background-primary-canvas` (a game screen, a ledger page), `outline` lets the canvas
|
|
82
|
+
show through and the row reads as part of the page. `fill` gives the row its own solid
|
|
83
|
+
plane — the wallet-ledger pattern, and the right default for trade lists.
|
|
84
|
+
|
|
85
|
+
Every variant sits on `rounded-2xl` (18px) — the card radius Card, Dialog and Popover use.
|
|
86
|
+
An Item is a content shell, not a menu row, so it takes the card corner rather than the
|
|
87
|
+
tighter `rounded-md` it used previously.
|
|
88
|
+
|
|
89
|
+
`fill` hover steps `primary-surface` -> `secondary-surface` rather than using the shared
|
|
90
|
+
`background-hover-default` glaze, which is translucent and would let the canvas through a
|
|
91
|
+
filled row instead of darkening it. The same override is repeated for `[a]:` because the
|
|
92
|
+
base link hover uses that glaze and outranks a plain `hover:` on an anchor.
|
|
93
|
+
|
|
76
94
|
## Tokens
|
|
77
95
|
|
|
78
96
|
**Colour (semantic):**
|
|
79
97
|
- title `text-text-prominent-default`; description `text-text-subtle-default` (links underline, hover `text-text-brand-selected`)
|
|
80
|
-
- outline: `border-border-default-default`, hover `bg-background-hover-default`; muted: `bg-background-secondary-surface`
|
|
98
|
+
- outline: `border-border-default-default`, hover `bg-background-hover-default`; fill: `bg-background-primary-surface` + `border-border-default-default`, hover `bg-background-secondary-surface`; muted: `bg-background-secondary-surface`
|
|
81
99
|
- group divider: `bg-border-default-default`
|
|
82
100
|
- focus: `border-ring-focus-default` + 3px `ring-ring-focus-strong` (control ring)
|
|
83
101
|
- icon media: `bg-background-secondary-surface` + `text-icon-prominent-default`
|
|
@@ -96,10 +114,10 @@ import { BellIcon } from "lucide-react"
|
|
|
96
114
|
|
|
97
115
|
**Do**
|
|
98
116
|
- Let `ItemGroup` draw dividers; only reach for `ItemSeparator` with `divider={false}`.
|
|
99
|
-
-
|
|
117
|
+
- Leave the radius alone — Item is `rounded-2xl` (18px), the card tier, not the 8px row tier.
|
|
100
118
|
- Use `asChild` with a real `<a>`/`<button>` when the whole row navigates.
|
|
101
119
|
|
|
102
120
|
**Don't**
|
|
103
|
-
- Don't mix `variant="outline"` items into a dividered group expecting dividers — they are deliberately skipped.
|
|
121
|
+
- Don't mix `variant="outline"` or `variant="fill"` items into a dividered group expecting dividers — they are deliberately skipped.
|
|
104
122
|
- Don't push the title past medium 500; row titles never reach semibold, and bold does not exist in components.
|
|
105
|
-
- Don't add shadows to muted/outline rows; state is shown by fill and hairline only.
|
|
123
|
+
- Don't add shadows to muted/outline/fill rows; state is shown by fill and hairline only.
|
|
@@ -12,17 +12,17 @@ The mobile amount tray — a centred amount with frosted − / + circles either
|
|
|
12
12
|
|
|
13
13
|
- Container — full-width row, `data-slot="stepper"`, `data-disabled`.
|
|
14
14
|
- − / + — composed `<Button variant="frosted" size="icon-lg">` (48px brand-selected tint circles); each disables at its bound.
|
|
15
|
-
- Two rows — the optional
|
|
15
|
+
- Two rows — the optional sentence-case `label` spans the whole control, then a 4px gap, then the `−` / amount / `+` row. The label is deliberately **not** nested in the value column: doing so made the buttons centre against the label-plus-amount stack, which dropped them off the amount's centre line.
|
|
16
16
|
- Centre of the row — the editable amount (`role="spinbutton"`, tabular semibold figure), flanked by the two circles.
|
|
17
17
|
|
|
18
18
|
## API
|
|
19
19
|
|
|
20
20
|
| Prop | Type | Default | Notes |
|
|
21
21
|
| --- | --- | --- | --- |
|
|
22
|
-
| `label` | `ReactNode` | — |
|
|
22
|
+
| `label` | `ReactNode` | — | Sentence-case caption above the amount, e.g. `"Stake (USDT)"`. Renders in the shared `caption` type style, so a Stepper sits level with other captioned controls in a form row. |
|
|
23
23
|
| `value` / `defaultValue` | `number` | `0` | Controlled / uncontrolled. |
|
|
24
24
|
| `onValueChange` | `(n: number) => void` | — | |
|
|
25
|
-
| `min` / `max` | `number` | ±∞ | Buttons disable at the bounds; typed values clamp on commit. |
|
|
25
|
+
| `min` / `max` | `number` | ±∞ | Buttons disable at the bounds; typed values clamp on commit. Bounds need not sit on the step grid — `min={0.5} step={1}` is legal and `0.5` is exactly reachable. |
|
|
26
26
|
| `step` | `number` | `1` | Decimal steps set the display precision (0.5 → "2.50"). |
|
|
27
27
|
| `disabled` | `boolean` | `false` | Pointer events off; the `+`/`−` render Button's own disabled state and the label and amount switch to `text-disabled-default`. No wash on the wrapper — stacking one over the Buttons' own dim multiplied to ~6% and made them invisible. |
|
|
28
28
|
| `placeholder`, `id`, `name`, `aria-label` | | — | Pass-through to the amount input. |
|
|
@@ -41,12 +41,13 @@ import { Stepper } from "@trading-game/design-intelligence-layer"
|
|
|
41
41
|
|
|
42
42
|
| Token | Value |
|
|
43
43
|
| --- | --- |
|
|
44
|
-
| `--stepper-stake-label-*` | 12 / medium / 16
|
|
45
|
-
| `--stepper-stake-amount-*` |
|
|
44
|
+
| `--stepper-stake-label-*` | Aliases `--type-caption-*` — 12 / medium / 16 / `tracking-loose`, sentence case |
|
|
45
|
+
| `--stepper-stake-amount-*` | 20 / semibold / 28, tabular — matches [Numpad](./numpad.md)'s digit size |
|
|
46
46
|
|
|
47
47
|
## Behaviour
|
|
48
48
|
|
|
49
|
-
- The amount is directly editable: type, then blur or Enter commits
|
|
49
|
+
- The amount is directly editable: type, then blur or Enter commits; ArrowUp/ArrowDown step the value.
|
|
50
|
+
- **The bounds are exempt from step rounding.** A value at or past a bound commits as exactly that bound; only values strictly inside the range are rounded to the step's precision (then clamped as a backstop). So `min`/`max` are both exactly *reachable* and *stable* even when they sit off the step grid: with `min={0.5} step={1}`, decrementing from `1` lands on `0.5` and stays there across blur and re-commit. Rounding a bound would move the value off it — `Math.round(0.5)` is `1` — and a clamp afterwards can't undo that, since `1` is inside the range; the pre-1.0.7 component rounded after clamping and so returned `1` forever, making `min` unreachable.
|
|
50
51
|
- `onValueChange` fires with the committed number.
|
|
51
52
|
- Full-width by default — constrain with `className` (`max-w-90` in the demo).
|
|
52
53
|
|
|
@@ -54,8 +55,10 @@ import { Stepper } from "@trading-game/design-intelligence-layer"
|
|
|
54
55
|
|
|
55
56
|
**Do**
|
|
56
57
|
- Put the unit in the `label` ("Stake (USDT)").
|
|
58
|
+
- Write `label` copy in sentence case; currency codes stay capitalised as proper nouns.
|
|
57
59
|
- Pair with [Numpad](./numpad.md) on mobile amount screens.
|
|
58
60
|
|
|
59
61
|
**Don't**
|
|
60
62
|
- Don't use it for long-range values — that's [Slider](./slider.md).
|
|
61
63
|
- Don't hide the label on money amounts; the unit matters.
|
|
64
|
+
- Don't hand-roll a caption above a Stepper to dodge the label's case — use `label`.
|
|
@@ -53,7 +53,7 @@ All scales run 50→1000 (mono 50→1200; blue adds 25 and 1000 as the two canva
|
|
|
53
53
|
| `background-brand-hover` | black 16% over brand | (same recipe, re-derives) | Primary button hover — a state layer, not a scale step |
|
|
54
54
|
| `background-brand-pressed` | black 32% over brand | (same recipe) | Primary button pressed |
|
|
55
55
|
| `background-brand-selected` | blue-600 10% over white ≈ `#E9E9FF` | blue-400 24% over canvas ≈ `#121A55` | Selected/active fills: active nav row, current page, checked choice card |
|
|
56
|
-
| `background-brand-container` | white 92% glaze over blue-600 (layered) | static — same | The icy brand panel
|
|
56
|
+
| `background-brand-container` | white 92% glaze over blue-600 (layered) | static — same | The icy brand panel. **No current consumers** — Calendar's range band and Badge `tint` both moved to `background-brand-selected` because a static value cannot carry dark. Retained for the v1.0 sweep. **Layered value — paint with `background:`, never `bg-*`** |
|
|
57
57
|
| `background-inverse-surface` | mono-1100 `#1C1C1C` | mono-50 `#FFFFFF` | The flipped surface (tooltips, toasts) |
|
|
58
58
|
| `background-overlay-default` | black-alpha-50 | black-alpha-64 | Modal scrims |
|
|
59
59
|
| `background-success-default` | green-50 | green-600 24% over canvas | Status tint surface (Section Message) |
|
|
@@ -80,7 +80,7 @@ All scales run 50→1000 (mono 50→1200; blue adds 25 and 1000 as the two canva
|
|
|
80
80
|
| `text-on-brand-static` | mono-50 | static | White text on brand fills — never flips |
|
|
81
81
|
| `text-on-brand-subtle-static` | white-alpha-64 | static | Secondary copy on a brand fill. On brand the ladder **inverts** — it descends from white through the alpha rungs instead of climbing the mono ramp (3.8:1 on blue-600, 2.7:1 on blue-400) |
|
|
82
82
|
| `text-on-brand-disabled-default` | white-alpha-32 | white-alpha-24 | Disabled ink on a brand fill — 1.8:1 over blue-600, 1.5:1 over blue-400. **Not static**, unlike the rest of the on-brand family: the fill itself flips blue-600 → blue-400, and blue-400 caps white at 4.3:1, so the rung comes down with it. Replaces the `opacity-24` wash on on-brand variants |
|
|
83
|
-
| `text-brand-container-static` | blue-600 | static |
|
|
83
|
+
| `text-brand-container-static` | blue-600 | static | Brand ink on a **static white** surface — Button `on-brand`, Toast's action button, Input selection. Still in use; do not retire with `background-brand-container` |
|
|
84
84
|
| `text-static-black` | mono-1100 | static | Ink on `background-static-white` |
|
|
85
85
|
| `text-success-default` / `-error-` / `-warning-` / `-information-` | status 600 | **static — same in both themes** (deliberate call) | Status text |
|
|
86
86
|
| `text-on-status-static` | mono-50 | static | White on solid status fills (below AA on green/amber — deliberate style call) |
|
|
@@ -109,7 +109,7 @@ Several values are **recipes, not scale steps** — a solid base with a fixed la
|
|
|
109
109
|
- **State layers**: hover = black 16% / pressed = black 32% mixed over the brand fill (`color-mix`), so any brand colour derives its own states.
|
|
110
110
|
- **Dark surfaces**: white 6% / 12% mixed over the dark canvas — solid results, no translucency.
|
|
111
111
|
- **Dark status tints**: status-600 at 24% mixed over the canvas — solid.
|
|
112
|
-
- **Brand container**: a real two-layer paint (white 92% glaze over blue-600) — consume via `background: var(--background-brand-container)`.
|
|
112
|
+
- **Brand container**: a real two-layer paint (white 92% glaze over blue-600) — consume via `background: var(--background-brand-container)`. Nothing consumes it today: it is static by construction, so anything needing a brand tint that survives dark takes `background-brand-selected` instead.
|
|
113
113
|
- **On-brand sunken fields** (Input/InputGroup `variant="on-brand"`): `black-alpha-32` glaze fill + `white-alpha-24` border over whatever brand colour the consumer painted.
|
|
114
114
|
- **Glass** (Button/NavigationButton `glass`, Card `glass`): `white-alpha-24` fill + border + `backdrop-blur-md`; hover 32, press 16. Theme-independent.
|
|
115
115
|
|
|
@@ -24,9 +24,9 @@ Radius encodes the element's *class*, not taste:
|
|
|
24
24
|
|---|---|---|
|
|
25
25
|
| Actions — buttons, chips, pills, toggle pills | `rounded-full` | Button, Chip, Pagination cells, Bottom Navigation, badges, glass circles |
|
|
26
26
|
| Icon buttons | circles (`rounded-full` on a square) | Navigation Button, Button icon sizes, Input Group icon buttons |
|
|
27
|
-
| Cards & panels | `rounded-2xl` = **18px** | Card, Dialog, Alert Dialog, Popover, Hover Card, Empty shell, Drawer's attached edge (`rounded-t-2xl`) |
|
|
27
|
+
| Cards & panels | `rounded-2xl` = **18px** | Card, Dialog, Alert Dialog, Popover, Hover Card, Empty shell, **Item** (every variant — a content shell, not a menu row), Drawer's attached edge (`rounded-t-2xl`) |
|
|
28
28
|
| Menus & floating lists | `rounded-lg` = **10px** | Dropdown/Context/Menubar/Select panels, Menubar bar, Navigation Menu viewport |
|
|
29
|
-
| Rows inside menus/lists | `rounded-md` = **8px** | Menu items,
|
|
29
|
+
| Rows inside menus/lists | `rounded-md` = **8px** | Menu items, Tabs triggers, Sidebar rows, Numpad keys |
|
|
30
30
|
| Form fields | `rounded-xs` = **4px** — deliberate, unchanged | Input, Textarea, Native Select, Input Group frame, OTP slot end caps — the whole text-entry family |
|
|
31
31
|
| Checkboxes | `rounded-2xs` | Checkbox |
|
|
32
32
|
|
|
@@ -68,6 +68,18 @@ Recurring ladders:
|
|
|
68
68
|
- **Overlay titles** (Dialog, Alert Dialog, Drawer, Sheet, Empty): 18/semibold/24; their descriptions 14/regular/20.
|
|
69
69
|
- **Small labels** (Badge sm, Kbd-like chips, Sidebar labels, Bottom Navigation, menu headings): 12/16, medium.
|
|
70
70
|
- **Helper text** (Field description/error): fixed **12/16 at every field size** — help text never scales with the control.
|
|
71
|
+
- **Standalone figures** (Stepper amount, Input OTP, Numpad keys): **20/28**. Weight varies with the job — the Stepper amount and OTP are semibold, Numpad keys medium — but the size is fixed, so a value typed on the pad reads at the same size in the tray above it. Only the Stepper amount adds `tabular-nums`, since it is the one that changes in place while the user holds `−` / `+`.
|
|
72
|
+
|
|
73
|
+
### Aliasing a foundation style
|
|
74
|
+
|
|
75
|
+
A component token normally points at a **primitive** step. Point it at a **semantic** `--type-*` instead when the component's text does the same job as a foundation style, so the two cannot drift apart:
|
|
76
|
+
|
|
77
|
+
```css
|
|
78
|
+
--stepper-stake-label-font-size: var(--type-caption-size);
|
|
79
|
+
--stepper-stake-label-tracking: var(--type-caption-tracking);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
The Stepper's `label` names the control beneath it — a caption's job — so it aliases `--type-caption-*` rather than re-declaring 12/16. Reserve this for a genuine role match: aliasing because two things happen to share a size today just couples them by accident.
|
|
71
83
|
|
|
72
84
|
## The one shared family: `--menu-*`
|
|
73
85
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# trading.game — Brand voice
|
|
2
2
|
|
|
3
|
-
**Version:** 2.
|
|
3
|
+
**Version:** 2.1 · September 2026
|
|
4
4
|
**Adds:** Channel-specific voice application per persona mode; anti-AI writing rules for all copy
|
|
5
5
|
|
|
6
6
|
---
|
|
@@ -106,7 +106,7 @@ The tone is not the same for all three modes. Edge Seekers respond to validation
|
|
|
106
106
|
Give them something to be early on. Frame the product as a read, not a game.
|
|
107
107
|
|
|
108
108
|
> "Vol 100 has been oscillating inside a 12-point range for three sessions.
|
|
109
|
-
> Rise
|
|
109
|
+
> Rise-Fall is pricing that in. If you've been watching it, now's the time."
|
|
110
110
|
|
|
111
111
|
> "The fastest feedback loop on a market read.
|
|
112
112
|
> Five ticks. Real price data. No waiting for a daily close."
|
|
@@ -163,7 +163,7 @@ Subject lines that work are different by mode:
|
|
|
163
163
|
|
|
164
164
|
**Edge Seeker:**
|
|
165
165
|
- "Your read on V_100 paid out."
|
|
166
|
-
- "Rise
|
|
166
|
+
- "Rise-Fall is running on Vol 200. Your call."
|
|
167
167
|
- "The chart moved where you said it would."
|
|
168
168
|
|
|
169
169
|
**System Runner:**
|
|
@@ -228,7 +228,7 @@ State the thing. Then the implication for the player. Don't lead with your feeli
|
|
|
228
228
|
|
|
229
229
|
| ✅ | ❌ |
|
|
230
230
|
|---|---|
|
|
231
|
-
| "Rise
|
|
231
|
+
| "Rise-Fall now runs on V_200. Higher vol, wider payout range. Check the multiplier before you trade." | "We're excited to announce an exciting new instrument! Amazing opportunity for all traders!" |
|
|
232
232
|
| "Digits is live. Tick-based prediction on the last digit of a price feed. 1–10 ticks, six contract types." | "Introducing Digits, our innovative new game that revolutionises the prediction experience!" |
|
|
233
233
|
| "Withdrawal processing is now instant. Not 'faster.' Instant." | "We've made some improvements to our withdrawal process for a more seamless experience." |
|
|
234
234
|
|
|
@@ -266,9 +266,9 @@ The other difference: HyperSwap assumes DeFi fluency. We can't. Some players hav
|
|
|
266
266
|
|
|
267
267
|
| HyperSwap register | trading.game register |
|
|
268
268
|
|---|---|
|
|
269
|
-
| "SWAP Genesis is live. Early believers get rewarded 🔥" | "Rise
|
|
269
|
+
| "SWAP Genesis is live. Early believers get rewarded 🔥" | "Rise-Fall is live on V_100. Edge is 2%. The rest is skill." |
|
|
270
270
|
| "Swappies, the airdrop is coming 🚀" | "Your win rate this week: 54%. Baseline is 50%. You're ahead." |
|
|
271
|
-
| "Earn boosted rewards for LPs 💰" | "Transferred 20 USDT to
|
|
271
|
+
| "Earn boosted rewards for LPs 💰" | "Transferred 20 USDT to Box-O. Your capital, your call." |
|
|
272
272
|
|
|
273
273
|
---
|
|
274
274
|
|
|
@@ -292,11 +292,10 @@ The other difference: HyperSwap assumes DeFi fluency. We can't. Some players hav
|
|
|
292
292
|
|
|
293
293
|
| Correct | Not |
|
|
294
294
|
|---|---|
|
|
295
|
-
| Rise & Fall
|
|
296
|
-
|
|
|
297
|
-
| Swipe Cards
|
|
295
|
+
| Rise-Fall | Rise & Fall / Rise and Fall / Rise/Fall |
|
|
296
|
+
| Box-O | BoxO / Box O / GridRush |
|
|
297
|
+
| Swipe | Swipe Cards / Swipe-Cards / SwipeCards |
|
|
298
298
|
| Digits | The Digits game |
|
|
299
|
-
| Dice | The Dice game |
|
|
300
299
|
|
|
301
300
|
### Formatting
|
|
302
301
|
|
|
@@ -322,4 +321,4 @@ Before publishing anything:
|
|
|
322
321
|
|
|
323
322
|
---
|
|
324
323
|
|
|
325
|
-
*trading.game Brand Voice — v2.
|
|
324
|
+
*trading.game Brand Voice — v2.1*
|
package/package.json
CHANGED
package/src/styles.css
CHANGED
|
@@ -1165,12 +1165,13 @@
|
|
|
1165
1165
|
--bottom-navigation-label-active-font-weight: var(--primitive-font-weight-semibold);
|
|
1166
1166
|
|
|
1167
1167
|
/* ── Stepper (stake variant) — component type tokens (private) ── */
|
|
1168
|
-
--stepper-stake-label-font-size: var(--
|
|
1169
|
-
--stepper-stake-label-font-weight: var(--
|
|
1170
|
-
--stepper-stake-label-line-height: var(--
|
|
1171
|
-
--stepper-stake-
|
|
1168
|
+
--stepper-stake-label-font-size: var(--type-caption-size);
|
|
1169
|
+
--stepper-stake-label-font-weight: var(--type-caption-weight);
|
|
1170
|
+
--stepper-stake-label-line-height: var(--type-caption-line);
|
|
1171
|
+
--stepper-stake-label-tracking: var(--type-caption-tracking);
|
|
1172
|
+
--stepper-stake-amount-font-size: var(--primitive-font-size-20);
|
|
1172
1173
|
--stepper-stake-amount-font-weight: var(--primitive-font-weight-semibold);
|
|
1173
|
-
--stepper-stake-amount-line-height: var(--primitive-line-height-
|
|
1174
|
+
--stepper-stake-amount-line-height: var(--primitive-line-height-28);
|
|
1174
1175
|
|
|
1175
1176
|
/* ── Progress — component type tokens (private) ── */
|
|
1176
1177
|
--progress-label-font-size: var(--primitive-font-size-12);
|
|
@@ -1981,8 +1982,7 @@
|
|
|
1981
1982
|
font-size: var(--stepper-stake-label-font-size);
|
|
1982
1983
|
line-height: var(--stepper-stake-label-line-height);
|
|
1983
1984
|
font-weight: var(--stepper-stake-label-font-weight);
|
|
1984
|
-
letter-spacing:
|
|
1985
|
-
text-transform: uppercase;
|
|
1985
|
+
letter-spacing: var(--stepper-stake-label-tracking);
|
|
1986
1986
|
}
|
|
1987
1987
|
|
|
1988
1988
|
.type-stepper-stake-amount {
|