coolify/.ai/design-system.md
Andras Bacsai 425eff0a58 docs: add Coolify design system reference
Add comprehensive AI/LLM-consumable design system documentation covering:
- Design tokens (colors, typography, spacing, shadows, focus rings)
- Dark mode strategy with accent color swaps and background hierarchy
- Component catalog (buttons, inputs, selects, cards, navigation, modals, etc.)
- Interactive state reference (focus, hover, disabled, readonly)
- CSS custom properties for theme tokens

Includes both Tailwind CSS classes and plain CSS equivalents for all components.
2026-02-01 19:02:31 +01:00

39 KiB
Raw Permalink Blame History

Coolify Design System

Purpose: AI/LLM-consumable reference for replicating Coolify's visual design in new applications. Contains design tokens, component styles, and interactive states — with both Tailwind CSS classes and plain CSS equivalents.


1. Design Tokens

1.1 Colors

Brand / Accent

Token Hex Usage
coollabs #6b16ed Primary accent (light mode)
coollabs-50 #f5f0ff Highlighted button bg (light)
coollabs-100 #7317ff Highlighted button hover (dark)
coollabs-200 #5a12c7 Highlighted button text (light)
coollabs-300 #4a0fa3 Deepest brand shade
warning / warning-400 #fcd452 Primary accent (dark mode)

Warning Scale (used for dark-mode accent + callouts)

Token Hex
warning-50 #fefce8
warning-100 #fef9c3
warning-200 #fef08a
warning-300 #fde047
warning-400 #fcd452
warning-500 #facc15
warning-600 #ca8a04
warning-700 #a16207
warning-800 #854d0e
warning-900 #713f12

Neutral Grays (dark mode backgrounds)

Token Hex Usage
base #101010 Page background (dark)
coolgray-100 #181818 Component background (dark)
coolgray-200 #202020 Elevated surface / borders (dark)
coolgray-300 #242424 Input border shadow / hover (dark)
coolgray-400 #282828 Tooltip background (dark)
coolgray-500 #323232 Subtle hover overlays (dark)

Semantic

Token Hex Usage
success #22C55E Running status, success alerts
error #dc2626 Stopped status, danger actions, error alerts

Light Mode Defaults

Element Color
Page background gray-50 (#f9fafb)
Component background white (#ffffff)
Borders neutral-200 (#e5e5e5)
Primary text black (#000000)
Muted text neutral-500 (#737373)
Placeholder text neutral-300 (#d4d4d4)

1.2 Typography

Font family: Inter, sans-serif (weights 100900, woff2, font-display: swap)

Heading Hierarchy

CRITICAL: All headings and titles (h1h4, card titles, modal titles) MUST be white (#fff) in dark mode. The default body text color is neutral-400 (#a3a3a3) — headings must override this to white or they will be nearly invisible on dark backgrounds.

Element Tailwind Plain CSS (light) Plain CSS (dark)
h1 text-3xl font-bold dark:text-white font-size: 1.875rem; font-weight: 700; color: #000; color: #fff;
h2 text-xl font-bold dark:text-white font-size: 1.25rem; font-weight: 700; color: #000; color: #fff;
h3 text-lg font-bold dark:text-white font-size: 1.125rem; font-weight: 700; color: #000; color: #fff;
h4 text-base font-bold dark:text-white font-size: 1rem; font-weight: 700; color: #000; color: #fff;

Body Text

Context Tailwind Plain CSS
Body default text-sm antialiased font-size: 0.875rem; line-height: 1.25rem; -webkit-font-smoothing: antialiased;
Labels text-sm font-medium font-size: 0.875rem; font-weight: 500;
Badge/status text text-xs font-bold font-size: 0.75rem; line-height: 1rem; font-weight: 700;
Box description text-xs font-bold text-neutral-500 font-size: 0.75rem; font-weight: 700; color: #737373;

1.3 Spacing Patterns

Context Value CSS
Component internal padding p-2 padding: 0.5rem;
Callout padding p-4 padding: 1rem;
Input vertical padding py-1.5 padding-top: 0.375rem; padding-bottom: 0.375rem;
Button height h-8 height: 2rem;
Button horizontal padding px-2 padding-left: 0.5rem; padding-right: 0.5rem;
Button gap gap-2 gap: 0.5rem;
Menu item padding px-2 py-1 padding: 0.25rem 0.5rem;
Menu item gap gap-3 gap: 0.75rem;
Section margin mb-12 margin-bottom: 3rem;
Card min-height min-h-[4rem] min-height: 4rem;

1.4 Border Radius

Context Tailwind Plain CSS
Default (inputs, buttons, cards, modals) rounded-sm border-radius: 0.125rem;
Callouts rounded-lg border-radius: 0.5rem;
Badges rounded-full border-radius: 9999px;
Cards (coolbox variant) rounded border-radius: 0.25rem;

1.5 Shadows

Input / Select Box-Shadow System

Coolify uses inset box-shadows instead of borders for inputs and selects. This enables a unique "dirty indicator" — a colored left-edge bar.

/* Default state */
box-shadow: inset 4px 0 0 transparent, inset 0 0 0 2px #e5e5e5;

/* Default state (dark) */
box-shadow: inset 4px 0 0 transparent, inset 0 0 0 2px #242424;

/* Focus state (light) — purple left bar */
box-shadow: inset 4px 0 0 #6b16ed, inset 0 0 0 2px #e5e5e5;

/* Focus state (dark) — yellow left bar */
box-shadow: inset 4px 0 0 #fcd452, inset 0 0 0 2px #242424;

/* Dirty (modified) state — same as focus */
box-shadow: inset 4px 0 0 #6b16ed, inset 0 0 0 2px #e5e5e5;  /* light */
box-shadow: inset 4px 0 0 #fcd452, inset 0 0 0 2px #242424;  /* dark */

/* Disabled / Readonly */
box-shadow: none;

Input-Sticky Variant (thinner border)

/* Uses 1px border instead of 2px */
box-shadow: inset 4px 0 0 transparent, inset 0 0 0 1px #e5e5e5;

1.6 Focus Ring System

All interactive elements (buttons, links, checkboxes) share this focus pattern:

Tailwind:

focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-coollabs dark:focus-visible:ring-warning focus-visible:ring-offset-2 dark:focus-visible:ring-offset-base

Plain CSS:

:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px #101010, 0 0 0 4px #6b16ed; /* light */
}

/* dark mode */
.dark :focus-visible {
  box-shadow: 0 0 0 2px #101010, 0 0 0 4px #fcd452;
}

Note

: Inputs use the inset box-shadow system (section 1.5) instead of the ring system.


2. Dark Mode Strategy

  • Toggle method: Class-based — .dark class on <html> element
  • CSS variant: @custom-variant dark (&:where(.dark, .dark *));
  • Default border override: All elements default to border-color: var(--color-coolgray-200) (#202020) instead of currentcolor

Accent Color Swap

Context Light Dark
Primary accent coollabs (#6b16ed) warning (#fcd452)
Focus ring ring-coollabs ring-warning
Input focus bar #6b16ed (purple) #fcd452 (yellow)
Active nav text text-black text-warning
Helper/highlight text text-coollabs text-warning
Loading spinner text-coollabs text-warning
Scrollbar thumb coollabs-100 coollabs-100

Background Hierarchy (dark)

#101010 (base)          — page background
  └─ #181818 (coolgray-100) — cards, inputs, components
       └─ #202020 (coolgray-200) — elevated surfaces, borders, nav active
            └─ #242424 (coolgray-300) — input borders (via box-shadow), button borders
                 └─ #282828 (coolgray-400) — tooltips, hover states
                      └─ #323232 (coolgray-500) — subtle overlays

Background Hierarchy (light)

#f9fafb (gray-50)       — page background
  └─ #ffffff (white)      — cards, inputs, components
       └─ #e5e5e5 (neutral-200) — borders
            └─ #f5f5f5 (neutral-100) — hover backgrounds
                 └─ #d4d4d4 (neutral-300) — deeper hover, nav active

3. Component Catalog

3.1 Button

Default

Tailwind:

flex gap-2 justify-center items-center px-2 h-8 text-sm text-black normal-case rounded-sm
border-2 outline-0 cursor-pointer font-medium bg-white border-neutral-200 hover:bg-neutral-100
dark:bg-coolgray-100 dark:text-white dark:hover:text-white dark:hover:bg-coolgray-200
dark:border-coolgray-300 hover:text-black disabled:cursor-not-allowed min-w-fit
dark:disabled:text-neutral-600 disabled:border-transparent disabled:hover:bg-transparent
disabled:bg-transparent disabled:text-neutral-300
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-coollabs
dark:focus-visible:ring-warning focus-visible:ring-offset-2 dark:focus-visible:ring-offset-base

Plain CSS:

.button {
  display: flex;
  gap: 0.5rem;
  justify-content: center;
  align-items: center;
  padding: 0 0.5rem;
  height: 2rem;
  font-size: 0.875rem;
  font-weight: 500;
  text-transform: none;
  color: #000;
  background: #fff;
  border: 2px solid #e5e5e5;
  border-radius: 0.125rem;
  outline: 0;
  cursor: pointer;
  min-width: fit-content;
}
.button:hover { background: #f5f5f5; }

/* Dark */
.dark .button {
  background: #181818;
  color: #fff;
  border-color: #242424;
}
.dark .button:hover {
  background: #202020;
  color: #fff;
}

/* Disabled */
.button:disabled {
  cursor: not-allowed;
  border-color: transparent;
  background: transparent;
  color: #d4d4d4;
}
.dark .button:disabled { color: #525252; }

Highlighted (Primary Action)

Tailwind (via isHighlighted attribute):

text-coollabs-200 dark:text-white bg-coollabs-50 dark:bg-coollabs/20
border-coollabs dark:border-coollabs-100 hover:bg-coollabs hover:text-white
dark:hover:bg-coollabs-100 dark:hover:text-white

Plain CSS:

.button-highlighted {
  color: #5a12c7;
  background: #f5f0ff;
  border-color: #6b16ed;
}
.button-highlighted:hover {
  background: #6b16ed;
  color: #fff;
}
.dark .button-highlighted {
  color: #fff;
  background: rgba(107, 22, 237, 0.2);
  border-color: #7317ff;
}
.dark .button-highlighted:hover {
  background: #7317ff;
  color: #fff;
}

Error / Danger

Tailwind (via isError attribute):

text-red-800 dark:text-red-300 bg-red-50 dark:bg-red-900/30
border-red-300 dark:border-red-800 hover:bg-red-300 hover:text-white
dark:hover:bg-red-800 dark:hover:text-white

Plain CSS:

.button-error {
  color: #991b1b;
  background: #fef2f2;
  border-color: #fca5a5;
}
.button-error:hover {
  background: #fca5a5;
  color: #fff;
}
.dark .button-error {
  color: #fca5a5;
  background: rgba(127, 29, 29, 0.3);
  border-color: #991b1b;
}
.dark .button-error:hover {
  background: #991b1b;
  color: #fff;
}

Loading Indicator

Buttons automatically show a spinner (SVG with animate-spin) next to their content during async operations. The spinner uses the accent color (text-coollabs / text-warning).


3.2 Input

Tailwind:

block py-1.5 w-full text-sm text-black rounded-sm border-0
dark:bg-coolgray-100 dark:text-white
disabled:bg-neutral-200 disabled:text-neutral-500 dark:disabled:bg-coolgray-100/40
dark:read-only:text-neutral-500 dark:read-only:bg-coolgray-100/40
placeholder:text-neutral-300 dark:placeholder:text-neutral-700
read-only:text-neutral-500 read-only:bg-neutral-200
focus-visible:outline-none

Plain CSS:

.input {
  display: block;
  padding: 0.375rem 0.5rem;
  width: 100%;
  font-size: 0.875rem;
  color: #000;
  background: #fff;
  border: 0;
  border-radius: 0.125rem;
  box-shadow: inset 4px 0 0 transparent, inset 0 0 0 2px #e5e5e5;
}
.input:focus-visible {
  outline: none;
  box-shadow: inset 4px 0 0 #6b16ed, inset 0 0 0 2px #e5e5e5;
}
.input::placeholder { color: #d4d4d4; }
.input:disabled { background: #e5e5e5; color: #737373; box-shadow: none; }
.input:read-only { color: #737373; background: #e5e5e5; box-shadow: none; }
.input[type="password"] { padding-right: 2.4rem; }

/* Dark */
.dark .input {
  background: #181818;
  color: #fff;
  box-shadow: inset 4px 0 0 transparent, inset 0 0 0 2px #242424;
}
.dark .input:focus-visible {
  box-shadow: inset 4px 0 0 #fcd452, inset 0 0 0 2px #242424;
}
.dark .input::placeholder { color: #404040; }
.dark .input:disabled { background: rgba(24, 24, 24, 0.4); box-shadow: none; }
.dark .input:read-only { color: #737373; background: rgba(24, 24, 24, 0.4); box-shadow: none; }

Dirty (Modified) State

When an input value has been changed but not saved, a 4px colored left bar appears via box-shadow — same colors as focus state. This provides a visual indicator that the field has unsaved changes.


3.3 Select

Same base styles as Input, plus a custom dropdown arrow SVG:

Tailwind:

w-full block py-1.5 text-sm text-black rounded-sm border-0
dark:bg-coolgray-100 dark:text-white
disabled:bg-neutral-200 disabled:text-neutral-500 dark:disabled:bg-coolgray-100/40
focus-visible:outline-none

Additional plain CSS for the dropdown arrow:

.select {
  /* ...same as .input base... */
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke-width='1.5' stroke='%23000000'%3e%3cpath stroke-linecap='round' stroke-linejoin='round' d='M8.25 15L12 18.75 15.75 15m-7.5-6L12 5.25 15.75 9'/%3e%3c/svg%3e");
  background-position: right 0.5rem center;
  background-repeat: no-repeat;
  background-size: 1rem 1rem;
  padding-right: 2.5rem;
  appearance: none;
}

/* Dark mode: white stroke arrow */
.dark .select {
  background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 24 24' stroke-width='1.5' stroke='%23ffffff'%3e%3cpath stroke-linecap='round' stroke-linejoin='round' d='M8.25 15L12 18.75 15.75 15m-7.5-6L12 5.25 15.75 9'/%3e%3c/svg%3e");
}

3.4 Checkbox

Tailwind:

dark:border-neutral-700 text-coolgray-400 dark:bg-coolgray-100 rounded-sm cursor-pointer
dark:disabled:bg-base dark:disabled:cursor-not-allowed
focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-coollabs
dark:focus-visible:ring-warning focus-visible:ring-offset-2 dark:focus-visible:ring-offset-base

Container:

flex flex-row items-center gap-4 pr-2 py-1 form-control min-w-fit
dark:hover:bg-coolgray-100 cursor-pointer

Plain CSS:

.checkbox {
  border-color: #404040;
  color: #282828;
  background: #181818;
  border-radius: 0.125rem;
  cursor: pointer;
}
.checkbox:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px #101010, 0 0 0 4px #fcd452;
}

.checkbox-container {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 1rem;
  padding: 0.25rem 0.5rem 0.25rem 0;
  min-width: fit-content;
  cursor: pointer;
}
.dark .checkbox-container:hover { background: #181818; }

3.5 Textarea

Uses font-mono for monospace text. Supports tab key insertion (2 spaces).

Important: Large/multiline textareas should NOT use the inset box-shadow left-border system from .input. Use a simple border instead:

Tailwind:

block w-full text-sm text-black rounded-sm border border-neutral-200
dark:bg-coolgray-100 dark:text-white dark:border-coolgray-300
font-mono focus-visible:outline-none focus-visible:ring-2
focus-visible:ring-coollabs dark:focus-visible:ring-warning
focus-visible:ring-offset-2 dark:focus-visible:ring-offset-base

Plain CSS:

.textarea {
  display: block;
  width: 100%;
  font-size: 0.875rem;
  font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace;
  color: #000;
  background: #fff;
  border: 1px solid #e5e5e5;
  border-radius: 0.125rem;
}
.textarea:focus-visible {
  outline: none;
  box-shadow: 0 0 0 2px #fff, 0 0 0 4px #6b16ed;
}
.dark .textarea {
  background: #181818;
  color: #fff;
  border-color: #242424;
}
.dark .textarea:focus-visible {
  box-shadow: 0 0 0 2px #101010, 0 0 0 4px #fcd452;
}

Note

: The 4px inset left-border (dirty/focus indicator) is only for single-line inputs and selects, not textareas.


3.6 Box / Card

Standard Box

Tailwind:

relative flex lg:flex-row flex-col p-2 transition-colors cursor-pointer min-h-[4rem]
dark:bg-coolgray-100 shadow-sm bg-white border text-black dark:text-white hover:text-black
border-neutral-200 dark:border-coolgray-300 hover:bg-neutral-100
dark:hover:bg-coollabs-100 dark:hover:text-white hover:no-underline rounded-sm

Plain CSS:

.box {
  position: relative;
  display: flex;
  flex-direction: column;
  padding: 0.5rem;
  min-height: 4rem;
  background: #fff;
  border: 1px solid #e5e5e5;
  border-radius: 0.125rem;
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
  color: #000;
  cursor: pointer;
  transition: background-color 150ms, color 150ms;
  text-decoration: none;
}
.box:hover { background: #f5f5f5; color: #000; }

.dark .box {
  background: #181818;
  border-color: #242424;
  color: #fff;
}
.dark .box:hover {
  background: #7317ff;
  color: #fff;
}

/* IMPORTANT: child text must also turn white/black on hover,
   since description text (#737373) is invisible on purple bg */
.box:hover .box-title { color: #000; }
.box:hover .box-description { color: #000; }
.dark .box:hover .box-title { color: #fff; }
.dark .box:hover .box-description { color: #fff; }

/* Desktop: row layout */
@media (min-width: 1024px) {
  .box { flex-direction: row; }
}

Coolbox (Ring Hover)

Tailwind:

relative flex transition-all duration-150 dark:bg-coolgray-100 bg-white p-2 rounded
border border-neutral-200 dark:border-coolgray-400 hover:ring-2
dark:hover:ring-warning hover:ring-coollabs cursor-pointer min-h-[4rem]

Plain CSS:

.coolbox {
  position: relative;
  display: flex;
  padding: 0.5rem;
  min-height: 4rem;
  background: #fff;
  border: 1px solid #e5e5e5;
  border-radius: 0.25rem;
  cursor: pointer;
  transition: all 150ms;
}
.coolbox:hover { box-shadow: 0 0 0 2px #6b16ed; }

.dark .coolbox {
  background: #181818;
  border-color: #282828;
}
.dark .coolbox:hover { box-shadow: 0 0 0 2px #fcd452; }

Box Text

IMPORTANT — Dark mode titles: Card/box titles MUST be #fff (white) in dark mode, not the default body text color (#a3a3a3 / neutral-400). A black or grey title is nearly invisible on dark backgrounds (#181818). This applies to all heading-level text inside cards.

.box-title {
  font-weight: 700;
  color: #000;              /* light mode: black */
}
.dark .box-title {
  color: #fff;              /* dark mode: MUST be white, not grey */
}

.box-description {
  font-size: 0.75rem;
  font-weight: 700;
  color: #737373;
}
/* On hover: description must become visible against colored bg */
.box:hover .box-description { color: #000; }
.dark .box:hover .box-description { color: #fff; }

3.7 Badge / Status Indicator

Tailwind:

inline-block w-3 h-3 text-xs font-bold rounded-full leading-none
border border-neutral-200 dark:border-black

Variants: badge-success (bg-success), badge-warning (bg-warning), badge-error (bg-error)

Plain CSS:

.badge {
  display: inline-block;
  width: 0.75rem;
  height: 0.75rem;
  border-radius: 9999px;
  border: 1px solid #e5e5e5;
}
.dark .badge { border-color: #000; }

.badge-success { background: #22C55E; }
.badge-warning { background: #fcd452; }
.badge-error { background: #dc2626; }

Status Text Pattern

Status indicators combine a badge dot with text:

<div style="display: flex; align-items: center;">
  <div class="badge badge-success"></div>
  <div style="padding-left: 0.5rem; font-size: 0.75rem; font-weight: 700; color: #22C55E;">
    Running
  </div>
</div>
Status Badge Class Text Color
Running badge-success text-success (#22C55E)
Stopped badge-error text-error (#dc2626)
Degraded badge-warning dark:text-warning (#fcd452)
Restarting badge-warning dark:text-warning (#fcd452)

3.8 Dropdown

Container Tailwind:

p-1 mt-1 bg-white border rounded-sm shadow-sm
dark:bg-coolgray-200 dark:border-coolgray-300 border-neutral-300

Item Tailwind:

flex relative gap-2 justify-start items-center py-1 pr-4 pl-2 w-full text-xs
transition-colors cursor-pointer select-none dark:text-white
hover:bg-neutral-100 dark:hover:bg-coollabs
outline-none focus-visible:bg-neutral-100 dark:focus-visible:bg-coollabs

Plain CSS:

.dropdown {
  padding: 0.25rem;
  margin-top: 0.25rem;
  background: #fff;
  border: 1px solid #d4d4d4;
  border-radius: 0.125rem;
  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
}
.dark .dropdown {
  background: #202020;
  border-color: #242424;
}

.dropdown-item {
  display: flex;
  position: relative;
  gap: 0.5rem;
  justify-content: flex-start;
  align-items: center;
  padding: 0.25rem 1rem 0.25rem 0.5rem;
  width: 100%;
  font-size: 0.75rem;
  cursor: pointer;
  user-select: none;
  transition: background-color 150ms;
}
.dropdown-item:hover { background: #f5f5f5; }
.dark .dropdown-item { color: #fff; }
.dark .dropdown-item:hover { background: #6b16ed; }

3.9 Sidebar / Navigation

Sidebar Container + Page Layout

The navbar is a fixed left sidebar (14rem / 224px wide on desktop), with main content offset to the right.

Tailwind (sidebar wrapper — desktop):

hidden lg:fixed lg:inset-y-0 lg:z-50 lg:flex lg:w-56 lg:flex-col min-w-0

Tailwind (sidebar inner — scrollable):

flex flex-col overflow-y-auto grow gap-y-5 scrollbar min-w-0

Tailwind (nav element):

flex flex-col flex-1 px-2 bg-white border-r dark:border-coolgray-200 border-neutral-300 dark:bg-base

Tailwind (main content area):

lg:pl-56

Tailwind (main content padding):

p-4 sm:px-6 lg:px-8 lg:py-6

Tailwind (mobile top bar — shown on small screens, hidden on lg+):

sticky top-0 z-40 flex items-center justify-between px-4 py-4 gap-x-6 sm:px-6 lg:hidden
bg-white/95 dark:bg-base/95 backdrop-blur-sm border-b border-neutral-300/50 dark:border-coolgray-200/50

Tailwind (mobile hamburger icon):

-m-2.5 p-2.5 dark:text-warning

Plain CSS:

/* Sidebar — desktop only */
.sidebar {
  display: none;
}
@media (min-width: 1024px) {
  .sidebar {
    display: flex;
    flex-direction: column;
    position: fixed;
    top: 0;
    bottom: 0;
    left: 0;
    z-index: 50;
    width: 14rem;       /* 224px */
    min-width: 0;
  }
}

.sidebar-inner {
  display: flex;
  flex-direction: column;
  flex-grow: 1;
  overflow-y: auto;
  gap: 1.25rem;
  min-width: 0;
}

/* Nav element */
.sidebar-nav {
  display: flex;
  flex-direction: column;
  flex: 1;
  padding: 0 0.5rem;
  background: #fff;
  border-right: 1px solid #d4d4d4;
}
.dark .sidebar-nav {
  background: #101010;
  border-right-color: #202020;
}

/* Main content offset */
@media (min-width: 1024px) {
  .main-content { padding-left: 14rem; }
}

.main-content-inner {
  padding: 1rem;
}
@media (min-width: 640px) {
  .main-content-inner { padding: 1rem 1.5rem; }
}
@media (min-width: 1024px) {
  .main-content-inner { padding: 1.5rem 2rem; }
}

/* Mobile top bar — visible below lg breakpoint */
.mobile-topbar {
  position: sticky;
  top: 0;
  z-index: 40;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1rem;
  gap: 1.5rem;
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(12px);
  border-bottom: 1px solid rgba(212, 212, 212, 0.5);
}
.dark .mobile-topbar {
  background: rgba(16, 16, 16, 0.95);
  border-bottom-color: rgba(32, 32, 32, 0.5);
}
@media (min-width: 1024px) {
  .mobile-topbar { display: none; }
}

/* Mobile sidebar overlay (shown when hamburger is tapped) */
.sidebar-mobile {
  position: relative;
  display: flex;
  flex: 1;
  width: 100%;
  max-width: 14rem;
  min-width: 0;
}
.sidebar-mobile-scroll {
  display: flex;
  flex-direction: column;
  padding-bottom: 0.5rem;
  overflow-y: auto;
  min-width: 14rem;
  gap: 1.25rem;
  min-width: 0;
}
.dark .sidebar-mobile-scroll { background: #181818; }

Tailwind:

flex lg:pt-6 pt-4 pb-4 pl-2

Logo:

text-2xl font-bold tracking-wide dark:text-white hover:opacity-80 transition-opacity

Search button:

flex items-center gap-1.5 px-2.5 py-1.5
bg-neutral-100 dark:bg-coolgray-100
border border-neutral-300 dark:border-coolgray-200
rounded-md hover:bg-neutral-200 dark:hover:bg-coolgray-200 transition-colors

Search kbd hint:

px-1 py-0.5 text-xs font-semibold
text-neutral-500 dark:text-neutral-400
bg-neutral-200 dark:bg-coolgray-200 rounded

Plain CSS:

.sidebar-header {
  display: flex;
  padding: 1rem 0 1rem 0.5rem;
}
@media (min-width: 1024px) {
  .sidebar-header { padding-top: 1.5rem; }
}

.sidebar-logo {
  font-size: 1.5rem;
  font-weight: 700;
  letter-spacing: 0.025em;
  color: #000;
  text-decoration: none;
}
.dark .sidebar-logo { color: #fff; }
.sidebar-logo:hover { opacity: 0.8; }

.sidebar-search-btn {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  padding: 0.375rem 0.625rem;
  background: #f5f5f5;
  border: 1px solid #d4d4d4;
  border-radius: 0.375rem;
  cursor: pointer;
  transition: background-color 150ms;
}
.sidebar-search-btn:hover { background: #e5e5e5; }
.dark .sidebar-search-btn {
  background: #181818;
  border-color: #202020;
}
.dark .sidebar-search-btn:hover { background: #202020; }

.sidebar-search-kbd {
  padding: 0.125rem 0.25rem;
  font-size: 0.75rem;
  font-weight: 600;
  color: #737373;
  background: #e5e5e5;
  border-radius: 0.25rem;
}
.dark .sidebar-search-kbd {
  color: #a3a3a3;
  background: #202020;
}

Menu Item List

Tailwind (list container):

flex flex-col flex-1 gap-y-7

Tailwind (inner list):

flex flex-col h-full space-y-1.5

Plain CSS:

.menu-list {
  display: flex;
  flex-direction: column;
  flex: 1;
  gap: 1.75rem;
  list-style: none;
  padding: 0;
  margin: 0;
}

.menu-list-inner {
  display: flex;
  flex-direction: column;
  height: 100%;
  gap: 0.375rem;
  list-style: none;
  padding: 0;
  margin: 0;
}

Menu Item

Tailwind:

flex gap-3 items-center px-2 py-1 w-full text-sm
dark:hover:bg-coolgray-100 dark:hover:text-white hover:bg-neutral-300 rounded-sm truncate min-w-0

Menu Item Active

Tailwind:

text-black rounded-sm dark:bg-coolgray-200 dark:text-warning bg-neutral-200 overflow-hidden

Menu Item Icon / Label

/* Icon */  flex-shrink-0 w-6 h-6 dark:hover:text-white
/* Label */ min-w-0 flex-1 truncate

Plain CSS:

.menu-item {
  display: flex;
  gap: 0.75rem;
  align-items: center;
  padding: 0.25rem 0.5rem;
  width: 100%;
  font-size: 0.875rem;
  border-radius: 0.125rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.menu-item:hover { background: #d4d4d4; }
.dark .menu-item:hover { background: #181818; color: #fff; }

.menu-item-active {
  color: #000;
  background: #e5e5e5;
  border-radius: 0.125rem;
}
.dark .menu-item-active {
  background: #202020;
  color: #fcd452;
}

.menu-item-icon {
  flex-shrink: 0;
  width: 1.5rem;
  height: 1.5rem;
}

.menu-item-label {
  min-width: 0;
  flex: 1;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

Sub-Menu Item

.sub-menu-item {
  /* Same as menu-item but with gap: 0.5rem and icon size 1rem */
  display: flex;
  gap: 0.5rem;
  align-items: center;
  padding: 0.25rem 0.5rem;
  width: 100%;
  font-size: 0.875rem;
  border-radius: 0.125rem;
}
.sub-menu-item-icon { flex-shrink: 0; width: 1rem; height: 1rem; }

3.10 Callout / Alert

Four types: warning, danger, info, success.

Structure:

<div class="callout callout-{type}">
  <div class="callout-icon"><!-- SVG --></div>
  <div class="callout-body">
    <div class="callout-title">Title</div>
    <div class="callout-text">Content</div>
  </div>
</div>

Base Tailwind:

relative p-4 border rounded-lg

Type Colors:

Type Background Border Title Text Body Text
warning bg-warning-50 dark:bg-warning-900/30 border-warning-300 dark:border-warning-800 text-warning-800 dark:text-warning-300 text-warning-700 dark:text-warning-200
danger bg-red-50 dark:bg-red-900/30 border-red-300 dark:border-red-800 text-red-800 dark:text-red-300 text-red-700 dark:text-red-200
info bg-blue-50 dark:bg-blue-900/30 border-blue-300 dark:border-blue-800 text-blue-800 dark:text-blue-300 text-blue-700 dark:text-blue-200
success bg-green-50 dark:bg-green-900/30 border-green-300 dark:border-green-800 text-green-800 dark:text-green-300 text-green-700 dark:text-green-200

Plain CSS (warning example):

.callout {
  position: relative;
  padding: 1rem;
  border: 1px solid;
  border-radius: 0.5rem;
}

.callout-warning {
  background: #fefce8;
  border-color: #fde047;
}
.dark .callout-warning {
  background: rgba(113, 63, 18, 0.3);
  border-color: #854d0e;
}

.callout-title {
  font-size: 1rem;
  font-weight: 700;
}
.callout-warning .callout-title { color: #854d0e; }
.dark .callout-warning .callout-title { color: #fde047; }

.callout-text {
  margin-top: 0.5rem;
  font-size: 0.875rem;
}
.callout-warning .callout-text { color: #a16207; }
.dark .callout-warning .callout-text { color: #fef08a; }

Icon colors per type:

  • Warning: text-warning-600 dark:text-warning-400 (#ca8a04 / #fcd452)
  • Danger: text-red-600 dark:text-red-400 (#dc2626 / #f87171)
  • Info: text-blue-600 dark:text-blue-400 (#2563eb / #60a5fa)
  • Success: text-green-600 dark:text-green-400 (#16a34a / #4ade80)

3.11 Toast / Notification

Container Tailwind:

relative flex flex-col items-start
shadow-[0_5px_15px_-3px_rgb(0_0_0_/_0.08)]
w-full transition-all duration-100 ease-out
dark:bg-coolgray-100 bg-white
dark:border dark:border-coolgray-200
rounded-sm sm:max-w-xs

Plain CSS:

.toast {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  width: 100%;
  max-width: 20rem;
  background: #fff;
  border-radius: 0.125rem;
  box-shadow: 0 5px 15px -3px rgba(0, 0, 0, 0.08);
  transition: all 100ms ease-out;
}
.dark .toast {
  background: #181818;
  border: 1px solid #202020;
}

Icon colors per toast type:

Type Color Hex
Success text-green-500 #22c55e
Info text-blue-500 #3b82f6
Warning text-orange-400 #fb923c
Danger text-red-500 #ef4444

Behavior: Stacks up to 4 toasts, auto-dismisses after 4 seconds, positioned bottom-right.


3.12 Modal

Tailwind (dialog-based):

rounded-sm modal-box max-h-[calc(100vh-5rem)] flex flex-col

Modal Input variant container:

relative w-full lg:w-auto lg:min-w-2xl lg:max-w-4xl
border rounded-sm drop-shadow-sm
bg-white border-neutral-200
dark:bg-base dark:border-coolgray-300
flex flex-col

Modal Confirmation container:

relative w-full border rounded-sm
min-w-full lg:min-w-[36rem] max-w-[48rem]
max-h-[calc(100vh-2rem)]
bg-neutral-100 border-neutral-400
dark:bg-base dark:border-coolgray-300
flex flex-col

Plain CSS:

.modal-box {
  border-radius: 0.125rem;
  max-height: calc(100vh - 5rem);
  display: flex;
  flex-direction: column;
}

.modal-input {
  position: relative;
  width: 100%;
  border: 1px solid #e5e5e5;
  border-radius: 0.125rem;
  filter: drop-shadow(0 1px 1px rgba(0, 0, 0, 0.05));
  background: #fff;
  display: flex;
  flex-direction: column;
}
.dark .modal-input {
  background: #101010;
  border-color: #242424;
}

/* Desktop sizing */
@media (min-width: 1024px) {
  .modal-input {
    width: auto;
    min-width: 42rem;
    max-width: 56rem;
  }
}

Modal header:

.modal-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 1.5rem;
  flex-shrink: 0;
}
.modal-header h3 {
  font-size: 1.5rem;
  font-weight: 700;
}

Close button:

.modal-close {
  width: 2rem;
  height: 2rem;
  border-radius: 9999px;
  color: #fff;
}
.modal-close:hover { background: #242424; }

3.13 Slide-Over Panel

Tailwind:

fixed inset-y-0 right-0 flex max-w-full pl-10

Inner panel:

max-w-xl w-screen
flex flex-col h-full py-6
border-l shadow-lg
bg-neutral-50 dark:bg-base
dark:border-neutral-800 border-neutral-200

Plain CSS:

.slide-over {
  position: fixed;
  top: 0;
  bottom: 0;
  right: 0;
  display: flex;
  max-width: 100%;
  padding-left: 2.5rem;
}

.slide-over-panel {
  max-width: 36rem;
  width: 100vw;
  display: flex;
  flex-direction: column;
  height: 100%;
  padding: 1.5rem 0;
  border-left: 1px solid #e5e5e5;
  box-shadow: -10px 0 15px -3px rgba(0, 0, 0, 0.1);
  background: #fafafa;
}
.dark .slide-over-panel {
  background: #101010;
  border-color: #262626;
}

3.14 Tag

Tailwind:

px-2 py-1 cursor-pointer text-xs font-bold text-neutral-500
dark:bg-coolgray-100 dark:hover:bg-coolgray-300 bg-neutral-100 hover:bg-neutral-200

Plain CSS:

.tag {
  padding: 0.25rem 0.5rem;
  font-size: 0.75rem;
  font-weight: 700;
  color: #737373;
  background: #f5f5f5;
  cursor: pointer;
}
.tag:hover { background: #e5e5e5; }
.dark .tag { background: #181818; }
.dark .tag:hover { background: #242424; }

3.15 Loading Spinner

Tailwind:

w-4 h-4 text-coollabs dark:text-warning animate-spin

Plain CSS + SVG:

.loading-spinner {
  width: 1rem;
  height: 1rem;
  color: #6b16ed;
  animation: spin 1s linear infinite;
}
.dark .loading-spinner { color: #fcd452; }

@keyframes spin {
  from { transform: rotate(0deg); }
  to { transform: rotate(360deg); }
}

SVG structure:

<svg class="loading-spinner" viewBox="0 0 24 24" fill="none">
  <circle cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4" opacity="0.25"/>
  <path fill="currentColor" opacity="0.75" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4z"/>
</svg>

3.16 Helper / Tooltip

Tailwind (trigger icon):

cursor-pointer text-coollabs dark:text-warning

Tailwind (popup):

hidden absolute z-40 text-xs rounded-sm text-neutral-700 group-hover:block
dark:border-coolgray-500 border-neutral-900 dark:bg-coolgray-400 bg-neutral-200
dark:text-neutral-300 max-w-sm whitespace-normal break-words

Plain CSS:

.helper-icon {
  cursor: pointer;
  color: #6b16ed;
}
.dark .helper-icon { color: #fcd452; }

.helper-popup {
  display: none;
  position: absolute;
  z-index: 40;
  font-size: 0.75rem;
  border-radius: 0.125rem;
  color: #404040;
  background: #e5e5e5;
  max-width: 24rem;
  white-space: normal;
  word-break: break-word;
  padding: 1rem;
}
.dark .helper-popup {
  background: #282828;
  color: #d4d4d4;
  border: 1px solid #323232;
}

/* Show on parent hover */
.helper:hover .helper-popup { display: block; }

3.17 Highlighted Text

Tailwind:

inline-block font-bold text-coollabs dark:text-warning

Plain CSS:

.text-highlight {
  display: inline-block;
  font-weight: 700;
  color: #6b16ed;
}
.dark .text-highlight { color: #fcd452; }

3.18 Scrollbar

Tailwind:

scrollbar-thumb-coollabs-100 scrollbar-track-neutral-200
dark:scrollbar-track-coolgray-200 scrollbar-thin

Plain CSS:

::-webkit-scrollbar { width: 6px; height: 6px; }
::-webkit-scrollbar-track { background: #e5e5e5; }
::-webkit-scrollbar-thumb { background: #7317ff; }
.dark ::-webkit-scrollbar-track { background: #202020; }

3.19 Table

Plain CSS:

table { min-width: 100%; border-collapse: separate; }
table, tbody { border-bottom: 1px solid #d4d4d4; }
.dark table, .dark tbody { border-color: #202020; }

thead { text-transform: uppercase; }

tr { color: #000; }
tr:hover { background: #e5e5e5; }
.dark tr { color: #a3a3a3; }
.dark tr:hover { background: #000; }

th {
  padding: 0.875rem 0.75rem;
  text-align: left;
  color: #000;
}
.dark th { color: #fff; }
th:first-child { padding-left: 1.5rem; }

td { padding: 1rem 0.75rem; white-space: nowrap; }
td:first-child { padding-left: 1.5rem; font-weight: 700; }

3.20 Keyboard Shortcut Indicator

Tailwind:

px-2 text-xs rounded-sm border border-dashed border-neutral-700 dark:text-warning

Plain CSS:

.kbd {
  padding: 0 0.5rem;
  font-size: 0.75rem;
  border-radius: 0.125rem;
  border: 1px dashed #404040;
}
.dark .kbd { color: #fcd452; }

4. Base Element Styles

These global styles are applied to all HTML elements:

/* Page */
html, body {
  width: 100%;
  min-height: 100%;
  background: #f9fafb;
  font-family: Inter, sans-serif;
}
.dark html, .dark body {
  background: #101010;
  color: #a3a3a3;
}

body {
  min-height: 100vh;
  font-size: 0.875rem;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/* Links */
a:hover { color: #000; }
.dark a:hover { color: #fff; }

/* Labels */
.dark label { color: #a3a3a3; }

/* Sections */
section { margin-bottom: 3rem; }

/* Default border color override */
*, ::after, ::before, ::backdrop {
  border-color: #202020; /* coolgray-200 */
}

/* Select options */
.dark option {
  color: #fff;
  background: #181818;
}

5. Interactive State Reference

Focus

Element Type Mechanism Light Dark
Buttons, links, checkboxes ring-2 offset Purple #6b16ed Yellow #fcd452
Inputs, selects, textareas Inset box-shadow (4px left bar) Purple #6b16ed Yellow #fcd452
Dropdown items Background change bg-neutral-100 bg-coollabs (#6b16ed)

Hover

Element Light Dark
Button (default) bg-neutral-100 bg-coolgray-200
Button (highlighted) bg-coollabs (#6b16ed) bg-coollabs-100 (#7317ff)
Button (error) bg-red-300 bg-red-800
Box card bg-neutral-100 + all child text #000 bg-coollabs-100 (#7317ff) + all child text #fff
Coolbox card Ring: ring-coollabs Ring: ring-warning
Menu item bg-neutral-300 bg-coolgray-100
Dropdown item bg-neutral-100 bg-coollabs
Table row bg-neutral-200 bg-black
Link text-black text-white
Checkbox container bg-coolgray-100

Disabled

/* Universal disabled pattern */
:disabled {
  cursor: not-allowed;
  color: #d4d4d4;           /* neutral-300 */
  background: transparent;
  border-color: transparent;
}
.dark :disabled {
  color: #525252;            /* neutral-600 */
}

/* Input-specific */
.input:disabled {
  background: #e5e5e5;      /* neutral-200 */
  color: #737373;            /* neutral-500 */
  box-shadow: none;
}
.dark .input:disabled {
  background: rgba(24, 24, 24, 0.4);
  box-shadow: none;
}

Readonly

.input:read-only {
  color: #737373;
  background: #e5e5e5;
  box-shadow: none;
}
.dark .input:read-only {
  color: #737373;
  background: rgba(24, 24, 24, 0.4);
  box-shadow: none;
}

6. CSS Custom Properties (Theme Tokens)

For use in any CSS framework or plain CSS:

:root {
  /* Font */
  --font-sans: Inter, sans-serif;

  /* Brand */
  --color-base: #101010;
  --color-coollabs: #6b16ed;
  --color-coollabs-50: #f5f0ff;
  --color-coollabs-100: #7317ff;
  --color-coollabs-200: #5a12c7;
  --color-coollabs-300: #4a0fa3;

  /* Neutral grays (dark backgrounds) */
  --color-coolgray-100: #181818;
  --color-coolgray-200: #202020;
  --color-coolgray-300: #242424;
  --color-coolgray-400: #282828;
  --color-coolgray-500: #323232;

  /* Warning / dark accent */
  --color-warning: #fcd452;
  --color-warning-50: #fefce8;
  --color-warning-100: #fef9c3;
  --color-warning-200: #fef08a;
  --color-warning-300: #fde047;
  --color-warning-400: #fcd452;
  --color-warning-500: #facc15;
  --color-warning-600: #ca8a04;
  --color-warning-700: #a16207;
  --color-warning-800: #854d0e;
  --color-warning-900: #713f12;

  /* Semantic */
  --color-success: #22C55E;
  --color-error: #dc2626;
}