/* ============================================================
   DEMO COMPONENT: GUEST AUTH ZONE            gbppl-demo-auth
   ------------------------------------------------------------
   Пиксельная копия https://portal.gildedbox.com/guest/auth
   (harvest public-login 2026-08-17, 7 ширин 360..2560; DOM и
   интерактивные состояния сняты Playwright 2026-08-18).
   Разметку дают шаблоны auth.js: <gb-guest-header>, <gb-field>,
   <gb-auth-flow>. Живые имена классов сохранены в разметке как
   данные для замера; стилевые правила висят на хуках .gbg-* / .gba-*.

   Лестницы (пороги xl = 1280, 2xl = 2000 — КАСТОМНЫЙ порог
   клиента, подтверждён на login: все 2xl-классы включаются между
   1920 и 2258, как на каталоге):

     семья форм-контролов  min-h 48 / 56 / 64 (инпут, сабмит,
                           Google-обёртка, OTP-ячейка — в ногу;
                           = интерполированная семья BUTTON L,
                           теперь ЖИВАЯ с public-login).
                           С gbppl-portal-fields-1 (04.09) у семьи
                           ДВЕ ИЕРАРХИИ, как у заголовков: сайт
                           48/56/64 при 14/16/18, портал (обёртка
                           .gba-scale-portal) 40/48/56 при 14/14/16.
                           Механизм — переменные, не второй класс;
                           арифметика и границы в блоке
                           «ПОРТАЛЬНАЯ СТУПЕНЬ» ниже. С
                           gbppl-portal-gate-1 (04.09) туда же доехал
                           пол многострочника --line: его поля
                           считались под сайтовую базу 48 и на
                           портальной базе 40 давали 47.39
     инпут                 underline: только border-bottom 1px
                           zinc-400, Inter 300 14/16/18 (lh = fs),
                           pad-x 12/12/16, ls 0.2, текст zinc-800;
                           hover бордер blue-600; focus БЕЗ рамки
                           (outline none, гаснет только placeholder)
     ошибка                бордер red-500, сообщение red-600 11px
                           справа (появляется только по сабмиту,
                           live 18.08: пустой и невалидный сабмит)
     лейбл                 11/12 caps 600, ls 0.5, zinc-500, lh 1.5;
                           золотая звёздочка required #bd9f58
     сабмит                УЕХАЛ В ОРГАНИЗМ (gbppl-button-2, 26.08):
                           .gb-btn --large --filled --primary --block.
                           Замер, что его описывал (bg blue-600,
                           radius 5, py 8, px 24/32, uppercase 600,
                           fs 14/16, ls -.35/-.4, лейбл-span
                           14/15(640)/16(2000) ls 1px, стрелка
                           absolute right 24/32 при 16/20/24) —
                           это и есть лестница L организма, снятая
                           отсюда. Здесь остался только отступ
                           .gba-submit
     карточка              max-w 600, mx auto, min-h calc(100vh-80),
                           py 0/96/128, вертикаль по центру;
                           стек 32/48/64, внутренний 24/32
     хедер гостя           header h-80 (плейсхолдер) + div.fixed:
                           #fcfdfd, c lg (1024) white/90 + blur 6px,
                           тень константная — как www-шапка, но
                           живой anatomy header > div.fixed
   ============================================================ */

/* ---------------- БАЗА ЗОНЫ ---------------- */

/* Живой грунт маршрута: дефолтный текст #191919 (--catalog-ink,
   вне цинка) и base line-height 24px наследуются всеми обёртками;
   preflight лайва держит на КАЖДОМ элементе border 0 solid #e5e5e5
   — воспроизводим в скоупе зоны, чтобы компьютед-сверка с
   public-login сходилась и по невидимым бордерам. Правила
   элементов (0-1-0) перекрывают базу (0-0-2) как на лайве. */
gb-guest-header, gb-auth-flow {
  color: var(--catalog-ink);
  line-height: 1.5;
}
gb-guest-header *, gb-guest-header *::before, gb-guest-header *::after,
gb-auth-flow *, gb-auth-flow *::before, gb-auth-flow *::after {
  border-width: 0;
  border-style: solid;
  border-color: var(--preflight-border);
}

/* ---------------- GUEST HEADER ---------------- */

/* Живая анатомия: header-плейсхолдер 80px в потоке + фиксированный
   бар (у www-шапки demo принят sticky; здесь fixed, чтобы селектор
   header > div.fixed конфига public-login совпадал один в один). */
gb-guest-header { display: block; }
.gbg-header { height: var(--header-h); }
.gbg-bar {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 999;
  height: var(--header-h);
  display: flex;
  align-items: center;
  background: var(--live-body);
  /* Тройная форма тени = живой tailwind-каскад ring-переменных:
     два нулевых слоя + константная тень хедера. */
  box-shadow: 0 0 #0000, 0 0 #0000, var(--shadow-header);
}
@media (min-width: 1024px) {
  .gbg-bar {
    background: var(--header-glass);
    backdrop-filter: blur(6px);
  }
}

/* Контейнер бара: живой .container портала = лестница www
   (16 / 24 с 1280 / клэмп 1920 + 48); имя класса container
   сохранено в разметке для селектора конфига, правила скоуплены. */
gb-guest-header .container {
  width: 100%;
  height: var(--header-h);
  min-height: 0;
  margin: 0 auto;
  padding-left: var(--container-pad-narrow);
  padding-right: var(--container-pad-narrow);
  display: flex;
  align-items: center;
  justify-content: space-between;
}
@media (min-width: 1280px) {
  gb-guest-header .container {
    padding-left: var(--container-pad);
    padding-right: var(--container-pad);
  }
}
@media (min-width: 1920px) {
  gb-guest-header .container {
    max-width: var(--container-max-xl);
    padding-left: var(--container-pad-wide);
    padding-right: var(--container-pad-wide);
  }
}

/* Знак: линк высотой бара, py 8 / 11 c lg (live guest header:
   py-2 lg:py-[11px]), картинка 168 в него вписана. Мобильный
   размер live не замерялся: фолбэк 144 = www-мобильный знак
   (felt, как в header.css). */
.gbg-brand { display: inline-flex; align-items: center; height: var(--header-h); padding: 8px 0; }
.gbg-brand img { width: 144px; height: auto; }
@media (min-width: 1024px) {
  .gbg-brand { padding: 11px 0; }
  .gbg-brand img { width: 168px; }
}

/* Скоуп-фикса цвета кнопок здесь БОЛЬШЕ НЕТ (24.08). Он стоял тут
   заплаткой на чужой баг: body.gb-demo a { color: inherit }
   (shell.css) перебивал цвет кнопки шапки, и лейбл Book a Meeting
   рендерился тёмным по тёмному. Владелец компонента — header.css —
   починен антидотом полной силы, и локальная копия превратилась бы
   ровно в тот дубль, который система запрещает (Тон-6). Гостевой
   хедер носит классы кнопочной семьи и ничего у неё не
   переопределяет, кроме раскладки (ниже). */

/* Нав и CTA живут только с lg (1024, живой порог бургера
   lg:hidden); ниже — бургер + знак + поиск, как на живом 360. */
.gbg-nav { display: none; }
.gbg-actions { display: flex; align-items: center; gap: 12px; }
.gbg-actions .gb-btn { display: none; }
@media (min-width: 1024px) {
  .gbg-nav { display: flex; align-items: center; }
  .gbg-actions .gb-btn { display: inline-flex; }
}

/* Бургер: живой бокс 30x40 mr-16, три линии; глиф felt (иконошрифт
   лайва не переносится, правило футера/каталога). Меню не открывает:
   гостевые страницы demo-лайва живут без дровера. */
.gbg-burger {
  width: 30px;
  height: 40px;
  margin-right: 16px;
  padding: 0;
  display: inline-flex;
  flex-direction: column;
  justify-content: center;
  gap: 7px;
  background: transparent;
  color: var(--zinc-900);
}
.gbg-burger span { display: block; width: 30px; height: 1.5px; background: currentColor; }
@media (min-width: 1024px) {
  .gbg-burger { display: none; }
}
.gbg-lead { display: flex; align-items: center; min-width: 0; }

/* ---------------- AUTH CARD / SECTION ---------------- */

/* Колонка формы: max-w 600 по центру, вертикальное центрирование
   в calc(100vh - 80px), py 0 / 96 (xl) / 128 (2xl). На 360 колонка
   лежит от края до края БЕЗ боковых полей — как на живом (x = 0). */
.gba-section {
  min-height: calc(100vh - var(--header-h));
  display: flex;
  flex-direction: column;
  justify-content: center;
  width: 100%;
  max-width: 600px;
  margin: 0 auto;
  padding-top: 0;
  padding-bottom: 0;
}
@media (min-width: 1280px) {
  .gba-section { padding-top: 96px; padding-bottom: 96px; }
}
@media (min-width: 2000px) {
  .gba-section { padding-top: 128px; padding-bottom: 128px; }
}

/* Внешний стек (space-y-8 xl:12 2xl:16): 32 / 48 / 64. */
.gba-stack { display: flex; flex-direction: column; }
.gba-stack > * + * { margin-top: 32px; }
@media (min-width: 1280px) { .gba-stack > * + * { margin-top: 48px; } }
@media (min-width: 2000px) { .gba-stack > * + * { margin-top: 64px; } }

/* Внутренний стек (space-y-6 xl:space-y-8): 24 / 32. */
.gba-group > * + * { margin-top: 24px; }
@media (min-width: 1280px) { .gba-group > * + * { margin-top: 32px; } }

/* Заголовок: sans 18/20/22, leading-tight, tracking-tight
   (-0.45 / -0.5 / -0.55), zinc-900; сабтайтл 13/16/16
   leading-relaxed zinc-500, ls 0.2, отступ 12 (space-y-3). */
.gba-header { margin: 0; }
.gba-h1 {
  margin: 0;
  font-family: var(--font-sans);
  font-size: 18px;
  font-weight: 400;
  line-height: 1.25;
  letter-spacing: -0.025em;
  color: var(--zinc-900);
}
.gba-sub {
  margin: 12px 0 0;
  font-size: 13px;
  line-height: 1.625;
  letter-spacing: 0.2px;
  color: var(--zinc-500);
}
@media (min-width: 1280px) {
  .gba-h1 { font-size: 20px; }
  .gba-sub { font-size: 16px; }
}
@media (min-width: 2000px) {
  .gba-h1 { font-size: 22px; }
}

/* ---------------- GOOGLE-КНОПКА ---------------- */

/* Живой виджет GSI пересобран статикой: обёртка div.block.w-full
   лайва задаёт семью 48/56/64, рамку surface-900 и radius 5 поверх
   iframe-кнопки; здесь то же одним элементом. Лейбл 14/16/16
   semibold ls 0.3 lh 110%; глиф G 20/28/32 с mr 12/16; пустой
   ::after того же размера уравновешивает центровку (как у лайва). */
.gba-google {
  width: 100%;
  min-height: 48px;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 8px 24px;
  background: var(--white);
  border: 1px solid var(--zinc-900);
  border-radius: var(--radius);
  transition: background 160ms;
}
.gba-google:hover { background: var(--zinc-50); }
.gba-google svg { width: 20px; height: 20px; flex: 0 0 auto; margin-right: 12px; }
.gba-google::after { content: ''; width: 20px; height: 20px; flex-shrink: 0; margin-left: 12px; pointer-events: none; }
.gba-google-label {
  font-family: var(--font-sans);
  font-size: 14px;
  font-weight: 600;
  line-height: 110%;
  letter-spacing: 0.3px;
  text-align: center;
  color: var(--zinc-900);
}
@media (min-width: 1280px) {
  .gba-google { min-height: 56px; padding-left: 32px; padding-right: 32px; }
  .gba-google svg, .gba-google::after { width: 28px; height: 28px; }
  .gba-google svg { margin-right: 16px; }
  .gba-google::after { margin-left: 16px; }
  .gba-google-label { font-size: 16px; }
}
@media (min-width: 2000px) {
  .gba-google { min-height: 64px; }
  .gba-google svg, .gba-google::after { width: 32px; height: 32px; }
}

/* Разделитель or: волосяные линии псевдоэлементами, zinc-200;
   текст 18/20, zinc-900, gap 12. */
.gba-divider {
  display: flex;
  align-items: center;
  gap: 12px;
  font-size: 18px;
  line-height: 1.5;
  color: var(--zinc-900);
}
.gba-divider::before, .gba-divider::after {
  content: '';
  flex: 1;
  height: 1px;
  background: var(--zinc-200);
}
@media (min-width: 1280px) {
  .gba-divider { font-size: 20px; }
}

/* ---------------- ФОРМА / <gb-field> ---------------- */

/* gb-field — flex-item живого form.row: без явной ширины ужмётся
   в shrink-to-fit (замер 18.08: 205 вместо 360). */
gb-field { display: block; width: 100%; }

/* Живая сетка Materialize: form.row с mx -8, ячейка .input-field
   с px 8 — форма на 16 шире колонки (замер: 616 при колонке 600). */
.gba-form { display: flex; flex-wrap: wrap; margin: 0 -8px; }
.gba-form .hidden { display: none; }

.gba-field {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  min-height: 1px;
  padding: 0 8px;
  margin-bottom: 16px;             /* !mb-4, e-mail поле */
}
/* Поля verify-шага: mb 24/32/40 (mb-6 md:mb-8 xl:mb-10). */
.gba-field--flow { margin-bottom: 24px; }
@media (min-width: 768px)  { .gba-field--flow { margin-bottom: 32px; } }
@media (min-width: 1280px) { .gba-field--flow { margin-bottom: 40px; } }
/* Последнее поле (confirm): mt 16, mb 0. */
.gba-field--last { margin-top: 16px; margin-bottom: 0; }

/* gbppl-label-eyebrow-1 (Ton 27.08: «унифицировать всё до eyebrow»): the caps
   field label stops keeping its own voice (live 11/12, tracking 0.5px) and
   wears the Eyebrow role, the one caps voice of the system. A documented
   departure from the live guest login; the floating variant below sets its
   own size and case and is not affected. */
.gba-label {
  display: block;
  font-size: var(--eyebrow-size);
  font-weight: var(--eyebrow-weight);
  line-height: 1.5;
  letter-spacing: var(--eyebrow-tracking);
  text-align: left;
  text-transform: uppercase;
  color: var(--eyebrow-color);
}
/* ЗВЁЗДОЧКА ГОВОРИТ ГОЛОСОМ ЛЕЙБЛА (gbppl-concierge-auth-2, 10.09).
   Тон, дословно: звёздочка обязательности НЕ должна быть золотой.

   Здесь стояло `color: var(--auth-required-gold)` — живое #bd9f58,
   снятое с формы гостевого входа 18.08 и записанное на витрине
   Field как «единственная часть поля не с палитры», исключение под
   общим вето на золото. Это была ТРАНСКРИПЦИЯ ЛАЙВА, и Тон её
   отменил: утверждённый компонент побеждает хаос живого портала.

   ЦВЕТА У НЕЁ ТЕПЕРЬ НЕТ ВООБЩЕ, и это сильнее любого нового
   значения: ::after наследует color лейбла, то есть звёздочка
   всегда ровно того тона, каким говорит подпись рядом (сегодня
   --eyebrow-color, Zinc 500). Один голос на роль, один и тот же во
   всех обликах поля; сменит лейбл ступень — звёздочка уйдёт с ним,
   без второй правки. Zinc 700 не понадобился: на 12px капсе знак
   читается и на белом, и на Zinc 50 (глазами, скрин в отчёте).
   Сам цвет не умер, он переехал на полку вето как замер лайва
   --gold-form (tokens.css). Отступ 5 остаётся живым. */
.gba-field.required .gba-label::after {
  content: '*';
  padding-left: 5px;
}

.gba-inputwrap { position: relative; }

/* Underline-инпут: только border-bottom 1px zinc-400, фон
   прозрачный, Inter 300 14/16/18 (lh = fs, leading-none), текст
   zinc-800, ls 0.2, pad-x 12/12/16, семья 48/56/64. Focus живой
   даёт ТОЛЬКО гашение плейсхолдера (outline none, бордер тот же);
   hover ведёт бордер в blue-600. */
.gba-input {
  width: 100%;
  min-height: var(--form-ctl-h);
  height: auto;
  margin: 0;
  /* Кегль и pad-x стали ИМЕНАМИ с живым числом в фолбеке
     (gbppl-portal-fields-1, 04.09, см. блок «ПОРТАЛЬНАЯ СТУПЕНЬ»
     ниже). Без объявления сверху здесь ровно те же 12 и 14, что
     стояли литералами: сайтовый масштаб не двигается ни на пиксель,
     а у портальной обёртки появляется рычаг. */
  padding: 0 var(--form-ctl-px, 12px);
  display: inline-block;
  background: transparent;
  /* Живой инпут красит border-color на ВСЕХ сторонах (zinc-400),
     ширину даёт только низу. */
  border-color: var(--zinc-400);
  border-bottom-width: 1px;
  border-radius: 0;
  font-family: var(--font-sans);
  font-size: var(--form-ctl-fs, 14px);
  font-weight: 300;
  line-height: 1;
  letter-spacing: 0.2px;
  color: var(--zinc-800);
  appearance: none;
  outline: none;
  overflow: clip;
  transition: color 0.2s cubic-bezier(0.4, 0, 0.2, 1), background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1), border-color 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.gba-input::placeholder {
  color: var(--zinc-400);
  opacity: 1;
  transition: opacity 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.gba-input:hover { border-color: var(--blue-600); }
/* gbppl-field-focus-1 (Ton 28.08: «при постановке курсора полоса не
   становится активной; должно быть как у обычного TextInput»). The
   field declared hover (live, Blue 600) but no focus at all, on input
   and textarea alike. DECLARED, not measured: the live lead form does
   not render on gildedbox.com/book-a-meeting today (no fields in any
   frame, 28.08), so the focus line takes the hover colour: blue is
   state (Тон-5), and a focused field is the most stated a field gets.
   One rule, both controls; the floating label already answers focus. */
.gba-input:focus { border-color: var(--blue-600); }
.gba-input:focus::placeholder { opacity: 0; }
/* DEMO-ONLY, gbppl-button-2. Витрине нужно поставить пять состояний
   поля в один ряд, а :hover и :focus в ряд не ставятся. Те же два
   имени, что объявил кнопочный организм, и то же правило: ни одна
   продуктовая страница их не носит. Ничего своего они не говорят —
   каждое повторяет живое правило строкой выше. */
.gba-input.is-hover { border-color: var(--blue-600); }
.gba-input.is-focus { border-color: var(--blue-600); }
.gba-input.is-focus::placeholder { opacity: 0; }
@media (min-width: 1280px) {
  .gba-input { min-height: var(--form-ctl-h-xl); font-size: var(--form-ctl-fs-xl, 16px); }
}
/* gbppl-227-mobile-4 (2026-10-14, Ton 14.10 «да, погнали!» on Ren's list;
   the 227 mobile audit's M-15). Under 1024 the field speaks 16, the floor
   under which iOS Safari zooms the page on focus: the checkout V5's billing
   address select was 14 on every phone (the portal step, .gba-scale-portal,
   keeps 14 on the desktop). The 227 room had lifted its own fields so
   (v3.css); the owner does it here, for every consumer. The floating field
   (.gba-field--floating, «как лайв», Ton 27.08) keeps the live lead form's
   13 / 14: its rule weighs more and is left as the live one is. 1024 and
   up: the ladder as it was. */
@media (max-width: 1023px) {
  .gba-input { font-size: 16px; }
}
@media (min-width: 2000px) {
  .gba-input {
    min-height: var(--form-ctl-h-2xl);
    font-size: var(--form-ctl-fs-2xl, 18px);
    padding: 0 var(--form-ctl-px-2xl, 16px);
  }
}

/* ============================================================
   ПОРТАЛЬНАЯ СТУПЕНЬ ФОРМ-КОНТРОЛОВ: .gba-scale-portal
                                  gbppl-portal-fields-1, 04.09
   ------------------------------------------------------------
   Тон, дословно: «Почему мы используем самый большой размер
   инпута, когда он здесь не нужен? Это не веб-сайт для
   маркетинга. На портале (а чекаут является частью портала) эти
   поля должны быть меньше.»

   ЭТО НЕ ВТОРОЕ ПОЛЕ И НЕ КОПИЯ КЛАССОВ. Поле одно, у него один
   облик, одни состояния (hover, focus, invalid, disabled) и один
   авторост. Меняется ровно то, чем лестница и является: НА КАКОЙ
   СТУПЕНИ поле стоит. Обёртка формы объявляет свои три ступени,
   контрол читает их теми же именами и теми же порогами, что и
   раньше, — поэтому за ступенью автоматически едут все, кто уже
   тратит семью: `.gba-textarea--line` (пол = ступень контрола),
   `.gba-select` (инсет шеврона = pad-x поля), `.gba-otp`.

   БЛИЗНЕЦ В КАНОНЕ. У заголовков это решение уже принято (Тон
   26.08): сайт носит hero-H1 36/48/52, портал и его страницы —
   page-H1 28/36/40, «на портале заголовки меньше, там большие не
   нужны». Поля получают ту же пару иерархий и по той же причине.

   АРИФМЕТИКА ВЫСОТ — ОДНА СТУПЕНЬ ВНИЗ ПО СЕТКЕ ДОМА, не новый
   ряд чисел. Сетка высот контролов (Тон 26.08): 72 / 64 / 56 /
   48 / 40 / 36 / 32.
     сайт    48 / 56 / 64
     портал  40 / 48 / 56   (48→40, 56→48, 64→56)
   Все три портальных числа — существующие ступени той же сетки,
   и верхние две из них сайт носит сам этажом ниже. Ни одного
   выдуманного значения.

   АРИФМЕТИКА КЕГЛЯ — ВНИЗ ТОЛЬКО ТАМ, ГДЕ ЕСТЬ КУДА.
     сайт    14 / 16 / 18
     портал  14 / 14 / 16
   16→14 и 18→16 — соседние ступени той же лестницы поля. База
   ОСТАЁТСЯ 14, потому что 14 и есть пол этой лестницы: ниже
   только 13, а 13 в доме встречается ровно один раз — в
   `.gba-field--floating`, где это ЗАМЕР чужой маркетинговой
   страницы (contact-us-219), а не выбор системы. Правило копии
   говорит «базовый текст 16, вторичное 14-15», и поле, в которое
   человек печатает, — не вторичный текст (Рассел: «мелкий
   блеклый текст = я не важен»). Форма шага та же, что у
   заголовков: высоты падают на всех трёх порогах, кегль — там,
   где лестница это позволяет.

   PAD-X СЛЕДУЕТ ЗА СТУПЕНЬЮ, А НЕ ЗА ПОРОГОМ. Сайт даёт 12 / 12
   / 16: шестнадцать приходят вместе со ступенью 64. У портала
   ступени 64 нет вообще, максимум 56, а 56 в сайтовой лестнице
   носит pad-x 12. Значит портальный pad-x плоский 12 на всех
   трёх — это НЕ решение, это следствие.

   ГЛИФ СЕЛЕКТА: 20 → 16. Двадцать — иконочная ступень large
   (LIVE auth 18.08), шестнадцать — соседняя ступень той же
   иконочной шкалы (--gb-btn-small-icon-xl / --gb-btn-large-icon).
   В контроле 40 высотой глиф 20 съедает половину строки.

   ЧЕГО ЭТА СТУПЕНЬ НЕ ТРОГАЕТ И ПОЧЕМУ:
     · пол простого `.gba-textarea` (80 / 96 с 2000) — это ЖИВОЕ
       число (!min-h-[80px]) и оно описывает СТРОКИ ТЕКСТА, а не
       семью контролов; носители в V5 появились 15.09
       (gbppl-v5-julia-1: поле сообщения открытки в двух местах
       сняло `--line` по слову Юли «a text box, not a field»).
       Пересчёт пола под портальный кегль = вопрос Тону, а не
       арифметика волны;
     · потолок автороста (три ступени 64) — свойство панели, в
       которой поле стоит, а не масштаба;
     · `.gba-field--floating` заперт «как лайв» (Тон 27.08) и в
       портальную обёртку не ставится.

   БЕЗ КЛАССА ВСЁ БАЙТ В БАЙТ. Ни одно правило выше не изменило
   значения: литералы стали именами С ТЕМ ЖЕ ЧИСЛОМ В ФОЛБЕКЕ.
   Пока обёртки нет, имена не объявлены, и браузер берёт фолбек.
   ============================================================ */
.gba-scale-portal {
  --form-ctl-h:      40px;   /* сетка высот: ступень под 48 */
  --form-ctl-h-xl:   48px;   /* ступень под 56 */
  --form-ctl-h-2xl:  56px;   /* ступень под 64 */
  --form-ctl-fs:     14px;   /* пол лестницы поля, ниже только живое 13 */
  --form-ctl-fs-xl:  14px;   /* 16 → 14 */
  --form-ctl-fs-2xl: 16px;   /* 18 → 16 */
  --form-ctl-px:     12px;   /* следствие: ступени 64 здесь нет */
  --form-ctl-px-2xl: 12px;
  --form-ctl-glyph:  var(--gb-btn-large-icon);  /* 16, ступень под 20 */
}

/* ПОЛ МНОГОСТРОЧНИКА ДОЕХАЛ ДО СТУПЕНИ ТОЛЬКО ЗДЕСЬ
                              gbppl-portal-gate-1, 04.09, прибором
   ------------------------------------------------------------
   `.gba-textarea--line` объявляет пол ступенью контрола
   (--form-ctl-h*), но у `.gba-textarea` вертикальные поля 12 и
   междустрочие 1.6 — числа, посчитанные под САЙТОВУЮ базу 48:
   12 + 22.4 + 12 + 1 = 47.4, и min-height 48 их накрывал. На
   портальной базе накрывать нечем: ступень 40, а собственный рост
   одной строки те же 47.39, поэтому `min-height` бессилен и поле
   стоит на 7.39 выше соседей по форме — ровно то, ради чего
   модификатор --line и заводился («в пустом дровере поле имени и
   поля текста стоят одного роста»). Замер 04.09, дровер Greeting
   card, V5: 360 → To 40, Message 47.39, From 40. Тот же перекос
   в панели карточки шага 2.
   И вторая половина той же арифметики: на 2xl коробка 56 (пол
   держит), но строка сидит в 12 от верха при 17.4 снизу —
   единственная строка не по центру своей ступени.

   ЛЕЧИТСЯ НЕ НОВЫМ ЧИСЛОМ, А ФОРМУЛОЙ ИЗ УЖЕ ОБЪЯВЛЕННЫХ: поля
   считаются от ступени, из которой вычтены волосок подчёркивания
   (1px, свой же бордер) и одна строка (1.6em — то самое
   междустрочие .gba-textarea, em берётся от кегля ступени). Одна
   строка становится ростом в ступень и стоит в ней по центру на
   всех трёх порогах: 40 / 48 / 56 ровно. Дальше поле растёт как
   росло.

   ПОЧЕМУ БОЛЬШЕ НЕ ТОЛЬКО ПОД ОБЁРТКОЙ. «Отдельное решение» из
   отчёта той волны принято 22.09 самим Тоном, и принято шире, чем
   ставился вопрос: строка и её центровка — дефолт владельца (см.
   блок AUTOGROW ниже). Формула переехала в само `.gba-textarea` и
   читает те же имена, поэтому под обёрткой она считает портальные
   ступени, без неё — сайтовые из tokens.css; скоуп-копия здесь
   стала бы третьим написанием одного правила и снята. */

/* ---------------- ВЕРСИЯ ПОЛЯ: .gba-textarea ----------------
   gbppl-booking-1, 25.08. Лид-форме Book a Meeting нужен ответ на
   вопрос «What are you looking for?» — многострочный. Тон-6, шаг
   2: не новое поле, а версия существующего. Всё, что делает
   инпут полем (подчёркивание, Inter 300 14/16/18, ls 0.2, цвет,
   pad-x, ошибка, hover-синий), остаётся от .gba-input; версия
   меняет ровно три вещи, которых у однострочника быть не может:

     высота    min-height живого textarea = 80 (!min-h-[80px],
               harvest public-book-a-meeting, цель textarea-comment),
               а не семья контролов 48/56/64: строк здесь несколько
               по определению;
     набор     line-height 1.6 вместо leading-none — междустрочие
               существует только у многострочного (живое 160%), и
               вертикальные поля 12 вместо центровки одной строки;
     ресайз    только вертикальный: горизонтальная ручка ломает
               колонку формы.

   Лестница шрифта у живого textarea своя (13/14/16), и версия её
   НЕ берёт: поле стоит в одной форме с остальными и идёт с ними в
   ногу по 14/16/18 (Тон-9 — входящее приводится к системе).

   ---------------- AUTOGROW, gbppl-field-autogrow-1, 01.09 --------
   Тон, дословно: «я тоже склоняюсь к Auto-Grow, поле должно расти».
   До этой волны рост был у ДВУХ потребителей и у каждого свой:
   booking.js растил живой брифинг скриптом, comments.js растил поле
   треда своей копией того же скрипта, а чекаут и витрина стояли
   мёртвыми коробками rows=3 и прокручивались внутри с первой же
   лишней строки. Поведение переезжает к владельцу целиком: у поля
   его одно, и получают его все, кто носит класс.

     ПОЛ      ОДНА СТРОКА, СТУПЕНЬ КОНТРОЛА (22.09, Тон, дословно:
              «он выглядит как обычный текстовый инпут... плюс он
              должен автоматически растягиваться, когда ты начинаешь
              писать. При этом текст не должен прыгать куда-то высоко
              вверх. И эта проблема у нас системно по всей системе. Я
              прошу тебя исправить этот компонент»). До этого дня пол
              был живым 80 (!min-h-[80px] лид-формы), и модификатор
              --line возвращал полю строку там, где потребитель о нём
              вспоминал; теперь строка — дефолт владельца, 80 остаётся
              только у самой лид-формы в её живом скоупе (ниже).
              Вертикаль строки считается формулой из уже объявленных
              имён — (ступень - волосок - 1.6em) / 2 — так одна строка
              стоит по центру своей ступени на обоих масштабах и всех
              трёх порогах, и каретка сидит на линии, а не этажом выше.
     РОСТ     field-sizing: content. Браузер сам меряет содержимое
              и сам держит пол и потолок; инлайновых высот в
              странице не появляется, а значит рост работает и там,
              где текст пришёл не с клавиатуры (Alpine чекаута,
              <template> дроверов, восстановленный черновик треда).
              Прибор на Chrome 141: пусто 79.99, середина 101.65,
              за потолком 191.99 и scrolls: true, стёрли — снова
              79.99. Браузеру без field-sizing то же самое считает
              auth.js по scrollHeight (фолбек, одна ветка).
     ПОТОЛОК  три ступени 64. Поле, которое растёт без предела,
              выдавливает кнопку из панели: в дроврере комментов это
              уже было замерено (gbppl-comments-c), и потолок стоял
              там, у потребителя. Здесь он у владельца, ступенями, а
              не производным токеном (ловушка 21в).
     ПРОКРУТКА за потолком — внутри поля, честная: overflow остаётся
              auto, и полоса появляется ровно тогда, когда текст
              перестал помещаться.
     РУЧКА    ВЕРНУЛАСЬ, вертикальная (22.09, Тон, дословно: «в правом
              уголке есть вот этот индикатор, что его можно
              растягивать»). Живое базовое правило говорит то же:
              textarea{resize:vertical} (замер 01.09). Поведение
              честное: пока ручку не трогали, поле меряет себя само;
              потянул — инлайновая высота сильнее авторазмера, и поле
              замирает на выбранном росте. Уголок и есть обещание
              ровно этого.
     БЕЗ АНИМАЦИИ. Высота меняется строкой, мгновенно: каретка
              обязана стоять там, где палец, а переход по height
              оставлял бы её позади набора. Тон-7 про фирменные
              хореографии, здесь служебная механика набора.
     СТРОКА, А НЕ БАЗОВАЯ ЛИНИЯ. display: block — у .gba-input он
              inline-block, и многострочник, севший на baseline
              обёртки, оставлял под своим боксом 6px пустоты от
              её strut (замер 28.08 в дровере: обёртка 86.28 вокруг
              поля 79.99). Дровер лечил это локально; лечится у
              владельца, и лечится всем — коробке чекаута и витрине
              тоже. Живой лид-формы правило не касается (ниже). */
.gba-textarea {
  min-height: var(--form-ctl-h);
  height: auto;
  padding-block: calc((var(--form-ctl-h) - 1px - 1.6em) / 2);
  line-height: 1.6;
  display: block;
  field-sizing: content;
  max-height: calc(var(--space-64) * 3);
  resize: vertical;
  overflow: auto;
  /* Полоса прокрутки, которая появляется на потолке, — тихая: узкая,
     без кнопок-стрелок, ползунок Zinc 300 на прозрачном (ступени
     шкалы, не новые значения). Классическая полоса Windows со
     стрелками весит в этом поле больше, чем сам текст, и это видно
     глазами на скрине, а не в числах. Ключевые слова, не числа:
     ширину полосы браузер держит свою. */
  scrollbar-width: thin;
  scrollbar-color: var(--zinc-300) transparent;
}
@media (min-width: 1280px) {
  .gba-textarea {
    min-height: var(--form-ctl-h-xl);
    padding-block: calc((var(--form-ctl-h-xl) - 1px - 1.6em) / 2);
  }
}
@media (min-width: 2000px) {
  .gba-textarea {
    min-height: var(--form-ctl-h-2xl);
    padding-block: calc((var(--form-ctl-h-2xl) - 1px - 1.6em) / 2);
  }
}

/* ТИХОЕ ТЕЛО НА ПОТОЛКЕ (gbppl-field-autogrow-1, DECLARED по Тон-17:
   на лайве такого нет, там многострочник фиксированный). Пока текст
   помещается, поле остаётся чистой линией — тем же полем, что стоит
   рядом с однострочниками. Когда текст перерос потолок и внутри
   началась прокрутка, за ним проступает земля: у прокручиваемой
   области должны быть видимые края, иначе строка, уехавшая под
   верхнюю кромку, выглядит просто обрезанной. Это тот же приём, что
   у filled-поля Material 3, но включённый только тогда, когда он
   нужен. Класс ставит auth.js по ФАКТУ прокрутки, не по числу строк.
   Перехода своего правило не заводит: background-color уже стоит в
   переходе .gba-input (200ms, та же кривая), и земля проявляется с
   ним. */
.gba-textarea.is-capped { background-color: var(--zinc-50); }

/* ---------------- ПОЛ В ОДНУ СТРОКУ: .gba-textarea--line ----------
                                   gbppl-comments-hitbox-1, 01.09
   Тон, дословно (в тот же час, что и жалоба на попадание курсором):
   «Не забудь про решение TextArea, чтобы она была растягиваемой, а не
   большой по дефолту. Это сразу сбивает, непонятно, куда ставить
   курсор.»

   Пол 80 выше — ЖИВОЙ (!min-h-[80px] лид-формы), и он остаётся полом
   поля. Но пол это не свойство многострочника, это его НАЧАЛЬНЫЙ РОСТ,
   и у формы, где многострочник стоит в ряд с однострочниками, начальный
   рост другой: строка. Поэтому не переписанное значение, а ось —
   модификатор, который ставит потребитель, знающий свою форму.

   ПОЛ = ТА ЖЕ ЛЕСТНИЦА КОНТРОЛА, что у соседа по колонке: 48 / 56 с
   1280 / 64 с 2000 (--form-ctl-h*). Ни одного нового числа: в пустом
   дровере поле имени и поля текста стоят одного роста, и глазу больше
   не приходится решать, куда целиться. Разница между рядами появляется
   только тогда, когда её создал набранный текст.

   Потолок, земля на потолке, снятая ручка и field-sizing не трогаются:
   растёт поле ровно так же, просто начинает с одной строки.

   22.09 ЭТА ОСЬ СТАЛА ДЕФОЛТОМ ВЛАДЕЛЬЦА (Тон, блок AUTOGROW выше):
   поле начинает строкой везде, класс остаётся именем оси в разметке
   носителей и ничего больше не переписывает. Снять его отовсюду —
   уборка, не поведение. */
.gba-textarea--line { min-height: var(--form-ctl-h); }
@media (min-width: 1280px) { .gba-textarea--line { min-height: var(--form-ctl-h-xl); } }
@media (min-width: 2000px) { .gba-textarea--line { min-height: var(--form-ctl-h-2xl); } }

/* ---------------- ВЕРСИЯ ПОЛЯ: ПЛАВАЮЩИЙ ЛЕЙБЛ ----------------
                                          gbppl-field-floating-1
   27.08. Тон, дословно: «Должно быть полностью как на live. Раз мы
   имитируем live, должно быть как там. Я бы даже не переделывал
   то, как настеканы поля в форме. Мы должны имитировать первый шаг
   точно так же, как на live. Это не sandbox, это live.»

   Живая лид-форма https://www.gildedbox.com/page/contact-us-219
   носит ДРУГОЙ облик того же поля: лейбл стоит внутри строки, а на
   фокусе или при заполнении уезжает вверх и сжимается. Это версия,
   не новое поле (Тон-6): подчёркивание, цвет чернил, ошибка,
   hover-синий и звёздочка required остаются от .gba-input, версия
   переписывает лестницу и место лейбла.

   ПОЧЕМУ ЛЕСТНИЦА СВОЯ. У гостевой авторизации (portal, замер
   18.08) поле идёт 14/16/18 при высоте 48/56/64. У лид-формы
   (замер 27.08, прибор на четырёх ширинах) — 13 / 14 с 1280 / 16 с
   2000 при высоте 48 / 48 / 56 и pad-x 12/12/16. Это ДВЕ разные
   живые страницы клиента, и на Live-странице мы носим ту, что
   стоит на ней. Дефолт <gb-field> не изменился ни на пиксель.

   ЧИСЛА ЛЕЙБЛА, снятые с живого label (LIVE 27.08):
     покой    absolute, top 50%, left 12 (16 с 2000), width 100%,
              translateY(-50%), Inter 300 14/1.5 (16 с 2000), ls
              0.2, zinc-600, pointer-events none
     активный top -4px, шрифт 11.2px/1.5, translateY(-50%) остаётся
     переход  all 200ms cubic-bezier(.4,0,.2,1) — та же кривая, что
              у остальных переходов поля

   11.2 НЕ ВЫДУМАНО. Живое правило — text-[70%], и 70% считаются от
   шрифта РОДИТЕЛЯ (16px базового текста страницы), а не от 14px
   самого лейбла: 16 x 0.7 = 11.2 на всех ширинах, включая 2xl, где
   покой уже 16. Записываем результат числом, потому что у нас
   родитель не обязан быть 16px, и процент дал бы другую ступень.

   ПОДЪЁМ БЕЗ JS. Лайв вешает на инпут класс .filled скриптом; нам
   хватает соседа: лейбл стоит ПОСЛЕ контрола, и «пусто» читается
   через :placeholder-shown (auth.js даёт таким полям плейсхолдер в
   один пробел — на placeholder="" псевдокласс не срабатывает
   вовсе). Автозаполнение Chrome тоже снимает :placeholder-shown,
   то есть лейбл поднимается и там, где события input не было. */
.gba-field--floating .gba-inputwrap { position: relative; }

/* Лестница живой лид-формы. Порог 2xl тот же 2000. */
.gba-field--floating .gba-input {
  min-height: var(--form-ctl-h);      /* LIVE 27.08: 48 и на 1280 */
  font-size: 13px;                    /* LIVE 27.08 */
}
@media (min-width: 1280px) {
  .gba-field--floating .gba-input { min-height: var(--form-ctl-h); font-size: 14px; }
}
@media (min-width: 2000px) {
  .gba-field--floating .gba-input {
    min-height: var(--form-ctl-h-xl); /* LIVE 27.08: 56, не 64 */
    font-size: 16px;
    padding: 0 16px;
  }
}

.gba-field--floating .gba-inputwrap > .gba-label {
  position: absolute;
  top: 50%;
  left: 12px;                          /* LIVE 27.08: left-3 */
  width: 100%;
  margin: 0;
  transform: translateY(-50%);
  font-size: 14px;                     /* LIVE 27.08 */
  font-weight: 300;
  line-height: 1.5;
  letter-spacing: 0.2px;
  text-transform: none;
  color: var(--zinc-600);
  pointer-events: none;
  transition: all 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
@media (min-width: 2000px) {
  .gba-field--floating .gba-inputwrap > .gba-label { left: 16px; font-size: 16px; }
}
/* Поднятое состояние. Демо-класс .is-focus повторяет живое правило
   и ничего своего не говорит — той же породы, что .gba-input.is-focus
   строкой выше: витрине нужно поставить состояния в один ряд. */
.gba-field--floating .gba-input:focus ~ .gba-label,
.gba-field--floating .gba-input.is-focus ~ .gba-label,
.gba-field--floating .gba-input:not(:placeholder-shown) ~ .gba-label {
  top: -4px;                           /* LIVE 27.08: -top-1 */
  font-size: 11.2px;                   /* LIVE 27.08: text-[70%] от 16 */
}

/* Статичный лейбл над полем остаётся ровно у одного поля живой
   формы — у комментария (LIVE 27.08: 11 / 12 с 1280, 600, ls 0.5,
   zinc-500). От гостевого он отличается ОДНИМ: регистр не
   переворачивается. Класс uppercase в живой разметке есть, но
   computed на всех четырёх ширинах говорит text-transform: none. */
.gba-field--floating > .gba-label { text-transform: none; }

/* Многострочник живой формы: своя лестница шрифта (13/14/16, как у
   однострочника этой же страницы), 160% междустрочия, min-h 80 на
   всех ширинах и рост по содержимому — высоту ставит booking.js,
   поэтому собственной прокрутки у поля нет.

   ЭТОТ ОБЛИК ОСТАЁТСЯ НА ЖИВОЙ МЕХАНИКЕ (gbppl-field-autogrow-1,
   01.09) — сознательное исключение из автороста владельца, потому
   что «Live имитирует лайв целиком» (Тон 27.08), а лайв растит это
   поле иначе. Замер живой contact-us-219 СЕГОДНЯ, 01.09 (страница
   снова отдаётся, 28.08 не отдавалась): у textarea класс
   overflow-hidden, !min-h-[80px], НИ max-height, НИ resize-none, а
   базовое правило страницы говорит textarea{resize:vertical}. То
   есть живое поле растёт без потолка, прокрутки внутри не имеет и
   уголок показывает. Три строчки ниже возвращают ему ровно это:

     field-sizing: fixed   стартовая высота остаётся живой (rows=3,
                           height=scrollHeight скриптом: 86 / 91 с
                           1280 / 101 с 2000). Content-размер дал бы
                           пол 80 и увёл замер формы с 467.23;
     max-height: none      потолка у живого нет;
     resize: vertical      уголок у живого есть;
     display: inline-block их textarea тоже стоит на базовой линии
                           обёртки, и те самые 6px strut'а входят в
                           живую высоту формы, с которой мы сошлись
                           число в число. Выпрямлять их здесь значит
                           разойтись с лайвом на 6px в четырёх
                           замерах сразу.

   Высоту по-прежнему ставит booking.js, и auth.js этого поля не
   трогает (та же проверка на .gba-field--floating). */
.gba-field--floating .gba-textarea {
  min-height: 80px;                    /* LIVE 27.08: !min-h-[80px] */
  padding: 12px;
  line-height: 1.6;                    /* LIVE 27.08: leading-[160%] */
  overflow: hidden;                    /* растёт, а не прокручивается */
  field-sizing: fixed;                 /* LIVE 01.09: высоту ведёт скрипт */
  max-height: none;                    /* LIVE 01.09: потолка нет */
  resize: vertical;                    /* LIVE 01.09: textarea{resize:vertical} */
  display: inline-block;               /* LIVE: strut обёртки входит в 467.23 */
}
@media (min-width: 2000px) {
  .gba-field--floating .gba-textarea { min-height: 80px; padding: 12px 16px; }
}
/* Плейсхолдер многострочника на лайве на ступень темнее, чем у
   однострочников (surface-500 против surface-400): у него он
   работает подсказкой, а не заглушкой. */
.gba-field--floating .gba-textarea::placeholder { color: var(--zinc-500); }

/* Ошибка (по сабмиту, live 18.08: пустой и невалидный e-mail дают
   одно состояние): бордер red-500 (перекрывает hover), сообщение
   red-600 11px справа. Классов helper-text/errorMessage у лайва
   НЕТ — сообщение живёт в span[role=alert].text-red-600. */
.gba-input.invalid { border-color: var(--red-500); }
.gba-input.invalid:hover { border-color: var(--red-500); }
.gba-error {
  display: block;
  position: relative;
  font-size: 11px;
  letter-spacing: 0.2px;
  text-align: right;
  color: var(--red-600);
}

/* ---------------- ПОДСКАЗКА ПОД ПОЛЕМ: .gba-helper ----------------
                                        gbppl-concierge-auth-2, 10.09
   Правило Тона: лейбл всегда КОРОТКИЙ и говорит, что это за поле;
   объяснение живёт в плейсхолдере или в подсказке под полем. До
   сих пор подсказка в доме была у ШАГА (.gba-hint, по центру под
   OTP и паролем) и у ФОРМЫ (.gbc-hint, служебная строка под
   действиями треда), а у самого поля её не было — и каждый, кому
   она понадобилась, написал бы свою. Теперь это параметр поля
   (auth.js, helper="…"), и рецепт один.

   ЧИСЛА — ИЗ ПРЕЦЕДЕНТА, НЕ НОВЫЕ: 14/1.5 Zinc 500 с отступом 8 —
   это .gbc-hint формы треда, буква в букву. Не .gba-hint (12 по
   центру, Zinc 400): та стоит под ШАГОМ, а не под полем; по центру
   в левой колонке формы читалось бы как подпись к чему-то другому,
   а мелкий блеклый текст у Рассела под прямым запретом («я не
   важен»).

   ЖИВЁТ РЯДОМ С ОШИБКОЙ, А НЕ ВМЕСТО НЕЁ. setError дописывает
   .gba-error в конец обёртки, то есть ПОД подсказку: одна говорит,
   что писать, другая — что не так с написанным, и гасить первую в
   тот момент, когда человек ошибся, было бы ровно наоборот. */
.gba-helper {
  margin: var(--space-8) 0 0;
  font-size: 14px;
  line-height: 1.5;
  text-align: left;
  color: var(--zinc-500);
}

/* ---------------- СЧЁТЧИК ПОЛЯ: .gba-count ----------------
                                        gbppl-field-count-1, 29.09
   Тон, 29.09, дважды за час. Сначала: «0 / 50 chars как айбрау под
   инпутами, это против канона» (айбрау = голос лейбла). Потом, когда
   я надел на счётчик ступень подсказки (14 слева, как абзац): «он
   должен быть маленький, определённого шрифта, и ты его ставил
   справа». Канон, который уже был записан: DESIGN-LAWS D1 «лейбл
   сверху капсом-айбрау, счётчик справа», и оба живых носителя рисуют
   его одинаково: чекаут V1-V4 (text-xs text-zinc-500 = 12 Zinc 500
   справа) и живая страница кампании портала (12 Zinc 500, снято
   прибором 28.09). LIVE > DECLARED: 12/1.5 Zinc 500, прижат вправо,
   8 под полем, цифры табличные, строчными. Счётчик это метка поля,
   а не текст для чтения: он не спорит с полом 14 для контента, как не
   спорит числительное бейджа. Подсказка .gba-helper остаётся слева:
   одна говорит, что писать, другой сколько осталось. --inline для
   строки лейбла (панель открытки чекаута V5): тот же голос в ряд. */
.gba-count {
  display: block;
  margin: var(--space-8) 0 0;
  font-size: 12px;              /* LIVE: text-xs of the checkout and the portal's campaign page */
  font-weight: 400;
  line-height: 1.5;
  letter-spacing: normal;
  text-transform: none;
  text-align: right;
  color: var(--zinc-500);
  font-variant-numeric: tabular-nums;
}
.gba-count--inline { display: inline; margin: 0; }
/* ОДИН ЖИТЕЛЬ ПОД ПОЛЕМ (Тон, 29.09): ошибка вытесняет счётчик и
   подсказку, пока она есть; clearError её убирает, и строка
   возвращается прежнему жителю. */
.gba-field:has(> .gba-error) > .gba-count,
.gba-field:has(> .gba-error) > .gba-helper { display: none; }

/* ============================================================
   ЧЕТВЁРТЫЙ ОБЛИК ПОЛЯ: .gba-select   gbppl-oro-select-stepper-1
   ------------------------------------------------------------
   Скилл, раздел 8, открыто с 27.08 (gbppl-checkout-14): «SELECT:
   компонента НЕТ. На чекауте их два... Оба надели .gba-input —
   ближайшее истинное, что система имеет, — и оба потеряли шеврон,
   который у селекта должен быть. Поле и селект это не одно и то
   же, и система обязана это сказать.»

   ЭТО ВЕРСИЯ ПОЛЯ, А НЕ ВТОРОЕ ПОЛЕ (Тон-6, шаг 2). Всё, что
   делает поле полем — подчёркивание Zinc 400, семья 48/56/64,
   Inter 300 14/16/18, ls 0.2, pad-x 12/12/16, hover и focus в
   Blue 600, красная линия ошибки — остаётся от .gba-input, буква
   в букву. Версия добавляет РОВНО ОДНО: знак того, что список
   раскрывается.

   ЧТО ЗАМЕРЕНО, А ЧТО ОБЪЯВЛЕНО (29.08, прибор):
     · НАШ чекаут до волны: оба селекта носят .gba-input, у
       которого `appearance: none`, то есть браузерной стрелки у
       них нет ВООБЩЕ — не «браузерная стрелка», а пустое место
       справа. Высоты 48 / 56, подчёркивание 1px Zinc 400.
     · Живой сайт клиента: провенанс в отчёте волны. Оттуда мера
       поля, которая у нас уже стоит; облик шеврона DECLARED по
       Тон-17 — недостающее состояние закрывается у владельца.

   МЕНЮ ОПЦИЙ НЕ РИСУЕТСЯ. Список раскрывает операционная система,
   и это осознанно: она рисует его правильно на телефоне, помнит
   клавиатурный поиск по букве и не требует ни слоя, ни ловушки
   фокуса, ни виртуального списка. Кастомный список стоил бы всего
   этого и не дал бы ничего, чего нет. День, когда селекту
   понадобится картинка в строке или группа с описанием, — день,
   когда этот абзац переписывается, и не раньше.

   ШЕВРОН: .gb-icon 20 с именем chevron-down из набора (icon.js),
   потому что рисовать стрелку CSS-треугольником значит завести
   двадцатую иконку мимо записи. Он лежит ПОСЛЕ контрола в DOM —
   как и плавающий лейбл, порядок несущий: состояние шеврона
   читается с соседа (`.gba-input:disabled ~ .gb-icon`), без JS.
   ============================================================ */

/* Коробка обёртки: та же .gba-inputwrap (position: relative), плюс
   вычет под шеврон. Обёртка НИЧЕГО не рисует: рисует контрол. */
.gba-select {
  /* Шеврон: ступень 20 иконочной шкалы (--gb-btn-large-icon-xl, LIVE
     auth 18.08). Отступ справа = pad-x поля, чтобы глиф стоял на
     той же вертикали, что и текст с другой стороны. */
  --gba-select-glyph: var(--form-ctl-glyph, var(--gb-btn-large-icon-xl));
  --gba-select-inset: var(--form-ctl-px, 12px);
  position: relative;
  display: block;
}
@media (min-width: 2000px) { .gba-select { --gba-select-inset: var(--form-ctl-px-2xl, 16px); } }

/* Место под глиф: инсет + сам глиф + зазор со шкалы. Меньше — и
   длинная опция уезжает под стрелку. */
.gba-select > .gba-input {
  padding-right: calc(var(--gba-select-inset) + var(--gba-select-glyph) + var(--space-8));
  cursor: pointer;
}

/* Глиф. pointer-events снят: клик по стрелке обязан раскрывать
   список, а не попадать в пустоту рядом с ним. Ищется и по классу
   компонента, и по атрибуту записи: icon.js подставляет разметку
   на DOMContentLoaded, а до тех пор место уже держится. */
.gba-select > .gb-icon,
.gba-select > [data-gb-icon] {
  position: absolute;
  top: 50%;
  right: var(--gba-select-inset);
  transform: translateY(-50%);
  width: var(--gba-select-glyph);
  height: var(--gba-select-glyph);
  color: var(--zinc-500);
  pointer-events: none;
  transition: color 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}

/* Состояние читается на всей обёртке, а не на глифе: наведение на
   поле и наведение на стрелку — одно событие для человека. Синий,
   потому что синий это состояние (Тон-5), и линия под полем в этот
   же момент идёт туда же. DECLARED вместе с самим шевроном. */
.gba-select:hover > .gb-icon,
.gba-select:focus-within > .gb-icon { color: var(--blue-600); }

/* DEMO ONLY, те же два имени, что объявили кнопка и поле: витрине
   нужно поставить пять состояний в один ряд, а :hover и :focus в
   ряд не ставятся. Ни одна продуктовая страница их не носит. */
.gba-select.is-hover > .gb-icon,
.gba-select.is-focus > .gb-icon { color: var(--blue-600); }

/* Порядок важен: гашение стоит ПОСЛЕ синего, иначе выключенный
   селект синел бы под курсором. */
.gba-select > .gba-input:disabled ~ .gb-icon { color: var(--zinc-300); }
.gba-select > .gba-input:disabled { cursor: not-allowed; }

/* Глазок пароля: живой i.icon-eye absolute right 16, bottom 16
   (20 с xl); глиф заменён инлайн-SVG (правило иконошрифта). */
.gba-eye {
  position: absolute;
  right: 16px;
  bottom: 16px;
  width: 18px;
  height: 18px;
  padding: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: transparent;
  color: var(--zinc-500);
}
@media (min-width: 1280px) { .gba-eye { bottom: 20px; } }
.gba-eye svg { width: 18px; height: 18px; }

/* ---------------- САБМИТ ФОРМЫ ----------------
   gbppl-button-2, 26.08. СЕМЬИ .gba-btn БОЛЬШЕ НЕТ: сабмит носит
   организм из componentsutton.css, и auth.css перестал быть
   владельцем кнопки — он остался владельцем ПОЛЕЙ.

     .gba-btn         -> .gb-btn --large --filled --primary --block
     .gba-btn-label   -> .gb-btn__label
     .gba-btn-icon    -> .gb-btn__icon
     .gba-btn--inline -> .gb-btn --large, то есть ровно дефолт
                         организма. Модификатор удалён: у него не
                         осталось ни одного потребителя (полка хаба
                         давно живёт на .gbs-door-link).

   ПОЧЕМУ СОВПАЛО ДО ПИКСЕЛЯ. Лестница L организма СНЯТА с этого
   самого сабмита 18.08: 48/56/64, пад 8/24 -> 8/32 с 1280, gap
   20 -> 24, внешний тип 14/600 -> 16, лейбл 14 / 15 с 640 / 16 с
   2000 при ls 1px, глиф 16/20/24, ховер Blue 700, disabled
   opacity .6. А его особая анатомия — ширина во всю строку,
   стрелка у правого края паддинга, лейбл с собственными полями
   pad-x, чтобы центрированный текст не налез на стрелку — стала
   модификатором .gb-btn--block, и там она объявлена один раз для
   всех размеров. Прибор до и после на 1280/1920/2258: расхождений
   ноль.

   ЧТО ОСТАЛОСЬ ЗДЕСЬ. Один отступ. Он никогда не принадлежал
   кнопке: это расстояние ОТ ПОЛЯ до сабмита, и назначает его
   форма, а не кнопка. Имя ему нужно своё, потому что кнопка
   теперь общая, а отступ местный. */
.gba-submit { margin-top: 16px; }


/* ---------------- ШАГ ВЕРИФИКАЦИИ ----------------
   Состояние за сабмитом e-mail (live 18.08, снято на 1280; лестницы
   остальных ширин — из живых классов, в замерах public-login их
   нет: state за интеракцией). */

.gba-vheader { text-align: center; }

/* Конверт в кольце: w 58/64/72, h 52/64/72, бордер preflight
   #e5e5e5 (живое умолчание border, вне цинка — факт каталога),
   глиф 32/36/48, mt 8. */
.gba-vicon-row { display: flex; align-items: center; justify-content: center; }
.gba-vicon {
  margin-top: 8px;
  width: 58px;
  height: 52px;
  display: flex;
  align-items: center;
  justify-content: center;
  border: 1px solid var(--preflight-border);
  border-radius: var(--radius-pill);
  color: var(--zinc-900);
}
.gba-vicon svg { width: 32px; height: 32px; }
@media (min-width: 1280px) {
  .gba-vicon { width: 64px; height: 64px; }
  .gba-vicon svg { width: 36px; height: 36px; }
}
@media (min-width: 2000px) {
  .gba-vicon { width: 72px; height: 72px; }
  .gba-vicon svg { width: 48px; height: 48px; }
}

/* Serif-титул шага: Noto Serif 500, 22/28/32, tight, tracking-tight
   (единственный serif на маршруте авторизации; замер 1280:
   28 / lh 35 / ls -0.7). */
.gba-vh1 {
  margin: 12px 0 0;
  font-family: var(--font-serif);
  font-size: 22px;
  font-weight: 500;
  line-height: 1.25;
  letter-spacing: -0.025em;
  color: var(--zinc-900);
}
.gba-vsub {
  margin: 12px 0 0;
  font-size: 13px;
  line-height: 1.625;
  letter-spacing: 0.2px;
  color: var(--zinc-500);
}
.gba-vsub p { margin: 0; }
.gba-vsub p + p { margin-top: 12px; }
.gba-vsub strong { font-weight: 600; color: var(--zinc-900); }
@media (min-width: 1280px) {
  .gba-vh1 { font-size: 28px; }
  .gba-vsub { font-size: 14px; }
}
@media (min-width: 2000px) {
  .gba-vh1 { font-size: 32px; }
  .gba-vsub { font-size: 16px; }
}

/* Radio-карточки метода: grid 2 колонки gap 12 (живой mb-5
   ИНЕРТЕН, замер 18.08: mb 0, интервалы держит space-y); карточка
   p 12 gap 10, бордер 1.5, radius 5, белая; актив = бордер zinc-900
   + тень живой карточки варианта продукта 0 0 6px 3px rgba(0,0,0,.15);
   идл = zinc-300, hover zinc-500. Радио 16 c точкой 8. Текстовый
   столбец несёт ls 1.5px (живой tracking-[1.5px]). */
.gba-methods {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 12px;
}
.gba-method {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  padding: 12px;
  text-align: left;
  background: var(--white);
  border: 1.5px solid var(--zinc-300);
  border-radius: var(--radius);
  transition: border-color 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.gba-method:hover { border-color: var(--zinc-500); }
.gba-method[aria-pressed="true"] {
  border-color: var(--zinc-900);
  box-shadow: 0 0 6px 3px rgba(0, 0, 0, 0.15);
}
.gba-method-radio {
  margin-top: 2px;
  width: 16px;
  height: 16px;
  flex-shrink: 0;
  display: grid;
  place-items: center;
  border: 1.5px solid var(--zinc-300);
  border-radius: var(--radius-pill);
  transition: border-color 0.2s;
}
.gba-method[aria-pressed="true"] .gba-method-radio { border-color: var(--zinc-900); }
.gba-method-radio span {
  display: none;
  width: 8px;
  height: 8px;
  border-radius: var(--radius-pill);
  background: var(--zinc-900);
}
.gba-method[aria-pressed="true"] .gba-method-radio span { display: block; }
.gba-method-copy { display: flex; flex-direction: column; letter-spacing: 1.5px; }
.gba-method-title { font-size: 16px; font-weight: 600; line-height: 1.25; color: var(--zinc-900); }
.gba-method-sub { margin-top: 8px; font-size: 14px; color: var(--zinc-500); }

/* Стек шага (space-y-8): 32 между зоной, Continue и ссылками —
   живые mt-4 кнопки и ссылок ПЕРЕКРЫТЫ space-y (замер 18.08:
   hint→Continue 32, Continue→links 32). Живой min-h-[140/160]
   зоны на поток не влияет (контент группы выше порога) — demo
   его не носит, чтобы не раздувать зону при коротком контенте. */
.gba-vstack > * + * { margin-top: 32px; }

/* Лейбл OTP: 12 constant, caps 600, ls .06em, zinc-500; та же
   звёздочка, и с 10.09 она тоже без своего цвета — см. блок
   «ЗВЁЗДОЧКА ГОВОРИТ ГОЛОСОМ ЛЕЙБЛА» выше. */
.gba-vlabel {
  display: block;
  font-size: 12px;
  font-weight: 600;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--zinc-500);
}
.gba-vlabel::after { content: '*'; padding-left: 5px; }

/* OTP: 6 ячеек grid gap 10; ячейка = underline-семья 48/56/64 по
   центру, Inter 500 14/16/18, фокус ведёт бордер в blue-600. */
.gba-otp { display: grid; grid-template-columns: repeat(6, 1fr); gap: 10px; width: 100%; }
.gba-otp input {
  width: 100%;
  min-height: var(--form-ctl-h);
  margin: 0;
  padding: 0;
  text-align: center;
  background: transparent;
  border-color: var(--zinc-400);
  border-bottom-width: 1px;
  border-radius: 0;
  font-family: var(--font-sans);
  font-size: var(--form-ctl-fs, 14px);
  font-weight: 500;
  letter-spacing: 0.2px;
  color: var(--zinc-900);
  outline: none;
  transition: border-color 0.2s cubic-bezier(0.4, 0, 0.2, 1);
}
.gba-otp input:focus { border-bottom-color: var(--blue-600); }
@media (min-width: 1280px) {
  .gba-otp input { min-height: var(--form-ctl-h-xl); font-size: var(--form-ctl-fs-xl, 16px); }
}
@media (min-width: 2000px) {
  .gba-otp input { min-height: var(--form-ctl-h-2xl); font-size: var(--form-ctl-fs-2xl, 18px); }
}

/* Подсказки: центр, zinc-400; OTP 12/14(lg)/16(xl), пароль
   12/14(xl)/16(2xl); mt 8. */
.gba-hint {
  margin: 8px 0 0;
  font-size: 12px;
  line-height: 1.375;
  letter-spacing: 0.2px;
  text-align: center;
  color: var(--zinc-400);
}
@media (min-width: 1024px) { .gba-hint--otp { font-size: 14px; } }
@media (min-width: 1280px) { .gba-hint--otp { font-size: 16px; } .gba-hint--pass { font-size: 14px; } }
@media (min-width: 2000px) { .gba-hint--pass { font-size: 16px; } }

/* Ссылки под Continue: центр, 14; линки blue-600 px 8 py 4,
   hover подчёркивание; заблокированный Resend = zinc-400; точка-
   разделитель zinc-400. */
.gba-vlinks {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  font-size: 14px;
}
/* Селектор (0,1,2): body.gb-demo a из shell.css той же силы,
   auth.css позже в каскаде — синий побеждает. */
gb-auth-flow .gba-vlinks a {
  padding: 4px 8px;
  color: var(--blue-600);
  letter-spacing: 0.2px;
}
.gba-vlinks a:hover { text-decoration: underline; }
gb-auth-flow .gba-vlinks a[aria-disabled="true"] {
  color: var(--zinc-400);
  pointer-events: none;
  text-decoration: none;
}
.gba-vlinks .gba-vdot { color: var(--zinc-400); font-size: 14px; }
