veza/apps/web/docs/DESIGN_SYSTEM_REFERENCE.md
senke f64a85414c refactor: Phase 1 — SUMI token foundation
- 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>
2026-02-12 01:48:01 +01:00

83 KiB
Raw Blame History

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

  1. 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.

  2. 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.

  3. Universalité — Lisible pour tous (8 ans80 ans, auditeur casuallabel pro). Pas de dark pattern, pas de complexité gratuite.

  4. 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.

  5. 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.

  6. 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-accent background, --sumi-text-inverse text
  • Links: --sumi-text-link
  • Active nav item: --sumi-accent-subtle background tint + --sumi-accent text
  • 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 300700 Universal readability. Google/Apple-tier.
Headings Space Grotesk --sumi-font-heading 'Inter', sans-serif 400700 Geometric but warm. Has personality without being aggressive. Nods to tech/cyber subtly.
Mono JetBrains Mono --sumi-font-mono 'SF Mono', 'Consolas', monospace 400600 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

  1. Never use more than 3 font weights on a single screen: pick from 400, 500, 600, 700.
  2. Headings are always font-heading (Space Grotesk), never mono or body.
  3. Monospace is ONLY for: BPM numbers, musical keys, code blocks, terminal output, timestamps in admin, file sizes, stream counts, durations.
  4. Maximum 4 type sizes per screen to maintain hierarchy clarity.
  5. Line length: Body text should not exceed 65ch (~520px at 14px). Use max-w-prose or equivalent.
  6. 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:

  1. Card padding: p-4 (compact) or p-6 (standard). NOT p-8 for cards (too much wasted space).
  2. Section spacing: gap-6 (tight) or gap-8 (standard) between related sections.
  3. Page-level spacing: gap-10 or gap-12 between major page sections.
  4. Never use space-y-* when gap-* 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:

  1. Default interactive elements (buttons, inputs): rounded (8px)
  2. Cards: rounded-lg (12px)
  3. Modals: rounded-xl (16px)
  4. Avatars: Always rounded-full
  5. 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:

  1. Glows are ANIMATED, never static (they pulse or appear then fade)
  2. Maximum 1 glowing element visible at a time on any screen
  3. 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:

  1. Cards do NOT have shadows in dark mode — they rely on background color difference.
  2. Cards in light mode get shadow-sm for subtle lift.
  3. Floating elements (player, dropdowns) get shadow-lg in light mode, shadow-md in dark mode.
  4. Modals always have shadow-xl + backdrop overlay (rgba(0,0,0,0.60) + backdrop-filter: blur(4px)).
  5. 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:

  1. Every animation must have a purpose: feedback, orientation, or celebration.
  2. If you can't explain what the animation TELLS the user — remove it.
  3. Hover effects are limited to: background change, opacity change, border change. NO scale transforms on cards.
  4. 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:

  1. Maximum 1 brush stroke element per screen
  2. Always opacity: 0.1 to 0.3 — they're atmosphere, not content
  3. Never compete with text for attention
  4. Color: sumi-400 or primary-400 only

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-accent fill + white check.
  • Toggle: See .sumi-toggle below.

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-tertiary color, 120px max
  • Title: sumi-h4, text-primary
  • Description: sumi-body, text-secondary, 2-3 lines max
  • CTA: .sumi-btn--primary below
  • 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-out on 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 alt text
  • All icons-only buttons have aria-label
  • Form fields have associated labels
  • Status changes use aria-live regions
  • 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 6401023px (md) 2-column grid, sidebar as overlay, condensed player
Desktop 10241279px (lg) Full sidebar + content, 3-column layouts
Large >= 1280px (xl) Max content width 1600px (max-w-layout-content), centered

Mobile-Specific Rules

  1. Sidebar becomes a bottom sheet or hamburger overlay
  2. Player mini-bar stays at bottom (above bottom nav if present)
  3. Cards go full-width with no horizontal padding reduction
  4. Touch targets minimum 44px x 44px (Apple HIG)
  5. 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

  1. Replace CSS tokens (search & replace global)
  2. Delete old files (design-system.css, design-tokens.css)
  3. Integrate new --sumi-* tokens into index.css
  4. Migrate shell components first (sidebar, header, player)
  5. Migrate primitives (buttons, inputs, cards)
  6. Migrate pages
  7. 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