:root{
  --burgundy:#4a1620; --burgundy-deep:#330f17; --burgundy-soft:#5c1d29;
  --vanilla:#ece1cb; --vanilla-2:#f3ebd9; --vanilla-line:#d8cbad;
  --ink:#2a2724; --ink-soft:#4d4842; --ink-mute:#837b6f;
  --terracotta:#b0502c; --khaki:#6b6736; --blue:#33455c;
  --stripe:#7d2630; --ok:#5e7d3a; --err:#a8362f;
  --mono:'Courier New','Courier',ui-monospace,SFMono-Regular,monospace;
  --disp:'Oswald',var(--mono);
  --r:16px; --r-sm:10px;
  --shadow:0 18px 50px rgba(0,0,0,.45);
  --grain-dark:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='160' height='160'><filter id='n'><feTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='2' stitchTiles='stitch'/><feColorMatrix type='saturate' values='0'/></filter><rect width='100%25' height='100%25' filter='url(%23n)'/></svg>");
  --grain-paper:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='120' height='120'><filter id='p'><feTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='2'/><feColorMatrix type='saturate' values='0'/></filter><rect width='100%25' height='100%25' filter='url(%23p)'/></svg>");
  /* ---- Семантические токены (введены при разделении ролей) ----------
     Значения совпадают с исходными, поэтому вид сайта не меняется.
     Смысл разделения: один и тот же цвет играл две роли сразу, и при
     смене темы это ломало читаемость. Теперь роль у каждого токена одна.
       --on-dark / --on-dark-mute — текст ПОВЕРХ тёмного фона
       --btn-dark / --btn-dark-soft — заливка тёмной кнопки
       --accent-ink / --accent-ink-soft — тёмный акцентный ТЕКСТ на светлом
       --btn-hover, --panel-1/2 — бывшие хардкоды                        */
  --on-dark:#ece1cb; --on-dark-mute:#d8cbad;
  --btn-dark:#2a2724; --btn-dark-soft:#837b6f;
  --accent-ink:#4a1620; --accent-ink-soft:#5c1d29;
  --btn-hover:#ffffff; --panel-1:#332f2b; --panel-2:#211e1b;

  /* ---- RGB-тройки для rgba() ------------------------------------------
     Полупрозрачные цвета нельзя выразить через обычный токен: rgba() ждёт
     числа, а не #hex. Поэтому те же цвета продублированы тройками — их
     подставляет rgba(var(--x-rgb), .5). Значения совпадают с исходными,
     вид базовой темы не меняется.
       --on-dark-rgb  светлое поверх тёмного: текст, рамки, подсветка
       --scrim-rgb    плотное затемнение поверх фотографии
       --shade-N-rgb  затемняющие слои шапки и подвала                    */
  --on-dark-rgb:236,225,203; --vanilla-line-rgb:216,203,173;
  --ink-rgb:42,39,36; --scrim-rgb:42,39,36;
  --terracotta-rgb:176,80,44; --burgundy-rgb:74,22,32; --burgundy-deep-rgb:51,15,23;
  --err-rgb:168,54,47; --ok-rgb:94,125,58;
  --shade-1-rgb:20,6,9; --shade-2-rgb:20,10,14; --shade-3-rgb:30,8,13; --shade-4-rgb:33,10,15;

}
*{margin:0;padding:0;box-sizing:border-box}
html{scroll-behavior:smooth}

/* Масштабирование на гостевой части отключено (сайт должен вести себя как
   приложение). Одного мета-тега viewport мало: Safari на iOS с 10-й версии
   игнорирует user-scalable=no, поэтому здесь гасим жесты через touch-action,
   а щипок в iOS добивается обработчиком gesture* в js/marketplace.js.
   Значение pan-x pan-y, а не none: прокрутка страницы и горизонтальная лента
   категорий .filter-scroll должны остаться рабочими — убираем только двойной
   тап и щипок. Правило действует лишь на гостевую часть: админка style.css
   не подключает. */
html, body{touch-action:pan-x pan-y}
body{
  font-family:var(--mono); color:var(--ink); background:var(--burgundy);
  -webkit-font-smoothing:antialiased; text-rendering:optimizeLegibility;
  min-height:100dvh; overflow-x:hidden; position:relative;
}
/* Фон — ГОТОВАЯ картинка дизайнера (Brandbook_Cover-selection.png).
   Вся текстура — стена, облачные разводы, крошки — уже нарисована внутри.
   Никаких CSS-градиентов и blend: их попытки пересобрать сцену и давали то
   розовизну, то блеск. Просто показываем изображение на весь экран.
   bg-hero.jpg — 2560×1440, 135 КБ; на узком экране грузим лёгкий bg-hero-m.jpg.
   background-attachment:fixed — фон стоит, контент скроллит по нему. */
body::before{content:"";position:fixed;inset:0;z-index:0;pointer-events:none;
  background:var(--burgundy) url("../assets/img/bg-hero.jpg") center center / cover no-repeat;}

/* ФОНОВЫЙ СЛАЙДЕР ГЛАВНОЙ
   ВАЖНО: слой лежит ВНУТРИ .hero (absolute, inset:0), а не на всё окно.
   Пока он был fixed inset:0, object-fit:cover подгонял снимок под всю высоту
   экрана, а видна была только верхняя половина — остальное закрывает кремовая
   плита меню. Из-за этого вертикальное кадрирование не совпадало с превью в
   админке. Теперь область подгонки совпадает с областью видимости.
   z-index:-1 кладёт слой под текст героя: .hero создаёт стековый контекст
   (position:relative + z-index:1), а его дети .hero-tag/.hero-sub/.hero-cta
   статичные, так что при z-index:0 они оказались бы ПОД фотографией.
   Живёт ровно там же, где body::before: фиксированный слой на весь экран,
   видимый за шапкой и героем, ниже закрытый кремовой плитой меню. Рисуется
   только когда в админке есть хотя бы один включённый кадр — иначе разметки
   нет вовсе и виден прежний бордовый фон.
   z-index:0 — как у body::before; контент сайта лежит на z-index:1.
   Старый фон остаётся ПОД слайдером: он служит подложкой, пока грузится
   первый кадр, поэтому вспышки белым не бывает. */
/* position:fixed — ради параллакса: снимок стоит на месте, плита меню наезжает
   на него при прокрутке. Высота НЕ 100%, а ровно видимая полоса (шапка + герой):
   её замеряет js/script.js и кладёт в --hero-band. Растяжка на всю высоту окна
   и была причиной того, что вертикальное кадрирование не совпадало с превью —
   картинка подгонялась под весь экран, а видна была только верхняя половина.
   Запасные 70vh — если JS не отработал: параллакс останется, кадрирование будет
   приблизительным, но ничего не сломается. */
.hero-slides{position:fixed;top:0;left:0;right:0;height:var(--hero-band,70vh);z-index:0;overflow:hidden;pointer-events:none}
.hero-slide{
  position:absolute;inset:0;width:100%;height:100%;
  object-fit:cover;
  /* Кадрирование задаётся покадрово в админке двумя инлайновыми переменными:
     --pos-d для широких экранов, --pos-m для узких. Так на телефоне у
     горизонтального снимка можно вытянуть в центр нужную часть, не трогая
     десктопный вид. Запасное значение 50% 50% — обычный центр. */
  object-position:var(--pos-d,50% 50%);
  opacity:0;transition:opacity 1.1s ease;
}
/* 820px — существующий брейкпоинт сайта (по нему же перестраивается подвал).
   Берём его, а не 560px: планшет в портрете кадрируется как телефон, а не
   как десктоп, и это ближе к тому, что человек ожидает от «мобильной версии». */
@media (max-width:820px){
  .hero-slide{object-position:var(--pos-m,50% 50%)}
}
.hero-slide.is-on{opacity:1}
/* Бордовая маска поверх фото. Плотность приходит из админки инлайновой
   переменной --hero-mask (доля от 0 до 1); .72 — запасное значение на случай,
   если переменная почему-то не доехала. */
.hero-slides::after{
  content:"";position:absolute;inset:0;
  /* Цвет приходит из админки РАЗЛОЖЕННЫМ на компоненты (--hero-mask-rgb: 74,22,32),
     а не как hex: подставить #rrggbb внутрь rgba() нельзя, а color-mix() ещё
     не везде поддерживается. Запасные значения — фирменный бордовый и .72. */
  background:rgba(var(--hero-mask-rgb,74,22,32),var(--hero-mask,.72));
}
/* Пользователю, который просил меньше движения, кроссфейд не показываем —
   автосмену в script.js для него тоже не запускаем. */
@media (prefers-reduced-motion: reduce){
  .hero-slide{transition:none}
}
/* На мобильном фон fixed привязан к границам viewport (inset:0), а они гуляют
   вместе с адресной строкой браузера при скролле — из-за этого фон дёргался.
   Даём фону запас: делаем его выше экрана и сдвигаем вверх. Когда панель
   прячется/появляется, оголиться нечему — край всегда за пределами видимого.
   height:130vh / top:-15vh: 15% сверху и 15% снизу в буфере, с запасом на
   любую высоту панели. inset:0 переопределяем через top/bottom:auto. */
@media (max-width:560px){body::before{
  background-image:url("../assets/img/bg-hero-m.jpg");
  top:-15vh;bottom:auto;height:130vh;}}
img{max-width:100%;display:block}
a{color:inherit;text-decoration:none}
.wrap{width:100%;max-width:1200px;margin:0 auto;padding:0 20px}
/* Полоса прокрутки страницы — ОДИНАКОВАЯ ВЕЗДЕ.
   ДОРОЖКА ЗАДАНА ЯВНО (бежевая), а не transparent: прозрачная показывает фон
   страницы, и на главной сквозь неё просвечивал бордовый body — полоса выглядела
   тёмной, а на /cart светлой. Ползунок бордовый: 12.4:1 на своей дорожке.
   ВАЖНО: scrollbar-color НАСЛЕДУЕТСЯ, поэтому правило на html задаёт вид
   скроллбаров и во вложенных блоках, у которых нет своего значения. */
html{scrollbar-width:thin;scrollbar-color:var(--accent-ink) var(--vanilla-2,#f3ebd9)}
body::-webkit-scrollbar{width:8px;height:8px}
body::-webkit-scrollbar-track{background:var(--vanilla-2,#f3ebd9)}
body::-webkit-scrollbar-thumb{background:var(--burgundy,#4a1620);border-radius:8px}
body::-webkit-scrollbar-thumb:hover{background:var(--terracotta,#b0502c)}
/* любой прокручиваемый блок без собственного правила — такой же тонкий.
   Здесь дорожка прозрачная: внутри блоков подложка и так светлая, а своя
   бежевая полоса на карточке смотрелась бы лишней рамкой. */
*::-webkit-scrollbar{width:8px;height:8px}
*::-webkit-scrollbar-track{background:transparent}
*::-webkit-scrollbar-thumb{background:var(--burgundy,#4a1620);border-radius:8px}
*::-webkit-scrollbar-thumb:hover{background:var(--terracotta,#b0502c)}

/* ==================== HEADER ==================== */
.site-header{position:sticky;top:0;z-index:30;
  background:rgba(var(--burgundy-deep-rgb),.86);backdrop-filter:blur(8px);
  border-bottom:1px solid rgba(var(--on-dark-rgb),.12);}
.header-row{display:flex;align-items:center;justify-content:space-between;gap:16px;height:66px}
.brand{display:flex;align-items:center;gap:12px}
.brand .mark-chip{background:var(--vanilla);border:1px solid var(--vanilla-line);border-radius:8px;padding:5px 8px;display:inline-flex;align-items:center;box-shadow:0 2px 0 rgba(0,0,0,.22)}
.brand .mark-chip img{height:30px;width:auto;display:block}
.brand .wm{font-family:var(--mono);font-weight:700;letter-spacing:4px;font-size:18px;color:var(--on-dark);text-transform:uppercase}
.header-actions{display:flex;align-items:center;gap:12px}
.phone-link{display:inline-flex;align-items:center;gap:8px;color:var(--on-dark);
  font-size:12.5px;letter-spacing:1px;opacity:.9}
.phone-link i{color:var(--terracotta)}
.phone-link:hover{opacity:1}

/* language pill (как в портале) */
.lang{position:relative}
.lang-btn{font-family:var(--mono);font-size:12px;font-weight:700;letter-spacing:.5px;
  text-transform:uppercase;background:var(--btn-dark);color:var(--on-dark);border:none;border-radius:999px;
  padding:8px 13px;display:inline-flex;align-items:center;gap:7px;cursor:pointer;transition:background .18s}
.lang-btn:hover{background:var(--burgundy-soft)}
.lang-btn .fa-chevron-down{font-size:9px;opacity:.7}
.lang-menu{position:absolute;top:calc(100% + 8px);right:0;min-width:168px;background:var(--vanilla-2);
  border:1px solid var(--vanilla-line);border-radius:var(--r-sm);box-shadow:0 12px 30px rgba(0,0,0,.4);
  overflow:hidden;opacity:0;visibility:hidden;transform:translateY(-6px);transition:.18s;z-index:40}
.lang-menu.show{opacity:1;visibility:visible;transform:translateY(0)}
.lang-opt{display:block;padding:11px 15px;color:var(--ink);font-size:13px;letter-spacing:.4px;
  border-bottom:1px solid var(--vanilla-line);cursor:pointer;transition:background .15s}
.lang-opt:last-child{border-bottom:none}
.lang-opt:hover,.lang-opt.active{background:rgba(var(--terracotta-rgb),.12);color:var(--terracotta)}

/* ==================== HERO ==================== */
.hero{position:relative;z-index:1;text-align:center;padding:56px 20px 44px}
.hero-logo{display:block;width:fit-content;margin:0 auto 22px;position:relative;padding:30px 48px 26px;animation:fadeUp .7s ease both;background:linear-gradient(180deg,var(--vanilla-2),var(--vanilla));border:1px solid var(--vanilla-line);border-radius:var(--r);box-shadow:var(--shadow)}
.hero-logo::before{content:"";position:absolute;inset:10px;border:1px dashed rgba(var(--ink-rgb),.16);border-radius:calc(var(--r) - 8px);pointer-events:none}
.hero-logo::after{content:"";position:absolute;inset:0;border-radius:var(--r);pointer-events:none;opacity:.05;mix-blend-mode:multiply;background-image:var(--grain-paper)}
.hero-logo img{position:relative;z-index:1;height:180px;width:auto;margin:0 auto;display:block}
/* .hero-tag стал <h1> (1.5.83, SEO): у h1 есть браузерный margin .67em —
   гасим, иначе герой разъезжается. font-size задан здесь, так что размер
   от смены тега не меняется. */
.hero-tag{display:inline-block;margin:0;font-family:var(--mono);font-weight:700;font-size:13px;letter-spacing:3px;
  text-transform:uppercase;color:var(--on-dark);padding-top:12px;border-top:2px solid var(--stripe);
  animation:fadeUp .7s .08s ease both}
.hero-sub{max-width:520px;margin:16px auto 26px;font-size:13.5px;line-height:1.6;color:rgba(var(--on-dark-rgb),.7);
  letter-spacing:.4px;white-space:pre-line;animation:fadeUp .7s .14s ease both}
.hero-cta{display:flex;gap:12px;justify-content:center;flex-wrap:wrap;animation:fadeUp .7s .2s ease both}
.btn{font-family:var(--mono);font-size:13px;font-weight:700;letter-spacing:1.5px;text-transform:uppercase;
  border:none;border-radius:var(--r-sm);padding:14px 22px;display:inline-flex;align-items:center;gap:10px;
  cursor:pointer;transition:transform .12s,background .18s}
.btn:active{transform:scale(.98)}
.btn-primary{background:var(--vanilla);color:var(--ink)}
.btn-primary:hover{background:var(--btn-hover)}
.btn-ghost{background:transparent;color:var(--on-dark);border:1.5px solid rgba(var(--on-dark-rgb),.35)}
.btn-ghost:hover{border-color:var(--terracotta);color:var(--terracotta)}
.btn-ghost i,.btn-primary i{color:var(--terracotta)}
@keyframes fadeUp{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}

/* ==================== MENU AREA (vanilla sheet) ==================== */
.menu-sheet{position:relative;z-index:1;background:var(--vanilla);
  border-top:1px solid var(--vanilla-line);margin-top:20px}
.menu-sheet::after{content:"";position:absolute;inset:0;pointer-events:none;z-index:0;
  opacity:.05;mix-blend-mode:multiply;background-image:var(--grain-paper)}
.menu-sheet .wrap{position:relative;z-index:1;padding-top:30px;padding-bottom:60px}

/* sticky category filter */
.filter-bar{position:sticky;top:66px;z-index:20;background:var(--vanilla);
  border-bottom:1px solid var(--vanilla-line);margin:0 -20px 8px;padding:12px 20px}
.filter-scroll{display:flex;gap:9px;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch}
.filter-scroll::-webkit-scrollbar{display:none}
.cat-btn{flex:0 0 auto;font-family:var(--mono);font-size:12px;font-weight:700;letter-spacing:1px;
  text-transform:uppercase;background:transparent;color:var(--ink-soft);
  border:1.5px solid var(--vanilla-line);border-radius:999px;padding:9px 16px;cursor:pointer;
  transition:.16s;white-space:nowrap}
.cat-btn:hover{border-color:var(--terracotta);color:var(--terracotta)}
.cat-btn.active{background:var(--btn-dark);color:var(--on-dark);border-color:var(--ink)}

/* signature: dimension-style category header */
.cat-block{margin:34px 0 4px;scroll-margin-top:132px}
.cat-head{display:flex;align-items:center;gap:14px;margin-bottom:20px}
.cat-index{font-family:var(--mono);font-size:12px;font-weight:700;letter-spacing:1px;color:var(--terracotta);
  border:1.5px solid var(--terracotta);border-radius:4px;padding:4px 8px;flex:0 0 auto}
.cat-name{font-family:var(--disp);font-weight:700;font-size:26px;letter-spacing:1px;text-transform:uppercase;color:var(--ink);flex:0 0 auto}
.cat-rule{flex:1;height:0;border-top:1.5px dashed rgba(var(--ink-rgb),.28);position:relative;top:2px}
.cat-count{font-family:var(--mono);font-size:11px;letter-spacing:1px;color:var(--ink-mute);flex:0 0 auto;text-transform:uppercase}

/* grid */
.grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:18px}

/* card — technical/paper */
/* Карточка — колонка, чтобы цену можно было прижать к низу.
   Грид и так растягивает все карточки ряда до одной высоты, но внутри был
   обычный поток: .card-meta шла сразу за описанием, а свободное место копилось
   ПОД ней. Из-за этого цена гуляла по высоте — заголовок в 2 строки против 3,
   у одного блюда есть вес, у другого нет. Теперь лишнее место уходит НАД ценой
   (.card-meta{margin-top:auto}), и цены в ряду стоят на одной линии. */
.card{position:relative;background:var(--vanilla-2);border:1px solid var(--vanilla-line);
  border-radius:var(--r-sm);overflow:hidden;cursor:pointer;transition:transform .16s,box-shadow .16s,border-color .16s;
  display:flex;flex-direction:column}
.card:hover{transform:translateY(-4px);box-shadow:0 14px 32px rgba(var(--burgundy-deep-rgb),.18);border-color:var(--terracotta)}
.card::before{content:"";position:absolute;inset:8px;border:1px dashed rgba(var(--ink-rgb),.16);
  border-radius:6px;pointer-events:none;z-index:2}
/* flex-shrink:0 обязателен: без него медиа — сжимаемый flex-элемент, и на
   карточке с длинным заголовком картинку расплющило бы, сломав aspect-ratio 4/3. */
.card-media{position:relative;aspect-ratio:4/3;background:var(--btn-dark);overflow:hidden;flex-shrink:0}
.card-media img{width:100%;height:100%;object-fit:cover}
.card-ph{position:absolute;inset:0;display:flex;align-items:center;justify-content:center;
  background:linear-gradient(160deg,var(--panel-1),var(--panel-2))}
.card-ph img{width:58%;height:auto;object-fit:contain;opacity:.16;filter:brightness(0) invert(1)}
.labels{position:absolute;top:10px;left:10px;z-index:3;display:flex;flex-direction:column;gap:6px;align-items:flex-start}
.lb{font-family:var(--mono);font-size:10px;font-weight:700;letter-spacing:1px;text-transform:uppercase;
  color:var(--on-dark);padding:4px 8px;border-radius:4px}
.lb-hit{background:var(--khaki)}.lb-new{background:var(--terracotta)}.lb-hot{background:var(--stripe)}.lb-veg{background:var(--ok)}
/* метки, которые приходят из iiko сверх исходных четырёх.
   --blue из брендбука до сих пор нигде не использовался — забираем под алкоголь.
   lb-def — страховка: нераспознанную метку показываем нейтрально, а не теряем. */
.lb-alco{background:var(--blue)}.lb-spec{background:var(--btn-dark)}.lb-def{background:var(--btn-dark-soft)}
/* Оверлей «нет в наличии» чисто декоративный: затемнение + подпись. Клики он
   перехватывать не должен — из-за этого не нажималась кнопка закрытия модалки.
   pointer-events:none пропускает клик к тому, что под ним; добавить распроданное
   в корзину это не позволяет — кнопки «добавить» у такой позиции просто нет
   (js/script.js: футер модалки рисуется при canOrder && !i.soldOut). */
.sold-out{position:absolute;inset:0;z-index:3;background:rgba(var(--shade-4-rgb),.62);display:flex;align-items:center;justify-content:center;pointer-events:none}
.sold-out span{font-family:var(--mono);font-size:12px;font-weight:700;letter-spacing:2px;text-transform:uppercase;
  color:var(--on-dark);border:2px solid var(--vanilla);padding:8px 14px;border-radius:6px;transform:rotate(-6deg)}
.card-body{position:relative;z-index:1;padding:16px 15px 15px;flex:1;display:flex;flex-direction:column}
.card-title{font-family:var(--disp);font-weight:600;font-size:18px;letter-spacing:.5px;text-transform:uppercase;color:var(--ink);line-height:1.05}
.card-desc{font-size:12px;line-height:1.5;color:var(--ink-soft);margin:7px 0 12px;min-height:34px}
.card-meta{display:flex;align-items:flex-end;justify-content:space-between;gap:10px;flex-wrap:wrap;margin-top:auto}
.card-weight{font-family:var(--mono);font-size:11px;letter-spacing:1px;color:var(--ink-mute)}
/* signature: price drawn as a dimension callout */
/* Цена и валюта — единое целое, разрывать между ними нельзя.
   На мобильном сетка падает до minmax(150px,1fr), и в карточку ~150px строка
   «вес + цена + валюта» не влезала: перенос рвал цену пополам («10 000» и
   «so'm» на разных строках), а декоративная скобка ::before центрируется по
   высоте — на двух строках она уезжала в сторону.
   nowrap держит цену целой, flex-wrap у .card-meta роняет её на свою строку
   целиком, margin-left:auto оставляет её справа — как и задумано в макете.
   На широких карточках оба свойства не срабатывают: там и так всё влезает. */
.price{font-family:var(--mono);font-weight:700;font-size:15px;color:var(--ink);letter-spacing:.5px;
  position:relative;padding-left:14px;white-space:nowrap;margin-left:auto}
.price::before{content:"";position:absolute;left:0;top:50%;width:8px;height:8px;transform:translateY(-50%);
  border-left:1.5px solid var(--stripe);border-top:1.5px solid var(--stripe);border-bottom:1.5px solid var(--stripe)}
.price .cur{color:var(--ink-mute);font-weight:400;font-size:12px}

/* ==================== MODAL ==================== */
.modal-overlay{position:fixed;inset:0;z-index:60;background:rgba(var(--shade-1-rgb),.72);backdrop-filter:blur(3px);
  display:none;align-items:center;justify-content:center;padding:18px}
.modal-overlay.open{display:flex;animation:fadeIn .2s ease}
@keyframes fadeIn{from{opacity:0}to{opacity:1}}
.modal{width:100%;max-width:520px;max-height:88dvh;background:var(--vanilla);border:1px solid var(--vanilla-line);
  border-radius:var(--r);box-shadow:var(--shadow);display:flex;flex-direction:column;overflow:hidden}
.modal-top{flex:0 0 auto;display:flex;align-items:center;justify-content:space-between;padding:15px 18px;background:var(--btn-dark);color:var(--on-dark)}
.modal-top h2{font-family:var(--mono);font-size:13px;font-weight:700;letter-spacing:1.5px;text-transform:uppercase}
.modal-x{background:none;border:none;color:var(--on-dark);font-size:26px;line-height:1;cursor:pointer;opacity:.85}
.modal-x:hover{opacity:1;color:var(--terracotta)}
/* модалка товара — та же полоса, что и везде */
.modal-scroll{flex:1 1 auto;min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:var(--accent-ink) transparent}
.modal-scroll::-webkit-scrollbar{width:8px}
.modal-scroll::-webkit-scrollbar-track{background:transparent}
.modal-scroll::-webkit-scrollbar-thumb{background:var(--burgundy,#4a1620);border-radius:8px}
.modal-scroll::-webkit-scrollbar-thumb:hover{background:var(--terracotta,#b0502c)}
#modalMedia{flex:0 0 auto}
.modal-media{aspect-ratio:16/10;background:var(--btn-dark);position:relative}
.modal-media img{width:100%;height:100%;object-fit:cover}
.modal-media .card-ph img{width:38%;height:auto;object-fit:contain}
.modal-body{padding:20px}
.modal-title{font-family:var(--disp);font-weight:700;font-size:24px;letter-spacing:.5px;text-transform:uppercase;color:var(--ink)}
.modal-desc{font-size:13px;line-height:1.6;color:var(--ink-soft);margin:8px 0 16px}
.modal-tags{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:14px}
.modal-facts{display:flex;gap:10px;flex-wrap:wrap;margin-bottom:16px}
.fact{display:inline-flex;align-items:center;gap:7px;background:rgba(var(--terracotta-rgb),.08);border:1px solid rgba(var(--terracotta-rgb),.2);
  border-radius:var(--r-sm);padding:8px 12px;font-size:12px;letter-spacing:.5px;color:var(--ink-soft)}
.fact i{color:var(--terracotta)}
.mod-group{margin-top:16px}
.mod-group-head{display:flex;align-items:center;gap:8px;margin-bottom:9px}
.mod-group-name{font-family:var(--mono);font-size:12px;font-weight:700;letter-spacing:1px;text-transform:uppercase;color:var(--ink)}
.mod-req{font-family:var(--mono);font-size:9px;font-weight:700;letter-spacing:1px;text-transform:uppercase;
  color:var(--on-dark);background:var(--stripe);border-radius:3px;padding:3px 6px}
.mod-item{display:flex;align-items:center;justify-content:space-between;gap:10px;padding:10px 0;border-bottom:1px dashed var(--vanilla-line)}
.mod-item:last-child{border-bottom:none}
.mod-item .n{font-size:13px;color:var(--ink-soft)}
/* вес модификатора: в iiko он есть, в исходном макете элемента не было */
.mod-item .mod-w{font-family:var(--mono);font-size:11px;letter-spacing:.5px;color:var(--ink-mute)}
.mod-item .p{font-family:var(--mono);font-size:12.5px;font-weight:700;color:var(--ink)}
.mod-item .p.free{color:var(--ok);font-weight:400}
.modal-price{margin-top:20px;padding-top:16px;border-top:2px solid var(--stripe);
  display:flex;align-items:baseline;justify-content:space-between}
.modal-price .lab{font-family:var(--mono);font-size:11px;letter-spacing:1.5px;text-transform:uppercase;color:var(--ink-mute)}
/* Та же связка число+валюта, что и на карточке — на узком экране
   длинная цена вроде «1 500 000 soʻm» рвалась бы так же. */
.modal-price .val{font-family:var(--disp);font-weight:700;font-size:26px;color:var(--ink);white-space:nowrap}
.modal-price .val .cur{font-family:var(--mono);font-size:14px;color:var(--ink-mute);font-weight:400}

/* ==================== FOOTER ==================== */
/* Футер БЕЗ своей картинки — намеренно. Основной фон (body::before) fixed и
   продолжается под всей страницей, включая футер. Даём футеру только
   полупрозрачное затемнение: сквозь него виден тот же fixed-фон, что и вверху,
   поэтому параллакс здесь такой же, единым полотном. Своя картинка приклеилась
   бы к футеру и ехала с ним — параллакс бы пропал; а свой fixed-фон дал бы на
   мобильном то самое дёрганье при скрытии панели браузера. Затемнение выделяет
   подвал и держит контраст для светлого текста. */
/* Подложка var(--burgundy) в том же объявлении делает подвал НЕПРОЗРАЧНЫМ,
   не меняя его вида: градиент теперь ложится на собственный фон элемента,
   а не на то, что лежит ниже по стеку. Раньше сквозь него просвечивал
   body::before — бордовая текстура, которую никто не замечал, — а с 1.5.57
   там же оказался слой слайдера, и на телефоне фотография проступала сквозь
   подвал. Итоговый цвет тот же: #2f0d14 сверху и #280b11 снизу.
   Запасное #4a1620 у var() существенно: без него пропажа переменной сделала бы
   ВСЁ объявление background недействительным на этапе вычисления, и подвал
   стал бы полностью прозрачным — то есть ровно та беда, ради которой правка. */
.site-footer{position:relative;z-index:1;color:var(--on-dark);padding:44px 20px 30px;
  background:var(--burgundy,#4a1620) linear-gradient(180deg, rgba(var(--shade-3-rgb),.62) 0%, rgba(var(--shade-3-rgb),.78) 100%);}
.site-footer>*{position:relative;z-index:1}
.foot-grid{display:grid;grid-template-columns:1fr 1fr 1fr;gap:60px;align-items:center}
.foot-brand{text-align:center}
.foot-brand .foot-plate{display:block;width:fit-content;margin:0 auto 16px;position:relative;padding:22px 32px 18px;background:linear-gradient(180deg,var(--vanilla-2),var(--vanilla));border:1px solid var(--vanilla-line);border-radius:var(--r);box-shadow:0 10px 26px rgba(0,0,0,.35)}
.foot-brand .foot-plate::before{content:"";position:absolute;inset:9px;border:1px dashed rgba(var(--ink-rgb),.16);border-radius:calc(var(--r) - 7px);pointer-events:none}
.foot-brand .foot-plate img{position:relative;z-index:1;height:104px;width:auto;display:block}
.foot-tag{font-family:var(--mono);font-size:12px;font-weight:700;letter-spacing:2px;text-transform:uppercase;
  color:rgba(var(--on-dark-rgb),.85);padding-top:10px;border-top:2px solid var(--stripe);display:inline-block}
.foot-col{text-align:center}
.foot-lang{display:none}
.foot-toggle{display:none}
.foot-lang-link{cursor:pointer}
.foot-col h4{font-family:var(--mono);font-size:11px;font-weight:700;letter-spacing:1.5px;text-transform:uppercase;
  color:var(--terracotta);margin-bottom:14px}
.foot-col a,.foot-col p{display:block;font-size:12.5px;letter-spacing:.5px;color:rgba(var(--on-dark-rgb),.78);
  margin-bottom:9px;line-height:1.5;text-align:center}
.foot-col a:hover{color:var(--terracotta)}
.foot-col .cat-link{cursor:pointer}
.foot-bottom{margin-top:34px;padding-top:18px;border-top:1px solid rgba(var(--on-dark-rgb),.14);
  font-family:var(--mono);font-size:10.5px;letter-spacing:2px;text-transform:uppercase;color:rgba(var(--on-dark-rgb),.5);
  text-align:center}

/* ==================== RESPONSIVE ==================== */
@media (max-width:820px){
  .foot-grid{grid-template-columns:1fr 1fr}
  .foot-brand{grid-column:1 / -1}
}
@media (max-width:560px){
  .header-row{height:58px}
  .brand .wm{font-size:15px;letter-spacing:3px}
  .brand img{height:32px}
  .phone-link span{display:none}
  .hero{padding:40px 18px 34px}
  .hero-logo img{height:140px}
  .filter-bar{top:58px}
  .cat-block{scroll-margin-top:116px}
  .cat-name{font-size:22px}
  .grid{grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:12px}

  /* Все карточки одного размера — только на мобильном.
     На узкой карточке (~150px) заголовки из iiko занимают от 2 до 4 строк
     («QO'SHIMCHA KETCHUP 20GR» против «GARNIR JAYDARCHA KARTOSHKA 120GR»),
     поэтому карточки в соседних рядах разъезжались по высоте.
     Задаём тексту фиксированную высоту, лишнее режем многоточием.

     Порядок и размеры заданы явно: название 1 строка → описание 3 строки →
     вес и цена. Высоты кратны строке, а не «на глаз»:
       заголовок 1 строка  = 1 × 1.05em = 1.05em  (18px × 1.05     ≈ 19px)
       описание  3 строки  = 3 × 1.5em  = 4.5em   (12px × 1.5 × 3  = 54px)
     Считаем в em, чтобы высота ехала за font-size, а не разъезжалась с ним.

     Шрифт НЕ уменьшаем: мельчить ради влезания хуже, чем обрезать хвост
     многоточием.

     ВНИМАНИЕ на будущее. Одна строка на название — осознанный выбор заказчика,
     не недосмотр. Цена решения: длинные имена из iiko режутся жёстко, и позиции
     с общим префиксом становятся неразличимы — «QO'SHIMCHA TAR-TAR SOUSI 20GR»
     и «QO'SHIMCHA BARBEKYU SOUSI 20GR» обе превратятся в «QO'SHIMCHA…».
     Если это вылезет — вернуть 2–3 строки (2.10em / 3.15em) и урезать описание. */
  .card-title{display:-webkit-box;-webkit-line-clamp:1;-webkit-box-orient:vertical;
    overflow:hidden;height:1.05em}
  .card-desc{display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;
    overflow:hidden;height:4.5em;min-height:0}
  .foot-grid{grid-template-columns:1fr;gap:0}
  .foot-lang{display:block}
  .foot-col{border-top:1px solid rgba(var(--on-dark-rgb),.12)}
  .foot-col .foot-head{cursor:pointer;position:relative;margin-bottom:0;padding:16px 6px;font-size:14.5px}
  .foot-toggle{display:inline-block;position:absolute;right:4px;top:50%;transform:translateY(-50%);transition:transform .2s ease;font-size:12px;color:var(--terracotta)}
  .foot-col.active .foot-toggle{transform:translateY(-50%) rotate(180deg)}
  .foot-acc{display:none;padding:2px 0 16px}
  .foot-col.active .foot-acc{display:flex;flex-direction:column;gap:6px}
  .foot-col a,.foot-col p{font-size:15px;margin-bottom:11px}
  .foot-tag{font-size:12.5px}
  .foot-bottom{font-size:12px;letter-spacing:1px;line-height:1.7}
}
@media (prefers-reduced-motion:reduce){*{transition:none!important;animation:none!important}}

/* ==================== LOADER (assemble MSHTM, seamless) ==================== */
.mshtm-loader{position:fixed;inset:0;z-index:9999;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:26px;background:linear-gradient(180deg,var(--vanilla-2),var(--vanilla));transition:opacity .55s ease, visibility .55s}
.mshtm-loader::after{content:"";position:absolute;inset:0;pointer-events:none;opacity:.05;mix-blend-mode:multiply;background-image:var(--grain-paper)}
.mshtm-loader.hide{opacity:0;visibility:hidden;pointer-events:none}
.ml-logo{position:relative;width:200px;height:232px;animation:mshtm2-settle 3.4s ease-in-out infinite;transform-origin:center;z-index:1}
/* Три готовых слоя-картинки. Никакого clip-path: лого нарезано заранее, резать
   нечего, поэтому субпиксельных швов не бывает в принципе. object-fit:contain —
   слои совмещаются по общему боксу 200×232. */
.ml-p{position:absolute;inset:0;width:100%;height:100%;object-fit:contain;-webkit-user-drag:none;user-select:none;will-change:transform,opacity}
.ml-left{animation:mshtm2-left 3.4s cubic-bezier(.34,1.4,.5,1) infinite}
.ml-right{animation:mshtm2-right 3.4s cubic-bezier(.34,1.4,.5,1) infinite}
.ml-down{animation:mshtm2-down 3.4s cubic-bezier(.34,1.4,.5,1) infinite}
.ml-cap{font-family:var(--mono);font-size:10px;font-weight:700;letter-spacing:4px;text-transform:uppercase;color:var(--ink-mute);z-index:1;padding-top:12px;border-top:2px solid var(--stripe)}
/* Тайминги из макета v3: слои прилетают (left→right→down) и держатся, settle
   бьёт «ударом» на 55–61% и уводит всё в прозрачность к 100%. */
@keyframes mshtm2-left{0%{transform:translateX(-170%) rotate(-5deg);opacity:0}16%{transform:translateX(0) rotate(0);opacity:1}100%{transform:translateX(0) rotate(0);opacity:1}}
@keyframes mshtm2-right{0%{transform:translateX(170%) rotate(5deg);opacity:0}10%{transform:translateX(170%) rotate(5deg);opacity:0}26%{transform:translateX(0) rotate(0);opacity:1}100%{transform:translateX(0) rotate(0);opacity:1}}
@keyframes mshtm2-down{0%{transform:translateY(190%);opacity:0}30%{transform:translateY(190%);opacity:0}46%{transform:translateY(0);opacity:1}100%{transform:translateY(0);opacity:1}}
@keyframes mshtm2-settle{0%,50%{transform:scale(1);opacity:1}55%{transform:scale(1.06)}61%{transform:scale(1)}88%{transform:scale(1);opacity:1}100%{transform:scale(1);opacity:0}}
@media (max-width:560px){.ml-logo{width:150px;height:174px}}
@media (prefers-reduced-motion:reduce){.ml-p{animation:none;opacity:1}}
/* Выбор модификаторов в модалке товара (patch 1.5.29) */
.mod-pick{cursor:pointer}
.mod-pick input{appearance:none;-webkit-appearance:none;flex:none;width:22px;height:22px;margin:0 12px 0 0;border:2px solid var(--vanilla-line,#d8cbad);background:var(--vanilla-2,#f3ebd9);cursor:pointer;position:relative;transition:border-color .15s,background .15s}
.mod-pick input[type=checkbox]{border-radius:6px}
.mod-pick input[type=radio]{border-radius:50%}
.mod-pick input:hover{border-color:var(--accent-ink-soft)}
.mod-pick input:checked{background:var(--burgundy,#4a1620);border-color:var(--accent-ink)}
.mod-pick input[type=checkbox]:checked::after{content:"";position:absolute;left:6px;top:2px;width:6px;height:11px;border:solid var(--vanilla,#ece1cb);border-width:0 2px 2px 0;transform:rotate(45deg)}
.mod-pick input[type=radio]:checked::after{content:"";position:absolute;left:50%;top:50%;width:8px;height:8px;border-radius:50%;background:var(--vanilla,#ece1cb);transform:translate(-50%,-50%)}
.mod-pick .n{flex:1}
.mod-hint{font-family:var(--mono);font-size:9px;font-weight:700;letter-spacing:1px;color:var(--ink-mute,#837b6f);border:1px solid var(--vanilla-line,#d8cbad);border-radius:20px;padding:1px 7px}
.modal-add-wrap{margin-top:20px}
.modal-add-err{color:var(--terracotta,#b0502c);font-family:var(--mono);font-size:12px;margin-bottom:8px}
.modal-add-err:empty{display:none}
.modal-add{width:100%;padding:15px;background:var(--burgundy,#4a1620);color:var(--on-dark);border:0;border-radius:12px;font-family:var(--mono);font-weight:700;font-size:14px;letter-spacing:.5px;text-transform:uppercase;cursor:pointer;transition:filter .15s}
.modal-add:hover{filter:brightness(1.1)}

/* Модалка товара: бейдж категории и круглая кнопка закрытия ПОВЕРХ фото (patch 1.5.48).
   Полосы больше нет — сама шапка прозрачная, подложки только у элементов,
   поэтому снимок виден целиком. Плотность подложек 72%: даже на светлом фото
   контраст текста около 5, при этом фактура снимка сквозь неё читается. */
.modal{ position:relative }
.modal-top{
  /* z-index 4, а не 3: у .sold-out тоже стоял 3, а .modal-media своего стекового
     контекста не создаёт (position:relative без z-index), поэтому при равных
     значениях побеждал тот, кто позже в DOM — оверлей ложился поверх шапки и
     накрывал кнопку закрытия. Шапка с бейджем и крестиком обязана быть выше. */
  position:absolute; top:0; left:0; right:0; z-index:4;
  background:none; -webkit-backdrop-filter:none; backdrop-filter:none;
  border-bottom:0; padding:14px 16px; color:var(--on-dark);
  pointer-events:none;                      /* клики ловят только бейдж и кнопка */
}
.modal-top h2, .modal-x{ pointer-events:auto }
.modal-top h2{
  background:rgba(var(--scrim-rgb),.72);
  -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  color:var(--on-dark); padding:7px 13px; border-radius:999px; text-shadow:none;
}
.modal-x{
  width:34px; height:34px; display:flex; align-items:center; justify-content:center;
  background:rgba(var(--scrim-rgb),.72);
  -webkit-backdrop-filter:blur(6px); backdrop-filter:blur(6px);
  color:var(--on-dark); border-radius:50%; font-size:20px; opacity:1; text-shadow:none;
  transition:background .15s, color .15s;
}
.modal-x:hover{ background:var(--burgundy); color:var(--on-dark) }

/* Фото подрезаем немного СНИЗУ — верх кадра остаётся целым */
.modal-media{ aspect-ratio:5/4; max-height:min(56dvh, 560px) }
.modal-media > img{ object-position:center top }
