> ## Documentation Index
> Fetch the complete documentation index at: https://docs.sesameterminal.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Design system and UX specs

# Design system and UX specs

The UX specs for sesame-bun. PLAN.md §4 has the summary; these files are the detail
that frontend engineers build from. The UI/UX designer owns this folder and
`frontend/src/styles/tokens.css`.

## Principles

1. **Fewest clicks.** Every task in the click-budget table (PLAN §4.1) is met on desktop
   and on mobile. Actions sit on the thing they act on (row actions, ladder header), not
   behind menus. Anything reachable only through a menu needs a palette command as well.

2. **Instant feedback.** Every click changes something on screen within one frame: an
   order chip appears in `sending` state, a button shows its pressed state, a switch shows
   its pending state. Server confirmation then replaces the pending state. Nothing waits
   for an animation.

3. **Never move a price under the cursor.** A price, button or order chip stays at the
   same pixel while the pointer (or a finger) is over its container. The rules that
   follow from this:
   * Ladder rows are fixed price levels. The ladder never re-centres while hovered or
     touched.
   * Column widths are fixed and digits are equal-width. Columns such as P\&L-if-closed
     and the pending-order dot keep their space even when empty.
   * Lists defer insert, remove and reorder while hovered (see [interactions.md](interactions.md#deferred-list-changes)).
   * Status banners use reserved lines, never insert rows above content.
   * Opening or closing a panel never shifts a price column that is left of it.

4. **One click, visible stake.** A price click sends a GTC limit at exactly that price
   for the active stake, with no confirmation. So the stake is always on screen (top bar
   on desktop, stake bar on mobile), and hovering a price shows exactly what a click
   sends (the cursor tag).

5. **Stale data looks stale.** When a feed lags, the last values stay visible but turn
   grey, their tint and flash stop, clicking them does nothing, and the panel shows the
   age. We never fill a gap from another source.

6. **Colour is never the only cue.** Green is bid, buy, profit and Yes; red is ask, sell,
   loss and No. Every coloured value also has a position (bid column left, ask right),
   a label (Buy, Sell) or a sign (+, −).

7. **Same features on phone and desktop.** Ladders become bottom sheets, right-click
   becomes long-press, hover becomes the always-visible stake bar. Touch targets are at
   least 44 px.

8. **Calm, consistent layout.** Controls in one row share one height (`--control-h` on
   desktop, `--touch-min` on touch). Siblings share padding from the spacing scale, and a
   control is vertically centred in its bar. Each section has at most one container level;
   tabs, segmented controls and summary figures sit on the surface, separated by spacing
   or a single divider, not wrapped in extra boxes. Every UX review measures this at 1440
   and 390 px (see `CLAUDE.md` "Layout consistency").

9. **Divider before box, simple before busy.** Separate with a thin low-contrast line or
   spacing; box only dialogs, sheets, popovers and toasts. Colour only for meaning, units in
   headers, blanks instead of zeros, quiet status until it matters, and desktop row actions
   on hover or focus (see `CLAUDE.md` "Visual simplicity").

10. **Content never resizes the layout.** Long names truncate with a tooltip, number slots
    reserve their widest value, live values never change an element's size, and loading,
    empty and stale states keep the loaded dimensions.

## Files

| File | Contents |
| - | - |
| [tokens.md](tokens.md) | Every token with both theme values, contrast table, type scale |
| [components.md](components.md) | Component inventory: sizes and states |
| [interactions.md](interactions.md) | Hotkeys, click/drag/long-press, stake, delay window, errors, click budgets |
| [motion.md](motion.md) | Per-component motion, enter/exit, reduced motion |
| [screens/app-shell.md](screens/app-shell.md) | Top bar, left rail, ladder dock, bottom dock, mobile header and tab bar |
| [screens/login.md](screens/login.md) | Login |
| [screens/command-palette.md](screens/command-palette.md) | Ctrl+K palette |
| [screens/live-board.md](screens/live-board.md) | Live sports board |
| [screens/watchlist.md](screens/watchlist.md) | Pinned markets |
| [screens/market-view.md](screens/market-view.md) | Outcomes, book, chart |
| [screens/price-ladder.md](screens/price-ladder.md) | Ladder column and mobile bottom sheet |
| [screens/portfolio.md](screens/portfolio.md) | Positions and activity |
| [screens/orders.md](screens/orders.md) | Open orders, steppers, bulk actions |
| [screens/alerts.md](screens/alerts.md) | Alert kinds and trigger rules, creation, alerts list, notification history |
| [screens/notifications.md](screens/notifications.md) | Toasts, desktop notifications, sounds, Telegram, the copy per kind, Settings > Notifications |
| [screens/settings.md](screens/settings.md) | Stakes, risk limits, theme, notifications |
| [screens/combos.md](screens/combos.md) | Combo mode and leg toggles, the slip and quote states, combo positions, keys and budgets |
| [contrast.mjs](contrast.mjs) | `node docs/design/contrast.mjs` re-checks the contrast table after a token change |

## Conventions used in these specs

* **Sizes** are CSS pixels at 100% zoom. Desktop wireframes assume 1440 × 900, mobile
  390 × 844 (iPhone 14 class) with safe-area insets on top of the stated heights.
* **Price format.** Prices show as cents: `42¢`, `42.5¢` on a 0.001 tick. The ladder
  price column drops the `¢` sign to save width. `lib/format` owns the formatting.
* **Money** is pUSD, shown as `$1,234.56`. Compact form in dense cells: `$1.2k`.
  P\&L is always signed: `+$12.40`, `−$3.10` (U+2212 minus).
* **Sizes** are shares: exact in your own orders (`59.52`), compact in book depth
  (`1.2k`, `12.5k`, `1.1M`).
* **Token names** are written without `var()`: `--bid` means `var(--bid)`.
* **Wireframe notation.** No emoji or pictographic symbols, in wireframes either. `[name]`
  in lower case is a lucide icon (`[bell]`, `[x]`, `[chevron-down]`, `[ellipsis]`);
  `[Label]` in sentence case is a button; `[ ]` and `[*]` are an unchecked and a checked
  checkbox; `(dot)` is a 6 px status dot; `[logo]` is the app or team logo; `|` is a 2 px
  bar (selection, last trade, possession). Box-drawing lines and `░` depth shading are
  layout, not content. Labels are in sentence case, as in the UI.
* **"Armed"** means the Safe/Armed switch is Armed and trading is enabled (not
  geoblocked, `LIVE_TRADING` set). Every trade action in these specs assumes armed; the
  disabled behaviour is in [components.md](components.md#price-button).
* **Out of scope:** funding (deposit, withdraw, bridge, redeem, split, merge) and Perps.
  A resolved position links out to polymarket.com to claim.

## Open questions for the tech lead

The specs follow the proposals below until the tech lead decides otherwise. None of
them edit PLAN.md.

1. **`--dur-flash` (400 ms).** PLAN §4.1 sets a 400 ms price flash; CLAUDE.md caps every
   duration at `--dur-slow`. Proposal: record the flash as the one exception in
   CLAUDE.md's Motion section.
2. **Portfolio row expand.** PLAN §4.1 says "height and opacity"; the hard rules forbid
   layout animation on streaming rows. Proposal: height changes in one frame and the
   contents fade (motion.md). Update the PLAN table to match.
3. **Hotkey classes.** CLAUDE.md says hotkeys are disabled unless Armed and Cancel all is
   the only global one. Navigation keys (`Mod+K`, `Esc`, `?`, `g` chords, `F6`, `` ` ``)
   must work in Safe. Proposal: the Armed/focus rule applies to trading hotkeys only
   (interactions.md).
4. **Browser arithmetic.** CLAUDE.md puts money arithmetic in Go. The ladder's P\&L column,
   the walk price, liquidation value, hedge figures and cursor-tag share estimates are
   money values. Proposal: the backend sends them (per-level P\&L can come with the
   position in the ladder topic; walk price and liquidation value from
   `engine/portfolio`); cursor-tag share counts are shown as estimates using a decimal
   library in `lib/format`, never sent.
5. **Delay window cancels.** Delayed orders cannot be cancelled. Proposal: `engine/orders`
   queues the cancel and sends it when the delay ends (chip `Delayed · cancel queued`).
   Until decided, the UI reports which orders stayed. The contract also needs the delay
   end time (e.g. `delayed_until`) to draw the countdown.
6. **Exit price.** Proposal: Exit (the ladder header button and the portfolio action) sells the whole position at the walk price
   (the lowest bid level that fills the full size), not the best bid, so one click gets
   out. Large exits may then fall outside `price_band_ticks`; consider exempting
   position-reducing sells from the band.
7. **Ladder rows 28 px.** The comfortable density is 36 px; the ladder alone uses 28 px on
   fine pointers (about 22 levels visible instead of 17) and 44 px on touch.
8. **Ladder dock scope.** PLAN puts "up to 4 ladders" on the board. Proposal: the dock is
   shared by Live and Watchlist and persists across routes.
9. **Selling without a position** is disabled (no automatic conversion into buying the
   other outcome), in line with "never convert a click".
10. **Double-click guard.** A repeat click on the same target within 350 ms reuses the
    idempotency key, so the backend places one order. Confirm this with
    `engine/orders`.
11. **Contract gaps for later phases:** notification settings (resolved in the Phase 4
    contract: `NotificationSettings`), layout state (dock height, docked ladders, grouping), the feed age in
    `FeedStatus` for the `Stale 6s` label, and a cancel-only venue state for the status
    pill.
12. **Palette ranking.** PLAN gives pinned > held > live > volume. Proposal: apply it inside
    two text-match tiers, so a strong match always beats a weak pinned one.
13. **Mobile repricing in the ladder sheet** costs one extra tap (select the chip, then
    tap per tick), because a tap on a level places an order. The Orders tab meets the
    budget exactly.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.