Перевірка

Що лишилось

Крок 6 етапу 08 зводить систему з продуктом і питає три питання: чого система не має, що продукт малює сам замість неї, і що вона носить даремно. Тут відповіді - з числом за кожним рядком і з приладом, який це число повторить: node tools/census.mjs і node tools/scope.mjs.

229 екранів390 і 1280460 завантажень63 154 спостереженняджерело: docs/backlog.md
Спершу довелось зібрати прилад, і це знахідка нуль

Крок 1 дав census.md - 22 229 спостережень на 180 екранах - і закінчується власним реченням: «the script is the artifact, not the table». Скрипт не зберегли. Лишився btn-census.json, тобто результат. Отже вимога паку «два заміри одним приладом» була нездійсненною, доки приладу немає, а зібрати його з пам'яті - це рівно та ручна правка, яку репозиторій забороняє для інструментів так само гучно, як для сторінок.

tools/census.mjs зібраний з методу, як його описує census.md: дві ширини (390 і 1280, бо десктопної шапки й мегаменю на 390 не існує), у браузері й ніколи грепом (шапку вставляє _nav.js, у розмітці її немає), обчислений стиль замість написаного правила, і тест на контрол дослівно - a / button / label / [role=button] / [onclick], або елемент, який вводить cursor:pointer, якого немає в батька.

Чого не відтворено, і це сказано, а не підігнано

census.md згортає коробчасті контроли у 24 форми на чотирьох осях і виключає чіпи, таби, мініатюри, пагінацію та поля зі сім'ї дії - за списком класів, який жив у втраченому скрипті й ніде в прозі не записаний. Підганяти числа, доки вони не зійдуться з опублікованою таблицею, довело б лише те, що їх можна підігнати.
Корпус, і число, яке міняє ціну будь-якого попереднього перепису
статичний обхідз розгортанням панелей
завантажень (екран x ширина)460460
відкрито панелей перед читанням–11 946
спостережень клікабельного35 71463 154
коробчастих контролів7 11814 896

43% клікабельної поверхні продукту лежить за станом, і обхід, який читає лише намальоване, не бачить жодного відсотка з них. Це стосується й 22 229 кроку 1: той замір знято статично, і саме тому два заміри не зводяться арифметично.

Список 1 - продукт до системи

Системі не бракує нічого. Кожен контрол сірого шару або має компонент, або живе на екрані, якого ніхто не фарбував.

Два кандидати повернулись, і обидва стояли на wireframes/overview.html - хабі, який перелічує екрани, а не є одним з них: flowlink і sm-item. Хаб виключено тією самою межею, що вже проведена через kit/ і concept/; CLAUDE.md проводить її поіменно.

22 контроли - це тираж, а не діра

Кожне входження сидить на одному з 54 ще-сірих екранів: addr-save (4 екрани) · bsearch (3) · uachip · bcard · chub-goal · chub-cat · thumb · ttl · read · cert · moz · cta · rev-google · q-exit · sc-goal · sc-chip · clr · ov-row · ov-cb · ov-prod · ov-chip · ov-all.
Вони закриються, коли їхні екрани отримають колір - роадмеп уже ставить це після етапу 09.
Скоупа не було на 23 екранах, і це міняє зміст списку 2

Крок 7.95 переніс вісім приватних стилів потоку тренера в design/system/components/ і заскоупив кожен селектор: .coach .qa-row, .coach .cnew - 360 входжень у 18 файлах. Клас скоупа поставили руками на одинадцять екранів того кроку, на <body>.

Більше його не ставив ніхто. clone-to-colour.mjs бере екран із wireframes/, а в сірому шарі класу на body немає взагалі - 142 файли, 142 голі теги. Тож кожен екран стану, пофарбований на 8.13 і 8.14, приїхав без нього, і на цих екранах увесь тренерський шар системи інертний: не перебитий, не програний за вагою селектора, а просто такий, що жодного разу не збігся.

tools/scope.mjs ставить питання браузеру як різницю, а не як список імен: додай клас, прочитай обчислений стиль кожного елемента, забери клас, прочитай знову. Зрушили 23 екрани.

кольорових екранів без скоупа, який носить їхня база23
з них рухають 40 і більше елементів9
найгучніший - coach-session-priceblock87 з 1 434 елементів, 56 селекторів на 87

Чий це скоуп - написано в самому екрані, а не вгадано

Кожен стан закінчує свій скрипт викликом wfBar('<база>.html', '<стан>'), а кожна база називає саму себе - отже стан носить рівно те, що носить його база. Альтернатива напрошувалась і була хибною: зв'язка зі wfHeader('coach') / wfCoachNav( ловить 36 екранів і промахується на трьох, які клас уже носять - cart-coach, coach-landing, coach-verify це екрани тренера без тренерської рейки.

Ще п'ять екранів зрушать, і фарбувати їх не можна

Саме вони й доводять, що скоуп несе навантаження, а не прикрашає: concept/directions (203 елементи від 2 селекторів), account-orders (67 від 2), kit/order-row, kit/badge, checkout-loggedin. Там .coach .x зіткнеться з x, який означає інше - тобто рівно з тим, задля чого простір імен і заводять. Перевірка показує їх окремим списком і ніколи не пише в них.
Чотири екрани носять скоуп і нічого ним не ловлять (17.08.2026, було один): cart-coach, cart-coach-empty, coach-home-error, coach-home-loading - і це рішення працює, а не дрейфує: приватні правила, які користувались неймспейсом, переїхали у свої компоненти, а правилу всередині coach-cabinet.css вже не треба, щоб екран казав .coach. Список РОСТЕ в міру завершення роботи, тому він у звіті й не валить гейт. Вирішено 2026-08-15: лишаємо, і перевірка перестала звати це дефектом (пункт 6 нижче): правило, яке ним користувалось, переїхало на справжнього сторожа ще на 7.96, а неймспейс, що сьогодні нічого не ловить, коштує один токен класу - тоді як неймспейс, якого бракує на одному екрані, коштує цілого класу тихих багів. Питає перевірка тепер протилежне: екран, що носить скоуп, якого не носить його база.
Список 2 - система до продукту, і це вся робота, що лишилась
на кроці 62026-08-17
екранів із приватним ПРАВИЛОМ312
приватних правил усього1 1540
з них перемальовують клас, який система вже має8860
з них оголошують те, чого немає більше ніде2100

Нуль. Останні два були одним відкладеним рішенням, а не двома роботами - .cv-card{ max-width: 560px } на coach-verify-error і coach-verify-deadend, - і 17.08.2026 його взяли, а не відклали вдруге: замір, якого відкладенню бракувало, виявився тим, що його вирішує. Див. пункт 2. Права колонка це перезамір тим самим приладом, а не 1 154 мінус те, що пішло.

«Перебивають» міряли як «такий клас у системи теж є», а на екранах станів тренера це було не одне й те саме - до 2026-08-14 система туди не дотягувалась зовсім, тож приватний блок був не шаром зверху, а єдиною фарбою на сторінці. Числа лишились; слово - ні, і правдивим його робить прохід вище.

Дванадцять найгучніших екранів - усі в потоці тренера, тобто в первинній аудиторії:

екранприватних правил, що перебивають систему
coach-session-addclient74
coach-session-addempty74
coach-session-priceblock67
coach-session-oos65
coach-session-loading64
coach-session-newclient52
coach-home-empty44
coach-home-free39
coach-tariff-cancel34
coach-order-error · coach-order-loadingпо 33
coach-clients-cap30

Це не косметичний борг, і один заміряний дефект це довів - але не з тієї причини, яка тут стояла

coach-session.css відповідає телефону через @media (max-width: 479px): .qa-row складається у два рядки, і дія бере весь другий. Базовий екран це правило читає і на 360 проходить. Чотири екрани станів - ні: «Додати клієнту» звисало на 10px за край, а html{ overflow-x: hidden } ці 10px обрізає, а не прокручує, тож правий край кнопки був недосяжний. node tools/accept.mjs 360 давав 4 провали на 204 екранах.
Причина, записана тут, була хибна, і хибну лишено навмисне. Тут стояло «приватний блок виграє в підключеного стилю». Не виграє: .qa-row це один клас, .coach .qa-row це два, тож система вже важила більше. Правило не збігалось узагалі, бо сторінка ніколи не була всередині .coach. На вагу селектора списали те, що зробив відсутній скоуп - і речення звучало досить правдоподібно, щоб браузера ніхто не спитав.
Виправлено 2026-08-14 через tools/scope.mjs --apply: accept.mjs 360 дає 0 на 205 екранах. Приватні копії .qa-row лишились на місці й тепер програють системі в кожному оголошенні - тобто переїхали з «перебивають» у інертний набір нижче.

І саме тому етап 10 не може початись поверх цього. У продукті 222 медіа-блоки: 170 у системі і 52 у приватних блоках цих 31 екрана, які додають 7 власних меж поверх системних. Шкала не зводить того, що не лежить у системі.

Список 3 - клас, якого ніхто не носить

Мертвих не лишилось. Шість видалив власник 2026-08-14; сьомий був помилкою приладу.

Ще дві купи названі, а не пораховані як дефект: 30 класів за станом, якого обхід не досягає - кожен пише скрипт, отже вони живі; обхід кличе всі open* / toggle*, але не вміє скролити (stuck, pdp-stuck, uiv-scrolled) і не проходить потік далі першого кроку (auth-load, auth-spin). І 43 чекають на свій екран - носить сірий шар, кольорового двійника ще немає; здебільшого system-page.css (16), cookie-banner.css (15) і account-shell.css (10).

Прилад помилився чотири рази, і всі чотири помилки однієї форми

Кожна відповідала на питання поруч із поставленим, і кожна давала правдоподібне число.
повідомивсправжня причина
962 мертвих класи, серед них coach і wfhмапа будувалась із рядків контролів, тож «не носить ніхто» означало «не носить нічого клікабельного»
svg jpg png html - мертві класи компонентівце хвости url(../../visuals/…jpg) і a[href="index.html"]
12 класів cat-overlay.css мертвіоверлей ніхто не відкрив - census.md уже знімав цю саму знахідку про .tbuy
menu-pop мертвийdesign/system/menu.js:39 ставить його під час зв'язування, а CSS ховає до відкриття; збирач пропускав display:none
Четверта коштувала 35-хвилинного обходу двічі: виправлення оголосили до перевірки, латка не застосувалась, і повтор дав байт-у-байт той самий запис - 1518 різних класів, 50 417 сумарно, в обох файлах. Саме ця однаковість його й викрила.
Видалено 2026-08-14, і чого кожне видалення коштувало

Два були сміттям, одне безкоштовним, три забрали спроєктований стан. Міркування трьох збережені дослівно в docs/backlog.md, тож повернути будь-яке коштує рядок CSS і вставку.

класрідчого система більше не вміє сказати
.only-mobile .only-deskсміття, 6 правилнічого. Закрило питання, яке account-shell.html тримав відкритим із кроку 5
.field--errдубль іменінічого. Жодне оголошення не змінилось: рантайм пише .err, і стан спрацьовує як раніше
.certthumb--pendingстан«сертифікат заявлений, але файлу ще немає»
.qans--waitстан«магазин готує відповідь»
.tsx--unprovenстанрізницю між доведеним і недоведеним знаком довіри - а «спершу довіра» це принцип 1
Жодна плитка смуги довіри не зрушила: 290 x 66.38 плитка, 38 x 38 коробка іконки, 308 x 283.5 смуга на 390 - до сотої ті самі числа, що були заміряні, коли виняток додавали
Міграцію спробували, наклали й відкотили - і це запис

262 з 1185 приватних правил верхнього рівня міряються як інертні: 215 не ловлять на своїй сторінці жодного елемента (залишок клону - clone-to-colour.mjs копіює блок повного екрана в його порожній і завантажувальний стани цілком), 47 ловлять і не рухають жодного значення. Сам лише coach-order-loading це 37 із 42.

Розріз наклали, і доказ його спіймав

tools/tree-diff.mjs - git archive еталона в окреме дерево, два сервери, один Chrome, порівняння обчисленого стилю кожного елемента по 40 властивостях на 390 і 1280 - знайшов 9 зрушень на 5 екранах: coach-clients-cap, -empty, -error, -loading і coach-home-loading. На 390 рядок рейки став помаранчевим (rgb(242,240,237) -> rgb(255,90,0)), на 1280 сторінка виросла на 555px. Усе відкочено, повторна звірка дає нуль.

Причина - метод, а не баг. Прилад міряв кожне правило поодинці, з усіма сусідами на місці, тобто відповідав на питання «чи зайве це правило за наявності всіх інших». Інертність не додається. На coach-clients-cap приватний блок тримав і .acc-nav, і .acc-link[aria-current="page"]: кожне окремо не міняло нічого, а зникнення обох перетворило рейку на мобільну стрічку чіпів, де поточний чіп account-shell.css фарбує через --bg-action під @media (max-width: 959px).

Два виправлення пішли в прилад і обидва правильні: обхід тепер накопичувальний і проти повного знімка документа (правило перефарбовує лише те, що ловить, але розкладка мандрує - батько росте слідом за дитиною і в селекторі його немає), а набір, знайдений на одній ширині, пропонується назад на іншій, бо їхнього об'єднання не бачив жоден браузер: на 390 прохід може зняти {A,B}, на 1280 {A,C}, і {A,B,C} не перевіряв ніхто.

Розриву вони не закрили. Прилад далі очищає правила, яких свіжа сторінка не очищає. Різниця, найімовірніше, між мутацією завантаженого документа і завантаженням без цих правил - скрипти сторінки вже відпрацювали й відреагували на те, що бачили. Це гіпотеза, а не вимір, і записана вона саме так.

Тож видалення чекає на прилад, якому можна вірити, а доказ лишається воротами. Вимір не змарновано: 262 знайдені, два роди розділені, і tree-diff назве будь-яку сторінку, яку зрушить майбутній розріз - із ширинею, елементом і властивістю.

Що крок 6 ще винен
  1. 36 контролів носили btn без рангу й малювались голим текстом. Закрито 2026-08-14. У button.css немає правила .btn - оздоблення і є ранг - а clone-to-colour.mjs ловив class="btn" і class="btn dark" цілими рядками, тож кожна кнопка з утилітним класом поруч проходила повз: btn qa-add (14), btn cs-save (7), btn dark cs-go (6), btn dark co-new (3), btn dark cgo-btn (2) і ще чотири, на 13 екранах. Та сама сім'я, що й lookahead 8.13: візерунок, досить тісний, щоб мати рацію про випадок перед собою, і хибний про набір.
    Ранг узято з бази кожного екрана, а не обрано руками, і це виявилось суттєвим: сірий шар позначає cs-go, co-new і cgo-btn як dark - своє слово для головної дії, - а кольорові бази свідомо зробили всі три btn--outline на 7.95 і 8.7, бо на екрані одна акцентна заливка, і це не вони. Ранг «за dark» додав би в потік тренера три нові помаранчеві заливки й назвав це виправленням. 34 з 36 відповіла база; двох, на яких продукт відповіді не має, вирішено в tools/btn-rank.mjs із сусідом, виписаним поруч: cart-coach-empty .cont бере btn--outline btn--s з покупцевого cart-empty, а .blocked у смузі coach-session-priceblock - btn--accent btn--l базової смуги, бо його aria-disabled="true" система вже вміє.
  2. Перенести 886 перемальовуючих правил у їхні компоненти. Це було власне тіло роботи, що лишалась, і передумова етапу 10. ЗАКРИТО 17.08.2026: 886 -> 3 -> 2 -> 0.

    ОСТАННІ ДВА ПОТРЕБУВАЛИ РІШЕННЯ, А РІШЕННЯ ПОТРЕБУВАЛО ЗАМІРУ, ЯКОГО НІХТО НЕ БРАВ. .cv-card{ max-width: 560px; margin: 0 auto } стояло на coach-verify-error і coach-verify-deadend, байт у байт однаково, і було відкладене чесними словами «чи стане 560 шириною панелі, вирішує етап 09». Чого відкладення не сказало: третій екран несе .cv-card - coach-verify-loading - і возив іншу відповідь, 828px на 1280, з центрованим заголовком у коробці 778, поки два його сусіди центрували той самий ранг по 510.

    Селектора, який відділив би два екрани від третього, немає, тож правило не можна було перенести, не вирішивши. Вирішено, і записано поруч із правилом як «змінна -> значення -> чому»: .coach .cv-card отримує max-width: 560px; margin-inline: auto, бо (1) два з трьох оголошують саме це, однаково, а правило, яке два екрани пишуть однаково, - це правило компонента не в тому файлі; (2) система вже обмежує те, що всередині картки (.cv-lead 440, .cv-card.mid .cv-actions 340), тож ширина картки - це те, що ці два обмеження вже наполовину кажуть; (3) .mid означає «по центру», а 828 завелика, щоб у ній центрувати.

    A/B у живих сторінках на 1280 / 900 / 390, правило вставлено й прибрано: error і deadend однакові до байта на кожній ширині й у кожному числі; loading 828 -> 560 на 1280 і 900, ряд кнопок переходить у два рядки, картка на 52px вища; loading на 390 однаковий, бо обмеження там не спрацьовує. scrollWidth - clientWidth нуль скрізь, в обидва боки. Дві з трьох кнопок того ряду - демо-перемикачі прототипу, а не контроли продукту. Скасовується одним оголошенням, і вся ціна помилки - 268px на одному десктопному екрані.

    Інертну половину знято 2026-08-15: 655 із 1154 приватних правил пішли з усіх 31 екрана, і доказ каже, що не зрушило нічого. tools/tree-diff.mjs --dir порівняв обчислений стиль кожного елемента на обох ширинах із деревом, яким воно було за хвилини до розрізу: 62 порівняння, 0 зрушених елементів. Це те саме порівняння, яке відмовило червневій спробі дев'ятьма рухами на п'яти екранах.

    допісля
    приватних правил на 31 екрані1 154499
    приватних блоків @media5219
    байтів усередині <style>–67 723

    Старий зонд міряв 262 інертні, цей знайшов 655 - і різниця в методі. private-css.mjs видаляв по одному правилу із ЗАВАНТАЖЕНОГО документа, що відповідає на питання «чи зайве це правило ПРИ ВСІХ інших», а інертність не додається. inert.mjs вирішує ЗАВАНТАЖЕННЯМ сторінки без правил, пробує спершу весь блок, а на невдачі ділить його навпіл і пропонує кожен шматок поверх уже доведеного безпечного, тож кожен ухвалений набір перевірений як набір. Далі обидва читання беруться ще раз: обчислений стиль по 85 властивостях разом із ::before і ::after, і хеш PNG.

    Форма результату - це трансформ клонування, а не випадок. Стани, клоновані з кольорової бази, віддають 88-93% (coach-order-loading 38 з 41, coach-orders-loading 28 з 31), бо clone-to-colour.mjs копіює в стан увесь блок базового екрана, разом із правилами для елементів, яких у стані немає. Стани з власною анатомією не віддають майже нічого: coach-verify-tier 2 з 27, coach-home-loading 1 з 19, coach-home-error 0 з 5. 499, що лишились, і є чесним предметом цього пункту.

    Число, якого ніхто не перезнімав, було 886. Його міряли як «цей клас є і в системі», ще до того, як виправлення скоупа дало системі дістати ці екрани, і відтоді з корпусу пішло 655 правил. Меншим числом воно не переписувалось навмисно: віднімання було б арифметикою, а не заміром.

    ПЕРЕЗНЯТО 17.08.2026 ТИМ САМИМ ПРИЛАДОМ І ТИМ САМИМ ПИТАННЯМ: 3, а до кінця дня 2. private.mjs обходить корпус і розкладає кожне приватне правило за тим, скільки домів мають його класи в системі. Усі категорії порожні, крім однієї: 3 правила, один дім, coach-verify.css - і це набір .cv-card, який пункт 3 відклав на етап 09 рішенням. За цим пунктом немає нічого, чого немає вже за тим; обидві половини списку 2 зійшлись на одному відкритому рішенні.

    І одне з тих трьох не малювало ніколи, що знайшов той самий прогін: 3 -> 2. З виправленим предметом inert.mjs обходить 3 сторінки замість 30 і закінчив за 42 секунди, тож спитати було не дорого: coach-verify-loading відповів 1 з 1 знімається, увесь блок, пікселі збіглись. Його правило це .cv-card{ padding: 40px 24px }, а система пише .coach .cv-card - (0,2,0) проти (0,1,0), тож екран малює --space-32 відтоді, як 8.40 забрав анатомію. Записка над ним казала «40 це щабель, тож відступ екрана очікування це вибір, а не дрейф, і скасовувати вибір це справа етапу 09»; каскад скасував його ще напередодні, і браузера ніхто не спитав. Відкладати це правило означало відкладати ніщо. Це .qa-row зі списку 2, віддзеркалене: там приватне правило звинуватили в перемозі, якої не було, тут приватне правило зберегли як рішення, коли воно вже програвало. Обидва рази речення було правдоподібне, а замір не взятий.

    І пункт 2 закрив себе не сам - його закрив прохід пункту 3, тому число й треба було ЗНЯТИ, а не вивести. Поділ на «886 перемальовують» і «210 локальних» був прогнозом двох різних робіт, а робота виявилась одна: правило, скопійоване з компонента, і правило, вигадане на екрані, відповідались одним проходом, екран за екраном, і жодну купу не можна було закінчити без другої. Прогноз був корисний, межа всередині нього - несправжня.

    Пункт публікував ще одне число, яке перестало бути правдою: «31 екран із приватним блоком <style>». 17.08.2026 обидва обходи все ще рахували саме це і показували 30 - при трьох правилах під ними. Двадцять сім із тих тридцяти не оголошували нічого: 22 несли записку на місці, звідки пішли правила, а 5 не несли нічого, крім порожніх рядків, які ті правила займали (cart-coach-empty, coach-client-empty, coach-session-addclient, coach-session-addempty, coach-tariff-cancel). Предмет у private.mjs та inert.mjs питав «чи є елемент <style>» там, де питання було «чи є правило»; тепер це один предикат у lib.mjs, спільний, а звіт називає сторінки-записки й порожні оболонки окремо, щоб одне більше не ховалось усередині іншого. П'яти оболонкам дано записку, яку носять їхні двадцять дві сестри, з призначенням, вичитаним із системи поіменно.

    І написання однієї з цих п'яти записок знайшло, де міграція внесла в систему мертвий код

    Крок 8.31b підняв #wf-bar{ position: relative; z-index: 80 } із двох екранів coach-session-add* у design/_stand.css, з дев'ятьма рядками про те, чому смуга стенда мусить лишатись над скримом overlay.css на 55. Міркування правильне про сірий шар. На кольоровому шарі смуга має display: none з 06.08.2026 - її ховає той самий файл чотирма рядками нижче, бо роль хрому тут перебрав .uiv-side; заміряно 17.08.2026: getComputedStyle дає display: none і висоту 0 на кожному перевіреному екрані. Ще п'ять правил її фарбували, а body:has(.cart-drawer) .wf-bar{ position: relative; z-index: 80 } було до того ж дослівним повтором правила над собою. Усі шість пішли; display: none !important лишається єдиним висловлюванням файла про смугу, !important - бо розмітка пише id="wf-bar", а id старший за клас.
    Міграція, яка перевіряє ПРИЗНАЧЕННЯ і ніколи не питає, чи ПРЕДМЕТ узагалі малюється, перенесе мертвий код у систему й дасть йому дім - і всі гейти пройдуть, бо правило справжнє, значення токенами, а компонент правильний. Список ужитків --text-oninverse у tokens.css втратив .wf-bar разом із фарбою.
    tree-diff показав «зрушило елементів 39» на кожній сторінці design за це видалення, а екран не зрушив ні на піксель. Він читає обчислений стиль, а querySelectorAll('*') бачить і схований елемент. Арифметика сходиться точно: піддерево смуги це 13 елементів на coach-home, 12 на index, 11 на coach-tariff-cancel, помножити на три рядки, які прилад читає з елемента - 39, 36 і 33, рівно ті числа, що в звіті, і жодного відмінного рядка поза цим піддеревом. Межу вписано в сам прилад, бо наступний, хто видалить правило зі схованого елемента, прочитає те саме тривожне число.
  3. Вирішити 210 локальних оголошень: компонент кожному або видалення кожному. ЗАКРИТО 16.08.2026, крім трьох правил, свідомо відкладених на етап 09.

    tools/private.mjs ділить залишок за тим, скільки домів має клас у системі, і перша купа - «один дім, тож кожна різниця це або діра, або воскресіння» - проходиться правило за правилом.

    на початкузараз
    приватних правил на кольорових екранах4682
    з них мають рівно один дім1572
    екранів, що ще носять правила (з 88)312
    приватних блоків @media190
    компонентів у системі8284

    Дві з цих клітинок не пережили перезаміру, і це предмет пункту 8

    «29 екранів» і «4 медіа-блоки» обидва знімали до останніх блоків купи 1 і більше не перезнімали: порахуємо ще раз 16.08.2026 - екранів було 23 на вході в цей блок, медіа-блоків 1. Жодне з двох не було хибним заміром, і обидва були хибним опублікованим числом - рівно той клас, заради якого зроблено tools/inventory.mjs, і рівно той, до якого він поки не дістає.

    Кожне закрите досі правило було станом, що заново відкрив рішення своєї бази, і після 109 таких це вже механізм, а не спостереження: clone-to-colour.mjs читає wireframes/, тож клонований стан приїздить із відповідями сірого шару на питання, які кольорова база вже вирішила інакше. Сім екранів coach-session-* - найчистіший випадок: 31 правило, і coach-session.css та stepper.css усі чотири з них ВИДАЛИЛИ, з причиною, виписаною поруч із кожним видаленням.

    Одне з них було живим дефектом на всіх семи

    margin-bottom: 76px - це висота липкої смуги, написана як повітря і поставлена на елемент, який на сторінці не останній. Тож нижче 940 воно малювало 76px діру ПОСЕРЕДИНІ екрана, з колонкою підсумку й підвалом під нею, а смуга далі закривала те, що опинялось унизу. Заміряно: проміжок між .cs-panel і .cs-summ був 96px на станах проти 20px на базі; тепер 20px усюди.

    Найбільший запис купи виявився не правилом, а блоком. 48 приватних правил на чотирьох екранах coach-clients-* - це account-shell.css, передрукований руками; рішення ухвалене й записане ще на 7.95 і виконане лише частково. Копія дрейфнула на п'яти властивостях (.acc проміжок 20/28 проти 24/32, .acc-prof 15/14/13 проти 16/12/12, .acc-tier 11px проти 12, .acc-link 13/15 проти 8/16, і 1fr там, де система пише minmax(0, 1fr)) і скасувала весь мобільний патерн: приватне .acc-link{ width: 100% } написане без медіа-запиту й перемагає системну стрічку чіпів під 960 за порядком, тож чотири екрани кабінету показували ОДИН рядок на всю ширину там, де решта кабінету показує прокручувану стрічку. Знято; малює account-shell.css.

    Це та зміна, яку в червні зміряли, назвали регресом і відкотили

    «на 390 рядок рейки став помаранчевим» - записано вище, в історії пункту 2. Той помаранчевий і є поточний чіп, що бере --bg-action, тобто власна відповідь системи, яку coach-home і account показували весь час. Відкат був правильний для тодішніх приладів і хибний про екран.

    Три винятки з механізму, і кожен вартий окремого рядка. Одне правило - помилка системи (.qadd-res), одне - справжня діра (.cnew .cn-tx), а одне, .cv-card, - система, яка мала рацію про екран, для якого писалась, і хибила про три, до яких дістала. Це найдорожчий рід: вона поклала три екрани станів coach-verify у рядок на кожному десктопі, і приватні правила були єдиним, що тримало їх стерпними на 390.

    Одне правило було мертве так, що жоден прилад у tools/ цього не бачить

    margin-bottom: 4px поруч із margin-top: 18px схлопується, і більший виграє начисто: заміряний проміжок 18px із правилом і 18px без нього, а обчислений margin-bottom обидва рази 4px. Усі прилади тут порівнюють обчислений стиль, тож усі називають це живим. Відрізнити змогло лише читання ВІДСТАНІ між двома елементами - це тепер tools/gap.mjs.

    Картка .cnew відповіла по-різному на своїх двох екранах, і це аргумент проти суцільного замітання. coach-cabinet.css закінчив крок 7.98 запискою наступному: «Whoever confirms the deletion of the block deletes these eight with it» - після того, як прибрав ту саму картку з coach-home за те, що вона несла слова й адресу кнопки рейки. Заміряно на 390: coach-home-free казав «Нова сесія» на coach-session.html за 515px під кнопкою рейки, яка каже «Нова сесія» на coach-session.html, тож картка пішла, і акцентних заливок на екрані стало 3 замість 4. coach-home-empty каже «Зібрати першу сесію» і несе речення, яке 7.98 сам назвав роботою порожнього стану, тож картка лишилась, а шість її структурних правил переїхали в компонент. Відкрите, і воно власникове: цей екран досі наводить дві акцентні заливки на одну адресу різними словами. Принцип 2 каже «один чіткий наступний крок»; яка з двох його несе - це погляд, а не замір.

    Найбільша окрема знахідка - мапа перейменувань, виконана на базі й не донесена до станів. coach-tariff.css відкривається дев'ятьма пронумерованими пунктами - «TWELVE RULES DELETED, ONE CUT TO A SINGLE DECLARATION, ONE MARKUP OVERRIDE REMOVED, TWO RULES WRITTEN» - і в кожному справжній замір на чотирьох ширинах. coach-tariff.html її несе і має порожній <style>. Два його стани не отримали нічого: інлайн-перевизначення H1, голий .tf-lead, .tf-badge замість пігулки стану, .tfov / .tfdlg замість системного скриму й діалогу, і - пункт 9 - btn--accent на «Скасувати підписку», помаранчева заливка на дії, що припиняє платну підписку, там, де button.css на 7.61 постановив: «the destructive control is the OUTLINE carrying the danger ink». Виконання мапи відтворило її заміри до сотої пікселя на екрані, де їх ніколи не знімали: діалог «before 350 x 357.53, radius 14 -> after 342 x 428.34, radius 12» вийшов 342 x 428.344, радіус 12. <style> на coach-tariff-cancel тепер порожній.

    Та сама мапа знайшлась на другому потоці, а з нею - клас контрола, якого прилади не бачать. Три стани coach-orders досі носили голий <h1> і голий .sub там, де 7.96 перевів базу на .acc-h1 і .sub acc-sub: заголовок пішов з Inter 22/800 на Oswald 30/600, тобто на лице, яке носить кожен інший екран кабінету. А рядки замовлень на coach-home-free несли <a href="coach-order.html">Деталі</a> узагалі без класу, вбрані приватним text-decoration: underline на 12px, там, де база малює btn--outline btn--s і btn--accent btn--s. Це сім'я пункту 1, і btn-rank.mjs проходить повз: він шукає контрол, що «носить btn без рангу», бо саме таку форму робить трансформ, а контрол, який не носить НІЧОГО, у його предмет не потрапляє взагалі. Вихід трансформа отримав прилад, вхід - ні. Записано в tools/README.md поруч із самим приладом, а не полагоджено вгадуванням, які посилання є текстовими.

    ТРЕТІЙ потік знайдено з двома лицями заголовка на один ранг, після кабінету й coach-orders: база coach-verify малює заголовок Oswald 30/600 усередині .cv-body, а три його екрани станів малювали свій Inter 22/800 усередині .cv-card. Приєднано, а не видалено: .cv-card це не .cv-body, тож видалення лишило б трьох ні з чим.

    А сам прилад роздавав хибні доми

    private.mjs читав КОЖЕН клас у селекторі, тож .loy .lrung.now реєстрував .now як власність loyalty-rung.css, і приватне .cv-steps2 li.now - чеклист перевірки, який до щабля лояльності не має жодного стосунку, - поверталось як «один дім: loyalty-rung.css», а це читається як вказівка перенести його туди. Тепер усередині одного компаунда назву дає лише ПЕРШИЙ клас. Перекласифікація рухає правила в обидва боки - два файли втрачають хибний запис, чотири отримують справжні, - і саме це каже, що старе прочитання було хибним, а не просто нестрогим. Жоден із дванадцяти попередніх проходів на матчі по модифікатору не стояв; це перевірено, а не припущено.

    Третє ім'я для картки-скелета, і анатомія, на яку ніхто не відповів. coach-clients-loading малював свої скелети як .skccard - радіус 14, власний тон і радіус .skline, власні ширини 45/68/88 проти системних 50/72/90, - тоді як listing-loading і account-loading носять .skcard із skeleton.css узагалі без приватних правил. Перейменовано в розмітці, п'ять правил пішло. А причина, чому обидва тренерські екрани завантаження виростили однакове приватне padding: 15px 16px, у тому, що .skcard кладе падінг на .skb, а в цих двох .skb немає: у коробки не було нутра. Те саме число на двох екранах - це відповідь компонента, а не екрана: .skcard:not(:has(.skb)){ padding: var(--space-16) }, і два екрани, які мають .skb, зміряли 0 зрушень - це і є весь ризик такої охорони.

    Порожній стан на одному екрані написаний іменами елементів, а на другому - завеликий. empty-state.css малює свою коробку іменами .ei .et .es .eact, і п'ять кольорових екранів їх пишуть; coach-client-empty писав .ic / <h3> / <p>, тож увесь його вигляд походив із п'яти приватних правил - включно зі суцільною гранню --line-hair там, де система малює пунктирну --line-strong, а це різниця між панеллю і заглушкою. А coach-home-empty приватно стиснув повносторінковий .emptybox, щоб той уліз у .acard, - тоді як компонент уже пропонує .emptybox.mini, і account-empty бере його рівно з цієї причини. Обидва полагоджено в розмітці; десять приватних правил пішло, а <style> на coach-client-empty тепер порожній.

    У хвості купи вердикт стає правдою про ІМ'Я і хибою про об'єкт

    «Один дім» означає, що клас оголошений рівно в одному компоненті - але buy-box.css оголошує .bb .tier, бейдж гуртової ціни всередині buy-box, тоді як приватне .tier на coach-verify-tier це ціла картка тарифу. Три з останніх восьми домів були такої форми (.bb .tier, .acc-prof .av проти скелетного .sk-prof .av, .goalcta .hint проти .cs-empty .hint). Тепер private.mjs друкує селектор, який породив кожен дім, тож хибний читається як хибний з одного погляду. Та сама правка, яку двома проходами раніше отримав tree-diff: не пом'якшуй вердикт, покажи, на чому він стоїть.

    Єдине правило, притримане «на погляд», відповіло читанням

    .ctab.add на coach-session-empty: нотатка казала, що таб має нижню грань, якої база не має, і водночас іншу висоту, 44 проти 90, тож це може бути свідоме «таб, під яким нічого немає». coach-session.css оголошує обидва - .coach .ctab (три рядки, min-width: 118px, border-bottom: 0, бо таб приєднується до панелі під ним) і .coach .ctab.add (один рядок, min-width: 0, пунктир). Отже 44 проти 90 - це різниця між табом «додати» і табом клієнта, а не між двома редакціями одного таба, а нижня грань була приватним правилом, яке перемальовувало .ctab з нуля, не знаючи, що система її знімає. Погляд побачив би таб, який виглядає нормально; відповіли два правила, прочитані поруч.

    Перший компонент, народжений із приватних блоків. .upsell на coach-clients-cap і .tf-upsell на coach-tariff-free були однією панеллю під двома іменами, і друга цитувала першу у власному коментарі: «same shape and same reasoning as .upsell on coach-clients-cap.html». Два файли, що погоджуються прозою й розходяться числами, - це визначення компонента, якого ніхто не написав. upsell.css і є той компонент, із повною п'ятіркою: css, design/kit/upsell.html, рядок у реєстрі стенда, рядок в inventory.md, @import у групу рівня 3. Три значення зведено (падінг 18, тло --bg-surface, заголовок --fs-16), жодне не рухає більш ніж на 2px.

    Другий компонент, і копія назвала атом на ім'я, перш ніж передрукувати його. .tier на coach-verify-tier і .tf-col на двох екранах coach-tariff - це картка Free / Pro у двох редакціях: та сама робота, згода в прозі, розбіжність у кожному числі. І обидві власноруч набрали ОБЛИЧЧЯ .acard - грань, радіус, тло, тінь, падінг, - причому власний коментар .tier НАЗВАВ той атом у реченні над копією. Прочитані з живих сторінок на 390, вони збіглися по всіх п'яти властивостях. Це перевиведення з посиланням на джерело: кожне значення правильне, кожен токен правильний, і наступна зміна картки продукту дійде рівно до однієї з двох. plan-card.css і є той компонент; розмітка носить acard на всіх трьох екранах; п'ять оголошень зникло.

    .tier.pro і .tf-col.on лишились двома станами навмисне

    Один каже «цей ми РАДИМО» - акцентна грань, запрошення. Другий каже «на цьому ви ЗАРАЗ» - чорнильна грань, твердження про акаунт, і акцент там відхилено вголос ще на 8.7. Звести їх в один стан означало б узяти сенс одного екрана й покласти на інший.

    Чотири дефекти вийшли разом із ним, усі зміряні. Ціна на екрані вибору стояла в Inter там, де ті самі цифри на екрані тарифу йдуть у моно - .tier-price приєднано до списку price.css, і .tf-price2 теж, а це мій власний недогляд кроку 8.28: той прохід узяв ранг і повітря й не пішов за родиною. .tier-flag виявився п'ятою редакцією пілюлі badge.css і стояв на 3px вище за .tf-mini через єдине оголошення, якого копія не написала, - line-height. Галочки списку були набрані в розмітці як <span class="m">✓</span>. А .tier-cta{ display: block } тихо перетворював флекс-бокс .btn--full назад на блок. Два списки на ОДНОМУ екрані малювали те саме речення двома способами - галочка на body-чорнилі вгорі, крапка на secondary внизу - і тепер малюють одним. tree-diff пояснює всі 33 зрушені елементи на кожному екрані тарифу і 4 перейменовані рядки.

    А інвентар виявився не інвентарем

    Додавання рядка plan-card.css показало, що inventory.md не містить жодного з восьми тренерських компонентів, які зайшли на 7.95 і 8.7; що upsell.css лежить там як молекула, тоді як його власна сторінка стенда називала його рівнем 3; і що колонка «Lines» - це знімок кроку 5 (tabbar.css читається там як 25, а на диску 72). Усі три записані у сам файл, під таблицею. За другим стоїть правило: тренерська група в index.css - це група СКОУПА, а не рівня, тож будь-який файл, покладений туди, втрачає єдине місце, де його рівень було видно.

    КУПА 1 ЗАКРИТА, І РЕШТА ТЕЖ

    Лишалось два правила, обидва .cv-card{ max-width: 560px; margin: 0 auto } - на coach-verify-error і coach-verify-deadend, свідомо відкладені на етап 09. Узяті 17.08.2026, щойно зміряли третій екран, який несе той самий клас. Третє правило стояло поруч до того ж дня - .cv-card{ padding: 40px 24px } на coach-verify-loading - і відкладеним рішенням не було зовсім: воно програє .coach .cv-card за специфічністю й не малювало ніколи. Див. пункт 2 про обидва.

    Останні чотири правила купи 1 виявились чотирма різними файлами, і жодне не було збігом імен. У кожного був справжній дім, на який перепис указував не з того боку.

    .sk-prof на coach-home-loading - це не «.av з account-shell», це 15 правил, що передрукували екран завантаження покупця, який не має жодного. І скелет, який вони малювали, був обіцянкою про екран, якого вже немає.

    щоскелет обіцявекран малює
    рейка5 рядків стовпчиком, 358 × 216стрічка чіпів 48 заввишки під 960
    смуга358 × 48358 × 145.17 (.cstat)
    CTA358 × 86нічого - .cnew видалено на 7.98
    сітка2 коробки поруч, 3163 картки на всю ширину, 1265.34

    І .skpulse не стояв на жодному елементі сторінки, тоді як кожен скелет на боці покупця дихає. .sk-spin у власному коментарі казав «this was the third edition» і не поставив наступного питання; skeleton.css на нього відповідає: «one slow breath, NEVER A SPINNER». Екран-скелет, який ще й крутить, говорить двома мовами завантаження одразу.

    А тоді фотографія знайшла те, повз що пройшли всі числа

    Переписаний екран збігся з двійником за кожним заміром, і картинка була порожня: біла картка профілю і сім порожніх пігулок. У двійника - теж, і account-loading.html віддавав це на 390 весь час. Причина - одне речення: ці смуги є ВІДСОТКАМИ, а під 960 їхні контейнери розмірюються по них. .acc-prof .who - флекс-дитина без нічого, що її розтягує (0.00 × 34, тримає смугу 90%-від-0); .acc-link під 960 - це чіп, а чіп розмірюється по вмісту (сім чіпів по 34.00 з нульовою смугою всередині). Два оголошення на тримачах, інлайнові ширини - геть з обох розміток (інлайн б'є будь-яке правило компонента), і :has(.skline), щоб три задеплоєні екрани акаунта показали 0 зрушень, а не «ну візуально нічого не змінилось».

    .ac-cli - це п'яте ім'я рядкового рунґа radio.css: вибрати клієнта зі списку і є вибором опції з кількох. Рядок отримав ховер, натиск, кільце фокусу і родинне тло вибраного - жодного з чотирьох він не мав. .tf-incl li.off пішов додому поруч із галочкою, якій він протилежність, і заодно владнав знак, який 8.29 узяв неправильно (\2715, а не тире: правило про тире - про тире В ТЕКСТІ). .cs-empty був шостою приватною редакцією .emptybox, третьою в цій купі.

    Купа 2, другий блок: модалка додавання клієнта, 32 правила -> 0

    Це діалог-РЕДАКТОР із client-dialog.css під шістьма іншими іменами, і приватна копія побудувала з нуля не той із двох діалогів того файлу: власна коробка 440 на радіусі 14 проти .cemodal 460 на --radius-12, а закриття - голий <a> на 19px без ховера, без кільця фокусу і без цілі дотику, на модалці, для якої це єдиний вихід. Три речі справді нові: список, що прокручується, і пунктирний запуск пішли в компонент, а #wf-bar{ z-index: 80 } - у design/_stand.css: смуга, яка каже, ЯКИЙ це екран, має лишатись над скримом на 55, і це потрібно кожному екрану стану, що відкриває модалку.

    І ті самі 27 пікселів, які діалог тарифу зміряв на 8.7

    «Додати першого клієнта» поруч зі «Скасувати» іде 154..387 у в'юпорті 360 - і сторінку це не прокручує: скрим обрізає, тож правий край головної дії просто недосяжний, а всі гейти читають 0. Два діалоги, по одному заміру кожен - правило стало компонентовим, копія з тарифу пішла.

    Холостий контроль сторінки стенда був червоний, і його ніхто не читав

    kit/client-dialog.html друкував «5 названо словами, але не показано в демо» стільки, скільки існує, - звірено з деревом ДО того, як цей прохід її торкнувся. Вердикт малюється в браузері, а жоден гейт туди не дивився. Тепер accept.mjs його збирає - власними словами тієї коробки, а не другою реалізацією тієї ж перевірки, бо дві реалізації можуть розійтись.

    А сортування, яке пояснювало ті 19 сторінок, лестило - і його зняли читанням

    Перша проба ділила 179 класів на «пише JS» (70) і «винне демо» (109), питаючи «чи трапляється цей рядок у JS-файлі»: classList.add АБО class="x" всередині скрипта. У цьому репозиторії друга половина не означає нічого - wireframes/_nav.js і є будівник сірого прототипу, тож більшість розмітки продукту лежить у рядкових літералах JS. Із 26 класів на семи найменших сторінках 23 виявились розміткою в шаблоні, а справжніх було три. Питання тихо перетворилось на «де лежить цей файл». tools/idle.mjs питає вузько й перевірювано: classList.add|toggle|remove('x') на елементі, який уже існує.
    перша пробазаміряно
    клас пише скрипт - це стан, а не демо709
    клас, за який сторінка винна демо109163

    Усі дев'ять станів закрито

    Кожен переїхав у KIT_STS із реченням на своїй сторінці про те, хто його пише і чому він не стоїть у спокої. dr-lock і pdp-stuck кладуть на <html> і <body>, тож намалювати їх означало б одягти стенд, а не демо; catov-open лягає на нижню вкладку, якої на тій сторінці немає взагалі; hidden - це відсутність банера; added - слід дії. Лишилось 15 сторінок і 159 класів, і всі до одного - демо, яке сторінка винна.

    Сама перевірка лежала в 74 ручних копіях, у п'яти редакціях

    Три відрізнялись лише переносом рядка. Четверта - plan-card і upsell - мала вирізаний пункт про стани, тож ці дві сторінки не змогли б доповісти неназваний стан, якби він у них був. П'ята, icon.html, тримала єдине правило, яке решта 73 загубили: міряти ПІСЛЯ проходів, а не при розборі, бо .uiv-trail ставить marks.js на DOMContentLoaded. Тепер один design/kit/_idle.js, і він читає ще й усередину рамки демо - це коштувало рівно 4 класи зі 162 (toolbar три і co-wrap), але сторінка, червона з неправдивої причини, і є предмет цього пункту.

    А список винятків тримав два класи, які не є станами

    На address-card у KIT_STS стояли .addr-del-row і .addr-back - обидва тут-таки намальовані на сторінці, а вмикає їх не клас: рядок видалення ховає атрибут hidden, «інший спосіб» - .mode-edit на модалці. Найдешевший спосіб позеленити цей гейт - припаркувати клас у винятках, тож виняток тепер має власний холостий контроль: голий ідентифікатор, який css компонента оголошує класом і жоден скрипт не перемикає.

    Перші п'ять сторінок закрито, і жоден із шести класів не був прикрасою

    .fsheet-ov бракувало тому, що збирач ішов деревом панелі, а підкладка їй сусідка. .ceov довелось поставити окремо від .wf-ov: дві fixed-підкладки на inset: 0 в одному в'юпорті читаються як один темний прямокутник. .oosbtn свідомо зняли з цієї сторінки на 7.91 за те, що вона малювала його контурним, - тепер він стоїть там, де в продукті, всередині .bb .buyrow. .pdp переїхав у рамку навколо власної смуги, бо смуга вирощує ціну на 960 саме ТОМУ, що .pdp відвів рейку покупки в другу колонку. А .ptabs виявився геть іншою смугою вкладок, яка ділить файл, - і це питання етапу 09.

    І перше ж справжнє демо привело живий дефект на екран покупця

    Плашка «★ Популярне» лягає на назву товару - design/listing-list.html, перша картка, перекриття 10 x 14px на 390 і на 360, на 1280 чисто. До 559 .pcard-l стає сіткою 56px 1fr, фото звужується до 56, а плашка всередині нього - position: absolute без обмеження ширини, і її 77px переходять у текстову колонку, що починається на 101; overflow у .lph немає. Друга плашка, «✦ Новинка», вужча на 13px і не зачіпає назву випадково, а не за правилом. Не полагоджено навмисно: обрізати слово, стиснути в трикрапку або лишити саму зірку - три різні відповіді про те, що екран каже на первинній ширині. Рішення власника.

    Ще три сторінки, шістнадцять класів, і всі однієї форми

    filter-rail, auth-dialog, cat-overlay. Жоден із шістнадцяти не був варіантом того, що вже стояло на сторінці: кожен - обличчя компонента, якого в спокої не існує, з однієї з двох причин. Ширина, яка його не малює: .hrail - display: none до 960, а флайаут і підкладка несуть !important до 860, тож на ширині рейки фільтрів уся ця сім'я не малює нічого, і жодне правило стенда цього не змінить. Тіло, яке переписується цілком: діалог входу має шість станів, оверлей - три рівні, і обидва замінюють панель повністю, тож .auth-load існує лише в loading, .auth-alt - лише в error, .wf-catov-goal - лише на рівні цілей.

    Жодна з п'яти нових рамок не набирає розмітки - вона натискає

    wfHomeRail({ open: true }), wfAuthGo('loading'), wfAuthGo('error'), catOverlayCat(0), catOverlayGoals() - власні функції продукту, ті самі, які викликають наведення й натискання. Сторінка, що передруковує те, що видає будівник, показує власну копію компонента, а не компонент.

    А заблокована ця робота була ще 24 копіями одного скрипта

    Механізм підгонки рамки - той, що дає <iframe> висоту вмісту й масштабує в'юпорт 1180 у вужчу колонку, - лежав інлайном у 24 сторінках побайтно, і ніс обмеження, яке ніколи не було рішенням: querySelector, однина. Сторінка могла тримати рівно одну рамку; друга завантажилась би й лишилась на типових 150px. Тепер design/kit/_frame.js і querySelectorAll. Це не прибирання мимохідь: filter-rail потребує двох рамок, auth-dialog - трьох, і кільком сторінкам із тих, що ще винні, теж треба більш ніж одна.

    Ще дві сторінки, двадцять класів, і сторінка під шухлядою

    cookie-banner: діалог налаштувань пише wfCookie() разом зі смугою, і він лишається закритим, доки хтось не натисне «Налаштувати», - тож десять із п'ятнадцяти класів не мали форми спокою взагалі. cart-drawer: три інші обличчя живуть на трьох інших екранах, а сторінка під шухлядою належить цьому ж файлу - .cart-behind, .cart-ov, .ph-grid, .ph-card сусіди шухляди, і вся суть .cart-behind у тому, що кошик - шухляда поверх сторінки, а не сторінка сама по собі.

    Третя екстракція за день, і вона не косметична

    Бут-блок рамок - список ініціалізаторів, який робить демо поведінкою, а не позою, - лежав у 33 однакових копіях. Тепер design/kit/demo/_boot.js, і в ньому дві речі, яких у копіях не було. Гачок FRAME_STATE викликається в одній точці: після ініціалізаторів, щоб будівники існували, і до проходів іконок і знаків, щоб розмітка, яку збудував стан, отримала свої гліфи. Покладений у кінець - як зробила б пряма екстракція - він лишає щойно зібрану панель в емодзі: це той самий дефект, який 7.78 виправив для тоста, а 7.87 для каталожного оверлея. І шлях до ассета, який будівник набирає руками: чотири будівники в design/_nav.js пишуть відносний до документа src у створений елемент. На кольоровому екрані це правильно, а рамка лежить двома рівнями глибше, тож той самий рядок дає 404. Знайдено порожнім кошиком, який намалював биту картинку замість ведмедя.

    А відкрита панель привела знахідку, більшу за обидва компоненти

    Контейнер кожної відкритої фіксованої панелі малює типове синє кільце фокусу Chrome - auto 1px rgb(0, 95, 204), синій, якого немає в жодній палітрі системи. Причина не в цих файлах: пастка фокусу з 7.85 ставить tabindex="-1" на верхню відкриту панель і фокусує контейнер - навмисно, «щоб він оголосив власну назву й не вибирав дію за того, хто ще не прочитав панель». Це правильно. Кільця для цього контейнера ніхто не оголошував: система описує :focus-visible покомпонентно, для контролів. Заміряно на трьох справжніх кольорових екранах, не на стенді: #fsheet на listing.html, #city-dlg на index.html, #wf-catov на product.html - усі три однаково. Не полагоджено: «зняти кільце з контейнера, який не є ціллю» і «дати контейнеру системне --color-focus» - різні відповіді про те, чи має людина з клавіатурою бачити, що фокус переїхав. Рішення власника.

    Ще три сторінки, 31 клас, і два з них виявились не демо

    .mega-pinned і .pinned - не стани продукту. Єдине, що їх ставить у всьому репозиторії, - чотири сірі екрани wireframes/megamenu*.html, і screens.md каже прямо: «.mega-pinned тримає відкритим для демо». Клас, чия мета - дати демо потримати панель відкритою, не підробляється тим, що демо тримає панель відкритою. Меню кабінету потребувало двох рамок: .cab-lvl - рядок лояльності покупця, .cab-tier - пігулка тарифу тренера, і одна .cab-head відповідає обом ролям. system-page побачив систему вперше: усі шістнадцять його класів лежать на чотирьох сірих екранах без кольорового двійника, і нові рамки вантажать system/index.css.

    Два з одинадцяти класів buy-box - мертвий код, і це третій список

    .bb .tier і .bb .qty не носить ніхто. Питання поставлено рендеру, а не розмітці, бо коробку частково будує JS: чотири екрани несуть .bb, і на кожному 0 збігів. У сірому шарі теж нічого: єдиний .tier у репозиторії - на wireframes/coach-verify-tier.html, і це картка тарифу зі скоупа .coach, ніколи не всередині коробки покупки. Кількість продукт рахує трьома іншими іменами, кожне у своєму файлі - .ci-qty, .co-qty, .oc-qty, - і жодне не лежить у .bb. Видалено, з заміром біля кожного видалення; --line-strong пішов разом із ними й того самого кроку пішов із таблиці токенів сторінки - це roles.mjs зробив свою роботу.

    І .tier - той самий рядок, який збив першу пробу сортування на 8.32, бо acc-tier і cab-tier трапляються в wireframes/_nav.js. Два прилади збиті одним іменем поспіль, і обидва рази виправлення те саме: питати рендер, а не текст джерела.

    Три відкриті питання закрито власником, і кожна відповідь лягла туди, де прилад може її виконати

    1. Фото лишається 84 на телефоні. product-card.css до 559: 56px -> 84px, а перевизначення .lph видалено, щоб стояло базове значення. Обрано за таблицею: усі три засоби знімають накладання, але висота картки 225 в усіх чотирьох варіантах - назва однаково лягає у два рядки, - тож звуження до 56 не купувало нічого видимого й платило за це зіткненням. Ціна: 43px ширини назви. Це єдиний варіант, який лишає слово.

    2. Кільце знято з контейнера панелі. [tabindex="-1"].open:focus{ outline: none } у base.css; кожен контрол усередині панелі зберігає власне :focus-visible.

    3. Шість фінішів вирішено, і відповіді лежать у самому приладі. Три написано (coach-clients-cap), три благословлено (home-*). Таблиця FINISH_DECIDED у btn-rank.mjs, бо екран, переклонований із сірого, втратив би ручну правку, а таблиця її повторить.

    І очевидний селектор для кільця був би регресом доступності

    Першим під руку йшов голий [tabindex="-1"]:focus, тож радіус ураження зміряли до того, як щось писати - питанням до рендеру на 88 екранах: div.menu-opt на 87, label.co-opt на 15, div.menu-list на 15, span.ptab на 12, span.vopt на 10, span.ord-tab на 2. Це roving tabindex - неактивні члени складеного віджета, на які стрілки фокус переводять і які мусять кільце мати. Прибрати його там означало б зняти справжній сигнал з усіх меню, смуг вкладок і виборів варіанта в продукті. Жоден із них ніколи не носить .open; кожна панель, яку фокусує пастка, носить.

    Шість заливок на екрані ліміту стали три

    Порахуємо на 390: база coach-clients - 3 акцентні (смуга «Нова сесія», «Додати клієнта», «Підписатись»); coach-clients-cap було 6 - та сама смуга, «Оформити Pro» і ТРИ «Нова сесія» на картках. Екран каже «ви вперлись у ліміт», отже його один чіткий наступний крок - «Оформити Pro», а він був одним із шести, чотири з яких кликали в два боки. Стало 3 проти 3, і найгучніше нове на екрані - апгрейд.

    Останні дві сторінки: 86 класів -> 11, і checkout-form закрито повністю

    Найбільший файл системи взяв вісім рамок, бо тримає вісім облич і дві адреси: власну обрізану оболонку чекауту (.co-head / .co-logo / .co-support / .co-foot - ні меню, ні пошуку, ні каталогу: на екрані, де платять, один вихід і жодного шляху вбік), варіанти ввійшлого й без адреси, екран відхиленого платежу з блоком «замовлення збережено», екран обробки, картку профілю .pfcard, яка не ділить із чекаутом жодного рядка, і два діалоги, які профіль відкриває. account-shell пішов 29 -> 11: сама оболонка, її сітка завантаження, рядок покупця в рейці тренера й шапка обраного.

    Один клас жив не в тому файлі, і сховався саме тому, що в нього немає розмітки

    .smeths - стос кнопок соцвходу під «або» - був оголошений у checkout-form.css, а трапляється в жодній розмітці: ні сірій, ні кольоровій. Єдине, що його пише, - wfAuthPanel(), тобто діалог входу. Переїхав у auth-dialog.css, обидва оголошення побайтно й кожне у своєму блоці.

    Він сидів не там саме тому, що розмітки в нього немає: жоден перепис входжень не міг на нього вказати, і ніхто не спитав, доки цю сторінку не змусили показати клас, якого на її п'яти екранах немає. Це холостий контроль знайшов рід дефекту, під який не було приладу.

    Останні 11 - це взагалі не кабінет, і це рішення власника

    .wt-flow .wt-fh .wt-fnote .wt-screen .wt-sname .wt-st .wt-states з .base .node .planned .soon - це дерево роадмепу: будує wfTree(), а викликає рівно одна сторінка репозиторію, wireframes/overview.html. Це хаб прототипу, який перелічує екрани, а не є екраном, і CLAUDE.md виключає його з корпусу компонентів поіменно.

    Три заміри, і всі три згодні: та сторінка вантажить _wf.css і ніколи систему; _wf.css оголошує цю сім'ю сам; і жодна сторінка, яка вантажить систему, цієї розмітки не містить. Тобто копія в account-shell.css недосяжна - і власна нотатка сторінки вже рахує ціну: 136 зі 169 оголошень файлу, які не збігаються з жодним елементом продукту.

    Прецедент - на цій же сторінці: .only-mobile і .only-desk були тим самим питанням, і власник закрив його видаленням 2026-08-14. Рекомендація: так само. Одноосібно не зроблено, бо той раз був явно рішенням власника, а цей удванадцятеро більший.

    ПУНКТ 3b ЗАКРИТО: 74 сторінки стенда, жодної червоної

    Власник ухвалив: дванадцять правил .wt-* видалено з account-shell.css, з трьома замірами, виписаними поруч. Хаб зміряно ПІСЛЯ, а не припущено: wireframes/overview.html так само малює 6 потоків, 50 екранів і 141 пігулку стану, з тією ж гранню, радіусом і формою пігулки - усе з _wf.css, який оголошує цю сім'ю сам. Чотири токени пішли з файлу разом із правилами і того самого кроку пішли з таблиці токенів сторінки - roles.mjs спіймав кожен.

    Борг пройшов 179 класів на 19 сторінках -> 0, а accept уперше на цьому етапі дає 234 екрани, 0 падінь.

    Що ця робота насправді знайшла, і чого не міг знайти жоден наявний прилад

    Три екстракції приладів, усі однієї форми - механізм, передрукований у кожну сторінку, якій він потрібен: _idle.js (74 копії, п'ять редакцій, в одній вирізано пункт про стани, в іншій - єдине правильне правило часу), _frame.js (24 копії з querySelector, який мовчки обмежував сторінку однією рамкою), _boot.js (33 копії плюс гачок, чиє розташування несуче, і шлях до ассета, який чотири будівники набирають руками).

    Два видалення мертвого коду - .bb .tier / .bb .qty і сім'я .wt-*. Одне правило не в тому файлі - .smeths, який сховався саме тому, що розмітки в нього немає взагалі. Один живий дефект на екрані покупця - плашка на назві товару. І один на весь шар панелей - синє кільце фокусу Chrome.

    Жодне з цього не діставалось приладами, які в репозиторії вже були. Усе це - відповіді на питання, якого ніхто не ставив: чи сторінка справді ПОКАЗУЄ те, що оголошує її файл.

    Купа 2, перший блок: сесія замовлення, 138 правил -> 48

    Сім екранів станів тренерської сесії несли найбільший блок, що лишався, а їхня база не має <style> взагалі: базу перевели, стани - ні. Та сама форма, що coach-tariff і coach-orders, вчетверо більша. Мапа - це три атрибути класу, застосовані трансформом, який читає базу, а не шістьма ручними правками; п'ятнадцять селекторів були чистим воскресінням buy-bar, client-row, price, discount, availability і chip.

    Що стани малювали натомість, на 390: дія липкої смуги 100.50 × 40 проти 243.30 × 64 - під порогом дотику 44px, на контролі, до якого веде вся сесія; «В наявності» у secondary там, де availability.css каже --text-success, тобто на сигналі довіри первинної аудиторії; закреслена ціна в rgb(170,170,170), сірому, якого немає в палітрі; поле швидкого додавання малювало коробку в коробці; чіпи цілей 33.19 заввишки.

    І чотири прилади дечого навчились. private.mjs читав КОМЕНТАР як селектор - withNotes нарощує спан на його примітку, а тут css пишуть усередині приміток, тож два правила були розкласифіковані хибно, і обидві примітки написали два попередні проходи. btn-rank.mjs ніколи не питав, чи ранг збігається з базою, і щоб спитати це надійно, знадобилось три ключі - слот, а не клас і не адреса, - плюс поділ, який тепер правило: розмір, що не збігається, - дефект; фініш, що не збігається, - рішення. А accept.mjs отримав колонку dot= після фотографії з двома крапками на кожному рядку наявності: 31 набраний знак на семи екранах, один з них - екран покупця з подвоєною крапкою на дванадцяти рядках.

    І один раз прилад упіймав мене раніше, ніж я себе. Перше написання правила .ac-info викинуло display: flex; flex-direction: column як «те, що блок і так робить із двома блоковими дітьми» - а діти там <span>, і два інлайнові спани в блоці стають в один рядок: «ІгорЦіль: Витривалість · 2 замовлення» на фотографії 390. У коментарі стояло «measured with and without, 0 moved», і нічого зміряно не було. Оголошення повернуто, а хибне речення замінено на те, що сталось насправді, а не стерто. Далі за купою 1: 111 локальних імен без дому, 88 правил на кілька компонентів, 24 частково нових, 2 без класу.

  4. Купа 2, третій блок: скелетон, 20 правил на 5 екранах -> 0

    skeleton.css відкривається переписом - смуга «written SIX times in FOUR files», - знятим на 7.28 по 40 кольорових екранах. Тренерський потік увійшов у колір на 7.95, тож перепис його не бачив. Перерахунок по п'ятьох тренерських екранах завантаження дає дев'ять редакцій смуги, і жодне оголошення не замінило видалених правил.
    смугависотарадіусґрунтде
    .sk-line13px6px--bg-sunkencoach-client-loading
    .skln12px6px--bg-rulecoach-order-loading, coach-orders-loading
    .qa-skel .sk12px6px--bg-rulecoach-session-loading
    .skline10px4px--bg-sunkenсистема, і 78 смуг із 84

    --bg-rule - це --warm-200, тобто --line-hair

    Три тренерські екрани фарбували скелетонну смугу кольором волосини, поки решта продукту фарбувала --warm-100. Зміряно tree-diff: rgb(233, 231, 226) -> rgb(242, 240, 237) на 21 смузі. А сам файл каже це одним рядком: «the ground of a skeleton bar is --bg-sunken and is stated once».

    А рядки навколо смуг були тим самим компонентом, передрукованим руками. Не схожість - ті самі оголошення поруч: .sk-row = .oc-item (40 / 1fr, gap 11, волосина), .sk-ph = .oc-ph (40 квадрат, радіус 7), .sk-top = .oc-top, .sk-actions = .oc-actions (gap 9, margin-top 14), .qa-skel = .qa-row (44 / 1fr, gap 11, padding 9/0), .skhd = .ccard-hd, .skav = .ccard-av, .skacts = .ccard-acts, .skclist = .clist, .skgrp = .od-grp.

    Тому відповідь не «перенести їх у компонент»

    Це правило 7.68, дочитане до кінця: скелетон - це обіцянка про коробку, яка його замінить, і єдина обіцянка, що не може розійтися, - сама коробка. Розмітка тих п'ятьох екранів тепер носить .ocard, .oc-item, .oc-ph, .ccard, .clist, .od-grp, .ord, .qa-row - справжнє, порожнє, зі .skline всередині. .skpulse уже був цієї форми і сам про це каже: «the container is usually a real component».

    Додалось рівно двоє оголошень, і обидва вже були написані двічі. Заглушка кнопки (.sk-btn 38 × 120 і .skacts i 38 із flex: 1), обидві на 2px нижчі за btn--s, чий min-height = --size-40; і .load-note, речення під скелетоном. Плюс три правила, що читають анатомію так само, як двоє з 8.30: що потрібно .od-grp і .ord, коли вони тримають смуги замість своїх справжніх дітей, і що потрібно смузі у флекс-рядку чи в auto-треку сітки - той самий дефект «відсоток від нічого», що його 8.30 зміряв на рейці кабінету, у другому середовищі існування.

    Одне з тих трьох правил було написане з розмітки ОДНОГО екрана

    Правило тримача один чернетковий прохід читалось .od-grp:not(:has(.od-grp-h)), .ord:not(:has(.ord-body)). Обидві половини клаузи .ord хибні: coach-cabinet.css дає .coach .ord власний падінг, тож правило відповідало на питання, якого ніхто не ставив, - а .ord-body пише лише account-orders, тож сторож зачепив би й чотири справжні картки замовлень на coach-orders.html. Та сама сім'я, що й матч по цілому рядку class="btn" з пункту 1. Знято з читанням поруч, а видалення доводить tree-diff: шість завантажених екранів, перед якими стоять ці скелетони, зрушили 0 елементів на обох ширинах.

    Це доводить 8.24 до кінця, а не скасовує його

    Той крок зняв coach-clients-loading з третього імені скелетонної картки і поставив на .skcard; те саме читання на крок далі каже, що це взагалі не скелетонна картка, а картка клієнта, що стоїть порожня. .skcard лишається каталогу й кабінету, де коробка-замінник це .pcard, - назвати їх це етап 09, а не рух, який цей крок зміряв.

    Купа 2, четвертий блок: коробка помилки й коробка порожнечі, 26 правил на 7 екранах -> 0

    empty-state.css ще з 7.28 каже, що порожньо і зламалось - різні речі, і каже це реченням на власній сторінці стенда. Жоден екран тренерського потоку цього не прочитав. .errbox носив рівно ОДИН екран у продукті - account-error, - а токен --line-danger-soft мав рівно одне вживання в усій системі: грань тієї єдиної коробки.
    коробкаграньрадіуспадінггліф
    .err · coach-client-error1px solid --line-strong1440/2232px на --mark-disabled
    .cerr · coach-home-error1.5px dashed --line-strong1644/26кільце 60px, --text-secondary
    .ord-err · order-error, orders-error1px --line-hair1444/24немає
    .empty · coach-clients-errorне своя коробка взагалі - ілюстрована плашка каталогу «тут поки нічого»
    .errbox1px --line-danger-soft--radius-1248/24--text-danger, 34

    Жодна з чотирьох не несла ролі небезпеки

    Не інший відтінок червоного - червоного не було зовсім. Плаский сірий, а на coach-client-error гліф попередження стояв на --mark-disabled, тобто чорнилі для того, що вимкнено. Первинна аудиторія, найгірша хвилина сценарію - і саме там продукт мовчав про те, що сталося.

    Разом із ними пішло те, що ці екрани домальовували руками: .err-btns .btn{ padding: 13px 24px } - розмір поверх btn--s, те саме видалення, що 8.30 зробив для .cs-empty .btn; .ord-empty, .ord-err в одному селекторі, тобто одна плашка на дві протилежні роботи; і p.lead на двох екранах клієнтів - це .es під іншим імям, з мірою 42ch на одному екрані й 46ch на другому.

    А міри в коробки не було, і саме тому обидва екрани її виростили

    .emptybox .es обмежена 440, .errbox .es - 420, а в .empty .es межі не було зовсім. Заміряно на 1280: 660px на coach-clients-empty, 726 на listing-error, 818 на coach-client-empty, 982 на product-error - до ста знаків у рядок. Одна декларація, 440 - число, яке сусідня коробка вже несе. tree-diff каже: рухає рівно один елемент на кожному з чотирьох екранів і нічого на 390, де коробка й так вужча за 440.

    Двом екранам додано гліф, і це рішення про вигляд, а не замір

    Усі інші коробки помилки в продукті несуть ⚠️, а коробка, якій компонент фарбує --text-danger, - це коробка, що його чекає. Заодно це тримає чесним правило 8.15: .errbox свідомо НЕ додано в селектор :first-child, бо після цього кроку немає жодної коробки помилки без гліфа, а селектор, що не покриває нічого, - той самий шум, що й порожній виняток. Міркування виписане біля самого правила.

    Купа 2, пятий блок: потік перевірки тренера, 32 правила на 4 екранах -> 0

    Кожне імя в тих блоках мало префікс cv- - це власна анатомія coach-verify.css, яку несли чотири екрани станів, тоді як база не несла нічого з неї. Лишились три відкладені правила .cv-card, і це весь залишок потоку.
    що коштувала копіязамір
    .lead - це .cv-lead, у якому бракує одного словатри редакції: 14px / 13.5px / 13.5px, три відступи, дві міри
    у .cv-lead не було міриcoach-verify-tier малював рядок 828px на 1280 - 93 знаки в рядок
    h1.cv-h1 набраний руками24/800 Inter проти --fs-30 Oswald - четвертий заголовок на два лиця
    голий .btn{ display: block } на двох екранахтретій випадок форми після .tier-cta (8.29) і .cs-empty .btn (8.30)

    І перше написання четвертого рядка було хибним - саме тому воно тут окремо

    Там стояло, що правило перетворює btn--full головної дії назад на блок. Браузер сказав ні: cv-cta написаний btn--accent btn--l btn--full без голого btn, тож правило до нього не діставало взагалі. Заміряно на coach-verify-error на 1280 до і після: воно діставало до другорядної дії, і там робило справжню роботу - контурна кнопка була 510 × 40 з margin-top: 11px, а сам атом дає 203 × 40 без відступу: контрол природної ширини, приклеєний до нижньої грані повношириного. Тож відповідь не в тому, щоб лишити голий .btn. Дві дії стосом - це група, у цього файлу вже був для неї клас (.cv-actions, на екрані глухого кута), і екран помилки просто його не носив. Твердження, яке виживає на одному екрані й гине на другому, - це те, для чого потрібен браузер.

    text-align: center свідомо вийшов із відкладеного набору

    Приватними лишились три правила - .cv-card{ max-width: 560px } двічі й { padding: 40px 24px } раз, - бо яка з відповідей картки стане відповіддю панелі, це рішення. Центрування до цього питання не належить: воно ділить чотири екрани за тим, що вони тримають, а не за значенням. Екран очікування й глухий кут центрують одне повідомлення; екран помилки лишає текст зліва, бо несе список. Тож це .cv-card.mid у компоненті, і все, що випливає з центрування - диск, кільце, лід, підрядок, нотатка, обмеження колонки дій на 340, - випливає з нього в одному місці.

    Купа 2, останній блок: 25 правил на 8 екранах - і купу закрито

    Після потоку перевірки лишились ті самі три атоми, передруковані втретє, плюс чотири падінги кнопок.
    атомщо написала копіящо каже система
    .acard · coach-home-free, -emptyрадіус 14, без плити й тіні; .ah gap 10; капслейбл на --text-secondary; лінк 12.5--radius-12, --bg-page, --elevation-1, --space-12, --text-muted, --fs-14
    .co-status · coach-home-free11px/800 на --line-strong, і стан .ok відрізано--fs-12 на --space-4/--space-12, зелений .ok
    .cl-oostag · coach-session-oos11px/800 Inter ні на чому.ci-oostag: моно --fs-10 на --bg-sunken
    .cs-empty · coach-session-newclientсьома приватна редакція, іменами елементів.emptybox з .ei .et .es

    Два падінги кнопок система видалила ЗА ІМЕНЕМ, і екрани їх досі несли

    coach-clients.css:411: «.cc-cta .btn{ padding: 13px 22px } DELETED - button.css owns the padding» - а coach-client-loading ніс рівно це правило. :332: «.ccard-acts .btn KEPT ONLY ITS flex: 1» - а coach-clients-cap ніс усі три оголошення. Третій, .cli .cgo-btn, оголошував три речі, які система вже оголошує в трьох різних файлах.

    А одну правку зміряли, визнали регресом і відкотили тим самим кроком

    Порожня коробка ставить .ei{ font-size: 0 } і показує SVG, який кладе marks.js. У приватної коробки такого правила не було, тож її 🛒 малював шрифт - а marks.js 🛒 не мапить, мапить UIV_EMOJI в design/_nav.js. Щойно компонент узяв гору, слот іконки зміряв 259 × 0: знак був не блідий, його не було. Той самий шов, що 🗑 на 7.13 і 📦 на 8.1, тож очевидна відповідь - третій рядок.

    Він коштував два задеплоєні екрани покупця. .ei - це ще й слот, який design/_nav.js:1566 заповнює маскотом на cart-empty і cart-coach-empty, і '🛒':'cart' замінив маскота контуром візка на обох. Відкочено; коробка бере 📦, знак, який уже носять три її сестри. Третій маршрут, що пише в той самий елемент, - ось чому шов між двома мапами не завжди закривається рядком у другій.

    Чотири з восьми екранів завантаження не дихали

    .skpulse лежить у системі з 7.28 із власною відповіддю на prefers-reduced-motion, а coach-client-loading, coach-order-loading, coach-orders-loading і coach-session-loading просто ніколи його не отримали - coach-session-loading так і написав у власному коментарі, «static, motion deferred». Тепер усі вісім. І один клас був мертвий з іншого боку: .skel на coach-orders-loading не оголошений ніде - ні тут, ні в сірому шарі. Список 3 питає «який клас не носить жодна розмітка»; це дзеркальне питання, і його не ставить жоден прилад.
  5. 105 мертвих class="dark" у design/*.html. Закрито 2026-08-15: знято 105 із 57 екранів, і не зрушило нічого.

    Зміряно до того, як чіпати, і саме замір зробив це безпечним. Усі 105 сиділи на контролах, які вже носять ранг btn--* - тобто слово було заступлене, а не забуте. wireframes/_wf.css:583 оголошує .btn.dark; під design/ .dark не оголошує ніхто - згадки в tokens.css, button.css і filter-sheet.css це коментарі про те, що колись воно важило, а design/kit/_page.css має .kp-demo.dark, і це власне полотно стенда, а не цей клас на продуктовому контролі. JS його теж не читає й не пише: кожен dark у design/_nav.js і design/system/theme.js - це назва РЕЖИМУ ТЕМИ.

    Правка у двох місцях, і одне з них - трансформ. clone-to-colour.mjs читає dark, щоб вирішити, чи клонований контрол стартує як btn--accent чи btn--outline, і раніше ніс його далі в результат - тож dark це ВХІД трансформа, і з виходу він тепер прибирається. Замітання того, що вже вийшло, живе в btn-rank.mjs, який володіє атрибутами класів кнопок у design/*.html, і воно йде ПІСЛЯ запису рангів: контрол, що приходить як btn dark cs-go, ще без рангу, тож замітання перед ранжуванням лишило б мертве слово і потребувало другого прогону.

    Сторож - те, що робить це замітанням, а не sed: dark мертвий лише там, де його заступив ранг. Усе інше, що носить це слово, потрапляє в список і лишається недоторканим.

    Доказ: tree-diff HEAD, 57 сторінок, 114 порівнянь, 0 зрушених, 630 перейменованих рядків - це 105 контролів x 3 рядки (елемент, ::before, ::after) x 2 ширини, точно. accept на 360 і 390 по 57 екранах: 0 падінь.

    А доказ довелось спершу навчити відрізняти перейменування від руху. Кожен рядок знімка починається з TAG.className, тож зміна класу робила рядок відмінним, поки всі 85 властивостей стояли на місці: перший прогін відповів «114 порівнянь, 114 зрушило» з порожнім переліком властивостей під кожним, і читач, який повірив би заголовку, відкотив би правильну зміну. Тепер зрушило рахує лише властивості, а перейменування називаються поруч окремим числом: рух властивості це візуальний регрес, перейменований рядок - це та правка розмітки, яку ти й робив.

  6. .cline.oos гасить цілий рядок до opacity: .5. Вирішено і зроблено 2026-08-15, власник віддав вигляд. Це таки був баг, і вирішив його замір.

    Число в цьому записі було хибне, і справжнє гірше саме там, де це важить. Скомпоноване з поверхнею, а не помножене начисто, rgb(28,28,28) при opacity: .5 на білому дає 3.30:1, а не 1.47 - заміряно в браузері на cart-oos, coach-session-oos, listing і listing-list при 390, усі чотири однаково. 3.30 проходить нетекстовий поріг 3:1 і провалює 4.5:1, який стосується того, чим це насправді є. 1.97 у плейсхолдера було правильне і не має значення: коробка-заглушка це декорація.

    фотографіядекорація, порогу немаєopacity: .5 лишається
    назва і ціначорнило, 4.5:13.30 -> 6.84:1 через --text-secondary

    Змінна - як гаситься недоступний товар

    Значення: фотографія лишає opacity: .5; назва і ціна беруть --text-secondary. Чому: прозорість міняє контраст, не оголошуючи ролі, а назва товару - це рівно те, що тренер читає, щоб обрати заміну, тобто останнє, чому можна бліднути. --text-secondary це наявна роль приглушеного чорнила, 265 вживань, 6.84:1 на білому.

    Застосовано в усіх чотирьох місцях, які поділяють це значення, бо одне значення не може мати двох трактувань: .ci.oos, .pcard.dim, .pcard-l.dim і .cline.oos, яке при цьому переїхало з приватного блоку coach-session-oos.html у coach-session.css, куди й належить - одне правило з купи пункту 2 заразом.

    Стан ніколи не тримався на затіненні. .ci-oostag і .pavail.out кажуть «Немає в наявності» словами, і саме це називає стан; затінення - це наголос.

    А замір ПІСЛЯ зміни спіймав помилку, яку міркування пропустило. color на .prow2 УСПАДКОВУЄТЬСЯ, а успадкування програє будь-якому власному оголошенню, хай найслабшому - у .pnew воно є, тож карточка сітки повернулась із 17.04:1, тобто не приглушена зовсім, точна протилежність правці. Роль мусила лягти на саму ціну. Той самий замір показав, що старе затінення гасило й .cartbtn.notify, «Повідомити про надходження» - єдину дію, яка на цій картці ще можлива. Тепер вона на повну силу, і це правильно: товару немає, а сповіщення є.

    Доказ: tree-diff --dir, 88 сторінок, 176 порівнянь, зрушило 10 - це 5 зачеплених екранів на двох ширинах і більше нічого, і кожен рух це або opacity 0.5 -> 1, або rgb(28,28,28) -> rgb(91,91,84). accept на 360 і 390 по цих п'ятьох: 0.

  7. cart-coach носить .coach дарма. Закрито 2026-08-15: лишаємо, і перевірка була неправа, називаючи це дефектом.

    На тому екрані нічого не зламано, і відповідь уже була написана в коді. Єдине правило, яке колись користувалось скоупом, це .coach .ci:last-child; воно переїхало в .cd-group .ci:last-child на кроці 7.96, і причина записана в cart-drawer.css: .coach не було сторожем, бо його носить кожен кольоровий екран тренера, тож правило діставало все, що носить .ci будь-де в потоці. Справжній сторож це .cd-group - 2 входження на cart-coach.html і 0 на cart.html та cart-oos.html.

    Лишаємо, і міркування тут навмисно несиметричне. cart-coach Є екраном тренера - замкнене продуктове рішення 1, кошик із позначкою клієнта. Скоуп пишеться з бази правилом, а не руками. Зняти його означало б лишити єдиний екран тренера без неймспейса, і наступний скоупований селектор тихо його промине - той самий дефект на 23 екрани, за який цей етап уже заплатив. Неймспейс, який сьогодні нічого не ловить, коштує один токен класу; неймспейс, якого бракує на одному екрані, коштує цілого класу тихих багів.

    scope.mjs через це валив гейт, а тепер питає правильне. Неймспейс, що нічого не ловить, потрапляє у звіт і не валить. Валить те, чого ніхто не питав: екран, що носить скоуп, якого не носить його база - екран, що заявляє потік, до якого не належить. Зараз таких 0.

  8. Два застарілі записи: design/overview.html каже 50 кольорових екранів, а примітка кроку 8.19 каже 41 ще-сірий. Закрито 2026-08-15, і запис був застарілий сам про себе. Обидва вже виправлені у своїх файлах: design/overview.html:283 несе «87 екранів + хаб (46 покупця, 41 тренера), перераховано 2026-08-14 кроком 6» і називає 50 числом, що застигло на етапі 07, а docs/decisions.md помічає 41 як застаріле поруч із 54 кроку 6. Рядок етапу 07 у README був правильний увесь час.

    Замість них знайшовся третій, і він не стояв у жодному списку. design/kit/docs/architecture.md і його сторінка казали «кольоровий шар це 40 екранів; сірий прототип - 142. У 42 екранів тренера кольору немає зовсім» - і на цій підставі ставили власникові питання про обсяг. Обидва числа зробила неправдою робота цього ж етапу. Запис помічено, а не переписано: це питання, на яке власник відповів 11 серпня, і відповідь без нього не читається.

    І що тут варто сказати вголос: список застарілих записів сам застаріває. Два пункти полагодили в місці правки, а список про це не почув; запис, якого ніхто не вписав, простояв зі своїми числами чотири дні. Захист, що масштабується, один - питати ВИХІД, а не вести список.

  9. Жоден прилад не питає, чи опубліковане число ще правда. Кожна цифра на стенді була правильна, коли її писали, і ніхто її не перепитує. Три спіймано руками за два дні (50, 41, 40/42), і щоразу тим, хто відкрив сторінку заради іншого. Форма перевірки відома з тих, що вже працюють: узяти твердження зі сторінки, узяти число з корпусу і впасти на розбіжності - grey-vars.mjs і vars.mjs роблять рівно це для значень.

    ПЕРШИЙ ПРИЛАД ЗРОБЛЕНО 16.08.2026: tools/inventory.mjs, і його предмет це реєстр компонентного шару, inventory.md. Перший прогін: 84 файли проти 73 рядків, 2 рядки на неіснуючий файл, 66 хибних Lines, 58 хибних Screens, підсумковий абзац каже «70 компонентів: 22/27/21» проти 73 (22/28/23) у своїх же таблицях. Колонка Screens правильною бути й не могла: то було сканування розмітки, а третину хрому цього продукту пише wireframes/_nav.js на завантаженні, тож вона читала footer.css 1 там, де підвал на 77 екранах.

    ДРУГИЙ ПРЕДМЕТ ПІДКЛЮЧЕНО 17.08.2026, І ЦЕ ТОЙ, ЩО ЙОГО СПРАВДІ ЧИТАЄ ЛЮДИНА. Реєстр це одна копія твердження «який завбільшки цей компонент»; смужка kp-meta на кожній design/kit/<компонент>.html це ДРУГА, а дрейфує саме друга. Питання H у тому самому приладі, по 75 сторінках стенда, що називають файл компонента:

    тегівхибних
    рівень750
    N рядків7353
    N селекторів5140
    N оголошень4619
    N екранів5637
    числових тегів усього270143

    Нуль у рядку «рівень» і робить решту читабельною. Перевірка, що знаходить хибним усе, підозріла так само, як та, що не знаходить нічого; одна сім'я, яка повернулась цілком чистою, каже, що парсер і корпус згодні, а дрейф справжній.

    Словник вичитано зі сторінок, а не обрано. loyalty-rung.html публікує «49 селекторів · 61 правило», а її файл міряє 67 селекторів і рівно 61 правило - тобто стенд уже розрізняє два слова, і перевірка це розрізнення береже: селектор це один член заголовка правила через кому на будь-якій глибині, правило це один блок. pdp-tabs.html закріпила інші два: 85 рядків і 102 оголошення, обидва точні сьогодні, проти застарілого числа селекторів. У двадцяти сторінок був правильний підрахунок рядків і у двадцяти семи - оголошень, і саме так конвенції підтверджені, а не вигадані.

    Закінчення їде разом із числом, бо ці теги це рендер-текст. button.html віддавала «461 рядків», де 561 хоче «рядок»; breadcrumb.html - «22 екранів», де число хоче «екрани». --apply пише те закінчення, якого вимагає нове число: 1 -> рядок, 2-4 -> рядки, 5+ -> рядків, а 11-14 беруть останню форму всупереч останній цифрі.

    І перший --apply зіпсував тринадцять тегів, ще до будь-якого коміту

    Зіставлення тега трималось лише за початок рядка, тож воно читало голову СКЛАДЕНОГО твердження - «3 екрани + значок на 14», «14 екранів, діалог на 5», «291 оголошення без елемента» - як число, яке впізнає, і перезапис міняв увесь тег на два слова. Два з трьох були навіть не про ту саму величину: 291 у cookie-banner це оголошення, які не збігаються з жодним елементом. Відкочено, і зіставлення тепер вимагає, щоб тег був ТОЧНО число + іменник; усе довше це твердження саме по собі й іде в «не дістає». Та сама сім'я, що й строкова заміна в btn-rank.mjs на 8.31, і спіймана так само - поглядом на те, що прилад написав.

    44 числові теги названо недосяжними, а не пропущено мовчки: 13 складених тверджень і 31 корпусне число, якому потрібен браузер і інше питання («106 екземплярів», «470 лічильників», «5 291 входження»). Ті тринадцять і далі несуть те, що несли: їм потрібна людина, яка знає, що означає кожне речення, а не регулярка.

    І прочерк, прочитаний як нуль, уже встиг знищити два опубліковані числа

    Перевірка завалила product-thumb.html за хвилину після того, як сторінку написали: «1 екран» проти клітинки реєстру, де стоїть «–». Реєстр мав рацію. inventory.mjs читав ту клітинку як sc ? Number(sc[0]) : 0, і то було свідомо - коментар поруч казав «відсутнє читається як 0, а не як невідоме», і це була правда, доки в кожному рядку стояло число. Зламав його product-thumb.css: він не оголошує жодного власного класу, тож обхід за якорями не може порахувати його екрани взагалі. Межу приладу сплющили у факт про продукт - і --apply той нуль уже застосував: counter.html поїхав із «19 екранів» у «0», icon.html із «39» у «0». Обидва повернуто, обидва тепер у «не дістає», і це чесний стан: підтвердити 19 чи 39 сьогодні в цьому репозиторії нічим. Прилад, який не вміє сказати «не знаю», каже число.

    ПИТАННЯ I, 17.08.2026: рівень записано в ЧОТИРЬОХ місцях, а перевірялись два. Файл оголошує (level N); inventory.md кладе його рядок в одну з трьох таблиць; index.css імпортує його в одну з трьох груп; design/kit/_nav.js ставить його сторінку під один із трьох заголовків. C і D звіряли перші два. Драбина це вся архітектура цього етапу - атом, імпортований після молекул, може бути ними перебитий, тобто рівно та інверсія, задля якої порядок і існує, - а на останні два ніхто ніколи не дивився.

    файлфайл кажеindex.cssреєстр стенда
    product-thumb.css121
    menu.css231
    upsell.css233

    Розбіжність із написаною поруч причиною це не дефект: upsell.css несе чотири рядки про те, чому імпортується там, де імпортується, а product-thumb.css не ніс нічого - тож перевірка питає про коментар і розділяє ці два роди у звіті. product-thumb.css переїхав у групу атомів, і tree-diff по п'ятьох екранах на обох ширинах знайшов усі відмінні рядки всередині схованого піддерева .wf-bar і жодного поза ним.

    Два рішення власника, і це різні питання

    • menu.css: три розміщення і три відповіді - файл каже молекула, імпорт каже організм, реєстр стенда каже атом. Одне з трьох правильне, і в джерелі немає нічого, що сказало б яке.
    • upsell.css: два НЕЗАЛЕЖНІ розміщення згодні між собою і незгодні з файлом - і імпорт, і реєстр звуть панель Pro організмом, і лише її власний вступний коментар каже молекула. Коли два розміщення сходяться проти декларації, помилка радше в декларації - але рівень це архітектурне твердження, тож рухається озвученим рішенням.
  10. 16 селекторів у шарі компонентів не збіглися з жодним елементом. Знайдено 17.08.2026 приладом tools/dead-sel.mjs, зібраним саме під це питання, бо його тут не ставив ніхто: inert.mjs питає, чи перебите ОГОЛОШЕННЯ, і селектора без елемента не бачить структурно - там немає програшного оголошення, яке можна знайти. Два вже ловили руками в одному файлі, і другий лише тому, що перед ним був перший: coach-order.css утратив .od-back на 8.7 рахуванням примірників і зберіг .od-line:last-child чотирма рядками нижче аж до 8.52.

    2925 селекторів у 84 файлах (2215 різних), спитано в браузера на 263 сторінках, що підключають system/index.css: 16 мертвих, 365 умовних із живим господарем, 6 народжуються в акті (тост, оголошений разом із рядком, який його будує), 4 цей рушій не приймає (::-moz-range-*).

    Сім із шістнадцяти це одна форма - список через кому, дописаний заради симетрії, де елемент має лише один член.

    файлживемертве поруч
    button.css.btn--outline .uiv-brand · .btn--s.btn--accent · .btn--ghost · .btn--l
    field.css.field-grp > .btn--accent> .btn--outline · > .btn--ghost
    empty-state.css.emptybox .et:first-child · .es:last-child.empty .et:first-child · .es:last-child

    Останній найгостріший, бо файл уже записав це правило чотирма рядками вище: «.errbox .et ніде не буває :first-child, і селектор, доданий під нього, не збігся б ні з чим. Виняток, що нічого не вкриває, валить перевірку так само гучно, як незадекларований випадок; правило теж». А тоді написав два.

    Решта дев'ять не одна сім'я і не одне рішення:

    селекторфайлщо це
    .pcard.dim .pold · .pcutproduct-card.cssпритемнені картки є, закреслені ціни є, жодна картка не є обома
    .pdp-tabs .tprice:not(:has(.told)) .tnewpdp-tabs.cssціна без старої ціни - у демо-товара вона завжди є
    .skcard:not(:has(.skb))skeleton.cssкартка скелета без блоку кнопки
    .pl-hw .pl-ic:emptyspec-table.cssслот значка, у якому нічого немає
    .wfh-meta .wfh-loc .uiv-ic:last-child svgheader.cssгосподаря теж немає
    .btn--stack .tl .uiv-ic svgstack-action.cssгосподаря теж немає
    .resend afield.cssблок будує скрипт, і посилання в ньому немає
    .coach .upsell p bupsell.cssабзац панелі Pro втратив жирне слово

    «Мертвий» тут означає «не збігся на цих 263 сторінках», а не «не може збігтися ніколи» - і лікуються ці два роди по-різному: правило без можливого господаря видаляється, а комбінація, якої корпус не показує, це питання про демо-дані. Прилад повідомляє факт і відмовляється вгадувати; прочитання за людиною.

    ЗАКРИТО 17.08.2026: шістнадцять прочитано, дванадцять видалено, чотири лишено з причиною. dead-sel 0

    Кожне з дванадцяти видалень несе прочитання поруч із правилом, і кожне з них це речення про ПРОДУКТ, а не про селектор: бренд-мітка називає стороннього провайдера, а провайдер ніколи не є єдиною дією регіону і ніколи не привид (button.css, три); контрол, приварений до краю поля, це той, що поле надсилає, тобто акцент за рангом (field.css, два); .wfh-loc тримає одну мітку, а каретка належить лише мовному меню (header.css); .tl це підпис таббару, вписаний у складений контрол так, ніби два підписи взаємозамінні (stack-action.css); кожен .empty носить гліф над заголовком і дію під тілом, тобто рівно те, що абзац чотирма рядками вище вже вивів (empty-state.css, два); жирне слово панелі справжнє в одній із двох її форм абзацу (upsell.css).

    Два видалення варті окремого рядка. .resend a був чотирма оголошеннями для посилання, якого немає: .resend тримає відлік у <span>, бо доки йде відлік, тиснути нема на що, а живе посилання це <a class="pf-resend"> в .otp-note, яке вже малює checkout-form.css:50. Мертве правило було дев'ятим двійником того самого контрола, на один токен інакшим, на розмітці, якої ніколи не існувало - тож дивлячись на екран, знайти його було неможливо. .skcard:not(:has(.skb)) був правильним того дня, коли його написали (8.24, для двох названих тренерських екранів), і корпус з-під нього поїхав: сьогодні дванадцять .skcard і жодного без .skb, а на тих двох екранах слово вціліло тільки в коментарі. Це і є аргумент за обхід усього корпусу, а не того, що крок зачепив.

    Чотири лишені оголошені в tools/dead-sel.mjs як KEPT_ON_PURPOSE, кожен зі своєю причиною, і контроль там валиться в обидва боки: запис, який ожив, означає, що випадок настав і нотатку час прибрати; запис, що називає селектор, якого не оголошує жоден файл, означає, що виняток пережив своє правило. Три це стани КРАМНИЦІ, яких немає в демо-каталозі - товар за повною ціною (pdp-tabs.css), товар, якого немає в наявності і який водночас зі знижкою (product-card.css, два). Четвертий - дзеркало тоста: .pl-hw .pl-ic:empty вбивається актом, бо розмітка везе слот порожнім, а design/_nav.js:1461 заповнює всі три на кожному завантаженні, тож на момент будь-якого заміру :empty хибне всюди.

    2925 селекторів до, 2913 після, і кількість живих не змінилась - 2534. Це і є доказ, що нічого живого не зачепили. Пікселі: tree-diff --dir по всіх 88 продуктових екранах на обох ширинах, 176 порівнянь, зрушило 0 елементів.

    І еталон довелось зібрати, бо tree-diff HEAD на це питання не відповідає

    Проти HEAD він каже «зрушило 4», і всі чотири належать попереднім крокам, які досі лежать у дереві незакоміченими - перевішування межі на coach-order (8.52) і 560 на coach-verify-loading (пункт 2). Гірше: без названих сторінок він питає git, які design/*.html змінились, і отримує дві, жодної з яких правка стилів не зачіпає взагалі - зміна в шарі компонентів торкається кожної сторінки, що його підключає, і жодного html-файлу. Тож еталон це робоче дерево, у якому лише десять таблиць стилів повернуто з HEAD, і --dir порівнюється з ним. Порівняння, чиї дві сторони різняться більше, ніж тим, що міряють, це не доказ.
Список 4 - що знайшов крок 1 етапу 09 і навмисно не полагодив

Крок із патерном - це рефакторинг, і його приймання - нуль зрушених пікселів. Кожне значення нижче переїзд зробив видимим; зняти його - окреме рішення у формі «змінна -> значення -> чому», і жодного з них тут не ухвалено. Вкласти зміну значення в переїзд - це рівно те, як рефакторинг перестає бути доказовим.

1. Ряд дій написаний п'ятьма різними відступами для однієї роботи. tools/pattern.mjs: одна композиція, 70 сірих і 58 кольорових екранів, під 53 іменами контейнера. Із шістнадцяти, що несуть правило, відступ це --space-12 десять разів, --space-8 чотири, голий 9px тричі, голий 10px двічі й --space-16 раз. 9px і 10px не на щаблі - драбина 4 / 8 / 12 / 16 - і coach-clients.css уже записав це у власному коментарі: «третє число на чотирьох рядах дій». Після переїзду кожне відхилення - одне оголошення в одному файлі, написане як .x.actions{ gap }, щоб переважити патерн.

ЗміннаСьогодніКандидатЧому не вирішено тут
.coach .cl-acts gap9px--space-81px на чотирьох тренерських екранах, і чотири ряди мають спершу узгодитись між собою
.coach .ccard-acts gap9px--space-8той самий 1px, на картці клієнта
.coach .oc-actions gap9px--space-8той самий 1px, на картці замовлення
.coach .cc-cta gap10px--space-122px, і це власний заклик екрана до дії
.coach .od-acts gap10px--space-122px на замовленні тренера
.coach .ord-acts gap10px--space-122px у кабінеті тренера
.addr-acts gap--space-8--space-12уже на щаблі; питання в тому, чи дії картки адреси навмисно тісніші
.aord-actions gap--space-8--space-12те саме питання на рядку замовлення
.cshelf .cs-act gap--space-8--space-12те саме питання на полиці довіри
.ci-links gap--space-16--space-12єдиний, що ШИРШИЙ за патерн, і він тримає два текстові посилання, а не дві кнопки

2. Два ряди дій не переведено, і обидва названо. .ceact і .cedlg .act - власний ряд діалогу клієнта, вісім сірих екранів і два кольорові: його розмітку будує wireframes/_nav.js, спільний скрипт ОБОХ корпусів, а сірий корпус цей етап не редагує. .sys-acts - ряд службової сторінки, нуль кольорових входжень, тож доводити пікселями нема чого. Етап 12 перезбирає обидва набори екранів і візьме патерн тоді.

3. Продуктова колонка сторінки лежить у файлі, який не входить у систему. .wf-canvas і .wf-page стоять на 129 і 122 сірих екранах, а оголошені в design/_stand.css, який починається словами «хром прототипу і стенда, НЕ частина системи». .wf-page{ max-width: 1200px } - це не хром, це контентна колонка продукту, і етапу 10 вона знадобиться. Лишено на місці навмисно: розміщення файлу - записане рішення кроку 7.26, і виносити продуктову розкладку з нього - рішення власника, а не побічний ефект кроку про патерни.

4. У системі немає класу, що означає «це головна дія екрана». І два документи проєкту суперечать одне одному в письмовому вигляді. DESIGN.md, рядок 44: «One orange per view ... A second filled orange button on a screen means the screen has not decided which step is the main one». button.css, рядок 20: .btn--accent це «the one action of a REGION». conventions.md, рядок 130, на боці зони. Продукт слухає зону на кожному екрані списку, тож застарів саме рядок у DESIGN.md - а його новий читач зустрічає першим, бо він стоїть під заголовком «The rules colour obeys». Кольоровий шар не має чим перевірити жодне з двох прочитань. Видимих .btn--accent буває 13 на екрані, бо акцентну кнопку «У кошик» носить кожна картка; власна позначка сірого шару dark доходить до 5. Фініш і є ранг, і від рангу вимагають означати дві різні речі. Чи потрібна системі окрема роль btn--primary, чи правило належить зонам і класом не перевіряється - рішення власника.

5. .acc-main не оголошений жодним файлом компонента. Стоїть на 43 сірих і 31 кольоровому екрані другою половиною оболонки кабінету, поруч із .acc і .acc-nav, які account-shell.css оголошує. Те саме з .stack, .navlink, .ctrl, .frange і .wfh-cabbtn. Мертвими вони не є - tools/dead-sel.mjs ставить протилежне питання й відповідає 0 - це класи, які носить розмітка і яких не називає жоден стиль системи.

6. Власний текст роадмеп-сайдбара - під 4.5:1, в ОБОХ темах, на кожній сторінці, що його несе. tools/theme.mjs, заміряно: a.nav-top «Дослідження» 4.14 темна / 4.33 світла проти rgb(242,241,238), 14 входжень; a.nav-link «Чому саме так» - та сама пара; підпис рядка «дизайн-процес» - та сама; span.nav-badge-soon - 3.79 / 3.79. Колонка «світла» й каже, чия це провина, і вона каже, що тема не винна: дефект старший за темну тему і живе в /_nav.css, у вигляді кореневого реєстру.

Крок 3 етапу 09 його не створив, але розширив його радіус на одну сторінку: віддавши why.html роадмеп-панель - чого пак вимагає від пункту роадмепу - він завів у це читання другу сторінку design/. Предмет обходу це design/, тож звіт називає дві сторінки; панель стоїть на кожному хабі етапу в репозиторії, тож справжній радіус - усі вони.

Не полагоджено тут із причини, яка є правилом, а не вподобанням: /_nav.css - це вигляд реєстру проєкту, він не належить жодному етапу дизайну, а його чорнило це значення. Змінити його - це «змінна -> значення -> чому», сказане вголос власником. Замір - те, що цей крок був винен.

Список 5 - тест самодостатності, етап 09 крок 5

Наступна реальна сторінка продукту, зібрана з готової системи й нічого більше: вузол 2.2, Ціль-колекція, база плюс три стани, чотири файли. Обрано власником із 54 сірих екранів без кольорового двійника, за мірою, яку називає пак: екран накриває 38 із 84 компонентів, більше за будь-якого іншого кандидата, і стоїть у флоу між двома вже пофарбованими (index -> goal -> listing).

На екрані не написано жодного стилю. Чотири файли не несуть ні елемента <style>, ні атрибута style; вони вантажать system/index.css і хром стенда, як кожна інша сторінка продукту. Усе нижче - те, чого система не змогла, записане, а не домальоване руками.

Чого бракуєДля чого знадобилосьЯкий рівень системи закриваєПріоритет
.gnote - примітка під гридом, що пояснює порядок карток за замовчуванням, не має ні компонента, ні правила ніде в системіgoal: колекція за ціллю сортується інакше за звичайний лістинг, і екран мусить це сказатикомпонент (тиха примітка під блоком) або варіант seo-textсередній - сьогодні це один абзац на одному екрані, але його нестиме кожна колекція за ціллю
.actions не має inline-варіантаgoal-empty і goal-error: ряд дій порожнього стану це inline-flex по центру, тобто він стискається під відцентрованим блоком. Патерн - flex, тобто розтягуєтьсяваріант патерна (.actions--inline)середній - саме тому .eact не переводили на кроці 1, і це стосується кожного порожнього стану продукту
.ctrl не оголошений жодною таблицею стилівусі чотири екрани, і listing до нихкомпонент або видалення - клас, який ніхто не малюєнизький - уже записано пунктом 5 списку 4, тут підтверджено на новому екрані

І одне, що НЕ є дірою системи, назване, щоб його за неї не прийняли. Комірка «Списком» у перемикачі вигляду на goal - мертвий <span>, бо goal-list.html не існує в продукті взагалі. Це відсутній екран, тобто рішення IA, записане на стенді view-toggle ще з етапу 08 як єдиний справжній дефект цього контрола. Кольорова копія успадковує його без змін; намалювати йому вигляд «недоступно» означало б вигадати стан, від чого крок 7.31 уже відмовився для чипа з тих самих підстав.

Беклог не порожній, і це та відповідь, яку крок був винен. Три діри системи й одна діра IA - з екрана, який людина інакше назвала б готовим.

Ще дві діри, знайдені проходом критики й позитивним контролем, а не на око.

Чого бракуєДля чого знадобилосьРівеньПріоритет
pagination.css не малює власних комірок. .pages a не отримує від компонента ні коробки, ні рамки, ні розміру; на listing кожне посилання вдягли руками на етапі 08 як btn--outline btn--icon btn--s. Тому пагінація нового екрана рендериться голим текстом, і карта фінішів цього не полагодить: посилання не носять жодного класу-ідентичності, тобто ключа, з якого читати фініш, не існуєgoal - колекція за ціллю посторінковакомпонент (пагінація має малювати .pages a сама, як button.css відмовляється малювати голий .btn)високий - єдина знахідка тут, що робить контрол невидимим, і вона дістає ще шість кольорових екранів
Посилання «наступна сторінка» не має доступного імені. <a href="?page=2">›</a> - шеврон і більше нічогоgoal, і та сама розмітка стоїть у сірому шарі ще шести кольорових екранівмікрокопі плюс розмітка, власність сірого шарусередній

Клавіатурний прохід читали проти контролю, а не окремо, і це змінило звіт. Перше читання goal казало «78 фокусованих елементів без кільця фокуса» і список цілей менших за 44px. Та сама проба на listing, прийнятому двійнику, відповідає 78 і той самий список - тобто обидва належать спільній оболонці й жодного з них тут не заведено. Що контроль справді виділив - одну дельту: три безіменні фокусовані проти двох у двійника, і третій це шеврон пагінації вище. Знахідка, яку обидва екрани поділяють, - це знахідка про корпус; новина лише в різниці.

І одна, що дістає далеко за межі цього екрана - знайдена позитивним контролем критики. clone-to-colour.mjs, рядок 138, завжди дописував btn--s кожному контролу, який ранжував - кнопку 40px, - тоді як зібрані руками екрани пишуть btn--accent btn без розміру і отримують власні 52px із button.css. Тобто головна дія порожнього стану виходила нижчою за поріг дотику 44px на кожному екрані, який трансформ коли-небудь клонував, і ніщо про це не казало: кнопка має ранг, вона видима й натискна, і побачити це можна лише порівнянням із двійником, зібраним руками.

Розкол чистий, і він же доказ: listing-empty, listing-error, cart-empty, product-oos - зібрані руками - несуть 0. account-empty несе 5, coach-home-empty 3, обидва клоновані. По всій теці design/ вигаданий розмір стоїть на 114 контролах на 43 екранах.

Прилад полагоджено (ранг читається з dark сірого шару; розмір сірий шар давати не має права), і чотири екрани цього кроку приведено до вигляду двійника. Решти 43 не чіпав: зняти розмір зі 114 відвантажених контролів - це зміна значення по корпусу, тобто «змінна -> значення -> чому» і рішення власника, а не побічний ефект кроку про патерни. Кожен із них - головна дія, у яку має влучити палець.

Список 6 - єдина дірка, яку відкрила темна тема, етап 09 крок 6

tools/theme.mjs по 276 із 280 кольорових сторінок: чорнило проти власного ґрунту, поріг 4.5:1. 35 форм стоять під ним. 34 з них провалюються і в СВІТЛІЙ темі - отже вони старші за тему й належать A10, уже записаному рішенню про акцент на блідому: #FF5A00 на блідому ґрунті це 3.13:1, і кожен підпис btn--accent це успадковує.

Рівно одну форму зламала САМЕ тема - і в цьому вся цінність прогону.

ЩоСвітлаТемнаДе
span.hptag - надзаголовок першої промо-плитки головної, «Акція тижня»5.452.97home-buyer · home-cart, 6 входжень

Плитка малює ґрунт через var(--bg-page) під фотографією (banner.css:108), а надзаголовок бере --text-action лише на першій плитці (hero.css:29). У світлій пара працює, бо блідий ґрунт лежить під світлим фото; у темній ґрунт інвертується, а фото ні - і чорнило втрачає опору, хоча сама роль має обидві половини. Роль може мати пару й усе одно провалитись: пара - це про токен, а контраст - про ПОВЕРХНЮ, на яку роль лягла. Це третя вісь, яку записав етап 08, і це її перший справжній улов.

Тут не полагоджено, і це навмисно

Рішення про значення в формі, якої вимагає проєкт - змінна, значення, чому - і воно власника: або надзаголовок перестає читати --text-action на фото-плитці, або фото-плитка отримує власну роль-серпанок. Вибір тут згорнув би зміну значення в крок про патерни.
Знято при верифікації - і обидва були мої

Прохід дизайн-рецензії посперечався з двома рядками вище, і джерело обидва рази розсудило проти мене. Знята знахідка лишається видимою з причиною, або вона повертається наступного разу тими самими словами.

«pagination.css не малює власних комірок» - ЗНЯТО. Компонент оголошує ряд, стан «недоступно» і заливку поточної комірки, а коробки не малює навмисно: комірка і є кнопкою, складеною на екрані як btn--outline btn--icon btn--s - рівно те, що пише прийнятий двійник listing.html:184. Системі не бракувало нічого; класів бракувало моєму екрану, разом із aria-current та ім'ям шеврона. Заміряно до правки: комірки 9.6 × 25.6px голого тексту проти 40 × 40 на двійнику, і Tab малює дефолтний синій контур Chrome на теплому нейтральному тлі. Полагоджено проходом у clone-to-colour.mjs, бо карта фінішів не дістає посилань без класу-ідентичності.

«.gnote потребує компонента» - ЗНЯТО, і правда протилежна: розмітку треба було прибрати. badge.css фіксує рішення письмово - .gnote це анотація сірого прототипу, «the coloured clone dropped it, correctly, which is why it renders on 0 of 39 coloured screens», - і клас пішов із системи на кроці 8.10. Двійник тримає те саме правило html-коментарем, «kept out of the visible UI». Мій екран був сороковим і єдиним, хто його малював: 16px повним чорнилом, найгучніший блок нижньої половини сторінки, гучніший за SEO під ним. Замовити під нього компонент означало б повернути в систему рівно те, що система свідомо з себе прибрала. Видалення робили руками на 8.10, тож трансформ його не знав; тепер це прохід.

І одну загострено, а не знято. Перемикач вигляду гірший за «мертву комірку Списком»: на goal обидві комірки це <span> - сірий оригінал пише їх так, тоді як wireframes/listing.html пише обидві як <a href>, - тобто весь контрол випав із порядку Tab, продовжуючи рекламувати cursor: pointer. Це дефект замороженого сірого шару, і він потребує власника, а не кольорової латки.

Спліт вмикався за ЕКРАНОМ, а рамці треба було МІСЦЕ - ЗАКРИТО правкою після критики

Заміряно на design/coach-clients.html, рамка спліта і дві її колонки:

В'юпорт.clsplitРейка (фіксовані 17.5rem)Деталь
860528280224
960628280324
1024692280388
1280732280428
1440 і далі868280564

Від 860 приблизно до 1010 деталь вужча за список, а на самій точці вона 224px - вужча за телефон. Це не поламано: .cdetails несе контейнерний поріг на 22rem, тож рядки «підпис - значення» складаються в одну колонку і панель читається. Але причина та сама, що зробила --grid-col-min-panel 19rem замість 22rem на кроці 4: оболонка кабінету забирає власну колонку навігації 268px, тож .acc-main на в'юпорті 860 - це бокс 528.

@media питає про ЕКРАН, а цій рамці потрібна відповідь про МІСЦЕ. Відповідь драбини - container-type: inline-size на .acc-main і @container на .clsplit: спліт вмикався б тоді, коли для нього є місце, а не тоді, коли широке вікно. Дві причини, чому це не взято всередині кроку 5, і обидві важити власнику:

  1. Це міняє, КОЛИ спліт з'являється, тобто рішення, назване вголос, а не рефакторинг.
  2. Кольоровий корпус не може заміряти це чесно: власна рейка роадмепу стенда з'являється на 1076 і роняє .acc-main із 692 назад до 528, тож контейнерний запит блимав би при перегляді копій і був би правильним у продукті.

ЗАКРИТО, і ціна вийшла на один рядок більша за кошторис. Спершу заміряно: нуль position: fixed усередині .acc-main на всіх трьох екранах клієнтів, тож контейнер безпечний. Кошторис помилився в одному місці: голого @container замало, бо місце немонотонне у в'юпорті - він вмикав спліт нижче 860 (там немає колонки навігації, бокс 828) і вимикав між 860 і 960 (оболонка забирає 268, бокс 532). Правило тепер @media (min-width: 860px) з @container (min-width: 41rem) усередині: спершу оболонка, потім місце. Спліт відкривається на в'юпорті 990 з панеллю 354px, і 224 більше немає.

Початковий кошторис, для запису: один container-type на .acc-main, один запит переїжджає в coach-clients.css, і wfClientSplit() перестає читати --bp-shell-wide через matchMedia, а питає ВИХІД - getComputedStyle(pane).display !== 'none', - тобто рівно те, що цей репозиторій питає скрізь. Спершу перевірити, що всередині .acc-main не живе нічого position: fixed: contain: layout перезакріпило б його на себе, і саме тому рама сторінки не могла стати контейнером на раунді 4.

20 сторінок стенда описують ширину, якої в компонента вже немає - етап 10, винне крокові 6

Заміряно по всіх 84 сторінках компонентів: числа (min|max-width: Npx), написані на сторінці, проти чисел, які файл компонента справді тримає після зняття коментарів. 22 сторінки назвали ширину, якої в їхньому власному файлі немає, крок 5 полагодив дві, яких торкався, лишилось 20.

СторінкаКажеУ файлі
account-shell640, 959, 960620, 859, 860
auth-dialog719, 720, 899, 900859, 860
checkout-form479, 480, 559619, 620, 860
coach-cabinet520, 640, 720619, 620
coach-landing559, 980619, 620, 860
coach-verify520, 760620, 860
footer479, 720619, 860
menu859619
pdp-tabs1180860
system-page720620, 859
trust-strip479619, 859, 860
buy-box · city-dialog479619
hero720860
address-card · button · field · loyalty-rung · product-grid · restock-noteрізнеу файлі немає жодної

Не всі 20 - дефекти, і саме тому це список, а не правка. Сторінка стенда має право називати ІСТОРІЮ: «було 720, стало 640» - це запис, і запис може тримати старе число. Не має права ПРАВИЛО, яке його називає: coach-clients тримав (min-width: 640px) -> .clist у дві колонки у таблиці «Межі» як чинну межу, через чотири раунди після того, як це число перестало існувати. Розділити одне від одного можна читанням кожної сторінки, а не регуляркою.

Сьогодні це не перевіряє ніхто, і в дірки є форма. tools/bp.mjs навмисно виключає стенд зі свого предмета - «у стенді, і це не предмет: 17», - бо сторінка стенда законно показує CSS, який не є продуктовим. Тож числа, які стенд пише ПРОЗОЮ, не перевіряє ніхто, а етап 10 зрушив 27 із них. Перевірка дешева (порівняння вище - п'ятнадцять рядків) і належить або п'ятим класом у bp.mjs зі стендом як явним другим предметом, або в inventory.mjs, який уже читає кожну сторінку стенда й кожен файл компонента і вже падає на дрейфі meta.

Рейка роадмепу стенда перебудовує сторінку продукту, і тепер це міняє, ЯКУ розкладку ви бачите

Заміряно на design/coach-clients.html, розгортка кроком 10px від 320 до 1600: спліт відкривається на 990 (.acc-main 658), закривається на 1080 (532) і відкривається знову на 1210 (662). Падіння на 1080 - це власна рейка роадмепу стенда, що з'являється на 1076 і штовхає сторінку: кольорові копії на ~216px вужчі за продакшн вище цієї ширини.

Це було правдою завжди і не важило досі. Кожна ширина, яку міряв цей етап, міряна з рейкою в сторінці, але з @media рейка зсувала лише числа. З @container вона вирішує, яку РОЗКЛАДКУ дістає сторінка, тобто засіб перегляду дістав голос у композиції продукту. У продукті рейки немає і розгортка дає один перехід на 990.

Три виходи, жоден не безкоштовний:

  1. Рейка накриває, а не перебудовує. Правильно по суті - це хром для розглядання продукту, а не його частина, - але вона закривала б вміст рівно на тих ширинах, де з'являється.
  2. Рейку глушать на час заміру, і всі прилади відкривають сторінки без неї. Дешево для приладів, але тоді ніхто ніколи не ДИВИТЬСЯ на те, що прилади міряють.
  3. Лишити і друкувати. Те, що стоїть сьогодні: tools/split.mjs друкує кожен перехід разом із боксом, який його спричинив, тож мерехтіння лежить у виводі кожного прогону, а не в чиїйсь пам'яті.
Два борги, які власник закрив рішенням - етап 10

Пошук у шапці: обрано «зняти підписи з дій». Зроблено КОНТЕЙНЕРНИМ питанням, а не точкою, тож третій брейкпойнт не знадобився: місце кінчається в РЯДУ, а ширина ряду - не ширина вікна (він обмежений 1200 і має падінги), тож медіазапит міряв би не той бокс. container-type: inline-size на .wfh-main, flex: 1 1 18rem на пошуку, і на @container (max-width: 63rem) слова йдуть. Поріг - це сума, яку ряд мусить втримати зі словами: 65 (лого) + 198 (навігація) + 18rem (підлога пошуку) + 408 (дії зі словами) + 4 зазори.

Слова сховані від ОКА, а не від читача. display: none зняв би доступне ім'я з чотирьох контролів, чий єдиний текст це і є - «Увійти» це вся назва тієї кнопки, - і проміняв би тісне поле на чотири безіменні іконки.

Закрито наполовину, і кошторис помилявся про другу половину. Він казав, що пошук дістане ті 408px. Заміряно після: дії віддають 44, а не 408 (408 → 364), бо кнопки лишають іконки, падінги і бейджі. Поле йде 44 → 88 на точці, 84 → 128 на 900, 204 → 238 на 1010, слова повертаються на 1040. Тобто подвоїлось і все ще тісне між 860 і ~960, а решту з'їдають .wfh-nav (198) і чотири коробки дій (364) - жодне з них не пошукове.

Дешевий наступний крок - мікрокопі, а не розкладка. На тому самому контейнерному порозі плейсхолдер міг би скоротитись із «Пошук товарів, брендів...» до «Пошук»: на 88px довгий показує «Пс», короткий читається повністю. Це продуктовий рядок, тож він належить microcopy.md і рішенню, а не правилу компонента.

Бонус-іконка: обрано нову монету. У наборі було 67 марок і жодна не називала ГРОШІ, тож «Бонуси» носили star, поки три дії поруч називали свою роботу. Новий coin - два концентричні кола на власній сітці набору 24×24 при обведенні 1.9: без блиску і без плюса, бо голос забороняє святкувати баланс. Рядка ніде не знадобилось: icons.html малює набір живим із design/system/icons.js і сам про це пише, «другої копії набору немає ніде», тож гліф з'явився на стенді тієї миті, коли почав існувати. Перевірено в браузері.

У системи п'ять visually-hidden оголошень написані двічі

menu.css несе їх на .menu-src, і тепер header.css несе ті самі п'ять на підписах дій. Це класичний патерн і він правильний в обох місцях, але друга копія - це те, з чого починається третя. Системі потрібна ОДНА утиліта - клас у base.css або плейсхолдер, - і обидва місця мають на неї вказувати. Дрібно, механічно, і належить тому, хто наступним відкриє base.css.

Борги, закриті цим проходом - етап 10

Темна дірка закрита, і діагноз у беклозі був неправильний про механізм. Він казав --bg-page у banner.css:108. Заміряно: це --bg-inverse у hero.css:29. «Inverse» означає «протилежне сторінці», тож уся сім'я перевертається злагоджено - вугілля у світлій, warm-50 у темній, і --text-oninverse перевертається разом. Не перевертається одне: --text-action, помаранчевий бренду. Та сама фарба зустрічала темний грунт, а потім блідий.

Нова semantic-сім'я, чиї дві половини навмисно рівні: --bg-media, --text-onmedia, --text-onmedia-muted, --line-media. Це не відсутня пара - обидві половини написані, і рівність є рішенням. Аргумент: промо-панель це ПОВЕРХНЯ-КАРТИНКА, а дві плитки поруч несуть справжні фотографії, які теми не вчать. Смуга вже була наполовину незалежною від теми, і перша плитка була відступником. Заміряно після: 5.45 в обох темах, грунт однаковий.

20 сторінок стенда: 49 привидів, і 11 із них законні. Читано посторінково, а не регуляркою, бо сам беклог писав, що регулярка не відрізнить запис від правила. Дев'ять сторінок несли застаріле чинне твердження і перезібрані - переважно секція «У файлі N медіа-умов», яка перелічує умови файла як факт; тепер ці списки генеруються з файла, а не набираються. Ще три - таблиці «Межі» тренерських сторінок. Вісім сторінок називають історію, і це законно. Три стилюють власні демо-таблиці власними запитами - це розкладка стенда, а не компонента, і перший замір порахував їх помилково.

І тепер це перевіряється, що й було справжньою знахідкою. inventory.mjs дістав клас H2: він і так читає кожну сторінку стенда і кожен файл компонента. Обидва законні класи оголошені списками і обидва мають холостий контроль - сторінка в списку, яка більше не несе привида, валить прогін так само гучно, як неоголошена. Обидва класи провалу доведено внесенням і відкотом.

Ховер, доданий щоб полагодити відсутній ховер, не малював нічого. Спіймав tools/vars.mjs у тому самому проході, що його вніс. Нове правило брало --bg-hover - ім'я, яким цю роль називає власна проза етапу 08, - і такий токен не оголошено ніде. Невизначена змінна це найтихіший провал, який має CSS: оголошення стає невалідним на обчисленні, тло падає у початкове значення, і ніхто нічого не каже. Полагоджено повторним ужитком: --bg-sunken це те, що бере кожен інший наведений рядок системи. Відкрите питання - проза, а не код: документація етапу 08 називає стан-токен, якого ніколи не існувало, тож наступний читач потягнеться по нього знову.