Кегль «Ваша инфраструктура» уменьшался только в @media по ширине ОКНА — не спасало, когда окно широкое, а панель (42% от него, `.layout` flex 42/58) сама по себе узкая: слово не помещалось, overflow:hidden обрезал его вместо переноса. Перешли на container query (`container-type: inline-size` на .brand-panel + `cqw` на .brand-headline) — тот же приём, что у аватара участника в комнате (container-type:size + cqmin, room.css). Кегль теперь считается от реальной ширины панели, а не окна, в любой раскладке. Тем же механизмом клипались плашки .brand-stats («AI-саммари») — добавлен flex-wrap в базовое правило вместо только-мобильного.
293 lines
14 KiB
CSS
293 lines
14 KiB
CSS
/*
|
||
* 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);
|
||
/* Запрос по ширине САМОЙ панели, а не окна: `.layout` — flex 42/58, и на
|
||
широком окне с узкой панелью `vw` (см. .brand-headline) не отражает
|
||
реальную доступную ширину — тот же паттерн, что у `.room-tile-avatar`
|
||
(container-type:size + cqmin, room.css) для аватара участника. */
|
||
container-type: inline-size;
|
||
}
|
||
.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%);
|
||
}
|
||
/* `margin-block: auto` держит блок по центру свободной высоты панели. Нужно
|
||
с тех пор, как из панели убрали нижнюю строку копирайта (она переехала в
|
||
общий футер): у `.brand-panel` осталось два потомка вместо трёх, и
|
||
`justify-content: space-between` иначе прижал бы текст к самому низу. */
|
||
.brand-copy { z-index: 1; margin-block: auto; }
|
||
.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);
|
||
/* `cqw` — от ширины `.brand-panel` (её `container-type: inline-size` выше),
|
||
а не окна: длинное слово «инфраструктура» иначе не помещается именно
|
||
тогда, когда окно широкое, а панель (42% от него) — узкая. Раньше кегль
|
||
уменьшался только в @media по ширине ОКНА (узкие экраны) — не спасало
|
||
от этого случая. */
|
||
font-size: clamp(20px, 8cqw, 34px);
|
||
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;
|
||
}
|
||
/* `flex-wrap` не только на мобильном медиа-запросе (см. ниже) — та же
|
||
природа бага, что у заголовка: узкая ПАНЕЛЬ (а не узкое окно) не даёт
|
||
двум плашкам поместиться в ряд, а `overflow:hidden` у `.brand-panel`
|
||
обрезал вторую вместо переноса. */
|
||
.brand-stats { display: flex; flex-wrap: wrap; 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` сама (cqw от ширины панели, см.
|
||
базовое правило) — здесь снимаем только `max-width:460px`: в сложенной
|
||
колонкой раскладке панель может стать шире 460px, а дизайн этого хочет. */
|
||
.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); }
|
||
}
|