Первоначальная версия VidConf
This commit is contained in:
270
frontend/src/styles/auth.css
Normal file
270
frontend/src/styles/auth.css
Normal file
@@ -0,0 +1,270 @@
|
||||
/*
|
||||
* VidConf — стили экранов auth (вход/регистрация/подтверждение email).
|
||||
* 1:1 воспроизводит design/mockups/auth.html.
|
||||
*/
|
||||
|
||||
.layout { display: flex; min-height: 100vh; }
|
||||
|
||||
/* ---------- Брендовая панель ---------- */
|
||||
.brand-panel {
|
||||
width: 42%;
|
||||
background: linear-gradient(160deg, #EDEFFA 0%, #F1F1F1 55%, #F7F7F8 100%);
|
||||
padding: var(--space-12);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
border-right: 1px solid var(--color-border);
|
||||
}
|
||||
.brand-panel::after {
|
||||
content: "";
|
||||
position: absolute;
|
||||
right: -120px;
|
||||
bottom: -120px;
|
||||
width: 380px;
|
||||
height: 380px;
|
||||
border-radius: 50%;
|
||||
background: radial-gradient(circle at 30% 30%, rgba(212, 242, 227, 0.45), rgba(212, 242, 227, 0) 70%);
|
||||
}
|
||||
.brand-copy { z-index: 1; }
|
||||
.eyebrow {
|
||||
font: var(--text-caption);
|
||||
letter-spacing: 0.08em;
|
||||
color: var(--color-ink-400);
|
||||
margin: 0 0 var(--space-4);
|
||||
}
|
||||
.brand-headline {
|
||||
font: var(--text-display-lg);
|
||||
font-family: var(--font-display);
|
||||
color: var(--color-ink-700);
|
||||
margin: 0 0 var(--space-4);
|
||||
max-width: 460px;
|
||||
}
|
||||
.brand-sub {
|
||||
font: var(--text-body-lg);
|
||||
color: var(--color-ink-500);
|
||||
max-width: 420px;
|
||||
margin: 0;
|
||||
}
|
||||
.brand-stats { display: flex; gap: var(--space-4); z-index: 1; margin-top: var(--space-8); }
|
||||
.stat-glass {
|
||||
background: var(--color-surface-glass);
|
||||
backdrop-filter: blur(16px);
|
||||
-webkit-backdrop-filter: blur(16px);
|
||||
border: 1px solid rgba(255, 255, 255, 0.7);
|
||||
box-shadow: var(--shadow-glass);
|
||||
border-radius: var(--radius-xl);
|
||||
padding: var(--space-4) var(--space-5);
|
||||
min-width: 140px;
|
||||
}
|
||||
.stat-glass strong { display: block; font: var(--text-h1); font-family: var(--font-display); color: var(--color-ink-700); }
|
||||
.stat-glass span { font: var(--text-caption); color: var(--color-ink-500); text-transform: none; letter-spacing: normal; }
|
||||
|
||||
/* ---------- Форма-панель ---------- */
|
||||
.form-panel {
|
||||
width: 58%;
|
||||
padding: var(--space-12) var(--space-16);
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
.screen-block { max-width: 440px; width: 100%; }
|
||||
.screen-title { font: var(--text-h1); color: var(--color-ink-900); margin: 0 0 var(--space-8); }
|
||||
|
||||
.tabs { display: flex; gap: var(--space-2); margin-bottom: var(--space-6); background: var(--color-bg-alt); padding: 4px; border-radius: var(--radius-full); width: fit-content; }
|
||||
.tab {
|
||||
padding: 8px 20px;
|
||||
border-radius: var(--radius-full);
|
||||
border: none;
|
||||
background: transparent;
|
||||
font: var(--text-body);
|
||||
color: var(--color-ink-500);
|
||||
text-decoration: none;
|
||||
display: inline-flex;
|
||||
}
|
||||
.tab.is-active { background: var(--color-surface); color: var(--color-ink-700); font-weight: 600; box-shadow: var(--shadow-sm); }
|
||||
|
||||
.field { margin-bottom: var(--space-5); }
|
||||
.field label { display: block; font: var(--text-body); font-weight: 600; color: var(--color-ink-900); margin-bottom: var(--space-2); }
|
||||
.input-wrap { position: relative; display: flex; align-items: center; }
|
||||
.input-wrap .field-icon { position: absolute; left: 14px; color: var(--color-ink-400); pointer-events: none; }
|
||||
.input-wrap input, .input-wrap select {
|
||||
width: 100%;
|
||||
font: var(--text-body-lg);
|
||||
font-family: var(--font-body);
|
||||
color: var(--color-ink-900);
|
||||
padding: 11px 14px 11px 42px;
|
||||
border-radius: var(--radius-md);
|
||||
border: 1px solid var(--color-border);
|
||||
background: var(--color-surface);
|
||||
outline: none;
|
||||
}
|
||||
.input-wrap input::placeholder { color: var(--color-ink-300); }
|
||||
.input-wrap input:hover, .input-wrap select:hover { border-color: var(--color-border-strong); }
|
||||
.input-wrap input:focus, .input-wrap select:focus { border-color: var(--color-focus-ring); box-shadow: 0 0 0 3px rgba(59, 77, 149, 0.12); }
|
||||
/* Нативный select в WebKit/Safari игнорирует border/border-radius/background
|
||||
без явного отключения UA-рендеринга: без appearance:none контрол рисуется
|
||||
системным виджетом («аквариумная» рамка ОС) поверх авторских стилей — этим
|
||||
объясняется «браузерный дефолт» без скругления и с меньшей высотой. */
|
||||
.input-wrap select {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
-moz-appearance: none;
|
||||
padding-right: 38px;
|
||||
cursor: pointer;
|
||||
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%236976AC' 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 14px center;
|
||||
background-size: 16px;
|
||||
}
|
||||
.input-wrap .toggle-eye {
|
||||
position: absolute;
|
||||
right: 14px;
|
||||
left: auto;
|
||||
background: none;
|
||||
border: none;
|
||||
padding: 0;
|
||||
cursor: pointer;
|
||||
color: var(--color-ink-400);
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.field.has-error input { border-color: var(--color-danger); box-shadow: 0 0 0 3px rgba(199, 54, 79, 0.1); }
|
||||
.error-msg { display: flex; align-items: center; gap: 6px; margin-top: var(--space-2); font: var(--text-body); color: var(--color-danger); }
|
||||
.hint-msg { margin-top: var(--space-2); font: var(--text-body); color: var(--color-ink-500); }
|
||||
|
||||
.row-between { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--space-6); }
|
||||
.checkbox-row { display: flex; align-items: center; gap: 8px; font: var(--text-body); color: var(--color-ink-500); }
|
||||
.link { color: var(--color-ink-700); font-weight: 600; text-decoration: none; background: none; border: none; cursor: pointer; font: var(--text-body); }
|
||||
.link:hover { text-decoration: underline; }
|
||||
|
||||
.btn-block { width: 100%; }
|
||||
.btn-primary.btn-lg { font: var(--text-body-lg); font-weight: 700; padding: 13px 24px; }
|
||||
.btn-secondary.btn-lg { font: var(--text-body-lg); font-weight: 600; padding: 12px 24px; }
|
||||
|
||||
/* ---------- Подтверждение email ---------- */
|
||||
.confirm-card {
|
||||
max-width: 440px;
|
||||
background: var(--color-surface);
|
||||
border: 1px solid var(--color-border);
|
||||
border-radius: var(--radius-2xl);
|
||||
padding: var(--space-8);
|
||||
text-align: left;
|
||||
}
|
||||
.confirm-icon {
|
||||
width: 56px;
|
||||
height: 56px;
|
||||
border-radius: var(--radius-full);
|
||||
background: var(--color-success-bg);
|
||||
color: var(--color-success);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
margin-bottom: var(--space-5);
|
||||
}
|
||||
.confirm-card h3 { font: var(--text-h2); color: var(--color-ink-900); margin: 0 0 var(--space-2); }
|
||||
.confirm-card p { font: var(--text-body-lg); color: var(--color-ink-500); margin: 0 0 var(--space-6); }
|
||||
.confirm-card .mail-chip {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
background: var(--color-bg-alt);
|
||||
border-radius: var(--radius-full);
|
||||
padding: 6px 14px;
|
||||
font: var(--text-mono-sm);
|
||||
color: var(--color-ink-700);
|
||||
margin-bottom: var(--space-6);
|
||||
}
|
||||
.confirm-card.pending .confirm-icon { background: var(--color-warning-bg); color: var(--color-warning); }
|
||||
.confirm-card.error .confirm-icon { background: var(--color-danger-bg); color: var(--color-danger); }
|
||||
|
||||
/* ---------- Переключатель темы: плавающая плашка (см. AuthLayout.tsx) ---------- */
|
||||
.theme-toggle--floating {
|
||||
position: fixed;
|
||||
top: 24px;
|
||||
right: 32px;
|
||||
z-index: 50;
|
||||
box-shadow: var(--shadow-md);
|
||||
}
|
||||
|
||||
/* =====================================================================
|
||||
* Тёмная тема: точечные патчи (design/mockups/dark/README.md, категория
|
||||
* «декоративные градиенты/тени») — литеральные rgba построены на индиго/
|
||||
* старом danger-hex светлой темы, поэтому не перекрашиваются через var().
|
||||
* ===================================================================== */
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root:not([data-theme]) .brand-panel {
|
||||
background: linear-gradient(160deg, #242424 0%, #1E1E1E 55%, #1A1A1A 100%);
|
||||
}
|
||||
:root:not([data-theme]) .brand-panel::after {
|
||||
background: radial-gradient(circle at 30% 30%, rgba(127, 221, 168, 0.16), rgba(127, 221, 168, 0) 70%);
|
||||
}
|
||||
:root:not([data-theme]) .stat-glass { border-color: rgba(255, 255, 255, 0.08); }
|
||||
}
|
||||
:root[data-theme='dark'] .brand-panel {
|
||||
background: linear-gradient(160deg, #242424 0%, #1E1E1E 55%, #1A1A1A 100%);
|
||||
}
|
||||
:root[data-theme='dark'] .brand-panel::after {
|
||||
background: radial-gradient(circle at 30% 30%, rgba(127, 221, 168, 0.16), rgba(127, 221, 168, 0) 70%);
|
||||
}
|
||||
:root[data-theme='dark'] .stat-glass { border-color: rgba(255, 255, 255, 0.08); }
|
||||
|
||||
/* ---------- Узкие экраны ---------- */
|
||||
/* ВАЖНО: этот блок должен идти строго ПОСЛЕДНИМ в файле — при равной
|
||||
специфичности с безусловными правилами выше (`.brand-panel`, `.form-panel`
|
||||
и т.п. — те же 0,1,0) побеждает порядок в исходнике, а не сам факт
|
||||
совпадения media query (тот же баг уже ловили в lobby.css/.action, гейт 3
|
||||
— см. комментарий там). Макет auth.html — desktop-only
|
||||
(`html { min-width: 1280px }`), адаптива в нём нет.
|
||||
Причина исходного бага: `.layout` — flex-row из двух панелей с width
|
||||
в процентах и без flex-shrink:0, а `.brand-panel` — overflow:hidden (нужен
|
||||
для декоративного круга). По спецификации flex, overflow:hidden отключает
|
||||
автоматический min-width:auto (= min-content) и делает его 0 — поэтому
|
||||
при узком viewport панель схлопывалась намного уже своего текста, а не
|
||||
переносила его: overflow:hidden просто обрезал то, что не поместилось,
|
||||
вместо переноса строк. Решение — не подбирать min-width, а на узких
|
||||
экранах складывать колонки в одну: тогда ширина каждой панели равна 100%
|
||||
и конкуренции за пространство между ними нет вовсе. */
|
||||
@media (max-width: 900px) {
|
||||
.layout {
|
||||
flex-direction: column;
|
||||
min-height: auto;
|
||||
}
|
||||
.brand-panel {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
padding: var(--space-8) var(--space-6) var(--space-6);
|
||||
border-right: none;
|
||||
border-bottom: 1px solid var(--color-border);
|
||||
}
|
||||
.brand-panel::after {
|
||||
width: 220px;
|
||||
height: 220px;
|
||||
right: -90px;
|
||||
bottom: -90px;
|
||||
}
|
||||
.brand-headline { max-width: none; }
|
||||
.brand-sub { max-width: none; }
|
||||
.brand-stats { flex-wrap: wrap; }
|
||||
.stat-glass { flex: 1 1 140px; min-width: 0; }
|
||||
|
||||
.form-panel {
|
||||
width: 100%;
|
||||
min-width: 0;
|
||||
padding: var(--space-8) var(--space-6);
|
||||
justify-content: flex-start;
|
||||
}
|
||||
.screen-block { max-width: 100%; }
|
||||
}
|
||||
|
||||
@media (max-width: 480px) {
|
||||
/* Совсем узкий телефон (375px) — экономим отступы и убираем декоративный
|
||||
круг: на компактном hero он ближе к тексту и уже не читается как акцент. */
|
||||
.brand-panel { padding: var(--space-6) var(--space-4); }
|
||||
.brand-panel::after { display: none; }
|
||||
.brand-stats { gap: var(--space-3); }
|
||||
.stat-glass { flex-basis: 100%; }
|
||||
|
||||
.form-panel { padding: var(--space-6) var(--space-4) var(--space-10); }
|
||||
}
|
||||
Reference in New Issue
Block a user