Skip to content
SuperCoach

Developers

Everything in coach-admin's new UI reads from one set of CSS variables, generated from tokens/tokens.json. Components use semantic tokens such as bg-primary or text-muted-foreground, never a hex value.

Install

coach-admin moves to Tailwind CSS v4 and shadcn/ui. Add the generated stylesheet after Tailwind:

@import "tailwindcss";
@import "./tokens.css"; /* generated from tokens/tokens.json */

tokens.css holds:

  • every primitive as a CSS variable (--lime-300);
  • the semantic tokens for SuperCoach on :root, and the Coach overrides under [data-brand="coach"];
  • a Tailwind @theme that resets Tailwind's own colors, radii, type scale, shadows and easing, and defines only the tokens. A class such as bg-red-500 or shadow-2xs produces no CSS, so values outside the system can't slip in.

Two products, one stylesheet

SuperCoach is the default theme on :root. Coach overrides only the tokens that differ, under [data-brand="coach"]. The buttons below read --primary and --secondary, so they change as soon as they sit inside a Coach element. Switch the preview's theme and direction to compare.

Using tokens

NeedTailwindCSS
A semantic colorbg-card text-card-foregroundvar(--card)
Spacingp-4 gap-2--spacing(4)
Radiusrounded-lgvar(--radius-lg)
Shadowshadow-mdvar(--shadow-md)
Layerz-(--z-modal)var(--z-modal)
Motionduration-(--duration-base) ease-standardvar(--duration-base)

Every token page has a copy button for each of these. Never use a primitive (var(--lime-300)) in a component.

Right-to-left

Set dir="rtl" and lang="ar" on <html> for Arabic. Use logical utilities (ps-4, me-2, start-0) instead of left and right, so layouts mirror without extra CSS. Text inside lang="ar" switches to Lama Sans automatically. More on the RTL page.

<html lang="ar" dir="rtl" data-brand="coach">

The direction switch in this site's header only sets dir, because the site's own copy stays in English; previews add lang="ar" with their Arabic copy.

Root font size

Migrating from SCSS

Replace each SCSS color variable with its semantic token. The full table, with every variable found in coach-admin, is searchable below; it is also on the Color page.

Audit action

127 of 127 variables

coach-admin SCSS color variables and the tokens that replace them
SCSS variableTodayUse this tokenNearest primitive (ΔE)Action
$white-text-color893 uses#FFFFFF--primary-foregroundwhite (0)keep
$primary-color464 uses#2A46CB--primarybrand-600 (0)keep
$black-text-color278 uses#000000--foregroundDiffers from the nearest primitive: the semantic token wins.black (0)keep
$dark-text-color224 uses#1D2939--foregroundDiffers from the nearest primitive: the semantic token wins.neutral-900 (3.7)merge
$grey-text-color165 uses#4D4D4D--foreground-secondaryneutral-700 (1.1)merge
$subtitle-text-color119 uses#667085--muted-foregroundneutral-600 (5.7)review
$todo-text-muted119 uses#667085No semantic token yetneutral-600 (5.7)review
$color118 uses#3B5998No semantic token yet—social brand (CoreUI social-button loop, $color)exclude
$facebook118 uses#3B5998No semantic token yet—social brand (CoreUI social-button loop, $color)exclude
$invoice-ink-secondary90 uses#5A6070--foreground-secondaryDiffers from the nearest primitive: the semantic token wins.neutral-600 (2.9)merge
$secondary-color71 uses#FF6D38No semantic token yetorange-500 (0)keep
$light-surface-bg68 uses#F5F5F7--mutedDiffers from the nearest primitive: the semantic token wins.neutral-50 (0.8)merge
$border-color52 uses#E4E4E4--borderneutral-200 (0.9)merge
$invoice-surface-bg42 uses#F8F9FCNo semantic token yetneutral-50 (0.4)merge
$error-color37 uses#FF6868--destructiveDiffers from the nearest primitive: the semantic token wins.red-500 (7.5)review
$todo-text-sub34 uses#6B7280No semantic token yetneutral-500 (5.4)review
$ai-darker-text33 uses#1E1E1ENo semantic token yetneutral-950 (2.2)merge
$danger-text-color32 uses#B91C1C--destructive-textred-700 (0)keep
$navbar-color31 uses#536C79No semantic token yetneutral-600 (4)merge
$sidebar-nav-link-icon-color31 uses#536C79No semantic token yetneutral-600 (4)merge
$scpay-ink-strong30 uses#344054No semantic token yetneutral-700 (5.5)review
$media-surface-bg29 uses#F0F0F0--mutedneutral-100 (0.3)merge
$success-color23 uses#4DBD74No semantic token yetgreen-500 (4.6)merge
$invoice-muted-text21 uses#9199A8No semantic token yetneutral-400 (4.4)merge
$invoice-warn-text21 uses#92400E--warning-textamber-800 (0)keep
$warning-text-color21 uses#92400E--warning-textamber-800 (0)keep
$todo-med-badge-fg21 uses#92400ENo semantic token yetamber-800 (0)keep
$danger-color21 uses#EF4444--destructiveDiffers from the nearest primitive: the semantic token wins.red-500 (0)keep
$todo-overdue-text21 uses#EF4444No semantic token yetred-500 (0)keep
$todo-high-bar21 uses#EF4444No semantic token yetred-500 (0)keep
$scpay-neutral-bg19 uses#F2F4F7--mutedneutral-100 (1.1)merge
$warning-bg-color18 uses#FFFBEBNo semantic token yetamber-50 (0)keep
$warning-color18 uses#D97706No semantic token yetamber-600 (0)keep
$checkbox-unchecked18 uses#EEEEEENo semantic token yetneutral-100 (0.7)merge
$input-placeholder-color16 uses#C0C0C0No semantic token yetneutral-300 (6.2)review
$danger-bg-color16 uses#FEE2E2--destructive-subtleDiffers from the nearest primitive: the semantic token wins.red-100 (0)keep
$todo-high-badge-bg16 uses#FEE2E2No semantic token yetred-100 (0)keep
$ai-light-gray-bg15 uses#F8F8F8No semantic token yetneutral-50 (0.2)merge
$sidebar-bg15 uses#29363DNo semantic token yetneutral-800 (2.2)merge
$navbar-active-color15 uses#29363DNo semantic token yetneutral-800 (2.2)merge
$aside-menu-color15 uses#29363DNo semantic token yetneutral-800 (2.2)merge
$input-affix-color13 uses#91939ENo semantic token yetneutral-400 (5.6)review
$upgrade-gradient13 uses#982CB1No semantic token yetviolet-ai-500 (10)review
$upgrade-gradient-hover13 uses#982CB1No semantic token yetviolet-ai-500 (10)review
$invoice-sar-bg13 uses#F0FDF4--success-subtlegreen-50 (0)keep
$success-surface-bg13 uses#F0FDF4No semantic token yetgreen-50 (0)keep
$invoice-usd-color12 uses#1D4ED8--infoblue-700 (0)keep
$success-text-color11 uses#15803D--success-textgreen-700 (0)keep
$invoice-net-color11 uses#15803D--success-textgreen-700 (0)keep
$invoice-sar-color11 uses#16A34A--successgreen-600 (0)keep
$todo-low-badge-fg11 uses#16A34ANo semantic token yetgreen-600 (0)keep
$dropdown-divider-bg10 uses#F0F3F5No semantic token yetneutral-100 (0.7)merge
$footer-bg10 uses#F0F3F5No semantic token yetneutral-100 (0.7)merge
$gray-10010 uses#F0F3F5No semantic token yetneutral-100 (0.7)merge
$disable-color10 uses#B0B0B0No semantic token yetneutral-400 (3.9)merge
$invoice-usd-bg9 uses#EFF6FF--info-subtleDiffers from the nearest primitive: the semantic token wins.neutral-50 (1.5)merge
$border-strong-color9 uses#C8CDD8--border-strongneutral-300 (2.7)merge
$todo-low-bar9 uses#22C55ENo semantic token yetgreen-500 (0)keep
$ai-light-text9 uses#5F5F5FNo semantic token yetneutral-600 (1.4)merge
$overlay-body-text-color9 uses#5F5F5FNo semantic token yetneutral-600 (1.4)merge
$checkbox-hover9 uses#CCCCCCNo semantic token yetneutral-300 (2.5)merge
$invoice-section-line8 uses#E2E5ECNo semantic token yetneutral-200 (1)merge
$success-text-strong8 uses#166534No semantic token yetlime-800 (3.7)merge
$warning-border-color8 uses#FDE68ANo semantic token yetamber-200 (0)keep
$ai-secondary-text8 uses#4A4A4ANo semantic token yetneutral-700 (0)keep
$ai-icon-hover8 uses#4A4A4ANo semantic token yetneutral-700 (0)keep
$danger-border-color7 uses#FCA5A5No semantic token yetred-300 (0)keep
$invoice-egp-bg7 uses#FFF7EDNo semantic token yetorange-50 (0.3)merge
$invoice-sar-border7 uses#86EFACNo semantic token yetgreen-300 (0)keep
$success-border-color7 uses#86EFACNo semantic token yetgreen-300 (0)keep
$ai-dark-text7 uses#777777No semantic token yetneutral-500 (3.1)merge
$gray-2007 uses#C2CFD6No semantic token yetneutral-300 (2.9)merge
$sidebar-nav-title-color7 uses#C2CFD6No semantic token yetneutral-300 (2.9)merge
$dropdown-border-color7 uses#C2CFD6No semantic token yetneutral-300 (2.9)merge
$form-row-bg6 uses#FBFBFDNo semantic token yetneutral-50 (1)merge
$invoice-egp-color6 uses#C2410CNo semantic token yetorange-700 (3.4)merge
$paid-experience-muted-text-color6 uses#6F7389No semantic token yetneutral-500 (5.3)review
$scpay-primary-tint6 uses#EEF1FC--accentbrand-50 (1.1)merge
$todo-text-title6 uses#1A1D23No semantic token yetneutral-950 (2.1)merge
$todo-high-badge-fg6 uses#DC2626No semantic token yetred-600 (0)keep
$scpay-row-line6 uses#EAECF0--borderDiffers from the nearest primitive: the semantic token wins.neutral-100 (1.3)merge
$scpay-muted-dot6 uses#98A2B3No semantic token yetneutral-400 (2.9)merge
$scroll-thumb-color6 uses#C7C6CCNo semantic token yetneutral-300 (4.2)merge
$invoice-egp-border5 uses#FDBA74No semantic token yetorange-300 (0.6)merge
$invoice-usd-border5 uses#BFDBFENo semantic token yetblue-200 (0)keep
$timeline-line-color5 uses#F2F4FANo semantic token yetneutral-100 (1.3)merge
$medium-grey-text-color-hover4 uses#232323No semantic token yetneutral-900 (0.8)merge
$todo-low-badge-bg4 uses#DCFCE7No semantic token yetgreen-100 (0)keep
$proof-accent-color4 uses#7ACA14No semantic token yetlime-500 (2.3)merge
$medium-grey-text-color4 uses#3E3E3E--foreground-secondaryDiffers from the nearest primitive: the semantic token wins.neutral-800 (4.3)merge
$verification-flag-gradient4 uses#A324A3No semantic token yetviolet-ai-500 (12.1)review
$ai-accent-color4 uses#7C5CBF--aiviolet-ai-500 (0)keep
$verification-pulse-color3 uses#43D426No semantic token yetlime-500 (2.7)merge
$secondary-color-hover3 uses#EDC2AENo semantic token yetred-200 (4.7)merge
$todo-med-bar3 uses#F59E0BNo semantic token yetamber-500 (0)keep
$todo-page-bg3 uses#F5F6FANo semantic token yetneutral-50 (0.6)merge
$todo-med-badge-bg3 uses#FEF3C7No semantic token yetamber-100 (0)keep
$invoice-tabby-color3 uses#6B36C9No semantic token yet—3rd-party brand (Tabby)exclude
$invoice-tamara-color3 uses#B23A1ENo semantic token yet—3rd-party brand (Tamara)exclude
$paid-experience-check-bg3 uses#EDF2FFNo semantic token yetbrand-50 (1)merge
$proof-quote-mark-color3 uses#C3C8D4No semantic token yetneutral-300 (4.1)merge
$scpay-primary-tint-border3 uses#D6DCF5No semantic token yetblue-200 (3.1)merge
$sticky-bg-color3 uses#F5F7FANo semantic token yetneutral-50 (0.4)merge
$scroll-thumb-hover-color3 uses#A7A4ADNo semantic token yetneutral-400 (1.4)merge
$twitter2 uses#00ACEDNo semantic token yet—social brandexclude
$nav-color2 uses#060606--sidebarneutral-950 (9.1)review
$ai-message-text2 uses#363638No semantic token yetneutral-800 (1.3)merge
$todo-grouped-border2 uses#3B4FCBNo semantic token yetbrand-600 (3)merge
$linkedin2 uses#4875B4No semantic token yet—social brandexclude
$ai-accent-text-color2 uses#5F3F9E--ai-foregroundviolet-ai-700 (0)keep
$overlay-muted-text-color2 uses#64748BNo semantic token yetnavy-500 (4.9)merge
$ai-lighter-text2 uses#727272No semantic token yetneutral-500 (4.8)merge
$ai-icon-gray2 uses#75787FNo semantic token yetneutral-500 (3)merge
$ai-primary-color2 uses#8A4FFFNo semantic token yetviolet-ai-500 (10.4)review
$checkbox-border-color2 uses#8A93A6No semantic token yetneutral-400 (6.4)review
$paid-experience-discount-bg2 uses#91EC6BNo semantic token yetlime-300 (5.5)review
$scpay-refund-text2 uses#9A3412No semantic token yetorange-800 (2.6)merge
$ai-footer-placeholder2 uses#B7B7B7No semantic token yetneutral-400 (6.1)review
$paid-experience-toggle-bg2 uses#CFD5DFNo semantic token yetneutral-300 (1.4)merge
$google-plus2 uses#D34836No semantic token yetred-600 (4.2)merge
$cell-border-color2 uses#EBEDEFNo semantic token yetneutral-100 (1.1)merge
$paid-experience-header-bg2 uses#EEF2FF--accentbrand-50 (0.9)merge
$invoice-tabby-bg2 uses#F2EAFENo semantic token yet—3rd-party brand (Tabby)exclude
$paid-experience-panel-bg2 uses#F7F7FCNo semantic token yetneutral-50 (0.5)merge
$row-hover-bg2 uses#FAFAFCNo semantic token yetneutral-50 (0.7)merge
$invoice-tamara-bg2 uses#FFF0E6No semantic token yet—3rd-party brand (Tamara)exclude
$invoice-due-row-bg2 uses#FFFDF4--warning-subtleDiffers from the nearest primitive: the semantic token wins.white (1.4)merge

Spacing, radius and font sizes snap to the nearest step; see Spacing and Typography.

Regenerating tokens

pnpm tokens

pnpm dev watches tokens/tokens.json, so a changed value shows up on every page without a restart.

Related: Designers, Tokens, Color.