veza/apps/web/src/index.css
senke af5c2ab3d2 feat: frontend improvements — UI polish, player bar, auth flow, i18n
- Header, Sidebar, Toast, Dropdown, EmptyState component refinements
- Auth flow: LoginPage, RegisterPage, AuthInput, AuthLayout improvements
- Player bar: glass effect, progress, track info, controls enhancements
- Dashboard, Discover, Search pages updates
- PlaylistCard, TrackCard component improvements
- Auth store and API interceptors hardening
- i18n: updated en/es/fr locale files
- CSS additions in index.css
- Package.json and vite config updates

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-18 11:35:44 +01:00

1054 lines
41 KiB
CSS
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

@import 'tailwindcss';
@import 'tw-animate-css';
@custom-variant dark (&:is([data-theme="dark"] *));
/* ╔══════════════════════════════════════════════════════════════════════════╗
║ SUMI DESIGN SYSTEM v2.0 — "L'encre et la lumière" ║
║ VEZA × TALAS — Single Source of Truth ║
║ Ref: apps/web/docs/DESIGN_SYSTEM_REFERENCE.md ║
╚══════════════════════════════════════════════════════════════════════════╝ */
/* ═══════════════════════════════════════════════════════════════════════════
DARK THEME (default) — Ink on void
═══════════════════════════════════════════════════════════════════════════ */
: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 — Les 4 Pigments d'accent ═══ */
--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-font-size-base: 16px;
--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;
/* Aliases for components using legacy var names */
--duration-fast: var(--sumi-duration-fast);
--duration-normal: var(--sumi-duration-normal);
--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;
/* ═══ CONTEXTUAL ACCENTS (feature-specific) ═══ */
--graffiti-magenta: #c840a0;
--gaming-gold: #d4b040;
--terminal-green: #3eaa5e;
--sakura: #e0a0b8;
/* ═══ SHADCN/RADIX SEMANTIC MAPPING ═══ */
--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;
--success: var(--sumi-success);
--success-foreground: #ffffff;
--warning: var(--sumi-warning);
--warning-foreground: var(--sumi-text-inverse);
--info: var(--sumi-info);
--info-foreground: var(--sumi-text-inverse);
--border: var(--sumi-border-default);
--input: var(--sumi-border-default);
--ring: var(--sumi-border-focus);
--radius: var(--sumi-radius-md);
/* Charts */
--chart-1: var(--sumi-accent);
--chart-2: var(--sumi-vermillion);
--chart-3: var(--sumi-sage);
--chart-4: var(--sumi-gold);
--chart-5: #8b7ec8;
/* 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);
--sidebar-ring: var(--sumi-accent);
/* Sidebar active item indicator */
--sidebar-active-indicator: inset 2px 0 0 0 var(--sidebar-primary);
/* ═══ LAYOUT PRIMITIVES (preserved from previous system) ═══ */
--layout-content-max-width: 100rem;
--layout-main-min-height: calc(100vh - 4rem);
--layout-page-min-height: 37.5rem;
--layout-page-min-height-sm: 25rem;
--layout-story-decorator-min-height: 12rem;
--layout-gap: 1rem;
--layout-gap-sm: 0.75rem;
--layout-gap-lg: 1.5rem;
--layout-drawer-max-height: 60vh;
--layout-panel-max-height: 70vh;
--layout-list-max-height: 25rem;
--layout-modal-max-height: 85vh;
--layout-modal-max-height-sm: 80vh;
--layout-modal-max-height-xs: 70vh;
--layout-modal-max-height-lg: 90vh;
--layout-lyrics-height: 60vh;
--layout-lyrics-height-sm: 50vh;
--layout-chat-height: calc(100vh - 6.25rem);
--layout-chat-main-height: calc(100vh - 6rem);
--layout-stream-height: calc(100vh - 6rem);
--layout-modal-full-height: calc(100vh - 2rem);
/* App shell — header, main offsets and margins (sidebar-driven) */
--header-height: 4rem;
--main-offset-top: 5rem;
--main-offset-bottom: 9rem;
--main-margin-left-expanded: 18rem;
--main-margin-left-collapsed: 7rem;
--header-left-expanded: 18rem;
--header-left-collapsed: 5rem;
/* Sidebar layout */
--sidebar-width-expanded: 15rem;
--sidebar-width-collapsed: 5rem;
--sidebar-offset-left: 1.5rem;
--sidebar-offset-top: 5rem;
--sidebar-offset-bottom: 1.5rem;
--sidebar-z-index: 95;
--sidebar-overlay-z-index: 90;
--player-z-index: var(--sumi-z-sticky);
}
/* ═══════════════════════════════════════════════════════════════════════════
LIGHT THEME — Washi Paper (和紙)
═══════════════════════════════════════════════════════════════════════════ */
[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-accent-subtle: rgba(74,111,165, 0.12);
--sumi-accent-muted: rgba(74,111,165, 0.20);
--sumi-accent-emphasis: #3d5f90;
--sumi-vermillion: #b84a35;
--sumi-vermillion-hover: #a03e2e;
--sumi-vermillion-subtle: rgba(184,74,53, 0.12);
--sumi-sage: #5a7e4e;
--sumi-sage-hover: #4d6e42;
--sumi-sage-subtle: rgba(90,126,78, 0.12);
--sumi-gold: #9a7d2e;
--sumi-gold-hover: #8a6d20;
--sumi-gold-subtle: rgba(154,125,46, 0.12);
--sumi-live: #c84040;
--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-shadow-glow: 0 0 0 3px rgba(74,111,165,0.25);
--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);
--primary-foreground: #ffffff;
}
/* ═══════════════════════════════════════════════════════════════════════════
HIGH CONTRAST MODE — WCAG AA 4.5:1+
═══════════════════════════════════════════════════════════════════════════ */
[data-theme="dark"][data-contrast="high"] {
--sumi-bg-void: #000000;
--sumi-bg-base: #000000;
--sumi-bg-raised: #0a0a0a;
--sumi-bg-overlay: #111111;
--sumi-bg-hover: #1a1a1a;
--sumi-bg-active: #222222;
--sumi-text-primary: #ffffff;
--sumi-text-secondary: #d0d0d0;
--sumi-text-tertiary: #b0b0b0;
--sumi-border-default: rgba(255,255,255,0.30);
--sumi-border-faint: rgba(255,255,255,0.15);
--sumi-border-strong: rgba(255,255,255,0.50);
}
[data-theme="light"][data-contrast="high"] {
--sumi-bg-void: #ffffff;
--sumi-bg-base: #ffffff;
--sumi-bg-raised: #f5f5f5;
--sumi-bg-overlay: #eeeeee;
--sumi-bg-hover: #e0e0e0;
--sumi-bg-active: #d0d0d0;
--sumi-text-primary: #000000;
--sumi-text-secondary: #333333;
--sumi-text-tertiary: #555555;
--sumi-border-default: rgba(0,0,0,0.30);
--sumi-border-faint: rgba(0,0,0,0.15);
--sumi-border-strong: rgba(0,0,0,0.50);
}
/* ═══════════════════════════════════════════════════════════════════════════
DENSITY MODES — compact reduces spacing ~25%
═══════════════════════════════════════════════════════════════════════════ */
[data-density="compact"] {
--sumi-space-0-5: 1.5px;
--sumi-space-1: 3px;
--sumi-space-1-5: 4.5px;
--sumi-space-2: 6px;
--sumi-space-2-5: 7.5px;
--sumi-space-3: 9px;
--sumi-space-4: 12px;
--sumi-space-5: 15px;
--sumi-space-6: 18px;
--sumi-space-8: 24px;
--sumi-space-10: 30px;
--sumi-space-12: 36px;
--sumi-space-16: 48px;
--sumi-space-20: 60px;
--sumi-text-base: 0.8125rem;
}
[data-density="comfortable"] {
font-size: 1rem;
}
/* ═══════════════════════════════════════════════════════════════════════════
FOCUS VISIBLE — distinct ring for keyboard navigation
═══════════════════════════════════════════════════════════════════════════ */
:focus-visible {
outline: 2px solid var(--sumi-accent);
outline-offset: 2px;
}
/* ═══════════════════════════════════════════════════════════════════════════
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 semantic */
--color-success: var(--success);
--color-success-foreground: var(--success-foreground);
--color-warning: var(--warning);
--color-warning-foreground: var(--warning-foreground);
--color-info: var(--info);
--color-info-foreground: var(--info-foreground);
/* SUMI direct accent access */
--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;
/* Chart colors */
--color-chart-1: var(--chart-1);
--color-chart-2: var(--chart-2);
--color-chart-3: var(--chart-3);
--color-chart-4: var(--chart-4);
--color-chart-5: var(--chart-5);
/* Shadows — wired to SUMI tokens (auto dark/light) */
--shadow-xs: var(--sumi-shadow-xs);
--shadow-sm: var(--sumi-shadow-sm);
--shadow-md: var(--sumi-shadow-md);
--shadow-lg: var(--sumi-shadow-lg);
--shadow-xl: var(--sumi-shadow-xl);
--shadow-2xl: var(--sumi-shadow-2xl);
/* Card-specific shadows */
--shadow-card: var(--sumi-shadow-sm);
--shadow-card-hover: var(--sumi-shadow-md);
/* 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);
--color-sidebar-ring: var(--sidebar-ring);
}
/* ═══════════════════════════════════════════════════════════════════════════
BASE STYLES
═══════════════════════════════════════════════════════════════════════════ */
@layer base {
* {
@apply border-border outline-ring/50;
}
html {
scroll-behavior: smooth;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
body {
@apply bg-background text-foreground;
font-size: var(--sumi-font-size-base);
font-feature-settings: "cv02", "cv03", "cv04", "cv11";
}
/* Paper grain texture — barely perceptible washi feeling */
body::before {
content: '';
position: fixed;
inset: 0;
background:
url("data:image/svg+xml,%3Csvg viewBox='0 0 400 400' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noise'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.8' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noise)'/%3E%3C/svg%3E");
opacity: 0.012;
pointer-events: none;
z-index: 9998;
mix-blend-mode: overlay;
}
::selection {
background: var(--primary);
color: var(--primary-foreground);
}
/* Custom Scrollbar — thin, subtle */
::-webkit-scrollbar {
width: 6px;
height: 6px;
}
::-webkit-scrollbar-track {
background: var(--sumi-scrollbar-track);
}
::-webkit-scrollbar-thumb {
background: var(--sumi-scrollbar-thumb);
border-radius: var(--sumi-radius-full);
transition: background-color 0.2s ease;
}
::-webkit-scrollbar-thumb:hover {
background: var(--sumi-scrollbar-hover);
}
@supports (scrollbar-width: thin) {
* {
scrollbar-width: thin;
scrollbar-color: var(--sumi-scrollbar-thumb) transparent;
}
}
/* Typography — headings use Space Grotesk */
h1, h2, h3, h4, h5, h6 {
@apply font-heading font-semibold tracking-tight text-foreground;
text-wrap: balance;
}
h1 { @apply text-4xl md:text-5xl; }
h2 { @apply text-3xl md:text-4xl; }
h3 { @apply text-2xl md:text-3xl; }
h4 { @apply text-xl md:text-2xl; }
h5 { @apply text-lg md:text-xl; }
h6 { @apply text-base md:text-lg; }
p {
@apply text-muted-foreground leading-relaxed;
text-wrap: pretty;
}
a:not([class]) {
@apply text-primary transition-colors;
}
a:not([class]):hover {
@apply text-primary/80;
}
code {
@apply font-mono text-sm bg-muted px-1.5 py-0.5 rounded;
}
pre {
@apply font-mono text-sm bg-muted p-4 rounded-lg overflow-x-auto;
}
}
/* ═══════════════════════════════════════════════════════════════════════════
SUMI UTILITY CLASSES
═══════════════════════════════════════════════════════════════════════════ */
@layer utilities {
/* Layout primitives — standard widths/heights for app shell and pages */
.max-w-layout-content { max-width: var(--layout-content-max-width); }
.min-h-layout-main { min-height: var(--layout-main-min-height); }
.min-h-layout-page { min-height: var(--layout-page-min-height); }
.min-h-layout-page-sm { min-height: var(--layout-page-min-height-sm); }
.min-h-layout-story { min-height: var(--layout-story-decorator-min-height); }
.max-h-layout-drawer { max-height: var(--layout-drawer-max-height); }
.max-h-layout-panel { max-height: var(--layout-panel-max-height); }
.max-h-layout-list { max-height: var(--layout-list-max-height); }
.max-h-layout-modal { max-height: var(--layout-modal-max-height); }
.max-h-layout-modal-sm { max-height: var(--layout-modal-max-height-sm); }
.max-h-layout-modal-xs { max-height: var(--layout-modal-max-height-xs); }
.max-h-layout-modal-lg { max-height: var(--layout-modal-max-height-lg); }
.h-layout-modal-sm { height: var(--layout-modal-max-height-sm); }
.h-layout-lyrics { height: var(--layout-lyrics-height); }
.h-layout-lyrics-sm { height: var(--layout-lyrics-height-sm); }
.h-layout-chat { height: var(--layout-chat-height); }
.h-layout-chat-main { height: var(--layout-chat-main-height); }
.h-layout-stream { height: var(--layout-stream-height); }
.h-layout-modal-full { height: var(--layout-modal-full-height); }
/* Sidebar layout utilities */
.w-sidebar-expanded { width: var(--sidebar-width-expanded); }
.w-sidebar-collapsed { width: var(--sidebar-width-collapsed); }
.left-sidebar { left: var(--sidebar-offset-left); }
.top-sidebar { top: var(--sidebar-offset-top); }
.bottom-sidebar { bottom: var(--sidebar-offset-bottom); }
.z-sidebar { z-index: var(--sidebar-z-index); }
.z-sidebar-overlay { z-index: var(--sidebar-overlay-z-index); }
.z-player { z-index: var(--player-z-index); }
/* App shell — header / main offsets */
.h-header { height: var(--header-height); }
.pt-main { padding-top: var(--main-offset-top); }
.pb-main { padding-bottom: var(--main-offset-bottom); }
.ml-main-expanded { margin-left: var(--main-margin-left-expanded); }
.ml-main-collapsed { margin-left: var(--main-margin-left-collapsed); }
/* Responsive margin-left for main */
@media (min-width: 1024px) {
.lg\:ml-main-expanded { margin-left: var(--main-margin-left-expanded); }
.lg\:ml-main-collapsed { margin-left: var(--main-margin-left-collapsed); }
.lg\:left-main-expanded { left: var(--main-margin-left-expanded); }
.lg\:left-main-collapsed { left: var(--main-margin-left-collapsed); }
.lg\:w-player-bar-expanded { width: calc(100vw - var(--main-margin-left-expanded) - 1rem); }
.lg\:w-player-bar-collapsed { width: calc(100vw - var(--main-margin-left-collapsed) - 1rem); }
}
/* Player bar width: mobile (no sidebar) */
.w-player-bar { width: calc(100vw - 2rem); }
.left-header-expanded { left: var(--header-left-expanded); }
.left-header-collapsed { left: var(--header-left-collapsed); }
/* Shell transition — sidebar width/opacity */
.transition-shell {
transition: width var(--sumi-duration-normal) var(--sumi-ease-out),
opacity var(--sumi-duration-normal) var(--sumi-ease-out),
transform var(--sumi-duration-normal) var(--sumi-ease-out);
}
/* Respect prefers-reduced-motion */
@media (prefers-reduced-motion: reduce) {
.transition-shell {
transition: none;
}
.player-bar-entrance {
animation: none !important;
}
}
/* Sidebar active nav item — left border indicator */
.sidebar-active-indicator {
box-shadow: var(--sidebar-active-indicator);
}
/* Glass Effect */
.glass, .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);
}
/* Typography utilities — SUMI hierarchy */
.font-heading { font-family: var(--sumi-font-heading); }
.font-serif { font-family: var(--sumi-font-serif); }
.text-display { @apply text-4xl font-bold tracking-tight; }
.text-heading-1 { @apply text-3xl font-semibold tracking-tight; }
.text-heading-2 { @apply text-2xl font-semibold; }
.text-heading-3 { @apply text-xl font-medium; }
.text-heading-4 { @apply text-lg font-medium; }
.text-body-lg { @apply text-base leading-relaxed; }
.text-body { @apply text-sm leading-relaxed; }
.text-caption { @apply text-xs text-muted-foreground; }
.text-label { @apply text-xs font-medium uppercase tracking-wider text-muted-foreground; }
/* SUMI typography classes (from design system) */
.sumi-display { font-family: var(--sumi-font-heading); font-size: var(--sumi-text-4xl); font-weight: var(--sumi-weight-bold); line-height: var(--sumi-leading-tight); letter-spacing: var(--sumi-tracking-tighter); }
.sumi-h1 { font-family: var(--sumi-font-heading); font-size: var(--sumi-text-3xl); font-weight: var(--sumi-weight-semibold); line-height: var(--sumi-leading-tight); letter-spacing: var(--sumi-tracking-tight); }
.sumi-h2 { font-family: var(--sumi-font-heading); font-size: var(--sumi-text-2xl); font-weight: var(--sumi-weight-semibold); line-height: var(--sumi-leading-snug); letter-spacing: var(--sumi-tracking-tight); }
.sumi-h3 { font-family: var(--sumi-font-heading); font-size: var(--sumi-text-xl); font-weight: var(--sumi-weight-medium); line-height: var(--sumi-leading-snug); }
.sumi-h4 { font-family: var(--sumi-font-heading); font-size: var(--sumi-text-lg); font-weight: var(--sumi-weight-medium); line-height: var(--sumi-leading-snug); }
.sumi-body-lg { font-size: var(--sumi-text-md); font-weight: var(--sumi-weight-regular); line-height: var(--sumi-leading-relaxed); }
.sumi-body { font-size: var(--sumi-text-base); font-weight: var(--sumi-weight-regular); line-height: var(--sumi-leading-normal); }
.sumi-body-sm { font-size: var(--sumi-text-sm); font-weight: var(--sumi-weight-regular); line-height: var(--sumi-leading-normal); }
.sumi-caption { font-size: var(--sumi-text-xs); font-weight: var(--sumi-weight-regular); line-height: var(--sumi-leading-normal); }
.sumi-label { font-size: var(--sumi-text-xs); font-weight: var(--sumi-weight-medium); line-height: var(--sumi-leading-normal); letter-spacing: var(--sumi-tracking-wider); text-transform: uppercase; }
.sumi-mono { font-family: var(--sumi-font-mono); font-size: var(--sumi-text-sm); }
/* Animation Utilities */
.animate-fade-in { animation: sumi-fade-in var(--sumi-duration-normal) var(--sumi-ease-out); }
.animate-slide-up { animation: sumi-slide-up var(--sumi-duration-normal) var(--sumi-ease-out); }
.animate-scale-in { animation: sumi-scale-in var(--sumi-duration-normal) var(--sumi-ease-out); }
.animate-fadeIn { animation: sumi-fade-in var(--sumi-duration-normal) var(--sumi-ease-out); }
.animate-scaleIn { animation: sumi-scale-in var(--sumi-duration-normal) var(--sumi-ease-out); }
.animate-pop { animation: sumi-pop var(--sumi-duration-slower) var(--sumi-ease-bounce); }
.animate-like-bounce { animation: like-bounce var(--sumi-duration-slow) var(--sumi-ease-out); }
.animate-shake { animation: shake 0.4s ease-in-out; }
.animate-spin-slow { animation: spin-slow 10s linear infinite; }
.animate-achievement { animation: achievement-slide 0.5s var(--sumi-ease-spring); }
.animate-eq { animation: eq-bar 0.5s ease-in-out infinite; }
.animate-marquee { animation: marquee 10s linear infinite; }
.animate-auth-enter { animation: auth-enter var(--sumi-duration-slow) var(--sumi-ease-out) both; }
.animate-empty-state-in { animation: sumi-scale-in var(--sumi-duration-normal) var(--sumi-ease-out) both; }
.animate-stagger-in { animation: sumi-slide-up var(--sumi-duration-normal) var(--sumi-ease-out) both; }
.animate-glow-pulse { animation: sumi-pulse 2s ease-in-out infinite; }
.animate-content-reveal { animation: content-reveal var(--sumi-duration-slow) var(--sumi-ease-out) both; }
.animate-glow-breathe { animation: glow-breathe 3s ease-in-out infinite; }
.animate-vinyl-spin { animation: vinyl-spin 3s linear infinite; }
.animate-vinyl-spin.paused { animation-play-state: paused; }
.animate-slide-in-right { animation: slide-in-right var(--sumi-duration-normal) var(--sumi-ease-spring); }
.animate-subtle-float { animation: subtle-float 6s ease-in-out infinite; }
/* Player bar entrance */
.player-bar-entrance {
animation: player-bar-entrance var(--sumi-duration-slower) var(--sumi-ease-spring) both;
}
/* Spotify-style progress bar */
.progress-bar-animated {
background: linear-gradient(90deg, var(--sumi-accent) 0%, var(--sumi-accent-hover) 50%, var(--sumi-accent) 100%);
background-size: 200% 100%;
animation: progress-shimmer 2s ease-in-out infinite;
}
/* Discord-style hover card lift */
.hover-lift {
transition: transform var(--sumi-duration-normal) var(--sumi-ease-out),
box-shadow var(--sumi-duration-normal) var(--sumi-ease-out);
}
.hover-lift:hover {
transform: translateY(-2px);
box-shadow: var(--sumi-shadow-lg);
}
.hover-lift:active {
transform: translateY(0);
box-shadow: var(--sumi-shadow-sm);
}
/* Scrollbar hide utility */
.scrollbar-hide {
-ms-overflow-style: none;
scrollbar-width: none;
}
.scrollbar-hide::-webkit-scrollbar {
display: none;
}
/* Line clamp utilities */
.line-clamp-2 {
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden;
}
.line-clamp-3 {
display: -webkit-box;
-webkit-line-clamp: 3;
-webkit-box-orient: vertical;
overflow: hidden;
}
/* Ink Wash Texture (hero/feature sections) */
.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;
}
/* Noise texture utility */
.noise { position: relative; }
.noise::before {
content: "";
position: absolute;
inset: 0;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.7' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.04'/%3E%3C/svg%3E");
pointer-events: none;
opacity: 0.5;
mix-blend-mode: overlay;
border-radius: inherit;
}
@media (prefers-reduced-motion: reduce) {
.animate-stagger-in { animation: none; }
.animate-glow-pulse { animation: none; }
.animate-content-reveal { animation: none; }
.animate-glow-breathe { animation: none; }
.animate-vinyl-spin { animation: none; }
.animate-slide-in-right { animation: none; }
.animate-subtle-float { animation: none; }
.progress-bar-animated { animation: none; }
.hover-lift { transition: none; }
.hover-lift:hover { transform: none; }
}
}
/* ═══════════════════════════════════════════════════════════════════════════
SKELETON SHIMMER — loading effect
═══════════════════════════════════════════════════════════════════════════ */
.skeleton-shimmer {
background: linear-gradient(
90deg,
transparent 0%,
rgba(255, 255, 255, 0.06) 40%,
rgba(255, 255, 255, 0.1) 50%,
rgba(255, 255, 255, 0.06) 60%,
transparent 100%
);
background-size: 200% 100%;
animation: shimmer 1.8s ease-in-out infinite;
}
@media (prefers-reduced-motion: reduce) {
.skeleton-shimmer {
animation: none;
background: none;
}
}
/* ═══════════════════════════════════════════════════════════════════════════
KEYFRAME ANIMATIONS — SUMI
═══════════════════════════════════════════════════════════════════════════ */
/* Core SUMI animations */
@keyframes sumi-fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
/* S5.1: Branded loading progress bar */
@keyframes loading-progress {
0% { width: 0; transform: translateX(0); }
50% { width: 70%; transform: translateX(0); }
100% { width: 100%; transform: translateX(100%); }
}
@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); }
}
/* Pop animation for modals/toasts */
@keyframes sumi-pop {
0% { opacity: 0; transform: scale(0.8); }
60% { opacity: 1; transform: scale(1.05); }
100% { transform: scale(1); }
}
/* Live/status pulse */
@keyframes sumi-pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.5; }
}
/* Ink brush stroke reveal — page transitions */
@keyframes sumi-brush-reveal {
from { clip-path: inset(0 100% 0 0); }
to { clip-path: inset(0 0 0 0); }
}
/* Skeleton loading */
@keyframes shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
/* EQ bars — "now playing" indicator */
@keyframes eq-bar {
0%, 100% { transform: scaleY(0.3); }
50% { transform: scaleY(1); }
}
/* Legacy-compatible animations (used in existing codebase) */
@keyframes like-bounce {
0% { transform: scale(1); }
25% { transform: scale(1.3); }
50% { transform: scale(0.9); }
75% { transform: scale(1.1); }
100% { transform: scale(1); }
}
@keyframes shake {
0%, 100% { transform: translateX(0); }
10%, 30%, 50%, 70%, 90% { transform: translateX(-4px); }
20%, 40%, 60%, 80% { transform: translateX(4px); }
}
@keyframes spin-slow {
to { transform: rotate(360deg); }
}
@keyframes typing {
0%, 60%, 100% { transform: translateY(0); }
30% { transform: translateY(-4px); }
}
@keyframes marquee {
0%, 20% { transform: translateX(0); }
80%, 100% { transform: translateX(-100%); }
}
@keyframes achievement-slide {
from { transform: translateX(100%); opacity: 0; }
to { transform: translateX(0); opacity: 1; }
}
@keyframes terminal-blink {
0%, 50% { opacity: 1; }
51%, 100% { opacity: 0; }
}
@keyframes auth-enter {
from { opacity: 0; transform: translateY(12px) scale(0.98); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
/* Player bar entrance — Spotify-style float up */
@keyframes player-bar-entrance {
from { opacity: 0; transform: translateY(20px) scale(0.98); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
/* Spotify-style content reveal */
@keyframes content-reveal {
from { opacity: 0; transform: translateY(16px) scale(0.99); filter: blur(4px); }
to { opacity: 1; transform: translateY(0) scale(1); filter: blur(0); }
}
/* Discord-style hover glow */
@keyframes glow-breathe {
0%, 100% { box-shadow: 0 0 0 0 rgba(124,157,214, 0); }
50% { box-shadow: 0 0 20px 2px rgba(124,157,214, 0.15); }
}
/* Vinyl spin for now-playing */
@keyframes vinyl-spin {
from { transform: rotate(0deg); }
to { transform: rotate(360deg); }
}
/* Progress bar shimmer (Spotify-style) */
@keyframes progress-shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
/* Notification slide in from right */
@keyframes slide-in-right {
from { opacity: 0; transform: translateX(100%); }
to { opacity: 1; transform: translateX(0); }
}
/* Subtle float for cards */
@keyframes subtle-float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-4px); }
}
@keyframes bar-fill {
from { width: 0; }
}
@keyframes level-up {
0% { transform: scale(1); }
50% { transform: scale(1.2); filter: brightness(1.5); }
100% { transform: scale(1); }
}
/* ═══════════════════════════════════════════════════════════════════════════
REDUCED MOTION
═══════════════════════════════════════════════════════════════════════════ */
@media (prefers-reduced-motion: reduce) {
*, *::before, *::after {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
scroll-behavior: auto !important;
}
/* Keep opacity transitions for functional feedback */
.interactive { transition: opacity 100ms ease-out; }
}