/* Оформление формы входа — EP-VRT0-03 §3.5, SP-VRT0-03-02 §5.

   Ни одного литерального цвета: цвет приходит только переменной из общего набора
   токенов `/auth-static/tokens.css` (`UIF-DS-18`, `UIF-DS-19`). Второй таблицы
   токенов у формы нет — она ссылается на ту же, что и продуктовая поверхность.

   Состав сентябрьского минимума формы закрыт: подписи, подсказка грамматики, показ
   пароля, отправка. Ни ссылки восстановления, ни значка защищённого канала, ни
   внешнего поставщика, ни второго фактора здесь нет — и появиться им неоткуда,
   потому что разметка их не объявляет.

   Продуктовая композиция (SP-LOGIN-ANIMATION, LOGIN-2026-09-22-01) объявлена
   ниже отдельным блоком под модификатором `.login--map`: сцена с декоративным
   глобусом, брендинг и панель. Административный вход модификатора не получает и
   сохраняет правила выше без изменений. */

* {
  box-sizing: border-box;
}

/* Скрытие атрибутом обязано побеждать объявленный `display`. Правило браузера по
   умолчанию слабее любого явного `display`, и строка с `display: flex` осталась бы
   видимой при `hidden` — то есть признак «запомнить» показывался бы на
   административной поверхности, где его не существует. То же правило держит
   скрытыми сцену и брендинг, пока скрипт не включил продуктовую композицию. */
[hidden] {
  display: none !important;
}

html,
body {
  height: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: var(--type-body);
  line-height: var(--leading);
}

.login {
  min-height: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: var(--sp-6);
}

.login-panel {
  width: 100%;
  max-width: 380px;
  background: var(--surface);
  border: var(--border-thin) solid var(--border);
  border-radius: var(--radius);
  padding: var(--sp-6);
  box-shadow: var(--shadow);
}

.login-head {
  margin-bottom: var(--sp-5);
}

.login-brand {
  display: block;
  font-size: var(--type-label);
  letter-spacing: 0.18em;
  color: var(--accent);
}

.login-title {
  margin: var(--sp-2) 0 0;
  font-size: var(--type-title);
  font-weight: 600;
}

.login-surface {
  margin: var(--sp-2) 0 0;
  font-size: var(--type-label);
  color: var(--text-2);
}

.login-form {
  display: flex;
  flex-direction: column;
  gap: var(--sp-4);
}

.login-field {
  display: flex;
  flex-direction: column;
  gap: var(--sp-1);
}

.login-field--inline {
  flex-direction: row;
  align-items: center;
  gap: var(--sp-2);
}

.login-label {
  font-size: var(--type-label);
  color: var(--text-2);
}

.login-label--inline {
  color: var(--text);
}

/* Рамка интерактивного контрола — `--text-3`, а не `--border-strong`: `UIF-DS-20`
   требует 3:1 к окружению, а `--border-strong` даёт на `--surface`/`--surface-2`
   только 1,94/1,85. Рамки поверхностей остаются `--border`/`--border-strong`. */
.login-input {
  width: 100%;
  padding: var(--sp-2) var(--sp-3);
  background: var(--surface-2);
  border: var(--border-thin) solid var(--text-3);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: var(--type-control);
}

.login-input:focus-visible {
  outline: var(--focus-w) solid var(--ctl-focus);
  outline-offset: 0;
}

/* Ввод вне объявленной грамматики помечается подсказкой, а не запретом отправки:
   отправка обязана дойти до автомата попыток при любом содержимом поля. */
.login-input[aria-invalid='true'] {
  border-color: var(--ctl-error);
}

.login-hint {
  margin: 0;
  font-size: var(--type-caption);
  color: var(--text-3);
}

.login-hint--invalid {
  color: var(--ctl-error);
}

.login-secret {
  display: flex;
  gap: var(--sp-2);
}

.login-reveal {
  flex: 0 0 auto;
  padding: var(--sp-2) var(--sp-3);
  background: var(--surface-3);
  border: var(--border-thin) solid var(--text-3);
  border-radius: var(--radius-sm);
  color: var(--text-2);
  font-family: var(--font-ui);
  font-size: var(--type-control);
  cursor: pointer;
}

.login-reveal:hover {
  background: var(--ctl-hover);
}

.login-reveal:focus-visible {
  outline: var(--focus-w) solid var(--ctl-focus);
}

.login-checkbox {
  width: var(--sp-4);
  height: var(--sp-4);
  accent-color: var(--accent);
}

.login-submit {
  margin-top: var(--sp-2);
  padding: var(--sp-3);
  background: var(--accent-dim);
  border: var(--border-thin) solid var(--accent);
  border-radius: var(--radius-sm);
  color: var(--text);
  font-family: var(--font-ui);
  font-size: var(--type-control);
  letter-spacing: 0.06em;
  cursor: pointer;
}

.login-submit:hover:not(:disabled) {
  background: var(--ctl-pressed);
}

.login-submit:focus-visible {
  outline: var(--focus-w) solid var(--ctl-focus);
}

/* Отключённая кнопка на время запроса — единственное клиентское проявление
   серверной нарастающей задержки. Собственного ожидания клиент не заводит:
   задержку исполняет автомат попыток, и дублировать её здесь значило бы удвоить. */
.login-submit:disabled {
  opacity: var(--ctl-disabled);
  cursor: progress;
}

.login-outcome {
  margin: var(--sp-4) 0 0;
  padding: var(--sp-3);
  background: var(--surface-2);
  border-left: var(--border-strong-w) solid var(--ctl-error);
  font-size: var(--type-control);
  color: var(--text);
}

.login-outcome--service {
  border-left-color: var(--warn);
}

.login-attempts {
  margin: var(--sp-2) 0 0;
  font-size: var(--type-caption);
  color: var(--text-3);
}

/* ── Продуктовая композиция — SP-LOGIN-ANIMATION §1.1, §3 ─────────────────────

   Действует только под `.login--map`, который выставляет скрипт после
   нормализации `next`. Экран делится пополам: слева — сцена с декоративным
   глобусом (абсолютно позиционирована, ввод формы не перехватывает), справа —
   брендинг и та же панель формы, отцентрованные внутри правой половины
   (поручение координатора 22.09.2026). Ниже 1000px (media query макета) сцена уходит в фон, при малой
   высоте брендинг сжимается; overflow не запрещается — при нехватке высоты
   документ прокручивается, и форма остаётся доступной. Цвета — только токены;
   смешение `color-mix` берёт токен и прозрачность. */

.login--map {
  position: relative;
  isolation: isolate;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  grid-template-areas:
    'scene brand'
    'scene panel';
  align-content: center;
  column-gap: var(--sp-6);
  row-gap: var(--sp-5);
}

/* Мягкая посадка глобуса в фон, чтобы диск не лежал наклейкой. */
.login--map::before {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background: radial-gradient(
    120% 80% at 22% 50%,
    color-mix(in srgb, var(--accent) 7%, transparent) 0%,
    transparent 62%
  );
}

.login--map .login-scene {
  position: absolute;
  inset: 0 auto 0 0;
  width: 50%;
  z-index: 0;
}

.login--map .login-globe {
  display: block;
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  touch-action: none;
  cursor: grab;
}

/* Подпись декоративности: глобус — не живая обстановка. Переносится по словам,
   горизонтальной прокрутки не порождает. */
.login--map .login-globe-caption {
  position: absolute;
  left: var(--sp-4);
  right: var(--sp-4);
  bottom: var(--sp-5);
  margin: 0;
  font-family: var(--font-mono);
  font-size: var(--type-micro);
  letter-spacing: 0.09em;
  text-transform: uppercase;
  text-align: center;
  color: var(--text-3);
  pointer-events: none;
}

.login--map .login-brandline {
  grid-area: brand;
  z-index: 1;
  display: flex;
  flex-direction: column;
  gap: var(--sp-5);
  width: 100%;
  max-width: 520px;
  justify-self: center;
  align-self: end;
}

.login--map .login-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: var(--sp-3);
  align-self: flex-start;
  margin: 0;
  padding: var(--sp-1) var(--sp-4);
  font-family: var(--font-mono);
  font-size: var(--type-caption);
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--accent);
  border: var(--border-thin) solid color-mix(in srgb, var(--accent) 45%, transparent);
  border-radius: var(--radius);
  background: color-mix(in srgb, var(--accent) 9%, transparent);
}

.login--map .login-eyebrow::before {
  content: '';
  width: var(--sp-2);
  height: var(--sp-2);
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 8px var(--accent);
}

.login--map .login-wordmark {
  margin: 0;
  font-family: var(--font-mono);
  font-weight: 700;
  font-size: clamp(38px, 5.2vw, 64px);
  line-height: 1;
  letter-spacing: 0.12em;
  color: var(--text);
}

.login--map .login-wordmark span {
  color: var(--accent);
}

.login--map .login-tagline {
  margin: 0;
  font-size: clamp(15px, 1.5vw, 19px);
  color: var(--text-2);
  max-width: 44ch;
}

/* Панель формы в композиции: тот же контент, панель макета поверх сцены. Малая
   подпись бренда уступает место словесному знаку; заголовок формы остаётся. */
.login--map .login-panel {
  grid-area: panel;
  z-index: 1;
  max-width: 520px;
  justify-self: center;
  align-self: start;
  background: color-mix(in srgb, var(--surface) 82%, transparent);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

.login--map .login-brand {
  display: none;
}

/* Узкий экран: глобус уходит в фон, колонка одна. */
@media (max-width: 1000px) {
  .login--map {
    grid-template-columns: minmax(0, 1fr);
    grid-template-areas:
      'brand'
      'panel';
  }

  .login--map .login-scene {
    inset: 0;
    width: 100%;
    opacity: 0.38;
  }

  .login--map .login-globe-caption {
    bottom: var(--sp-3);
  }

  .login--map .login-brandline,
  .login--map .login-panel {
    max-width: 460px;
    justify-self: center;
  }
}

/* Низкое окно: словесный знак меньше, подзаголовок снимается. */
@media (max-height: 640px) {
  .login--map .login-wordmark {
    font-size: 34px;
  }

  .login--map .login-tagline {
    display: none;
  }
}

/* Уважение к prefers-reduced-motion: движение здесь смысла не несёт. Сам кадр
   останавливает скрипт; здесь гасится только свечение индикатора. */
@media (prefers-reduced-motion: reduce) {
  .login--map .login-eyebrow::before {
    box-shadow: none;
  }
}
