HIGH: - chat: действия над сообщением доступны на мобильном (меню ⋯) - iOS-зум: базовые input/textarea text-base, auth-экраны 16px - контент не перекрыт нижней навигацией на iPhone (safe-area) - контрасты: billing-оверлей, бот-кнопка, заголовки задач (text-primary) - клавиатура: входящие на Главной, aria-label нижней навигации, триггер чата button - confirm() → AlertDialog (сайдбар, чат, настройки) - счётчики непрочитанных 7-8px → 10px MEDIUM: - офлайн-баннеры и бейджи на токенах warning/success/info/destructive - transition-all → точечные свойства в примитивах ui - шрифты: Inter без дублей (24 семейства → 2), letter-spacing с body убран - prefers-reduced-motion kill-switch - autocomplete + aria на auth/профиле, ошибки пароля у поля - SPA: document.title + фокус на main при навигации, тост с action без таймера - FormEditor: превью на Dialog, табы скроллятся на мобильном, без инлайн-стилей - empty states с запросом и «Сбросить фильтры», UX-тексты
541 lines
14 KiB
CSS
541 lines
14 KiB
CSS
/* Шрифты подключаются в client/index.html (variable Inter + DM Mono).
|
||
Не добавлять @import шрифтов сюда — это дублирует запросы и ломает порядок каскада. */
|
||
@import './themes/styles/generated-skins.css';
|
||
|
||
@tailwind base;
|
||
@tailwind components;
|
||
@tailwind utilities;
|
||
|
||
/*
|
||
* Fallback переменные для случая, когда data-skin/data-theme ещё не применены
|
||
* (например, во время гидратации). Основные значения берутся из generated-skins.css.
|
||
*/
|
||
:root {
|
||
--background: hsl(0 0% 100%);
|
||
--foreground: hsl(220 10% 15%);
|
||
--card: hsl(0 0% 100%);
|
||
--card-foreground: hsl(220 10% 15%);
|
||
--popover: hsl(0 0% 100%);
|
||
--popover-foreground: hsl(220 10% 15%);
|
||
--primary: hsl(220 10% 15%);
|
||
--primary-foreground: hsl(0 0% 100%);
|
||
--secondary: hsl(220 5% 96%);
|
||
--secondary-foreground: hsl(220 10% 15%);
|
||
--muted: hsl(220 5% 96%);
|
||
--muted-foreground: hsl(220 5% 45%);
|
||
--accent: hsl(220 5% 93%);
|
||
--accent-foreground: hsl(220 10% 15%);
|
||
--destructive: hsl(0 72% 51%);
|
||
--destructive-foreground: hsl(0 0% 100%);
|
||
--border: hsl(220 5% 90%);
|
||
--input: hsl(0 0% 100%);
|
||
--ring: hsl(220 10% 15%);
|
||
|
||
--status-done: hsl(142 50% 45%);
|
||
--status-progress: hsl(45 90% 50%);
|
||
--status-overdue: hsl(0 70% 55%);
|
||
--status-paused: hsl(220 5% 60%);
|
||
|
||
--warning: hsl(48 96% 89%);
|
||
--warning-foreground: hsl(25 83% 31%);
|
||
--success: hsl(141 84% 93%);
|
||
--success-foreground: hsl(142 72% 24%);
|
||
--info: hsl(214 95% 93%);
|
||
--info-foreground: hsl(224 71% 40%);
|
||
|
||
--chart-1: hsl(220 10% 25%);
|
||
--chart-2: hsl(142 50% 45%);
|
||
--chart-3: hsl(45 90% 50%);
|
||
--chart-4: hsl(200 70% 50%);
|
||
--chart-5: hsl(0 70% 55%);
|
||
|
||
--sidebar: hsl(0 0% 100%);
|
||
--sidebar-foreground: hsl(220 10% 15%);
|
||
--sidebar-primary: hsl(220 10% 15%);
|
||
--sidebar-primary-foreground: hsl(0 0% 100%);
|
||
--sidebar-accent: hsl(220 5% 96%);
|
||
--sidebar-accent-foreground: hsl(220 10% 15%);
|
||
--sidebar-border: hsl(220 5% 92%);
|
||
--sidebar-ring: hsl(220 10% 15%);
|
||
|
||
--font-sans: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
||
--font-mono: "DM Mono", "SF Mono", "Monaco", "Inconsolata", monospace;
|
||
|
||
--radius: 0.25rem;
|
||
|
||
--shadow-2xs: none;
|
||
--shadow-xs: none;
|
||
--shadow-sm: none;
|
||
--shadow: none;
|
||
--shadow-md: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
|
||
--shadow-lg: 0 1px 3px 0 rgba(0, 0, 0, 0.05);
|
||
--shadow-xl: 0 2px 4px 0 rgba(0, 0, 0, 0.05);
|
||
--shadow-2xl: 0 4px 6px -1px rgba(0, 0, 0, 0.05);
|
||
|
||
--tracking-normal: -0.01em;
|
||
--spacing: 0.25rem;
|
||
|
||
--elevate-1: rgba(0, 0, 0, 0.03);
|
||
--elevate-2: rgba(0, 0, 0, 0.08);
|
||
}
|
||
|
||
.dark {
|
||
--elevate-1: rgba(255, 255, 255, 0.03);
|
||
--elevate-2: rgba(255, 255, 255, 0.08);
|
||
--background: hsl(220 10% 8%);
|
||
--foreground: hsl(220 5% 92%);
|
||
--card: hsl(220 10% 10%);
|
||
--card-foreground: hsl(220 5% 92%);
|
||
--popover: hsl(220 10% 10%);
|
||
--popover-foreground: hsl(220 5% 92%);
|
||
--primary: hsl(0 0% 100%);
|
||
--primary-foreground: hsl(220 10% 8%);
|
||
--secondary: hsl(220 10% 14%);
|
||
--secondary-foreground: hsl(220 5% 92%);
|
||
--muted: hsl(220 10% 14%);
|
||
--muted-foreground: hsl(220 5% 55%);
|
||
--accent: hsl(220 10% 16%);
|
||
--accent-foreground: hsl(220 5% 92%);
|
||
--destructive: hsl(0 70% 55%);
|
||
--destructive-foreground: hsl(0 0% 100%);
|
||
--border: hsl(220 10% 18%);
|
||
--input: hsl(220 10% 12%);
|
||
--ring: hsl(0 0% 100%);
|
||
|
||
--status-done: hsl(142 50% 55%);
|
||
--status-progress: hsl(45 90% 55%);
|
||
--status-overdue: hsl(0 70% 60%);
|
||
--status-paused: hsl(220 5% 55%);
|
||
|
||
--warning: hsl(32 92% 14%);
|
||
--warning-foreground: hsl(43 96% 56%);
|
||
--success: hsl(144 80% 10%);
|
||
--success-foreground: hsl(142 71% 58%);
|
||
--info: hsl(224 64% 21%);
|
||
--info-foreground: hsl(213 97% 81%);
|
||
|
||
--chart-1: hsl(220 5% 70%);
|
||
--chart-2: hsl(142 50% 55%);
|
||
--chart-3: hsl(45 90% 55%);
|
||
--chart-4: hsl(200 70% 55%);
|
||
--chart-5: hsl(0 70% 60%);
|
||
|
||
--sidebar: hsl(220 10% 8%);
|
||
--sidebar-foreground: hsl(220 5% 92%);
|
||
--sidebar-primary: hsl(0 0% 100%);
|
||
--sidebar-primary-foreground: hsl(220 10% 8%);
|
||
--sidebar-accent: hsl(220 10% 14%);
|
||
--sidebar-accent-foreground: hsl(220 5% 92%);
|
||
--sidebar-border: hsl(220 10% 16%);
|
||
--sidebar-ring: hsl(0 0% 100%);
|
||
|
||
--radius: 0.25rem;
|
||
|
||
--shadow-md: 0 1px 2px 0 rgba(0, 0, 0, 0.15);
|
||
--shadow-lg: 0 2px 4px 0 rgba(0, 0, 0, 0.2);
|
||
--shadow-xl: 0 4px 6px -1px rgba(0, 0, 0, 0.2);
|
||
--shadow-2xl: 0 8px 10px -2px rgba(0, 0, 0, 0.25);
|
||
}
|
||
|
||
@layer base {
|
||
* {
|
||
@apply border-border;
|
||
}
|
||
|
||
body {
|
||
@apply font-sans antialiased bg-background text-foreground;
|
||
font-size: 13px;
|
||
line-height: 1.5;
|
||
/* letter-spacing на весь body убран: кириллица 13px слипается.
|
||
Трекинг остаётся только на заголовках (tracking-tight ниже). */
|
||
font-feature-settings: "cv11", "ss01";
|
||
}
|
||
|
||
/* Clean typography */
|
||
h1 {
|
||
@apply text-xl font-semibold tracking-tight;
|
||
}
|
||
|
||
h2 {
|
||
@apply text-lg font-medium tracking-tight;
|
||
}
|
||
|
||
h3 {
|
||
@apply text-base font-medium;
|
||
}
|
||
|
||
h4 {
|
||
@apply text-sm font-medium;
|
||
}
|
||
|
||
/* Fast transitions */
|
||
button, a, input, select, textarea {
|
||
@apply transition-colors duration-100 ease-out;
|
||
}
|
||
}
|
||
|
||
@layer components {
|
||
/* Page container */
|
||
.page-container {
|
||
@apply max-w-6xl mx-auto;
|
||
}
|
||
|
||
/* Page header */
|
||
.page-header {
|
||
@apply flex items-center justify-between mb-4 pb-3 border-b border-border;
|
||
}
|
||
|
||
.page-title {
|
||
@apply text-lg font-medium text-foreground;
|
||
}
|
||
|
||
/* Compact buttons */
|
||
.btn-compact {
|
||
@apply h-7 px-2.5 text-xs font-medium;
|
||
}
|
||
|
||
.btn-small {
|
||
@apply h-6 px-2 text-xs;
|
||
}
|
||
|
||
.btn-icon {
|
||
@apply h-7 w-7 p-0;
|
||
}
|
||
|
||
/* Compact inputs */
|
||
.input-compact {
|
||
@apply h-7 px-2 text-xs;
|
||
}
|
||
|
||
/* Clean table */
|
||
.table-minimal {
|
||
@apply w-full text-xs;
|
||
}
|
||
|
||
.table-minimal thead {
|
||
@apply border-b border-border;
|
||
}
|
||
|
||
.table-minimal th {
|
||
@apply py-2 px-3 text-left font-medium text-muted-foreground uppercase tracking-wider text-[10px];
|
||
}
|
||
|
||
.table-minimal td {
|
||
@apply py-2 px-3 border-b border-border/50;
|
||
}
|
||
|
||
.table-minimal tbody tr:hover {
|
||
@apply bg-muted/30;
|
||
}
|
||
|
||
/* Card minimal */
|
||
.card-minimal {
|
||
@apply border border-border rounded bg-card p-3;
|
||
}
|
||
|
||
/* Badge minimal */
|
||
.badge-minimal {
|
||
@apply inline-flex items-center px-1.5 py-0.5 text-[10px] font-medium rounded;
|
||
}
|
||
|
||
/* Status colors */
|
||
.status-badge {
|
||
@apply inline-flex items-center gap-1.5 px-2 py-0.5 text-xs rounded-full;
|
||
}
|
||
|
||
.status-badge-done {
|
||
background-color: color-mix(in srgb, var(--status-done) 12%, transparent);
|
||
color: var(--status-done);
|
||
}
|
||
|
||
.status-badge-progress {
|
||
background-color: color-mix(in srgb, var(--status-progress) 12%, transparent);
|
||
color: var(--status-progress);
|
||
}
|
||
|
||
.status-badge-overdue {
|
||
background-color: color-mix(in srgb, var(--status-overdue) 12%, transparent);
|
||
color: var(--status-overdue);
|
||
}
|
||
|
||
/* Nav item */
|
||
.nav-item {
|
||
@apply flex items-center gap-2 px-2 py-1.5 text-xs font-medium text-muted-foreground rounded hover:bg-muted hover:text-foreground transition-colors;
|
||
}
|
||
|
||
.nav-item-active {
|
||
@apply bg-muted text-foreground;
|
||
}
|
||
|
||
/* Section header */
|
||
.section-header {
|
||
@apply text-[10px] font-medium text-muted-foreground uppercase tracking-wider px-2 py-1.5;
|
||
}
|
||
|
||
/* Toolbar */
|
||
.toolbar {
|
||
@apply flex items-center gap-1.5 p-1.5 border-b border-border bg-background;
|
||
}
|
||
|
||
/* Empty state */
|
||
.empty-state {
|
||
@apply flex flex-col items-center justify-center py-12 text-center text-muted-foreground;
|
||
}
|
||
|
||
/* Form grid */
|
||
.form-grid {
|
||
@apply grid gap-3;
|
||
}
|
||
|
||
.form-row {
|
||
@apply flex items-center gap-2;
|
||
}
|
||
|
||
.form-label {
|
||
@apply text-xs font-medium text-muted-foreground;
|
||
}
|
||
|
||
/* List item */
|
||
.list-item {
|
||
@apply flex items-center gap-3 px-3 py-2 border-b border-border/50 hover:bg-muted/30 cursor-pointer;
|
||
}
|
||
|
||
.list-item:last-child {
|
||
@apply border-b-0;
|
||
}
|
||
}
|
||
|
||
@layer utilities {
|
||
/* Status badge utilities */
|
||
.status-done {
|
||
background-color: hsl(var(--status-done));
|
||
}
|
||
|
||
.status-progress {
|
||
background-color: hsl(var(--status-progress));
|
||
}
|
||
|
||
.status-overdue {
|
||
background-color: hsl(var(--status-overdue));
|
||
}
|
||
|
||
.status-paused {
|
||
background-color: hsl(var(--status-paused));
|
||
}
|
||
|
||
/* Text utilities */
|
||
.text-caption {
|
||
@apply text-[10px] text-muted-foreground;
|
||
}
|
||
|
||
.text-label {
|
||
@apply text-xs font-medium;
|
||
}
|
||
|
||
/* Truncate utilities */
|
||
.line-clamp-1 {
|
||
overflow: hidden;
|
||
display: -webkit-box;
|
||
-webkit-box-orient: vertical;
|
||
-webkit-line-clamp: 1;
|
||
}
|
||
|
||
/* Finance elevation */
|
||
.hover-elevate {
|
||
position: relative;
|
||
}
|
||
.hover-elevate::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
border-radius: inherit;
|
||
pointer-events: none;
|
||
opacity: 0;
|
||
background: var(--elevate-1);
|
||
transition: opacity 0.15s ease;
|
||
}
|
||
.hover-elevate:hover::after {
|
||
opacity: 1;
|
||
}
|
||
|
||
.hover-elevate-2 {
|
||
position: relative;
|
||
}
|
||
.hover-elevate-2::after {
|
||
content: "";
|
||
position: absolute;
|
||
inset: 0;
|
||
border-radius: inherit;
|
||
pointer-events: none;
|
||
opacity: 0;
|
||
background: var(--elevate-2);
|
||
transition: opacity 0.15s ease;
|
||
}
|
||
.hover-elevate-2:hover::after {
|
||
opacity: 1;
|
||
}
|
||
|
||
.active-elevate:active::after {
|
||
opacity: 1;
|
||
}
|
||
.active-elevate-2:active::after {
|
||
opacity: 1;
|
||
}
|
||
|
||
.toggle-elevate[data-state="on"]::after,
|
||
.toggle-elevate-2[data-state="on"]::after {
|
||
opacity: 1;
|
||
}
|
||
}
|
||
|
||
/* jspreadsheet formula cell highlight */
|
||
td.formula-highlight {
|
||
background-color: var(--tw-background-transparent-secondary) !important;
|
||
border: 1px solid var(--tw-border-strong) !important;
|
||
}
|
||
|
||
/* Mobile bottom navigation safe area */
|
||
.safe-area-bottom {
|
||
padding-bottom: env(safe-area-inset-bottom, 0);
|
||
}
|
||
|
||
/* Fix: Tailwind utility .flex overrides preflight [hidden] rule.
|
||
Radix primitives (Tabs, Dialog, Accordion, etc.) use hidden attr for inactive/unmounted content.
|
||
Ensure [hidden] always hides even when combined with flex/grid/display utilities. */
|
||
[hidden] {
|
||
display: none !important;
|
||
}
|
||
|
||
/* Fix Radix ScrollArea display:table horizontal overflow in chats */
|
||
.chat-scroll-area [data-radix-scroll-area-viewport] > div {
|
||
display: block !important;
|
||
min-width: 0 !important;
|
||
}
|
||
|
||
/* Scrollbar minimal */
|
||
::-webkit-scrollbar {
|
||
width: 6px;
|
||
height: 6px;
|
||
}
|
||
|
||
::-webkit-scrollbar-track {
|
||
background: transparent;
|
||
}
|
||
|
||
::-webkit-scrollbar-thumb {
|
||
background: var(--tw-border-strong);
|
||
border-radius: 3px;
|
||
}
|
||
|
||
::-webkit-scrollbar-thumb:hover {
|
||
background: var(--tw-font-extra-light);
|
||
}
|
||
|
||
/* Focus visible — removed per user request */
|
||
@layer base {
|
||
*:focus-visible {
|
||
outline: none;
|
||
--tw-ring-offset-shadow: none;
|
||
--tw-ring-shadow: none;
|
||
box-shadow: none;
|
||
}
|
||
}
|
||
|
||
/* Selection */
|
||
::selection {
|
||
background-color: var(--tw-background-transparent-secondary);
|
||
}
|
||
|
||
/* Глобальный kill-switch анимаций для пользователей с prefers-reduced-motion */
|
||
@media (prefers-reduced-motion: reduce) {
|
||
*, *::before, *::after {
|
||
animation-duration: 0.01ms !important;
|
||
animation-iteration-count: 1 !important;
|
||
transition-duration: 0.01ms !important;
|
||
}
|
||
}
|
||
|
||
/* ============================================================
|
||
Notion-Style Task Detail — Inline Edit System
|
||
Added: 2026-07-16
|
||
============================================================ */
|
||
|
||
@layer components {
|
||
/* --- Unified field grid: label + value --- */
|
||
.notion-field-row {
|
||
@apply grid gap-x-3 gap-y-1 py-1.5 px-2 -mx-2 rounded transition-colors;
|
||
grid-template-columns: 1fr; /* mobile: stacked */
|
||
}
|
||
|
||
@media (min-width: 768px) {
|
||
.notion-field-row {
|
||
grid-template-columns: minmax(120px, 140px) 1fr;
|
||
align-items: start;
|
||
}
|
||
}
|
||
|
||
/* Editable hover state */
|
||
.notion-field-row[data-editable="true"]:not([data-editing="true"]):hover {
|
||
@apply bg-muted/40;
|
||
}
|
||
|
||
/* --- Label column --- */
|
||
.notion-field-label {
|
||
@apply flex items-center gap-1;
|
||
}
|
||
|
||
@media (min-width: 768px) {
|
||
.notion-field-label {
|
||
@apply justify-end text-right;
|
||
padding-top: 2px;
|
||
}
|
||
}
|
||
|
||
/* --- Value column --- */
|
||
.notion-field-value {
|
||
@apply min-w-0;
|
||
}
|
||
|
||
/* --- Sticky bottom action bar --- */
|
||
.sticky-action-bar {
|
||
@apply sticky bottom-0 z-40 bg-background/95 backdrop-blur-sm border-t;
|
||
box-shadow: 0 -2px 10px rgba(0, 0, 0, 0.05);
|
||
}
|
||
|
||
/* --- Inline editor inputs (unified height) --- */
|
||
.inline-input {
|
||
@apply border border-input rounded-md bg-background px-2 text-[13px];
|
||
@apply focus:outline-none focus:ring-1 focus:ring-primary focus:border-primary;
|
||
height: 32px;
|
||
line-height: 30px;
|
||
padding-top: 0;
|
||
padding-bottom: 0;
|
||
}
|
||
|
||
.inline-textarea {
|
||
@apply border border-input rounded-md bg-background px-2 py-1.5 text-[13px];
|
||
@apply focus:outline-none focus:ring-1 focus:ring-primary focus:border-primary;
|
||
min-height: 32px;
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.inline-select {
|
||
@apply inline-input w-full appearance-none;
|
||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24' fill='none' stroke='%236B7280' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E");
|
||
background-repeat: no-repeat;
|
||
background-position: right 8px center;
|
||
padding-right: 28px;
|
||
}
|
||
}
|
||
|
||
/* --- PWA Safe Area --- */
|
||
.safe-area-bottom {
|
||
padding-bottom: env(safe-area-inset-bottom, 0);
|
||
}
|
||
|
||
@supports (padding-bottom: env(safe-area-inset-bottom)) {
|
||
.safe-area-bottom {
|
||
padding-bottom: max(12px, env(safe-area-inset-bottom));
|
||
}
|
||
}
|