/* Мини-апп заказ-нарядов. Редизайн v2.

   Имена классов те же, что в боевом приложении: файл кладётся вместо
   старого app.css и работает без правок JS. Что нельзя сделать одним CSS,
   перечислено в ВНЕДРЕНИЕ.md.

   Три вещи, ради которых всё переделано.

   1. Заголовки. Было: .h2 15px приглушённым серым, то есть тише текста
      под собой. Стало: 19px полужирным светлым. Владелец 22.08.2026:
      «заголовки надо выделить».

   2. Расстояния. Было: 8-10px между нажимаемыми элементами при подушечке
      пальца в 45-50px. Стало: цель не ниже 48px, зазор 12px, между
      действиями с разными последствиями 24px. Владелец: «чтобы палец
      случайно не попадал на другие кнопки».

   3. Подтверждение. Всё, что уходит человеку наружу, требует двух нажатий.
      Взведённая кнопка становится янтарной: этот цвет больше нигде
      не встречается, спутать не с чем. */

:root {
  color-scheme: dark;

  /* ПАЛИТРА. Редизайн v3 по макетам от 06.09.2026.
   *
   * Что изменилось против v2 и почему. Было: карточки с подложкой, зелёная
   * градиентная кнопка, синий заголовок, цветная активная вкладка, плитки
   * со счётчиками. Цветов на экране оказывалось четыре разом, и деньги -
   * то, ради чего на экран заходят - ничем не выделялись среди них.
   *
   * Стало: один акцент на экран, много воздуха, крупные суммы. Списки без
   * карточек, строки разделяет волосяная линия. Цвет остался только там,
   * где он сообщение: зелёный - деньги получены, янтарный - ждут, красный -
   * не чаще одного раза на экран. На вкладках цвета нет вовсе, положение
   * показывает яркость подписи.
   *
   * Имена токенов прежние: на них стоят две тысячи строк ниже, и
   * переименование дало бы огромную дифф без единого изменения вида.
   */

  /* Поверхности. Чистого чёрного нет, фон один на всё приложение. */
  --void:   #0B0B0D;   /* шапка, нижняя панель */
  --paper:  #0B0B0D;   /* фон страницы */
  --panel:  rgba(255, 255, 255, .06);   /* материал: панель, вкладки */
  --raise:  rgba(255, 255, 255, .10);   /* поле ввода, нажатое состояние */
  --sheet:  rgba(28, 28, 32, .82);      /* лист снизу, поверх экрана */

  /* Свет сверху: радиальное пятно на 7%. Единственный градиент на фоне -
     без него страница выглядит краской, а не материалом. */
  --glow: radial-gradient(120% 50% at 50% -10%, rgba(255,255,255,.07), transparent 60%);

  /* Плоские значения тех же поверхностей - для стыков, где прозрачность
     наложилась бы сама на себя и дала шов. */
  --lift:   #17171A;
  --lift-2: #1F1F23;

  /* Линии. Одна на всё приложение: она и разделитель списка, и рамка. */
  --edge:   rgba(255, 255, 255, .08);
  --edge-2: rgba(255, 255, 255, .12);

  /* Текст. Один белый с тёплым отливом, четыре ступени прозрачности. */
  --ink:    #F5F5F2;
  --ink-2:  rgba(245, 245, 242, .55);
  --muted:  rgba(245, 245, 242, .55);
  --faint:  rgba(245, 245, 242, .30);

  /* Сигналы, не украшения. */
  --signal:      #30D158;   /* деньги получены, выдан, готово */
  --signal-ink:  #0B0B0D;
  --signal-dim:  rgba(48, 209, 88, .14);

  --stamp:     #FF453A;   /* ошибка, просрочка. Один раз на экран */
  --stamp-dim: rgba(255, 69, 58, .13);

  --amber:     #FFB020;   /* ждёт оплаты, не проведено, взведённая кнопка */
  --amber-ink: #0B0B0D;

  --white-plate: #F4F4F1;  /* госномер, единственный объёмный предмет */

  /* Цвет раздела снят намеренно. Владелец 03.09.2026 просил «повыделять
     разделы цветами», и это было сделано; макеты 06.09.2026 отменяют:
     на вкладках цвета нет, активную видно по яркости. Смыслы от этого
     не размываются - зелёный остался только у денег. */
  --sec:     var(--ink);
  --sec-dim: var(--panel);

  /* Тень одна на приложение - свечение под главной кнопкой. Кромка светом
     остаётся: на тёмном фоне она работает там, где тень не видно. */
  --gleam: inset 0 1px 0 rgba(255, 255, 255, .06);
  --gleam-strong: inset 0 1px 0 rgba(255, 255, 255, .18);
  --drop: none;
  --drop-lift: none;
  --btn-glow: 0 10px 20px rgba(245, 245, 242, .16);

  /* Радиусы: ровно три. */
  --r-sm: 14px;
  --r-md: 14px;
  --r-lg: 20px;
  --r-xl: 28px;

  /* Шаг 4. Веб-шрифты не грузятся: приложение уже воевало с белым экраном
     на LTE в подземном паркинге. */
  --text: "Golos Text", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  --mono: ui-monospace, "SF Mono", "Cascadia Mono", Consolas, monospace;

  /* Размеры из макетов. */
  --pad: 20px;
  --row: 72px;      /* строка машины: min-height, мета может переноситься */
  --row-s: 50px;    /* строка-пункт меню */
  --row-w: 64px;    /* строка работы */
  --btn-h: 54px;

  --ease: cubic-bezier(.2, .8, .2, 1);
  --spring: cubic-bezier(.32, 1.15, .42, 1);
  --fast: 120ms;
  --d-nav: 240ms;
  --d-count: 400ms;

  /* Нижняя панель плавающая, поэтому запас снизу считается от неё. */
  --nav-h: 64px;
  --safe-b: max(10px, env(safe-area-inset-bottom, 0px));
}


/* Golos Text - кириллический гротеск Паратайпа, сделан под русский
   интерфейс. Системный стек остаётся фолбэком.

   Шесть файлов: кириллица и латиница отдельно, три веса. Начертание 500
   не скачивается вовсе - браузер возьмёт ближайшее 600, а на медленном
   LTE это 59 сэкономленных килобайт.

   font-display: swap - текст рисуется системным шрифтом сразу и подменяется,
   когда файл доедет. Из-за шрифта белого экрана не будет. */
/* Golos Text вариативный: ось веса 400-900 живёт внутри одного файла.
   Поэтому и объявление одно на подмножество, с диапазоном весов.

   Раньше здесь стояло шесть объявлений с весами 400, 600 и 700, и все
   шесть вели на ОДИН И ТОТ ЖЕ файл с базовым весом 400. Браузер честно
   его брал и жирнил сам: каждый заголовок в приложении рисовался
   искусственно утолщённым Regular, а не настоящим Golos Bold. Видно
   было по ширинам - 700, 800 и 900 давали ровно одну и ту же строку.
   Заодно ушли четыре лишние копии, 128 КБ. */
@font-face {
  font-family: "Golos Text";
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  /* format("woff2"), а не "woff2-variations". Сафари до 16-й версии
     подсказку "woff2-variations" не понимает и молча ПРОПУСКАЕТ всё
     объявление: шрифт не загружается, и айфон рисует приложение
     системным - с другими ширинами и другой высотой строки, то есть
     «криво» во всех местах разом. Переменные оси при обычной подсказке
     работают везде: файл тот же. */
  src: url("fonts/golos-cyrillic.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}
@font-face {
  font-family: "Golos Text";
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url("fonts/golos-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

* { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }

/* Кнопки и поля берут шрифт приложения.
 *
 * По умолчанию браузер рисует в них СВОЙ шрифт: font-family на body
 * элементы формы не наследуют. Замер 07.09.2026 на экране примерки:
 * 24 узла из 375-пиксельного экрана рисовались системным шрифтом -
 * все 18 плиток материала, три карточки образа и подписи под ними.
 * На клиентском экране в чужом шрифте была ГЛАВНАЯ кнопка «Записаться».
 *
 * Владелец: «очень неудобно выглядит примерка». Половина экрана в одном
 * шрифте, половина в другом - это первое, что видно, и глазом читается
 * как недоделка.
 *
 * Только family: размеры у кнопок свои, и `font: inherit` их сбросил бы
 * к семнадцати пикселям разом. */
button, input, select, textarea, optgroup {
  font-family: inherit;
}

body {
  margin: 0;
  /* Пятно света сверху лежит на фоне страницы и не прокручивается:
     это материал, а не элемент содержимого.
     Раньше оно держалось на background-attachment: fixed. В вебвью
     айфона это свойство не работает как задумано: слой перерисовывается
     не на каждом кадре прокрутки, и пятно ползёт по экрану рывками -
     ровно то «всё ползёт», на которое жаловался владелец 07.09.2026.
     Отдельный неподвижный слой ниже делает то же самое и ведёт себя
     одинаково во всех браузерах. */
  background: var(--paper);
  color: var(--ink);
  font: 400 17px/1.45 var(--text);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;
  /* Слово, которое не влезает в строку, переносится с разрывом, а не
     распирает страницу. Без этого хватает одного слитного слова, чтобы
     вёрстка поехала: замер 03.09.2026 на карточке наряда - слово из 45
     символов вылезло за край в 25 местах сразу, включая заголовок экрана
     и подписи под работами. В данных такое приходит само: ссылка
     в заметке о клиенте, слитное название услуги, длинная марка.

     Именно anywhere, а не break-word: break-word разрешает перенос,
     но НЕ уменьшает минимальную ширину элемента по содержимому. Кнопка
     или чип, чья ширина считается от текста, с ним всё равно распирает
     строку - проверено, те же 25 мест остались на месте. Фразы с
     пробелами оба варианта рвут одинаково, по пробелам. */
  overflow-wrap: anywhere;
}
/* Обрезка нужна и на корне, а не только на body.
   overflow-x на body Сафари для прокрутки вьюпорта не учитывает: страница
   всё равно уезжает вбок, и левый край содержимого пропадает за экраном.
   Одно переполнившее поле - и весь наряд смотрится косым.
   Прокрутки по горизонтали в мини-аппе нет нигде: всё, что не влезает
   по ширине, либо переносится, либо листается внутри своего блока
   (лента образов в примерке - у неё своя overflow-x: auto). */
/* Тот самый неподвижный слой света. z-index: -1 уводит его под
   содержимое, но оставляет над фоном страницы. pointer-events: none
   обязателен: слой лежит поверх всей страницы и без него съел бы
   касания. */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -1;
  background: var(--glow);
  pointer-events: none;
}
html { overflow-x: clip; }
/* Запас для старых айфонов. clip Сафари понимает только с 16-й версии,
   а ползло как раз на айфоне: на iOS 15 и ниже правило выше молча
   не работает, и страница снова уезжает вбок.
   hidden делает то же, но создаёт контейнер прокрутки, поэтому включаем
   его только там, где clip не поддержан - иначе он ломает липкие шапки
   (position: sticky у фильтра плёнок и у заголовка экрана). */
@supports not (overflow: clip) {
  html, body { overflow-x: hidden; }
}


/* Крупный заголовок экрана. Тридцать четыре пикселя против семнадцати
   в тексте - разница вдвое, и она видна прищурившись. Это и есть ответ
   на «заголовки надо выделить» на уровне всего экрана, а не секции. */
/* Заголовок экрана лежит на живом свете.
 *
 * 14.09.2026, владелец в третий раз: «почему ты не выделил наряды,
 * приёмку». Размер не помогал - под заголовком сумма в 38 пикселей,
 * и она всё равно крупнее. Линия делала из экрана документ, и её сняли.
 *
 * Работает другое: под заголовком то же переливание, что на обложке
 * первого экрана. Заголовок перестаёт быть первой строкой списка -
 * у него своё место, а у приложения одно лицо на всех экранах.
 * Свет приглушён вдвое против обложки: там он главный, здесь подложка.
 */
.bigtitle {
  position: relative;
  max-width: 480px;
  margin: 14px auto 2px;
  padding: 0 var(--pad);
  font: 600 30px/1.14 var(--text);
  letter-spacing: -.025em;
  color: var(--ink);
  isolation: isolate;
}
.bigtitle::before {
  content: "";
  position: absolute; z-index: -1;
  left: calc(-1 * var(--pad)); right: calc(-1 * var(--pad));
  top: calc(-90px - env(safe-area-inset-top, 0px)); bottom: -26px;
  background:
    radial-gradient(42% 60% at 18% 30%, rgba(58, 91, 255, .55) 0%, transparent 70%),
    radial-gradient(38% 56% at 72% 18%, rgba(180, 76, 255, .45) 0%, transparent 70%),
    radial-gradient(44% 62% at 64% 76%, rgba(255, 94, 122, .40) 0%, transparent 70%),
    radial-gradient(40% 58% at 26% 82%, rgba(25, 198, 217, .40) 0%, transparent 70%);
  filter: blur(48px);
  animation: hero-drift 8s ease-in-out infinite alternate,
             hero-hue 12s linear infinite;
  pointer-events: none;
}
/* Низ подложки гасим в фон страницы: иначе свет продолжается в список
   и первая строка машины лежит на цветном. */
.bigtitle::after {
  content: "";
  position: absolute; z-index: -1;
  left: calc(-1 * var(--pad)); right: calc(-1 * var(--pad));
  top: 50%; bottom: -26px;
  background: linear-gradient(180deg, transparent, var(--paper) 88%);
  pointer-events: none;
}
/* Цвет раздела на заголовке. Нижняя панель занимает 52 пикселя из
   восьмисот, и цвет там видит только тот, кто его ищет: Stephan дважды
   посмотрел тихий вариант и сказал «не вижу что поменялось».
   
   Обрубок в 44 пикселя под широким заголовком он назвал кривым, и был
   прав: правый конец полоски обрывался посреди слова и читался как
   недоделка. Поэтому линия во всю ширину заголовка, а сам заголовок
   берёт цвет раздела.
   
   Только там, где раздел известен: на клиентской витрине data-sec нет,
   и заголовок остаётся белым. */
.bigtitle::after { content: ""; display: none; }
/* Заголовок остаётся белым и без полоски: в макетах 06.09.2026 цвета
   на заголовке нет, а где ты находишься, говорит сам заголовок. Правило
   оставлено пустым, а не удалено - data-sec на body по-прежнему ставит
   nav.js, и по нему красится активная вкладка. */
/* Браузерное [hidden] это display: none из его собственной таблицы, и любое
   авторское display его перебивает. Редизайн раздал display: flex строкам,
   и всё, что код прячет свойством .hidden, осталось на экране: «Скидка -
   0 ₽» и «Сумма работ» висели в каждом наряде без скидки, строка оклада -
   в каждом исполнителе. Двадцать четыре места в коде рассчитывают на hidden. */
[hidden] { display: none !important; }

main {
  max-width: 480px;
  margin: 0 auto;
  /* Снизу запас под плавающую панель И под главную кнопку: она тоже
     absolute, и без запаса последняя строка списка уходит под неё. */
  padding: 4px var(--pad) calc(var(--nav-h) + var(--safe-b) + 96px);
}

/* Цифры везде табличные: иначе денежная колонка гуляет при прокрутке.
   Моноширинный не берём - на Android нет SF Mono, фолбэк даёт другие
   метрики и колонка едет ровно на дешёвом телефоне. */
.num, .price__sum, .slot__sum, .total, .week__total, .summary__n, .item__pay {
  font-variant-numeric: tabular-nums;
  font-feature-settings: "tnum" 1;
}

/* Числа не переносятся.
 *
 * Неразрывного пробела перед «₽» не хватило: глобальное
 * `overflow-wrap: anywhere` ниже в файле разрешает разрыв в ЛЮБОМ месте,
 * когда строка не влезает, и неразрывный пробел его не останавливает.
 * Замер на 320 пикселях 08.09.2026: «356 250 ₽» в карточке наряда шло
 * в две строки при ширине узла 96 пикселей. Коды символов при этом
 * честные - 33 35 36 a0 32 35 30 a0 20bd.
 *
 * Тот же корень, что у «Записатьс / я» на главной кнопке 07.09.2026.
 *
 * Сумма, разорванная пополам, - это не «немного криво», это другая
 * сумма: «356 250 ₽» в две строки читается как «356» и «250 ₽».
 * Если не влезает - ужимается подпись рядом: у неё слов много,
 * а у суммы каждый знак значащий.
 *
 * .week__total не включаем: там целая фраза «В работе 2 машины
 * на 400 000 ₽ · осталось получить 200 000 ₽», ей переноситься
 * положено, а суммы внутри неё держит неразрывный пробел. */
.num, .price__sum, .slot__sum, .summary__n, .item__pay {
  overflow-wrap: normal;
  word-break: keep-all;
}

/* ============================================================
   ЗАГОЛОВКИ. Главная правка релиза.
   ============================================================ */

/* Было 15px var(--muted) - тише текста под собой. Теперь заголовок
   выигрывает по всем трём признакам: размер, вес, цвет. */
.h2 {
  margin: 28px 0 0;
  padding-bottom: 10px;
  border-bottom: 1px solid var(--edge);
  font: 400 13px/1.3 var(--text);
  letter-spacing: 0;
  color: var(--ink-2);
  text-transform: none;
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}
.h2:first-child { margin-top: 4px; }

/* Правая приписка в заголовке: «3 наряда», «расчёт сразу». */
.h2 > span:last-child:not(:first-child) {
  font: 400 15px/1.2 var(--text);
  color: var(--muted);
  letter-spacing: 0;
  flex: none;
}

/* Крупный заголовок экрана - только на клиентских экранах. */
.hero--photo .hero__title { text-shadow: 0 2px 12px rgba(0,0,0,.5); }
.hero__title, .result__title {
  font: 700 32px/1.08 var(--text);
  letter-spacing: -.025em;
  margin: 0;
}
/* У героя под заголовком свой отступ в подложке, а у результата примерки
   сразу карточка с ценой - без поля они лежали вплотную, ноль пикселей. */
.result__title { margin-bottom: 12px; }

/* Служебная метка. Капитель приглушённым серым осталась ТОЛЬКО здесь:
   раньше так выглядели все заголовки, и экран читался серой стеной. */
.hero__eyebrow, .consent__head, .done__head, .issues__head, .notes .note__head,
.mark__head, .day__head, .preset__head {
  /* Подпись слева, счётчик справа - как у крупных заголовков экрана.
     Впритык они читались одной строкой: «КЛИЕНТ ВИЗИТОВ: 2». */
  justify-content: space-between;
  font: 600 12px/1.2 var(--text);
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--muted);
}

/* Фильтр по финишу над каталогом. Липкий: цветов 746, и вернуться
   к переключателю с середины списка иначе значит листать вверх. */
.chips--finish {
  position: sticky; top: 56px; z-index: 20;
  margin: 0 -16px 10px; padding: 10px 16px;
  background: var(--paper);
  border-bottom: 1px solid var(--edge);
}

.chips-sub {
  margin: 14px 0 8px;
  font: 600 13px/1.2 var(--text);
  color: var(--ink-2);
}

.muted { color: var(--muted); }
/* Подпись под блоком. Нижнее поле обязательно: у кнопки своего верхнего
   отступа нет, и без этого «Записаться на осмотр» вставала вплотную
   к тексту - пять пикселей вместо двенадцати по всему приложению. */
.footnote, .hint, .field-hint {
  font: 400 14px/1.4 var(--text);
  color: var(--muted);
  margin: 8px 0 12px;
}

/* ============================================================
   ХРОМ: шапка и нижняя панель. Стекло живёт только здесь.
   ============================================================ */

/* Размытие стоит дорого, поэтому оно на двух неподвижных элементах,
   а не на прокручиваемом содержимом. На вебвью без backdrop-filter
   работает сплошная заливка из первой строки. */
.masthead {
  position: sticky; top: 0; z-index: 40;
  display: flex; align-items: center; gap: 10px;
  padding: 12px 16px calc(12px + env(safe-area-inset-top, 0px));
  padding-top: calc(12px + env(safe-area-inset-top, 0px));
  background: transparent;
  /* Заливка и линия под шапкой появляются, только когда под неё заехало
     содержимое. Над снимком шапка прозрачная: сверху человек видит машину,
     а не полоску с названием.
     Пока экран не прокручен, шапка сливается с фоном и не режет его. */
  border-bottom: 1px solid transparent;
  transition: border-color var(--fast) var(--ease);
}
.masthead--scrolled { background: rgba(11, 11, 13, .96); border-bottom-color: var(--edge); }
/* Мелкая подпись экрана живёт только после того, как крупный заголовок
   уехал под шапку. Иначе на экране два одинаковых заголовка подряд. */
.masthead__screen {
  opacity: 0;
  transform: translateY(4px);
  transition: opacity var(--fast) var(--ease), transform var(--fast) var(--ease);
}
.masthead--scrolled .masthead__screen { opacity: 1; transform: none; }
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .masthead--scrolled {
    background: rgba(11, 11, 13, .72);
    -webkit-backdrop-filter: blur(24px) saturate(180%);
    backdrop-filter: blur(24px) saturate(180%);
  }
}
/* В шапке стоит знак студии, а не слово. Он у них уже есть и узнаётся
   сам: три полосы с косым срезом. Пропорция знака 3:1, поэтому ширина
   считается от высоты, а не задаётся отдельно. */
.masthead__brand {
  display: inline-flex; align-items: center;
  color: var(--ink);
  /* Высота держится до ответа сервера: знак приходит из настроек, и без
     этой строки шапка на долю секунды была бы ниже, а потом прыгала. */
  min-height: 18px;
}
.brand {
  display: block;
  /* Просветы между полосами это 12.5% высоты знака, то есть ниже 16px
     они схлопываются и знак читается смазанным пятном. 18px - предел,
     где все три полосы ещё держатся раздельно. */
  /* Ширина от пропорций самого знака, а не посчитанная под один логотип:
     приложение продаётся разным студиям, и у каждой знак своей формы. */
  height: 18px; width: auto;
  fill: currentColor;
  /* Над снимком шапка прозрачная, и белый знак на светлом кадре
     пропал бы. На тёмном фоне тень незаметна. */
  filter: drop-shadow(0 1px 3px rgba(0, 0, 0, .55));
}
.masthead__screen {
  font: 500 15px/1 var(--text); color: var(--ink-2);
}

/* Нижняя панель. Плавающая пилюля, а не полоса во всю ширину:
   так она читается как элемент поверх содержимого, а не как его край. */
.nav {
  position: fixed; z-index: 50;
  left: var(--pad); right: var(--pad); bottom: calc(var(--safe-b) + 8px);
  max-width: 440px; margin: 0 auto;
  /* Зазор 4px между вкладками - исключение из правила «12px между целями».
     Панель это один сегментный контрол: вкладка шириной 110-117px, целятся
     в середину, и промах уводит в соседнюю вкладку, а не в необратимое
     действие. Правило 12px написано для кнопок, стоящих в потоке столбиком. */
  display: grid; grid-template-columns: repeat(3, 1fr); gap: 4px;
  padding: 0 6px;
  height: var(--nav-h);
  align-items: center;
  border-radius: var(--r-xl);
  background: rgba(24, 24, 27, .98);
  border: 0;
  box-shadow: var(--gleam);
}
/* Список уходит под панель мягко, а не обрывается о её край.
   Градиент лежит НАД содержимым и ПОД панелью. */
.nav::before {
  content: ""; position: absolute; z-index: -1;
  left: calc(-1 * var(--pad)); right: calc(-1 * var(--pad));
  bottom: calc(-1 * (var(--safe-b) + 8px)); height: 160px;
  background: linear-gradient(180deg, transparent, var(--paper) 62%);
  pointer-events: none;
}
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .nav {
    background: rgba(24, 24, 27, .92);
    -webkit-backdrop-filter: blur(24px) saturate(180%);
    backdrop-filter: blur(24px) saturate(180%);
  }
}
.nav__btn {
  flex: 1; min-height: 52px;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 3px;
  padding: 6px 4px;
  border: 0; border-radius: 16px;
  background: none; color: var(--faint);
  font: 500 11px/1.1 var(--text);
  cursor: pointer;
  transition: background var(--fast) var(--ease), color var(--fast) var(--ease);
}
.nav__btn svg { width: 22px; height: 22px; }
/* Активная вкладка: цвета нет, только яркость.
   
   До 06.09.2026 активная заливалась плотным цветом раздела - это решение
   владельца от 03.09, и оно работало: тихие варианты он не различал.
   Макеты отменяют заливку, потому что цвет на вкладке спорил с цветом
   денег в списке над ней: зелёная сумма и зелёная вкладка в одном кадре
   читались как связанные, хотя связи нет.
   
   Чтобы разница осталась заметной без цвета, активная вкладка получает
   и полный белый, и вес 600, а неактивные приглушены до .45 - это
   двойной признак, а не один оттенок. */
.nav__btn--on {
  background: none;
  color: var(--ink);
  box-shadow: none;
  font-weight: 600;
}
.nav__btn--on svg { stroke-width: 1.9; }
.nav__btn:active { background: var(--raise); }

.offline-strip {
  position: sticky; top: 0; z-index: 45;
  padding: 10px 16px;
  background: var(--stamp); color: #2A0F0C;
  font: 600 15px/1.2 var(--text); text-align: center;
}

/* ============================================================
   СЕКЦИИ И КАРТОЧКИ
   ============================================================ */

/* Карточек в макетах 06.09.2026 нет. Подложка, радиус и кромка сняты:
   строки разделяет волосяная линия, а группировку показывает пустое место.
   Класс оставлен на месте - на него ссылается вся разметка в JS. */
.card {
  background: none;
  border: 0;
  border-radius: 0;
  padding: 16px 0;
  margin-bottom: 0;
  box-shadow: none;
}
.card + .card { border-top: 1px solid var(--edge); }

/* Карточки, стоящие подряд, склеиваются в один предмет.
 *
 * Долг мастерам это не четыре коробки, а список из четырёх строк. Задачи
 * не три коробки, а список из трёх. Пока каждая несла свою рамку и свои
 * скругления, экран читался стопкой одинаковых прямоугольников - ровно то,
 * из-за чего он выглядел дёшево.
 *
 * Первая в череде получает верхние углы, последняя нижние, между ними
 * волосяная линия. Одиночная карточка остаётся скруглённой со всех сторон.
 * Всё на соседних селекторах, разметку JS трогать не нужно.
 */
.card + .card:not(.order) {
  margin-top: 0;
  border-top: 1px solid var(--edge);
  border-top-left-radius: 0; border-top-right-radius: 0;
}
.card:not(.order):has(+ .card:not(.order)) {
  margin-bottom: 0;
  border-bottom-left-radius: 0; border-bottom-right-radius: 0;
}

/* Пара «подпись слева - значение справа». Редизайн потерял разведение
   по краям, и суммы липли к подписи посреди пустой карточки: «Провёл
   нарядов на 620 000 ₽» вместо колонки цифр по правому краю. */
.row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.row.muted { font-size: 15px; }
/* Кнопка в такой строке. У .btn ширина 100%, и пара кнопок в одном ряду
   переполняла его: «Похоже» вылезала за карточку и наезжала на «Не похоже».
   Делим ряд поровну, min-width снимает флексовый минимум по содержимому. */
.row > .btn { flex: 1 1 0; width: auto; min-width: 0; }

/* Строка наряда в списке. Нажимается целиком, поэтому внутри неё
   мелких кнопок нет. */
/* Иконка из спрайта. Цвет наследуется от родителя, поэтому одна и та же
   иконка работает и на тихой кнопке, и на зелёной. */
.ico { width: 20px; height: 20px; flex: none; display: block; }

.card.order {
  /* flex-start, а НЕ center. Замер на айфоне 375px 07.09.2026: у наряда,
     где номер, счёт работ и статус не влезли в одну строку, левая колонка
     стала на 21px выше, и правая - сумма со сроком - от центрирования
     съехала вниз. Рядом стоят два наряда: у одного сумма на одной линии
     с машиной, у другого ниже. Владелец: «всё криво».
     От верха выравнивание не зависит от длины содержимого вовсе. */
  display: flex; align-items: flex-start; gap: 12px;
  width: 100%; min-height: var(--row);
  margin: 0; padding: 12px 0;
  background: none; border-radius: 0; box-shadow: none;
  cursor: pointer;
  transition: background var(--fast) var(--ease);
}

/* Миниатюра машины. Снимок приёмки, тот же, что стоит в шапке документа.
   Без фото - значок: строки обязаны стоять по одной сетке, иначе список
   разъезжается и выглядит собранным на коленке. */
/* Миниатюру в списке макеты 06.09.2026 убрали: на 320px она отбирала
   74 пикселя у названия, и «Volkswagen Tiguan» обрезалось. Снимок приёмки
   остался в самой карточке наряда - там его смотрят, а не опознают машину
   по шестидесяти пикселям. Правило не удалено: разметку рисует JS, и класс
   ещё приходит из него в других списках. */
.order__thumb { display: none; }
.order__thumb--kept {
  width: 60px; height: 60px; flex: none;
  display: grid; place-items: center;
  border-radius: 12px;
  background: var(--raise);
  color: var(--faint);
  overflow: hidden;
  box-shadow: var(--gleam);
}
.order__thumb--photo { background: #000; }
.order__thumb img { width: 100%; height: 100%; object-fit: cover; display: block; }
.order__thumb .ico { width: 26px; height: 26px; }

.order__body { flex: 1; min-width: 0; }
/* Стрелка говорит, что строка открывается. Без неё список читается
   как справка, а не как список, в который можно провалиться. */
.order__go { display: none; }
.jump .order__go { flex: none; color: var(--faint); display: grid; place-items: center; }
.order__go .ico { width: 18px; height: 18px; }

/* Разделитель между машинами, а не рамка вокруг каждой. */
.card.order + .card.order {
  /* Линия во всю ширину: миниатюры больше нет, и отступ под неё оставлял
     разрыв в начале каждой линии. */
  border-top: 1px solid var(--edge);
}
/* Строка без миниатюры: предложение и запись, из которой заводят наряд.
   У них слева нет фото, а флекс от строки наряда расставлял их блоки
   шеренгой и сплющивал до нуля - список уезжал за край экрана. */
.card.order--flat { display: block; }
.card.order--flat + .card.order--flat {
  border-image: none;
  border-top: 1px solid var(--edge);
}

/* Нажатие подсвечивает строку во всю ширину экрана, как в списке iOS. */
.card.order { transition: background var(--fast) var(--ease), transform 90ms var(--spring); }
.card.order:active {
  background: var(--panel);
  box-shadow: 0 0 0 var(--pad) var(--panel);
}
.order__head {
  justify-content: flex-start; gap: 8px; margin: 5px 0 0;
  flex-wrap: wrap;
}
.order__head .tag { white-space: nowrap; overflow-wrap: normal; }
/* Машина - доминанта строки. Всё остальное заметно тише: раньше название
   было 17px, а номер и сумма 15px, и разница в одну ступень не читалась. */
.order__car {
  margin: 0;
  font: 600 17px/1.2 var(--text);
  letter-spacing: -.01em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.order__client { font-size: 15px; color: var(--ink-2); margin: 0 0 4px; }

/* Правая колонка строки: сумма и срок. Прижата к правому краю и не
   сжимается - название слева делит ширину только с ней, поэтому строка
   помещается на 320 пикселях без обрезки марки. */
.order__side {
  flex: none; display: flex; flex-direction: column; align-items: flex-end;
  gap: 5px; text-align: right;
}
.order__sum { font: 600 17px/1.2 var(--text); letter-spacing: -.01em; }
.order__side .due { margin: 0; white-space: nowrap; }

/* Мета рядом с номером: чем машина занята. Тише названия на две ступени. */
.order__meta {
  font: 400 13px/1.3 var(--text); color: var(--muted);
  white-space: nowrap; overflow-wrap: normal;
}

/* ============================================================
   СТРОКА РАБОТЫ. Кружок готовности слева, сумма справа.
   ============================================================ */
.item__head { align-items: center; gap: 12px; min-height: var(--row-w); }
.item__main { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 3px; }
.item__title { font: 500 15px/1.25 var(--text); }
.item__sub { font: 400 13px/1.3 var(--text); color: var(--ink-2); }
.item__price { flex: none; font: 600 15px/1.2 var(--text); }

/* Работа раскрывается нажатием: сама строка всегда на виду, действия
   под ней. Шеврон поворачивается - это единственный признак, по которому
   понятно, что строка вообще открывается. */
.item__head--tap { cursor: pointer; }
.item__head--tap:active { background: var(--panel); box-shadow: 0 0 0 var(--pad) var(--panel); }
.item__chev { flex: none; display: grid; place-items: center; color: var(--faint); }
.item__chev .ico { width: 16px; height: 16px; transition: transform var(--fast) var(--ease); }
.item__chev--open .ico { transform: rotate(90deg); }
.item__more { padding-top: 4px; }

/* Кружок готовности. Пустой - обводка, закрытый - заливка с галкой.
   Галка нарисована двумя линиями, а не значком из спрайта: на 14 пикселях
   спрайтовая галка со скруглениями превращается в кляксу. */
.mark-dot {
  width: 24px; height: 24px; flex: none;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1.5px solid var(--faint);
}
.mark-dot--done { border-color: var(--signal); background: var(--signal); }
.mark-dot__tick {
  width: 12px; height: 7px;
  border-left: 2px solid #0B0B0D;
  border-bottom: 2px solid #0B0B0D;
  transform: translateY(-1px) rotate(-45deg);
}

/* ============================================================
   ШАПКА НАРЯДА. Госномер, машина, деньги - в таком порядке.
   
   Было: номер и марка одной строкой, имя клиента, телефон, а сумма
   лежала внизу экрана за списком работ и полями. У стойки человек
   спрашивает «сколько с меня», и ответ был на четвёртом экране прокрутки.
   ============================================================ */
.ordhead__car {
  margin: 16px 0 0;
  font: 600 28px/1.15 var(--text);
  letter-spacing: -.02em;
}
.ordhead__meta { margin: 6px 0 0; font: 400 13px/1.35 var(--text); color: var(--ink-2); }
.ordhead__sum {
  display: block; margin: 24px 0 0;
  font: 600 38px/1 var(--text); letter-spacing: -.03em;
}
.ordhead__pay { margin: 8px 0 0; font: 400 15px/1.35 var(--text); color: var(--ink-2); }
.ordhead__due { color: var(--amber); }
.ordhead__dot { color: var(--faint); }
.ordhead__when { margin: 6px 0 0; font: 400 13px/1.35 var(--text); color: var(--ink-2); }
/* Шапка - единственная карточка без линии сверху: над ней только
   кнопка возврата. */
.card.ordhead, .ordhead { padding-top: 0; }

/* ============================================================
   ДЕНЕЖНАЯ ШАПКА ЭКРАНА. Сумма, ради которой на экран заходят.
   Тридцать восемь пикселей против семнадцати в строке - разница видна
   прищурившись, и это единственное крупное число на экране.
   ============================================================ */
.bigsum { margin: 18px 0 22px; }
.bigsum__n {
  display: block;
  font: 600 38px/1 var(--text);
  letter-spacing: -.03em;
  color: var(--ink);
}
.bigsum__note { margin: 8px 0 0; font: 400 13px/1.3 var(--text); color: var(--ink-2); }
.bigsum__due { margin: 4px 0 0; font: 400 15px/1.3 var(--text); color: var(--amber); }
.bigsum__hint { margin: 4px 0 0; font: 400 13px/1.3 var(--text); color: var(--ink-2); }
/* Зелёной сумма бывает в одном месте - в истории, где деньги уже получены.
   Класс ставит экран, а не список. */
.bigsum--done .bigsum__n { color: var(--signal); }
/* Долг клиентов: сумма янтарная. Тот же смысл, что и у янтарных подписей,
   - деньги есть, но они ещё не в кассе. */
.bigsum__n--wait { color: var(--amber); }
/* Число работ слева, деньги справа в колонку. */
.order .row.muted { justify-content: space-between; font-size: 14px; }
/* Сумма справа в строке наряда гремит нарочно. В строке без миниатюры
   справа стоит номер предложения, ему греметь незачем. */
.order:not(.order--flat) .row.muted > span:last-child {
  color: var(--ink); font-weight: 600; font-size: 16px;
}

/* Блочный: в строке наряда это span внутри обычного блока, а у строчных
   элементов вертикальный margin не работает - зазор пропадал. */
.due { display: block; font-size: 13px; color: var(--muted); margin: 5px 0 0; }
/* В строке задачи срок стоит рядом с именами, а не отдельным абзацем
   под ними: верхний отступ там сдвигал плашку вниз на восемь пикселей. */
.row > .due { margin-top: 0; }
.due--late { color: var(--amber); font-weight: 400; }


/* ============================================================
   СТРОКИ-ПЕРЕХОДЫ. Один экран - одно дело.
   ============================================================ */

/* Сгруппированы в один предмет с разлиновкой внутри, а не рассыпаны
   отдельными кнопками: это оглавление, а не три разных действия. */
/* Оглавление раздела. Подложка снята: в макетах это те же строки списка,
   отделённые от машин пустым местом в 16px, а не другим материалом. */
.jumps {
  margin: 16px 0 0;
  border-radius: 0;
  overflow: visible;
  background: none;
  box-shadow: none;
  border-top: 1px solid var(--edge);
}
.jump {
  display: flex; align-items: center; gap: 12px;
  width: 100%; min-height: var(--row-s);
  padding: 0;
  border: 0; background: none;
  color: var(--ink);
  font: 400 17px/1.3 var(--text);
  letter-spacing: -.01em;
  text-align: left;
  cursor: pointer;
  transition: background var(--fast) var(--ease);
}
.jump + .jump { border-top: 1px solid var(--edge); }
.jump:active { background: var(--panel); box-shadow: 0 0 0 var(--pad) var(--panel); }
.jump__name { flex: 1; min-width: 0; }
/* Цифра, ради которой на экран заходят: она правее подписи и тише её.
   Янтарной её делает JS через .jump__value--wait там, где деньги ждут. */
.jump__value {
  flex: none;
  font: 400 15px/1.2 var(--text);
  font-variant-numeric: tabular-nums;
  color: var(--muted);
}
.jump__value--wait { color: var(--amber); }
.jump__go { flex: none; display: grid; place-items: center; color: var(--faint); }
.jump__go .ico { width: 18px; height: 18px; }

/* ============================================================
   ГОСНОМЕР. Единственное белое пятно в приложении.
   В боксе машину опознают по номеру, поэтому он набран как настоящая
   табличка, а не как строка текста. Цвета намеренно не из токенов.
   ============================================================ */
/* Табличка набрана тем же шрифтом, что и приложение: моноширинный
   на Android подменяется системным, метрики уезжают, и номер выглядел
   набранным другим шрифтом на дешёвом телефоне. Второй шрифт в макетах
   запрещён отдельным пунктом. */
.plate {
  display: inline-flex; align-items: stretch; flex: none;
  height: 36px;
  border: 1px solid #2A2A2E; border-radius: 6px;
  background: var(--white-plate); color: #111;
  overflow: hidden;
  font: 700 19px/1 var(--text);
  letter-spacing: .08em;
  text-transform: uppercase;
}
.plate__main { padding: 0 10px; display: flex; align-items: center; }
.plate__region {
  padding: 0 6px; border-left: 1px solid #111;
  font: 700 13px/1 var(--text); letter-spacing: .02em;
  display: flex; flex-direction: column; align-items: center; justify-content: center;
  gap: 2px;
  background: var(--white-plate);
}
/* Флаг: три полосы 9x5. Рисуется фоном, а не картинкой - это три строки
   CSS против отдельного файла и ещё одного круга по сети. */
.plate__region::after {
  content: ""; display: block;
  width: 9px; height: 5px;
  border: .5px solid #888;
  background: linear-gradient(180deg,
    #FFF 0 33.3%, #2E5BFF 33.3% 66.6%, #E1322D 66.6% 100%);
}

/* В строке списка номер стоит в мете, рядом с числом работ: это опознание
   машины, а не заголовок. Отсюда 20px и мелкий регион без флага - флаг
   на пяти пикселях превращается в грязное пятно. */
.order .plate, .plate--inline {
  height: 20px;
  border-radius: 4px;
  font: 700 11px/1 var(--text);
  letter-spacing: .04em;
}
.order .plate__main, .plate--inline .plate__main { padding: 0 5px; }
.order .plate__region, .plate--inline .plate__region {
  padding: 0 4px; font: 700 9px/1 var(--text); gap: 0;
}
.order .plate__region::after, .plate--inline .plate__region::after { display: none; }

/* ============================================================
   СТАТУСЫ. Риска и цвет текста, а не пилюля.
   ============================================================ */
.tag {
  display: inline-flex; align-items: center; gap: 6px;
  padding: 0; border-radius: 0;
  font: 600 13px/1 var(--text);
  color: var(--muted);
  background: none;
}
.tag::before {
  content: ""; width: 7px; height: 7px; flex: none;
  border-radius: 50%;
  background: var(--muted);
}
/* «в работе» - обычная подпись без цвета: это не событие, а состояние,
   в котором машина находится большую часть времени. Цветом отмечено то,
   что случилось: выдана, готово - зелёным; ждёт денег - янтарным. */
.tag--work { color: var(--muted); }
.tag--work::before { display: none; }
.tag--done, .tag--ready { color: var(--signal); }
.tag--done::before, .tag--ready::before { background: var(--signal); }
.tag--wait { color: var(--amber); }
.tag--wait::before { background: var(--amber); }
.tag--check { color: var(--amber); }
.tag--check::before { background: var(--amber); }

.dot { width: 8px; height: 8px; border-radius: 50%; background: var(--signal); flex: none; }
.mark, .mark__status { font-size: 15px; }
.warn { color: var(--stamp); font-weight: 600; }

/* ============================================================
   КНОПКИ. Цель не ниже 48px, зазор между соседними 12px.
   ============================================================ */
.btn {
  display: flex; align-items: center; justify-content: center; gap: 10px;
  width: 100%; min-height: var(--btn-h);
  padding: 15px 18px;
  border: 0; border-radius: var(--r-xl);
  cursor: pointer;
  font: 600 17px/1.2 var(--text);
  letter-spacing: -.01em;
  color: var(--ink);
  background: var(--panel);
  box-shadow: var(--gleam);
  transition: transform var(--fast) var(--ease), background var(--fast) var(--ease);
}
.btn:active { transform: scale(.985); background: var(--raise); }
.btn svg { width: 20px; height: 20px; flex: none; }

/* Главное действие: белая кнопка со свечением под ней.
 *
 * До 06.09.2026 здесь был зелёный перелив «как их плёнка»: два градиента
 * и бегущий блик, восемь секунд на проход. Приём честный - студия продаёт
 * хамелеоны и перламутры, - но в новой сетке он мешал. Зелёный на кнопке
 * спорил с зелёным у денег («получено», «выдан»), и на экране «Деньги»
 * выходило три зелёных пятна разного смысла разом.
 *
 * Теперь цвет главной кнопки нейтральный, а единственная тень в приложении -
 * её свечение. Движения на кнопке нет: в макетах ничего не мигает
 * и не пульсирует.
 */
.btn--go {
  background: var(--white-plate);
  background-image: none;
  color: #0B0B0D;
  box-shadow: var(--btn-glow);
  font-weight: 600;
  animation: none;
}
.btn--go:active {
  background: #E4E4E0;
  background-image: none;
  animation: none;
}

/* Кнопка на снимке живёт по тем же правилам. */
.hero__cta {
  background: var(--white-plate);
  background-image: none;
  color: #0B0B0D;
  box-shadow: var(--btn-glow);
  animation: none;
}
.hero__cta:active { background: #E4E4E0; animation: none; }

/* Второе зелёное пятно на экране обесценивает первое. Главное действие
   в потоке остаётся заливным, действие внутри карточки становится тихим
   с зелёной подписью. */
/* Второе белое пятно на экране обесценивает первое: главная кнопка
   в потоке остаётся залитой, действие внутри секции - обводкой. */
.card .btn--go {
  background: transparent;
  color: var(--ink);
  border: 1px solid var(--edge-2);
  box-shadow: none;
}
.card .btn--go:active { background: var(--panel); }

/* Исключение - приёмка. Там карточка работы и есть содержимое экрана,
   а «Принять работу» - его единственное главное действие. Обводка вместо
   заливки делала обе кнопки одинаковыми, и выбор «принять или вернуть»
   переставал читаться с одного взгляда. */
.card.job .btn--go {
  background: var(--white-plate);
  color: #0B0B0D;
  border: 0;
  box-shadow: var(--btn-glow);
}
.card.job .btn--go:active { background: #E4E4E0; }

.btn--quiet {
  background: transparent; color: var(--ink);
  border: 1px solid var(--edge-2);
  box-shadow: none;
}
.btn--quiet:active { background: var(--raise); }

.btn--flag { background: var(--stamp-dim); color: var(--stamp); border: 1px solid rgba(255, 69, 58, .30); }

.btn:disabled {
  background: transparent;
  border: 1px solid var(--edge);
  /* Цветом, а не opacity: на тёмном она даёт грязь.
     Но не самым тусклым: подпись неактивной кнопки часто объясняет, ПОЧЕМУ
     она неактивна («Ничего не выбрано»), и такое надо читать. На .38 выходило
     3.16 при норме 4.5. Неактивность и так видна по отсутствию заливки. */
  color: rgba(235, 235, 245, .52);
  box-shadow: none;
  cursor: default;
}
.btn:disabled:active { transform: none; }

/* Было 8px. Соседние кнопки одного веса. */
.btn + .btn { margin-top: 12px; }
/* Своего верхнего отступа у кнопки нет, и строка текста над ней его тоже
   не даёт: «Сделано» в задаче и «Выплатить» в деньгах вставали к подписи
   вплотную, ноль пикселей при общем ритме в двенадцать. */
.row + .btn, .paylines + .btn { margin-top: 12px; }

/* Между списком и кнопкой под ним - 24 пикселя, а не ноль.
 *
 * 13.09.2026, владелец: «проверь все вёрстки, чтобы нельзя было случайно
 * куда-то кликнуть». Замер показал ровно это: последняя строка машины
 * и кнопка «Новый наряд» стояли впритык, зазор 0. Промах пальцем по строке
 * заводил новый наряд - действие с другими последствиями, чем «открыть».
 *
 * Между однородными строками зазор оставляем нулевым намеренно: там
 * промах открывает соседнюю машину, и это не беда. Правило про 24 пикселя
 * действует только на границе «список - действие». */
.card.order + .btn,
.act + .btn,
.jumps + .btn,
.week + .btn,
.card.order + .linkbtn,
.act + .linkbtn { margin-top: 24px; }

/* Граница «переход - действие» в карточке наряда.
 *
 * Замер 13.09.2026 на живом наряде: строка «Заметки и фото» и ссылка
 * «удалить наряд» стояли впритык, зазор 0. У ссылки цель добирается
 * псевдоэлементом до 48 пикселей, то есть невидимая её часть заходила
 * на восемь пикселей внутрь строки заметок - нажатие по низу строки
 * попадало в удаление наряда.
 *
 * То же между кнопкой «Машина выдана, закрыть наряд» и строкой чек-листа.
 */
.jump + .linkbtn,
.jump + .btn,
.btn + .jump,
.btn + .act,
.linkbtn + .jump { margin-top: 24px; }

/* Удаление отделяется всегда и от всего: это единственное действие
   в приложении, которое нельзя отменить. */
.linkbtn--drop { margin-top: 28px; }

/* Секция, которая открывается нажатием. Подсветка во всю ширину, как
   у строки списка: без неё непонятно, что карточка вообще нажимается. */
.card--tap { cursor: pointer; }
.card--tap:active { background: var(--panel); box-shadow: 0 0 0 var(--pad) var(--panel); }
/* То же для текстовой ссылки, и здесь это не про воздух, а про палец:
   её цель добирается псевдоэлементом до 48px, то есть на 8px выше рамки.
   Впритык к кнопке сверху цели перекрывались, и «напомнить клиенту»
   отбирало нижнюю кромку у «Оплачено 15 000 ₽». */
.btn + .linkbtn, .row + .linkbtn, .linkbtn + .btn { margin-top: 12px; }
/* Необратимое действие отбивается от частого. */
.btn--flag, .btn--go + .btn--quiet { margin-top: 24px; }

/* ============================================================
   ВЗВЕДЁННАЯ КНОПКА. Всё, что уходит человеку наружу, требует
   двух нажатий. ui.js подменяет текст и вешает .armed; класс
   переименовывать нельзя.

   Янтарный больше нигде в приложении не встречается: взведённое
   состояние нельзя спутать ни с обычной кнопкой, ни с ошибкой.
   ============================================================ */
.armed,
.btn.armed,
.btn--quiet.armed,
.linkbtn.armed {
  background: var(--amber) !important;
  color: var(--amber-ink) !important;
  border-color: var(--amber) !important;
  font-weight: 700 !important;
  box-shadow: var(--gleam-strong), 0 0 0 3px rgba(232, 177, 76, .22) !important;
}
.linkbtn.armed {
  padding: 10px 14px; border-radius: var(--r-sm);
  text-decoration: none;
}

/* Текстовая кнопка внутри строки. Цель добирается псевдоэлементом,
   а не раздуванием вида. */
.linkbtn {
  position: relative;
  display: inline-flex; align-items: center; gap: 6px;
  min-height: 32px;
  padding: 4px 2px;
  border: 0; background: none; cursor: pointer;
  color: var(--ink-2);
  font: 400 15px/1.2 var(--text);
}
.linkbtn::after {
  content: ""; position: absolute;
  left: -10px; right: -10px; top: 50%;
  height: 48px; transform: translateY(-50%);
}
.linkbtn--on { color: var(--ink); }
/* «Убрать» красным, «изменить» обычным: это разные по цене действия,
   и одинаковыми их делать нельзя - промахнётся палец, пропадёт работа.
   Редизайн потерял цвет, и «удалить наряд» выглядело как «изменить». */
.linkbtn--drop { color: var(--stamp); }

/* ============================================================
   ВИТРИНА КЛИЕНТА
   ============================================================ */

/* Снимок из их бокса во весь верх экрана.
 *
 * До 23.08.2026 фото было полоской в 300 пикселей с полями по бокам, под ним
 * три одинаковые строки-действия. Экран читался как меню: серый список,
 * в котором главное действие ничем не отличалось от остальных.
 *
 * Теперь снимок идёт от края до края и от самого верха, под шапку. Шапка
 * над ним прозрачная, линии под ней нет, пока экран не тронут: сверху
 * человек видит машину, а не полоску с названием. Запись живёт прямо
 * на снимке - это единственное действие, ради которого сюда заходят.
 */
.hero {
  position: relative;
  /* Вылезаем из полей main и уходим под шапку: она 56px с безопасной зоной.
     Боковые поля берём из той же переменной, что и поля страницы.
     Раньше здесь стояло -14px при --pad: 20px, и «фото во весь экран»
     не доходило до краёв на 6 пикселей с каждой стороны: замер на айфоне
     07.09.2026 - снимок 363 при окне 375. Владелец: «у клиента на айфоне
     всё криво». По бокам главного снимка стояли полоски фона, и это
     первое, что видит клиент, открыв приложение.
     Числом такое не держится: поля страницы поменяли, а тут забыли. */
  margin: calc(-1 * (56px + env(safe-area-inset-top, 0px)))
          calc(-1 * var(--pad)) 24px;
  padding: calc(96px + env(safe-area-inset-top, 0px)) 20px 22px;
  /* dvh, а не vh: на айфоне vh считается по самому высокому окну, без
     панелей, а в вебвью Телеграма видно меньше - блок оказывается выше
     экрана, и страницу ведёт, когда панель появляется и исчезает.
     Строка с vh оставлена первой как запас для iOS до 15.4, где dvh
     ещё нет: браузер возьмёт то, что понимает. */
  min-height: 74vh;
  min-height: 74dvh;
  display: flex; align-items: flex-end;
  background: var(--panel);
  overflow: hidden;
}
/* Обложка первого экрана без фотографии.
 *
 *  Макеты 06.09.2026: четыре цветных пятна под сильным размытием медленно
 *  плывут, поверх лежит тёмный градиент, из-под которого читается текст.
 *  Картинок нет вовсе - это чистый CSS, ноль килобайт по сети. Раньше
 *  студия без своего снимка получала ровную серую заливку, и первый экран
 *  выглядел незаполненным.
 *
 *  Фотография бокса, если студия её загрузила, важнее: там их настоящий
 *  цех. Поэтому градиент живёт только на .hero без класса --photo.
 *
 *  Движение медленное нарочно: 18-27 секунд на круг. Это фон, а не
 *  анимация, и заметить её можно, только если смотреть специально.
 */
.hero:not(.hero--photo)::before {
  content: ""; position: absolute; inset: -20%;
  background:
    radial-gradient(38% 32% at 22% 28%, #3A5BFF 0%, transparent 70%),
    radial-gradient(34% 30% at 74% 22%, #B44CFF 0%, transparent 70%),
    radial-gradient(40% 34% at 66% 68%, #FF5E7A 0%, transparent 70%),
    radial-gradient(36% 30% at 28% 74%, #19C6D9 0%, transparent 70%);
  filter: blur(60px);
  animation: hero-drift 8s ease-in-out infinite alternate,
             hero-hue 12s linear infinite;
}
@keyframes hero-drift {
  from { transform: translate3d(-4%, -3%, 0) scale(1.05); }
  to   { transform: translate3d(4%, 3%, 0) scale(1.15); }
}
@keyframes hero-hue {
  to { filter: blur(60px) hue-rotate(360deg); }
}
/* Тёмный градиент поверх пятен: снизу почти сплошной фон страницы, чтобы
   белый текст лежал на своём, а не на цветном. */
.hero:not(.hero--photo)::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(180deg,
    rgba(11,11,13,.35) 0%, rgba(11,11,13,.05) 22%, rgba(11,11,13,.55) 45%,
    rgba(11,11,13,.92) 62%, var(--paper) 78%);
}

/* Возврат из витрины в рабочий экран. Лежит поверх обложки, ниже шапки
   приложения, с тенью - под ним бывает светлый кадр. */
.hero__back {
  position: absolute; z-index: 2;
  top: calc(64px + env(safe-area-inset-top, 0px));
  left: var(--pad);
  color: var(--ink);
  text-shadow: 0 1px 4px rgba(0, 0, 0, .6);
}

.hero--photo::before {
  content: ""; position: absolute; inset: 0;
  background-image: var(--shot, none);
  background-size: cover; background-position: 50% 42%;
}
/* Затемнение снизу. Без него белые буквы теряются на светлом кузове,
   а нижняя граница снимка режет экран пополам. */
/* Затемнение снизу. Без него белые буквы теряются на светлом кузове,
 * а нижняя граница снимка режет экран пополам.
 *
 * Голубое пятно, которое здесь стояло 23.08.2026, убрано: в палитре
 * и без него было шесть цветовых семейств, а это добавляло седьмое.
 * Свет на нижнюю часть кадра теперь даёт сама фотография.
 */
.hero--photo::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(180deg,
      rgba(10,12,14,.55) 0%, rgba(10,12,14,.12) 28%,
      rgba(16,18,21,.72) 62%, var(--paper) 100%);
}
/* Второй слой обложки: в нём проявляется СЛЕДУЮЩИЙ кадр, пока под ним
   ещё стоит текущий. Одним слоем плавно не сменить - background-image
   не анимируется, и смена шла бы рывком через чёрное.

   Порядок отрисовки держится сам собой: ::before рисуется первым,
   потом дети в порядке разметки, потом ::after. Слой вставляется первым
   ребёнком, то есть ложится НА фотографию и ПОД затемнение, иначе
   проявляющийся кадр перекрыл бы градиент и белый текст поплыл. */
.hero__fade {
  position: absolute; inset: 0;
  background-image: var(--shot-next, none);
  background-size: cover; background-position: 50% 42%;
  opacity: 0; transition: opacity 1100ms cubic-bezier(.4,0,.2,1);
  pointer-events: none;
}
/* Кадр меняется сам, без участия человека. Тем, кто просил систему
   убрать анимацию, обложку оставляем неподвижной. */
@media (prefers-reduced-motion: reduce) {
  .hero__fade { transition: none; }
}

.hero__body { position: relative; z-index: 1; width: 100%; }

.hero__eyebrow { margin: 0 0 10px; color: rgba(255,255,255,.80); text-shadow: 0 1px 3px rgba(0,0,0,.7); }
/* Адрес и часы приходят двумя span без разделителя. Без flex они
   склеиваются в «Приморский пр., 72Ежедневно 11:00-21:00». */
.hero__meta {
  display: flex; flex-wrap: wrap; align-items: baseline;
  gap: 4px 12px;
  margin: 10px 0 0; font-size: 15px; color: var(--ink-2);
  text-shadow: 0 1px 3px rgba(0,0,0,.6);
}
.hero__meta > span + span::before {
  content: "·"; margin-right: 12px; color: var(--muted);
}
.hero__slot {
  display: inline-flex; align-items: center; gap: 8px;
  margin: 28px 0 0; padding: 0;
  border-radius: 0;
  background: none;
  border: 0;
  color: var(--ink);
  font: 400 15px/1.3 var(--text);
}
/* Точка перед строкой - весь цвет, который есть на первом экране. */
.hero__slot::before {
  content: ""; width: 6px; height: 6px; flex: none;
  border-radius: 50%;
  background: var(--signal);
}
.hero__slot .dot { display: none; }

/* Запись прямо на снимке. Слева действие, справа время: человеку не нужно
   читать строку целиком, чтобы понять, когда его примут. */
.hero__cta {
  /* По центру, а не по краям: с 08.09.2026 у кнопки один ребёнок.
     Плашка с датой убрана - её принимали за выбранный слот. */
  display: flex; align-items: center; justify-content: center; gap: 12px;
  width: 100%; min-height: 58px;
  margin-top: 20px; padding: 14px 18px;
  border: 0; border-radius: var(--r-md);
  color: var(--signal-ink);
  box-shadow: var(--gleam-strong), var(--drop-lift);
  cursor: pointer;
  transition: transform 90ms var(--spring), background var(--fast) var(--ease);
}
.hero__cta:active { transform: scale(.985); }
.hero__cta-main {
  font: 700 18px/1.2 var(--text); letter-spacing: -.01em;
  /* Не рвать по буквам. `overflow-wrap: anywhere` в теле страницы стоит
     намеренно: слитное слово из данных иначе распирает вёрстку. Но на
     кнопке данных нет, там наш собственный текст, и «Записатьс / я»
     недопустимо ни при какой ширине. */
  overflow-wrap: normal;
}
.hero__cta-when {
  font: 400 15px/1.2 var(--text);
  font-variant-numeric: tabular-nums;
  padding: 0; border-radius: 0;
  background: none;
  color: rgba(11, 11, 13, .55);
  /* Перенос запрещён: на 320 пикселях «12 авг, 12:00» вставало двумя
     строками. Замер из ветки айфонной вёрстки - подпись 105 + зазор 12 +
     время 101 + поля кнопки 36 = 254 при 280 доступных, места хватает. */
  white-space: nowrap;
}

/* Крупные строки-действия. Было margin-bottom 10px, стало 12px,
   высота гарантирована 72px. */
.act {
  display: flex; align-items: center; gap: 14px;
  width: 100%; min-height: var(--row);
  margin: 0; padding: 12px 0;
  text-align: left; cursor: pointer;
  background: none; color: var(--ink);
  border: 0; border-radius: 0;
  box-shadow: none;
  font: 400 17px/1.35 var(--text);
  transition: background var(--fast) var(--ease);
}
.act + .act { border-top: 1px solid var(--edge); }
.act:active { background: var(--panel); box-shadow: 0 0 0 var(--pad) var(--panel); }
.act:active { transform: scale(.99); background: var(--raise); }
.act--go {
  border-color: rgba(53, 196, 106, .35);
  background: linear-gradient(180deg, rgba(53,196,106,.13), rgba(53,196,106,.05));
}
.act--go .act__head { color: var(--signal); }
.act__icon {
  width: 28px; height: 28px; flex: none;
  display: grid; place-items: center;
  border-radius: 0;
  background: none;
  color: var(--ink-2);
  box-shadow: none;
}
.act--go .act__icon { background: var(--signal-dim); color: var(--signal); }
.act__icon svg { width: 22px; height: 22px; }
.act__body { flex: 1; min-width: 0; }
.act__head { display: block; font: 600 17px/1.25 var(--text); letter-spacing: -.01em; }
.act__sub { display: block; margin-top: 3px; font-size: 13px; color: var(--muted); }
.act__arrow { flex: none; color: var(--faint); display: grid; place-items: center; }
.act__arrow svg { width: 18px; height: 18px; }

/* ============================================================
   ПРАЙС И ДЕНЬГИ
   Суммы всех строк секции стоят в одной вертикали справа.
   ============================================================ */
/* Прайс. Подложка и вертикальная линия колонки сумм сняты: в макетах
   списки живут на фоне страницы, а колонку держит выравнивание, а не
   нарисованная черта. */
.pricelist {
  background: none;
  border: 0;
  border-radius: 0;
  padding: 0;
  margin-bottom: 12px;
  box-shadow: none;
}
.price {
  display: flex; align-items: baseline; gap: 14px;
  justify-content: space-between;
  padding: 14px 0;
  border-top: 1px solid var(--edge);
}
.price:first-child { border-top: 0; }
.price__name { flex: 1; min-width: 0; font-size: 16px; }
/* Колонка сумм держит свою ширину, и селектор здесь длиннее нарочно.
 *
 * Ниже в файле стоит сплошное `.card *, .price > * { min-width: 0 }` -
 * оно нужно, чтобы дети flex-строк не распирали вёрстку. Но по весу
 * (0,1,1) оно сильнее короткого `.price__sum` (0,1,0) и молча съедало
 * ширину колонки: замер на 375 пикселях 07.09.2026 - сумма 70 пикселей
 * вместо 104.
 *
 * А вертикальная линия, которая отбивает эту колонку, нарисована фоном
 * на постоянном расстоянии от края карточки. Колонка съехала вправо,
 * линия осталась на месте - и прошла ПОСЕРЕДИНЕ названий услуг.
 * Именно это владелец и показал снимком: «в услугах, когда за клиента
 * заходишь».
 *
 * Так что дело не в линии. Ширину колонки возвращаем, и линия сама
 * встаёт в промежуток между названием и суммой. */
.pricelist .price__sum, .price__sum {
  flex: none; min-width: 104px; text-align: right;
  font: 600 17px/1.2 var(--text);
  letter-spacing: -.01em;
}
.price__sum--ask { font-weight: 400; font-size: 15px; color: var(--muted); }
/* ПРАЙС - НАСТОЯЩАЯ ТАБЛИЦА, А НЕ СТОЛБИК FLEX-СТРОК.
 *
 * Владелец 07.09.2026, после починки съехавшей колонки: «делай таблицу».
 * Речь про переносы: 16 названий из 34 на 375 пикселях шли в две строки.
 *
 * Колонка сумм держала 104 пикселя - ширину самой длинной подписи
 * «от 330 000 ₽» - и держала их в КАЖДОЙ строке, хотя в большинстве
 * стоит «25 000 ₽» на семьдесят шесть. Двадцать восемь пикселей
 * отбирались у названия в каждой строке ради двух строк, которым они
 * действительно нужны.
 *
 * Flex иначе и не умеет: строка считает ширину сама, ничего не зная
 * о соседях, и ради ровного столбика цифр ширину приходится назначать
 * наперёд по самой длинной подписи. Таблица считает колонку по своему
 * содержимому и делится результатом со всеми строками сразу.
 *
 * border-collapse: collapse обязателен. По умолчанию у таблицы
 * border-spacing 2px: линии разошлись бы зазорами, а горизонтальные
 * волоски удвоились бы на стыках строк.
 *
 * Вертикальная линия теперь граница ячейки, а не фон карточки на
 * постоянном расстоянии от края. Из-за того фона она и прошла посреди
 * названий, когда колонка съехала: фон стоял на месте, текст двигался.
 * Разойтись с колонкой граница ячейки не может по устройству. */
.pricelist__rows { display: table; width: 100%; border-collapse: collapse; }
.pricelist__rows .price { display: table-row; border-top: 0; }
.pricelist__rows .price__name,
.pricelist__rows .price__sum {
  display: table-cell; vertical-align: baseline;
  border-top: 1px solid var(--edge);
}
.pricelist__rows .price__name { width: 100%; padding: 14px 14px 14px 0; }
.pricelist__rows .price__sum {
  /* Ширину больше не назначаем: её считает таблица. Переносить подпись
     цены нельзя - «от 330 000 ₽» в две строки читается как две цены. */
  min-width: 0; white-space: nowrap;
  padding: 14px 0 14px 14px;
  border-left: 1px solid var(--edge);
}
.pricelist__rows .price:first-child > * { border-top: 0; }
/* Итог перекрывает вертикальную линию колонки собственной подложкой.
 *
 * Линия нарисована фоном карточки на постоянном расстоянии 128 пикселей
 * от правого края, а сумма итога бывает шире своей колонки: «от 50 000 ₽
 * + осмотр» это 190 пикселей против 104, и линия проходила сквозь текст.
 *
 * Укоротить сумму нельзя, не соврав: приписка про осмотр и есть то,
 * из-за чего итог честный. Поэтому строка выходит на всю ширину
 * карточки и закрывает линию под собой. */
.price--total {
  border-top: 1px solid var(--edge);
  font-weight: 600;
  margin: 4px 0 0;
  padding: 14px 0;
  background: none;
}
.price--total .price__name { font-weight: 700; font-size: 17px; }
.price--total .price__sum { font-size: 19px; }

/* Итог по цеху - строка-итог, набирается как заголовок. */
.total {
  display: flex; justify-content: space-between; align-items: baseline;
  padding: 14px 0;
  margin-bottom: 0;
  background: none;
  border: 0; border-top: 1px solid var(--edge);
  font: 600 19px/1.2 var(--text);
  letter-spacing: -.01em;
}
/* А это не итог, а поясняющая строка под расписанием: «В работе 2 машины
   на 400 000 ₽, осталось получить 200 000 ₽». Заголовочным кеглем она
   притворялась итогом и выглядела лишней коробкой. */
.week__total {
  margin: 4px 2px 16px;
  padding: 0;
  background: none; border: 0;
  font: 400 15px/1.45 var(--text);
  color: var(--muted);
}
.summary-line { font-size: 15px; color: var(--ink-2); margin: 0 0 12px; }

/* Сводка тремя счётчиками. */
/* Сводка. Плитки с подложкой сняты: в макетах вместо трёх счётчиков
   стоит одна крупная сумма и подписи под ней. Числа остаются, но читаются
   как подпись к экрану - строкой, без рамок и без своего материала.
   Крупную сумму над ними ставит manager.js. */
.summary {
  display: flex; flex-wrap: wrap; gap: 4px 16px;
  margin: 6px 0 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
}
.summary__cell {
  display: flex; align-items: baseline; gap: 6px;
  padding: 0;
  background: none;
  border: 0;
}
.summary__n { font: 400 15px/1.3 var(--text); letter-spacing: 0; color: var(--ink-2); }
.summary__n--check { color: var(--amber); }
.summary__cell .muted { font-size: 15px; }

/* Шапка машины в списке выплаты.
   Владелец 06.09.2026: «оплачено почему то у всех машин, а не у одной».
   Строки шли сплошняком по времени приёмки, и отметить одну машину было
   нельзя. Шапка группы плотнее и светлее строк, чтобы группы читались
   как группы, а не как ещё одна работа. */
.payhead {
  margin-top: 12px; padding-top: 10px;
  border-top: 1px solid var(--edge);
  color: var(--ink); font: 600 15px/1.3 var(--text);
}
.paylines > .payhead:first-child { margin-top: 0; padding-top: 0; border-top: 0; }

.payline, .paylines .payline {
  display: flex; justify-content: space-between; gap: 12px;
  padding: 12px 0;
  border-top: 1px solid var(--edge);
  font-size: 15px;
}
/* Суммы стоят колонкой. Замер на 402 px до правки: левый край значений
   гулял по шести положениям (251, 281, 320, 329, 330, 342), потому что
   значение вставало там, где кончилась подпись. 84 px это самая длинная
   реальная сумма («310 000 ₽» = 74 px) плюс запас. */
.payline > .num, .payhead .num {
  flex: none;
  min-width: 84px;
  text-align: right;
}
.payline:first-child { border-top: 0; }
.payline--gap { margin-top: 10px; }
.payline__what {
  display: flex; align-items: center; gap: 12px;
  flex: 1; min-width: 0; color: var(--ink-2);
}
/* Подпись работы без суммы: сама работа и под ней «сумма не указана».
   Раньше эти слова стояли в колонке значений и разваливали её:
   надписи нужно 149 px против 45-59 px у суммы, и на 402 px она
   переносилась на две строки. */
.payline__col { display: grid; gap: 2px; min-width: 0; }
.payline__col .field-hint { margin: 0; }
/* Цвет и размер галочки задаём сами: accent-color красит её нашим зелёным,
   а не зелёным операционной системы, и 18 пикселей вместо 24 возвращают
   её в строку, а не над ней. */
.payline__what input[type="checkbox"],
.paylines input[type="checkbox"] {
  width: 18px; height: 18px; flex: none;
  accent-color: var(--signal);
  cursor: pointer;
}

/* Пара «подпись - значение». Значение справа держит свою ширину: «3 работы»
   ломалось на «3» и «работы», и перенос читался как сбой. Ужимается подпись
   слева, поэтому ей разрешено уходить уже своего минимума - иначе строка
   вылезала бы за карточку, а body её молча срезает.

   Шапку наряда правило обходит: там слева госномер с собственным flex: none,
   и запрет сжиматься ещё и марке уводил «Mercedes-Benz GLE 400d Coupe»
   на 73px за край экрана без всякой прокрутки. */
.card > .row:not(.order__head) > :first-child:not(:only-child) { min-width: 0; }
/* Кнопка тут исключение: она не «значение справа», а половина ряда,
   и flex: none оставлял её по ширине подписи - «Не похоже» выходило
   заметно уже «Похоже». Ширину кнопкам раздаёт `.row > .btn` выше. */
.card > .row:not(.order__head) > :last-child:not(:first-child):not(.btn) { flex: none; }
/* Подпись под работой: «мастеру 4 000 ₽», «к 12.09», «скидка 7%»,
   «нет телеграма клиента». Размер здесь обязателен.
   
   08.09.2026: правило стояло без размера, то есть подпись наследовала
   17 пикселей от body и рисовалась полужирной. В старой сетке она лежала
   внутри карточки с мелким шрифтом и разницы не было видно, а на плоском
   списке такая подпись читалась крупнее самой работы. На скриншоте
   владельца строка «нет телеграма клиента, дайте QR при приёмке» шла
   в две строки жирным и выглядела заголовком раздела. */
.item__pay { font: 400 13px/1.35 var(--text); }

/* ============================================================
   СПИСКИ ВЫБОРА: услуга, день, время
   ============================================================ */
.pick {
  display: flex; align-items: center; gap: 14px;
  width: 100%; min-height: 60px;
  margin-bottom: 12px; padding: 16px;
  text-align: left; cursor: pointer;
  background: var(--lift); color: var(--ink);
  border: 0; border-radius: var(--r-md);
  box-shadow: var(--gleam), var(--drop);
  font: 400 17px/1.3 var(--text);
  transition: transform var(--fast) var(--ease), background var(--fast) var(--ease);
}
.pick:active { transform: scale(.99); background: var(--raise); }
.pick__name { flex: 1; min-width: 0; font-weight: 500; }
.pick__price { flex: none; color: var(--muted); font-size: 15px; }
/* ТОЧКА ВЫБОРА У СТРОКИ УСЛУГИ.
 *
 * Владелец 07.09.2026: «не понятно, что кликается, надо чтобы точечкой
 * отмечалось». До этого выбранная строка выглядела ровно как
 * невыбранная: класс `pick--on` ставился в JS, а в CSS его не было
 * ВООБЩЕ - мой промах того же дня.
 *
 * Кружок пустой, пока не выбрано: он и есть приглашение нажать. */
.pick__dot {
  flex: none;
  width: 22px; height: 22px;
  border-radius: 50%;
  border: 1.5px solid var(--edge-2);
  display: grid; place-items: center;
  transition: border-color var(--fast) var(--ease),
              background var(--fast) var(--ease);
}
.pick__dot::after {
  content: "";
  width: 10px; height: 10px;
  border-radius: 50%;
  background: var(--signal-ink);
  transform: scale(0);
  transition: transform .16s cubic-bezier(.2, .9, .3, 1.35);
}
/* Строка выбора услуги плотнее обычной строки-перехода.
 *
 * Замер на 375 пикселях 07.09.2026: при общих отступах имени оставалось
 * 177 пикселей, и «Керамическое покрытие» переносилось на две строки,
 * хотя цена рядом занимает семьдесят шесть. Владелец про этот экран:
 * «всё криво и слишком близко» - тесно было именно имени.
 *
 * Отыгрываем 32 пикселя: поля 14 вместо 16, зазор 12 вместо 14, кегль
 * имени 16 вместо 17. Точка выбора и цена остаются на месте. */
.pick--tick { gap: 12px; padding: 14px; }
.pick--tick .pick__name { font-size: 16px; }
.pick--tick .pick__price { font-size: 14px; }

.pick--on { border: 1px solid var(--signal); background: var(--signal-dim); }
.pick--on .pick__name { font-weight: 600; }
.pick--on .pick__dot { background: var(--signal); border-color: var(--signal); }
.pick--on .pick__dot::after { transform: scale(1); }

/* Калькуляция под списком. Стоит на своём воздухе: раньше строчка
   «Выбрано 2: 45 000 ₽» лежала вплотную к зелёной кнопке и читалась
   как её подпись, а не как итог выбора. */
.picked-sum { margin: 22px 0 18px; }
.picked-sum .h2 { margin-bottom: 10px; }

.pick--off {
  background: transparent; border-style: dashed; border-color: var(--edge);
  color: var(--faint); cursor: default;
}
.pick--off:active { transform: none; background: transparent; }

/* Сетка времени. Слотов бывает до двадцати, поэтому это именно сетка,
   а не ряд из трёх чипов. */
.times {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: 12px;
  margin-bottom: 12px;
}
.time, .slot__time {
  min-height: 52px;
  display: flex; align-items: center; justify-content: center;
  border-radius: var(--r-md);
  border: 1px solid var(--edge-2);
  background: var(--lift);
  color: var(--ink);
  font: 600 17px/1 var(--text);
  font-variant-numeric: tabular-nums;
  cursor: pointer;
  box-shadow: var(--gleam);
  transition: transform var(--fast) var(--ease), background var(--fast) var(--ease);
}
.time:active { transform: scale(.97); background: var(--raise); }

.day { margin-bottom: 12px; }
.day__head {
  display: flex; justify-content: space-between; align-items: baseline;
  margin-bottom: 8px;
}
.day__name { font: 700 17px/1.2 var(--text); color: var(--ink); text-transform: none; letter-spacing: -.01em; }
.day__empty { font-size: 15px; color: var(--muted); padding: 6px 0 2px; }
.day--off { opacity: 1; }
.day--off .day__name { color: var(--muted); }
/* Заголовок секции в цеху.
 *
 * JS собирает их как .row.muted.month, а не .h2 - в manager.js это шесть
 * мест, плюс shifts.js и tasks.js. Без отдельного правила главная жалоба
 * владельца («заголовки надо выделить») на самом плотном экране остаётся
 * в силе: .muted красит их серым, .row.muted сажает до 15px, и заголовок
 * снова оказывается тише текста под собой.
 *
 * Тот же класс несёт разделитель месяца в истории. Там это тоже заголовок
 * секции, и выглядеть он должен так же.
 */
/* Месяц как кнопка: прошлые месяцы свёрнуты, по строке открываются.
   Владелец 06.09.2026: «только актуальный месяц показывало». Кнопке
   нужны свои сбросы - браузер сам даёт ей фон, рамку и центровку. */
.month--tap {
  width: 100%; background: none; border: 0; cursor: pointer;
  text-align: left; font: inherit; color: inherit;
}
.month--tap:active { opacity: .6; }

.row.muted.month {
  margin: 28px 0 12px;
  padding: 0;
  border: 0;
  font: 700 19px/1.25 var(--text);
  letter-spacing: -.01em;
  color: var(--ink);
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}
/* Правая половина строки - значение. Оно тише заголовка. */
.row.muted.month > span:last-child:not(:first-child) {
  font: 400 15px/1.2 var(--text);
  font-variant-numeric: tabular-nums;
  color: var(--muted);
  letter-spacing: 0;
  flex: none;
}

.week { margin-bottom: 12px; }
.slot {
  display: flex; gap: 12px; align-items: flex-start;
  padding: 14px 0;
  border-top: 1px solid var(--edge);
}
.slot:first-child { border-top: 0; }
.slot__time { min-height: 0; padding: 0; border: 0; background: none; box-shadow: none;
  font-size: 15px; color: var(--muted); width: 52px; justify-content: flex-start; }
/* Строка записи: машина, работа, клиент - тремя строками. Редизайн снял
   с блока колонку, и три span-а слиплись в один абзац: «BMW M8» рвалось
   пополам, слот раздувался до 151px вместо шестидесяти. */
.slot__body { display: flex; flex-direction: column; gap: 2px; flex: 1; min-width: 0; }
/* Машина - доминанта строки, как в списке нарядов: по ней узнают запись.
   Работа и клиент мельче не для красоты: колонка в слоте всего 183px,
   и на 15px «Керамическое покрытие» переносилось на вторую строку -
   строка записи раздувалась до 145px, а в дне их бывает шесть. */
.slot__car { font: 600 16px/1.25 var(--text); color: var(--ink); }
.slot__what { font-size: 14px; color: var(--ink-2); }
.slot__who { font-size: 13px; color: var(--muted); }
/* Телефон в расписании это ссылка tel:, по ней звонят. Двадцать пикселей
   высоты для звонка мало, а расширять зону псевдоэлементом здесь нельзя:
   слоты стоят вплотную, и невидимая зона залезла бы на соседнюю строку.
   Поэтому ссылка честно занимает 48px и делается заметной. */
.slot__tel {
  display: inline-flex; align-items: center;
  min-height: 48px;
  font-size: 15px;
  color: var(--signal);
  text-decoration: none;
}
.slot__sum { flex: none; font-weight: 600; }
/* Строка с галочкой. Сам квадратик системный и мелкий - 13px, - но нажимают
   по всей строке: label переключает свой input. Значит цель это строка,
   и она обязана быть не ниже 48px. Таких строк в приложении семь:
   согласие на обработку данных, «записываю клиента, а не себя», доп. работы
   в наряде и в предложении, чек-лист, исполнители, оклад мастера. */
.walkin,
label.row:has(> input[type="checkbox"]),
label:has(> input[type="checkbox"]):not(.consent__agree) {
  display: flex; align-items: center; gap: 12px;
  /* Не по краям: квадратик стоит первым, подпись должна идти сразу за ним. */
  justify-content: flex-start;
  min-height: 48px;
  padding: 8px 0;
  cursor: pointer;
  color: var(--ink-2);
  font-size: 15px;
}
/* Свой квадратик вместо системного. Системный - это 13px серого браузерного
   виджета, который в тёмном интерфейсе выглядит инородно, а на зелёном
   accent-color превращается в ядовитый лаймовый квадрат. */
input[type="checkbox"] {
  appearance: none; -webkit-appearance: none;
  width: 24px; height: 24px; flex: none; margin: 0;
  display: inline-grid; place-content: center;
  border: 1.5px solid rgba(235, 235, 245, .34);
  border-radius: 7px;
  background: rgba(255, 255, 255, .05);
  transition: background-color .16s ease, border-color .16s ease;
}
input[type="checkbox"]::after {
  content: "";
  width: 6px; height: 11px;
  margin-top: -2px;
  border: solid var(--void);
  border-width: 0 2.5px 2.5px 0;
  transform: rotate(45deg) scale(0);
  transition: transform .16s cubic-bezier(.2, .9, .3, 1.35);
}
input[type="checkbox"]:checked {
  background: var(--signal);
  border-color: var(--signal);
}
input[type="checkbox"]:checked::after { transform: rotate(45deg) scale(1); }
/* Пока запрос в пути, код гасит галочку. Системный вид блокировки ушёл
   вместе с appearance: none, поэтому рисуем его сами - иначе человек
   тычет в живую с виду галочку впустую. */
input[type="checkbox"]:disabled { opacity: .4; cursor: default; }
input[type="checkbox"]:focus-visible {
  outline: 2px solid var(--ink-2); outline-offset: 2px;
}

/* ============================================================
   ПРИМЕРКА ПЛЁНКИ
   ============================================================ */

/* ============================================================
   БЕГУНОК «ДО И ПОСЛЕ» в примерке
   ============================================================ */

/* pan-y обязателен: без него палец, ведущий бегунок вбок, уводил бы
   страницу вниз, а вниз в Telegram это жест закрытия приложения.
   С pan-y вертикальная прокрутка остаётся у страницы, горизонталь наша. */
.cmp {
  --cmp: 50%;
  --cmp-n: .5;
  position: relative;
  /* Сверху 14px не для красоты: над бегунком стоит ссылка «примерить ещё»,
     у неё зона нажатия шире самой надписи, и вплотную бегунок эту зону
     перекрывал. Ссылка теряла половину площади. */
  margin: 14px 0 12px;
  border-radius: var(--r-lg);
  overflow: hidden;
  touch-action: pan-y;
  cursor: ew-resize;
  user-select: none;
  -webkit-user-select: none;
  background: var(--panel);
}
/* Нижний снимок задаёт высоту, верхний ложится на него и режется. */
.cmp__after { display: block; width: 100%; }
.cmp__before {
  position: absolute; inset: 0;
  clip-path: inset(0 calc(100% - var(--cmp)) 0 0);
}
.cmp__before img {
  width: 100%; height: 100%;
  object-fit: cover;
  display: block;
}

/* Граница и ручка. Белая линия читается на любом кузове, тень держит её
   на светлом кадре. */
.cmp__handle {
  position: absolute; top: 0; bottom: 0;
  left: var(--cmp);
  width: 44px; margin-left: -22px;
  padding: 0; border: 0; background: none;
  display: grid; place-items: center;
  cursor: ew-resize;
  /* Жест на ручке прокрутке не отдаём. Правило читается браузером ОДИН
     раз, в начале касания, поэтому оно обязано стоять здесь заранее,
     а не выставляться из pointerdown посреди жеста.

     Замер 19.09.2026 настоящими касаниями, 390x844: при вертикальной
     дрожи пальца 14 px граница уезжала с 50% всего до 53.7%, а страница
     прокручивалась на 28 px - жест забирала прокрутка. Владелец:
     «еле двигается».

     У самой картинки остаётся pan-y: она занимает пол-экрана, и листать
     по ней страницу нужно. */
  touch-action: none;
}
.cmp__handle::before {
  content: ""; position: absolute; top: 0; bottom: 0; left: 21px;
  width: 2px; background: #fff;
  box-shadow: 0 0 6px rgba(0, 0, 0, .45);
}
.cmp__grip {
  position: relative;
  width: 38px; height: 38px;
  border-radius: 50%;
  background: rgba(255, 255, 255, .96);
  box-shadow: 0 2px 10px rgba(0, 0, 0, .45);
}
/* Стрелки внутри ручки рисуются рамками: две фигуры вместо картинки. */
.cmp__grip::before, .cmp__grip::after {
  content: ""; position: absolute; top: 50%;
  width: 0; height: 0;
  border: 5px solid transparent;
  transform: translateY(-50%);
}
.cmp__grip::before { left: 7px; border-right-color: #16181B; }
.cmp__grip::after  { right: 7px; border-left-color: #16181B; }

.cmp--live .cmp__grip { transform: scale(1.06); }

/* Подписи по углам. Пропадают, когда бегунок доехал до края: подпись
   «до» над кадром, где этого «до» уже не видно, только путает. */
.cmp__tag {
  position: absolute; top: 12px;
  padding: 5px 10px;
  border-radius: 999px;
  background: rgba(0, 0, 0, .55);
  color: #fff;
  font: 600 12px/1 var(--text);
  letter-spacing: .06em;
  text-transform: uppercase;
  pointer-events: none;
}
.cmp__tag--before {
  left: 12px;
  opacity: clamp(0, calc((var(--cmp-n, .5) - .04) * 14), 1);
}
.cmp__tag--after {
  right: 12px;
  opacity: clamp(0, calc((.96 - var(--cmp-n, .5)) * 14), 1);
}

@media (prefers-reduced-motion: reduce) {
  .cmp--live .cmp__grip { transform: none; }
}

.shot-box { margin-bottom: 12px; }
.shot {
  width: 100%; display: block;
  border-radius: var(--r-lg);
  border: 1px solid var(--edge);
}
.shot--result { margin-bottom: 12px; }
.hidden-input { position: absolute; width: 1px; height: 1px; opacity: 0; pointer-events: none; }

.presets-block { margin-bottom: 8px; }
.presets {
  display: flex; gap: 12px; overflow-x: auto;
  margin: 0 -14px; padding: 4px 14px 8px;
  scroll-snap-type: x mandatory;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
}
.presets::-webkit-scrollbar { display: none; }
.preset {
  /* Половина полки минус зазор: на узком экране видно РОВНО две карточки
     целиком, третья выглядывает краем и этим показывает, что полка
     листается. Раньше стояло 200px: на 375 пикселях вторая карточка
     обрезалась посреди слова, и это читалось не как «листай», а как
     сломанная вёрстка. Владелец: «очень неудобно».
     Пол при 150px нужен для 320-пиксельного айфона, там половина
     полки уже слишком узкая для двух слов в строке. */
  flex: none; width: calc(50% - 6px); min-width: 150px; min-height: 92px;
  scroll-snap-align: start;
  display: flex; flex-direction: column; gap: 6px;
  padding: 14px;
  text-align: left; cursor: pointer;
  border-radius: var(--r-md);
  border: 1px solid var(--edge-2);
  background: var(--panel);
  color: var(--ink);
  box-shadow: var(--gleam);
}
.preset--on { border-color: var(--signal); background: var(--signal-dim); }
.preset__head { color: var(--ink); font: 700 16px/1.2 var(--text); letter-spacing: 0; text-transform: none; }
.preset__sub { font-size: 13px; color: var(--muted); line-height: 1.35; }
/* .preset__dabs убран вместе с разметкой: см. .chip__dab ниже. Состав
   образа читается словами под названием, а не тремя квадратиками. */

/* Плитка материала: настоящий образец, а не абстрактная кнопка.
   Это язык товара - глянец, сатин, мат клиент видит в веере. */
.chips { display: flex; flex-wrap: wrap; gap: 12px; margin-bottom: 12px; }
.chip {
  display: inline-flex; align-items: center; gap: 8px;
  min-height: 40px;
  padding: 8px 14px;
  border-radius: 20px;
  background: none; color: var(--ink);
  border: 1px solid var(--edge-2);
  box-shadow: none;
  font: 400 15px/1.2 var(--text);
  cursor: pointer;
  transition: transform var(--fast) var(--ease), background var(--fast) var(--ease);
}
.chip:active { transform: scale(.97); }
/* Выбранный чип белый, сумма внутри него тёмная на белом. Зелёная обводка
   снята: зелёный теперь значит «деньги получены», а выбор работы деньгами
   ещё не является. */
.chip--on {
  border-color: var(--white-plate);
  background: var(--white-plate);
  color: #0B0B0D;
  font-weight: 600;
}
.chip--on .muted, .chip--on .chip__sum { color: rgba(11, 11, 13, .55); }
/* .chip__dab убран вместе с разметкой: владелец 06.09.2026 просил убрать
   «кристаллики», и это была последняя россыпь мелких цветных квадратов -
   в чипах слотов и в карточках готовых образов. Выкраска самой плёнки
   в каталоге живёт отдельным элементом (.dab) и осталась на месте. */
.chips-group { margin-bottom: 12px; }
.chips-group .h2 { margin: 0 0 10px; font-size: 17px; }
.chips-group .chips { margin-bottom: 0; }
.chips-group .chips-group { margin: 12px 0 0 12px; }
.catalog { margin-bottom: 12px; }


/* Выкраски бренда. Внутри каталога чипы перестают быть пилюлями
   и становятся плитками с настоящим цветом плёнки: человек выбирает
   по цвету, а не по названию. Кружок 26px для этого мал.

   :has() держат все современные вебвью. Где его нет, каталог остаётся
   лентой пилюль - это рабочее состояние, а не поломка. */
.chips-group:has(> .catalog) .chips {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
  gap: 12px;
}
.chips-group:has(> .catalog) .chip {
  flex-direction: column; align-items: stretch; gap: 8px;
  min-height: 96px;
  padding: 8px 8px 10px;
  border-radius: var(--r-md);
  font: 500 12px/1.25 var(--text);
  text-align: left;
}
/* Название плёнки под выкраской: три строки максимум, дальше многоточие.
   Иначе сетка теряет ритм: у одних плёнок имя в слово, у других в строку. */
.chips-group:has(> .catalog) .chip > span:last-child {
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical;
  overflow: hidden; color: var(--ink-2);
}
.chips-group:has(> .catalog) .chip--on {
  border-color: var(--signal);
  box-shadow: var(--gleam), 0 0 0 2px rgba(53,196,106,.35);
}
.catalog { justify-content: flex-start; text-align: left; font-weight: 600; }
.catalogs { display: grid; gap: 12px; }

/* Что выбрано. На боевом экране 22.08.2026 эта строка висела сиротой
   между каталогами и сметой: «Metallic Yellow · 90330» без подписи,
   без подложки, просто обрывок текста посреди экрана. Теперь это
   именованный блок с меткой - видно, что это выбор, а не мусор. */
.picked {
  margin: 20px 0 12px;
  padding: 14px 16px;
  border-radius: var(--r-md);
  background: var(--panel);
  box-shadow: var(--gleam);
}
.picked::before {
  content: "Выбрано";
  display: block;
  margin-bottom: 6px;
  font: 600 12px/1.2 var(--text);
  letter-spacing: .09em;
  text-transform: uppercase;
  color: var(--muted);
}
.picked-line { margin: 0; font: 600 17px/1.35 var(--text); color: var(--ink); }
.picked .muted.picked-line { font-weight: 400; color: var(--muted); }
/* Карточка выбранной работы складывается СТОЛБИКОМ.
 *
 *  Здесь же был корень поломки, из-за которой 29.08.2026 разъезжались
 *  карточки снимков: класс ставил display:flex в направлении row, и всё
 *  содержимое карточки вставало в РЯД. Тогда починили точечно, только
 *  для .shots. Владелец 30.08.2026 прислал тот же разъезд на экране
 *  наряда: название работы сжималось в колонку и переносилось по слогам,
 *  «изменить/убрать» ложилось поверх имени мастера, «мастеру 80 000 ₽»
 *  разрывалось на три строки, а в режиме правки поля формы уезжали
 *  за правый край экрана.
 *
 *  Внутри карточки лежат три блока (название с ценой, мастер с кнопками,
 *  сумма мастеру), и в режиме правки - вся форма. Все они строки,
 *  а не колонки. Поэтому направление вертикальное. */
.picked__row { display: flex; flex-direction: column; gap: 6px; padding: 6px 0; }
/* Длинное название («Полная оклейка кузова в цветной PPF») не должно
   распирать строку и выдавливать цену за край. */
.picked__row .row > span:first-child { min-width: 0; overflow-wrap: anywhere; }
.picked__row .row { flex-wrap: wrap; }
/* Цена держится правого края, даже когда название заняло всю строку
   и цену перенесло вниз.
 *
 *  Владелец 31.08.2026 про коммерческое предложение: «там вёрстка ползёт
 *  чуть». В предложении названия длинные - «Стёкла: Атермальная тонировка
 *  Llumar Air 80». Замер на 375px: название занимало все 315 пикселей строки
 *  в три ряда, а цена уезжала на следующую строку ВЛЕВО, под название,
 *  и вместо «работа слева, деньги справа» получался столбик из двух
 *  прижатых к левому краю чисел.
 *
 *  Перенос строки сам по себе правильный: без него цена выдавливалась
 *  за край. Не хватало только прижать её вправо на новой строке. */
.picked__row .row > .num { margin-left: auto; }
.estimate { margin-top: 12px; }
.counter { font-size: 14px; color: var(--muted); text-align: center; margin: 12px 0 0; }

/* ============================================================
   КАРТОЧКА НАРЯДА. Самый плотный экран: тридцать блоков подряд.
   Именно здесь заголовки и отбивка решают всё.
   ============================================================ */
.car-head {
  display: flex; align-items: center; gap: 12px;
  margin: 24px 0 12px; padding-top: 20px;
  border-top: 1px solid var(--edge-2);
  font: 700 19px/1.25 var(--text);
  letter-spacing: -.01em;
}
.car-head:first-child { margin-top: 0; padding-top: 0; border-top: 0; }

.item__accept {
  /* Было 37px высотой у каждой работы, десяток подряд. */
  min-height: 48px;
  margin-top: 12px; padding: 12px 16px;
  font-size: 16px;
}
.item__comment { margin: 8px 0 0; font-size: 15px; color: var(--ink-2); }
.plan { margin-top: 12px; padding-top: 12px; border-top: 1px solid var(--edge); }
.add-work { margin-top: 12px; }

/* Исполнители работы. Владелец 13.08.2026: «машину может клеить два
   человека». Блок одного исполнителя сцеплен рамкой: иначе четыре поля
   подряд читаются как один длинный список, и непонятно, чья сумма к кому
   относится.

   Редизайн сделал блок горизонтальным флексом, и шесть полей одного
   мастера сплющило в строку: подпись «По окладу, отдельно не платим»
   зажималась в колонку 68px и разъезжалась на три строки. Возвращаем
   вертикаль. */
.crew__row {
  margin-bottom: 12px;
  padding: 12px;
  border: 1px solid var(--edge);
  border-radius: var(--r-md);
}
.crew__row .field { margin-bottom: 8px; }
.crew__row .field:last-of-type { margin-bottom: 0; }
.crew__drop { display: block; margin-top: 8px; }

.field {
  display: block; width: 100%; min-height: 52px;
  padding: 14px 16px;
  margin-bottom: 12px;
  border-radius: var(--r-sm);
  border: 1px solid var(--edge);
  background: var(--panel);
  color: var(--ink);
  font: 400 17px/1.3 var(--text);
}
/* Фокус светлой кромкой, без цвета. Зелёная рамка вокруг поля спорила
   с зелёным у денег: рамка выбранного поля читалась как «оплачено». */
.field:focus {
  outline: none;
  border-color: var(--edge-2);
  background: var(--raise);
  box-shadow: 0 0 0 3px rgba(255, 255, 255, .06);
}
.field::placeholder { color: var(--faint); }
/* Поле даты в Сафари держит СВОЮ минимальную ширину: под «дд.мм.гггг»,
   иконку календаря и внутренние отступы. width: 100% её не отменяет,
   и на узком айфоне поле распирает карточку - страница начинает ездить
   вбок, а левый край содержимого уходит за экран. Stephan 03.09.2026
   про наряд из шести работ: «в заказ нарядах вёрстка ползёт».
   В Хроме этого не видно: там поле сжимается само. */
input[type="date"].field, input[type="time"].field {
  min-width: 0; max-width: 100%;
  /* Одних min-width и max-width не хватило, и это доказано замером
     с телефона владельца 05.09.2026 13:43: «Новый наряд», экран 440px,
     поле 446px в родителе 412px. То есть правило применилось (браузер
     отдал min-width 0 и max-width 100%), а поле всё равно распёрло.
     Ширину задаёт не сам input, а нативный контрол внутри него, и пока
     он рисуется системой, он тянет одеяло на себя. Поэтому отключаем
     системный вид и ужимаем внутренний элемент со значением.

     Настольный WebKit это не воспроизводит: там поле честно сжимается
     до 412px. Проверить можно только на его айфоне, и дозор вёрстки
     сообщит сам, если вылет останется. */
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
}
input[type="date"].field::-webkit-date-and-time-value,
input[type="time"].field::-webkit-date-and-time-value {
  /* Внутренний элемент со значением по умолчанию центрируется и держит
     ширину под самый длинный формат. Прижимаем влево и отдаём ему ровно
     ширину поля, не больше. */
  text-align: left;
  width: 100%;
  min-width: 0;
  margin: 0;
}
/* Иконка календаря у нативного поля на айфоне занимает место справа
   и участвует в той же минимальной ширине. Оставляем её, но не даём
   ей растягивать поле. */
input[type="date"].field::-webkit-calendar-picker-indicator {
  margin-left: auto;
  flex: none;
}
select.field {
  appearance: none;
  background-color: var(--lift-2);
  color: var(--ink);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='9' viewBox='0 0 14 9'%3E%3Cpath d='M1 1l6 6 6-6' stroke='%239099A1' stroke-width='2' fill='none' stroke-linecap='round'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 16px center;
  padding-right: 44px;
}
select.field:focus { background-color: var(--lift-2); }
/* Пункты красим отдельно: часть систем берёт их цвет не от поля. */
select.field option { background: #1F1F23; color: #F5F5F2; }
select.field option:disabled { color: rgba(245, 245, 242, .45); }

.notes { margin-bottom: 12px; }
.note {
  padding: 14px 0;
  border-top: 1px solid var(--edge);
}
.note:first-child { border-top: 0; }
.note--mine .note__text { color: var(--ink); }
.note__author { font: 600 13px/1.2 var(--text); color: var(--muted); }
.note__text { margin: 0; font-size: 16px; white-space: pre-wrap; overflow-wrap: anywhere; }
.note__empty { color: var(--muted); font-size: 15px; padding: 12px 0; }
.note__input { margin-bottom: 12px; }
.note__photo { width: 100%; border-radius: var(--r-md); margin-top: 10px; display: block; }
.note__head { margin-bottom: 8px; align-items: baseline; }

/* Снимки в КП: две колонки, не три.
 *
 *  При трёх на телефоне 375px колонка выходит 117px, а подпись
 *  «поставить в шапку» одна занимает около 120px. Две ссылки в строке
 *  туда не влезали и вылезали поверх соседних снимков и за сетку -
 *  владелец 29.08.2026 прислал скриншот именно с этим.
 *
 *  Две колонки заодно чинят второе: по превью в 117px нельзя оценить
 *  примерку, а лежат они там ровно для этого. */
.shots { display: grid; grid-template-columns: repeat(2, 1fr); gap: 10px; margin-bottom: 12px; }
.shots img { width: 100%; aspect-ratio: 4 / 3; object-fit: cover; border-radius: var(--r-sm); display: block; }
/* Карточка снимка складывается СТОЛБИКОМ.
 *
 *  Корень поломки был здесь: у неё класс picked__row, а он ставит
 *  display:flex - то есть снимок и строка действий ложились рядом
 *  по горизонтали внутри ячейки шириной в пол-экрана. Замер на 375px:
 *  карточка 14..183, строка действий 129..193, десять пикселей наружу.
 *  Оттуда подписи и налезали на соседние снимки. */
.shots .card { display: block; }
/* Действия под снимком переносятся и умеют сжиматься. Даже если надпись
   когда-нибудь удлинится, наружу она больше не вылезет. */
.shots .row { flex-wrap: wrap; justify-content: flex-start; gap: 6px 12px; margin-top: 6px; }
.shots .row .linkbtn { min-width: 0; }

.qr { width: 160px; height: 160px; display: block; margin: 0 auto 12px; border-radius: var(--r-sm); background: #fff; padding: 8px; }

.issues, .done, .task, .mark { margin-bottom: 12px; }
.issues__head, .done__head, .mark__head { margin-bottom: 10px; }
.task__title { font: 600 17px/1.3 var(--text); margin: 0 0 6px; }
/* Срок держим на одной строке с именами: при двух исполнителях список
   переносится, и плашка уезжала к середине. По базовой линии, а не по
   верхнему краю - шрифты тут разного размера. */
.task > .row.muted { align-items: baseline; }
.mark__row { display: flex; align-items: center; gap: 12px; padding: 10px 0; }
.mark__chips { display: flex; gap: 10px; flex-wrap: wrap; }
.mark__note, .mark__hint { font-size: 14px; color: var(--muted); margin: 6px 0 0; }
/* Но не в поле ввода.
 *
 * `.mark__note` висит и на подписи, и на поле «чем запомнился». Поле
 * с размером меньше 16 пикселей айфон встречает зумом: при касании
 * страница увеличивается и сама назад НЕ возвращается - дальше вся
 * вёрстка и правда «ползёт». Владелец жаловался на это словами
 * «постоянно всё ползёт», и найдено это обходом всех экранов 07.09.2026:
 * из полей ввода во всём приложении мельче шестнадцати было ровно одно,
 * зато в карточке наряда - там, где он бывает каждый день.
 *
 * Шестнадцать - не «побольше для красоты», а порог Сафари. */
input.mark__note, textarea.mark__note { font-size: 16px; }
.mark__past { color: var(--muted); font-size: 15px; }

/* ============================================================
   СОГЛАСИЕ НА ОБРАБОТКУ ДАННЫХ
   ============================================================ */
.consent { margin-bottom: 12px; }
.consent__head { margin-bottom: 10px; }
.consent__list { margin: 0 0 12px; padding-left: 20px; }
.consent__item { margin-bottom: 6px; font-size: 16px; }
.consent__text, .consent__who { font-size: 15px; color: var(--ink-2); }
.consent__text { margin: 0; white-space: pre-wrap; }
.consent__note { font-size: 14px; color: var(--muted); margin-top: 10px; }
.consent__agree {
  display: flex; align-items: flex-start; gap: 14px;
  min-height: 56px;
  padding: 16px;
  margin: 16px 0;
  border-radius: var(--r-md);
  border: 1px solid var(--edge-2);
  background: var(--panel);
  cursor: pointer;
  font-size: 16px;
}
/* Размеры и вид галочка берёт из общего правила input[type="checkbox"];
   accent-color после appearance: none не работает, здесь он не нужен. */

/* Пустое место вместо галочки у работ без суммы. Размер тот же, что
   у галочки выше: замер 11.09.2026 показал, что без него подпись такой
   работы начиналась на 36 px левее соседних, и левая кромка группы
   выглядела рваной. */
.payline__место { width: 24px; height: 24px; flex: none; }

/* ============================================================
   СОСТОЯНИЯ
   ============================================================ */
/* Строка расписания нажимается: по ней открывается карточка записи.
   Подсветка во всю ширину, как в списке нарядов, - иначе непонятно,
   что строка вообще нажимается. */
.slot--tap { cursor: pointer; }
.slot--tap:active { background: var(--panel); box-shadow: 0 0 0 var(--pad) var(--panel); }

/* Пары «подпись - значение» в карточке записи. */
.sheet__rows { margin: 0 0 20px; }
.sheet__row {
  padding: 10px 0;
  border-bottom: 1px solid var(--edge);
  font-size: 15px;
}
.sheet__row:last-child { border-bottom: 0; }

.state {
  padding: 40px 16px; color: var(--muted); text-align: center; font-size: 16px;
}

/* ============================================================
   ПУСТОЕ СОСТОЯНИЕ. Круг с иконкой, крупная строка, подпись.
   Серая строчка по центру читалась как ошибка загрузки, а не как
   «работы нет»: человек ждал, что сейчас догрузится.
   ============================================================ */
.empty { padding: 80px 0 40px; text-align: center; }
.empty__ring {
  width: 56px; height: 56px; margin: 0 auto;
  display: grid; place-items: center;
  border-radius: 50%;
  border: 1.4px solid var(--ink-2);
  color: var(--ink-2);
}
.empty__ring .ico { width: 24px; height: 24px; }
.empty__head { margin: 22px 0 0; font: 600 20px/1.2 var(--text); letter-spacing: -.01em; }
.empty__sub { margin: 8px auto 0; max-width: 260px; font: 400 15px/1.35 var(--text); color: var(--ink-2); }
.state--error { color: var(--stamp); }

.done { color: var(--ink-2); }
.done__when { margin: 0; font: 500 17px/1.3 var(--text); color: var(--ink); }

/* ============================================================
   ПОДТВЕРЖДЕНИЕ ОТПРАВКИ КЛИЕНТУ.
   Новые классы, добавляются к существующим именам, ничего не ломают.
   ============================================================ */
.sheet-back {
  position: fixed; inset: 0; z-index: 60;
  background: rgba(0, 0, 0, .55);
  display: flex; align-items: flex-end;
}
@supports (backdrop-filter: blur(1px)) {
  .sheet-back { -webkit-backdrop-filter: blur(6px); backdrop-filter: blur(6px); }
}
.sheet {
  width: 100%; max-width: 480px; margin: 0 auto;
  padding: 20px var(--pad) calc(20px + var(--safe-b));
  border-radius: var(--r-xl) var(--r-xl) 0 0;
  /* Лист - единственное место с собственным материалом: он лежит ПОВЕРХ
     экрана, и без своей плотности сливался бы с ним. Размытие даёт
     стеклянный край, тень под листом не нужна. */
  background: var(--sheet);
  border-top: 0;
  box-shadow: var(--gleam);
}
@supports (backdrop-filter: blur(1px)) or (-webkit-backdrop-filter: blur(1px)) {
  .sheet {
    -webkit-backdrop-filter: blur(30px) saturate(180%);
    backdrop-filter: blur(30px) saturate(180%);
  }
}
.sheet__grip {
  width: 36px; height: 5px; border-radius: 3px;
  background: var(--faint);
  margin: 0 auto 18px;
}
.sheet__title { font: 600 22px/1.25 var(--text); letter-spacing: -.015em; margin: 0 0 10px; }
.sheet__what {
  padding: 14px 0; margin: 0 0 8px;
  border-radius: 0;
  border-top: 1px solid var(--edge);
  border-bottom: 1px solid var(--edge);
  background: none;
  font-size: 16px;
}
.sheet__to { font-size: 15px; color: var(--muted); margin: 0 0 20px; }

@media (prefers-reduced-motion: reduce) {
  * { animation: none !important; transition: none !important; }
}

:focus-visible {
  outline: 2px solid var(--ink-2);
  outline-offset: 2px;
  border-radius: 4px;
}


/* ============================================================
   СТРОКА-ПЕРЕХОД
   ============================================================

   Имя, счётчик, стрелка - одна строка вместо блока на восемьсот
   пикселей. Заметки, чек-лист и видео в карточке наряда занимали
   раскрытыми 1796px из 4766, то есть 38%, и выдавливали вниз кнопки,
   которыми пользуются каждый день.

   Высота 56px: столько же, сколько у остальных строк списка, чтобы
   переход не выделялся из ритма экрана. */
/* Второе объявление .jump возвращало подложку и рамку - оно стояло ниже
   первого и перебивало его. Оставлена одна строка списка: линия сверху,
   ничего вокруг. */
.jump:active { transform: scale(.99); background: var(--raise); }
.jump + .jump { margin-top: 8px; }
.jump__t { flex: 1; min-width: 0; }
.jump__n {
  flex: none; color: var(--muted); font-weight: 500; font-size: 15px;
}
/* «нет» вместо нуля: ноль читается как счётчик и заставляет всматриваться,
   слово - как состояние, и его видно не глядя. */
.jump__n--none { color: var(--faint); font-size: 14px; }
/* Строка, мимо которой проходить нельзя. Не цвет, а вес и метка: палитра
   сведена к одной оси и двум акцентам, третий владелец забраковал.
   Точка слева - та же, что у «идёт сейчас», но приглушённая до серого:
   она говорит «здесь что-то есть», а не «здесь действие». */
.jump__n--on {
  color: var(--ink); font-weight: 600;
  display: inline-flex; align-items: center; gap: 7px;
}
.jump__n--on::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%;
  background: var(--muted); flex: none;
}
.jump__a { flex: none; color: var(--faint); font-weight: 400; }


/* ============================================================
   ЛИЦО ПЛЁНКИ
   ============================================================

   Цвет лежит в самом блоке, свет накладывается сверху отдельным слоем.
   Свет не нарисован, а снят: кусок кузова из их же бокса, переведённый
   в чистую светлоту. Форма бликов поэтому подлинная - она повторяет
   изгиб панели, и нарисовать её нельзя.

   Владелец 27.08.2026 про рисованный вариант: «выглядит как глянцевая
   кнопка, а не как плёнка».

   Каждой плитке достаётся свой участок текстуры через --px/--py: сетка
   из восемнадцати одинаково бликующих образцов читается как обои,
   а вживую два выкраса рядом никогда не отражают свет одинаково. */
.dab {
  position: relative; display: block; width: 100%;
  border-radius: 9px; overflow: hidden;
  background: var(--c, #888);
  border: 1px solid rgba(255, 255, 255, .14);
}
/* ОБРАЗЕЦ - ЦВЕТ И ОДИН БЛИК. Снимка машины сверху больше нет.
 *
 * Владелец просил убрать «кристаллики» трижды. Первые два раза я убирал
 * не то: снял слой блёсток из JS, а сор давала накладка снимка. На каждую
 * плитку клался маленький серый кадр капота (tex/gloss.png) режимами
 * soft-light и hard-light, и на площади 100 на 70 пикселей от машины
 * оставались случайные белые штрихи - они и читались крошкой.
 *
 * Ответ был написан в этом же файле ниже, в блоке .dab--tiny: «ниже
 * двадцати пикселей текстура перестаёт быть поверхностью и становится
 * грязью, там оставляем цвет и один тонкий отлив». Теперь так у всех.
 *
 * Отделка не теряется: силой блика (глянец резкий, сатин мягче, мат
 * почти без него), заголовком раздела над плитками и названием плёнки.
 */
.dab::after {
  content: ""; position: absolute; inset: 0;
  background: linear-gradient(160deg,
    rgba(255, 255, 255, var(--блик, .3)) 0%,
    rgba(255, 255, 255, calc(var(--блик, .3) * .18)) 34%,
    rgba(0, 0, 0, .16) 100%);
}

/* Глянец: резкая световая полоса. Сатин между глянцем и матом - на этом
   экране он обязан читаться отдельно, иначе выбор плёнки становится
   угадыванием. Мат свет рассеивает, поэтому блик почти в ноль. */
.d-gloss      { --блик: .44; }
.d-satin      { --блик: .26; }
.d-matte      { --блик: .07; }
.d-supermatte { --блик: .02; }

/* Хром. Снимка хромовой машины у студии нет, выведен из глянцевого.
   Зеркало показывает не блик, а комнату: светлый потолок, резкая линия
   горизонта, отражённый пол. Без этой линии хром выглядит светло-серым. */
.d-chrome {
  background: linear-gradient(180deg,
    var(--c-hi) 0%, var(--c) 34%, var(--c-lo) 49%, #0A0A0C 50.5%,
    var(--c) 56%, var(--c-hi) 82%, var(--c-hi) 100%);
}
.d-chrome { --блик: .5; }

/* Хамелеон. Снимка тоже нет. Цвет уезжает по углу взгляда, поэтому под
   светом лежит переход между двумя оттенками, а не один. */
.d-chameleon {
  background: linear-gradient(114deg,
    var(--c-a) 0%, var(--c) 48%, var(--c-b) 100%);
}
.d-chameleon { --блик: .34; }

/* Прозрачная - не цвет, а верхний слой. Белый брусок про прозрачность
   не говорит ничего, шашечку узнают без подписи. */
.d-clear {
  background:
    linear-gradient(45deg, rgba(255,255,255,.12) 25%, transparent 25%,
      transparent 75%, rgba(255,255,255,.12) 75%) 0 0 / 14px 14px,
    linear-gradient(45deg, rgba(255,255,255,.12) 25%, transparent 25%,
      transparent 75%, rgba(255,255,255,.12) 75%) 7px 7px / 14px 14px,
    #2A2A2E;
}
.d-clear { --блик: .14; }

/* МЕЛКИЙ ОБРАЗЕЦ. Отличается теперь только скруглением: приём
   «цвет и один блик» с 08.09.2026 общий для всех размеров, и отдельного
   правила для мелкого больше не нужно. */
.dab--tiny { border-radius: 6px; }


/* ============================================================
   ВОРОНКА КАТАЛОГА ПЛЁНОК
   ============================================================

   Владелец 27.08.2026: «нужно чтобы было не всё вывалено, а сам выбирал
   по поиску цвет, тип, глянец, монохром, а затем марку плёнки». */

.pillbar {
  display: flex; gap: 8px; overflow-x: auto;
  padding: 2px 0 10px; scrollbar-width: none;
}
.pillbar::-webkit-scrollbar { display: none; }
.pill {
  flex: none; display: inline-flex; align-items: center; gap: 7px;
  min-height: 40px; padding: 0 14px; border-radius: 20px;
  background: var(--lift); color: var(--ink);
  border: 1px solid var(--edge-2); font: 500 14px/1 var(--text);
  white-space: nowrap; cursor: pointer;
}
.pill--on {
  border-color: var(--signal); background: var(--signal-dim);
  font-weight: 600;
}
.pill--x { color: var(--muted); }
.pill__dab { display: block; width: 17px; height: 17px; flex: none; }
.pill__dab .dab { height: 17px; }

/* Строка поиска. Взято у МГК: на тысяче позиций найти плёнку
   по артикулу фильтрами нельзя, а код с веера человек знает. */
.search { margin-bottom: 12px; }

.huehead { margin: 14px 0 8px; display: flex;
  justify-content: space-between; align-items: baseline; gap: 8px; }

/* Три колонки: восемнадцать плиток в две давали четыре экрана
   прокрутки только ради меню. */
.huegrid { display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 8px; margin-bottom: 12px; }
.huegrid--solo { grid-template-columns: 1fr; }
/* На узких экранах три колонки не держат строку «Серебристый 30»: замер
   05.09.2026 на 320px дал шесть порванных плиток из восемнадцати. Две
   колонки шире, и всё встаёт в строку. Порог 360, а не 320: на 360
   рвалась одна. */
@media (max-width: 360px) {
  /* :not обязателен. Одиночная плитка тоже .huegrid, специфичность
     у правил одинаковая, и медиазапрос ниже по файлу молча делал её
     половинной - «Прозрачные с блёстками» рвалось уже из-за меня. */
  .huegrid:not(.huegrid--solo) { grid-template-columns: repeat(2, 1fr); }
}
.huecell {
  /* Поля по бокам 6px, а не 8. Замер 05.09.2026: строке «Серебристый 30»
     при восьми не хватало ровно этих четырёх пикселей, и она рвалась
     на две. */
  padding: 8px 6px 9px; border-radius: var(--r-md);
  background: var(--lift); border: 1px solid var(--edge-2);
  cursor: pointer; text-align: left;
}
.huecell:active { transform: scale(.98); }
.huecell .dab { height: 40px; }
/* Кружок цвета на шаге выбора.
   Обводка не украшение: чёрная плёнка на тёмном фоне без неё выглядит
   дырой в карточке, а белая сливается с подложкой. Проверено на кадре:
   при .16 «Чёрный» читался как пустое место. */
.huedot {
  display: block; width: 46px; height: 46px; border-radius: 50%;
  background: var(--c);
  box-shadow: 0 0 0 1px rgba(255, 255, 255, .32),
              inset 0 -6px 12px rgba(0, 0, 0, .18);
  margin: 2px auto 2px;
}
.huecell--dot { text-align: center; }
.huecell--dot b { justify-content: center; gap: 6px; }
.huegrid--solo .huecell .dab { height: 52px; }
/* Имя и счётчик в одну строку: отдельной строкой счётчик добавлял
   по 17px на каждую из восемнадцати плиток, то есть почти экран. */
.huecell b {
  display: flex; justify-content: space-between; gap: 4px;
  font: 600 11px/1.3 var(--text); color: var(--ink); margin-top: 6px;
}
.huecell b i {
  font: 500 11px/1.3 var(--text); color: var(--muted);
  font-style: normal; font-variant-numeric: tabular-nums;
  /* Число не переносится и не сжимается.
     Замер каталога 05.09.2026: у трёх плиток из восемнадцати длинное имя
     («Серебристый», «Коричневый», «Фиолетовый») выдавливало счётчик,
     и «30» вставало столбиком - «3» и под ней «0». Это читается как
     поломка, а не как число. */
  white-space: nowrap; flex: 0 0 auto;
}
.huecell b span {
  /* Длинное имя переносится само, а не ломает соседа. min-width нужен:
     во флексе элемент по умолчанию не уже своего содержимого и вместо
     переноса распирает строку. */
  min-width: 0; overflow-wrap: anywhere;
}

.typebar { margin-bottom: 12px; }
.typebar .chip { min-height: 54px; padding: 8px 14px 8px 8px;
  font-size: 14px; }
/* 38px, а не 26: чип типа существует, чтобы показать поверхность.
   На 26px текстура отключается как грязь, и глянец с матом выходят
   одинаковыми цветными квадратами - то есть чип не делает своей работы. */
.typebar .dab { width: 38px; height: 38px; flex: none; border-radius: 8px; }

/* Панель фильтров не влезает в 375px и прокручивается пальцем.
   Чтобы это было видно, а не выглядело обрезанным, край подтуманиваем. */
.pillbar { position: relative; -webkit-mask-image:
  linear-gradient(90deg, #000 0, #000 calc(100% - 22px), transparent 100%);
  mask-image:
  linear-gradient(90deg, #000 0, #000 calc(100% - 22px), transparent 100%); }
/* «Сбросить» уезжала за край и была не видна вовсе. Ставим её первой,
   когда есть что сбрасывать: это единственная кнопка, которую ищут
   специально. */
.pill--x { order: -1; color: var(--stamp); border-color: var(--edge-2); }

.brands { display: grid; gap: 8px; margin-bottom: 12px; }
.brandrow {
  display: flex; align-items: center; gap: 10px; width: 100%;
  min-height: 52px; padding: 8px 12px; border-radius: var(--r-md);
  background: var(--lift); border: 1px solid var(--edge-2);
  color: var(--ink); font: 600 15px/1.2 var(--text);
  text-align: left; cursor: pointer;
}
.brandrow--on { border-color: var(--signal); background: var(--signal-dim); }
.brandrow__n { flex: 1; min-width: 0; }
/* .brandrow__d (пять образцов у марки) убран: владелец 05.09.2026 просил
   «убрать кристаллики», и это была единственная россыпь мелких цветных
   квадратов на экране. Стили удалены вместе с разметкой, чтобы не гнить
   мёртвым правилом. */
.brandrow__k {
  color: var(--muted); font-weight: 500; font-size: 14px;
  font-variant-numeric: tabular-nums;
}
.brandrow__a { color: var(--faint); font-weight: 400; }

.found { margin-bottom: 8px; }
.filmgrid { display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 10px; margin-bottom: 12px; }
/* Подзаголовок типа поверхности внутри сетки плёнок: глянец отдельно,
   мат отдельно. Во всю ширину сетки, иначе встанет плиткой в колонку. */
.filmgrid__head {
  grid-column: 1 / -1;
  margin: 6px 0 0;
  font: 600 13px/1.2 var(--text);
  letter-spacing: .04em; text-transform: uppercase;
  color: var(--muted);
}
.filmgrid__head:first-child { margin-top: 0; }
.filmcell {
  padding: 8px 8px 9px; border-radius: var(--r-md);
  background: var(--lift); border: 1px solid var(--edge-2);
  cursor: pointer; text-align: left;
}
.filmcell:active { transform: scale(.98); }
.filmcell.chip--on {
  border-color: var(--signal); background: var(--signal-dim);
}
.filmcell .dab { height: 58px; }
.filmcell b {
  display: block; font: 600 12px/1.3 var(--text);
  color: var(--ink); margin-top: 7px;
}
.filmcell i {
  display: block; font: 500 11px/1.3 var(--text);
  color: var(--faint); font-style: normal;
}

/* Выкраска под результатом примерки. Владелец сравнивает её, снятую макро
   с ладони, с бортом машины, снятым с трёх метров, и говорит «не похоже».
   Оба масштаба рядом снимают вопрос без единой генерации. Высоту держим:
   выкраски приходят разной формы, от квадрата до широкой полосы, и без
   ограничения полоса на пол-экрана отодвигала бы кнопки оценки за сгиб. */
.swatch__img {
  display: block; width: 100%; max-height: 190px;
  object-fit: cover; border-radius: var(--r-sm);
}
.swatch__hint { margin-top: 10px; }

/* Сравнение цветов: каталожный против замеренного со снимка мастера. */
.colcmp { margin: 12px 0; }
/* Переносим, а не держим в одну строку: после добавления плитки
   «отсюда цвет» плиток стало четыре, и на 320 px ряд вылезал за экран
   на 52 пикселя, на 360 - на 12. Замерено. */
.colcmp__row { display: flex; flex-wrap: wrap; gap: 14px 16px; }
.colcmp__one { text-align: center; }
.colcmp__dab { display: block; width: 72px; height: 72px;
               border-radius: 8px;
               border: 1px solid rgba(255, 255, 255, .15); }
.colcmp__one i { font-size: 12px; opacity: .7; font-style: normal; }
/* Сам снимок мастера. Размер как у квадратов, иначе строка из трёх
   разновысоких плиток читается как сбой вёрстки. */
.colcmp__shot { display: block; width: 72px; height: 72px; object-fit: cover;
                border-radius: 8px; background: var(--panel);
                border: 1px solid rgba(255, 255, 255, .15); }
/* Тот самый кусок снимка, по которому считается цвет: центральные 25%.
   400% это 1/0.25, центр по центру - и в плитке видно ровно то, что
   померили. Рамку поверх миниатюры рисовать нельзя: у неё object-fit:
   cover, и рамка показывала бы не то место. */
.colcmp__zone { display: block; width: 72px; height: 72px;
                border-radius: 8px; background: var(--panel);
                background-size: 400% 400%; background-position: center;
                border: 1px solid var(--signal); }
.colcmp__btns { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 10px; }
.swatchpick { margin-top: 8px; }

/* Повторная примерка под сравнением цветов: снимок уже применён,
   и результат надо перерисовать.
   Волосяная линия, а не только отступ: без неё кнопка читалась четвёртой
   в ряду решений по цвету, хотя она про другое. Проверено глазами
   на 375 px, отступа в 14 px не хватало. */
.refit {
  margin-top: 16px; padding-top: 16px; border-top: 1px solid var(--edge);
}

/* ============================================================
   СТРАХОВКА ОТ РАСПОЛЗАНИЯ. Причина, а не симптом.
   ============================================================

   Флекс-ребёнок по умолчанию имеет min-width: auto, то есть НЕ сжимается
   ниже своего содержимого. Хром в большинстве случаев всё равно ужимает
   текст, а Сафари честно распирает строку - и вся страница уезжает вбок.
   Владелец 03.09.2026, второй раз про наряды: «вёрстка ползёт, ты не всё
   поправил». У него айфон, у меня Хром: на 320, 360, 375, 390, 393, 412,
   430 и 440 пикселях, с крупным шрифтом и слитными словами - ровно.

   В приложении 50 флекс-контейнеров, и разрешение сжиматься было прописано
   у четырнадцати. Вместо охоты за конкретным местом снимаем запрет там,
   где живёт текст: в карточках, строках и списках.

   Тем, кто держать ширину ОБЯЗАН - иконки, кружки, миниатюры, госномер -
   это не мешает: у них flex: none, и сжимать их браузер не станет.

   Картинкам отдельная страховка: снимок шире контейнера тоже уводит
   страницу, а max-width это чинит раз и навсегда. */
.card *, .order *, .row > *, .jump > *, .price > *, .payline > *,
.summary__cell > *, .mark__row > *, .day__head > *, .slot > *,
.item > *, .booking > *, .hero__body > * { min-width: 0; }

/* Статус работы. Текст его задаёт код («ждёт», «на проверке»), но
   страховка нужна и здесь: тег - это inline-flex, а значит тоже
   распирает строку, если однажды в него попадёт что-то длинное. */
.tag { max-width: 100%; }

img, svg, video, canvas { max-width: 100%; }
