Решили: всё кликабельное, что построено на VisualElement (чип, слот, карточка релика,
карточка сосуда, карточка лавки, строка запаса, строка сброса, образцы цвета и курсора, крышка
сундука, карточка арканы), получает focusable = true; строки настроек — НЕ получают, у них фокус
принимает вложенный контрол.
Почему: правила .gm-chip:focus и .gm-slot:focus стояли в теме и выглядели работающими, но
VisualElement фокус не принимает по умолчанию — состояние не наступало ни разу. Гейт состояний
зачитывал их как покрытие, потому что проверяет объявление, а не достижимость. Практическая цена
не в красоте: на Steam Deck курсора нет, и без фокуса выбор награды, покупка в лавке и надевание
снаряжения оказываются недостижимы. Отвергли вариант «фокус только у кнопок» (дешевле сейчас, но
геймпадная навигация стала бы отдельным заходом на те же файлы) и вариант «focusable только у
того, что ведёт к выбору» (граница «ведёт к выбору» пришлось бы проводить заново на каждом новом
элементе).
Сказано: обязательный набор состояний и решение про фокус — вердикты Макса от 06.08.2026: наведение, нажатие, выключенность и фокус у всего кликаемого; отклик строки настроек — «полоса подсвечивается целиком». Формулировка правила про полосу — его же, от 26.07.2026: «Нет, полоса везде. Вдруг просто навестись захочется, хихи. КОНСИСТЕНТНОСТЬ.»
Грабли: :focus-within в UI Toolkit не существует, поэтому подсветить строку настроек от
фокуса её потомка нечем. Сделать focusable саму строку значило бы поставить Tab две остановки
подряд на одном месте, поэтому у строк требование фокуса снято — и снято ОТДЕЛЬНОЙ КОНСТАНТОЙ
(RowInteractive), чтобы «не нужно» не читалось как «забыли дописать». Второе: :checked держит
сам Toggle, а не строка вокруг него, — контактный лист сначала навязывал состояние корню образца
и показывал отмеченную галочку неотличимой от пустой, хотя правило в теме уже стояло.
Владелец правды: UiComponentRegistry (наборы состояний), конструкторы контролов в
Scripts/UI/Components, тест UiStateGateTests.