/* Витрина доставки LUCHO (shop.lecho-rest.ru). Перенос макета web/mockups/delivery.html
   в живую страницу: телефон-рамка макета = колонка #app (на десктопе 480px по центру).
   Токены — те же, что в lecho-tokens.css (палитра ребрендинга 12.10.2026); здесь короткие
   имена, как в макете. Макет остался в старой палитре — источник истины теперь tokens. */
@font-face { font-family: "Sporting Grotesque"; src: url("/static/fonts/SportingGrotesque-Regular.woff2") format("woff2"); font-weight: 400; font-display: swap; }
@font-face { font-family: "Sporting Grotesque"; src: url("/static/fonts/SportingGrotesque-Bold.woff2") format("woff2"); font-weight: 700; font-display: swap; }
@font-face { font-family: "Mulish"; src: url("/static/fonts/Mulish-Variable.woff2") format("woff2"); font-weight: 200 1000; font-display: swap; }

:root {
  --cream: #F9F4E8; --cream-50: #FDFAF3; --cream-200: #EFE7D3; --paper: #E6DCC2;
  --red: #C04026; --red-600: #A8371F; --red-100: #F5D9D0;
  --olive: #8E9D2A; --olive-700: #69741F; --olive-100: #E9ECD0;   /* olive-700 — под текст (бежевый 4.6:1); чистый olive — только заливки без текста */
  --green: var(--olive); --green-700: var(--olive-700); --black: #333333; --muted: #6B6A5E;
  --line: rgba(51,51,51,.14); --line-strong: rgba(51,51,51,.28);
  --r-sm: 6px; --r: 14px; --r-lg: 22px; --pill: 999px;
  --shadow-sm: 0 2px 6px rgba(69,42,20,.10); --shadow: 0 12px 30px -12px rgba(69,42,20,.28);
  --pad: 20px; --bar-h: 72px;   /* 13.10: 10 + 48 + 12 (+ safe-area считается отдельно); было 96 при фактических 80 */
  --safe-b: env(safe-area-inset-bottom, 0px); --safe-t: calc(max(env(safe-area-inset-top, 0px), var(--tg-safe-area-inset-top, 0px)) + var(--tg-content-safe-area-inset-top, 0px)); /* статусбар (env; на Android WebView env=0 — берём из SDK, на iOS числа равны) + нативные кнопки Telegram в Fullscreen (SDK пишет переменную; вне Telegram обеих нет → 0px). Android живьём не проверен. */
}
* { box-sizing: border-box; }
html { background: var(--cream); -webkit-text-size-adjust: 100%; overscroll-behavior-y: none; }
body { margin: 0; background: var(--cream); color: var(--black); font-family: "Mulish", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif; font-size: 15px; line-height: 1.4; -webkit-font-smoothing: antialiased; }
button { font: inherit; color: inherit; background: none; border: 0; padding: 0; margin: 0; cursor: pointer; -webkit-tap-highlight-color: transparent; touch-action: manipulation; }
a, label { touch-action: manipulation; }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
input { font: inherit; color: inherit; }
a { color: inherit; }
img { max-width: 100%; }
svg { width: 20px; height: 20px; stroke: currentColor; fill: none; stroke-width: 2; stroke-linecap: round; stroke-linejoin: round; flex: none; }
:focus-visible { outline: 3px solid rgba(192,64,38,.55); outline-offset: 2px; border-radius: 6px; }
[hidden] { display: none !important; }
@media (prefers-reduced-motion: reduce) { *, *::before, *::after { transition: none !important; animation: none !important; } }

#app { max-width: 480px; margin: 0 auto; min-height: 100vh; min-height: 100svh; background: var(--cream); position: relative; }
@media (min-width: 520px) { html, body { background: var(--cream-200); } #app { box-shadow: 0 0 0 1px var(--line), 0 28px 60px -20px rgba(69,42,20,.30); } }
.scr { display: flex; flex-direction: column; gap: 16px; padding: calc(14px + var(--safe-t)) var(--pad) calc(var(--bar-h) + var(--safe-b) + 20px); min-height: 100vh; min-height: 100svh; }
.scr.nobar { padding-bottom: calc(16px + var(--safe-b)); }  /* 40px читалось как «прокрутка в пустоту» под «В меню» (16.09) */

.display { font-family: "Sporting Grotesque", "Helvetica Neue", Helvetica, Arial, sans-serif; text-transform: uppercase; letter-spacing: .02em; font-weight: 400; line-height: 1.06; margin: 0; text-wrap: balance; }
.eyebrow { font-size: 12px; letter-spacing: .18em; text-transform: uppercase; font-weight: 700; color: var(--muted); }
.muted { color: var(--muted); }
.num { font-variant-numeric: tabular-nums; }
.center { text-align: center; }
.hint { font-size: 13px; color: var(--muted); }
.hint a, .lnk { color: var(--red); font-weight: 700; text-decoration: none; }
/* текстовые КНОПКИ («Войдите», «Моего дома нет», «Изменить», «Повторить») — тач-цель 44px, текст был ≈18px (аудит 28.09 N7) */
button.lnk { min-height: 44px; display: inline-flex; align-items: center; }

/* шапка */
.top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.top img.logo { width: 100%; max-width: 280px; min-width: 0; height: auto; display: block; }  /* «на одном уровне» 10,1:1: на 375px вся доступная ширина (~279px) = 28px высоты; решение владельца 13.10 — вариант 1 */
.ava { width: 44px; height: 44px; border-radius: 50%; background: var(--olive-700); color: var(--cream); display: grid; place-items: center; font-weight: 800; font-size: 18px; line-height: 1; flex: none; }  /* Mulish: у Catallina буква сидит выше центра */
.ava.ghost { background: var(--cream-50); color: var(--black); border: 1px solid var(--line-strong); }
.ava.lg { width: 52px; height: 52px; font-size: 22px; }
.addr { display: flex; align-items: center; gap: 8px; min-height: 48px; width: 100%; padding: 4px 12px; border: 1px solid var(--line-strong); border-radius: var(--pill); font-size: 14px; font-weight: 600; background: var(--cream-50); text-align: left; }
.addr svg { width: 18px; height: 18px; }
.addr .tx { flex: 1; min-width: 0; display: flex; flex-direction: column; line-height: 1.15; }
.addr .tx b { font-size: 14px; font-weight: 800; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.addr .tx small { font-size: 12px; color: var(--muted); font-weight: 600; }
.addr .chev { width: 16px; height: 16px; }
/* без адреса — утверждение о зоне (27.09): без пина и шеврона, заголовок может перенестись на узком телефоне,
   справа вопрос «Мой дом?» цветом ссылки — единственная подсказка, что строка нажимается */
/* 13.10: форма по роли — пилюля у того, что нажимают (адрес с пином в одну строку), 22px у информационной карточки.
   Двухстрочное утверждение о зоне в пилюле становилось овалом и не совпадало с «Повторить» под ним (скрин владельца). */
.addr.zone { padding: 12px 14px; border-radius: var(--r-lg); border-color: var(--line); }
.addr.zone .tx b { white-space: normal; }
.addr .ask { flex: none; font-size: 13px; font-weight: 800; color: var(--red); }
.hrow { display: contents; }   /* на телефоне обёртки как будто нет: адрес и плашка «кухня закрыта» — обычные строки .scr; строкой их делает только десктоп */

/* лента категорий */
.rail { flex: none; display: flex; gap: 6px; overflow-x: auto; margin: 0 calc(-1 * var(--pad)); padding: 8px var(--pad); scrollbar-width: none; position: sticky; top: var(--safe-t); z-index: 5; background: var(--cream); -webkit-overflow-scrolling: touch; } /* top = safe-t, не 0: в Fullscreen мини-аппа и PWA лента уезжала под статусбар (скрин 17.09); зазор над ней закрывают тени .stuck */
.rail::-webkit-scrollbar { display: none; }
/* Подложка над ПРИЛИПШЕЙ лентой (17.09, скрины владельца из встроенного браузера Telegram iOS). Telegram рисует страницу
   и под своей полупрозрачной шапкой (у WKWebView scrollView.clipsToBounds = false), а липкие элементы крепит к краю окна
   под ней — над лентой просвечивали цены и фото. Копии ленты тенью вверх закрывают эту полосу кремом; в обычном браузере
   она за краем экрана. Только при .stuck (ставит viewCatalog): у ленты в потоке та же подложка накрыла бы адрес над ней.
   Тень, а не ::before: overflow-x: auto у ленты режет псевдоэлементы, а собственную тень элемента — нет. Шаг 40px меньше
   высоты ленты (60px), поэтому копии идут без щелей до 200px вверх — шапка Telegram развёрнута примерно на 130pt. */
.rail.stuck { box-shadow: 0 -40px 0 var(--cream), 0 -80px 0 var(--cream), 0 -120px 0 var(--cream), 0 -160px 0 var(--cream), 0 -200px 0 var(--cream); }
.chip { flex: none; height: 44px; padding: 0 14px; border-radius: var(--pill); border: 1px solid var(--line); background: var(--cream-50); font-size: 12px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; display: inline-flex; align-items: center; gap: 6px; white-space: nowrap; }
.chip.on { background: var(--red); border-color: var(--red); color: #fff; }
.chip.lower { text-transform: none; letter-spacing: 0; font-size: 14px; font-weight: 600; }
.chip .chev { width: 16px; height: 16px; }

/* сетка блюд */
.sect { display: flex; align-items: baseline; gap: 10px; }
.sect .display { font-size: 26px; }
.sect .cnt { font-size: 14px; color: var(--muted); }
.grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 18px 14px; }
.card { display: flex; flex-direction: column; gap: 8px; text-align: left; height: 100%; }
.grid { align-items: stretch; }
.card .ph { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-radius: var(--r); display: block; background: var(--cream-200); }
.card .nm { font-weight: 600; font-size: 15px; line-height: 1.25; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; }
.card .pw { display: flex; align-items: baseline; gap: 7px; min-width: 0; }
.card .wt { font-size: 13px; color: var(--muted); font-weight: 600; white-space: nowrap; }
.card .pr { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 8px; margin-top: auto; padding-top: 2px; min-height: 44px; }   /* min-height = высота кнопки «+»: у «разобрали» её нет, и без этого строка цены оказывалась на 18px ниже соседних (скрин владельца 18.09) */
.card .pr b { font-size: 17px; font-weight: 800; }
.card.off .ph { filter: grayscale(1) opacity(.55); }
.card.off .nm, .card.off .wt { color: var(--muted); }
.card.off .pr b { color: var(--muted); font-weight: 600; text-decoration: line-through; }
.card .pr.stp { justify-content: stretch; }                                /* степпер «− n +» во всю плитку вместо цены (25.09) */
.card .pr.stp .qty { flex: 1; justify-content: space-between; gap: 6px; }
.card .pr.stp .qty b { font-size: 17px; font-weight: 800; }
.dish .upsell { margin-top: -4px; }
.card .gone { font-size: 12px; font-weight: 700; color: var(--muted); letter-spacing: .06em; text-transform: uppercase; }
.add { width: 44px; height: 44px; border-radius: var(--pill); background: var(--red); color: #fff; display: grid; place-items: center; box-shadow: var(--shadow-sm); flex: none; }
.add.ghost { background: var(--cream-50); color: var(--black); border: 1px solid var(--line-strong); box-shadow: none; }
.add.sm { width: 40px; height: 40px; }
.add.sm svg { width: 18px; height: 18px; }
.add.cnt { background: var(--olive-700); color: var(--cream); font-weight: 800; font-size: 15px; }
.qty { display: inline-flex; align-items: center; gap: 12px; }
.qty b { font-size: 17px; min-width: 16px; text-align: center; }

/* нижняя панель */
.bar { position: fixed; left: 0; right: 0; margin: 0 auto; width: 100%; max-width: 480px; bottom: 0; z-index: 20; background: var(--olive-700); color: var(--cream); padding: 10px var(--pad) max(12px, var(--safe-b)); display: flex; align-items: center; justify-content: space-between; gap: 14px; }   /* 13.10 (скрины владельца): было 12 / 52 / safe+6 = 104px в веб-приложении — «слишком высокая плашка» */
.bar .btn { height: 48px; }
/* Оливковый хвост под нижней панелью (17.09, Telegram iOS): стеклянная панель Telegram висит ниже нашей, и между ними
   просвечивало меню. Стекло ложится на олив — две панели читаются одной; в обычном браузере хвост за нижним краем экрана.
   ::after, а не тень с разлётом: тень вылезла бы по бокам колонки на десктопе. Фиксированная панель прокрутку страницы
   не удлиняет, а вот липкая панель шторки удлинила бы прокрутку самой шторки — там хвост выключен. */
/* ⚠️ 13.10: хвост ТОЛЬКО в Telegram — во встроенном браузере (`env-tg_browser`: инцидент 17.09 был именно там, стеклянная
   панель Telegram под WKWebView) и в мини-аппе (`env-tg_app`); класс ставит boot (ревью Fable 14.10 W1: сперва оставили одному мини-аппу). Нижняя панель Safari на iOS 26 тоже стеклянная и
   берёт цвет страницы под собой: с хвостом она красилась оливковым и читалась продолжением нашей панели — «плашка
   на пол-экрана» (скрины владельца 13.10). Без хвоста стекло берёт кремовый. */
body.env-tg_app .bar::after, body.env-tg_browser .bar::after { content: ""; position: absolute; left: 0; right: 0; top: 100%; height: 160px; background: var(--olive-700); pointer-events: none; }
body.env-tg_app .sheet .bar::after, body.env-tg_browser .sheet .bar::after { content: none; }
/* 13.10 (второй скрин владельца): Safari iOS 26 кладёт страницу ПОД свою стеклянную панель и отдаёт её высоту как
   safe-area-inset-bottom (~64pt): панель с bottom:0 и padding = safe-b уходила под стекло на 64pt и красила его оливковым —
   «плашка не изменилась» — см. решение владельца ниже: заливка до края оставлена намеренно. */
/* ⚠️ 13.10, история за один вечер: панель пробовали ставить НАД стеклом Safari iOS 26 (bottom = safe-b), потом плавающей
   карточкой с зазором — Safari продолжает нижний край страницы под свою панель, и при bottom:0 стекло красится оливковым.
   Решение владельца 23:54: ОСТАВИТЬ оливковую заливку до края — стекло в цвет панели читается её продолжением.
   Поэтому панель во всех хостах одинаковая: bottom: 0, padding-bottom = max(12px, safe-b). Не возвращать плавающую. */
.bar .l { display: flex; flex-direction: column; gap: 2px; line-height: 1.2; min-width: 0; }
.bar .l b { font-size: 18px; font-weight: 800; }
.bar .l span { font-size: 13px; color: var(--cream-50); }   /* без opacity: и .8, и .92 роняли контраст ниже 4,5:1 (ревью Fable 13.10) */
.btn { height: 52px; padding: 0 22px; border-radius: var(--pill); background: var(--red); color: #fff; font-weight: 800; font-size: 16px; display: inline-flex; align-items: center; justify-content: center; gap: 8px; white-space: nowrap; box-shadow: var(--shadow-sm); text-decoration: none; }
.btn:disabled { opacity: .55; box-shadow: none; cursor: default; }
@media (hover: hover) { .btn:not(:disabled):hover { background: var(--red-600); } .btn.ghost:hover, .btn.quiet:hover { background: var(--paper); } .add:not(.ghost):hover { background: var(--red-600); } .add.ghost:hover, .chip:not(.on):hover, .house:hover, .prow:hover { background: var(--cream-200); } }
.btn.wide { width: 100%; flex: none; }
.btn.ghost { background: var(--cream-200); color: var(--black); box-shadow: none; }
.btn.quiet { background: var(--cream-200); color: var(--muted); box-shadow: none; }
.bar .btn.wide { width: auto; flex: 1; }
.bar .qty .add.ghost { background: var(--olive); color: var(--black); border-color: rgba(249,244,232,.35); }   /* 13.10: светлая кнопка на чернильной панели, тёмный «−/+» (4,2:1) */
.btn .spin { width: 18px; height: 18px; border: 2px solid rgba(255,255,255,.4); border-top-color: #fff; border-radius: 50%; animation: spin .8s linear infinite; }
@keyframes spin { to { transform: rotate(360deg); } }

/* шапка внутренних экранов */
.hdr { display: flex; align-items: center; gap: 12px; }
.hdr .display { font-size: 26px; flex: 1; }
/* Оптическая правка (замер 18.09, скрин владельца) была под Catallina: её заглавные сидели ВЫШЕ
   середины строки, и блок опускали на 2px. У Sporting Grotesque капс сидит по центру коробки —
   сдвиг снят 13.10 (ребрендинг); если на скрине заголовок снова «всплывёт», вернуть `top: 2px`
   на `.hdr > .display, .hdr > .orderno` (position, не margin: при align-items: center внешний
   отступ делится пополам). */
.hdr .lnk { font-size: 14px; color: var(--muted); font-weight: 600; }
.back { width: 44px; height: 44px; border-radius: var(--pill); background: var(--cream-50); color: var(--black); display: grid; place-items: center; box-shadow: var(--shadow-sm); flex: none; }

/* блюдо (шторка) */
.dish { display: flex; flex-direction: column; gap: 16px; }
.hero { margin: 0 calc(-1 * var(--pad)); width: calc(100% + 2 * var(--pad)); position: relative; overflow: hidden; }  /* overflow здесь безопасен: панель — сосед, не потомок */
.hero img { width: calc(100% + 2px); max-width: none; margin-left: -1px; height: 300px; object-fit: cover; display: block; background: var(--cream-200); }  /* на 1px шире с каждой стороны: субпиксельная кремовая полоска у края фото (iOS, 16.09 — то справа, то слева); лишнее режет .hero, ширина шторки не растёт */
.hero .back { position: absolute; top: calc(14px + var(--safe-t)); left: 16px; }  /* в Fullscreen Telegram нативная «Закрыть» лежала ровно на нашей кнопке (скрин владельца 28.09) */
.dish h1.display { font-size: 28px; }
.dish .meta { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; margin-top: 6px; }
.dish .meta b { font-size: 22px; font-weight: 800; }
.dish p { margin: 0; font-size: 15px; line-height: 1.5; }
.kbju { display: flex; align-items: center; justify-content: space-between; width: 100%; height: 48px; margin: -4px 0; border-top: 1px solid var(--line); border-bottom: 1px solid var(--line); font-size: 15px; font-weight: 600; }
.kbju span small { font-weight: 600; color: var(--muted); margin-left: 8px; }
.kbju .chev { width: 16px; height: 16px; transition: transform var(--transition, 200ms); }
.kbju[aria-expanded="true"] .chev { transform: rotate(180deg); }
.nutri { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); padding: 4px 0 0; margin-top: -8px; }
.nutri div { display: flex; flex-direction: column; gap: 2px; align-items: center; }
.nutri b { font-size: 16px; font-weight: 800; }
.nutri span { font-size: 12px; color: var(--muted); }
.tiles { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 10px; margin-top: 8px; }
.tile { position: relative; display: flex; flex-direction: column; gap: 4px; padding: 6px 6px 8px; border-radius: var(--r); border: 1.5px solid var(--line); background: var(--cream-50); text-align: left; min-height: 64px; }
.tile img { width: 100%; aspect-ratio: 1 / 1; object-fit: cover; border-radius: 10px; display: block; }
.tile .t { font-size: 12px; font-weight: 700; line-height: 1.2; }
.tile .p { font-size: 12px; color: var(--muted); }
.tile.on { border-color: var(--olive); background: var(--olive-100); }
.tile.off { opacity: .5; } .tile.off img { filter: grayscale(1); }   /* добавка в стопе (01.10) */
.tile .chk { position: absolute; top: 10px; right: 10px; width: 22px; height: 22px; border-radius: 50%; background: var(--olive-700); color: var(--cream); display: grid; place-items: center; }
.tile .chk svg { width: 13px; height: 13px; stroke-width: 3; }
.tile.noimg { justify-content: center; padding-right: 30px; }

/* корзина и оформление */
.items { display: flex; flex-direction: column; }
.item { display: flex; gap: 12px; align-items: flex-start; padding: 10px 0; border-bottom: 1px solid var(--line); }
.item:last-child { border-bottom: 0; }
.item img { width: 60px; height: 60px; border-radius: 10px; object-fit: cover; display: block; flex: none; background: var(--cream-200); }
.item .c { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; }
.item .c .nm { font-weight: 600; font-size: 15px; line-height: 1.25; }
.item .c .md { font-size: 13px; color: var(--muted); }
.item .ln { display: flex; align-items: center; justify-content: space-between; margin-top: 4px; }
.item .ln b.lsum { font-size: 16px; font-weight: 800; }
.item .ln .qty { gap: 10px; }
.upsell { flex: none; display: flex; gap: 10px; overflow-x: auto; margin: 0 calc(-1 * var(--pad)); padding: 2px var(--pad); scrollbar-width: none; }
.upsell::-webkit-scrollbar { display: none; }
.up { flex: none; width: 112px; display: flex; flex-direction: column; gap: 5px; padding: 6px 6px 8px; border: 1px solid var(--line); border-radius: var(--r); background: var(--cream-50); text-align: left; }
.up img { width: 100%; height: 78px; border-radius: 10px; object-fit: cover; display: block; background: var(--cream-200); }
.up .nm { font-size: 13px; line-height: 1.2; font-weight: 600; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden; min-height: 2.4em; }
.up .pr { display: flex; align-items: center; justify-content: space-between; }
.up .pr b { font-size: 14px; font-weight: 800; }
.up .add.sm { width: 36px; height: 36px; }
.bonus { background: var(--cream-50); border: 1px solid var(--line); border-radius: var(--r-lg); padding: 12px 14px; display: flex; flex-direction: column; gap: 8px; }
.bonus .row { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
.bonus .row b { font-size: 16px; font-weight: 800; }
.bonus .sub { font-size: 13px; color: var(--muted); font-weight: 600; }
.switch { width: 50px; height: 30px; border-radius: var(--pill); background: var(--paper); position: relative; flex: none; transition: background 200ms; }
.switch::after { content: ""; position: absolute; top: 3px; left: 3px; width: 24px; height: 24px; border-radius: 50%; background: #fff; box-shadow: var(--shadow-sm); transition: transform 200ms; }
.switch[aria-checked="true"] { background: var(--red); }
.switch[aria-checked="true"]::after { transform: translateX(20px); }
.bonus .res { display: flex; justify-content: space-between; font-size: 15px; border-top: 1px solid var(--line); padding-top: 10px; }
.bonus .res b { color: var(--red); font-weight: 800; }
.mini { display: flex; justify-content: space-between; font-size: 14px; color: var(--muted); }
.mini .ok { color: var(--green-700); font-weight: 600; }
.sum { display: flex; flex-direction: column; gap: 8px; }
.join { background: var(--cream-50); border: 1px solid var(--line); border-radius: var(--r-lg); padding: 14px; display: flex; flex-direction: column; gap: 8px; }
.join b { font-size: 16px; font-weight: 800; }
.join p { font-size: 14px; color: var(--muted); line-height: 1.35; margin: 0; }
.join .row { display: grid; grid-template-columns: 1fr 1fr; gap: 8px; margin-top: 4px; }
.join .row .btn { height: 48px; padding: 0 12px; }
.sum .ln { display: flex; justify-content: space-between; gap: 12px; font-size: 15px; }
.sum .ln.tot { border-top: 1px solid var(--line); padding-top: 10px; font-size: 20px; font-weight: 800; }
.sum .ln .neg { color: var(--red); font-weight: 700; }

.tabs { display: flex; padding: 4px; background: var(--cream-200); border-radius: var(--pill); }
.tab { flex: 1; height: 40px; border-radius: var(--pill); display: grid; place-items: center; font-size: 12px; font-weight: 700; letter-spacing: .12em; text-transform: uppercase; color: var(--muted); }
.tab.on { background: var(--red); color: #fff; box-shadow: var(--shadow-sm); }
.fld { display: flex; flex-direction: column; gap: 8px; }
.sel { min-height: 48px; width: 100%; display: flex; align-items: center; gap: 10px; padding: 0 12px 0 14px; border: 1px solid var(--line-strong); border-radius: var(--r); background: var(--cream-50); font-size: 16px; font-weight: 600; text-align: left; }
.sel span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sel .chev { width: 16px; height: 16px; }
.sel.tall { min-height: 56px; }
.sel .tx { display: flex; flex-direction: column; line-height: 1.15; white-space: normal; }
.sel .tx b { font-size: 15px; font-weight: 800; }
.sel .tx small { font-size: 12px; color: var(--muted); font-weight: 600; }
.row3 { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.inp { position: relative; height: 52px; border: 1px solid var(--line-strong); border-radius: var(--r); background: var(--cream-50); padding: 0 12px; display: flex; flex-direction: column; justify-content: center; }
.inp small { font-size: 11px; color: var(--muted); line-height: 1; margin-bottom: 3px; letter-spacing: .04em; text-transform: uppercase; font-weight: 700; }
.inp input { width: 100%; border: 0; background: none; padding: 0; font-size: 16px; font-weight: 600; line-height: 1.2; outline: none; }
.inp input::placeholder { color: var(--muted); font-weight: 400; }
.inp.err { border-color: var(--red); }
.inp.big { height: 56px; }
.contact { display: flex; align-items: center; gap: 10px; }
.contact .inp { flex: 1; min-width: 0; }
.contact .tel { display: flex; flex-direction: column; align-items: flex-end; gap: 3px; font-size: 13px; color: var(--muted); white-space: nowrap; }
.contact .tel b { color: var(--black); font-size: 14px; }
.phone-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.phone-row .who b { color: var(--black); font-size: 15px; }
.ok-chip { display: inline-flex; align-items: center; gap: 5px; height: 28px; padding: 0 10px; border-radius: var(--pill); background: rgba(150,170,125,.25); color: var(--green-700); font-size: 12px; font-weight: 700; white-space: nowrap; }
.ok-chip svg { width: 14px; height: 14px; stroke-width: 3; }
.ok-chip.sm { height: 22px; font-size: 11px; }
.chips { display: flex; gap: 6px; flex-wrap: wrap; }
.err { color: var(--red); font-size: 13px; font-weight: 600; }

/* состояния */
.closed { display: flex; align-items: center; gap: 10px; padding: 12px 14px; border-radius: var(--r-lg); background: var(--olive-700); color: var(--cream); font-size: 14px; line-height: 1.3; }
.closed b { font-weight: 800; }
.warnbox { display: flex; align-items: flex-start; gap: 10px; padding: 12px 14px; border-radius: var(--r-lg); background: var(--red-100); border: 1px solid rgba(192,64,38,.35); font-size: 14px; line-height: 1.35; }
.warnbox > svg, .warnbox > .row > svg { width: 20px; height: 20px; flex: none; color: var(--red); margin-top: 1px; }   /* только значок плашки: общее `.warnbox svg` красило и плюсы кнопок в плитках «чем закрыть минимум» — красный на красном (владелец 27.09) */
.warnbox b { font-weight: 800; }
.warnbox.col { flex-direction: column; align-items: stretch; gap: 10px; }   /* stretch: у .warnbox flex-start, и лента плиток внутри росла по содержимому за край экрана (телефон, 26.09) */
.warnbox.col .row { display: flex; align-items: flex-start; gap: 10px; }
.warnbox .upsell { margin: 0 -14px; padding: 0 14px 2px; }   /* плитки «чем закрыть минимум» внутри плашки (26.09): лента до её края, не до края экрана */
.rate { display: flex; flex-direction: column; gap: 8px; padding: 14px; border-radius: var(--r-lg); border: 1px solid var(--line); background: var(--cream-50); }   /* «как всё прошло?» на доставленном заказе (26.09) */
.rate b { font-size: 17px; font-weight: 800; }
.rate p { margin: 0; font-size: 14px; color: var(--muted); line-height: 1.4; }
.rate .row { display: flex; gap: 8px; margin-top: 4px; }
.rate textarea.inp { font: inherit; font-size: 16px; padding: 10px 12px; border-radius: var(--r); border: 1px solid var(--line-strong); background: #fff; resize: vertical; }
.repeat { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: var(--r-lg); border: 1px solid var(--line); background: var(--cream-50); text-align: left; }   /* «повторить прошлый заказ» на главной (26.09) */
.repeat > svg { width: 22px; height: 22px; flex: none; color: var(--red); }
.repeat .tx { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 2px; line-height: 1.2; }
.repeat .tx b { font-size: 15px; font-weight: 800; }
.repeat .tx small { font-size: 13px; color: var(--muted); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.invite { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: var(--r-lg); background: var(--olive-700); color: var(--cream); text-decoration: none; }
.invite .c { flex: 1; display: flex; flex-direction: column; gap: 2px; }
.invite .c b { font-size: 15px; font-weight: 800; }
.invite .go { height: 40px; padding: 0 14px; border-radius: var(--pill); background: var(--cream); color: var(--olive-700); font-size: 13px; font-weight: 800; display: inline-flex; align-items: center; white-space: nowrap; }
.errstate { flex: 1; display: flex; flex-direction: column; justify-content: center; align-items: center; text-align: center; gap: 14px; padding: 30px 10px 60px; }
.errstate .ic { width: 72px; height: 72px; border-radius: 999px; background: var(--red-100); color: var(--red); display: grid; place-items: center; }
.errstate .ic svg { width: 34px; height: 34px; }
.errstate h2.display { font-size: 26px; }
.errstate p { margin: 0; font-size: 15px; line-height: 1.5; }
.errstate .btn { width: 100%; }
.empty { flex: 1; display: flex; flex-direction: column; align-items: center; justify-content: center; text-align: center; gap: 12px; padding: 40px 10px; color: var(--muted); }
.empty .display { font-size: 24px; color: var(--black); }
.toast { position: fixed; left: 0; right: 0; margin: 0 auto; bottom: calc(var(--bar-h) + var(--safe-b) + 12px); z-index: 40; max-width: 440px; width: calc(100% - 40px); padding: 12px 16px; border-radius: var(--r); background: var(--black); color: var(--cream); font-size: 14px; line-height: 1.35; box-shadow: var(--shadow); }
.toast.err { background: var(--red-600); color: #fff; }
/* плашка о cookie и Метрике (01.10): место тоста, но с кнопкой; над панелью корзины, под шторками */
.cookie { position: fixed; left: 0; right: 0; margin: 0 auto; bottom: calc(var(--bar-h) + var(--safe-b) + 12px); z-index: 25; max-width: 440px; width: calc(100% - 40px); padding: 10px 10px 10px 16px; border-radius: var(--r); background: var(--paper); color: var(--black); font-size: 13px; line-height: 1.35; box-shadow: var(--shadow); display: flex; align-items: center; gap: 12px; }
.cookie .btn { height: 44px; padding: 0 16px; font-size: 14px; flex: none; }
.cookie.nobar { bottom: calc(var(--safe-b) + 12px); }
body.has-cookie .scr { padding-bottom: calc(var(--bar-h) + var(--safe-b) + 20px + var(--cookie-h, 100px)); }
body.has-cookie .scr.nobar { padding-bottom: calc(16px + var(--safe-b) + var(--cookie-h, 100px)); }

/* шторки */
.dim { position: fixed; inset: 0; z-index: 30; background: rgba(13,8,2,.45); display: flex; align-items: flex-end; justify-content: center; transition: opacity 200ms; }
.dim.closing { opacity: 0; }
.dim.closing .sheet { transform: translateY(100%); }
.sheet.drag { transition: none; }
.sheet { width: 100%; max-width: 480px; max-height: calc(100vh - 24px); max-height: calc(100svh - 24px); overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; touch-action: pan-y; will-change: transform; transition: transform 220ms var(--ease, ease-out); background: transparent; padding: 0; border-radius: var(--r-lg) var(--r-lg) 0 0; box-shadow: 0 -12px 40px rgba(13,8,2,.25); }
/* Скругление и клип — на самом скроллере (.sheet): он и так режет содержимое, sticky-панели не мешает, а фото режется
   ОДНИМ краем — два скруглённых края (обёртка + картинка) давали кремовую кайму в углах (скрин владельца 16.09 вечер) */
/* Прозрачный скроллер + кремовая обёртка внутри: резинку Safari у краёв не отменить посреди жеста,
   но теперь в неё «выглядывает» тёмная подложка, а не крем — читается как движение шторки (15.09) */
.sbody { background: var(--cream); border-radius: var(--r-lg) var(--r-lg) 0 0; padding: 10px var(--pad) calc(24px + var(--safe-b)); display: flex; flex-direction: column; gap: 14px; }
/* ⚠️ Без overflow: hidden — иначе sticky-панель «В корзину» липнет не к низу шторки, а к контентной коробке .sbody
   и висит на 24px + safe-area выше, накрывая плитки соусов (скрины владельца 16.09, iOS и Android; замер в Chromium: 764 против 812).
   Скругление — на .sheet. */
.sheet .grip { width: 40px; height: 4px; border-radius: 999px; background: var(--line-strong); margin: 0 auto 4px; flex: none; }
.sheet h2.display { font-size: 24px; }
.sheet p { margin: 0; font-size: 14px; color: var(--muted); }
.sheet.dish .sbody { padding-top: 0; }
.sheet.dish .grip { display: none; }
.sheet .bar { position: sticky; bottom: 0; left: auto; right: auto; width: auto; margin: 6px calc(-1 * var(--pad)) calc(-24px - var(--safe-b)); box-shadow: 0 1px 0 var(--olive); }  /* тень в 1px: дробный safe-area оставлял кремовую полоску под панелью */
/* 13.10: «Продолжить» в шторке адреса — липкий подвал, как панель «В корзину» у блюда: список домов делал шторку выше
   экрана, а кнопка лежала за сгибом, и в Safari iOS 26 её накрывала системная панель (скрин владельца). Те же поля,
   что у .sheet .bar: отрицательный низ съедает отступ .sbody, свой padding возвращает safe-area. */
.sfoot { position: sticky; bottom: 0; margin: 0 calc(-1 * var(--pad)) calc(-24px - var(--safe-b)); padding: 10px var(--pad) max(12px, calc(var(--safe-b) + 6px)); background: var(--cream); box-shadow: 0 -12px 12px -8px var(--cream); }
.choice { display: flex; align-items: center; gap: 12px; padding: 12px 14px; border-radius: var(--r); border: 1.5px solid var(--line); background: var(--cream-50); text-align: left; }
.choice.on { border-color: var(--olive); background: var(--olive-100); }
.choice .ic { width: 40px; height: 40px; border-radius: 999px; display: grid; place-items: center; background: var(--cream-200); color: var(--black); flex: none; }
.choice.on .ic { background: var(--olive-700); color: var(--cream); }
.choice .c { flex: 1; display: flex; flex-direction: column; gap: 1px; }
.choice .c b { font-size: 15px; font-weight: 800; }
.choice .c span { font-size: 13px; color: var(--muted); }
.two { display: grid; grid-template-columns: 1fr 1fr; gap: 10px; }
.miss { display: flex; flex-direction: column; gap: 10px; }
.sheet .miss p { font-size: 14px; color: var(--black); }
.choice.big { flex-direction: column; align-items: flex-start; gap: 8px; padding: 12px; min-height: 104px; }
.choice.big .c b { font-size: 15px; line-height: 1.15; }
.houses { display: flex; flex-direction: column; border: 1px solid var(--line); border-radius: var(--r); background: var(--cream-50); overflow: hidden; }
.houses.scroll { max-height: 300px; overflow-y: auto; overscroll-behavior: contain; }
.house { display: flex; align-items: center; justify-content: space-between; min-height: 56px; padding: 0 16px; border-bottom: 1px solid var(--line); font-size: 16px; font-weight: 600; width: 100%; text-align: left; }
.house:last-child { border-bottom: 0; }
.house.on { color: var(--olive-700); font-weight: 800; }
.house.on svg { width: 18px; height: 18px; stroke-width: 3; }
.house small { font-size: 12px; color: var(--muted); font-weight: 600; margin-left: 8px; }
.codes { display: grid; grid-template-columns: repeat(4, 1fr); gap: 10px; padding: 0 30px; position: relative; }
.codes span { aspect-ratio: 1 / 1; border-radius: var(--r); border: 1.5px solid var(--line-strong); background: var(--cream-50); display: grid; place-items: center; font-size: 28px; font-weight: 800; }
.codes span.cur { border-color: var(--red); }
.codes input { position: absolute; inset: 0; opacity: 0; font-size: 28px; }
.slots { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 8px; }
.slots .chip.lower { justify-content: center; padding: 0; }
.slots .chip.lower.off { color: var(--paper); border-style: dashed; }

/* статус заказа */
.orderno { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; }
.orderno .display { font-size: 22px; }
.orderno span { font-size: 14px; color: var(--muted); }
.eta { padding: 14px 16px; border-radius: var(--r-lg); background: var(--cream-50); border: 1px solid var(--line); display: flex; flex-direction: column; gap: 2px; }
.eta b { font-size: 22px; font-weight: 800; }
.eta span { font-size: 14px; color: var(--muted); }
.tl { display: flex; flex-direction: column; }
.tl .st { display: grid; grid-template-columns: 28px 1fr auto; gap: 12px; align-items: start; padding: 10px 0; position: relative; }
.tl .st::before { content: ""; position: absolute; left: 13px; top: 38px; bottom: -10px; width: 2px; background: var(--line); }
.tl .st:last-child::before { display: none; }
.tl .dot { width: 28px; height: 28px; border-radius: 999px; border: 2px solid var(--line-strong); background: var(--cream); display: grid; place-items: center; color: #fff; }
.tl .st.done .dot { background: var(--green-700); border-color: var(--green-700); }
.tl .st.now .dot { background: var(--red); border-color: var(--red); }
.tl .st.now .dot::after { content: ""; width: 10px; height: 10px; border-radius: 50%; background: #fff; }
.tl .dot svg { width: 14px; height: 14px; stroke-width: 3; }
.tl .t b { display: block; font-size: 15px; font-weight: 800; }
.tl .t span { font-size: 13px; color: var(--muted); }
.tl .st.todo .t b { color: var(--muted); font-weight: 600; }
.tl .tm { font-size: 13px; color: var(--muted); padding-top: 3px; }

/* профиль */
.prof { display: flex; flex-direction: column; gap: 12px; }
.prof .who { display: flex; align-items: center; gap: 12px; }
.prof .who h2.display { font-size: 22px; }
.prof .who p { margin: 2px 0 0; }
.stat { display: flex; align-items: center; justify-content: space-between; gap: 12px; padding: 14px 16px; border-radius: var(--r-lg); background: var(--olive-700); color: var(--cream); }
.stat b { font-size: 32px; font-weight: 800; line-height: 1; }
.stat span { font-size: 13px; color: var(--cream-50); text-align: right; line-height: 1.3; }
.last { display: flex; flex-direction: column; gap: 6px; }
.last .h { display: flex; justify-content: space-between; font-size: 13px; color: var(--muted); }
.last .h b { color: var(--black); font-weight: 800; font-size: 14px; }
.last .l { font-size: 14px; line-height: 1.35; }
.plist { display: flex; flex-direction: column; }   /* строки профиля без внешнего gap — иначе текст сидит выше центра между линиями */
.prow { display: flex; align-items: center; gap: 12px; min-height: 56px; padding: 6px 0; width: 100%; border-top: 1px solid var(--line); font-size: 15px; font-weight: 600; text-align: left; text-decoration: none; }
.prow .ic { width: 36px; height: 36px; border-radius: 999px; display: grid; place-items: center; background: var(--cream-200); flex: none; }
.prow .ic svg { width: 18px; height: 18px; }
.prow .c { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.prow .c small { font-size: 13px; color: var(--muted); font-weight: 600; }
.prow .chev { width: 16px; height: 16px; }
.prow.quiet { justify-content: center; color: var(--muted); }
.olist { display: flex; flex-direction: column; }
.olist .prow .c b { font-weight: 800; }

/* условия */
.cond { display: flex; flex-direction: column; gap: 14px; }
.cond h3 { font-size: 12px; letter-spacing: .18em; text-transform: uppercase; font-weight: 700; color: var(--muted); margin: 6px 0 0; }
.cond p { margin: 0; font-size: 14px; line-height: 1.45; }
.cond .kv { display: grid; grid-template-columns: auto 1fr; gap: 6px 12px; font-size: 14px; }
.cond .kv span:nth-child(2n) { text-align: right; font-weight: 700; }
.cond .req { font-size: 12px; color: var(--muted); line-height: 1.45; }
.skel { background: linear-gradient(90deg, var(--cream-200), var(--cream-50), var(--cream-200)); background-size: 200% 100%; animation: shimmer 1.2s infinite; border-radius: var(--r); }
@keyframes shimmer { to { background-position: -200% 0; } }

/* ==================== десктоп: каталог во всю ширину (17.09, «уровень 1») ====================
   Витрина рисовалась телефоном в рамке: #app 480px по центру на любом экране, два блюда в ряд,
   остальное — пустой фон. Раскрывается ТОЛЬКО каталог: класс `.wide` ставит ему `render()`.
   Корзина, оформление, статус заказа, условия и все шторки остаются узкими — там формы и списки,
   которым ширина не нужна, а строка во весь ноутбук читается хуже.
   Потолок колонки 1180px: при 4 колонках карточка ~264px, то есть фото каталога (`MAX_SIDE` 560
   в delivery/images.py) хватает даже на 2× экран, и крупные /img/l/ в ленту тянуть не нужно.
   Ступени 760/980 считаны от карточки, и считаны так, чтобы она только РОСЛА: в узкой колонке
   (480px) карточка 213px, третья колонка догоняет этот размер лишь к 760px — на 640px она давала
   178px, то есть переход на «десктоп» уменьшал блюда. Мобильная вёрстка не тронута: до 760px
   весь блок молчит. */
@media (min-width: 760px) {
  #app.wide { max-width: 1180px; --pad: 32px; }   /* --pad, а не padding у .scr: от него же считают свои отрицательные поля лента и hero */
  #app.wide .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 26px 20px; }
  #app.wide .bar { max-width: 1180px; }           /* панель корзины по ширине колонки; 480px по центру висели бы посреди каталога */
  /* Адрес и плашка «кухня закрыта» — одной строкой: адрес прижат вправо, плашка слева (решение владельца 17.09).
     row-reverse, а не order: в разметке адрес идёт первым (он есть всегда, плашка — только когда кухня закрыта),
     и при закрытой кухне первый по потоку элемент должен оказаться справа. Без плашки адрес просто стоит справа.
     flex-start: плашка выше пилюли, и «на том же уровне» — это общая верхняя кромка, а не центры. */
  /* 26.09: сетка вместо row-reverse — приветствие и адрес одной строкой, плашка «кухня закрыта» под
     приветствием слева, адрес держит правую колонку обеих строк (align-self start — на верхней кромке). */
  /* 27.09: приветствия больше нет — строка «плашка | адрес», а без плашки адрес во всю ширину: пилюля
     справа над пустой левой колонкой читалась оторванной. */
  #app.wide .hrow { display: grid; grid-template-columns: minmax(0, 1fr) 360px; grid-template-areas: "closed addr"; gap: 12px 16px; align-items: start; }
  #app.wide .hrow .addr { grid-area: addr; align-self: start; }
  #app.wide .hrow:not(:has(.closed)) .addr { grid-column: 1 / -1; }
  #app.wide .hrow .closed { grid-area: closed; min-width: 0; }
}
@media (min-width: 980px) { #app.wide .grid { grid-template-columns: repeat(4, minmax(0, 1fr)); } }
/* Корзина, оформление, страница заказа — «средняя» колонка 680px на десктопе (решение владельца 26.09: 480px
   на ноутбуке читались телефонной полоской). Не во всю ленту: форма и список позиций шире 680 растягивают
   строку «название … цена» так, что глаз теряет пару. Панель внизу — по той же ширине. */
@media (min-width: 760px) {
  #app.mid { max-width: 680px; --pad: 28px; }
  #app.mid .bar { max-width: 680px; }
  #app.mid .up { width: 128px; }
}
/* Наведение на карточку: состояние, а не движение — мышь должна видеть, что блюдо кликабельно.
   Отдельная строка для .off: у «разобрали» своя серая заливка той же специфичности, и без неё
   наведение вернуло бы карточку в цвет. */
@media (hover: hover) { .card:hover .ph { filter: brightness(.95); } .card.off:hover .ph { filter: grayscale(1) opacity(.55); } }
