Место, где утверждается дизайн-язык приложения. Витрина и экраны импортируют один и тот же компонент из одного места — отдельного кода «для витрины» не существует. Значения приходят из globals.css через design-tokens.ts: витрина не хранит их у себя, иначе разойдётся с системой молча.
У каждого токена подписана роль и замеренный контраст. Свотч без подписи не защищает решение: спорить будут о цвете, а обсуждать надо роль. Клиника переключается классом на контейнере — сплошной бренд и градиенты меняются, поверхности и семантика цикла остаются.
--backgroundСтраница. Тонированная, а не белая: карточка отделяется от неё заливкой--card1.17:1 к страницеПоверхности в потоке: карточка цикла, карточка врача, таб-бар--muted1.03:1 к странице · 1.13:1 к карточкеВложенная плашка: предложение УЗИ, контейнер дня, плитка прививки--popoverВсплывающее: шторка, меню, поповер. Отделяется тенью, а не заливкой--foreground15.50:1 к странице · 18.10:1 к карточкеОсновной текст, заголовки, число «сегодня»--muted-foreground3.00:1 к карточке · 2.66:1 к плашкеПодписи, специальность врача, дни недели, неактивный таб✕ AA для обычного текста требует 4.5:1 — не проходит нигде--brandбелым по нему 5.94:1 (взрослая, болотный #536c20) · 4.58:1 (детская)Сплошной бренд: кнопки, аватар врача, активные состояния, точки--brand-fromСветлый конец градиента карточки приёма, стоп 20.5 %--brand-toбелым 5.94:1 (взрослая)Тёмный конец того же градиента, стоп 74.8 %--brand-onпо шапке 2.10…2.95:1 (взрослая)Значки фактов на карточке приёма; у детской ещё и дата✕ Значки — графика, им нужно 3:1: у светлого ядра не берут--hero-1белым 4.23:1 (взрослая) · 2.23:1 (детская)Светлое ядро градиента у правого низа шапки✕ У детской белый текст на ядре не берёт даже 3:1 — он и не стоит там--hero-2белым 5.00:1 (взрослая) · 3.22:1 (детская)Середина, стоп 50 %--hero-3белым 5.94:1 (взрослая) · 4.58:1 (детская)Тёмный край. Он же заливка под системной полосой--hero-promo-1белым 5.08:1Терракотовое ядро — акцент клиники #b2522c: рекомендация красит шапку иначе, чем приём--hero-promo-2белым 6.24:1Середина: посчитана как середина крайних стопов, стоп 50 %--hero-promo-3белым 7.68:1Тёмный край рекомендации и заливка полосы под ней--hero-tintбелым 2.71:1 (взрослая) · 1.47:1 (детская)Тёплый разлив у нижней кромки: ядро на 0.12 L светлее и на 24° к жёлтому✕ Наносится в 62 %, и только у нижнего края — текста там нет--hero-coolбелым 8.23:1 (взрослая) · 6.80:1 (детская)Холодная глубина дальнего угла. У взрослой — цвет фрейма, у детской — край на 0.12 L темнее и на 42° к синему--hero-promo-tintбелым 3.07:1Разлив под шапкой рекомендации — к жёлтому от терракоты✕ Самый светлый цвет шапки. Белым по нему не набирают ничего--hero-promo-coolбелым 9.87:1Глубина рекомендации: тот же тон терракоты, светлота 0.39--cycle-mensМенструация: заливка кружков дней и цвет фазы. Одинаков во всех клиниках--cycle-fertФертильное окно и день овуляции. Прогноз против факта — светлотой, не цветом--cycle-mens-softПрогноз менструации: базовый цвет на 44 % по белому, считается из него--cycle-fert-softПрогноз фертильного окна: то же правило 44 % по белому--cycle-mens-deepТёмный конец менструации: обводка выбранного дня и цифра на осветлении. По осветлению 6.91:1, по белому 11.97:1--cycle-fert-deepТёмный конец фертильного окна: та же роль. По осветлению 5.10:1, по белому 7.98:1--help-toбелым 4.59:1Светлый конец, стоп 0 % — под текстом--help-midбелым 5.70:1Середина, стоп 45 % — там нет ни текста, ни знака--help-fromбелым 10.19:1Тёмный конец, стоп 100 % — под знаком, его силуэт держит корпус--alert-fromбелым 4.79:1Исходник осветления --alert-soft. Плоскостью больше не рисуется--alert-softтёмным 7.19:1Остров «Скорая помощь — 103» в шторке «Помощь сегодня»--alert-deepпо осветлению 7.19:1Текст на этом острове: заголовок, номер и список признаков--preg-1Начало первого кольца--preg-2Конец первого кольца и начало второго — один стоп на два--preg-3Конец второго кольца и начало третьего--preg-4Конец третьего кольца--border1.24:1 к карточкеДекоративная линия и рамка «сегодня» в полосе дней. Под контрол не годится--input3.62:1 к карточке · 3.20:1 к плашкеГраница контрола: WCAG 1.4.11 требует 3:1, если рамка — единственный признак поля--destructiveбелым 4.79:1Ошибка и отмена. Взят тёмный конец градиента «Нужна помощь сегодня?»--home-indicatorСистемная полоса смахивания. Не бренд и не тема — чужой интерфейс--keyboardПодложка системной цифровой клавиатуры на экранах входа. Чужой интерфейс--keyboard-keyКлавиша системной клавиатуры--keyboard-key-edgeНижняя кромка клавиши системной клавиатурыСчитано по WCAG 2.1 скриптом, а не оценено на глаз.
Палитра снята с макета, и три её роли не берут WCAG AA. Значения не подменены: выбор цвета принадлежит дизайнеру. Ниже — замер, требуемый порог и кандидаты, чтобы решение принималось на числах. Решение принимается на гейте 2.
| Где | Замер | Нужно | Кандидаты |
|---|---|---|---|
| Подписи #849999 по белой карточке | 3.00:1 (по плашке #eaf3f3 — 2.66:1) | 4.5:1 — это обычный текст 14/16 и 12/16 | #748b8b даёт 3.62 / 3.20 — тоже мало. Проходят: #667b7b (4.48 / 3.97), #617575 (4.87 / 4.32), #5c7070 (5.24 / 4.65). Первый, который берёт AA на обеих поверхностях, — #5c7070 |
| Дата белым на болотной шапке | 4.23:1 у светлого ядра, 5.94:1 у края | 4.5:1 — набрана 16/16 | Не берёт только у самого ядра, а дата стоит у верхнего края. С 29.09.2026 бренд болотный: белым по нему 5.94, у кнопки #49601c→#617f28 — 7.06…4.59, прежняя проблема «белым по #25ae6a 2.86:1» снята |
| Заголовок «Нужна помощь сегодня?» белым по градиенту тревоги | 4.79:1 у тёмного конца, 3.38:1 у светлого | 3:1 как крупный текст он берёт; 4.5:1 как обычный — нет. 18/24 semibold стоит на границе определения «крупный» | Либо кегль до 20/24 и хватает 3:1 наверняка, либо светлый конец градиента темнеет: #e83c00 даёт 3.62, #d93800 — 4.13 |
| Подпись блока тревоги, белый при 80 % прозрачности | 3.41:1 у тёмного конца, 2.62:1 у светлого | 4.5:1 — обычный текст 14/16 | Полная непрозрачность поднимает до 3.38…4.79 — это дешевле всего и ближе всего к порогу. Прозрачность здесь ничего не значит смыслово: она только приглушает |
| Белый текст на акцентах цикла | #cb6440 — 3.86:1, #00a6ff — 2.66:1 | 3:1, если по ним пойдёт хоть какой-то текст | Сейчас текста по ним нет — только заливка кружков, и тогда порог не применяется. Ограничение вступит в силу, если появится плашка с подписью |
Manrope — заголовки и имена, Roboto Condensed — тексты, подписи и числа. В макете на месте Manrope стоит Involve (Zetafonts, коммерческий); замена принята 31.08.2026. Табличные цифры включены глобально: в интерфейсе сравнивают цены и даты.
Пять ступеней шкалы плюс два исключения по интерлиньяжу. Интерлиньяжи взяты из макета и теснее ступеней Tailwind по умолчанию: макет плотный, воздух держат отступы, а не строки. Колонка «Flutter» — имя будущего стиля в AppTypography.
Вход
text-display-lg · Manrope SemiBold32 / 36displayLЗапись на приём
text-display · Manrope SemiBold28 / 32displayПриём у гинеколога
text-xl · Manrope Bold20 / 24titleLВаш цикл
text-lg · Manrope SemiBold18 / 24titleMФертильное окно
text-lg · Manrope Regular18 / 24titleMLightАнна Ковалёва
text-base · Manrope Bold16 / 20titleSСмирнова Екатерина Павловна
text-base · Roboto Condensed16 / 20bodyLУЗИ молочных желёз
text-base · Roboto Condensed Medium16 / 20bodyLStrongИсследование лучше делать с 5 по 12 день цикла — так снимок точнее.
text-sm · Roboto Condensed14 / 20bodyMАкушер-гинеколог · 5 200 ₽
text-caption · Roboto Condensed14 / 16captionВозьмите с собой результаты прошлых анализов
text-xs · Roboto Condensed12 / 16noteЗапись
text-label · Roboto Condensed12 / 14labelШкала закрыта. Логический пиксель Flutter равен CSS-пикселю при базе 16 — значит шкала переносится буквально, если её не разбавлять значениями по месту.
gap-1gap-2 / island-stackgap-3gap-4 / p-4p-5gap-6gap-8Раздел нужен, чтобы «подогнали к шкале» было решением, а не потерей: произвольные числа не переносятся во Flutter, они там размываются по месту.
Пять ступеней и «таблетка».
rounded-tailrounded-platerounded-ctarounded-cardrounded-herorounded-pillВ потоке теней нет вовсе: карточка отделяется заливкой. Тень существует ровно для того, что всплывает над экраном, и это её единственная роль.
shadow-sheet--shadow-sheetШторка снизу. Единственное, что отделяется тенью, а не заливкойshadow-float--shadow-floatПлавающий элемент над содержимым: тост, подсказка| Роль | Токен | Значение | Двойник во Flutter |
|---|---|---|---|
| Кривая Одна на весь интерфейс. Быстрый старт, мягкая остановка | --ease | cubic-bezier(0.2, 0.8, 0.2, 1) | Cubic(0.2, 0.8, 0.2, 1) |
| Нажатие Отклик на касание: масштаб 0.97 через press-tap | --duration-tap | 120ms | Duration(milliseconds: 120) |
| Переход Экран уезжает вглубь, шторка раскрывается | --duration-move | 220ms | Duration(milliseconds: 220) |
| Акцент Кольцо цикла, подтверждение записи | --duration-slow | 320ms | Duration(milliseconds: 320) |
Инвариант 2: у каждого повторяющегося поведения один владелец. Описанный словами стиль руками переизобретут чуть иначе; названную функцию — нет. При порте во Flutter у владельца есть ровно один адрес в Dart.
| Поведение | Владелец | Где |
|---|---|---|
| Главное действие экрана: три тона одного размера, неактивное состояние | AppButton | components/kit/app-button.tsx |
| Полоса действия, прибитая к низу экрана | ActionBar | components/kit/action-bar.tsx |
| Кружок выбора слева в строке | SelectMark | components/kit/select-mark.tsx |
| Остров записи: кто идёт, к кому, где и когда | BookingSummary | components/blocks/booking-summary.tsx |
| Текст клиники про услугу отдельным блоком | ServiceNote | components/blocks/service-note.tsx |
| Способы оплаты задатка | PaymentMethods | components/blocks/payment-methods.tsx |
| Сделанные записи: создать, перенести, отменить | useAppointmentsStore | lib/stores/appointments.ts |
| Отклик на нажатие | press-tap | globals.css, @utility |
| Мишень во всю карточку поверх своих мишеней | CardTarget | components/kit/card-target.tsx |
| Отклик карточки со слоем-мишенью внутри | press-card | globals.css, @utility |
| Градиент шапки главной: клиника и рекомендация | brand-hero, promo-hero | globals.css, @utility |
| Перетекание цвета шапки по жесту | --hero-blend | globals.css, @property |
| Градиент кнопки | brand-cta | globals.css, @utility |
| Рамка телефона и системный хром | DeviceFrame | components/shell/device-frame.tsx |
| Навигация стеком: push / pop / popAll | ScreenStack, useScreenStack | components/shell/screen-stack.tsx |
| Оболочка: рамка, стек и панель вкладок вместе | DeviceShell | components/shell/device-shell.tsx |
| Панель вкладок: пять разделов, активный только цветом | AppTabBar | components/blocks/app-tab-bar.tsx |
| Отрисовка иконки из файла с цветом из токена | AppIcon | components/kit/app-icon.tsx |
| Иконочная кнопка: 48 белая, 32 на градиенте, 24 знаком без плашки | AppIconButton | components/kit/icon-button.tsx |
| Стопка аватаров профилей | AvatarStack | components/kit/avatar-stack.tsx |
| Кружок с лицом или инициалами: врач и администратор | DoctorAvatar | components/kit/doctor-avatar.tsx |
| Карточка прошлого приёма: услуга, врач, цена визита | VisitCard | components/kit/visit-card.tsx |
| Строка «иконка 16 + факт о приёме» | IconRow | components/kit/icon-row.tsx |
| Пузырь с хвостом-вектором | SpeechBubble | components/kit/speech-bubble.tsx |
| Точки карусели | CarouselDots | components/kit/carousel-dots.tsx |
| Стекло большой карточки: градиент, 254, обрезка скруглением | HeroSurface | components/kit/hero-surface.tsx |
| Непрозрачная плашка стрелки на брендовом градиенте | plate-on-brand | globals.css, @utility |
| Блик по самому тексту: 15 % строки, проход за 2.6 с | sheen-text | globals.css, @utility |
| Содержимое большой карточки: заголовок, стрелка, слои | HeroCard | components/kit/hero-card.tsx |
| Прокрутка со снапом по карточке, индикатор и неподвижный слой поверх | CardCarousel | components/kit/card-carousel.tsx |
| Шторка снизу внутри рамки телефона | AppSheet | components/kit/app-sheet.tsx |
| День в полоске цикла: шесть видов и «выбран» | CycleDay | components/kit/cycle-day.tsx |
| Полоска дней: прокрутка, снап по центру, выбор дня | CycleStrip | components/kit/cycle-strip.tsx |
| Перетаскивание мышью (леса для показа с ноутбука) | useDragScroll | hooks/use-drag-scroll.ts |
| Вложенное предложение услуги с градиентной кнопкой | ServiceOffer | components/kit/service-offer.tsx |
| Фазы цикла, виды дня и окно УЗИ — считаются, а не пишутся | demo-cycle.ts | lib/demo-cycle.ts |
| Кольцо триместра: дуга, градиент цепочки, заполнение | TrimesterRing | components/kit/trimester-ring.tsx |
| Кольцо срока: сорок недель, три дуги триместров | PregnancyRing | components/kit/pregnancy-ring.tsx |
| План наблюдения: шесть исследований со сроками | PregnancyPlan | components/blocks/pregnancy-plan.tsx |
| Плашка действия у нижней кромки большой карточки | HeroCtaPlate | components/kit/hero-cta-plate.tsx |
| Приглашение записаться первым кадром ленты | FirstVisitCard | components/blocks/first-visit-card.tsx |
| «Как это работает»: три шага для карты без приёмов | HowItWorks | components/blocks/how-it-works.tsx |
| Часы клиники: один факт, а не три формулировки | CLINIC_HOURS | lib/demo-medcards.ts |
| Стеклянный знак направления, пунктир вместо него | CatalogIcon | components/kit/catalog-icon.tsx |
| Карточка направления для ленты | DirectionCard | components/kit/direction-card.tsx |
| «Или выберите направление»: каталог лентой | DirectionRail | components/blocks/direction-rail.tsx |
| Появление содержимого: прозрачность и подъём | rise-in | globals.css, @utility |
| Число, которое перелистывается как счётчик | RollingNumber | components/kit/rolling-number.tsx |
| Системная «назад»: жест от кромки и кнопка Android | SystemBackProvider | components/shell/system-back.tsx |
| Сообщение в переписке: пузырь, цитата, вложение, статус | ChatBubble | components/kit/chat-bubble.tsx |
| Три точки «печатает» | ChatTyping | components/kit/chat-bubble.tsx |
| Поле ввода сообщения и кнопка отправки | ChatComposer | components/kit/chat-composer.tsx |
| Лента переписки: группы, дни, переход к найденному | ChatThread | components/blocks/chat-thread.tsx |
| Пустой чат: приглашение и темы | ChatInvite | components/blocks/chat-invite.tsx |
| Поиск по переписке: найденное вместо ленты, новые сверху | ChatSearch | components/blocks/chat-search.tsx |
| Найденное сообщение: кто, когда, подсвеченный запрос | ChatSearchRow | components/kit/chat-search-row.tsx |
| Цикл до первой отметки: приглашение кадром ленты | CycleInvite | components/blocks/cycle-invite.tsx |
| Заполнение кольца анимацией | ring-fill | globals.css, @utility + @keyframes |
| Срок, триместр и заполненность — считаются из даты | demo-pregnancy.ts | lib/demo-pregnancy.ts |
| Русское склонение по числу и дата словами | plural, formatDay | lib/format.ts |
| Врач тремя строками: имя, специальность со стажем, место | DoctorPlate | components/kit/doctor-plate.tsx |
| Поверхность поля поиска: белое стекло | glass-field | globals.css, @utility |
| Ввод поискового запроса | SearchInput | components/kit/search-input.tsx |
| Поиск по каталогу: услуги, врачи, направления | searchCatalog | lib/search.ts |
| Мишень не меньше 44 × 44 | tap-44 | globals.css, @utility |
| Мишень 44 по высоте у элемента в ряду | tap-row-44 | globals.css, @utility |
| Белый остров экрана | AppCard | components/kit/app-card.tsx |
| Блок «Задаток внесён» | DepositRow | components/blocks/deposit-row.tsx |
| Подсветка изменившегося значения | useChangeFlash | hooks/use-change-flash.ts |
| Короткое сообщение поверх экрана | useToast | components/shell/app-toast.tsx |
| Состояния загрузки: три формы | SkeletonRows, SkeletonCard, SkeletonHero | components/kit/skeletons.tsx |
| Экран поверх устройства (оплата) | push(node, { modal: true }) | components/shell/screen-stack.tsx |
| Строка направления каталога | DirectionRow | components/kit/direction-row.tsx |
| Строка услуги | ServiceRow | components/kit/service-row.tsx |
| Строка папки документов | FolderRow | components/kit/folder-row.tsx |
| Строка документа | DocumentRow | components/kit/document-row.tsx |
| Группа строк под липкой подписью месяца | ListGroup | components/kit/list-group.tsx |
| Плитка: знак на подложке, название, счёт — «Ещё», папки | FolderTile | components/kit/folder-tile.tsx |
| Поиск на месте: поле наверх, справа «Отмена», подсказка | SearchBar | components/kit/search-bar.tsx |
| Плавное сворачивание блока по высоте | Collapsible | components/kit/collapsible.tsx |
| Группа строк-переходов в одной карточке с линиями | NavGroup | components/kit/nav-group.tsx |
| Строка операции по счёту: сумма справа | LedgerRow | components/kit/ledger-row.tsx |
| Окно под файл документа | FilePlaceholder | components/kit/file-placeholder.tsx |
| Страница документа схемой, одна или из нескольких | DocumentSheet | components/kit/document-sheet.tsx |
| Превью файла: лист вполовину, нажатие — во весь экран | DocumentPreview | components/kit/document-preview.tsx |
| Документ плиткой в ленте «Новые»: превью, название, путь | DocumentTile | components/kit/document-tile.tsx |
| Размер плитки «Новых» по числу документов | documentTileSize | components/kit/document-tile.tsx |
| Лента плиток документов во всю ширину экрана | DocumentRail | components/blocks/document-rail.tsx |
| Плашка аккаунта: фото, имя заголовком, телефон | AccountPlate | components/blocks/account-plate.tsx |
| Строка уведомления: знак, событие, чья · когда | NotificationRow | components/kit/notification-row.tsx |
| Строка приёма: услуга, врач, статус, сумма | VisitRow | components/kit/visit-row.tsx |
| Остаток на счёте медкарты | BalanceCard | components/blocks/balance-card.tsx |
| Клиника сети: адрес, метро, звонок, маршрут | ClinicCard | components/blocks/clinic-card.tsx |
| Карта схемой с меткой клиники | MapPreview | components/kit/map-preview.tsx |
| Факт со знаком: часы, календарь, глобус | IconFact | components/kit/icon-fact.tsx |
| Цена значением: «от» приглушённым, число чернилами | PriceTag | components/kit/price-tag.tsx |
| Обводка выбранной строки — кольцом внутрь | select-ring | globals.css, @utility |
| Ведущий знак строки на подложке 40 | IconPlate | components/kit/icon-plate.tsx |
| Заголовок внутри карточки 16/20 | CardTitle | components/kit/card-title.tsx |
| Строка с плашкой знака | PlateRow | components/kit/plate-row.tsx |
| Пустое состояние и заглушка «ещё не собрано» | EmptyState | components/kit/empty-state.tsx |
| Оговорка под содержимым: линия и подпись | Footnote | components/kit/footnote.tsx |
| Сообщение, которое надо заметить: красный остров | AttentionNote | components/kit/attention-note.tsx |
| Раскрывающийся список: подпись с шевроном | Disclosure | components/kit/disclosure.tsx |
| Скорая помощь: граница ответственности и признаки | EmergencyHelp | components/blocks/emergency-help.tsx |
| Вероятность забеременеть: плашка со ступенью | ChancePlate | components/kit/chance-plate.tsx |
| Строка выбора карточкой: кружок, название, пояснение | ChoiceRow | components/kit/choice-row.tsx |
| Строка с переключателем | SwitchRow | components/kit/switch-row.tsx |
| Группа экрана с заголовком 20 | FormSection | components/kit/form-section.tsx |
| Строка сводки записи | SummaryRow | components/kit/summary-row.tsx |
| Доп. услуги к приёму | ExtrasList | components/blocks/extras-list.tsx |
| Итог приёма: сумма, время, задаток | BookingTotal | components/blocks/booking-total.tsx |
| Арифметика приёма | bookingTotals | lib/booking-total.ts |
| Несовместимость услуг и её причина | conflictReason | lib/service-conflicts.ts |
| Правило клиники про день цикла | cycleFitFor | lib/service-cycle-rules.ts |
| День цикла у выбранной даты | CycleFitNote | components/blocks/cycle-fit-note.tsx |
| Окна времени кнопками | SlotChips | components/kit/slot-chips.tsx |
| Дни врача, в которых есть окна | daysWithSlots | lib/demo-slots.ts |
| Текст к приёму «чтобы врач подготовился» | VisitNote | components/blocks/visit-note.tsx |
| Длительность словами | durationLabel | lib/booking-total.ts |
| Черновик записи | useBookingStore | lib/stores/booking.ts |
| Плашка выбранной услуги | ServiceSummary | components/kit/service-summary.tsx |
| Карточка врача со свободным временем | DoctorSlotCard | components/kit/doctor-slot-card.tsx |
| Календарь выбора дня записи | MonthCalendar | components/kit/month-calendar.tsx |
| Липкая панель под шапкой экрана | sticky-panel | globals.css, @utility |
| Острова экрана через 8 | island-stack | globals.css, @utility |
| Свободные окна врача на день | slotsFor | lib/demo-slots.ts |
| Ближайшее окно и почему его нет | availabilityFor | lib/demo-slots.ts |
| Строка про ближайшее время | availabilityLabel | lib/demo-slots.ts |
| Врач ко времени: первый свободный в порядке клиники | freeDoctorsAt | lib/demo-slots.ts |
| Цена услуги: «от» до врача, его ступень при | priceLabelFor | lib/demo-services.ts |
| Длительность услуги: вилка до врача | minutesLabel | lib/demo-services.ts |
| Цена «от» у направления каталога | entryPriceFor | lib/demo-services.ts |
| День относительно сегодняшнего | dayRelative | lib/format.ts |
| Дата с годом: «15 окт 2025» | formatDayYear | lib/format.ts |
| Поле поиска (кнопка, похожая на поле) | SearchField | components/kit/search-field.tsx |
| Помощь сегодня: три варианта шторкой | UrgentHelpSheet | components/blocks/urgent-help-sheet.tsx |
| Телефон клиники и его tel: | clinicPhone | lib/demo-medcards.ts |
| Аватар медкарты: снимок или инициалы | MedcardAvatar | components/kit/medcard-avatar.tsx |
| Инициалы из имени | initials | lib/format.ts |
| Шапка: назад или действие слева, название, действие | ScreenHeader | components/kit/screen-header.tsx |
| Корневой экран раздела с крупным заголовком | RootScreen | components/kit/root-screen.tsx |
| Цена в рублях | formatPrice | lib/format.ts |
| Тип и размер файла строкой | fileMeta | lib/format.ts |
| Градиент блока «Нужна помощь сегодня?» | help-hero | globals.css, @utility |
| Скрытая полоса прокрутки | scrollbar-none | globals.css, @utility |
| Открытый раздел и просьба открыть другой | useAppTabs | components/shell/app-tabs.tsx |
| Кольцо цикла: один цикл кругом, день 1 сверху | CycleRing | components/kit/cycle-ring.tsx |
| Месяц цикла сеткой 7 × N | CycleMonth | components/blocks/cycle-month.tsx |
| Возврат выбора на сегодняшний день | TodayButton | components/kit/today-button.tsx |
| Строка-переход: заголовок, подпись-значение, шеврон | NavRow | components/kit/nav-row.tsx |
| Выбор из коротких вариантов чипами, одиночный и множественный | ChoiceChips | components/kit/choice-chips.tsx |
| Отметки одного дня цикла: выделения, боль, симптомы | CycleDaySheet | components/blocks/cycle-day-sheet.tsx |
| Ступенчатый ввод числа | Stepper | components/kit/stepper.tsx |
| Легенда цикла: вид дня и его происхождение | CycleLegendSheet | components/blocks/cycle-legend-sheet.tsx |
| Справка про базальную температуру | BasalTemperatureSheet | components/blocks/basal-temperature-sheet.tsx |
| Модель цикла: отметка месячных и настройки | useCycleStore | lib/stores/cycle.ts |
| Лицо врача у своей записи — заглушка показа | doctorWithDemoFace | lib/demo-doctors.ts |
| Шапка главной: цветное поле от верха экрана | HeroBackdrop | components/blocks/hero-backdrop.tsx |
| Вид системной полосы: тон глифов и скрим | useChromeClaim | components/shell/app-chrome.tsx |
| Верх экрана входа: знак W, заголовок, пояснение по центру | SignInHeader | components/kit/sign-in-header.tsx |
| Поле телефона: маска +7, подпись сворачивается в фокусе | PhoneField | components/kit/phone-field.tsx |
| Код входа по ячейкам | CodeCells | components/kit/code-cells.tsx |
| Согласие мелким текстом со ссылками на документы | ConsentNote | components/kit/consent-note.tsx |
| Системная цифровая клавиатура: заявка экрана, нажатия | SystemKeyboard, useSystemKeyboard | components/shell/system-keyboard.tsx |
| Вход или приложение: оболочка до входа | SessionGate | components/shell/session-gate.tsx |
| Оболочка до входа: стек без вкладок, корень — телефон | SignInShell | components/shell/sign-in-shell.tsx |
| Маска номера телефона | formatPhone | lib/format.ts |
| Как добраться: шторка с картой со строки «Где и когда» | ClinicRouteSheet | components/blocks/clinic-route-sheet.tsx |
| Клиника, где принимает медкарта | clinicOf | lib/demo-clinics.ts |
| Канал кода входа: Telegram или SMS — заглушка сервера | signInChannel | lib/demo-account.ts |
| Свободные деньги на счёте: хватает — задаток без оплаты | freeBalanceOf | lib/demo-account.ts |
| Причины записи в стоматологию по медкарте | dentReasonsFor | lib/demo-dent.ts |
| Ветка записи в стоматологию: колл-центр, врач, время | dentNextStep | lib/demo-dent.ts |
| Следующий экран записи в стоматологию | useDentRoute | hooks/use-dent-route.tsx |
| Клиника приёма по услуге: адрес и маршрут | clinicOfService | lib/demo-clinics.ts |
| Клиника приёма одной строкой для «Где и когда» | clinicNameFor | lib/demo-clinics.ts |
| Выбор врача услуги с ближайшим окном | ServiceDoctorsScreen | components/screens/service-doctors-screen.tsx |
То, чего в вебе не бывает: системный хром и навигация стеком. Без них дизайн врёт про доступное место.
Глубина стека: 0. Откройте экран, чтобы увидеть переход и то, как ведёт себя слой под ним.
push, pop, popAll. Двойник во Flutter — Navigator с теми же именами.Transform.scale плюс Opacity.Собранные секции главной. Показываются внутри рамки 393: навбар в ширину ноутбука — это другой навбар, и он ничего не проверяет.
Навбар главного экрана — узел 56:5402 макета. 393 × 64, поля 16, содержимое отбито сверху на 8. Три элемента лежат стопкой, а не рядом: имя центрировано по экрану, а не между соседями, — иначе оно уехало бы влево на 10px, потому что аватары шире колокольчика. Центруется само имя, без шеврона: слева от него противовес шеврону с отступом, и шеврон висит справа.
Фрейма в Figma нет — собрано по решениям из журнала прототипа. Переключается медкарта, а не «профиль»: слово изъято из глоссария, потому что означало сразу и аккаунт, и медкарту. Аккаунт живёт в «Ещё» и от выбора не зависит.
Пять фреймов макета — 56:5479, 56:5733, 58:6095, 75:6663, 75:6794 — это одна лента, а не пять блоков. Прокрути её пальцем или трекпадом, или встань фокусом и нажми стрелки влево-вправо.
58:6095 те же координаты и та же оболочка, а точки у него третьи. Значит это не баннер поверх экрана, а элемент очереди «что у меня дальше».Решение 31.08.2026: пузырь несёт авторскую фразу с бюджетом ~87 знаков, а полное правило подготовки живёт на экране приёма. Обрезка многоточием есть, но она страховка от ошибки, а не обычный путь.
Основание: из 13 настоящих правил подготовки в выгрузке клиники в две строки влезает одно. Шесть занимают три строки, пять — пять, одно — шесть. Ниже одно и то же правило к УЗИ брюшной полости в трёх видах.
Рост до трёх строк был собран и отклонён 31.08.2026: пузырь поднимался с 171 до 155, а факты кончаются на 148 — зазор падал с 23px до 7, то есть до касания. И правило всё равно обрезалось: из пяти строк было видно три. Чтобы зазор остался прежним, карточка должна была вырасти с 254 до 270. Параметра высоты у пузыря больше нет — 48 и только 48.
Ассеты под карточку приёма, показанные на её же градиенте и в её высоте (254). Здесь решаются две вещи, которые на белом фоне не видны: нет ли светлой каймы от вырезки и одинаково ли посажены кадры. Переключатель клиники наверху меняет градиент — на фиолетовом кайма заметнее, чем на зелёном.
Барковская Анна
Алабушева Анастасия
Медведко Сергей
Ахмедов Махир
Клименко Лада
Хаматуллин Вильдан
Орлова Ксения
Николаева АннаПортреты подставные: на них не изображены врачи, чьими именами названы файлы. Имена стоят для того, чтобы настоящие снимки легли на те же пути без правки кода. Специальности, стаж, адреса, цены и слоты в демо-данных — настоящие, из выгрузок клиники. Клиент своих врачей узнаёт, поэтому в показе это надо называть вслух.
Владелец — DoctorAvatar. Понадобятся в повторной записи и каталоге услуг: там врач упомянут, а не показан по пояс. Круг рисует вёрстка, а не файл. Первая выгрузка пришла с зелёным фоном внутри PNG, и он не подчинялся scope-классу клиники: на детском экране бренд фиолетовый, а аватар остался бы зелёным. Снимки заменены на прозрачные, цвет круга — bg-brand.
Восемь из двенадцати — те же люди, что на портретах по пояс: у файлов общий корень, и общий корень значит одно лицо. Шесть уже разобраны по приёмам, шесть в запасе. Аватары подставные, как и портреты.
Узел 126:8445. Заголовок 20/24, гэп 16, карточки 288 с гэпом 8, в конце «Новая запись» 133. Лента прокручивается пальцем, мышью и трекпадом; снапа нет намеренно. С 10.09.2026 в ленте визиты, а не врачи: карточка называет услугу, по которой к врачу обращались, и ведёт на сборку приёма с заполненными услугой, врачом и доп. услугами того приёма. Цена в карточке — за названную услугу у этого врача, доп. услуги в неё не входят: их состав объясняет сборка, где они стоят отмеченными строками. Разбор — у VisitCard.

Прошлых приёмов пока нет
Выберите направление или напишите нам

Пока тихо
Напомним о приёме и сообщим о документах
Уведомления приходят по всем вашим пациентам
Всё настоящее, из выгрузки прайса. Слева норма: название целиком. В середине и справа — обрезка, и это обычное состояние, а не страховка: строка держит около двадцати пяти знаков (288 минус поля 32, минус портрет 40 и гэп 12), а в прайсе есть имена до восьмидесяти. Опознаётся услуга по началу названия плюс по имени врача под ним.
Имя врача в обрезку не попадает ни у одного: самая длинная фамилия 11 знаков («Гогичашвили», «Чебоксарова», «Поликарпова») плюс имя, а вторая строка набрана 12 и держит около сорока.
edit из того же набора Iconsax, что колокольчик и глобус; обводка в файле переведена на currentColor. В макете её штрих #292D32, у нас `text-foreground` #161616 — разница неразличима, но названа.Узел 79:7078. Карточка 361 × 96, радиус 24, градиент тревоги под 75.1°, заголовок 18/24, подпись 14/16 в две строки, стеклянная иллюстрация 64. Единственная красная плоскость в системе — и она разрешена ситуацией, а не назначена для яркости: правило характера запрещает «красные плашки там, где ничего не случилось», а здесь случилось.
public/illustrations/README.md, а не в компоненте — подгонка числами живёт до первой замены ассета.Узлы 56:5525 и 56:5526. Ряд 393 × 53, пять вкладок по 78 через justify-between — отсюда и шаг 78.75 из макета. Внутри: знак 24, гэп 2, метка 12/14, отбивка сверху 8.
logo-w, message-text, more-2. Два — «Запись» и «Документы» — собраны в макете из отдельных векторных слоёв, и такие слои сервер не отдаёт вовсе: пять попыток, каждый раз «Error getting image». Их прислал дизайнер плоским SVG. Обводка у всех пяти переведена на currentColor, остальные атрибуты как в выгрузке: у папки у первого пути нет linecap/linejoin, и дописывать их нельзя — углы там держит miter.Узлы 126:8466, 126:8491, 126:8516. Карточка 361 × 194 — те же числа, что у карточки цикла: блок встаёт на её место. Кольца 98 с шагом 94, обводка 4, дорожка --muted. Срок акушерский, от первого дня последних месячных, как считает врач в карте.
Ваш срок 5 недель
Первый триместр · роды 3 декабря
Ваш срок 20 недель
Второй триместр · роды 3 декабря
Ваш срок 20 недель 3 дня
Второй триместр · роды 3 декабря
Ваш срок 36 недель
Третий триместр · роды 3 декабря
Ваш срок 40 недель
Третий триместр · роды 3 декабря
Три триместра, у каждого пустое кольцо, дуга 35 % и полное. Цепочка видна на полных: конец первого равен началу второго, конец второго — началу третьего, поэтому три круга читаются как один путь от первых недель к родам. Дуга у всех начинается на девяти часах и идёт по часовой — так в макете, а не на двенадцати, как обычно.
stroke-dasharray, и на той стороне рисуется тем же путём. За это уже платили: кольцо цикла в HTML-прототипе пришлось переделывать ровно по этой причине.prefers-reduced-motion гасит анимацию глобальным правилом, и кольца сразу оказываются заполненными.hidden — из-за этого её сначала и не было. Решение общее с карточкой цикла: два блока делят место на экране, и угол у них выглядит одинаково. Знак 24 приглушённым цветом, высота заголовка та же 48.CardTarget). До 03.09.2026 обработчик не передавался и мишени не было вовсе — вести было некуда; теперь карточка открывает экран «Моя беременность».Блок состояния детской карты — на том же месте, что карточка цикла у взрослой. Решение концепта v0.6: «позиция под ближайшим приёмом — это место причины вернуться, и у родителя она тоже есть». Референс свой: фрейм 75:6728 и собранный блок в замороженном прототипе; среди 71 скриншота конкурентов прививок нет ни у кого. Пройденных прививок в блоке нет — правка дизайнера сразу после первой отрисовки, «может, пройденные прививки не имеет смысла отображать в виджете?». Блок состояния отвечает на «что сейчас», а сделанные прививки — на «что было», и это вопрос экрана, где под них лежит раздел из девяти строк; историю в блоке называет подпись со счётом. Правило вышло одно: есть план — показываем план, нет — показываем историю. Освободившееся место отдано второму пункту плана, а не воздуху: 224 против 288 до правки. Форму дизайнер выбрал из трёх — строки плана, а не полоска плиток из макета: те шесть плиток не были данными (в прототипе шапка говорила «три прививки в карте», а сертификат в той же карте — «девять с рождения»), а анонимные кружки нельзя прочитать без легенды. Креста из макета нет: красный крест против непоставленной прививки читается как выговор родителю, а правило 8 свода интонации запрещает приложению медицинские оценки — и пропуска приложение всё равно не знает, отвод и прививка из поликлиники выглядят в данных одинаково. Приложение не считает, когда пора: окно («в 6 лет») и его последний день приходят с планом от клиники, потому что правила календаря — медицинское решение врача, а не арифметика по дате рождения.
Прививки
9 записей в карте клиники
Прививки
9 записей в карте клиники
Осмотр педиатра и прививка — за один приём · 30 минут
Прививки
9 записей в карте клиники
Прививки
9 записей в карте клиники
Не знаете, к кому?
Опишите, что беспокоит, — администратор подскажет специалиста и подберёт время
Введите номер, указанный при регистрации в клинике. Пришлём код в Telegram или по SMS
Продолжая, вы принимаете и даёте
Перед записью нужна консультация специалиста
Можно добавить сейчас или уже на приёме у врача
Можно добавить сейчас или уже на приёме у врача
Часть стоимости приёма, остальное доплатите в клинике
Нет сети
Похоже, пропал интернет. Проверьте связь и попробуйте ещё раз
Не получилось загрузить
Извините, у нас не получилось. Попробуйте ещё раз — а если не выйдет, напишите нам, и администратор всё сделает руками
Это 5 день вашего цикла — как рекомендуют для этой услуги
Иной день согласовывается с врачом. При боли день цикла не важен
Это 12 день вашего цикла, а рекомендуют 5–7 день цикла
Иной день согласовывается с врачом. При боли день цикла не важен
Внесите задаток 1 000 ₽ в течение 30 минут, иначе запись отменится
Задаток 1 000 ₽ возьмём из денег на счёте, остальное доплатите в клинике
Вы записались, до встречи в клинике!На 5-7 день цикла (от начала менструации), иной день согласовывается с врачом в индивидуальном порядке. При боли день цикла не важен.
С собой необходимо иметь документ, подтверждающий личность. Стоимость забора крови оплачивается отдельно. Выявляет риск трисомии 21 хромосомы (синдром Дауна), трисомии 18 хромосомы (синдром Эдвардса),трисомии 13 хромосомы (синдром Патау), половых анеуплоидий (в зависимости от пола плода в заключение указывается риск моносомии Х (синдром Тернера) и трисомии Х (синдром ХХХ)- для женского пола плода; дисомии Х (синдром Клайнфельтера) и дисомии Y (синдром Якобс)- для мужского пола плода) частых микроделеционных синдромов: микроделеция 22q11.2 (синдром ДиДжорджи), микроделеция 1р36 (синдром 1р36), микроделеция 15q11-13 (синдром Ангельмана/ Прадера-Вилли), микроделеция 4р16.3 (синдром Вольфа-Хиршхорна), микроделеция 5р15 (синдром кошачьего крика). При проведении НИПТ “расширенная панель” устанавливается статус носительства частых аутосомно-рецессивных мутаций у матери в генах CFTR, PAH, GALT, GJB2, SLC26A4, TPP1, ATP7B, DARS2, DHCR7, HEXA, IDUA, PIGN, PKHD1, PMM2, SLC26A2, USH2A, SMARCAL1, ALDOB.
Все состояния одной моделью: карточка получает цикл и дату, а фазу и вид каждого кружка считает сама. Захардкоженные кружки выглядят правдоподобно ровно до первого вопроса «почему тут так».
Узлы 56:5688, 58:6050 и 56:5414. Белая карточка 361, радиус 24, отбивка 15 по горизонтали и 16 по вертикали — 15 стоит во всех трёх фреймах, это не описка. Высота считается из содержимого: 194 без предложения, 338 с ним.
Шесть видов и модификатор «выбран». Слева обычная ячейка, справа выбранная — у неё белая подложка, и на ней видно, зачем у белого диска белая обводка. Кружки — не текст и не единственный носитель факта: под каждым стоит число, а фаза названа словами в заголовке. Поэтому порог контраста 3:1 к ним не применяется; замеры для протокола — #cb6440 к ячейке 3.42, #00a6ff — 2.36.
Месячные начались 5 июля
Следующие ≈ 3 августа
Месячные начались 5 июля
Следующие ≈ 3 августа
Месячные начались 5 июля
Следующие ≈ 3 августа
Месячные начались 5 июля
Следующие ≈ 3 августа
Месячные начались 5 июля
Следующие ≈ 3 августа
Месячные начались 3 августа
Следующие ≈ 1 сентября
Полоска листается пальцем, мышью и стрелками. Прокрутка ничего не выбирает — это осмотр: выбор ставит нажатие, и уже оно доводит день до центра. Первый заход считал выбранным день по центру, и тогда пролистать полоску, ничего не выбрав, было нельзя: заголовок менялся сам, стоило сдвинуть полосу на день. Уехав прокруткой, выбранный день может оказаться сбоку или за кадром — за этим и нужна кнопка «сегодня».
Месячные начались 5 июля
Следующие ≈ 3 августа
Месячные начались 5 июля
Следующие ≈ 3 августа
Месячные начались 5 июля
Следующие ≈ 3 августа
Месячные начались 5 июля
Следующие ≈ 3 августа
dayKind.CardTarget), а не оболочка: внутри живут свои мишени — дни в полоске, «сегодня», плашка предложения и её крестик, — и кнопка внутри кнопки невалидна. Ценой ушёл отклик на нажатие: масштабировать прозрачный слой нечего, а сжимать карточку целиком нельзя — тогда она сжималась бы и от нажатия на день.useDragScroll, общий с каруселью карточек. При порте не переносится: на телефоне свайп.Блик переехал с подложки на строку действия (правка дизайнера 05.09.2026), и вместе с ним ушёл шеврон: у строки теперь один признак нажимаемости, а не два. Плашка большая и светлая, проход по ней читался как погода — что-то шевелится, а нажать нечего конкретного; строка действия единственное, что на плашке нужно нажать. Владелец — sheen-text: градиент кладётся фоном и обрезается по буквам, полоса светлее текста на 25 % и занимает 15 % строки. Цена обратная прежней: блик по подложке текст осветлял и контраст на проходе поднимал, а блик по самим буквам их светлит — 2.54:1 в покое против 1.95:1 на проходе, и строка единственный носитель цены. Тёмный проход вместо светлого поднял бы контраст до 4.16:1 (#018551) — решение за дизайнером.
Месячные начались 5 июля
Следующие ≈ 3 августа
#eaf3f3, а не брендовая, как в макете: брендовая была бы второй по площади цветной поверхностью главной — 38 124 px² против 34 656 у блока тревоги, — а крупная брендовая плоскость на экране допускается одна. Брендовым остался только текст действия. Нажимается вся плашка целиком, а не строка: 337 × 104 против прежних 339 × 36. Заголовок — Roboto Condensed Medium 16/20, то есть у него с заголовком карточки разные кегль, вес и гарнитура: 18/24 Manrope SemiBold спорил с ним на равных. С 07.09.2026 у плашки второй носитель — предложение под кольцом на экране беременности: «Скрининговое исследование II триместра», правило клиники о сроке и цена. Там она стояла строкой со знаком (PlateRow), и дизайнер снял расхождение доводом «единообразие у одинаковых элементов» — содержание у них и правда одно. Крестика там нет: скрывать пункт плана некуда. Подпись действия при этом переменная — «Записаться на приём», когда срок идёт, и «Записаться заранее», когда пункт ещё впереди: эту разницу до правки нёс знак строки, часы против календаря. В тот же день появился и третий носитель — предложения дня на экране цикла, лентой под кольцом. Там плашек бывает от одной до пяти, и подпись действия тоже переменная: «Записаться на этот день», когда день подходит по правилу клиники.button, и кнопка внутри кнопки невалидна — браузер разбирает такую разметку как попало, а нажатие достаётся то одному, то другому. Крестик взят из макета напрямую — узел 156:3665, третий заход. Первые два были угадыванием: сначала знак без плашки (тон plain), потом, на «сделай как в фигме», 32 с белой подложкой и тёмным знаком — по числам соседних контролов. Дизайнер выделил плашку в Figma, и в макете оказалось третье: круг 24 белым в 56 %, крестик приглушённым цветом в 40 %, вписанный в поле 24 как 9→15 (6 при обводке 1.5), и позиция 8 от края, а не 12. То есть контрол тише всего, что мы пробовали: сведённая подложка #f6fafa — 1.07:1 к плашке, знак #c8d3d3 — 1.46:1 к своей подложке, против 18.1:1 второго захода и 2.66:1 первого. Порог 3:1 для графического контрола не берётся втрое, но значение из макета не подменено: выбор цвета принадлежит дизайнеру. Подложку рисует разметка, а не файл знака — то же правило, из-за которого у аватаров врачей меняли выгрузку с запечённым зелёным. Мишень до 44 растит tap-44. Заголовок получает отбивку справа только когда крестик есть: в макете её нет, потому что там заголовок короткий, а у нас название приходит из прайса. Без обработчика крестика нет вовсе — на экране цикла предложение живёт шторкой дня, и скрывать там нечего. Скрытие помнится до следующих месячных: ключ хранения — дата начала цикла, отметили новые — окно посчиталось заново, и предложение вернулось.Главная фигура экрана «Мой цикл». Холст 288: снаружи дуга прогресса 4, просвет 6, полоса фаз 28, внутри чаша 212. Перерисовано 05.09.2026 по референсу дизайнера: подряд идущие дни одного вида — один отрезок с круглыми торцами, а не двадцать девять отдельных дуг. Словарь видов дня у кольца, полоски и календаря один (dayKind): кольцо — не второй график со своими правилами, а тот же ряд дней, свёрнутый в круг.
03.09.2026 кольцо перестало быть картой дней — правка дизайнера «выглядит довольно просто и стандартно». Точки дней внутри полосы сняты: тот же атлас дней рисовала полоска сверху, и две одинаковые карты в одной панели читались как виджет из набора, а работу «где граница дня» полоска делает лучше — там у дня есть подпись, число и мишень. Кольцу осталось то, чего полоска не умеет: показать длину цикла целиком и место в ней.
Тем же проходом: полоса выросла с 20 до 28, метка 40 с числом месяца стала ползунком 24 без числа (в центре стоял день цикла, а на метке — число месяца, два числа с разным смыслом в ста пикселях друг от друга), внутренний круг подтонирован цветом фазы (cycle-bowl, 16 % к краю: до правки там было 248 пикселей белой пустоты; третьим проходом чаша отодвинута от полосы на 10 и обводки не имеет), а прогресс вынесен наружу отдельной дугой. Дорожки под отрезками больше нет — в просветах между фазами видна сама панель, а не тёмное кольцо. Прогресс сначала попробовали красить внутри полосы — пройденные нейтральные дни брендовым, — и отрисовка показала, что зелёная дуга между красной и синей читается четвёртой фазой. Снаружи спутать её с фазой нечем: другой радиус, другая толщина, другой цвет.
Сегодня отмечено зелёной меткой внутри полосы фаз — 11.09.2026, и она заменила собой пилюлю «Сегодня» над полоской дней: та появлялась при уходе с сегодняшнего дня и роняла кольцо вниз на 40 ровно тогда, когда на кольцо смотрят. Метка ничего не двигает, она лежит внутри холста. Первый заход поставил её на конец дуги прогресса — угол тот же, — и дизайнер поправил: снаружи она становилась утолщением дуги, то есть читалась её частью, а не отдельным днём. Дни живут в полосе фаз, там же, где метка выбранного дня. Кружок 14 в белом кольце до 20 — те же 20 против 28, что у плотной отметки месячных; белое кольцо обязательно, цвет фазы под меткой свой в каждом месте круга. Показывается только на не-сегодняшнем дне: на сегодняшнем её место занимает метка выбранного дня, и две метки на одном угле были бы одной мыслью дважды. Метка ещё и мишень — возврат на сегодня, 44 при знаке 20.
В центре стоит вероятность забеременеть, а не даты овуляции и следующих месячных (11.09.2026). Довод дизайнера тот же, что снял легенду фаз: обе даты уже нарисованы этим же кольцом — фаза названа словом, дуги показывают её границы, числа лежат в календаре. А вероятность из кольца не читается никак. Три ступени словами, без процентов: число выглядит как знание, которого у модели по одному отмеченному циклу быть не может. Цена названа — дата следующих месячных ушла из слов.
Правка дизайнера 04.09.2026 в два шага: «можешь добавить микроанимацию для дня цикла внутри круга? чтобы число как счётчик менялось», а затем «а можешь сделать более интересную? например первое число в десятке приезжает чуть раньше второго». Двигаются четыре вещи, и каждая — про переключение дня, а не про украшение. Число перелистывается по разрядам: старший идёт без задержки, следующий на 60 мс позже — половина --duration-tap на разряд (владелец RollingNumber, 220 мс на разряд). Метка едет по кольцу и везёт с собой цвет дня — переход стоит и на смещении, и на обводке, 320 мс. Чаша перетекает цветом фазы: переменная --bowl зарегистрирована как <color>, иначе цвет в градиенте менялся бы щелчком. Название фазы меняет цвет переходом, а слово подменяется мгновенно: текст на месте, движется только цвет.
AnimatedSwitcher со SlideTransition) держит обоих детей по той же причине.tabular-nums страховкой от смены гарнитуры.prefers-reduced-motion гасит всё глобальным правилом.Температура не предсказывает овуляцию, а подтверждает её — и от этого зависит вся раскладка. Подъём происходит после овуляции и виден, только когда держится несколько дней, поэтому приложение никогда не скажет «овуляция завтра» по температуре: оно скажет «овуляция была позавчера». Отсюда два состояния цикла, которые экран обязан различать словами. Правило обнаружения — «три над шестью»: три подряд измерения выше максимума предыдущих шести, третье выше него не меньше чем на 0,2 °C; овуляция приходится на день перед первым из трёх. Разовый скачок даёт болезнь, поздний отход ко сну и бокал вина — это названо в справке ТЗ, — поэтому значит не цифра, а ряд. Пропущенное утро окно не домысливает: нет хотя бы одного из шести — окно не считается вовсе. Алгоритм клиникой не подтверждён: в ТЗ его нет, сказано лишь «рассчитываем по ней».
Прибор экрана «Моя беременность», собранный 03.09.2026 по задаче дизайнера «по стилю придерживаться экрана цикла». Геометрия та же — холст 288, полоса 28, просвет 6, чаша с отбивкой 48, метка тремя кругами: два состояния женского здоровья читаются одним прибором, и человек, освоивший экран цикла, не учит второй интерфейс.
Отличий от кольца цикла два, и оба по смыслу. Дуги показывают заполнение, а не только фазу: у цикла «сколько прошло» говорит отдельная дуга снаружи, а у беременности триместр и есть отрезок срока — поэтому здесь у каждого триместра дорожка и заливка по ней до сегодняшнего дня, а внешней дуги нет. Цвет — цепочка градиентов (--preg-1…4): конец одного триместра равен началу следующего, и весь срок читается одной растяжкой от сиреневого к зелёному. Стопы и приём — из TrimesterRing, кольца на виджете.
Поворот растяжки пришлось поправить на 90°, и это поймал замер: у дуг стоит rotate(-90), чтобы первая неделя пришлась на двенадцать часов, а градиент с userSpaceOnUse живёт в той же системе координат элемента и поворачивается вместе с ним. Без поправки первый триместр рисовался ровным синим: по пикселям 41 → 12 → 32 в красном канале там, где сиреневый стоп даёт 142.
ChancePlate — вероятность забеременеть на главной, под полоской дней и над предложением услуги: сначала «что со мной сегодня», потом «что с этим можно сделать». Шкала идёт внутри светлого, а не от серого к синему: полный цвет фазы во всю ширину карточки был бы крупной насыщенной поверхностью, а в системе бренд и фазы живут в мелких акцентах. С 14.09.2026 это строка свойства: слева предмет, справа ступень словом. Три точки, которыми ступень дублировалась, убраны — довод, на котором они держались («цвет различим, но не считается»), слово снимает целиком. При климаксе плашки нет вовсе — там прогноз овуляции не считается, и строка говорила бы неправду.
--tick: белая точка терялась на сером секторе, тёмная — на красном. Здесь та же задача решена словарём, а не новым цветом: на насыщенной дуге точка белая вполсилы, на осветлённой — белая целиком, на светлой дорожке — приглушённая.--line (1.24:1 к белому) против --muted (1.13:1), между собой около 1.1:1. Это очень мало, и носителем факта эта разница не является: где стоит сегодняшний день, сказано словом «сегодня» в полоске и заголовком «Ваш день цикла» в центре. На кольце она работает как граница между пройденной и предстоящей частью, а границу глаз ловит там, где двух отдельных пятен не различил бы.transform-origin: 50% 100% и переходом по повороту (у нас 320 мс — ступень «акцентная анимация», заведённая как раз под это кольцо). Число внутри контр-вращается на тот же угол с той же длительностью и остаётся вертикальным. Угол считается непрерывным — к позиции внутри цикла прибавляется полный оборот за каждый пройденный цикл, — иначе переход с двадцать девятого дня на первый ехал бы назад через весь круг, пока полоска едет вперёд.ring-fill) — там дуга это прогресс. Здесь отрезков пять-шесть, и последовательное появление читалось бы как загрузка: кольцо показывает позицию, а не выполненную долю.Обе вещи появились 05.09.2026 по правкам дизайнера: «на экране должен быть переход к календарю по месяцам» и «непонятно, как изменить день месячных после первой отметки». Календарь — третья проекция одного и того же ряда дней: те же dayKind, сплошное это факт, обводка той же краской — прогноз. Шторка отметки закрывает четыре случая: сдвиг на день назад, сдвиг вперёд (пропадает, если завтра ещё не наступило), выбор дня в календаре и откат последней отметки.
SelectMark отдаёт варианту целую строку, и три слова превратили бы шторку дня в четыре экрана; Stepper для чисел на шкале, а у обильности шкалы нет — «умеренные» это не «половина обильных». Повторное нажатие по выбранному снимает выбор: поля дневника необязательные, и вернуться к «ничего не отмечено» надо уметь без кнопки «очистить» у каждого поля. Белым по бренду — 2.86:1, тот же названный случай, что у главной кнопки. Подпись группы — чернила 16 и отбивка 12, ряды чипов на 8. Правка «пилюли прилипают к заголовкам» чинилась семь раз, и шесть из них мимо: группа была fieldset, а подпись legend, который браузер вынимает из потока — gap до него не доходил вовсе. Теперь это div с role="group". У чипа есть слот под знак (icon у группы, не у варианта): им пользуется «Начались месячные» с каплей — группа из одного чипа, который на деле переключатель важного действия. Перечисление, где у каждого чипа свой значок, — это уже список, а не поле выбора.Пять владельцев. NavRow — переход со подписью, которая несёт данные, а не пересказ заголовка: «Цикл 29 дней · месячные 5 дней», а не «настроить цикл». Смысл строки в том, что за большинством значений проваливаться не нужно. TodayButton — возврат выбора на сегодня; остался только в карточке цикла на главной, где делит угол со стрелкой. С экрана цикла он ушёл 11.09.2026: там он появлялся при уходе с сегодняшнего дня и ронял кольцо вниз на 40 ровно тогда, когда на кольцо смотрят, — возврат переехал зелёной меткой внутрь полосы фаз, на своё число. Stepper — ступенчатый ввод числа; границы приходят пропсами, потому что степпер не знает, что такое цикл. ChoiceRow и SwitchRow собраны 11.09.2026 вместе с настройками цикла. Первый выделен на третьем носителе: одна и та же раскладка была написана трижды — доп. услуги, способы оплаты, цель цикла, — и восстанавливалась копированием из чужого файла. Второй — первый переключатель в приложении вообще: примитив Switch лежал в витрине без единого носителя. Разница между ними не оформительская: кружок отвечает на «что из списка», тумблер — на «включено или нет», и кружки у независимых наблюдений сказали бы, что отмечать можно что-то одно.
arrow-right, а не стрелка в угол: arrow-up-right означает «открыть отсюда целый экран».tap-44). Значение стоит в колонке 72: без неё «5 дней» и «10 дней» двигали бы кнопки под пальцем на каждом шаге. На границе кнопка выключена, а не спрятана — исчезающая кнопка сдвигает значение, и следующее нажатие попадает не туда. Минус набран U+2212, а не дефисом: дефис на кегле 16 вдвое короче плюса.Открыты и стоят в настоящей рамке: шторка садится в её элемент через контекст, без рамки useDeviceFrame падает — намеренно. Шторки дня здесь больше нет — 07.09.2026 её содержимое переехало на экран: предложения дня стоят под кольцом лентой, а «консультация гинеколога» и «написать в клинику» — строками. Правка дизайнера: «мб логично и на экране цикла перенести такой блок под кольцо вместо шторки?».
CycleDay, с тем же числом. Захардкоженная легенда разъехалась бы с полоской молча. Происхождение здесь важнее цвета: «дни, которые вы отметили сами» против «посчитаны по длине цикла, а не отмечены» — это единственное, чего словами на экране не сказано нигде.Вся линия одним листом. Расхождения между знаками — спорящие мотивы, разный вес, пропавшее брендовое пятно — видны только когда они лежат рядом, а живут они по экранам.
Матовый пластик, три цвета: светлый корпус, брендовый акцент примерно на пятую часть предмета, тёмный якорь на ручках и подставках. Камера одна на весь набор, тени нет — знаки идут вырезкой в прозрачный PNG. Разбор стиля и промпты — docs/design/uikit/clay-prompts.md.




































































Стоковые компоненты shadcn: наши токены они уже слушают, масштаб у них пока свой. Приводить к макету — обёрткой или scoped-правилом по data-slot, никогда правкой файлов в components/ui.
Варианты, размеры и состояния. Приложение использует default и outline; secondary и ghost — для вложенных действий. У destructive заливка приглушённая, а не сплошная: сплошной красный на экране записи читается как ошибка, а не как отмена.
Граница поля — токен --input (3.62:1 к карточке), а не декоративный --border: WCAG требует 3:1 там, где рамка единственный признак поля. Ошибка выражается через aria-invalid, а не через класс: тогда её видит и скринридер.
Флажок, переключатель и радиогруппа. В приложении переключатель отвечает за напоминания и за показ цикла, радиогруппа — за выбор клиники и способа приёма.
Карточка, бейдж, аватар, разделитель. У аватара два состояния одного примитива: снимок и инициалы — у пациента фото есть, у врача из выгрузки нет. Карточка примитива и карточка макета — разные вещи: у макета радиус 24 и белая заливка на тонированной странице, у примитива стоковый радиус. Свести их — работа фазы 3.
Alert — для состояния экрана, не для медицинской оценки: правило 8 свода tone of voice запрещает приложению оценивать здоровье.
Табы и аккордеон. Аккордеон в приложении несёт правила подготовки к исследованию; табы — основа SegmentedTabs, в приложении это выбор клиники на записи.
Единственная поверхность, которая отделяется тенью, а не заливкой (--shadow-sheet). В приложении шторка снизу несёт управление записью — перенос, отмену, напоминание.