- Rewrite index.css with complete SUMI token system (dark + light themes) - All --sumi-* variables: backgrounds, surfaces, borders, text, pigments, spacing, radius, shadows, glass, scrollbar, motion, z-index, layout - shadcn/Radix semantic mapping (--background, --foreground, etc.) - Tailwind @theme mapping with new fonts (Inter, Space Grotesk, JetBrains Mono) - SUMI keyframe animations (sumi-fade-in, sumi-slide-up, sumi-scale-in, etc.) - Delete 11 redundant CSS files (design-system.css, design-tokens.css, button.css, card.css, input.css, badge-avatar.css, header.css, fix-input-focus.css, fix-login-form.css, visual-enhancements.css, premium-utilities.css) - Update main.tsx: single CSS import (index.css only) - Update ThemeProvider: data-theme attribute instead of .dark class toggle - Update index.html FOUC script: data-theme attribute Co-authored-by: Cursor <cursoragent@cursor.com>
83 KiB
SUMI Design System — Source de Vérité
Version: 2.0 — Merged (Visual truth: Web version)
Updated: 2026-02-12
Status: Active — Single Source of Truth for ALL UI decisions
System Name: SUMI (墨) — "L'encre et la lumiere"
1. Philosophy & Identity
1.1 Name: SUMI (墨)
"Sumi" is the Japanese word for ink — the fundamental medium of sumi-e painting (ink wash). This design system takes its visual language from the encounter between ink and paper: depth without darkness, light without glare, expression without excess.
The name replaces all previous system names (KODO, Spectre Astral, Neon Refined, Botanical). There is now ONE system.
1.2 Core Concept: "L'encre et la lumière"
The visual identity of Veza/Talas is built on a single metaphor: ink diluted in water, applied on washi paper. This is not a decorative theme — it's a design grammar that unifies ALL user experiences.
Encre sur papier. Chaque surface est une feuille, chaque accent un coup de pinceau délibéré. L'espace (間 ma) est sacré.
1.3 Les 6 Règles Inviolables
-
Encre, pas néon — Les couleurs sont des pigments, pas des lumières. Quand tout brille, rien ne se distingue. Le glow est UNIQUEMENT pour les focus rings.
-
Espace sacré (Ma 間) — Spacing généreux, densité maîtrisée. Ce qui n'est pas là est aussi important que ce qui y est. Le vide n'est pas vide — il respire.
-
Universalité — Lisible pour tous (8 ans–80 ans, auditeur casual–label pro). Pas de dark pattern, pas de complexité gratuite.
-
Wabi-sabi numérique — Authenticité > perfection stérile. Personnalité dans les détails, pas dans les effets. Les textures sont subtiles, les formes légèrement organiques.
-
Révélation progressive — Simple pour l'auditeur, profond pour le label. Les fonctions avancées (stats, gestion multi-artistes, analytics) se révèlent au fur et à mesure. Jamais tout d'un coup.
-
Thèmes comme épices — Gaming (XP, achievements), cyber (monospace, terminal), graffiti (chips, tags) = 5% de l'UI, 100% de la personnalité. Ce sont des accents, pas le plat principal.
1.4 Thèmes Absorbés
| Thème | Comment il se manifeste | Où dans l'UI |
|---|---|---|
| Fusain / Lavis japonais | Couleurs chaudes, tons d'encre, espace | Partout — c'est le langage visuel de base |
| Nature / Botanical | Sauge comme couleur success, tons terreux | Badges, états online/success |
| Cybersec / Linux | JetBrains Mono, terminal blocks, stats mono | Stats, analytics, terminal, durées |
| Jeux vidéo 2D | XP bar, achievements, animation pop | Gamification, récompenses |
| Graffiti / Tag | Chips genre, tags, énergie gestuelle | Tags musicaux, filtres, catégories |
| Musique indé | Authenticité, imperfection, warmth | Ton général, pas de clinquant |
1.5 Mnemonic S.U.M.I.
As a quick memory device, the system name also encodes its principles:
- S — Subtle: 90% neutral ink tones. Accent ONLY where action or status demands it.
- U — Universal: Grandmother and label manager see the same natural interface.
- M — Measured: 4px grid, defined elevations, purposeful transitions. No ornament without function.
- I — Intentional: Every visual decision answers "what does this help the user DO?"
1.6 Reference Products (Quality Benchmarks)
The SUMI system targets the visual quality and polish of:
- Spotify: Surface hierarchy, typography-driven hierarchy, minimal accent usage
- Discord: Information density without clutter, dark mode excellence, community warmth
- Linear: Precision, speed feel, glass effects done right
- Arc Browser: Personality without sacrificing usability
1.7 What SUMI is NOT
- NOT a neon/cyberpunk interface (no #00fff7 everywhere)
- NOT a flat botanical/nature app (nature is a sub-theme, not the identity)
- NOT a gaming UI (gaming elements appear only in gamification features)
- NOT music-focused visually (music is the CONTENT; the UI is content-agnostic)
- NOT anxious or overstimulating (calm > cool)
2. Color System — "Les 4 Pigments"
The SUMI palette repose sur des neutres chauds (90% of the UI) and 4 intentional accent pigments. Pas 50 variables. Pas de neon. Think: charcoal on rice paper, not LED screens.
2.1 The 90/10 Rule
90% of every screen is ink tones (warm neutrals). 10% is accent color — reserved exclusively for primary actions, active states, status indicators, and navigation markers. This ratio is non-negotiable.
2.2 Backgrounds — Couches d'encre
Like ink wash (墨絵): darkest = most ink, lightest = diluted wash. These are WARM darks — notice the slight warm undertone vs cold slate.
Dark mode (default):
| Token | Hex | Role |
|---|---|---|
--sumi-bg-void |
#0c0c0f |
Deepest — app background behind everything |
--sumi-bg-base |
#121215 |
Primary background — main content area |
--sumi-bg-raised |
#1a1a1f |
Cards, sidebar — one layer up |
--sumi-bg-overlay |
#222228 |
Dropdowns, popovers, modals |
--sumi-bg-hover |
#2a2a31 |
Hover state on surfaces |
--sumi-bg-active |
#32323a |
Active/pressed state |
--sumi-bg-wash |
#18181d |
Subtle tinted bg (like diluted ink wash) |
Light mode ("Washi Paper" 和紙 — warm off-whites, like handmade Japanese paper. NOT cold clinical white):
| Token | Hex | Role |
|---|---|---|
--sumi-bg-void |
#f0ece4 |
Warmest base — like aged washi |
--sumi-bg-base |
#f6f3ed |
Main content — fresh rice paper |
--sumi-bg-raised |
#ffffff |
Cards — pure white stands out on cream |
--sumi-bg-overlay |
#ffffff |
Modals, dropdowns |
--sumi-bg-hover |
#ede9e1 |
Hover on light surfaces |
--sumi-bg-active |
#e4e0d8 |
Pressed on light surfaces |
--sumi-bg-wash |
#f8f6f1 |
Subtle tinted bg |
2.3 Surfaces
For components that sit ON backgrounds (inputs, wells, insets):
| Token | Dark | Light | Usage |
|---|---|---|---|
--sumi-surface-inset |
#101013 |
#ebe7df |
Sunken — search bars, input fields |
--sumi-surface-subtle |
#1e1e24 |
#f2eee6 |
Slightly raised — table rows alternate |
--sumi-surface-card |
#1a1a1f |
#ffffff |
Standard card |
--sumi-surface-elevated |
#242430 |
#ffffff |
Floating — FAB, sticky headers |
2.4 Borders — Ink lines
| Token | Dark | Light | Usage |
|---|---|---|---|
--sumi-border-faint |
rgba(255,255,255, 0.06) |
rgba(0,0,0, 0.05) |
Subtle separation |
--sumi-border-default |
rgba(255,255,255, 0.10) |
rgba(0,0,0, 0.10) |
Standard borders |
--sumi-border-strong |
rgba(255,255,255, 0.16) |
rgba(0,0,0, 0.18) |
Emphasized borders |
--sumi-border-focus |
rgba(139,170,220, 0.50) |
rgba(80,110,170, 0.45) |
Focus rings |
--sumi-border-accent |
rgba(139,170,220, 0.30) |
rgba(80,110,170, 0.25) |
Accent-colored borders |
Border width: Always 1px. The only exception is the active sidebar indicator (3px left border) and focus rings (2px outline).
2.5 Text — Densités d'encre
| Token | Dark | Light | Usage |
|---|---|---|---|
--sumi-text-primary |
#f0ede8 (warm white) |
#1a1816 (deep charcoal) |
Titles, main content |
--sumi-text-secondary |
#a8a4a0 |
#5c5854 |
Descriptions, metadata |
--sumi-text-tertiary |
#706c68 |
#8a8580 |
Timestamps, captions |
--sumi-text-disabled |
#4a4844 |
#b5b0aa |
Disabled state |
--sumi-text-inverse |
#121215 |
#f0ede8 |
On accent backgrounds |
--sumi-text-link |
#8baade |
#4a6fa5 |
Links — soft blue |
Text hierarchy rule: Info principale = text-primary (titles, names), info secondaire = text-secondary (artist under title, descriptions), info tertiaire = text-tertiary (timestamps, durations, captions). Données chiffrées = font-mono toujours (12,847 streams, 3:42, +23.4%).
2.6 Les 4 Pigments d'Accent
| Pigment | Kanji | Variable | Hex (dark) | Hex (light) | Usage |
|---|---|---|---|---|---|
| Indigo Ink | 藍墨 | --sumi-accent |
#7c9dd6 |
#4a6fa5 |
Primaire — boutons, active, focus, navigation |
| Vermillion Seal | 朱印 | --sumi-vermillion |
#d4634a |
#b84a35 |
Danger — erreurs, destructif, notifications, live |
| Sage | 草墨 | --sumi-sage |
#7a9e6c |
#5a7e4e |
Success — online, validé, nature |
| Gold Leaf | 金墨 | --sumi-gold |
#c9a84c |
#9a7d2e |
Reward — XP, achievements, premium, warnings |
Each pigment has 3 variants:
| Variant | Indigo | Vermillion | Sage | Gold |
|---|---|---|---|---|
base |
#7c9dd6 |
#d4634a |
#7a9e6c |
#c9a84c |
hover |
#93afe0 |
#de7a64 |
#8eb280 |
#d6b860 |
subtle |
rgba(124,157,214, 0.12) |
rgba(212,99,74, 0.12) |
rgba(122,158,108, 0.12) |
rgba(201,168,76, 0.12) |
Additional accent variants (Indigo only): --sumi-accent-active: #6b8dc6, --sumi-accent-muted: rgba(124,157,214, 0.20), --sumi-accent-emphasis: #5a7fba.
Usage rules for primary (Indigo):
- Primary buttons:
--sumi-accentbackground,--sumi-text-inversetext - Links:
--sumi-text-link - Active nav item:
--sumi-accent-subtlebackground tint +--sumi-accenttext - Focus ring:
--sumi-shadow-glow - Progress bars, sliders:
--sumi-accent - NEVER as background for cards, sections, or large areas
2.7 Semantic Mapping
--sumi-success: var(--sumi-sage);
--sumi-warning: var(--sumi-gold);
--sumi-error: var(--sumi-vermillion);
--sumi-info: var(--sumi-accent);
--sumi-live: #e05a5a; /* Brighter red for live indicators */
--sumi-online: var(--sumi-sage);
Each semantic color has a *-subtle variant for tinted backgrounds (e.g. --sumi-success-subtle: var(--sumi-sage-subtle)).
2.8 Contextual Accents — Feature-Specific Colors
These colors appear ONLY in their specific feature contexts. They are NOT part of the general UI palette.
| Token | Hex | Feature Context |
|---|---|---|
--graffiti-magenta |
#c840a0 |
Creative expression: artist profiles, cover art badges |
--gaming-gold |
#d4b040 |
XP, achievements, leaderboards, level badges |
--terminal-green |
#3eaa5e |
Admin panel, dev tools, API status |
--sakura |
#e0a0b8 |
Delicate moments: welcome, onboarding, empty states |
Strict usage rule: If you cannot justify which FEATURE requires the contextual color, use --sumi-accent or --sumi-vermillion instead.
2.9 Color Architecture Summary
┌───────────────────────────────────────────────────────┐
│ SUMI COLOR MODEL │
├───────────────────────────────────────────────────────┤
│ │
│ ████████████████████████████████████████ 90% │
│ Sumi Neutrals (--sumi-bg-*, --sumi-text-*) │
│ Backgrounds, surfaces, text, borders │
│ │
│ ██████ 7% │
│ Indigo Ink 藍墨 (--sumi-accent) │
│ Buttons, links, active states, focus │
│ │
│ ███ 2% │
│ Vermillion 朱印 + Sage 草墨 + Gold 金墨 │
│ Errors, success, warnings, achievements │
│ │
│ █ 1% │
│ Contextual (magenta, gold, green, sakura) │
│ Feature-specific moments only │
│ │
└───────────────────────────────────────────────────────┘
3. Typography — "The Brush & The Grid"
3.1 Font Stack
3 fonts + 1 decorative. That's it. No Orbitron. No display fonts that scream.
| Role | Font | Variable | Fallbacks | Weight Range | Why |
|---|---|---|---|---|---|
| Body | Inter | --sumi-font-body |
-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif | 300–700 | Universal readability. Google/Apple-tier. |
| Headings | Space Grotesk | --sumi-font-heading |
'Inter', sans-serif | 400–700 | Geometric but warm. Has personality without being aggressive. Nods to tech/cyber subtly. |
| Mono | JetBrains Mono | --sumi-font-mono |
'SF Mono', 'Consolas', monospace | 400–600 | Code, terminal UI, stats. The cybersec/linux accent. |
| Decorative | Noto Serif JP | --sumi-font-serif |
Georgia, serif | 400, 600 | Easter eggs, citations japonaises (rare). |
Fonts removed (and why):
- Orbitron: Too sci-fi/gaming. Makes the app look like a cyberpunk game, alienates non-tech users.
- Rajdhani: Too niche/specific. Doesn't add readability.
- Barlow / DM Sans: Good but Inter is the industry standard body font with better feature support.
- Source Serif 4 / Instrument Serif: Serif fonts don't belong in a streaming app primary stack.
- Bebas Neue: Display-only font, Space Grotesk at bold weights covers this.
Loading strategy:
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=Space+Grotesk:wght@400;500;600;700&family=JetBrains+Mono:wght@400;500;600&family=Noto+Serif+JP:wght@400;600&display=swap" rel="stylesheet">
Font feature settings (Inter): font-feature-settings: 'cv02', 'cv03', 'cv04', 'cv11'; — stylistic alternates for cleaner glyphs.
3.2 Type Scale (Major Third — 1.250)
| Class | Token | Size | Font | Weight | Line Height | Spacing | Usage |
|---|---|---|---|---|---|---|---|
.sumi-display |
--sumi-text-4xl |
2.25rem (36px) | Heading | 700 | --sumi-leading-tight (1.25) |
--sumi-tracking-tighter (-0.03em) |
Hero, landing |
.sumi-h1 |
--sumi-text-3xl |
1.875rem (30px) | Heading | 600 | --sumi-leading-tight |
--sumi-tracking-tight (-0.015em) |
Titre de page |
.sumi-h2 |
--sumi-text-2xl |
1.5rem (24px) | Heading | 600 | --sumi-leading-snug (1.375) |
--sumi-tracking-tight |
Section |
.sumi-h3 |
--sumi-text-xl |
1.25rem (20px) | Heading | 500 | --sumi-leading-snug |
Normal | Sous-section |
.sumi-h4 |
--sumi-text-lg |
1.125rem (18px) | Heading | 500 | --sumi-leading-snug |
Normal | Sous-titre |
.sumi-body-lg |
--sumi-text-md |
1rem (16px) | Body | 400 | --sumi-leading-relaxed (1.625) |
Normal | Texte important |
.sumi-body |
--sumi-text-base |
0.875rem (14px) | Body | 400 | --sumi-leading-normal (1.5) |
Normal | Texte standard |
.sumi-body-sm |
--sumi-text-sm |
0.8125rem (13px) | Body | 400 | --sumi-leading-normal |
Normal | Texte compact |
.sumi-caption |
--sumi-text-xs |
0.75rem (12px) | Body | 400 | --sumi-leading-normal |
Normal | Timestamps, captions |
.sumi-label |
--sumi-text-xs |
0.75rem (12px) | Body | 500 | --sumi-leading-normal |
--sumi-tracking-wider (0.05em) |
Labels uppercase |
.sumi-mono |
--sumi-text-sm |
0.8125rem (13px) | Mono | 400 | — | — | Stats, durées |
3.3 Typography Tokens
Line Heights:
| Token | Value |
|---|---|
--sumi-leading-none |
1 |
--sumi-leading-tight |
1.25 |
--sumi-leading-snug |
1.375 |
--sumi-leading-normal |
1.5 |
--sumi-leading-relaxed |
1.625 |
--sumi-leading-loose |
1.75 |
Letter Spacing:
| Token | Value |
|---|---|
--sumi-tracking-tighter |
-0.03em |
--sumi-tracking-tight |
-0.015em |
--sumi-tracking-normal |
0 |
--sumi-tracking-wide |
0.025em |
--sumi-tracking-wider |
0.05em |
--sumi-tracking-widest |
0.1em |
Font Weights:
| Token | Value |
|---|---|
--sumi-weight-light |
300 |
--sumi-weight-regular |
400 |
--sumi-weight-medium |
500 |
--sumi-weight-semibold |
600 |
--sumi-weight-bold |
700 |
3.4 Text Color Hierarchy
On dark surfaces:
| Priority | Token | Hex | Usage |
|---|---|---|---|
| Primary | --sumi-text-primary |
#f0ede8 |
Headings, important text, interactive labels |
| Secondary | --sumi-text-secondary |
#a8a4a0 |
Body text, descriptions |
| Tertiary | --sumi-text-tertiary |
#706c68 |
Metadata, timestamps, helper text |
| Disabled | --sumi-text-disabled |
#4a4844 |
Disabled labels, placeholder |
On light surfaces:
| Priority | Token | Hex | Usage |
|---|---|---|---|
| Primary | --sumi-text-primary |
#1a1816 |
Headings, important text |
| Secondary | --sumi-text-secondary |
#5c5854 |
Body text |
| Tertiary | --sumi-text-tertiary |
#8a8580 |
Metadata |
| Disabled | --sumi-text-disabled |
#b5b0aa |
Disabled |
3.5 Typography Rules
- Never use more than 3 font weights on a single screen: pick from 400, 500, 600, 700.
- Headings are always
font-heading(Space Grotesk), never mono or body. - Monospace is ONLY for: BPM numbers, musical keys, code blocks, terminal output, timestamps in admin, file sizes, stream counts, durations.
- Maximum 4 type sizes per screen to maintain hierarchy clarity.
- Line length: Body text should not exceed
65ch(~520px at 14px). Usemax-w-proseor equivalent. - Font feature settings: Always enable Inter's stylistic alternates with
'cv02', 'cv03', 'cv04', 'cv11'.
4. Spacing, Radius & Elevation
4.1 Spacing — 4px Base Grid
All spacing uses the standard Tailwind scale built on a 4px base unit. NO arbitrary spacing values.
| Token | Tailwind | Value | Typical Use |
|---|---|---|---|
1 |
p-1 / gap-1 |
4px | Icon-to-text micro gap |
1.5 |
p-1.5 / gap-1.5 |
6px | Tight chip/badge padding |
2 |
p-2 / gap-2 |
8px | Internal component gap, icon button padding |
3 |
p-3 / gap-3 |
12px | Compact card padding, input horizontal padding |
4 |
p-4 / gap-4 |
16px | Standard card padding, list item spacing |
5 |
p-5 / gap-5 |
20px | Form group spacing |
6 |
p-6 / gap-6 |
24px | Generous card padding, section internal spacing |
8 |
p-8 / gap-8 |
32px | Section-to-section spacing |
10 |
p-10 / gap-10 |
40px | Large section spacing |
12 |
p-12 / gap-12 |
48px | Page-level section gaps |
16 |
p-16 / gap-16 |
64px | Hero sections top/bottom |
20 |
p-20 / gap-20 |
80px | Maximum content spacing |
Spacing rules:
- Card padding:
p-4(compact) orp-6(standard). NOTp-8for cards (too much wasted space). - Section spacing:
gap-6(tight) orgap-8(standard) between related sections. - Page-level spacing:
gap-10orgap-12between major page sections. - Never use
space-y-*whengap-*on a flex/grid parent achieves the same result.
4.2 Border Radius
Inspired by ink brush curves — soft but not bubbly. The dominant shape language is "soft rectangle".
| Token | Tailwind | Value | Usage |
|---|---|---|---|
none |
rounded-none |
0px | Table cells, inline code |
sm |
rounded-sm |
4px | Chips inside inputs, micro elements |
md |
rounded-md |
6px | Badges, small buttons, tags |
DEFAULT |
rounded |
8px | Buttons, inputs, small cards |
lg |
rounded-lg |
12px | Standard cards, dropdowns, popovers |
xl |
rounded-xl |
16px | Modals, large feature cards |
2xl |
rounded-2xl |
20px | Hero cards, full-page modals |
full |
rounded-full |
9999px | Avatars, pills, circular buttons, sliders |
Radius rules:
- Default interactive elements (buttons, inputs):
rounded(8px) - Cards:
rounded-lg(12px) - Modals:
rounded-xl(16px) - Avatars: Always
rounded-full - NEVER mix different radii on the same component — children should use smaller or equal radius.
4.3 Elevation & Shadow System
Shadows in SUMI are "ink pooling" — soft, warm-tinted, not harsh black.
Dark mode shadows:
| Token | CSS Value | Usage |
|---|---|---|
--sumi-shadow-xs |
0 1px 2px rgba(0,0,0,0.30) |
Inputs, badges |
--sumi-shadow-sm |
0 2px 4px rgba(0,0,0,0.25), 0 1px 2px rgba(0,0,0,0.20) |
Cards at rest |
--sumi-shadow-md |
0 4px 12px rgba(0,0,0,0.30), 0 2px 4px rgba(0,0,0,0.15) |
Cards hover, tooltips |
--sumi-shadow-lg |
0 8px 24px rgba(0,0,0,0.35), 0 4px 8px rgba(0,0,0,0.20) |
Dropdowns, popovers |
--sumi-shadow-xl |
0 16px 48px rgba(0,0,0,0.40), 0 8px 16px rgba(0,0,0,0.20) |
Modals, drawers |
--sumi-shadow-2xl |
0 24px 64px rgba(0,0,0,0.50) |
Full-screen overlays |
Light mode shadows (softer):
| Token | CSS Value |
|---|---|
--sumi-shadow-xs |
0 1px 2px rgba(0,0,0,0.05) |
--sumi-shadow-sm |
0 2px 4px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04) |
--sumi-shadow-md |
0 4px 12px rgba(0,0,0,0.08), 0 2px 4px rgba(0,0,0,0.04) |
--sumi-shadow-lg |
0 8px 24px rgba(0,0,0,0.10), 0 4px 8px rgba(0,0,0,0.05) |
--sumi-shadow-xl |
0 16px 48px rgba(0,0,0,0.12), 0 8px 16px rgba(0,0,0,0.06) |
--sumi-shadow-2xl |
0 24px 64px rgba(0,0,0,0.15) |
Glow — used ONLY for focus states and primary CTA. Never decorative:
| Token | CSS Value | When to use |
|---|---|---|
--sumi-shadow-glow |
0 0 0 3px rgba(124,157,214,0.25) |
Focus rings on interactive elements |
--sumi-shadow-glow-lg |
0 0 20px rgba(124,157,214,0.15) |
"Now playing", active live stream |
Glow rules:
- Glows are ANIMATED, never static (they pulse or appear then fade)
- Maximum 1 glowing element visible at a time on any screen
- Respect
prefers-reduced-motion: no glow animations
4.4 Glass Panel
Frosted ink paper — for player bar, header, floating panels. NOT for regular cards.
.sumi-glass {
background: var(--sumi-glass-bg);
backdrop-filter: blur(var(--sumi-glass-blur));
-webkit-backdrop-filter: blur(var(--sumi-glass-blur));
border: 1px solid var(--sumi-glass-border);
}
| Token | Dark | Light |
|---|---|---|
--sumi-glass-bg |
rgba(18,18,21, 0.80) |
rgba(255,255,255, 0.85) |
--sumi-glass-border |
rgba(255,255,255, 0.08) |
rgba(0,0,0, 0.06) |
--sumi-glass-blur |
12px |
12px |
4.5 Scrollbar
| Token | Dark | Light |
|---|---|---|
--sumi-scrollbar-track |
transparent |
transparent |
--sumi-scrollbar-thumb |
rgba(255,255,255, 0.10) |
rgba(0,0,0, 0.12) |
--sumi-scrollbar-hover |
rgba(255,255,255, 0.18) |
rgba(0,0,0, 0.22) |
Width: 6px. Border-radius: --sumi-radius-full.
4.6 Z-Index Scale
| Token | Value | Usage |
|---|---|---|
--sumi-z-base |
0 | Default |
--sumi-z-raised |
10 | Slightly elevated |
--sumi-z-dropdown |
100 | Dropdown menus |
--sumi-z-sticky |
200 | Sidebar, header, player |
--sumi-z-overlay |
300 | Overlays |
--sumi-z-modal |
400 | Modals |
--sumi-z-popover |
500 | Popovers |
--sumi-z-toast |
600 | Toast notifications |
--sumi-z-tooltip |
700 | Tooltips |
--sumi-z-max |
999 | Emergency override |
4.7 Layout Tokens
| Token | Value | Usage |
|---|---|---|
--sumi-max-width |
1400px | Overall page max |
--sumi-max-width-content |
1200px | Content area |
--sumi-max-width-narrow |
800px | Narrow layouts (settings, forms) |
--sumi-max-width-prose |
65ch | Body text maximum line length |
--sumi-sidebar-width |
240px | Sidebar expanded |
--sumi-sidebar-collapsed |
64px | Sidebar collapsed |
--sumi-header-height |
56px | Header bar |
--sumi-player-height |
80px | Player bar |
4.8 Surface Hierarchy
The surface system creates depth through background color, not shadows. This is the Spotify/Discord approach.
┌─ Layer 0: Canvas ──────────────────────────────────────┐
│ --sumi-bg-void (dark) / washi (light) │
│ The page background. Nothing sits below this. │
│ │
│ ┌─ Layer 1: Surface ──────────────────────────────┐ │
│ │ --sumi-bg-raised / --sumi-surface-card │ │
│ │ Cards, panels, sidebar content area │ │
│ │ │ │
│ │ ┌─ Layer 2: Elevated ──────────────────────┐ │ │
│ │ │ --sumi-surface-elevated / glass panels │ │ │
│ │ │ Dropdowns, popovers, floating player │ │ │
│ │ │ │ │ │
│ │ │ ┌─ Layer 3: Overlay ────────────────┐ │ │ │
│ │ │ │ --sumi-bg-overlay │ │ │ │
│ │ │ │ Modals, dialogs, command palette │ │ │ │
│ │ │ └───────────────────────────────────┘ │ │ │
│ │ └──────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────┘
Rules:
- Cards do NOT have shadows in dark mode — they rely on background color difference.
- Cards in light mode get
shadow-smfor subtle lift. - Floating elements (player, dropdowns) get
shadow-lgin light mode,shadow-mdin dark mode. - Modals always have
shadow-xl+ backdrop overlay (rgba(0,0,0,0.60)+backdrop-filter: blur(4px)). - The sidebar is Layer 1 (raised) — it uses
--sumi-bg-raised.
5. Motion & Texture
5.1 Animation Principles
Motion in SUMI follows the movement of ink on paper: fluid arrival, calm rest, gentle exit. Never mechanical. Never bouncy unless celebrating (achievement unlocked).
Rules:
- Every animation must have a purpose: feedback, orientation, or celebration.
- If you can't explain what the animation TELLS the user — remove it.
- Hover effects are limited to: background change, opacity change, border change. NO scale transforms on cards.
- Respect
prefers-reduced-motion: disable decorative motion, keep functional feedback (opacity changes OK, position changes not).
5.2 Duration Scale
| Token | Value | Usage |
|---|---|---|
--sumi-duration-instant |
75ms | Button press feedback, keyboard response |
--sumi-duration-fast |
150ms | Hover in/out, focus ring appear, tooltip show |
--sumi-duration-normal |
200ms | Panel open/close, sidebar toggle, dropdown appear |
--sumi-duration-slow |
300ms | Modal entrance, sidebar transition |
--sumi-duration-slower |
500ms | Achievement animation only |
5.3 Easing Curves
| Token | Value | Usage |
|---|---|---|
--sumi-ease-default |
cubic-bezier(0.25, 0.1, 0.25, 1) |
Standard for everything |
--sumi-ease-out |
cubic-bezier(0.33, 1, 0.68, 1) |
Decelerate — entries, elements appearing |
--sumi-ease-in |
cubic-bezier(0.32, 0, 0.67, 0) |
Accelerate — exits, elements disappearing |
--sumi-ease-in-out |
cubic-bezier(0.65, 0, 0.35, 1) |
Symmetric — toggles, smooth both ways |
--sumi-ease-bounce |
cubic-bezier(0.34, 1.56, 0.64, 1) |
Playful — achievements ONLY, never elsewhere |
--sumi-ease-spring |
cubic-bezier(0.175, 0.885, 0.32, 1.1) |
Natural spring — toast notifications |
5.4 Transition Presets (CSS Variables)
Composable transition presets for consistency:
--sumi-transition-colors: color var(--sumi-duration-fast) var(--sumi-ease-default),
background-color var(--sumi-duration-fast) var(--sumi-ease-default),
border-color var(--sumi-duration-fast) var(--sumi-ease-default);
--sumi-transition-opacity: opacity var(--sumi-duration-fast) var(--sumi-ease-default);
--sumi-transition-transform: transform var(--sumi-duration-normal) var(--sumi-ease-out);
--sumi-transition-shadow: box-shadow var(--sumi-duration-fast) var(--sumi-ease-default);
--sumi-transition-all: all var(--sumi-duration-normal) var(--sumi-ease-default);
5.5 Hover States — The Complete List
What hovering DOES in SUMI:
| Element | Hover Effect | Transition |
|---|---|---|
| Button (primary) | Lighten background 10% | background 150ms ease-out |
| Button (ghost) | Show sumi-800 background |
background 150ms ease-out |
| Card | Show white/5% overlay OR lighten surface |
background 150ms ease-out |
| Link | Underline + slightly dim | color 150ms ease-out |
| Nav item | Background tint + text brighten | background 150ms ease-out, color 150ms ease-out |
| Table row | Lighten background | background 100ms ease-out |
| Icon button | Background tint circle | background 150ms ease-out |
What hovering does NOT do:
- NO
scale()transforms on any element - NO shadow changes on hover (shadows are static by elevation)
- NO border-color changes (except on inputs going to focus)
- NO glow effects on hover (glows are for status, not interaction)
5.6 Keyframe Animations
/* Essential animations — only these are allowed */
@keyframes sumi-fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes sumi-fade-out {
from { opacity: 1; }
to { opacity: 0; }
}
@keyframes sumi-slide-up {
from { opacity: 0; transform: translateY(8px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes sumi-slide-down {
from { opacity: 0; transform: translateY(-8px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes sumi-scale-in {
from { opacity: 0; transform: scale(0.95); }
to { opacity: 1; transform: scale(1); }
}
@keyframes sumi-scale-out {
from { opacity: 1; transform: scale(1); }
to { opacity: 0; transform: scale(0.95); }
}
/* Achievement pop — the ONE playful animation (gaming touch) */
@keyframes sumi-pop {
0% { opacity: 0; transform: scale(0.8); }
60% { opacity: 1; transform: scale(1.05); }
100% { transform: scale(1); }
}
/* Subtle pulse for live indicators */
@keyframes sumi-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
/* Ink brush stroke reveal — for page transitions (signature SUMI touch) */
@keyframes sumi-brush-reveal {
from { clip-path: inset(0 100% 0 0); }
to { clip-path: inset(0 0 0 0); }
}
/* Skeleton shimmer (loading) */
@keyframes shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
/* EQ bars — for "now playing" indicator */
@keyframes eq-bar {
0%, 100% { transform: scaleY(0.3); }
50% { transform: scaleY(1); }
}
5.7 Texture — The Sumi Layer
The visual signature that makes SUMI unique. These textures are SUBTLE — they create atmosphere, not noise.
5.7.1 Paper Grain (Global)
A barely perceptible noise texture on the body background. Gives the feeling of looking at washi paper on a screen.
body::after {
content: '';
position: fixed;
inset: 0;
background: url("data:image/svg+xml,...noise-svg...");
opacity: 0.012; /* Almost invisible — you feel it, don't see it */
pointer-events: none;
z-index: 9999;
mix-blend-mode: overlay;
}
Opacity: 1.2% in dark mode, 2% in light mode. If users set prefers-reduced-motion, disable it entirely.
5.7.2 Ink Wash Gradients (Hero/Feature Sections)
For hero sections, featured content, or onboarding screens — a soft, asymmetric gradient that feels like diluted ink spreading on wet paper.
.sumi-wash-texture {
position: relative;
}
.sumi-wash-texture::after {
content: '';
position: absolute;
inset: 0;
background:
radial-gradient(ellipse at 20% 50%, var(--sumi-accent-subtle) 0%, transparent 60%),
radial-gradient(ellipse at 80% 20%, rgba(201,168,76,0.04) 0%, transparent 50%);
pointer-events: none;
}
Key characteristics:
- Asymmetric (never centered or symmetrical)
- Very low opacity (4-8%)
- Uses primary and warm colors
- Organic ellipse shapes, not circles
5.7.3 Brush Stroke Accents (Special Moments)
For empty states, achievement cards, artist profile headers — SVG brush strokes as decorative elements. These are NOT used in general UI.
Usage contexts:
- Empty state illustrations: A single brush stroke as background
- Achievement card borders: Ink splash frame
- Artist profile hero: Calligraphic flourish behind artist name
- 404 page: Sumi-e landscape sketch
Rules:
- Maximum 1 brush stroke element per screen
- Always
opacity: 0.1to0.3— they're atmosphere, not content - Never compete with text for attention
- Color:
sumi-400orprimary-400only
6. Component Specifications
Every component below uses --sumi-* CSS custom properties. The CSS class definitions below are the definitive implementations.
6.1 Card
.sumi-card {
background: var(--sumi-surface-card);
border: 1px solid var(--sumi-border-faint);
border-radius: var(--sumi-radius-lg);
padding: var(--sumi-space-4);
transition: var(--sumi-transition-shadow), var(--sumi-transition-colors);
}
.sumi-card:hover {
border-color: var(--sumi-border-default);
box-shadow: var(--sumi-shadow-sm);
}
.sumi-card--interactive { cursor: pointer; }
.sumi-card--interactive:hover {
background: var(--sumi-bg-hover);
box-shadow: var(--sumi-shadow-md);
}
.sumi-card--elevated {
background: var(--sumi-surface-elevated);
box-shadow: var(--sumi-shadow-md);
}
Card variants (prose specs):
| Variant | Details |
|---|---|
| Media Card (Track, Album, Playlist) | Cover aspect-square, rounded-lg. Title text-sm font-medium, truncated. Subtitle text-xs text-secondary, truncated. Play overlay on hover. |
| Stat Card | Icon container 40px rounded-lg, value sumi-h2, label sumi-label, trend indicator mono ±%. |
| Profile Card | Avatar rounded-full, name sumi-h4, role badge pill. |
6.2 Buttons
.sumi-btn {
display: inline-flex; align-items: center; justify-content: center;
gap: var(--sumi-space-2);
font-family: var(--sumi-font-body);
font-size: var(--sumi-text-sm);
font-weight: var(--sumi-weight-medium);
line-height: 1;
padding: var(--sumi-space-2) var(--sumi-space-4);
border-radius: var(--sumi-radius-md);
border: 1px solid transparent;
cursor: pointer;
transition: var(--sumi-transition-colors), var(--sumi-transition-shadow);
user-select: none; white-space: nowrap;
}
.sumi-btn:focus-visible { box-shadow: var(--sumi-shadow-glow); }
.sumi-btn:disabled { opacity: 0.4; cursor: not-allowed; pointer-events: none; }
/* Primary — THE action */
.sumi-btn--primary {
background: var(--sumi-accent); color: var(--sumi-text-inverse); border-color: var(--sumi-accent);
}
.sumi-btn--primary:hover { background: var(--sumi-accent-hover); border-color: var(--sumi-accent-hover); }
.sumi-btn--primary:active { background: var(--sumi-accent-active); }
/* Secondary — bordered, subtle */
.sumi-btn--secondary {
background: transparent; color: var(--sumi-text-primary); border-color: var(--sumi-border-strong);
}
.sumi-btn--secondary:hover { background: var(--sumi-bg-hover); border-color: var(--sumi-accent); color: var(--sumi-accent); }
/* Ghost — no border, minimal */
.sumi-btn--ghost { background: transparent; color: var(--sumi-text-secondary); border-color: transparent; }
.sumi-btn--ghost:hover { background: var(--sumi-bg-hover); color: var(--sumi-text-primary); }
/* Danger */
.sumi-btn--danger { background: var(--sumi-vermillion); color: white; border-color: var(--sumi-vermillion); }
.sumi-btn--danger:hover { background: var(--sumi-vermillion-hover); }
/* Sizes */
.sumi-btn--xs { padding: var(--sumi-space-1) var(--sumi-space-2); font-size: var(--sumi-text-xs); }
.sumi-btn--sm { padding: var(--sumi-space-1-5) var(--sumi-space-3); font-size: var(--sumi-text-sm); }
.sumi-btn--lg { padding: var(--sumi-space-3) var(--sumi-space-6); font-size: var(--sumi-text-md); }
.sumi-btn--icon { padding: var(--sumi-space-2); width: 36px; height: 36px; }
.sumi-btn--icon-sm { padding: var(--sumi-space-1-5); width: 28px; height: 28px; }
6.3 Input
.sumi-input {
display: block; width: 100%;
font-family: var(--sumi-font-body);
font-size: var(--sumi-text-base);
color: var(--sumi-text-primary);
background: var(--sumi-surface-inset);
border: 1px solid var(--sumi-border-default);
border-radius: var(--sumi-radius-md);
padding: var(--sumi-space-2) var(--sumi-space-3);
transition: var(--sumi-transition-colors), var(--sumi-transition-shadow);
}
.sumi-input::placeholder { color: var(--sumi-text-tertiary); }
.sumi-input:hover { border-color: var(--sumi-border-strong); }
.sumi-input:focus { outline: none; border-color: var(--sumi-accent); box-shadow: var(--sumi-shadow-glow); }
Additional form elements (prose specs):
- Checkbox/Radio: 18px, 2px border, checked =
--sumi-accentfill + white check. - Toggle: See
.sumi-togglebelow.
6.4 Badge / Tag
.sumi-badge {
display: inline-flex; align-items: center; gap: var(--sumi-space-1);
font-family: var(--sumi-font-body);
font-size: var(--sumi-text-xs); font-weight: var(--sumi-weight-medium);
padding: var(--sumi-space-0-5) var(--sumi-space-2);
border-radius: var(--sumi-radius-full);
line-height: var(--sumi-leading-normal);
}
.sumi-badge--default { background: var(--sumi-bg-hover); color: var(--sumi-text-secondary); }
.sumi-badge--accent { background: var(--sumi-accent-subtle); color: var(--sumi-accent); }
.sumi-badge--success { background: var(--sumi-success-subtle); color: var(--sumi-success); }
.sumi-badge--warning { background: var(--sumi-warning-subtle); color: var(--sumi-warning); }
.sumi-badge--error { background: var(--sumi-error-subtle); color: var(--sumi-error); }
.sumi-badge--live { background: rgba(224,90,90,0.15); color: var(--sumi-live); }
6.5 Chip (Graffiti touch)
.sumi-chip {
display: inline-flex; align-items: center; gap: var(--sumi-space-1);
font-size: var(--sumi-text-xs); font-weight: var(--sumi-weight-semibold);
padding: var(--sumi-space-1) var(--sumi-space-2-5);
border-radius: var(--sumi-radius-sm);
background: var(--sumi-bg-hover); color: var(--sumi-text-secondary);
border: 1px solid var(--sumi-border-faint);
transition: var(--sumi-transition-colors); cursor: pointer;
}
.sumi-chip:hover { background: var(--sumi-accent-subtle); color: var(--sumi-accent); border-color: var(--sumi-border-accent); }
.sumi-chip--selected { background: var(--sumi-accent-subtle); color: var(--sumi-accent); border-color: var(--sumi-accent); }
6.6 Avatar
.sumi-avatar {
display: inline-flex; align-items: center; justify-content: center;
border-radius: var(--sumi-radius-full); overflow: hidden;
background: var(--sumi-bg-hover); color: var(--sumi-text-secondary);
font-weight: var(--sumi-weight-medium); flex-shrink: 0;
}
.sumi-avatar--xs { width: 24px; height: 24px; font-size: 10px; }
.sumi-avatar--sm { width: 32px; height: 32px; font-size: var(--sumi-text-xs); }
.sumi-avatar--md { width: 40px; height: 40px; font-size: var(--sumi-text-sm); }
.sumi-avatar--lg { width: 48px; height: 48px; font-size: var(--sumi-text-base); }
.sumi-avatar--xl { width: 64px; height: 64px; font-size: var(--sumi-text-lg); }
.sumi-avatar--2xl { width: 96px; height: 96px; font-size: var(--sumi-text-2xl); }
.sumi-avatar img { width: 100%; height: 100%; object-fit: cover; }
/* Online indicator (position: relative on parent required) */
.sumi-avatar__status {
position: absolute; bottom: 0; right: 0;
width: 10px; height: 10px; border-radius: var(--sumi-radius-full);
border: 2px solid var(--sumi-bg-raised);
}
.sumi-avatar__status--online { background: var(--sumi-online); }
.sumi-avatar__status--live { background: var(--sumi-live); animation: sumi-pulse 2s ease-in-out infinite; }
6.7 Dropdown / Menu
.sumi-menu {
background: var(--sumi-bg-overlay);
border: 1px solid var(--sumi-border-default);
border-radius: var(--sumi-radius-lg);
box-shadow: var(--sumi-shadow-xl);
padding: var(--sumi-space-1);
z-index: var(--sumi-z-dropdown);
min-width: 180px;
animation: sumi-scale-in var(--sumi-duration-fast) var(--sumi-ease-out);
}
.sumi-menu__item {
display: flex; align-items: center; gap: var(--sumi-space-2);
padding: var(--sumi-space-2) var(--sumi-space-3);
border-radius: var(--sumi-radius-sm);
font-size: var(--sumi-text-sm); color: var(--sumi-text-secondary);
cursor: pointer; transition: var(--sumi-transition-colors);
}
.sumi-menu__item:hover { background: var(--sumi-bg-hover); color: var(--sumi-text-primary); }
.sumi-menu__item--active { background: var(--sumi-accent-subtle); color: var(--sumi-accent); }
.sumi-menu__item--danger { color: var(--sumi-vermillion); }
.sumi-menu__item--danger:hover { background: var(--sumi-vermillion-subtle); }
.sumi-menu__separator { height: 1px; background: var(--sumi-border-faint); margin: var(--sumi-space-1) 0; }
6.8 Modal
.sumi-modal-backdrop {
position: fixed; inset: 0;
background: rgba(0,0,0,0.60); backdrop-filter: blur(4px);
z-index: var(--sumi-z-modal);
animation: sumi-fade-in var(--sumi-duration-fast) var(--sumi-ease-out);
}
.sumi-modal {
position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%);
background: var(--sumi-bg-overlay);
border: 1px solid var(--sumi-border-default);
border-radius: var(--sumi-radius-xl);
box-shadow: var(--sumi-shadow-2xl);
z-index: calc(var(--sumi-z-modal) + 1);
max-width: 560px; width: 90vw; max-height: 85vh; overflow-y: auto;
animation: sumi-scale-in var(--sumi-duration-normal) var(--sumi-ease-out);
}
.sumi-modal__header { padding: var(--sumi-space-5) var(--sumi-space-6) var(--sumi-space-3); }
.sumi-modal__body { padding: var(--sumi-space-3) var(--sumi-space-6); }
.sumi-modal__footer { padding: var(--sumi-space-3) var(--sumi-space-6) var(--sumi-space-5); display: flex; justify-content: flex-end; gap: var(--sumi-space-2); }
6.9 Toast
.sumi-toast {
display: flex; align-items: flex-start; gap: var(--sumi-space-3);
background: var(--sumi-surface-elevated);
border: 1px solid var(--sumi-border-default);
border-radius: var(--sumi-radius-lg);
padding: var(--sumi-space-3) var(--sumi-space-4);
box-shadow: var(--sumi-shadow-xl);
min-width: 300px; max-width: 420px;
animation: sumi-slide-up var(--sumi-duration-slow) var(--sumi-ease-spring);
}
6.10 Tooltip
.sumi-tooltip {
background: var(--sumi-bg-overlay);
color: var(--sumi-text-primary);
font-size: var(--sumi-text-xs);
padding: var(--sumi-space-1-5) var(--sumi-space-2-5);
border-radius: var(--sumi-radius-md);
box-shadow: var(--sumi-shadow-lg);
border: 1px solid var(--sumi-border-default);
max-width: 240px; z-index: var(--sumi-z-tooltip);
}
6.11 Tabs
.sumi-tabs {
display: flex; gap: var(--sumi-space-1);
border-bottom: 1px solid var(--sumi-border-faint);
}
.sumi-tab {
padding: var(--sumi-space-2) var(--sumi-space-4);
font-size: var(--sumi-text-sm); font-weight: var(--sumi-weight-medium);
color: var(--sumi-text-tertiary); cursor: pointer;
border-bottom: 2px solid transparent;
transition: var(--sumi-transition-colors);
}
.sumi-tab:hover { color: var(--sumi-text-primary); }
.sumi-tab--active { color: var(--sumi-text-primary); border-bottom-color: var(--sumi-accent); }
6.12 Toggle
.sumi-toggle {
position: relative; width: 40px; height: 22px;
background: var(--sumi-bg-active); border-radius: var(--sumi-radius-full);
cursor: pointer; transition: var(--sumi-transition-colors);
}
.sumi-toggle--active { background: var(--sumi-accent); }
.sumi-toggle__knob {
position: absolute; top: 2px; left: 2px;
width: 18px; height: 18px; border-radius: var(--sumi-radius-full);
background: white; box-shadow: var(--sumi-shadow-xs);
transition: transform var(--sumi-duration-fast) var(--sumi-ease-out);
}
.sumi-toggle--active .sumi-toggle__knob { transform: translateX(18px); }
6.13 Divider
.sumi-divider { height: 1px; background: var(--sumi-border-faint); border: none; margin: var(--sumi-space-4) 0; }
6.14 Sidebar
.sumi-sidebar {
position: fixed; top: 0; left: 0; bottom: 0;
width: var(--sumi-sidebar-width);
background: var(--sumi-bg-raised);
border-right: 1px solid var(--sumi-border-faint);
z-index: var(--sumi-z-sticky);
display: flex; flex-direction: column;
transition: width var(--sumi-duration-slow) var(--sumi-ease-out);
overflow: hidden;
}
.sumi-sidebar--collapsed { width: var(--sumi-sidebar-collapsed); }
.sumi-sidebar__nav-item {
display: flex; align-items: center; gap: var(--sumi-space-3);
padding: var(--sumi-space-2) var(--sumi-space-3);
border-radius: var(--sumi-radius-md);
color: var(--sumi-text-secondary); font-size: var(--sumi-text-sm);
font-weight: var(--sumi-weight-medium); cursor: pointer;
transition: var(--sumi-transition-colors); text-decoration: none;
}
.sumi-sidebar__nav-item:hover { background: var(--sumi-bg-hover); color: var(--sumi-text-primary); }
.sumi-sidebar__nav-item--active { background: var(--sumi-accent-subtle); color: var(--sumi-accent); }
/* Active indicator — 3px left accent bar */
.sumi-sidebar__nav-item--active::before {
content: ''; position: absolute; left: 0; top: 25%; bottom: 25%;
width: 3px; background: var(--sumi-accent);
border-radius: 0 var(--sumi-radius-full) var(--sumi-radius-full) 0;
}
.sumi-sidebar__section-label {
font-size: var(--sumi-text-xs); font-weight: var(--sumi-weight-medium);
letter-spacing: var(--sumi-tracking-wider); text-transform: uppercase;
color: var(--sumi-text-tertiary);
padding: var(--sumi-space-4) var(--sumi-space-3) var(--sumi-space-1);
}
6.15 Header
.sumi-header {
position: fixed; top: 0; right: 0;
height: var(--sumi-header-height);
background: var(--sumi-glass-bg);
backdrop-filter: blur(var(--sumi-glass-blur));
-webkit-backdrop-filter: blur(var(--sumi-glass-blur));
border-bottom: 1px solid var(--sumi-border-faint);
z-index: var(--sumi-z-sticky);
display: flex; align-items: center;
padding: 0 var(--sumi-space-6); gap: var(--sumi-space-4);
}
6.16 Player Bar
.sumi-player {
position: fixed; bottom: 0; left: 0; right: 0;
height: var(--sumi-player-height);
background: var(--sumi-glass-bg);
backdrop-filter: blur(16px); -webkit-backdrop-filter: blur(16px);
border-top: 1px solid var(--sumi-border-faint);
z-index: var(--sumi-z-sticky);
display: flex; align-items: center;
padding: 0 var(--sumi-space-6);
}
Player variants (prose specs — not in Web version CSS):
| Component | Details |
|---|---|
| Mini Player | 3 columns: track info (left, 48px cover rounded-md), controls (center), volume/queue (right). Progress bar: 4px → 6px on hover, --sumi-accent fill. |
| Full Player | Background: gradient from dominant album color at 15% opacity. Cover: 280px max, rounded-xl, shadow-xl. Time: font-mono. |
| Queue Drawer | Slides up, max-height 60vh. Current track: --sumi-accent-subtle bg + left border. Drag handle: pill at top center. |
6.17 Data Display
/* Table */
.sumi-table { width: 100%; border-collapse: separate; border-spacing: 0; font-size: var(--sumi-text-sm); }
.sumi-table th {
text-align: left; padding: var(--sumi-space-2) var(--sumi-space-3);
font-size: var(--sumi-text-xs); font-weight: var(--sumi-weight-medium);
letter-spacing: var(--sumi-tracking-wide); text-transform: uppercase;
color: var(--sumi-text-tertiary); border-bottom: 1px solid var(--sumi-border-default);
}
.sumi-table td { padding: var(--sumi-space-3); border-bottom: 1px solid var(--sumi-border-faint); color: var(--sumi-text-secondary); }
.sumi-table tr:hover td { background: var(--sumi-bg-hover); }
.sumi-table .sumi-col-number { font-family: var(--sumi-font-mono); font-size: var(--sumi-text-xs); letter-spacing: var(--sumi-tracking-wide); }
/* Track List Item */
.sumi-track {
display: flex; align-items: center; gap: var(--sumi-space-3);
padding: var(--sumi-space-2) var(--sumi-space-3); border-radius: var(--sumi-radius-md);
transition: var(--sumi-transition-colors); cursor: pointer;
}
.sumi-track:hover { background: var(--sumi-bg-hover); }
.sumi-track--playing { background: var(--sumi-accent-subtle); }
.sumi-track__number { font-family: var(--sumi-font-mono); font-size: var(--sumi-text-xs); color: var(--sumi-text-tertiary); width: 24px; text-align: right; }
.sumi-track__title { font-weight: var(--sumi-weight-medium); color: var(--sumi-text-primary); }
.sumi-track__artist { font-size: var(--sumi-text-sm); color: var(--sumi-text-secondary); }
.sumi-track__duration { font-family: var(--sumi-font-mono); font-size: var(--sumi-text-xs); color: var(--sumi-text-tertiary); margin-left: auto; }
/* Stat Card */
.sumi-stat { display: flex; flex-direction: column; gap: var(--sumi-space-1); padding: var(--sumi-space-4); }
.sumi-stat__label { font-size: var(--sumi-text-xs); font-weight: var(--sumi-weight-medium); letter-spacing: var(--sumi-tracking-wide); text-transform: uppercase; color: var(--sumi-text-tertiary); }
.sumi-stat__value { font-family: var(--sumi-font-heading); font-size: var(--sumi-text-2xl); font-weight: var(--sumi-weight-bold); letter-spacing: var(--sumi-tracking-tight); color: var(--sumi-text-primary); }
.sumi-stat__value--mono { font-family: var(--sumi-font-mono); }
.sumi-stat__trend { font-family: var(--sumi-font-mono); font-size: var(--sumi-text-xs); }
.sumi-stat__trend--up { color: var(--sumi-sage); }
.sumi-stat__trend--down { color: var(--sumi-vermillion); }
6.18 Specialty Components (Thematic Personality)
/* XP / Achievement Bar (Gaming touch 🎮) */
.sumi-xp-bar { display: flex; align-items: center; gap: var(--sumi-space-3); }
.sumi-xp-bar__track { flex: 1; height: 6px; background: var(--sumi-bg-hover); border-radius: var(--sumi-radius-full); overflow: hidden; }
.sumi-xp-bar__fill { height: 100%; background: var(--sumi-gold); border-radius: var(--sumi-radius-full); transition: width var(--sumi-duration-slower) var(--sumi-ease-out); }
.sumi-xp-bar__label { font-family: var(--sumi-font-mono); font-size: var(--sumi-text-xs); font-weight: var(--sumi-weight-medium); color: var(--sumi-gold); }
/* Achievement Toast (Gaming 🎮) */
.sumi-achievement {
display: flex; align-items: center; gap: var(--sumi-space-3);
background: var(--sumi-surface-elevated);
border: 1px solid var(--sumi-gold-subtle); border-left: 3px solid var(--sumi-gold);
border-radius: var(--sumi-radius-lg); padding: var(--sumi-space-3) var(--sumi-space-4);
animation: sumi-pop var(--sumi-duration-slower) var(--sumi-ease-bounce);
}
.sumi-achievement__icon {
width: 36px; height: 36px; display: flex; align-items: center; justify-content: center;
background: var(--sumi-gold-subtle); border-radius: var(--sumi-radius-md); font-size: var(--sumi-text-lg);
}
/* Terminal Block (Cybersec/Linux 💻) */
.sumi-terminal {
background: var(--sumi-bg-void); border: 1px solid var(--sumi-border-default);
border-radius: var(--sumi-radius-lg); font-family: var(--sumi-font-mono);
font-size: var(--sumi-text-sm); overflow: hidden;
}
.sumi-terminal__header {
display: flex; align-items: center; gap: var(--sumi-space-2);
padding: var(--sumi-space-2) var(--sumi-space-3);
background: var(--sumi-bg-raised); border-bottom: 1px solid var(--sumi-border-faint);
}
.sumi-terminal__dot { width: 8px; height: 8px; border-radius: var(--sumi-radius-full); }
.sumi-terminal__dot--red { background: var(--sumi-vermillion); }
.sumi-terminal__dot--yellow { background: var(--sumi-gold); }
.sumi-terminal__dot--green { background: var(--sumi-sage); }
.sumi-terminal__body { padding: var(--sumi-space-4); color: var(--sumi-text-secondary); line-height: var(--sumi-leading-relaxed); }
.sumi-terminal__prompt { color: var(--sumi-accent); }
.sumi-terminal__output { color: var(--sumi-text-tertiary); }
/* Live Indicator (📡 Stream) */
.sumi-live-dot {
display: inline-flex; align-items: center; gap: var(--sumi-space-1-5);
font-size: var(--sumi-text-xs); font-weight: var(--sumi-weight-semibold);
text-transform: uppercase; letter-spacing: var(--sumi-tracking-wider);
color: var(--sumi-live);
}
.sumi-live-dot::before {
content: ''; width: 6px; height: 6px;
border-radius: var(--sumi-radius-full); background: var(--sumi-live);
animation: sumi-pulse 2s ease-in-out infinite;
}
/* Cover Art (🎵 Music) */
.sumi-cover {
border-radius: var(--sumi-radius-md); overflow: hidden;
background: var(--sumi-bg-hover); aspect-ratio: 1; position: relative;
}
.sumi-cover img { width: 100%; height: 100%; object-fit: cover; }
.sumi-cover--sm { width: 40px; height: 40px; border-radius: var(--sumi-radius-sm); }
.sumi-cover--md { width: 56px; height: 56px; }
.sumi-cover--lg { width: 160px; height: 160px; border-radius: var(--sumi-radius-lg); }
.sumi-cover--xl { width: 240px; height: 240px; border-radius: var(--sumi-radius-xl); }
.sumi-cover--hero { width: 100%; max-width: 300px; box-shadow: var(--sumi-shadow-xl); }
/* Progress Slider (🎧 Player) */
.sumi-slider {
position: relative; width: 100%; height: 4px;
background: var(--sumi-bg-hover); border-radius: var(--sumi-radius-full); cursor: pointer;
}
.sumi-slider:hover { height: 6px; }
.sumi-slider__fill { height: 100%; background: var(--sumi-accent); border-radius: var(--sumi-radius-full); position: relative; }
.sumi-slider__thumb {
position: absolute; right: -6px; top: 50%; transform: translateY(-50%);
width: 12px; height: 12px; border-radius: var(--sumi-radius-full);
background: white; box-shadow: var(--sumi-shadow-sm);
opacity: 0; transition: opacity var(--sumi-duration-fast);
}
.sumi-slider:hover .sumi-slider__thumb { opacity: 1; }
6.19 Chat (Prose Spec)
| Element | Spec |
|---|---|
| Message Bubble | Max-width 70%. Own: --sumi-accent-subtle bg, right-aligned. Others: --sumi-bg-hover bg, left-aligned. rounded-xl with squared corner on sender's side. |
| Timestamp | sumi-caption, text-tertiary, below message. |
| Reactions | Small pills, --sumi-bg-active bg, emoji + count. |
| Room List | 48px items, 36px avatar, room name sumi-body font-medium, last message sumi-caption text-secondary, unread badge --sumi-accent pill with white text. |
6.20 Skeleton / Loading
| Aspect | Spec |
|---|---|
| Shape | Matches the content it replaces (text line, avatar, card) |
| Background | --sumi-bg-hover (dark) / --sumi-bg-active (light) |
| Animation | shimmer sweep, 1.8s, ease-in-out, infinite |
| Shimmer highlight | rgba(255,255,255, 0.06) (dark) / rgba(255,255,255, 0.40) (light) |
| Radius | Matches the component being loaded |
6.21 Empty States
Empty states use the sumi-e aesthetic most directly. They are the moments where the app's personality shines.
- Container: centered,
max-w-sm,py-16 - Illustration: Simple brush stroke SVG,
--sumi-text-tertiarycolor, 120px max - Title:
sumi-h4,text-primary - Description:
sumi-body,text-secondary, 2-3 lines max - CTA:
.sumi-btn--primarybelow - Background: Optional
.sumi-wash-texture
7. Anti-Patterns — INTERDIT
| Ne JAMAIS faire | Faire a la place |
|---|---|
Couleurs Tailwind par defaut (slate, zinc, gray) |
Tokens --sumi-* exclusively |
| Glow/neon decoratif | Glow UNIQUEMENT pour focus rings (--sumi-shadow-glow) |
| Orbitron ou font gaming | Space Grotesk pour headings |
| Clip-path manga/hex | border-radius standard (--sumi-radius-*) |
| Plus de 4 couleurs d'accent | Indigo, Vermillon, Sauge, Or — c'est tout |
| Gradient sur composants | Gradient uniquement hero/cover (.sumi-wash-texture) |
| Box-shadow decoratif | Shadow = elevation fonctionnelle uniquement |
| Animations > 300ms | Max 300ms sauf achievements (500ms) |
Valeurs CSS arbitraires (w-[347px]) |
Tokens et echelle Tailwind/SUMI |
!important sauf utilitaires |
Specificite CSS normale |
| Neon flicker, matrix rain, terminal green text | Subtilite, discretion |
8. Component Checklist — Quality Gate
Avant de merger un composant, verifier :
- Utilise uniquement des tokens
--sumi-* - Fonctionne en dark ET light theme
- Responsive (teste a 320px, 768px, 1024px, 1280px)
- Focus visible avec
--sumi-shadow-glow - Pas plus de 2 fonts utilisees (body + heading, ou body + mono)
- Pas d'animation > 300ms (sauf achievement)
- Contrast ratio >= 4.5:1 pour le texte (WCAG AA)
- Pas de valeur CSS arbitraire
- States couverts : default, hover, active, focus, disabled
- Donnees chiffrees en
font-mono(--sumi-font-mono)
9. Theme Contexts & Accessibility
9.1 How Sub-Themes Surface
Instead of applying ALL your interests equally across the UI (which creates visual chaos), each theme surfaces in a SPECIFIC context. The base SUMI aesthetic is always the foundation.
Theme Map
| Theme | Where It Appears | How It Manifests | Never Appears In |
|---|---|---|---|
| Sumi-e / Lavis | Everywhere (base) | Ink neutrals, paper textures, soft shadows, ink wash gradients, brush stroke decorative elements | — |
| Nature | Empty states, onboarding, community features, settings backgrounds | Organic shapes in illustrations, leaf/branch motifs in empty state art, earthy warm accents, organic radius on feature cards | Navigation, data tables, admin |
| Graffiti / Tag | Artist profiles, creative tools, release announcements, achievement badges | Bold uppercase type moments (display font at large size), manga clip-paths on special cards, splash/drip micro-texture on album art hover, high-contrast headlines | General cards, forms, settings |
| Gaming | XP/levels, achievements, leaderboards, challenges, gamification UI | --sumi-gold accent, .sumi-xp-bar, .sumi-achievement, level numbers in bold |
Chat, marketplace, analytics |
| Terminal / Linux | Admin panel, developer API page, system status, file manager | .sumi-terminal, monospace font for data, --terminal-green for success status, --sumi-bg-void even in light mode |
Player, social, onboarding |
| Music | Player, waveforms, streaming page, track cards | Waveform visualizations, EQ bar animations, BPM/key in mono font — but these are FUNCTIONAL, not decorative. The player itself uses the base SUMI palette | Everywhere else looks the same whether it's a music app or not |
Implementation Examples
Graffiti moment — Artist profile hero:
<div className="relative overflow-hidden rounded-2xl">
<div className="absolute inset-0 opacity-10 bg-graffiti-magenta" />
<div className="relative p-8">
<h1 className="sumi-display uppercase tracking-tight">{artist.name}</h1>
{/* Bold, high-contrast — the graffiti energy comes from typography, not color */}
</div>
</div>
Gaming moment — Achievement toast:
<div className="sumi-achievement">
<div className="sumi-achievement__icon">🏆</div>
<div>
<div className="sumi-h4">First Upload!</div>
<div className="sumi-caption" style={{ color: 'var(--sumi-text-secondary)' }}>+100 XP</div>
</div>
</div>
Terminal moment — Admin status:
<div className="sumi-terminal">
<div className="sumi-terminal__header">
<span className="sumi-terminal__dot sumi-terminal__dot--red" />
<span className="sumi-terminal__dot sumi-terminal__dot--yellow" />
<span className="sumi-terminal__dot sumi-terminal__dot--green" />
</div>
<div className="sumi-terminal__body">
<span className="sumi-terminal__prompt">$</span> status api-gateway
<div className="sumi-terminal__output">● online — uptime: 99.97%</div>
</div>
</div>
9.2 Dark Mode vs Light Mode
Dark mode is the DEFAULT (like Spotify, Discord). Light mode is the secondary option.
Dark Mode (default)
- Canvas:
--sumi-bg-void(#0c0c0f) - Surfaces:
--sumi-surface-card(#1a1a1f) - Text:
--sumi-text-primary(#f0ede8),--sumi-text-secondary(#a8a4a0) - Borders:
--sumi-border-default(rgba 10%) - Accent:
--sumi-accent(#7c9dd6) - Character: Calm, focused, immersive — like a recording studio at night
Light Mode
- Canvas:
--sumi-bg-void(#f0ece4) — warm washi paper, NOT pure white - Surfaces:
--sumi-surface-card(#ffffff) - Text:
--sumi-text-primary(#1a1816),--sumi-text-secondary(#5c5854) - Borders:
--sumi-border-default(rgba 10%) - Accent:
--sumi-accent(#4a6fa5) — darker for contrast on light - Character: Airy, bright, like a sunlit studio with paper walls
Switching Behavior
- Follows system preference by default (
prefers-color-scheme) - User can override in settings (dark / light / auto)
- Data attribute:
[data-theme="dark"]/[data-theme="light"] - Transition between modes:
--sumi-duration-normal--sumi-ease-in-outon background, color, border-color
9.3 Accessibility Requirements
SUMI targets WCAG 2.1 AA compliance (AAA where feasible).
Contrast Ratios (validated)
| Combination | Contrast Ratio | Rating |
|---|---|---|
--sumi-text-primary on --sumi-bg-base (heading on dark) |
~14:1 | AAA |
--sumi-text-secondary on --sumi-bg-base (body on dark) |
~7.5:1 | AAA |
--sumi-text-tertiary on --sumi-bg-base (muted on dark) |
~4.5:1 | AA |
--sumi-accent on --sumi-bg-base (accent on dark) |
~5.5:1 | AA |
--sumi-text-inverse on --sumi-accent (text on button) |
~5.5:1 | AA |
--sumi-text-primary on --sumi-bg-base (text on light) |
~14:1 | AAA |
--sumi-text-secondary on --sumi-bg-base (muted on light) |
~5.5:1 | AA |
Focus Management
- All interactive elements MUST have visible focus states
- Focus ring:
box-shadow: var(--sumi-shadow-glow)— 3px Indigo ring at 25% - Focus is never hidden or removed via CSS
- Tab order follows visual reading order
- Skip-to-main-content link at the top of the page
Motion Accessibility
@media (prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
/* Keep opacity transitions for functional feedback */
.interactive { transition: opacity 100ms ease-out; }
}
Screen Reader Requirements
- All images have
alttext - All icons-only buttons have
aria-label - Form fields have associated labels
- Status changes use
aria-liveregions - Modal traps focus correctly
- Player controls are fully keyboard-accessible
- Current track info is announced via
aria-live="polite"
Color Independence
- Never use color ALONE to convey information
- Status indicators: color + icon (checkmark for success, X for error, etc.)
- Form errors: red border + error icon + error message text
- Charts: use patterns/shapes in addition to color
9.4 Responsive Breakpoints
| Breakpoint | Width | Behavior |
|---|---|---|
| Mobile | < 640px (sm) | Single column, hamburger nav, full-width cards, bottom nav possible |
| Tablet | 640–1023px (md) | 2-column grid, sidebar as overlay, condensed player |
| Desktop | 1024–1279px (lg) | Full sidebar + content, 3-column layouts |
| Large | >= 1280px (xl) | Max content width 1600px (max-w-layout-content), centered |
Mobile-Specific Rules
- Sidebar becomes a bottom sheet or hamburger overlay
- Player mini-bar stays at bottom (above bottom nav if present)
- Cards go full-width with no horizontal padding reduction
- Touch targets minimum 44px x 44px (Apple HIG)
- No hover effects — focus/active states only
10. Implementation Guide — Tailwind + CSS Variables
10.1 CSS Variable Architecture
The system uses two layers: CSS custom properties for the raw values, and Tailwind @theme for mapping them to utility classes. This is already the pattern in index.css — we're simplifying and replacing the content.
index.css (source of truth)
├── :root, [data-theme="dark"] → Dark mode tokens (default)
├── [data-theme="light"] → Light mode tokens
├── @theme inline → Tailwind mapping
├── @layer base → Base styles, typography
└── @layer utilities → Custom utility classes
design-system.css → DELETED (merged into index.css)
design-tokens.css → DELETED (merged into index.css)
10.2 CSS Variables — Complete Map
:root, [data-theme="dark"] {
/* ═══ BACKGROUNDS ═══ */
--sumi-bg-void: #0c0c0f;
--sumi-bg-base: #121215;
--sumi-bg-raised: #1a1a1f;
--sumi-bg-overlay: #222228;
--sumi-bg-hover: #2a2a31;
--sumi-bg-active: #32323a;
--sumi-bg-wash: #18181d;
/* ═══ SURFACES ═══ */
--sumi-surface-inset: #101013;
--sumi-surface-subtle: #1e1e24;
--sumi-surface-card: #1a1a1f;
--sumi-surface-elevated: #242430;
/* ═══ BORDERS ═══ */
--sumi-border-faint: rgba(255,255,255, 0.06);
--sumi-border-default: rgba(255,255,255, 0.10);
--sumi-border-strong: rgba(255,255,255, 0.16);
--sumi-border-focus: rgba(139,170,220, 0.50);
--sumi-border-accent: rgba(139,170,220, 0.30);
/* ═══ TEXT ═══ */
--sumi-text-primary: #f0ede8;
--sumi-text-secondary: #a8a4a0;
--sumi-text-tertiary: #706c68;
--sumi-text-disabled: #4a4844;
--sumi-text-inverse: #121215;
--sumi-text-link: #8baade;
/* ═══ PIGMENTS ═══ */
--sumi-accent: #7c9dd6;
--sumi-accent-hover: #93afe0;
--sumi-accent-active: #6b8dc6;
--sumi-accent-muted: rgba(124,157,214, 0.20);
--sumi-accent-subtle: rgba(124,157,214, 0.12);
--sumi-accent-emphasis: #5a7fba;
--sumi-vermillion: #d4634a;
--sumi-vermillion-hover: #de7a64;
--sumi-vermillion-subtle: rgba(212,99,74, 0.12);
--sumi-sage: #7a9e6c;
--sumi-sage-hover: #8eb280;
--sumi-sage-subtle: rgba(122,158,108, 0.12);
--sumi-gold: #c9a84c;
--sumi-gold-hover: #d6b860;
--sumi-gold-subtle: rgba(201,168,76, 0.12);
/* ═══ SEMANTIC ═══ */
--sumi-success: var(--sumi-sage);
--sumi-success-subtle: var(--sumi-sage-subtle);
--sumi-warning: var(--sumi-gold);
--sumi-warning-subtle: var(--sumi-gold-subtle);
--sumi-error: var(--sumi-vermillion);
--sumi-error-subtle: var(--sumi-vermillion-subtle);
--sumi-info: var(--sumi-accent);
--sumi-live: #e05a5a;
--sumi-online: var(--sumi-sage);
/* ═══ TYPOGRAPHY ═══ */
--sumi-font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--sumi-font-heading: 'Space Grotesk', 'Inter', sans-serif;
--sumi-font-mono: 'JetBrains Mono', 'SF Mono', 'Consolas', monospace;
--sumi-font-serif: 'Noto Serif JP', Georgia, serif;
--sumi-text-4xl: 2.25rem;
--sumi-text-3xl: 1.875rem;
--sumi-text-2xl: 1.5rem;
--sumi-text-xl: 1.25rem;
--sumi-text-lg: 1.125rem;
--sumi-text-md: 1rem;
--sumi-text-base: 0.875rem;
--sumi-text-sm: 0.8125rem;
--sumi-text-xs: 0.75rem;
--sumi-leading-none: 1;
--sumi-leading-tight: 1.25;
--sumi-leading-snug: 1.375;
--sumi-leading-normal: 1.5;
--sumi-leading-relaxed: 1.625;
--sumi-leading-loose: 1.75;
--sumi-tracking-tighter: -0.03em;
--sumi-tracking-tight: -0.015em;
--sumi-tracking-normal: 0;
--sumi-tracking-wide: 0.025em;
--sumi-tracking-wider: 0.05em;
--sumi-tracking-widest: 0.1em;
--sumi-weight-light: 300;
--sumi-weight-regular: 400;
--sumi-weight-medium: 500;
--sumi-weight-semibold: 600;
--sumi-weight-bold: 700;
/* ═══ SPACING ═══ */
--sumi-space-0-5: 2px;
--sumi-space-1: 4px;
--sumi-space-1-5: 6px;
--sumi-space-2: 8px;
--sumi-space-2-5: 10px;
--sumi-space-3: 12px;
--sumi-space-4: 16px;
--sumi-space-5: 20px;
--sumi-space-6: 24px;
--sumi-space-8: 32px;
--sumi-space-10: 40px;
--sumi-space-12: 48px;
--sumi-space-16: 64px;
--sumi-space-20: 80px;
/* ═══ RADIUS ═══ */
--sumi-radius-xs: 2px;
--sumi-radius-sm: 4px;
--sumi-radius-md: 6px;
--sumi-radius-lg: 12px;
--sumi-radius-xl: 16px;
--sumi-radius-2xl: 20px;
--sumi-radius-full: 9999px;
/* ═══ SHADOWS ═══ */
--sumi-shadow-xs: 0 1px 2px rgba(0,0,0,0.30);
--sumi-shadow-sm: 0 2px 4px rgba(0,0,0,0.25), 0 1px 2px rgba(0,0,0,0.20);
--sumi-shadow-md: 0 4px 12px rgba(0,0,0,0.30), 0 2px 4px rgba(0,0,0,0.15);
--sumi-shadow-lg: 0 8px 24px rgba(0,0,0,0.35), 0 4px 8px rgba(0,0,0,0.20);
--sumi-shadow-xl: 0 16px 48px rgba(0,0,0,0.40), 0 8px 16px rgba(0,0,0,0.20);
--sumi-shadow-2xl: 0 24px 64px rgba(0,0,0,0.50);
--sumi-shadow-glow: 0 0 0 3px rgba(124,157,214,0.25);
--sumi-shadow-glow-lg: 0 0 20px rgba(124,157,214,0.15);
/* ═══ GLASS ═══ */
--sumi-glass-bg: rgba(18,18,21, 0.80);
--sumi-glass-border: rgba(255,255,255, 0.08);
--sumi-glass-blur: 12px;
/* ═══ SCROLLBAR ═══ */
--sumi-scrollbar-track: transparent;
--sumi-scrollbar-thumb: rgba(255,255,255, 0.10);
--sumi-scrollbar-hover: rgba(255,255,255, 0.18);
/* ═══ MOTION ═══ */
--sumi-duration-instant: 75ms;
--sumi-duration-fast: 150ms;
--sumi-duration-normal: 200ms;
--sumi-duration-slow: 300ms;
--sumi-duration-slower: 500ms;
--sumi-ease-default: cubic-bezier(0.25, 0.1, 0.25, 1);
--sumi-ease-out: cubic-bezier(0.33, 1, 0.68, 1);
--sumi-ease-in: cubic-bezier(0.32, 0, 0.67, 0);
--sumi-ease-in-out: cubic-bezier(0.65, 0, 0.35, 1);
--sumi-ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
--sumi-ease-spring: cubic-bezier(0.175, 0.885, 0.32, 1.1);
--sumi-transition-colors: color var(--sumi-duration-fast) var(--sumi-ease-default),
background-color var(--sumi-duration-fast) var(--sumi-ease-default),
border-color var(--sumi-duration-fast) var(--sumi-ease-default);
--sumi-transition-opacity: opacity var(--sumi-duration-fast) var(--sumi-ease-default);
--sumi-transition-transform: transform var(--sumi-duration-normal) var(--sumi-ease-out);
--sumi-transition-shadow: box-shadow var(--sumi-duration-fast) var(--sumi-ease-default);
/* ═══ Z-INDEX ═══ */
--sumi-z-base: 0;
--sumi-z-raised: 10;
--sumi-z-dropdown: 100;
--sumi-z-sticky: 200;
--sumi-z-overlay: 300;
--sumi-z-modal: 400;
--sumi-z-popover: 500;
--sumi-z-toast: 600;
--sumi-z-tooltip: 700;
--sumi-z-max: 999;
/* ═══ LAYOUT ═══ */
--sumi-max-width: 1400px;
--sumi-max-width-content: 1200px;
--sumi-max-width-narrow: 800px;
--sumi-max-width-prose: 65ch;
--sumi-sidebar-width: 240px;
--sumi-sidebar-collapsed: 64px;
--sumi-header-height: 56px;
--sumi-player-height: 80px;
}
/* ═══ LIGHT THEME ═══ */
[data-theme="light"] {
--sumi-bg-void: #f0ece4;
--sumi-bg-base: #f6f3ed;
--sumi-bg-raised: #ffffff;
--sumi-bg-overlay: #ffffff;
--sumi-bg-hover: #ede9e1;
--sumi-bg-active: #e4e0d8;
--sumi-bg-wash: #f8f6f1;
--sumi-surface-inset: #ebe7df;
--sumi-surface-subtle: #f2eee6;
--sumi-surface-card: #ffffff;
--sumi-surface-elevated: #ffffff;
--sumi-border-faint: rgba(0,0,0, 0.05);
--sumi-border-default: rgba(0,0,0, 0.10);
--sumi-border-strong: rgba(0,0,0, 0.18);
--sumi-border-focus: rgba(80,110,170, 0.45);
--sumi-border-accent: rgba(80,110,170, 0.25);
--sumi-text-primary: #1a1816;
--sumi-text-secondary: #5c5854;
--sumi-text-tertiary: #8a8580;
--sumi-text-disabled: #b5b0aa;
--sumi-text-inverse: #f0ede8;
--sumi-text-link: #4a6fa5;
--sumi-accent: #4a6fa5;
--sumi-accent-hover: #3a5f95;
--sumi-accent-active: #5a7fb5;
--sumi-vermillion: #b84a35;
--sumi-vermillion-hover: #a03e2e;
--sumi-sage: #5a7e4e;
--sumi-sage-hover: #4d6e42;
--sumi-gold: #9a7d2e;
--sumi-gold-hover: #8a6d20;
--sumi-shadow-xs: 0 1px 2px rgba(0,0,0,0.05);
--sumi-shadow-sm: 0 2px 4px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
--sumi-shadow-md: 0 4px 12px rgba(0,0,0,0.08), 0 2px 4px rgba(0,0,0,0.04);
--sumi-shadow-lg: 0 8px 24px rgba(0,0,0,0.10), 0 4px 8px rgba(0,0,0,0.05);
--sumi-shadow-xl: 0 16px 48px rgba(0,0,0,0.12), 0 8px 16px rgba(0,0,0,0.06);
--sumi-shadow-2xl: 0 24px 64px rgba(0,0,0,0.15);
--sumi-glass-bg: rgba(255,255,255, 0.85);
--sumi-glass-border: rgba(0,0,0, 0.06);
--sumi-scrollbar-thumb: rgba(0,0,0, 0.12);
--sumi-scrollbar-hover: rgba(0,0,0, 0.22);
}
10.3 shadcn/Radix Semantic Mapping
For shadcn/ui components, map --sumi-* tokens to the expected semantic variables:
:root, [data-theme="dark"] {
--background: var(--sumi-bg-base);
--foreground: var(--sumi-text-primary);
--card: var(--sumi-surface-card);
--card-foreground: var(--sumi-text-primary);
--popover: var(--sumi-bg-overlay);
--popover-foreground: var(--sumi-text-primary);
--primary: var(--sumi-accent);
--primary-foreground: var(--sumi-text-inverse);
--secondary: var(--sumi-bg-hover);
--secondary-foreground: var(--sumi-text-primary);
--muted: var(--sumi-bg-hover);
--muted-foreground: var(--sumi-text-secondary);
--accent: var(--sumi-bg-hover);
--accent-foreground: var(--sumi-text-primary);
--destructive: var(--sumi-vermillion);
--destructive-foreground: #ffffff;
--border: var(--sumi-border-default);
--input: var(--sumi-border-default);
--ring: var(--sumi-border-focus);
--radius: var(--sumi-radius-md);
/* Sidebar mapping */
--sidebar: var(--sumi-bg-raised);
--sidebar-foreground: var(--sumi-text-secondary);
--sidebar-primary: var(--sumi-accent);
--sidebar-primary-foreground: var(--sumi-text-primary);
--sidebar-accent: var(--sumi-accent-subtle);
--sidebar-accent-foreground: var(--sumi-text-primary);
--sidebar-border: var(--sumi-border-faint);
}
10.4 Tailwind Theme Mapping
@theme inline {
/* Typography */
--font-sans: var(--sumi-font-body);
--font-heading: var(--sumi-font-heading);
--font-mono: var(--sumi-font-mono);
--font-serif: var(--sumi-font-serif);
/* Semantic color mapping to Tailwind utilities */
--color-background: var(--background);
--color-foreground: var(--foreground);
--color-card: var(--card);
--color-card-foreground: var(--card-foreground);
--color-popover: var(--popover);
--color-popover-foreground: var(--popover-foreground);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-muted: var(--muted);
--color-muted-foreground: var(--muted-foreground);
--color-accent: var(--accent);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-foreground: var(--destructive-foreground);
--color-border: var(--border);
--color-input: var(--input);
--color-ring: var(--ring);
/* Extended palette */
--color-success: var(--sumi-success);
--color-warning: var(--sumi-warning);
--color-error: var(--sumi-error);
--color-sumi-accent: var(--sumi-accent);
--color-sumi-vermillion: var(--sumi-vermillion);
--color-sumi-sage: var(--sumi-sage);
--color-sumi-gold: var(--sumi-gold);
--color-gaming-gold: var(--sumi-gold);
--color-terminal-green: #3eaa5e;
--color-graffiti-magenta: #c840a0;
--color-sakura: #e0a0b8;
/* Radius */
--radius-sm: var(--sumi-radius-sm);
--radius-md: var(--sumi-radius-md);
--radius-lg: var(--sumi-radius-lg);
--radius-xl: var(--sumi-radius-xl);
--radius-2xl: var(--sumi-radius-2xl);
--radius-full: var(--sumi-radius-full);
/* Sidebar */
--color-sidebar: var(--sidebar);
--color-sidebar-foreground: var(--sidebar-foreground);
--color-sidebar-primary: var(--sidebar-primary);
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
--color-sidebar-accent: var(--sidebar-accent);
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
--color-sidebar-border: var(--sidebar-border);
}
10.5 Migration Mapping (Old -> New)
| Ancien (Kodo/Fusion) | Nouveau (Sumi) |
|---|---|
--kodo-void / --veza-void |
--sumi-bg-void |
--kodo-ink / --veza-ink |
--sumi-bg-base |
--kodo-graphite |
--sumi-bg-raised |
--kodo-cyan / --veza-cyan |
--sumi-accent |
--kodo-magenta / --veza-magenta |
Supprime — utiliser --sumi-vermillion si danger |
--kodo-lime / --veza-lime |
Supprime — utiliser --sumi-sage si success |
--kodo-gold / --veza-xp-gold |
--sumi-gold |
--kodo-red / --veza-error |
--sumi-vermillion |
--glass-hud-bg |
--sumi-glass-bg |
--glow-cyan, --glow-magenta etc. |
Supprime — un seul --sumi-shadow-glow pour focus |
.clip-manga, .clip-hex |
Supprime |
.animate-neon-flicker |
Supprime |
.backdrop-blur-cyber |
.sumi-glass |
font-display (Orbitron) |
font-heading (Space Grotesk) |
font-body (Barlow/DM Sans) |
font-sans (Inter) |
10.6 Files to Update During Refonte
| File | Action | What Changes |
|---|---|---|
apps/web/src/index.css |
Rewrite | Replace ALL current :root, .dark, @theme, @layer content with SUMI tokens above. Keep layout utility classes. |
apps/web/src/styles/design-system.css |
Delete | All tokens merged into index.css. |
apps/web/src/styles/design-tokens.css |
Delete | All tokens merged into index.css. |
apps/web/docs/DESIGN_DIRECTION.md |
Archive | Rename to DESIGN_DIRECTION_LEGACY.md. Replaced by this document. |
apps/web/docs/DESIGN_TOKENS.md |
Rewrite | Point to this document as source of truth. |
apps/web/docs/APP_SHELL.md |
Keep | Still valid for shell layout. Update color references to --sumi-*. |
Google Fonts link in index.html |
Update | Load Inter + Space Grotesk + JetBrains Mono + Noto Serif JP. Remove Orbitron, Barlow, Bebas Neue, DM Sans. |
10.7 Migration Checklist
When refactoring each component/page from current system to SUMI:
□ Replace font references
- font-display/Orbitron → font-heading (Space Grotesk)
- font-body/Barlow/DM Sans → font-sans (Inter)
- Keep font-mono as-is (JetBrains Mono)
□ Replace color classes
- bg-kodo-void → bg-background (--sumi-bg-base)
- bg-kodo-ink → bg-card (--sumi-surface-card)
- bg-kodo-graphite → bg-muted (--sumi-bg-hover)
- text-kodo-text-main → text-foreground (--sumi-text-primary)
- text-kodo-text-dim → text-muted-foreground (--sumi-text-secondary)
- border-kodo-steel → border-border (--sumi-border-default)
- bg-kodo-cyan → bg-primary (--sumi-accent, use sparingly!)
- text-kodo-cyan → text-primary (--sumi-accent)
□ Remove excessive decoration
- Remove all hover:scale-* transforms
- Remove decorative shadows (keep only functional)
- Remove gradient backgrounds on cards
- Remove glow effects on general elements
- Remove neon border effects
□ Fix spacing
- Cards: p-4 or p-6 (not p-8)
- Sections: gap-6 or gap-8
- Page sections: gap-10 or gap-12
- Check 4px grid alignment
□ Verify accessibility
- Focus rings visible (--sumi-shadow-glow)
- Contrast ratios pass AA (4.5:1)
- Touch targets >= 44px
- Color not used alone for status
□ Test both modes
- Dark mode looks correct
- Light mode looks correct
- Transition between modes is smooth
10.8 Component Class Patterns
Standard patterns to follow when building/updating components:
// ✅ CORRECT — SUMI style
<div className="sumi-card">
<h3 className="sumi-h4">{title}</h3>
<p className="sumi-body" style={{ color: 'var(--sumi-text-secondary)' }}>{description}</p>
</div>
// Also OK — using Tailwind + shadcn semantic mapping
<Card className="bg-card border border-border rounded-lg p-4 hover:bg-accent transition-colors">
<h3 className="text-sm font-medium font-heading text-foreground">{title}</h3>
<p className="text-xs text-muted-foreground mt-1">{description}</p>
</Card>
// ❌ WRONG — Old style
<Card className="bg-kodo-ink border-kodo-steel rounded-2xl p-8 hover:scale-[1.02] hover:shadow-neon-cyan/20">
<h3 className="text-kodo-text-main font-display">{title}</h3>
</Card>
// ✅ CORRECT — Button
<button className="sumi-btn sumi-btn--primary">Upload Track</button>
// Also OK — Tailwind
<Button className="bg-primary text-primary-foreground hover:bg-primary/90 rounded-md px-4 py-2 text-sm font-medium font-sans">
Upload Track
</Button>
// ❌ WRONG
<Button className="bg-gradient-to-r from-kodo-cyan to-kodo-magenta hover:scale-105 font-display uppercase">
UPLOAD
</Button>
10.9 Migration Order
- Replace CSS tokens (search & replace global)
- Delete old files (
design-system.css,design-tokens.css) - Integrate new
--sumi-*tokens intoindex.css - Migrate shell components first (sidebar, header, player)
- Migrate primitives (buttons, inputs, cards)
- Migrate pages
- Validate with component checklist (Section 8)
11. Quick Reference Card
Colors You'll Use 95% of the Time
| What | Dark Mode | Light Mode |
|---|---|---|
| Page background | bg-background (--sumi-bg-base #121215) |
bg-background (--sumi-bg-base #f6f3ed) |
| Card background | bg-card (--sumi-surface-card #1a1a1f) |
bg-card (--sumi-surface-card #ffffff) |
| Primary text | text-foreground (--sumi-text-primary #f0ede8) |
text-foreground (--sumi-text-primary #1a1816) |
| Secondary text | text-muted-foreground (--sumi-text-secondary #a8a4a0) |
text-muted-foreground (#5c5854) |
| Borders | border-border (--sumi-border-default rgba 10%) |
same |
| Primary accent | bg-primary / text-primary (--sumi-accent #7c9dd6) |
#4a6fa5 |
| Hover surface | hover:bg-accent (--sumi-bg-hover #2a2a31) |
#ede9e1 |
The Only Fonts
| Tailwind Class | Font | Token |
|---|---|---|
font-sans |
Inter | --sumi-font-body |
font-heading |
Space Grotesk | --sumi-font-heading |
font-mono |
JetBrains Mono | --sumi-font-mono |
font-serif |
Noto Serif JP | --sumi-font-serif (rare) |
The Only Radii
| Token | Value | When |
|---|---|---|
--sumi-radius-md (6px) |
Buttons, inputs | |
--sumi-radius-lg (12px) |
Cards | |
--sumi-radius-xl (16px) |
Modals | |
--sumi-radius-full |
Avatars, pills |
The Only Shadows
| Token | When |
|---|---|
| none | Most elements (dark mode) |
--sumi-shadow-sm |
Cards (light mode) |
--sumi-shadow-lg |
Dropdowns, floating panels |
--sumi-shadow-xl |
Modals |
--sumi-shadow-glow |
Focus rings |
SUMI Design System v2.0 — Veza / Talas — "L'encre et la lumiere" This document is the single source of truth. All design decisions defer to it. 墨は心の鏡 — L'encre est le miroir du coeur