veza/apps/web/src/index.css
senke bdca911730 fix(a11y): fix primary button contrast ratio + tap-target test false positives
- Fix --sumi-text-inverse: #13110f → #f5f0e8 (was dark-on-dark)
  Primary buttons now have ~4.8:1 contrast ratio (WCAG AA pass)
  Affects: Sign In, Register, all primary action buttons

- Tap-target test: skip sr-only elements (intentionally invisible)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-25 09:53:51 +01:00

1448 lines
56 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 v4.0 — "Lavis d'encre" (墨の濃淡) ║
║ VEZA × TALAS — Single Source of Truth ║
║ Ink wash aesthetic — contrast, wabi-sabi, ma (間) ║
╚══════════════════════════════════════════════════════════════════════════╝ */
/* ═══════════════════════════════════════════════════════════════════════════
DARK THEME (default) — Sumi ink on void (墨の闇)
═══════════════════════════════════════════════════════════════════════════ */
:root, [data-theme="dark"] {
/* ═══ BACKGROUNDS — Ink dilutions (墨の濃淡) ═══ */
--sumi-bg-void: #0d0d0b;
--sumi-bg-base: #13110f;
--sumi-bg-raised: #1a1714;
--sumi-bg-overlay: #242018;
--sumi-bg-hover: #2e2a22;
--sumi-bg-active: #383228;
--sumi-bg-wash: #17140f;
/* ═══ SURFACES — Ink planes (墨面) ═══ */
--sumi-surface-inset: #0f0d0b;
--sumi-surface-subtle: #1e1a15;
--sumi-surface-card: #1a1714;
--sumi-surface-elevated: #242018;
/* ═══ BORDERS — Ink lines (筆線) ═══ */
--sumi-border-faint: rgba(232,224,208, 0.03);
--sumi-border-default: rgba(232,224,208, 0.06);
--sumi-border-strong: rgba(232,224,208, 0.10);
--sumi-border-focus: rgba(184,58,30, 0.50);
--sumi-border-accent: rgba(184,58,30, 0.25);
/* ═══ TEXT — Ink on washi (墨と和紙) ═══ */
--sumi-text-primary: #e8e0d0;
--sumi-text-secondary: #9e9688;
--sumi-text-tertiary: #6b6560;
--sumi-text-disabled: #3d3930;
--sumi-text-inverse: #f5f0e8;
--sumi-text-link: #b83a1e;
/* ═══ PIGMENTS — Shu vermillion (朱) + Kin gold (金) ═══ */
--sumi-accent: #b83a1e;
--sumi-accent-hover: #c84a2e;
--sumi-accent-active: #8b2500;
--sumi-accent-muted: rgba(184,58,30, 0.18);
--sumi-accent-subtle: rgba(184,58,30, 0.06);
--sumi-accent-emphasis: #8b2500;
--sumi-vermillion: #a04050;
--sumi-vermillion-hover: #b05060;
--sumi-vermillion-subtle: rgba(160,64,80, 0.10);
--sumi-sage: #4f6840;
--sumi-sage-hover: #5f7850;
--sumi-sage-subtle: rgba(79,104,64, 0.10);
--sumi-gold: #b8860b;
--sumi-gold-hover: #c8960b;
--sumi-gold-subtle: rgba(184,134,11, 0.10);
/* ═══ 金 — KIN (GOLD LEAF) ═══ */
--sumi-kin: #b8860b;
--sumi-kin-hover: #c8960b;
--sumi-kin-subtle: rgba(184,134,11, 0.08);
/* ═══ PATINA (SUMI v4) ═══ */
--sumi-patina-green: #5A8A72;
--sumi-patina-warmth: 0deg;
--sumi-grain-opacity: 0.05;
/* ═══ 墨の六色 — Six Tones of Ink ═══ */
--sumi-ink-kuro: #0d0d0b; /* 黒 pure black */
--sumi-ink-sumi: #1a1714; /* 墨 ink */
--sumi-ink-usuzumi: #3d3930; /* 薄墨 light ink */
--sumi-ink-hai: #6b6560; /* 灰 ash */
--sumi-ink-gin: #9e9688; /* 銀 silver */
--sumi-ink-kasumi: #c4bba8; /* 霞 mist */
/* ═══ CIRCADIAN (SUMI v4) ═══ */
--sumi-circadian-warmth: 0deg;
--sumi-circadian-brightness: 1;
/* ═══ 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: #a04050;
--sumi-online: var(--sumi-sage);
/* ═══ TYPOGRAPHY ═══ */
--sumi-font-body: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--sumi-font-heading: 'Noto Serif JP', Georgia, 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.2em;
--sumi-weight-extralight: 200;
--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: 1px;
--sumi-radius-sm: 2px;
--sumi-radius-md: 2px;
--sumi-radius-lg: 4px;
--sumi-radius-xl: 6px;
--sumi-radius-2xl: 8px;
--sumi-radius-full: 9999px;
/* ═══ SHADOWS — Ink diffusion (滲み) ═══ */
--sumi-shadow-xs: 0 1px 3px rgba(13,13,11,0.20);
--sumi-shadow-sm: 0 2px 8px rgba(13,13,11,0.15), 0 1px 3px rgba(13,13,11,0.12);
--sumi-shadow-md: 0 4px 20px rgba(13,13,11,0.15), 0 2px 6px rgba(13,13,11,0.10);
--sumi-shadow-lg: 0 8px 35px rgba(13,13,11,0.18), 0 4px 12px rgba(13,13,11,0.10);
--sumi-shadow-xl: 0 16px 55px rgba(13,13,11,0.22), 0 8px 20px rgba(13,13,11,0.12);
--sumi-shadow-2xl: 0 24px 75px rgba(13,13,11,0.30);
--sumi-shadow-glow: 0 0 0 3px rgba(184,58,30, 0.20);
--sumi-shadow-glow-lg: 0 0 20px rgba(184,58,30, 0.10);
--sumi-shadow-kin: 0 0 16px rgba(184,134,11, 0.15);
/* ═══ GLASS — Shoji screen (障子) ═══ */
--sumi-glass-bg: rgba(19,17,15, 0.80);
--sumi-glass-border: rgba(232,224,208, 0.04);
--sumi-glass-blur: 12px;
/* ═══ SCROLLBAR ═══ */
--sumi-scrollbar-track: transparent;
--sumi-scrollbar-thumb: rgba(232,224,208, 0.06);
--sumi-scrollbar-hover: rgba(232,224,208, 0.12);
/* ═══ 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: #a04050;
--gaming-gold: #b8860b;
--terminal-green: #4f6840;
--sakura: #d4a0b0;
--sumi-shu: #b83a1e; /* 朱 — hanko seal vermillion */
--sumi-ai: #2a4e68; /* 藍 — indigo */
/* ═══ 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;
--mobile-bottom-nav-height: 4rem;
--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 (和紙) — Ink on warm paper
═══════════════════════════════════════════════════════════════════════════ */
[data-theme="light"] {
--sumi-bg-void: #e8e0cf;
--sumi-bg-base: #f0ebe0;
--sumi-bg-raised: #f0ebe0;
--sumi-bg-overlay: #f0ebe0;
--sumi-bg-hover: #e4dccb;
--sumi-bg-active: #ddd4c0;
--sumi-bg-wash: #ece5d6;
--sumi-surface-inset: #e0d8c8;
--sumi-surface-subtle: #e8e0cf;
--sumi-surface-card: #f0ebe0;
--sumi-surface-elevated: #f5f0e5;
--sumi-border-faint: rgba(26,23,20, 0.04);
--sumi-border-default: rgba(26,23,20, 0.06);
--sumi-border-strong: rgba(26,23,20, 0.12);
--sumi-border-focus: rgba(139,37,0, 0.45);
--sumi-border-accent: rgba(139,37,0, 0.20);
--sumi-text-primary: #1a1714;
--sumi-text-secondary: #3d3930;
--sumi-text-tertiary: #6b6560;
--sumi-text-disabled: #c4bba8;
--sumi-text-inverse: #e8e0d0;
--sumi-text-link: #8b2500;
--sumi-accent: #8b2500;
--sumi-accent-hover: #7a2000;
--sumi-accent-active: #9b3510;
--sumi-accent-subtle: rgba(139,37,0, 0.08);
--sumi-accent-muted: rgba(139,37,0, 0.15);
--sumi-accent-emphasis: #6a1c00;
--sumi-vermillion: #803040;
--sumi-vermillion-hover: #702838;
--sumi-vermillion-subtle: rgba(128,48,64, 0.10);
--sumi-sage: #3d5530;
--sumi-sage-hover: #304828;
--sumi-sage-subtle: rgba(61,85,48, 0.10);
--sumi-gold: #9a7208;
--sumi-gold-hover: #886008;
--sumi-gold-subtle: rgba(154,114,8, 0.10);
--sumi-kin: #9a7208;
--sumi-kin-hover: #886008;
--sumi-kin-subtle: rgba(154,114,8, 0.06);
--sumi-live: #803040;
--sumi-shadow-xs: 0 1px 3px rgba(26,23,20,0.04);
--sumi-shadow-sm: 0 2px 8px rgba(26,23,20,0.05), 0 1px 3px rgba(26,23,20,0.03);
--sumi-shadow-md: 0 4px 20px rgba(26,23,20,0.06), 0 2px 6px rgba(26,23,20,0.04);
--sumi-shadow-lg: 0 8px 35px rgba(26,23,20,0.08), 0 4px 12px rgba(26,23,20,0.04);
--sumi-shadow-xl: 0 16px 55px rgba(26,23,20,0.10), 0 8px 20px rgba(26,23,20,0.05);
--sumi-shadow-2xl: 0 24px 75px rgba(26,23,20,0.12);
--sumi-shadow-glow: 0 0 0 3px rgba(139,37,0, 0.18);
--sumi-shadow-kin: 0 0 16px rgba(154,114,8, 0.12);
--sumi-glass-bg: rgba(240,235,224, 0.85);
--sumi-glass-border: rgba(26,23,20, 0.04);
--sumi-scrollbar-thumb: rgba(26,23,20, 0.08);
--sumi-scrollbar-hover: rgba(26,23,20, 0.16);
--sumi-grain-opacity: 0.06;
--primary-foreground: #f0ebe0;
}
/* ═══════════════════════════════════════════════════════════════════════════
HIGH CONTRAST MODE — 極墨 (Extreme Ink) — WCAG AA 4.5:1+
═══════════════════════════════════════════════════════════════════════════ */
[data-theme="dark"][data-contrast="high"] {
--sumi-bg-void: #000000;
--sumi-bg-base: #050504;
--sumi-bg-raised: #0d0c0a;
--sumi-bg-overlay: #141210;
--sumi-bg-hover: #1e1c18;
--sumi-bg-active: #262420;
--sumi-text-primary: #ffffff;
--sumi-text-secondary: #d5cfc2;
--sumi-text-tertiary: #b0a898;
--sumi-border-default: rgba(232,224,208,0.25);
--sumi-border-faint: rgba(232,224,208,0.12);
--sumi-border-strong: rgba(232,224,208,0.40);
--sumi-accent: #d85030;
--sumi-accent-hover: #e86040;
}
[data-theme="light"][data-contrast="high"] {
--sumi-bg-void: #ffffff;
--sumi-bg-base: #fdfcf8;
--sumi-bg-raised: #f8f5ee;
--sumi-bg-overlay: #f0ece2;
--sumi-bg-hover: #e5e0d5;
--sumi-bg-active: #d8d2c5;
--sumi-text-primary: #000000;
--sumi-text-secondary: #1a1714;
--sumi-text-tertiary: #3d3930;
--sumi-border-default: rgba(26,23,20,0.25);
--sumi-border-faint: rgba(26,23,20,0.12);
--sumi-border-strong: rgba(26,23,20,0.40);
--sumi-accent: #7a1800;
--sumi-accent-hover: #601200;
}
/* ═══════════════════════════════════════════════════════════════════════════
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: #d090a8;
--color-sumi-shu: var(--sumi-shu);
--color-sumi-kin: var(--sumi-kin);
--color-sumi-ai: var(--sumi-ai);
/* 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";
}
/* ═══ SUMI v4 — Washi fiber grain (和紙繊維) ═══
Anisotropic noise simulating washi paper fiber direction.
baseFrequency 0.4x0.9 = horizontal fibers. 5 octaves = fine detail.
GPU-composited via position:fixed. */
body::after {
content: '';
position: fixed;
inset: 0;
background:
url("data:image/svg+xml,%3Csvg viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='w'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.4 0.9' numOctaves='5' stitchTiles='stitch' seed='2'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23w)'/%3E%3C/svg%3E");
opacity: var(--sumi-grain-opacity, 0.05);
pointer-events: none;
z-index: 9998;
mix-blend-mode: overlay;
}
/* ═══ SUMI v4 — Subtle ink wash vignette (墨暈し) ═══
Very faint radial light at top-center, like a distant lamp on canvas. */
body::before {
content: '';
position: fixed;
inset: 0;
background: radial-gradient(ellipse at 30% 20%, rgba(210,195,168, 0.04) 0%, transparent 60%),
radial-gradient(ellipse at 70% 80%, rgba(180,165,135, 0.03) 0%, transparent 50%);
pointer-events: none;
z-index: 0;
}
/* ═══ SUMI v4 — Circadian + Patina filter ═══
Applied on #root to avoid affecting the grain layer.
hue-rotate shifts warmth. brightness adjusts for time of day.
Transition is 5 min (300s) so changes are imperceptible. */
#root {
filter:
hue-rotate(calc(var(--sumi-circadian-warmth) + var(--sumi-patina-warmth, 0deg)))
brightness(var(--sumi-circadian-brightness));
transition: filter 300s linear;
}
/* Eco mode — disable all cosmetic layers */
[data-eco="true"] body::after { display: none; }
[data-eco="true"] body::before { display: none; }
[data-eco="true"] #root { filter: none; transition: none; }
/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
body::after { display: none; }
body::before { display: none; }
#root { filter: none; transition: none; }
}
/* ═══ SUMI v4 — Patina levels (墨の歳月) ═══ */
[data-patina="1"] { --sumi-grain-opacity: 0.06; }
[data-patina="2"] { --sumi-grain-opacity: 0.07; }
[data-patina="3"] {
--sumi-grain-opacity: 0.08;
--sumi-border-default: rgba(184, 58, 30, 0.05);
}
[data-patina="4"] {
--sumi-grain-opacity: 0.09;
--sumi-border-default: rgba(184, 58, 30, 0.08);
--sumi-shadow-sm: 0 2px 8px rgba(184, 58, 30, 0.08), 0 1px 3px rgba(13,13,11,0.12);
}
::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 tracking-tight text-foreground;
text-wrap: balance;
}
h1 { @apply text-4xl md:text-5xl; font-weight: 200; }
h2 { @apply text-3xl md:text-4xl; font-weight: 300; }
h3 { @apply text-2xl md:text-3xl; font-weight: 400; }
h4 { @apply text-xl md:text-2xl; font-weight: 400; }
h5 { @apply text-lg md:text-xl; font-weight: 500; }
h6 { @apply text-base md:text-lg; font-weight: 500; }
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); }
.h-mobile-nav { height: var(--mobile-bottom-nav-height); }
/* 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 — Shoji screen (障子) */
.glass, .sumi-glass {
background: var(--sumi-glass-bg);
backdrop-filter: blur(var(--sumi-glass-blur)) saturate(0.85);
-webkit-backdrop-filter: blur(var(--sumi-glass-blur)) saturate(0.85);
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 tracking-tight; font-weight: 200; }
.text-heading-1 { @apply text-3xl tracking-tight; font-weight: 300; }
.text-heading-2 { @apply text-2xl; font-weight: 400; }
.text-heading-3 { @apply text-xl; font-weight: 400; }
.text-heading-4 { @apply text-lg; font-weight: 400; }
.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-extralight); 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-light); 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-regular); 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-regular); 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-regular); 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; }
.animate-card-enter { animation: card-enter var(--sumi-duration-slow) var(--sumi-ease-out) both; }
/* Now-playing EQ bars container */
.eq-bars {
display: flex;
align-items: flex-end;
gap: 2px;
height: 14px;
width: 14px;
}
.eq-bars > span {
display: block;
width: 3px;
border-radius: 1px;
background: currentColor;
}
.eq-bars > span:nth-child(1) { animation: eq-bar-1 0.8s ease-in-out infinite; }
.eq-bars > span:nth-child(2) { animation: eq-bar-2 0.7s ease-in-out infinite; }
.eq-bars > span:nth-child(3) { animation: eq-bar-3 0.9s ease-in-out infinite; }
.eq-bars.paused > span { animation-play-state: paused; height: 30%; }
/* Gradient text animation */
.animate-gradient-text {
background-size: 200% auto;
animation: gradient-shift 3s ease-in-out infinite;
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
}
/* Section divider — brush stroke (筆致) */
.section-divider {
height: 2px;
background: linear-gradient(90deg,
transparent 0%,
var(--sumi-border-faint) 8%,
var(--sumi-border-strong) 25%,
var(--sumi-border-strong) 75%,
var(--sumi-border-faint) 92%,
transparent 100%
);
opacity: 0.8;
}
/* Gold leaf line — 金箔 accent divider */
.gold-line {
height: 1px;
background: linear-gradient(90deg, transparent 0%, rgba(184,134,11,0.4) 30%, rgba(184,134,11,0.15) 70%, transparent 100%);
}
/* Player bar entrance */
.player-bar-entrance {
animation: player-bar-entrance var(--sumi-duration-slower) var(--sumi-ease-spring) both;
}
/* Progress bar — ink flow */
.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;
}
/* Sumi-e animation utilities */
.animate-ink-drop { animation: sumi-ink-drop var(--sumi-duration-slow) var(--sumi-ease-spring); }
.animate-ink-spread { animation: sumi-ink-spread var(--sumi-duration-slower) var(--sumi-ease-out); }
.animate-brush-stroke { animation: sumi-brush-stroke var(--sumi-duration-slow) var(--sumi-ease-out); }
.animate-ink-reveal { animation: sumi-ink-reveal var(--sumi-duration-slower) var(--sumi-ease-out) both; }
/* 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 — sumi-nagashi (墨流し) */
.sumi-wash-texture { position: relative; }
.sumi-wash-texture::after {
content: '';
position: absolute;
inset: 0;
background:
radial-gradient(ellipse at 15% 60%, var(--sumi-accent-subtle) 0%, transparent 55%),
radial-gradient(ellipse at 85% 25%, rgba(255,255,255,0.015) 0%, transparent 45%),
radial-gradient(ellipse at 50% 90%, rgba(184,58,30,0.03) 0%, transparent 50%);
pointer-events: none;
}
/* Ink bleed hover — bokashi (暈し) */
.sumi-ink-bleed { position: relative; overflow: hidden; }
.sumi-ink-bleed::after {
content: '';
position: absolute;
inset: 0;
background: radial-gradient(circle at var(--mouse-x, 50%) var(--mouse-y, 50%),
rgba(184,58,30, 0.06) 0%,
transparent 55%);
opacity: 0;
transition: opacity var(--sumi-duration-normal) var(--sumi-ease-default);
pointer-events: none;
}
.sumi-ink-bleed:hover::after { opacity: 1; }
/* Hanko stamp — subtle seal impression (判子) */
.sumi-hanko {
transform: rotate(-1.5deg);
box-shadow:
1px 1px 0 rgba(184,58,30, 0.2),
-0.5px -0.5px 0 rgba(0,0,0, 0.08);
}
/* Notan — dramatic light/dark contrast container (濃淡) */
.sumi-notan {
background: linear-gradient(
180deg,
var(--sumi-bg-void) 0%,
var(--sumi-bg-base) 30%,
var(--sumi-bg-raised) 100%
);
}
/* Bokashi gradient wash — for hero backgrounds (暈し) */
.sumi-bokashi {
background: linear-gradient(
135deg,
var(--sumi-bg-void) 0%,
var(--sumi-bg-base) 40%,
var(--sumi-bg-wash) 60%,
var(--sumi-bg-void) 100%
);
}
/* Sumi-nagashi marble background — floating ink (墨流し) */
.sumi-nagashi {
background:
radial-gradient(ellipse at 20% 50%, var(--sumi-bg-wash) 0%, transparent 50%),
radial-gradient(ellipse at 80% 50%, var(--sumi-bg-raised) 0%, transparent 40%),
radial-gradient(ellipse at 50% 80%, rgba(184,58,30,0.02) 0%, transparent 45%),
var(--sumi-bg-void);
background-size: 200% 200%;
}
.sumi-nagashi.animate { animation: sumi-nagashi 25s ease-in-out infinite; }
/* Ink card — atmospheric container with wash background */
.ink-card {
position: relative;
border-radius: var(--sumi-radius-sm);
overflow: hidden;
}
.ink-card::before {
content: '';
position: absolute;
inset: -20px;
background:
radial-gradient(ellipse at 25% 25%, rgba(232,224,208, 0.035) 0%, transparent 55%),
radial-gradient(ellipse at 75% 75%, rgba(232,224,208, 0.025) 0%, transparent 50%);
filter: blur(8px);
pointer-events: none;
}
.ink-card::after {
content: '';
position: absolute;
bottom: 0; left: 5%; right: 10%;
height: 1px;
background: linear-gradient(90deg, transparent 0%, var(--sumi-border-default) 20%, var(--sumi-border-faint) 60%, transparent 100%);
pointer-events: none;
}
.ink-card > * { position: relative; z-index: 1; }
/* Ghost kanji — large decorative character */
.ghost-kanji {
position: absolute;
font-family: var(--sumi-font-heading);
font-weight: 200;
opacity: 0.06;
pointer-events: none;
user-select: none;
line-height: 1;
z-index: 0;
color: currentColor;
}
[data-theme="light"] .ghost-kanji { opacity: 0.08; }
/* Brush underline — vermillion stroke accent */
.brush-underline::after {
content: '';
display: block;
margin-top: 8px;
height: 2px;
width: min(120px, 40%);
background: linear-gradient(90deg, var(--sumi-accent) 0%, transparent 100%);
border-radius: 1px;
}
/* Hanko seal — logo mark */
.hanko-seal {
position: relative;
transform: rotate(-2deg);
box-shadow:
0 0 0 1px rgba(184,58,30, 0.25),
0 2px 8px rgba(184,58,30, 0.12);
overflow: hidden;
}
.hanko-seal::after {
content: '';
position: absolute;
inset: 0;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='50' height='50'%3E%3Cfilter id='n'%3E%3CfeTurbulence baseFrequency='0.8' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.15'/%3E%3C/svg%3E");
mix-blend-mode: overlay;
pointer-events: none;
}
/* Brush stroke divider — tapered ink line */
.brush-divider {
height: 2px;
background: linear-gradient(90deg,
var(--sumi-border-strong) 0%,
var(--sumi-border-default) 40%,
var(--sumi-border-faint) 70%,
transparent 100%);
border-radius: 1px;
}
/* Vertical brush stroke border — for sidebar/panel edges */
.sumi-stroke-border-left {
border-left: 2px solid var(--sumi-border-strong);
border-image: linear-gradient(
to bottom,
transparent 0%,
var(--sumi-border-default) 10%,
var(--sumi-border-strong) 30%,
var(--sumi-border-strong) 70%,
var(--sumi-border-default) 90%,
transparent 100%
) 1;
}
/* Noise texture utility — washi fiber (和紙) */
.noise { position: relative; }
.noise::before {
content: "";
position: absolute;
inset: 0;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 512 512' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.35 0.85' numOctaves='5' stitchTiles='stitch' seed='3'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)' opacity='0.05'/%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; }
.animate-ink-drop { animation: none; }
.animate-ink-spread { animation: none; }
.animate-brush-stroke { animation: none; }
.animate-ink-reveal { animation: none; }
.sumi-nagashi.animate { animation: none; }
.sumi-ink-bleed::after { display: 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); }
}
/* Ink content reveal — emerges from darkness */
@keyframes content-reveal {
from { opacity: 0; transform: translateY(16px) scale(0.99); filter: blur(6px); }
to { opacity: 1; transform: translateY(0) scale(1); filter: blur(0); }
}
/* Sumi ink glow — subtle vermillion breathe */
@keyframes glow-breathe {
0%, 100% { box-shadow: 0 0 0 0 rgba(184,58,30, 0); }
50% { box-shadow: 0 0 20px 2px rgba(184,58,30, 0.10); }
}
/* 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); }
}
/* Now-playing EQ bars — 3-bar audio visualizer */
@keyframes eq-bar-1 {
0%, 100% { height: 30%; }
25% { height: 80%; }
50% { height: 50%; }
75% { height: 100%; }
}
@keyframes eq-bar-2 {
0%, 100% { height: 50%; }
20% { height: 100%; }
45% { height: 30%; }
70% { height: 80%; }
}
@keyframes eq-bar-3 {
0%, 100% { height: 60%; }
30% { height: 40%; }
55% { height: 100%; }
80% { height: 45%; }
}
/* Gradient text shimmer (for headings) */
@keyframes gradient-shift {
0% { background-position: 0% 50%; }
50% { background-position: 100% 50%; }
100% { background-position: 0% 50%; }
}
/* Gentle card entrance — stagger-friendly */
@keyframes card-enter {
from { opacity: 0; transform: translateY(12px) scale(0.97); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
/* Ripple expand for empty states */
@keyframes ripple-expand {
0% { transform: scale(0.8); opacity: 0.4; }
50% { transform: scale(1.15); opacity: 0.15; }
100% { transform: scale(0.8); opacity: 0.4; }
}
/* ═══════════════════════════════════════════════════════════════════════════
SUMI-E ANIMATIONS — 墨絵 Ink Wash Effects
═══════════════════════════════════════════════════════════════════════════ */
/* Ink drop — element appears like ink hitting wet paper */
@keyframes sumi-ink-drop {
0% { transform: scale(0); opacity: 0; border-radius: 50%; }
35% { transform: scale(1.08); opacity: 0.85; border-radius: 48% 52% 50% 50%; }
55% { transform: scale(0.96); opacity: 1; }
75% { transform: scale(1.02); }
100% { transform: scale(1); opacity: 1; border-radius: inherit; }
}
/* Ink spread — circular reveal like ink spreading on washi */
@keyframes sumi-ink-spread {
0% { clip-path: circle(0% at 50% 50%); filter: blur(6px); opacity: 0; }
40% { filter: blur(2px); opacity: 0.8; }
100% { clip-path: circle(100% at 50% 50%); filter: blur(0); opacity: 1; }
}
/* Brush stroke reveal — horizontal wipe like a calligraphy stroke */
@keyframes sumi-brush-stroke {
0% { clip-path: inset(0 100% 0 0); opacity: 0.4; }
60% { clip-path: inset(0 8% 0 0); opacity: 0.9; }
100% { clip-path: inset(0 0 0 0); opacity: 1; }
}
/* Ink reveal — content emerges from darkness like ink on wet paper */
@keyframes sumi-ink-reveal {
0% { opacity: 0; transform: translateY(12px); filter: blur(8px) brightness(0.7); }
40% { filter: blur(3px) brightness(0.9); }
100% { opacity: 1; transform: translateY(0); filter: blur(0) brightness(1); }
}
/* Sumi-nagashi — floating ink marble drift */
@keyframes sumi-nagashi {
0% { background-position: 0% 50%; }
25% { background-position: 100% 25%; }
50% { background-position: 100% 75%; }
75% { background-position: 0% 60%; }
100% { background-position: 0% 50%; }
}
/* Ink pulse — like a droplet ripple in an ink stone (硯) */
@keyframes sumi-ink-pulse {
0% { box-shadow: 0 0 0 0 rgba(184,58,30, 0.25); }
50% { box-shadow: 0 0 0 8px rgba(184,58,30, 0); }
100% { box-shadow: 0 0 0 0 rgba(184,58,30, 0); }
}
/* ═══════════════════════════════════════════════════════════════════════════
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; }
}