Skip to main content

Design System

Bilko Design System

Source: Extracted from apps/web/tailwind.config.ts + brand identity spec Design Language: Modern Balkan accounting SaaS — clean, professional, accessible


Token Architecture Overview

graph TD
    TC["tailwind.config.ts\n(73 design tokens)"]

    TC --> COLORS["Color Tokens"]
    TC --> TYPE["Typography Tokens"]
    TC --> SPACE["Spacing Tokens"]
    TC --> RADIUS["Border Radius Tokens"]
    TC --> SHADOW["Shadow Tokens"]
    TC --> BP["Breakpoint Tokens"]

    COLORS --> PRIMARY["Primary Brand\n#00E5A0 / #00B380 / #33EBB3"]
    COLORS --> STATUS["Status Colors\nsuccess / warning / error / info"]
    COLORS --> TEXT["Text Scale\nprimary / secondary / muted"]
    COLORS --> BG["Backgrounds\nlight #FAFAFA / surface #FFF"]
    COLORS --> SIDEBAR["Sidebar (Dark Theme)\nbg / text / text-muted / active / hover"]
    COLORS --> CHART["Chart Colors\nrevenue / expense / profit / neutral"]

    TYPE --> FONT["Inter (Google Fonts)\nxs 12px → 4xl 40px"]
    TYPE --> WEIGHT["Weights\n400 / 500 / 600 / 700"]

    SPACE --> GRID["8px Grid\nxs 4px → 3xl 64px"]

    RADIUS --> SIZES["6px / 8px / 12px / full"]

    SHADOW --> ELEV["card / modal / dropdown"]

    BP --> SCREEN["640px / 768px / 1024px / 1280px"]

Color Palette

Primary Brand Colors

Primary:        #00E5A0  (Vibrant teal-green — primary CTA, links, active states)
Primary Dark:   #00B380  (Darker variant for hover states)
Primary Light:  #33EBB3  (Lighter variant for backgrounds)

Status Colors

Success:        #22C55E  (Green — success states, paid invoices, positive metrics)
Warning:        #F59E0B  (Amber — warnings, pending items, aging invoices)
Error:          #EF4444  (Red — errors, overdue invoices, negative actions)
Info:           #3B82F6  (Blue — informational messages, neutral data)

Text Colors

Text Primary:   #111113  (Near-black — body text, headings)
Text Secondary: #6B7280  (Gray-600 — secondary text, labels)
Text Muted:     #888888  (Gray-500 — muted text, placeholders)

Background Colors

Background Light:   #FAFAFA  (Off-white — main content area background)
Background Surface: #FFFFFF  (White — card backgrounds, modals)

Border Color

Border:         #E5E7EB  (Gray-200 — borders, dividers)

Chart Colors

Chart Revenue:  #22C55E  (Green — revenue bars/lines)
Chart Expense:  #EF4444  (Red — expense bars/lines)
Chart Profit:   #3B82F6  (Blue — profit bars/lines)
Chart Neutral:  #6B7280  (Gray — neutral data points)

Sidebar Colors (Dark Theme)

Sidebar BG:         #111113  (Near-black — sidebar background)
Sidebar Text:       #FAFAFA  (Off-white — sidebar text)
Sidebar Text Muted: #888888  (Gray — inactive menu items)
Sidebar Active:     #00E5A0  (Primary green — active menu item)
Sidebar Hover:      #1F1F23  (Slightly lighter black — hover state)

Usage:

  • Sidebar = dark (#111113) with light text
  • Content area = light (#FAFAFA) with dark text
  • Cards = white (#FFFFFF) surface on light background

Color Relationship Map

graph LR
    subgraph BRAND["Brand Identity"]
        P["Primary\n#00E5A0"]
        PD["Primary Dark\n#00B380\n(hover)"]
        PL["Primary Light\n#33EBB3\n(bg tint)"]
        P --> PD
        P --> PL
    end

    subgraph LAYOUT["Layout Zones"]
        SBG["Sidebar BG\n#111113"]
        SBG --> STEXT["Sidebar Text\n#FAFAFA"]
        SBG --> SMUTED["Sidebar Muted\n#888888"]
        SBG --> SACTIVE["Active Item\n#00E5A0"]

        CBG["Content BG\n#FAFAFA"]
        CBG --> SURF["Card Surface\n#FFFFFF"]
        CBG --> BORDER["Border\n#E5E7EB"]
    end

    subgraph SEMANTIC["Semantic Status"]
        SUCCESS["Success\n#22C55E\n(paid, positive)"]
        WARN["Warning\n#F59E0B\n(pending, aging)"]
        ERR["Error\n#EF4444\n(overdue, delete)"]
        INFO["Info\n#3B82F6\n(neutral data)"]
    end

    subgraph TEXT_SCALE["Text Scale"]
        TP["Text Primary\n#111113"]
        TS["Text Secondary\n#6B7280"]
        TM["Text Muted\n#888888"]
    end

    P -->|"active states"| SACTIVE
    SUCCESS -->|"chart-revenue"| CR["Chart Revenue"]
    ERR -->|"chart-expense"| CE["Chart Expense"]
    INFO -->|"chart-profit"| CP["Chart Profit"]

Typography

Font Family

Sans Serif: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif

Source: Google Fonts Inter (variable font) Fallback: System UI fonts for performance

Font Sizes

xs:   12px  (Small badges, captions)
sm:   14px  (Table cells, secondary text, form labels)
base: 16px  (Body text, default)
lg:   18px  (Subheadings, emphasized text)
xl:   20px  (Section titles)
2xl:  24px  (Card titles, small headings)
3xl:  32px  (Page headings)
4xl:  40px  (Hero text, large numbers)

Font Weights

normal:    400  (Body text)
medium:    500  (Emphasis, table headers)
semibold:  600  (Subheadings, button text)
bold:      700  (Headings, metric numbers)

Type Scale Usage

  • Headings:
    • Page title: text-3xl font-bold (32px, 700)
    • Section title: text-2xl font-bold (24px, 700)
    • Card title: text-base font-semibold (16px, 600)
  • Body:
    • Default: text-base font-normal (16px, 400)
    • Table cells: text-sm font-medium (14px, 500)
    • Muted text: text-sm text-text-muted (14px, #888888)
  • Numbers:
    • Metrics: text-3xl font-bold (32px, 700)
    • Totals: text-2xl font-bold (24px, 700)
    • Amounts: text-base font-medium (16px, 500)

Spacing System (8px Grid)

xs:  4px   (Tight spacing, icon gaps)
sm:  8px   (Input padding, small gaps)
md:  16px  (Default spacing, card padding)
lg:  24px  (Section spacing)
xl:  32px  (Large section spacing)
2xl: 48px  (Major section breaks)
3xl: 64px  (Hero spacing)

Usage:

  • Card padding: p-6 (24px)
  • Form field gap: space-y-4 (16px)
  • Section spacing: space-y-6 (24px)
  • Grid gap: gap-6 (24px)

Consistency: All spacing uses 8px increments (4px, 8px, 16px, 24px, 32px, 48px, 64px)


Border Radius

sm:   6px   (Small elements, badges)
md:   8px   (Buttons, inputs, cards)
lg:   12px  (Modals, large cards)
full: 9999px (Circular elements, pills)

Usage:

  • Cards: rounded-md (8px)
  • Buttons: rounded-md (8px)
  • Inputs: rounded-md (8px)
  • Badges: rounded-sm (6px)
  • User avatar: rounded-full (circular)

Shadows

Card Shadow:     0 2px 8px rgba(0, 0, 0, 0.08)   (Subtle card elevation)
Modal Shadow:    0 8px 24px rgba(0, 0, 0, 0.12)  (Dialog/modal elevation)
Dropdown Shadow: 0 4px 16px rgba(0, 0, 0, 0.10)  (Dropdown menu elevation)

Usage:

  • Cards: shadow-card
  • Modals/dialogs: shadow-modal
  • Dropdown menus: shadow-dropdown

Philosophy: Subtle shadows for depth, avoid heavy shadows (material design style)


Design Token Relationships

classDiagram
    class ButtonTokens {
        +height_default: 40px
        +height_sm: 32px
        +height_lg: 48px
        +padding_x: 16px
        +border_radius: 8px (md)
        +font_size: 14px medium
        +variant_default: primary-bg white-text
        +variant_outline: border-only transparent
        +variant_ghost: no-border no-bg
        +variant_destructive: error-red white-text
    }

    class InputTokens {
        +height: 40px
        +padding_x: 12px
        +border: 1px solid #E5E7EB
        +border_radius: 8px (md)
        +font_size: 14px normal
        +focus_ring: 2px primary-color
    }

    class CardTokens {
        +background: #FFFFFF
        +border: 1px solid #E5E7EB
        +border_radius: 8px (md)
        +shadow: 0 2px 8px rgba-8pct
        +padding: 24px
    }

    class BadgeTokens {
        +padding: 4px 8px
        +border_radius: 6px (sm)
        +font_size: 12px medium
        +variant_success: green-bg
        +variant_warning: amber-bg
        +variant_destructive: red-bg
        +variant_secondary: light-gray-bg
    }

    class TableTokens {
        +row_height: 48px
        +cell_padding_x: 12px
        +cell_padding_y: 16px
        +border: 1px solid #E5E7EB
        +hover: light-gray #FAFAFA
        +header_weight: medium
        +header_color: text-secondary
    }

    class ColorTokens {
        +primary: #00E5A0
        +primary_dark: #00B380
        +success: #22C55E
        +warning: #F59E0B
        +error: #EF4444
        +info: #3B82F6
        +text_primary: #111113
        +text_secondary: #6B7280
        +border: #E5E7EB
        +surface: #FFFFFF
        +bg_light: #FAFAFA
    }

    ButtonTokens --> ColorTokens : uses primary, error
    InputTokens --> ColorTokens : uses border, primary (focus)
    CardTokens --> ColorTokens : uses surface, border
    BadgeTokens --> ColorTokens : uses success, warning, error
    TableTokens --> ColorTokens : uses border, bg-light (hover)

Breakpoints

sm:  640px   (Small tablets, large phones)
md:  768px   (Tablets)
lg:  1024px  (Small desktops, large tablets)
xl:  1280px  (Desktops)

Mobile-First Strategy:

  • Base styles = mobile (< 640px)
  • sm: = small tablet (640px+)
  • md: = tablet/desktop toggle (768px+)
  • lg: = desktop layout (1024px+)
  • xl: = wide desktop (1280px+)

Responsive Patterns:

  • Grid: grid-cols-1 md:grid-cols-2 lg:grid-cols-3
  • Sidebar: hidden md:block (hide on mobile)
  • Filters: flex-col sm:flex-row (stack on mobile, row on tablet+)

Responsive Layout Behavior

graph TD
    subgraph MOBILE["Mobile (< 640px)"]
        M1["Sidebar: hidden\n(overlay when toggled)"]
        M2["TopBar: shows hamburger + logo"]
        M3["Grid: single column"]
        M4["Filters: stacked vertically"]
        M5["Tables: horizontal scroll"]
    end

    subgraph TABLET["Tablet (768px+)"]
        T1["Sidebar: visible, persistent"]
        T2["TopBar: shows search + user menu"]
        T3["Grid: 2 columns"]
        T4["Filters: row layout"]
        T5["Tables: full width"]
    end

    subgraph DESKTOP["Desktop (1024px+)"]
        D1["Sidebar: 256px fixed width"]
        D2["TopBar: full bar"]
        D3["Grid: 3 columns"]
        D4["Settings: sidebar + content split"]
        D5["Banking: full tab content"]
    end

Component Tokens

Button

  • Height: 40px (default), 32px (sm), 48px (lg), 40px (icon)
  • Padding: 16px horizontal (default), 12px (sm), 20px (lg)
  • Border Radius: 8px (md)
  • Font: 14px medium (default), 12px (sm), 16px (lg)
  • Variants:
    • Default: Primary green background, white text
    • Outline: Border only, transparent background
    • Ghost: No border, no background, hover shows background
    • Destructive: Error red background, white text

Input

  • Height: 40px
  • Padding: 12px horizontal
  • Border: 1px solid #E5E7EB (border color)
  • Border Radius: 8px (md)
  • Font: 14px normal
  • Focus: Primary color ring (2px)

Card

  • Background: #FFFFFF (surface)
  • Border: 1px solid #E5E7EB
  • Border Radius: 8px (md)
  • Shadow: 0 2px 8px rgba(0, 0, 0, 0.08)
  • Padding: 24px (default content padding)

Badge

  • Padding: 4px 8px
  • Border Radius: 6px (sm)
  • Font: 12px medium
  • Variants:
    • Default: Gray background
    • Success: Green background
    • Warning: Amber background
    • Destructive: Red background
    • Secondary: Light gray

Table

  • Row Height: 48px (default)
  • Cell Padding: 12px horizontal, 16px vertical
  • Border: 1px solid #E5E7EB (between rows)
  • Hover: Light gray background (#FAFAFA)
  • Header: Medium font weight, secondary text color

Icon System

Library: Lucide React (v0.469.0) Size: Consistent 16px (w-4 h-4) or 20px (w-5 h-5) Usage:

  • Buttons: 16px icon + 8px gap from text
  • Menu items: 20px icon + 12px gap from text
  • Standalone: 24px or larger

Common Icons:

  • Plus (add actions)
  • Search (search inputs)
  • Menu (mobile sidebar toggle)
  • User (user menu)
  • Bell (notifications)
  • ChevronDown/Right (expandable sections)
  • Check (success, reconciliation)
  • X (close, delete)
  • Download (export actions)
  • Send (send email)

Chart Design Tokens

Chart Colors (Recharts)

Revenue:  #22C55E  (Green bars)
Expense:  #EF4444  (Red bars)
Profit:   #3B82F6  (Blue bars)
Neutral:  #6B7280  (Gray — when no semantic meaning)

Chart Typography

  • Axis Labels: 12px normal
  • Tooltip: 14px medium
  • Legend: 12px normal

Chart Layout

  • Responsive Container: 100% width, fixed height (250px default)
  • Cartesian Grid: Dashed, #E5E7EB stroke
  • Tooltip Background: White with border
  • Border Radius: 8px (md)

Accessibility

Color Contrast

  • All text colors meet WCAG AA standards
  • Primary text (#111113) on white = 16.17:1 (AAA)
  • Secondary text (#6B7280) on white = 4.69:1 (AA)
  • Primary green (#00E5A0) on white = 2.92:1 (fails — used for accents only, not body text)

Focus Indicators

  • All interactive elements have visible focus ring
  • Focus ring color: Primary green (#00E5A0)
  • Focus ring width: 2px

Semantic HTML

  • Proper heading hierarchy (h1 → h2 → h3)
  • Form labels properly associated with inputs
  • ARIA labels on icon-only buttons
  • Table headers properly scoped

Design Principles

  1. Clarity over Decoration — Data-first, minimal ornamentation
  2. Consistent Spacing — 8px grid, predictable rhythm
  3. Accessible by Default — WCAG AA minimum, Radix UI primitives
  4. Mobile-First — Responsive from 375px+ (iPhone SE)
  5. Dark Sidebar + Light Content — Clear visual separation
  6. Primary Color as Accent — Green (#00E5A0) for actions, not backgrounds
  7. Subtle Shadows — Elevation without heaviness
  8. Data-Dense UI — Tables, charts, metrics — optimized for information density

Brand Identity Alignment

From ~/system/specs/bilko-brand-identity.md:

  • Primary Color: #00E5A0 (implemented)
  • Typography: Inter (implemented)
  • Tone: Modern, professional, Balkan-focused (implemented)
  • Dark Sidebar: #111113 (implemented)
  • Logo Placement: Top left sidebar (implemented)

Future Tokens (Phase 2)

When implementing API integration:

  • Loading States: Skeleton component colors
  • Error States: Error message backgrounds (#FEF2F2, light red)
  • Success States: Success message backgrounds (#F0FDF4, light green)
  • Toast Notifications: Background, text, border colors
  • Dark Mode: Full dark theme variant (optional)