Files
iistwin/client/src/index.css
Ильяс Султанов 17a8dc42f2 fix(ui): второй пакет ревью better-interface — каркас, чат, реестр, настройки
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-тексты
2026-08-04 19:20:59 +03:00

541 lines
14 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.

/* Шрифты подключаются в 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));
}
}