Організм · рівень 3

Діалог входу

Одні двері для всіх ролей: телефон, потім код, без пароля й без окремого входу для тренера. Найбільший з панелей шару - 171 рядок, 47 селекторів, 263 оголошення, - і його широка розкладка описана двічі: структурний блок каже 880 / 42% / 34 / 40, колірний каже 920 / 44% / 42 / 38. Вирішувач це підтверджує: 33 оголошення зі @media (min-width: 720px) структури не виграють жодного разу.

рівень 3design/system/components/auth-dialog.css248 рядків91 селектор278 оголошень14 екранів, діалог на 5
З чого складається

Діалог складає сім чужих файлів: поле, кнопку, код, скелет, форму чекауту, рядок посилань і чекбокс. Свого в ньому - оболонка, дві колонки й межа між ними.

ФайлКласівЯкі саме
field.css8.cc .cool .field .field--mono .field-grp .fld .ph-field .resend
button.css5.btn--full .btn--icon .btn--l .btn--lift .btn--s
otp.css4.box .otp .otp-err .otp-note
skeleton.css2.auth-skel .sl
checkout-form.css2.smeths .uiv-apple
link-row.css1.linkrow
checkbox.css1.cb

10 класів усередині кореня мають більш ніж одного власника, тож із коду не видно, чий вони: .btn--accent .btn--ghost .btn--outline .err .ic .m .on .opt .uiv-brand .uiv-trail

Анатомія

Розмітка тут - не переписана від руки. Її знято з design/auth.html у цій же сесії, обробники зняті, посилання підняті на рівень. Цей організм у спокої не існує - він display: none, доки щось не додасть open, - тож стенд додає цей клас сам. Показано на сцені: трансформований предок стає для position: fixed тим блоком, від якого рахується його inset, тож панель не накриває сторінку й не втрачає жодного свого оголошення.

Показано в рамці шириною 390, і ширина названа не для краси: це ширина, на якій цей організм у продукті стоїть. Медіа-умова читає в'юпорт, а не контейнер, тож жодне правило самого стенда цього не вирішує - тільки справжній в'юпорт, а він є лише в рамки. Сам організм у рамці обмежено до 1064px - це ширина, яку він займає в продукті на 1280. Витягнутий зі своєї колонки, він розтягнувся б на всю рамку, і кнопка на 294 стала б кнопкою на 1490.

1Оверлей .auth-ov - position:fixed, inset:0, z-index:60, фон --scrim-overlay. 5 екземплярів на 5 екранах (auth.html, auth-code, auth-error, auth-loading, auth-newuser). На решті 9 з 14 екранів оверлея немає в розмітці взагалі: там лише .bt і .lt - імена, які цей файл ділить з іншими
2Модалка .auth-modal - від 720 дві колонки. Ширина сказана двічі: max-width:880px у структурі й max-width:920px у кольорі. Змінна рядка теж: --auth-row це 34px у структурі й 42px у кольорі
3Візуал .auth-visual - до 720 display:none. Вище: 42% у структурі, 44% у кольорі; штрихування змінюється на фотографію мaскота з градієнтною вуаллю (--veil-page ... --veil-inverse)
4Логотип двічі .auth-mlogo і .vlogo - до 719 знак стоїть у верхньому рядку форми, від 720 він ховається і його роль бере логотип візуалу. Два елементи, одна робота, розділені межею
5Форма .auth-form .auth-h1 .auth-cta .auth-or .auth-alt - бічні поля 40 у структурі й 38 у кольорі, записані сирим числом: 38 немає на шкалі відступів. Хрестик .auth-x це --fs-20, і коментар у файлі пам'ятає, що крок 6.7 знайшов його на 16, коли решта закриттів була на 20
6Чекання .auth-load .auth-spin .lp .auth-note - по одному екземпляру, і всі на auth-loading.html. .auth-alt так само один, на auth-error.html: у кольорі кожен стан діалогу має свій окремий екран, а не одну сторінку з перемикачем

Одна межа, два правописи

У файлі сім блоків на межі 720: п'ять написано (min-width: 720px) з пробілом (структура) і два (min-width:720px) без нього (колір). Перепис групує медіа-умови за рядком, тому бачить чотири різні умови там, де межі три.

Числа стенда всередині продукту. Крок 7.26 вийняв звідси @media(min-width:900px){ .auth-ov{ left:216px } } і @media(max-width:899px){ .auth-ov{ top:40px } }: 216 це ширина панелі стенда, 40 висота його смуги, 899/900 його власна межа. Коли стенд переїхав на 1076, а файл лишився на 899, між 900 і 1075 діалог від'їжджав на 216 праворуч від панелі, якої там уже не було. Тепер це --shell-left і --shell-top, нулі поза стендом - і саме тому inset:0 зі структури програє свої top і left.
Ще два обличчя, і без них п'ять класів файлу не існує ніде

Діалог має шість станів, і рамка вище показує лише перший, phone. Решта п'яти класів живуть у двох інших: .auth-load, .auth-spin, .lp і .auth-note - у стані loading, .auth-alt - у стані error. Це не варіанти оформлення: у спокої першої рамки їх немає взагалі, бо панель перебудовується цілком.

Стан не підроблено. Обидві рамки викликають wfAuthGo('loading') і wfAuthGo('error') - ту саму функцію, яку натискає «Отримати код» у продукті, - і панель збирає wfAuthPanel(). Стенд не пише розмітки: він натискає.

.auth-load - блок з aria-live="polite", тож очікування чують, а не тільки бачать. .auth-spin - кільце, .lp - рядок «На номер», .auth-note - замок під дією
.auth-alt - «Надіслати новий код» під акцентною «Спробувати ще раз»: дві дії різної ваги, і саме це різниця, заради якої клас існує. Контурний фініш тут з button.css, а не свій

Три рамки на одній сторінці стали можливі тільки цим кроком

До 8.34 підгонка рамки брала querySelector('.kp-frame'), однину, і друга рамка лишилась би не підігнаною. Тепер це design/kit/_frame.js, один файл на 24 сторінки, з querySelectorAll.
Стани
СтанЩо робитьЧому так
спокій.auth-ov - display:noneна кольорових екранах не трапляється жодного разу: там, де оверлей є, він уже відкритий, а на решті екранів його немає в розмітці
відкрито.auth-ov.open - display:flexвирішувач: display:none збіглося з 10 елементами й жодного разу не виграло - на всіх заміряних екранах діалог розкритий
помилка[data-state="error"] фарбує .vi і .bi в --line-danger / --text-dangerстан живе на оверлеї, а фарбує двох дітей у різних колонках
новий[data-state="newuser"] - те саме в --line-successєдина пара станів у файлі, і обидва написані атрибутом, а не класом
чекання.auth-spin обертається через uivspin; @media (prefers-reduced-motion:reduce) ставить animation:noneне заміряно: драйвер цієї сесії читає будь-яку анімацію як зупинену, тож твердити тут нема чого
фокуспастка кроку 7.85 веде фокус на .auth-ovа role="dialog" і aria-modal лежать на .auth-modal рівнем нижче: фокус приходить на елемент без ролі
Межі

У файлі 4 медіа-умови, і кожна з них - межа, якої стандартні ширини перепису (360 / 390 / 720 / 1280) не бачать зсередини смуги. Заміряти їх треба власними ширинами, по одній з кожного боку.

Холостий контроль

Сторінка звіряє себе з файлом: 22 власні класи і 0 станів.

Було 21. .smeths прийшов із checkout-form.css на 8.36 - стос кнопок соцвходу під «або». Правило лежало у файлі чекауту, хоч пише його wfAuthPanel() і трапляється воно лише тут; у розмітці репозиторію цього класу немає взагалі, тому воно й сиділо не там непоміченим.

ПОВЕДІНКА НА ШИРИНІ - етап 10, крок 4

Від якого порогу: --bp-shell-wide, парою 860/859, і це вісім блоків про одну поведінку: діалог перестає бути телефонним шитом і стає двопанельним модалом. Було 720/719, поза реєстром. 860, а не 620, і причина - замір: на 620 модал обмежений вікном, тож панелі виходять 243.8 і 310.3, і колонка ФОРМИ стає вужчою за однопанельну форму, яку вона замінила (618). На 860 вони 349.4 і 444.6. Формі краще широко, тож друга панель чекає точки оболонки.
Рух

Робота: СТАТУС. Рухається: обертун очікування коду. Тривалість цикл .9s, поза реєстром, крива linear. Значення читаються через var(): підміна токена в браузері веде за собою кожне з них. При prefers-reduced-motion рух зникає, а стан лишається.

Діалог сам поки не з'являється рухом: він відкривається перемиканням display, а це не анімується звичайним переходом. Рішення про появу поверхонь - крок 4.

Крок 4. Поверхня з'являлась перемиканням display, а це дискретна властивість - інтерполювати нема чого, тому діалог просто виникав. transition-behavior: allow-discrete плюс @starting-style дають йому кадр, з якого починати. Затемнення і панель це два рухи, а не один: темрява каже «те, що позаду, поставлено на паузу», панель піднімається на --move-md і каже «а ось що прийшло». Обертун очікування перейшов на --dur-cycle / --ease-cycle, а @keyframes uivspin поїхав у base.css: він був оголошений тут і читався з checkout-form.css.

Токени

Прочитані з auth-dialog.css: 24 семантичні ролі і 38 примітиви.

Семантичні ролі (24)Примітиви (38)
--bg-hatch --bg-page --bg-rule --bg-sunken --bg-surface --elevation-4 --elevation-mark --fade-inverse --fade-page --line-action --line-danger --line-hair --line-onphoto --line-success --scrim-overlay --text-action --text-body --text-danger --text-muted --text-primary --text-secondary --text-success --veil-inverse --veil-page--container-text --dur-cycle --dur-slow --ease-cycle --ease-enter --ease-exit --font-display --font-mono --fs-12 --fs-14 --fs-16 --fs-18 --fs-20 --fs-24 --fs-30 --fs-34 --fw-black --fw-bold --fw-semibold --lh-airy --lh-flat --ls-display --ls-eyebrow --ls-lead --move-md --radius-12 --radius-16 --radius-8 --radius-circle --size-40 --size-46 --space-12 --space-16 --space-24 --space-32 --space-4 --space-40 --space-8
Що знайшов вирішувач

З 47 селекторів вирішувач знайшов 39 оголошень, які збігаються з елементами й ніде не виграють, і 33 з них - один і той самий випадок: @media (min-width: 720px) структурного блоку, який колірний блок переказує заново і б'є. Це і є розділ етапу 08, де колір іде другим навмисне, - але тут він не додає фарбу, а переписує геометрію: ширину модалки, ширину візуалу, всі чотири відступи форми й змінну --auth-row. Ще два - top і left від inset:0, які забирають зміщення оболонки. Одне - display:none проти .open. Одне - верхня межа спінера, яку колір фарбує в --line-action, і це задумано.

Два оголошення без відповіді

animation-delay і animation-play-state з @media (prefers-reduced-motion:reduce) позначені як такі, що не виграють, а переможцем названо * без імені файлу. Хто це - [?]. Питання, а не відповідь: заміряти анімацію цим драйвером не вийде, тож розв'язати це можна тільки читанням каскаду, і це робота етапу 09.
Немає в коді -> етап 09

Чого бракує

  • Дві редакції широкої розкладки - 880/920, 42%/44%, 34/42, 40/38. Треба одна, сказана вголос як «змінна -> значення -> чому»
  • 38 сирим числом у колірному блоці там, де структура читала --space-40
  • Роль на оверлеї чи на модалці - role="dialog" зараз на .auth-modal, а фокус пастка веде на .auth-ov. Рішення про семантику, не про поведінку
  • Межу 720 не заміряно власними ширинами - потрібні 719 і 720, по одній з кожного боку

Не домальовано наперед і не замовчано: етап 09 стартує з цього списку, зведеного в design/kit/docs/architecture.md.