Titandocs

Compliance checklist

Run this before opening a PR that touches any surface.

If a line fails, the fix is almost always "use the token" rather than "adjust the value".

Tokens

Colour semantics

  • Green appears only for gain / long / buy / success / up.
  • Red appears only for loss / short / sell / error / down.
  • --warn is used for risk — liquidation price, capacity, alerts — not red.
  • No green or red on a non-financial element.
  • Badges use the soft background with the solid text colour, never solid-on-solid.
  • Variable intensity uses color-mix, not a hand-picked second shade.

Typography

  • Every number carries tabular-nums.
  • Live prices, addresses, order book, and timestamps are mono.
  • Column headers are uppercase, tracking-[0.06–0.1em], --t3.
  • Large text has tighter tracking, not looser.
  • Money values split integer (--t1) from decimals (--t2).

Surfaces & elevation

  • Interactive controls sit on --surface-3; their active state drops to --surface.
  • In-page cards have no shadow.
  • Only floating layers (popover, modal, context menu, toast) cast a shadow.
  • Floating layers combine translucency + backdrop-blur(28px) saturate(1.6).

Motion

  • All animation is inside @media (prefers-reduced-motion: no-preference).
  • Page entrances translate only — never animate opacity.
  • Interactive elements press with scale(.96).
  • Durations sit in 120–350 ms.
  • Springs use cubic-bezier(.34,1.56,.64,1); general easing uses cubic-bezier(.2,.7,.3,1).

Component hygiene

  • Named export, memo, explicit displayName.
  • forwardRef on anything wrapping a DOM element.
  • State lives on data-*, not a conditional class string.
  • Visuals live in CSS; the component is a thin wrapper.
  • Static config is a module-level constant.
  • cn() for class joining — no clsx.

Accessibility

  • Focus is visible and uses --focus-ring (the only blue in the chrome).
  • The active nav item carries aria-current="page".
  • Modals dismiss on Escape and overlay click.
  • Contrast: --t3 is 0.55 dark / 0.62 light. Do not restore the old 0.4.
  • Colour is never the only signal — pair it with a label, sign, or icon.

Privacy

  • Financial values respect hideValues (masked as •••).
  • Anything sensitive carries .tabular-nums, .font-mono, or [data-ph-mask] so PostHog session replay masks it.

The masking rule is easy to break by accident: rendering a balance in a plain <span> without a numeric class leaks it into replay recordings. If a value is money, it gets one of those three classes — the mask is a side effect of following the typography rule, which is why the two rules are worth keeping coupled.

i18n

  • Every user-facing string goes through useT().
  • No hardcoded English in a component.
  • Number formatting respects the numberFormat preference, not a hardcoded locale.

On this page