/* Оформление сервиса. Значения и правила — docs/reference/ui.md, решения — ADR-0027
   (три ширины, откуда взято) и ADR-0019 (кегль, контраст, доступность).
   Вёрстка идёт от телефона: всё ниже описывает телефон, медиазапросы только добавляют.

   Цвета затемнены против посадочной страницы: там текст рекламный, здесь его читают
   на улице, при солнце, с телефона в руке. Каждая пара «текст на фоне» — не ниже 4.5:1. */

:root {
  --paper:#ffffff; --surface:#f9f8f8; --line:#ebebeb; --line-soft:#f1f1f1;
  --ink:#262f3c;                 /* 13.5:1 на белом */
  --muted:#606c7e;               /* 5.3:1 на белом, 5.0:1 на карточке */
  --accent:#16b6d2;              /* только рамки и заливки: текста на нём не бывает */
  --accent-ink:#0a6c7d;          /* текст, ссылки, кнопки — 6.1:1 */
  --accent-2:#c8384a;            /* наведение — 5.1:1 с белым */
  --brand:#2b52cc;               /* имя сервиса в шапке — 6.2:1 на фоне шапки */
  --accent-soft:#e6f7fb; --accent-line:#cceef5;
  --on-accent:#ffffff;
  --frame:#d6dfeb;
  --price:#c62222;               /* 5.8:1 на белом */
  --danger-ink:#c0272d;          /* отмена и прочее необратимое — 5.9:1 на белом */
  --quota:#436f0c; --quota-bg:#eff8e4;   /* 5.5:1 на своей плашке */
  --warn:#8a6d0b; --warn-bg:#fff8dd;     /* 4.6:1 на своей плашке */
  --shadow:0 1px 2px rgba(38,47,60,.05), 0 8px 24px -12px rgba(38,47,60,.22);
  --r:12px;
  /* Шрифт системный: витрину открывают на рынке, с мобильной связи (ADR-0027). */
  --sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
}

* { box-sizing:border-box; }
html { -webkit-text-size-adjust:100%; }
/* Базовый кегль 18, и ни одна надпись в интерфейсе не мельче 16 (ADR-0019). */
body { margin:0; background:var(--paper); color:var(--ink); font-family:var(--sans);
       font-size:18px; line-height:1.6; }
img { max-width:100%; }
a { color:var(--accent-ink); }
/* Куда пришёл фокус с клавиатуры, видно на всём сервисе, а не только в полях
   формы: правила доступности пишутся один раз и на все экраны (ADR-0019).
   Поля ниже задают свою обводку сами — она частнее и остаётся в силе. */
:focus-visible { outline:3px solid var(--accent-ink); outline-offset:2px; }

.wrap { max-width:960px; margin:0 auto; padding:0 18px; }

/* ---------- шапка и подвал ---------- */
.top { border-bottom:1px solid var(--line); background:var(--surface); }
.top .wrap { display:flex; align-items:center; gap:16px; min-height:60px; flex-wrap:wrap; }
.top .brand { font-weight:800; letter-spacing:-.02em; text-decoration:none; color:var(--brand);
              margin-right:auto; }
.top nav { display:flex; gap:16px; flex-wrap:wrap; font-size:16px; align-items:center; }
.top nav a { color:var(--accent-ink); }
.top nav a:hover { color:var(--accent-2); }

main { padding:28px 0 48px; }
footer { padding:24px 0 40px; font-size:16px; color:var(--muted); }
/* Телефон в подвале — рабочая ссылка: с телефона по нему звонят, а не переписывают. */
footer .contacts { margin-bottom:.3em; }
footer .contacts a { font-weight:650; white-space:nowrap; }

/* Ссылка на экран кода стоит над контактами: ею пользуются чаще, чем звонят. */
footer .share { margin-bottom:.8em; }
footer .share a { font-weight:650; }

/* ---------- общее ---------- */
h1 { font-size:clamp(26px,5.2vw,34px); line-height:1.12; letter-spacing:-.024em;
     font-weight:800; margin:0 0 .4em; text-wrap:balance; }
h2 { font-size:clamp(20px,3.4vw,25px); line-height:1.2; letter-spacing:-.02em;
     font-weight:800; margin:1.4em 0 .5em; }
p { margin:0 0 1em; }
.lede { max-width:60ch; }
.muted { color:var(--muted); }
.eyebrow { font-size:16px; letter-spacing:.12em; text-transform:uppercase;
           color:var(--muted); font-weight:700; }

/* Кнопка не ниже 48 пикселей и достаёт до большого пальца (ADR-0019). */
.btn { display:inline-block; text-decoration:none; font-weight:600; font-size:17px;
       min-height:48px; padding:12px 26px; border-radius:999px;
       border:2px solid var(--accent-ink); background:var(--accent-ink);
       color:var(--on-accent); cursor:pointer; font-family:inherit; }
.btn:hover { background:var(--accent-2); border-color:var(--accent-2); }
.btn.ghost { background:transparent; color:var(--accent-ink); }
.btn.ghost:hover { background:var(--accent-ink); color:var(--on-accent); }

/* ---------- формы ---------- */
/* Узкая колонка: вход набирают одной рукой, стоя. На широком экране растягивать
   поле ввода через весь экран незачем. */
.form { max-width:26rem; }
.form label { display:block; font-size:16px; font-weight:650; margin-bottom:6px; }
.form input, .form select {
  width:100%; font:inherit; color:inherit; background:var(--paper);
  border:1px solid var(--frame); border-radius:9px; padding:12px 14px;
  min-height:48px; font-size:18px;
}
.form input:focus, .form select:focus {
  outline:2px solid var(--accent-ink); border-color:var(--accent-ink);
}
.form .field { margin-bottom:18px; }
/* Выбор из нескольких: кружок остаётся кружком. Правило выше растягивает
   любое поле на всю ширину — радиокнопке от этого становится плохо: она
   раздувается в круг на пол-экрана, а подпись уезжает на строку ниже
   (найдено на снимке формы отсечки, 11 сентября). */
.form input[type="radio"], .form input[type="checkbox"] {
  width:auto; min-height:0; min-width:22px; height:22px; margin:0 10px 0 0;
  flex:0 0 auto; padding:0;
}
/* Подпись варианта — обычный текст рядом с кружком, а не заголовок поля:
   заголовок здесь один, у всего выбора. Строка высотой в палец (ADR-0019). */
.form label:has(> input[type="radio"]), .form label:has(> input[type="checkbox"]) {
  display:flex; align-items:center; font-weight:400; font-size:18px;
  margin:0; min-height:44px; cursor:pointer;
}
.form .hint { font-size:16px; color:var(--muted); margin:6px 0 0; }
.form .actions { display:flex; gap:12px; flex-wrap:wrap; align-items:center; margin-top:24px; }
.form input.code { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:28px;
                   font-weight:800; letter-spacing:.22em; text-align:center; }

.errors { background:var(--warn-bg); border:1px solid var(--warn); border-radius:9px;
          padding:12px 14px; margin-bottom:18px; font-size:17px; }
.errors ul { margin:0; padding-left:18px; }

/* ---------- карточки ---------- */
.cards { display:grid; gap:16px; }
/* `position:relative` — не оформление: от карточки считается растянутый слой
   ссылки-заголовка, описанный ниже. */
.card { position:relative; background:var(--surface); border:1px solid var(--line);
        border-radius:var(--r); padding:18px; }
.card h3 { margin:0 0 .2em; font-size:18px; font-weight:700; }
.card p { margin:0; font-size:17px; color:var(--muted); }

/* Название рынка или прилавка — это переход, и выглядеть оно должно переходом.
   Здесь стояло `color:inherit; text-decoration:none`, и название читалось
   обычным заголовком: человек не понимал, что по нему переходят.
   Цвет и подчёркивание вместе, а не что-то одно: по одному цвету ссылку от
   заголовка не отличит тот, кто цвет различает плохо (ADR-0019, правило 23). */
.card a.title { color:var(--accent-ink); text-decoration:underline;
                text-underline-offset:3px; }
/* Нажимается вся карточка, а не одна строка названия: на телефоне цель выходит
   размером с палец, а не со строку. Пустой слой поверх карточки принадлежит
   самой ссылке — поэтому разметка не меняется, а клавиатуре и читалке экрана
   переход по-прежнему виден один, заголовком, а не двумя одинаковыми. */
.card a.title::after { content:""; position:absolute; inset:0; }
/* Прочие ссылки карточки уходят под этот слой и перестают нажиматься —
   поднимаем их обратно (в кабинете это «Заказов на ближайшие дни»). */
.card a:not(.title) { position:relative; }

/* Отклик до нажатия: видно, что карточка — цель. Только там, где переход есть:
   на странице продавца карточками набраны доводы, и подсвечивать в них нечего.
   `:focus-within`, а не `:focus`: фокус приходит на заголовок, а показать надо
   карточку целиком — обводка самой ссылки обнимает только текст. */
.card:has(a.title):hover { border-color:var(--accent-line); box-shadow:var(--shadow); }
.card:has(a.title):hover a.title { color:var(--accent-2); }
.card:has(a.title):focus-within { border-color:var(--accent-ink);
                                  box-shadow:var(--shadow); }

/* Состояние подписано словом, а не только цветом (ADR-0019, правило 23). */
.state { display:inline-block; font-size:16px; font-weight:700; border-radius:999px;
         padding:4px 12px; background:var(--line-soft); color:var(--muted); }
.state.on { background:var(--quota-bg); color:var(--quota); }
.state.off { background:var(--warn-bg); color:var(--warn); }

/* Фотография в карточке списка: прилавок узнают по ней, а не по названию
   (ТЗ 5.1). Кадр 4:3 — та же пропорция, в которой лежит превью (ADR-0015). */
.card-photo { display:block; width:100%; aspect-ratio:4/3; object-fit:cover;
              border-radius:9px; margin:0 0 12px; background:var(--line-soft); }

/* Города строкой: их единицы, и выпадающий список тут был бы лишним экраном. */
.towns { display:flex; flex-wrap:wrap; gap:10px; margin:0 0 16px; }
.town { display:inline-block; font-size:17px; font-weight:650; border-radius:999px;
        padding:10px 16px; background:var(--surface); border:1px solid var(--line);
        text-decoration:none; color:var(--accent-ink); }
.town.here { background:var(--accent-soft); border-color:var(--accent-line);
             color:var(--ink); }

/* Дни выдачи строкой — то же, что города на стартовой: их единицы, и список
   короче выпадающего. Выбранный день выделен, остальные — ссылки (ADR-0047). */
.days { display:flex; flex-wrap:wrap; gap:10px; margin:0 0 16px; }
.day { display:inline-block; font-size:17px; font-weight:650; border-radius:999px;
       padding:10px 16px; background:var(--surface); border:1px solid var(--line);
       text-decoration:none; color:var(--accent-ink); min-height:44px; }
.day.here { background:var(--accent-soft); border-color:var(--accent-line);
            color:var(--ink); }
/* Пометка про закрытый приём идёт второй строкой внутри той же таблетки:
   рядом со словом она разрывала бы строку дней на телефоне. */
.day .sub { display:block; font-size:16px; font-weight:400; color:var(--muted); }

/* Две двери перед списком рынков. Без них всё, что адресовано продавцу, уезжает
   вниз тем дальше, чем больше рынков, а покупатель читает про выгоды продавца
   вместо своих. Порядок внутри страницы важнее длины: сначала «кто вы», потом дело. */
.doors { display:grid; gap:14px; margin:26px 0 4px; }
@media (min-width:720px) { .doors { grid-template-columns:1fr 1fr; } }
.door { background:var(--surface); border:1px solid var(--line); border-radius:var(--r);
        padding:20px; display:flex; flex-direction:column; }
.door h2 { margin:0 0 .4em; font-size:clamp(19px,3vw,22px); }
.door p { color:var(--muted); font-size:17px; }
/* Кнопки прижаты к низу: у плашек разный текст, но одна линия действий. */
.door .actions { margin:auto 0 0; padding-top:8px; display:flex; gap:16px;
                 align-items:center; flex-wrap:wrap; }

/* Строка поиска по витрине (ADR-0053). Поле тянется во всю ширину, кнопка
   и «показать всё» встают рядом, а на узком экране переносятся под поле.
   Высота поля та же, что у кнопки: до обоих достаёт большой палец (ADR-0019). */
.filter { display:flex; flex-wrap:wrap; align-items:center; gap:10px 12px;
          margin:0 0 14px; }
.filter input { flex:1 1 12rem; min-width:0; font:inherit; font-size:17px;
                min-height:48px; padding:10px 14px; color:inherit;
                background:var(--paper); border:1px solid var(--frame);
                border-radius:9px; }

.empty { background:var(--accent-soft); border:1px solid var(--accent-line);
         border-radius:var(--r); padding:24px 20px; }
.empty p:last-child { margin:0; }
.state-row { margin-top:10px; }

/* Демо-рынок подписан на каждом экране: перепутать его с рабочим прилавком
   не должен ни покупатель, ни продавец (ADR-0019, правило 8). */
.demo { background:var(--warn-bg); border:1px solid var(--warn); color:var(--warn);
        border-radius:9px; padding:12px 14px; font-weight:650; margin:0 0 20px; }

/* ---------- карточка прилавка ---------- */
.panel { border-top:1px solid var(--line); padding-top:8px; margin-top:28px; }
.panel h2 { margin-top:.6em; }
.panel p:last-child { margin-bottom:0; }
.stall-photo { border-radius:var(--r); display:block; max-width:100%; height:auto; }
/* На странице прилавка снимок уже не главный: товар и цены важнее, поэтому
   в потоке стоит превью. Крупное открывается накладкой (.lightbox ниже) —
   тем же способом, что и снимок товара, и тоже без скрипта. */
.stall-photo.small { width:240px; max-width:60%; aspect-ratio:4/3; object-fit:cover; }
.photo { margin:0 0 16px; }

/* Снимок рынка в шапке его страницы устроен так же и теми же классами: способ
   смотреть фотографию в сервисе один (ADR-0059). Схема — исключение: это
   чертёж, его читают целиком и увеличивают пальцами, поэтому ни кадра 4:3,
   ни накладки у неё нет, а ширину держит `.wrap`. */
.scheme img { display:block; width:100%; height:auto; border-radius:var(--r);
              background:var(--line-soft); }
.scheme p { margin:10px 0 0; }

/* Снимок экрана в руководстве продавца (ADR-0061). Рамка обязательна: без неё
   светлый кадр сливается со страницей, и человек не понимает, где кончается
   объяснение и начинается экран. Ширина снимка — 390 CSS-пикселей, ровно та,
   в которой он снят; на широком экране он не растягивается, потому что
   растянутый вдвое кадр телефона выглядит браком, а не помощью.
   Высота отпущена в `auto`: атрибуты width и height в разметке держат место
   до загрузки, но перебивать их шириной из стилей нельзя — кадр вытянется
   в полосу (найдено 13.09.2026, сторожит `tests/test_ui.py`). */
.shot { margin:16px 0 0; max-width:390px; }
.shot img { display:block; width:100%; height:auto; border:1px solid var(--line);
            border-radius:9px; background:var(--paper); }
.shot figcaption { margin-top:8px; font-size:16px; color:var(--muted); }

/* Образец списка товара на странице продавца: строки, а не колонки. Что он
   должен показать — что список принимается любой, поэтому и выглядит он как
   прайс, переписанный от руки, а не как форма, которую надо заполнить. */
.sample { background:var(--surface); border:1px solid var(--line); border-radius:9px;
          padding:14px 16px; margin:0 0 16px; }
.sample p { margin:0 0 4px; }
.sample p:last-child { margin-bottom:0; }
.sample .head { font-weight:700; margin-top:12px; }
.sample .head:first-child { margin-top:0; }

/* Пары «что — сколько»: на телефоне столбиком, дальше в две колонки. */
.pairs { margin:0 0 16px; }
.pairs dt { font-size:16px; color:var(--muted); }
.pairs dd { margin:0 0 12px; font-weight:650; }

/* Квадратный код на своей странице: его снимают чужой камерой с вытянутой
   руки, поэтому он занимает ширину экрана, но не растёт бесконечно —
   на компьютере код шире ладони уже не читается лучше (ADR-0056). */
.qr { width:100%; max-width:340px; margin:0 auto 18px; }
.qr svg { display:block; width:100%; height:auto; }

.address { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-size:17px;
           background:var(--surface); border:1px dashed var(--frame); border-radius:9px;
           padding:12px 14px; overflow-wrap:anywhere; }

/* Необратимое действие спрятано за раскрытием и не стоит рядом с обычными. */
.danger { margin-top:28px; border:1px solid var(--warn); background:var(--warn-bg);
          border-radius:9px; padding:14px 16px; }
.danger summary { cursor:pointer; font-weight:700; }
.danger p { margin:.8em 0; font-size:17px; }

/* ---------- строки списка ---------- */
/* Строка товара: название слева, число справа — как на макетах телефона. */
.rows { width:100%; border-collapse:collapse; }
.rows td { border-bottom:1px solid var(--line-soft); padding:12px 0; vertical-align:top; }
.rows tr:last-child td { border-bottom:0; }
.rows .num { text-align:right; white-space:nowrap; font-variant-numeric:tabular-nums; }
.rows .act { text-align:right; white-space:nowrap; padding-left:12px; }
.rows .sub { font-size:16px; color:var(--muted); font-weight:400; }
/* Снимок товара в строке: узкая колонка, кадр 4:3 — тот же, что у превью. */
.rows .pic { width:72px; padding-right:12px; }
/* height:auto обязателен. У снимка в разметке стоят настоящие размеры файла
   (400×300) — они держат место до загрузки и не дают странице прыгать. Браузер
   читает их как CSS-подсказки: ширину наше правило перебивает, а высота осталась
   бы в 300 px, и кадр вытянулся бы в узкую полосу. */
.thumb { display:block; width:72px; height:auto; aspect-ratio:4/3;
         object-fit:cover; border-radius:8px; background:var(--line-soft); }
.thumb.none { display:flex; align-items:center; justify-content:center;
              font-size:16px; color:var(--muted); }
/* Снимок товара крупно — накладкой во весь экран и без скрипта: нажатие ставит
   в адрес «#shotN», и накладка разворачивается по :target. Превью 400 px
   показывалось в 72, то есть впятеро мельче, чем лежит на диске: на телефоне
   по нему не разобрать ни сорта, ни спелости. Теперь кадр в строке заметнее,
   а полный — по нажатию на него же, без подписи-ссылки рядом. */
.shot { display:block; cursor:zoom-in; }
.lightbox { display:none; }
/* Снимок стоит фоном, а не <img>: скрытый <img loading="lazy"> браузер забирает
   всё равно — замерено 13 сентября по логу, три крупных файла ушли на витрину,
   которую никто не раскрывал. Фон элемента с display:none не запрашивается,
   пока элемент не показан, и накладка ничего не стоит до нажатия (ADR-0009).
   Адрес файла приходит в style= у самой накладки: он свой у каждой строки.
   Оттуда же он побеждает `background-color` ниже — встроенный стиль сильнее
   любого селектора, сокращённая запись `background` его бы стёрла. */
.lightbox:target { display:flex; position:fixed; inset:0; z-index:50;
                   padding:16px; background-color:rgba(0,0,0,.86);
                   background-size:contain; background-repeat:no-repeat;
                   background-position:center; }
/* Тёмное поле — сплошная ссылка «закрыть»: тап мимо снимка возвращает к строке,
   как и «Назад». Снимок остаётся нажимаемым, чтобы его можно было сохранить. */
.lightbox .away { position:absolute; inset:0; }
.lightbox .close { position:absolute; top:12px; right:12px; min-height:44px;
                   display:flex; align-items:center; padding:0 18px;
                   border-radius:999px; background:var(--paper); color:var(--ink);
                   font-weight:650; text-decoration:none; }

.rows .price { color:var(--price); font-weight:700; }
/* Кончилось — цена бледнеет и зачёркивается, а рядом стоит слово «нет». */
.rows .price.out { color:var(--muted); text-decoration:line-through; }

/* Действие внутри строки выглядит ссылкой, но остаётся кнопкой формы. */
.linkish { background:none; border:0; padding:0; font:inherit; color:var(--accent-ink);
           cursor:pointer; text-decoration:underline; }
.linkish:hover { color:var(--accent-2); }
/* Отмена заказа: жирным и красным, строкой в палец высотой. Бледной ссылкой
   её искали долго — замечание с поля. Цвет тут не единственный носитель
   смысла: рядом стоит само слово «отменить» (ADR-0019, правило 23), а
   необратимость после отсечки по-прежнему объясняет блок `.danger`. */
.linkish.danger-link { color:var(--danger-ink); font-weight:700;
                       min-height:44px; padding:8px 0; }
.linkish.danger-link:hover { color:var(--danger-ink); }
.rows form { display:inline; margin-left:12px; }

/* ---------- витрина дня ---------- */
/* Позиция, по которой приём остановлен: бледнее и со словом, а не только бледнее. */
.rows tr.gone td { opacity:.55; }
.rows .left { color:var(--quota); font-weight:700; }
.inline { font-size:16px; color:var(--muted); white-space:nowrap; }
.mini { width:6.5rem; font:inherit; font-size:17px; padding:8px 10px; min-height:44px;
        border:1px solid var(--frame); border-radius:8px; margin-left:6px;
        font-variant-numeric:tabular-nums; }
.rows .act form { display:block; margin:0 0 8px; }
.inline-form { margin-top:16px; }
.inline-form .btn + .btn { margin-left:10px; }

.note { background:var(--quota-bg); border:1px solid var(--quota); color:var(--ink);
        border-radius:9px; padding:12px 14px; margin-bottom:18px; font-size:17px; }

/* ---------- корзина ---------- */
/* Подпись к полю количества нужна тому, кто слушает страницу, и мешает тому,
   кто её видит: единица и так написана рядом с полем. Поэтому не display:none —
   спрятанное так поле не читает и озвучиватель. */
.sr { position:absolute; width:1px; height:1px; overflow:hidden;
      clip-path:inset(50%); white-space:nowrap; }
/* Итог по прилавку стоит под столбцом сумм, а не под названиями. */
p.num { text-align:right; font-variant-numeric:tabular-nums; margin:8px 0 0; }
/* Строка корзины: поле количества и действия под названием, а не в столбце цены. */
.rows .inline-form { margin-top:10px; }
.rows .inline-form .mini { margin-left:0; }

/* Код визита — то, что человек показывает и называет у прилавка: он крупнее
   всего на странице, потому что читают его через прилавок и не с первого ряда. */
.visit-code { font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
              font-size:56px; font-weight:800; letter-spacing:.08em;
              margin:.1em 0 .3em; color:var(--accent-ink); }

/* Заказы одного визита идут подряд под общим кодом: разделяет их отступ
   и название прилавка, а не рамка — рамок на странице и так довольно. */
.order { margin-top:22px; }
.order h2 { margin:0 0 .2em; font-size:19px; }

/* Имя покупателя крупное, код рядом моноширинным: продавец окликает по имени,
   а сверяет по коду (ТЗ 4.10, ADR-0017). */
.order h2 .code { font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
                  font-size:22px; color:var(--accent-ink); margin-left:10px;
                  letter-spacing:.06em; }

/* ---------- выдача ---------- */
/* Имя первое и самое крупное: на нём стоит вторая проверка кода (ADR-0019,
   правило 17). Кнопка «Выдал» — во всю ширину и высокая: её нажимают десятки
   раз в день большим пальцем руки, держащей телефон (правило 18). */
.handout-find .code { width:100%; max-width:12rem; }
.handout-name { font-size:34px; font-weight:800; letter-spacing:-.02em; margin:0 0 .2em; }
.handout-total { font-size:26px; font-weight:800; color:var(--price);
                 text-align:right; margin:.4em 0 1em; font-variant-numeric:tabular-nums; }
.btn.big { width:100%; min-height:64px; font-size:20px; }
.handout-card .danger { margin-top:28px; }
.rows .code { font-family:ui-monospace,SFMono-Regular,Menlo,monospace; font-weight:700;
              font-size:19px; color:var(--accent-ink); }

/* ---------- полоса корзины ---------- */
/* Корзина под рукой на любой строке витрины: `position:sticky` держит полосу
   над страницей, пока не доскроллили до её настоящего места в самом низу.
   Без скрипта — витрину открывают на рынке, с мобильной связи (ADR-0019).
   Ширину задаёт `.wrap`, поэтому полоса не растягивается во весь экран
   на компьютере, а выглядит карточкой над содержимым. */
.cart-bar { position:sticky; bottom:12px; z-index:20; margin:28px 0 12px;
            display:flex; align-items:center; flex-wrap:wrap; gap:10px 14px;
            background:var(--paper); border:1px solid var(--accent-line);
            border-radius:var(--r); padding:12px 14px; box-shadow:var(--shadow); }
/* Кнопка не сжимается и не переносится по слогам, текст забирает остаток
   и на узком экране уходит строкой выше. */
.cart-bar .what { flex:1 1 9rem; min-width:0; font-size:17px; font-weight:650; }
.cart-bar .sub { display:block; font-size:16px; font-weight:400; color:var(--muted); }
.cart-bar .btn { flex:0 0 auto; }

/* ---------- стартовая страница ---------- */
/* Обещание сервиса стоит выше дверей, но не заслоняет их: рассказ о том, как всё
   устроено, идёт ниже — пришедшему сделать дело листать до конца не нужно. */
.hero { margin-bottom:8px; }
.hero .eyebrow { margin:0 0 8px; }
.hero .lede { font-size:19px; }
.after-cards { font-size:16px; margin:16px 0 0; }

/* Шаги нумерованы кружком, а не точкой: номер здесь часть смысла — порядок дня
   продавца, — и читается он раньше заголовка. */
.steps { counter-reset:step; list-style:none; padding:0; margin:0; display:grid; gap:16px; }
.steps li { position:relative; background:var(--surface); border:1px solid var(--line);
            border-radius:var(--r); padding:18px 18px 18px 62px; counter-increment:step; }
.steps li::before { content:counter(step); position:absolute; left:18px; top:18px;
                    width:30px; height:30px; border-radius:999px;
                    background:var(--accent-ink); color:var(--on-accent);
                    font-size:17px; font-weight:800; line-height:30px; text-align:center; }
.steps h3 { margin:0 0 .3em; font-size:19px; font-weight:700; }
.steps p { margin:0; font-size:17px; color:var(--muted); }

.callout { background:var(--accent-soft); border:1px solid var(--accent-line);
           border-radius:var(--r); padding:20px; margin:28px 0 0; }
.callout p { margin:0; font-size:19px; font-weight:650; }

/* Вопрос сложен раскрытием: на телефоне четыре ответа подряд — это экран,
   который пролистывают, не читая. Раскрытие родное, скриптов не требует. */
.faq { border-top:1px solid var(--line-soft); padding:14px 0; }
.faq summary { cursor:pointer; font-weight:700; }
.faq p { margin:.7em 0 0; font-size:17px; color:var(--muted); max-width:64ch; }

/* ---------- витрина покупателя: строка товара ---------- */
/* Строка витрины — единственная, у которой в правом столбце стоит форма:
   поле количества и кнопка. Рядом с названием и ценой они не помещаются
   в 360 px, и кнопка «В корзину» уезжала за правый край экрана — найдено
   на телефоне 11 сентября. На телефоне строка раскладывается в карточку:
   название с ценой сверху, форма — отдельной строкой во всю ширину.
   Таблицей строка снова становится с 640 px, где место для столбца есть. */
.goods, .goods tbody { display:block; }
.goods tr { display:flex; flex-wrap:wrap; align-items:flex-start; gap:0 12px;
            padding:12px 0; border-bottom:1px solid var(--line-soft); }
.goods tr:last-child { border-bottom:0; }
.goods td { display:block; padding:0; border-bottom:0; }
.goods .pic { flex:0 0 auto; width:84px; padding-right:0; }
.goods .thumb { width:84px; }
/* min-width:0 — чтобы длинное название переносилось, а не распирало строку. */
.goods .name { flex:1 1 8rem; min-width:0; }
/* Цена остаётся неразрывной, а вторая цена под ней переносится: «от 3 кг —
   295 ₽» в одну строку забирает треть экрана. */
.goods .num { flex:0 1 auto; margin-left:auto; text-align:right; white-space:normal; }
.goods .price { white-space:nowrap; }
.goods .act { flex:1 0 100%; margin-top:10px; padding-left:0; text-align:left;
              white-space:normal; }
.goods .act form { display:flex; flex-wrap:wrap; align-items:center; gap:8px; margin:0; }
.goods .act .mini { margin-left:0; }
/* На телефоне кнопка добирает остаток строки рядом с полем количества: рука
   уже там, и искать глазами нечего. Строка узкая — поле и кнопка всё равно
   стоят рядом, а не в столбик. */
.goods .act .btn { flex:1 1 auto; padding-left:18px; padding-right:18px; }

/* ---------- планшет ---------- */
@media (min-width:640px) {
  .cards { grid-template-columns:1fr 1fr; }
  .steps { grid-template-columns:1fr 1fr; }
  .pairs { display:grid; grid-template-columns:auto 1fr; gap:8px 24px; }
  .pairs dt, .pairs dd { margin:0; }
  .stall-photo { max-width:560px; }
  .stall-photo.small { max-width:240px; }

  /* Витрина покупателя: места хватает, строка снова таблица (см. .goods выше). */
  .goods { display:table; }
  .goods tbody { display:table-row-group; }
  .goods tr { display:table-row; border-bottom:0; padding:0; }
  .goods td { display:table-cell; border-bottom:1px solid var(--line-soft);
              padding:12px 0; }
  .goods tr:last-child td { border-bottom:0; }
  .goods .pic { padding-right:12px; width:112px; }
  .goods .thumb { width:112px; }
  .goods .num { white-space:nowrap; }
  .goods .act { text-align:right; padding-left:12px; }
  .goods .act form { display:block; margin:0 0 8px; }
  .goods .act .mini { margin-left:6px; }
}

/* ---------- компьютер ---------- */
@media (min-width:960px) {
  main { padding:40px 0 64px; }
  .cards { grid-template-columns:1fr 1fr 1fr; }
}
