/*
 * Корзина и знакомство за столом.
 *
 * Отдельный файл, а не хвост app.css: корзину можно выключить из настроек,
 * и тогда ни стилей, ни скрипта на странице нет вовсе. Палитра и шрифты
 * берутся из app.css - здесь только то, чего там нет.
 */

/* ------------------------------------------------------ кнопка у блюда */
/*
 * Кнопка сидит в строке цены и подхватывает её выравнивание. Отдельной
 * строкой под карточкой она бы растянула все карточки в сетке на высоту
 * самой длинной.
 *
 * Кольцо, а не диск.
 *
 * Сплошной оранжевый круг был тяжелее всего, что вокруг: в сетке из
 * тридцати карточек тридцать заливок тянут взгляд сильнее самих блюд, а
 * цена рядом рядом с ними теряется. К тому же оранжевый в брендбуке
 * (стр. 6) отдан знаку и активному состоянию - у кнопки заказа этой роли
 * нет, и повторять её тут значит обесценивать.
 *
 * Осталась оливковая волосяная линия и тонкий плюс. Заливка приходит
 * только при наведении и нажатии - Grey Olive с кремовым силуэтом, та же
 * пара, что у плавающей кнопки корзины (брендбук, стр. 9). Мелкая кнопка
 * и крупная теперь читаются как одно семейство, а не как два разных
 * элемента.
 */
.addbtn {
    flex: none;
    position: relative;
    display: grid;
    place-items: center;
    width: 1.9rem;
    height: 1.9rem;
    margin-left: auto;
    padding: 0;
    color: color-mix(in srgb, var(--ink) 80%, transparent);
    background: transparent;
    border: 1px solid color-mix(in srgb, var(--ink) 38%, transparent);
    border-radius: 50%;
    cursor: pointer;
    transition: color .18s var(--ease), background .18s var(--ease),
                border-color .18s var(--ease), transform .15s var(--ease);
}

/* Палец шире кольца: 30 пикселей мимо промахиваются. Область нажатия
   растёт до сорока шести, сама кнопка остаётся мелкой. Расширение уходит
   в зазор сетки и на соседнюю карточку не заходит. */
.addbtn::after {
    content: '';
    position: absolute;
    inset: -.5rem;
    border-radius: 50%;
}

/* Тоньше линия - меньше веса. Атрибут stroke-width в разметке
   перекрывается отсюда: у CSS приоритет выше. */
.addbtn svg { width: 16px; height: 16px; stroke-width: 1.5; }

.addbtn:hover,
.addbtn:focus-visible {
    color: var(--cream);
    background: var(--ink);
    border-color: var(--ink);
}
.addbtn:active { transform: scale(.9); }

/* В строчных разделах - бар, вино - та же кнопка чуть мельче: строка
   ниже карточки, и кольцо в 1.9rem её распирало. Цвета не переопределяем,
   они уже оливковые. */
.addbtn--row {
    align-self: center;
    width: 1.6rem;
    height: 1.6rem;
    margin-left: .55rem;
}

/*
 * Отклик на нажатие: на телефоне без него непонятно, засчиталось ли.
 *
 * Заливку показывает именно эта анимация, а не :hover - на телефоне
 * наведения нет вовсе, и без вспышки кольцо на нажатие никак не отвечало
 * бы. К концу заливка гаснет сама: свойства, которых нет в последнем
 * кадре, браузер доводит до собственного значения кнопки.
 */
.addbtn.is-hit { animation: hit .32s var(--ease); }
@keyframes hit {
    0% {
        transform: scale(1);
        color: var(--cream);
        background: var(--ink);
        border-color: var(--ink);
    }
    45% {
        transform: scale(.82);
        color: var(--cream);
        background: var(--ink);
        border-color: var(--ink);
    }
    100% { transform: scale(1); }
}

/* ------------------------------------------ две цены: выбор на «+» */
/*
 * Плашки «Бокал 2 800» и «Бутылка 13 000» раскрываются на месте цены
 * по нажатию на «+» и той же семьи, что он: оливковое кольцо, заливка
 * при наведении. Число внутри - дисплейным шрифтом и золотом, как сама
 * цена, чтобы глаз не терял её при раскрытии.
 */
.choose {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: .35rem;
    animation: rise .18s var(--ease) both;
}
.choose__b {
    display: inline-flex;
    align-items: baseline;
    gap: .35rem;
    padding: .26rem .65rem;
    font: inherit;
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .06em;
    text-transform: uppercase;
    color: var(--ink);
    background: none;
    border: 1px solid color-mix(in srgb, var(--ink) 38%, transparent);
    border-radius: 999px;
    cursor: pointer;
    transition: color .16s var(--ease), background .16s var(--ease), border-color .16s var(--ease);
}
.choose__b b {
    font-family: var(--display);
    font-size: .95rem;
    font-weight: 700;
    color: var(--gold-ink);
    font-variant-numeric: tabular-nums;
}
.choose__b:hover,
.choose__b:focus-visible {
    color: var(--cream);
    background: var(--ink);
    border-color: var(--ink);
}
.choose__b:hover b,
.choose__b:focus-visible b { color: var(--cream); }

/* Пока выбирают, цену и отточие прячем: их место заняли плашки. */
.is-choosing .price,
.is-choosing .row__price,
.is-choosing .row__leader { display: none; }

/* «+» становится крестиком отмены: тот же знак, повёрнутый на 45°. */
.addbtn svg { transition: transform .18s var(--ease); }
.addbtn.is-open svg { transform: rotate(45deg); }

/* --------------------------------------------------- плавающая кнопка */
/*
 * Кнопка зелёная, силуэт кремовый - пара Grey Olive и Light Ivory из
 * брендбука (стр. 9, тёмная плашка знака). Раньше силуэт был цвета фона
 * страницы: на глаз почти то же самое, но это бумага, а не фирменный
 * кремовый, и рядом с оранжевой кнопкой «наверх» разница была видна.
 */
.cartbtn {
    position: fixed;
    right: clamp(1rem, 3vw, 2rem);
    bottom: calc(clamp(1rem, 3vw, 2rem) + 3.6rem);
    z-index: 36;
    display: flex;
    align-items: center;
    gap: .45rem;
    height: 2.9rem;
    padding: 0 .95rem 0 .8rem;
    color: var(--cream);
    background: var(--ink);
    border: 0;
    border-radius: 999px;
    cursor: pointer;
    box-shadow: 0 6px 20px color-mix(in srgb, var(--ink) 45%, transparent);
    transition: background .18s var(--ease);
}
.cartbtn:hover { background: color-mix(in srgb, var(--ink) 82%, var(--gold)); }
.cartbtn svg { width: 19px; height: 19px; }
.cartbtn__n {
    min-width: 1.15rem;
    font-family: var(--display);
    font-size: .92rem;
    font-weight: 700;
    font-variant-numeric: tabular-nums;
    text-align: center;
}
/* Пустую корзину прячем не совсем: гость должен знать, что она есть. */
.cartbtn.is-empty { opacity: .45; }
.cartbtn.is-empty:hover { opacity: 1; }

/* ------------------------------------------------- хозяин заведения */
/*
 * Пока предмет летит, из-за корзины поднимается человек в цилиндре с
 * подносом, открывает крышку, ловит прилетевшее на блюдо, закрывает и
 * уходит вниз.
 *
 * Стоит на слой ниже кнопки (35 против 36), поэтому появляется из-за неё
 * и туда же прячется. Ниже пояса ничего не нарисовано: эту часть всё
 * равно закрывает кнопка.
 *
 * Место считает JS из настоящих размеров кнопки, причём выравнивает по
 * голове, а не по краю рисунка: поднос вынесен далеко влево, и по общей
 * ширине фигура встала бы боком. Кнопка к тому же пилюля, её ширина
 * растёт со счётчиком - зашитые координаты увели бы его после девятого
 * блюда.
 *
 * pointer-events выключены: он проходит поверх страницы и не должен
 * перехватывать нажатия по блюдам под собой.
 */
.oste {
    position: fixed;
    left: 0;
    top: 0;
    z-index: 35;
    width: 6.2rem;
    opacity: 0;
    pointer-events: none;
}
.oste svg { display: block; width: 100%; height: auto; overflow: visible; }
.oste__skin { fill: var(--cream); }
.oste__shirt { fill: var(--ground); }
.oste__coat { fill: var(--accent); }
.oste__sleeve { stroke: var(--accent); fill: none; }
/* Цилиндр, усы и бабочка почти чёрные, но с оливковой примесью: чистый
   чёрный в брендбуке не встречается ни разу. */
.oste__dark { fill: color-mix(in srgb, var(--ink) 78%, #000); }
/* Поднос латунный, а не серебряный: серого в палитре нет вовсе, а
   Pearl Gold читается как металл и остаётся фирменным. Купол светлее
   подноса - иначе крышка сливается с блюдом в одно пятно. */
.oste__tray { fill: var(--gold); }
.oste__dome { fill: color-mix(in srgb, var(--gold) 45%, var(--cream)); }
/* Дно блюда тёмное: открытая крышка должна что-то показывать. */
.oste__well { fill: color-mix(in srgb, var(--ink) 62%, #000); }

.oste.is-up { animation: oste-peek 1.15s var(--ease); }
.oste.is-up .oste__lid {
    transform-box: view-box;
    /* Вращение от края блюда - крышку так и приподнимают, с одной
       стороны, а не отрывают вверх целиком. */
    transform-origin: 34px 31px;
    animation: oste-lid 1.15s var(--ease);
}

/*
 * Доли кадров подобраны под полёт: предмет летит 800 мс, вся сцена идёт
 * 1150. Крышка открыта с 30-й по 70-ю долю, то есть с 345-й по 805-ю
 * миллисекунду - предмет попадает на блюдо в 800-ю.
 */
@keyframes oste-peek {
    0% { transform: translateY(82%); opacity: 0; }
    14% { transform: translateY(0); opacity: 1; }
    82% { transform: translateY(0); opacity: 1; }
    100% { transform: translateY(86%); opacity: 0; }
}
@keyframes oste-lid {
    0%, 14% { transform: none; }
    30%, 70% { transform: translate(-1px, -15px) rotate(-11deg); }
    82%, 100% { transform: none; }
}

.is-bumped { animation: bump .3s var(--ease); }
@keyframes bump {
    0% { transform: scale(1); }
    40% { transform: scale(1.32); }
    100% { transform: scale(1); }
}

/* ------------------------------------------------------------- панель */
.cart {
    position: fixed;
    inset: 0;
    z-index: 60;
    display: flex;
    justify-content: flex-end;
}
.cart__veil {
    position: absolute;
    inset: 0;
    background: color-mix(in srgb, var(--ink) 55%, transparent);
    backdrop-filter: blur(2px);
    animation: fadein .2s var(--ease);
}
@keyframes fadein { from { opacity: 0; } to { opacity: 1; } }

.cart__sheet {
    position: relative;
    display: flex;
    flex-direction: column;
    width: min(26rem, 100%);
    max-height: 100%;
    background: var(--ground);
    border-left: 1px solid var(--hair);
    box-shadow: -12px 0 40px color-mix(in srgb, var(--ink) 25%, transparent);
    animation: slidein .24s var(--ease);
}
@keyframes slidein {
    from { transform: translateX(100%); }
    to { transform: none; }
}

.cart__head {
    display: flex;
    align-items: flex-start;
    justify-content: space-between;
    gap: 1rem;
    padding: 1.2rem var(--edge) .9rem;
    border-bottom: 1px solid var(--hair);
}
.cart__title {
    font-family: var(--display);
    font-size: 1.35rem;
    font-weight: 700;
    color: var(--accent);
}
.cart__where {
    margin-top: .15rem;
    font-size: .72rem;
    font-weight: 600;
    letter-spacing: .14em;
    text-transform: uppercase;
    color: var(--ink-faint);
}
.cart__x {
    flex: none;
    display: grid;
    place-items: center;
    width: 2.1rem;
    height: 2.1rem;
    padding: 0;
    color: var(--ink-dim);
    background: none;
    border: 1px solid var(--hair);
    border-radius: 50%;
    cursor: pointer;
}
.cart__x svg { width: 15px; height: 15px; }
.cart__x:hover { color: var(--ink); border-color: var(--ink-faint); }

/* Кто за столом. Показываем только когда соседей действительно больше
   одного - строка «вы» в одиночку ничего не сообщает. */
.cart__people {
    display: flex;
    flex-wrap: wrap;
    gap: .35rem;
    padding: .8rem var(--edge) 0;
}
.who {
    padding: .2rem .55rem;
    font-size: .68rem;
    font-weight: 600;
    letter-spacing: .06em;
    color: var(--gold-ink);
    background: color-mix(in srgb, var(--gold) 16%, transparent);
    border-radius: 999px;
}
.who--me { color: var(--ground); background: var(--accent); }

.cart__list {
    flex: 1;
    overflow-y: auto;
    padding: .4rem var(--edge) 1rem;
}

.crow {
    display: flex;
    align-items: center;
    gap: .8rem;
    padding: .7rem 0;
    border-bottom: 1px solid color-mix(in srgb, var(--ink) 10%, transparent);
}
.crow.is-going {
    opacity: 0;
    transform: translateX(1rem);
    transition: opacity .2s var(--ease), transform .2s var(--ease);
}

/*
 * Крестик перед блюдом: убрать позицию целиком.
 *
 * Та же семья, что кнопка «+» у блюда и степпер: оливковое волосяное
 * кольцо, заливка только при наведении и нажатии. Мельче степпера - это
 * не главное действие строки, а запасной выход. Область нажатия шире
 * кольца на .35rem с каждой стороны: 22 пикселя пальцем не попасть.
 */
.crow__x {
    flex: none;
    position: relative;
    display: grid;
    place-items: center;
    width: 1.4rem;
    height: 1.4rem;
    padding: 0;
    color: color-mix(in srgb, var(--ink) 62%, transparent);
    background: none;
    border: 1px solid color-mix(in srgb, var(--ink) 28%, transparent);
    border-radius: 50%;
    cursor: pointer;
    transition: color .16s var(--ease), background .16s var(--ease), border-color .16s var(--ease);
}
.crow__x::after {
    content: '';
    position: absolute;
    inset: -.35rem;
    border-radius: 50%;
}
.crow__x svg { width: 11px; height: 11px; }
.crow__x:hover,
.crow__x:focus-visible {
    color: var(--cream);
    background: var(--accent);
    border-color: var(--accent);
}
/* Чужая строка за столом: кнопки нет, слот остаётся - названия в
   столбик. */
.crow__x--off { visibility: hidden; }

.crow__main { flex: 1; min-width: 0; }
.crow__name {
    display: block;
    font-family: var(--display);
    font-size: .98rem;
    font-weight: 600;
    line-height: 1.25;
}
.crow__who {
    display: block;
    margin-top: .1rem;
    font-size: .7rem;
    color: var(--ink-faint);
}
.crow--mine .crow__who { color: var(--accent); }

.crow__right {
    flex: none;
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: .35rem;
}
.crow__sum {
    font-family: var(--display);
    font-size: .92rem;
    font-weight: 600;
    color: var(--gold-ink);
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
}

.qty {
    display: flex;
    align-items: center;
    gap: .1rem;
    border: 1px solid var(--hair);
    border-radius: 999px;
}
.qty__b {
    width: 1.7rem;
    height: 1.7rem;
    padding: 0;
    font: inherit;
    font-size: 1rem;
    line-height: 1;
    color: var(--ink-dim);
    background: none;
    border: 0;
    border-radius: 50%;
    cursor: pointer;
}
.qty__b:hover { color: var(--ground); background: var(--accent); }
.qty__n {
    min-width: 1.35rem;
    font-size: .88rem;
    font-weight: 700;
    text-align: center;
    font-variant-numeric: tabular-nums;
}
/* Чужую строку не редактируют - показываем это, а не прячем кнопки:
   исчезнувший элемент управления читается как поломка. */
.qty--locked { opacity: .4; }
.qty--locked .qty__b { cursor: default; }
.qty--locked .qty__b:hover { color: var(--ink-dim); background: none; }

.cart__empty {
    padding: 2.5rem var(--edge);
    text-align: center;
    font-size: .9rem;
    color: var(--ink-dim);
}

.cart__foot {
    padding: 1rem var(--edge) 1.3rem;
    border-top: 2px solid var(--ink);
    background: var(--paper);
}
.cart__sum {
    display: flex;
    align-items: baseline;
    justify-content: space-between;
    gap: 1rem;
    font-size: .74rem;
    font-weight: 600;
    letter-spacing: .16em;
    text-transform: uppercase;
    color: var(--ink-faint);
}
.cart__sum strong {
    font-family: var(--display);
    font-size: 1.5rem;
    font-weight: 700;
    letter-spacing: 0;
    text-transform: none;
    color: var(--accent);
    font-variant-numeric: tabular-nums;
}
.cart__note {
    margin-top: .5rem;
    font-size: .74rem;
    line-height: 1.4;
    color: var(--ink-faint);
}

body.cart-open { overflow: hidden; }

/* -------------------------------------------------------- знакомство */
.hello {
    position: fixed;
    inset: 0;
    z-index: 70;
    display: grid;
    place-items: center;
    padding: var(--edge);
}
.hello__card {
    position: relative;
    width: min(23rem, 100%);
    padding: 1.6rem;
    background: var(--ground);
    border: 1px solid var(--hair);
    border-radius: 4px;
    box-shadow: 0 20px 60px color-mix(in srgb, var(--ink) 35%, transparent);
    animation: rise .3s var(--ease) both;
}
.hello__title {
    font-family: var(--display);
    font-size: 1.3rem;
    font-weight: 700;
    color: var(--accent);
}
.hello__note {
    margin-top: .5rem;
    font-size: .86rem;
    line-height: 1.45;
    color: var(--ink-dim);
}
.hello__input {
    width: 100%;
    margin-top: 1rem;
    padding: .7rem .9rem;
    font: inherit;
    font-size: 1rem;
    color: var(--ink);
    background: var(--paper);
    border: 1px solid var(--hair);
    border-radius: 3px;
    outline: none;
}
.hello__input:focus { border-color: var(--accent); }
.hello__actions {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 1rem;
    margin-top: 1rem;
}
.hello__skip {
    padding: .5rem 0;
    font: inherit;
    font-size: .84rem;
    color: var(--ink-faint);
    background: none;
    border: 0;
    cursor: pointer;
}
.hello__skip:hover { color: var(--ink); }
.hello__go {
    padding: .6rem 1.3rem;
    font: inherit;
    font-size: .88rem;
    font-weight: 700;
    color: var(--ground);
    background: var(--accent);
    border: 0;
    border-radius: 999px;
    cursor: pointer;
}
.hello__go:hover { background: var(--ink); }

@media (max-width: 40rem) {
    .cart__sheet { width: 100%; }
    .cartbtn { bottom: calc(clamp(1rem, 3vw, 2rem) + 3.6rem); }
}

@media print {
    .addbtn, .cartbtn, .cart, .hello, .oste { display: none; }
}

/* ------------------------------------------------- миниатюра в корзине */
/*
 * Снимок появляется только у позиций, где он есть. В баре и вине фото нет
 * вовсе - это две трети меню, и пустые рамки выстроили бы колонку серых
 * квадратов. Строка без миниатюры просто начинается с названия.
 */
.crow__pic {
    flex: none;
    width: 3rem;
    height: 3rem;
    object-fit: cover;
    border-radius: 3px;
    background: var(--paper);
}

/* ------------------------------------------------- полёт в корзину */
/*
 * Дугу рисуют две наложенные дорожки: внешний слой едет по горизонтали
 * ровно, внутренний по вертикали - сначала вверх, потом вниз. Сумма даёт
 * бросок. Ведёт это композитор, поэтому анимация доигрывает и тогда,
 * когда основному потоку не до неё.
 *
 * Скриптом по кадрам не считаем сознательно: requestAnimationFrame не
 * вызывается, пока страница не отрисовывается, и первая версия просто
 * висела неподвижной точкой. В этом проекте на том же уже обжигались с
 * подсветкой навигации.
 */
.flyer {
    position: fixed;
    left: 0;
    top: 0;
    z-index: 90;
    pointer-events: none;
    will-change: transform;
    animation: fly-x .8s cubic-bezier(.45, 0, .55, 1) forwards;
}

.flyer__i {
    will-change: transform, opacity;
    /* Сдвиг на половину себя: координаты считаются по центру предмета,
       иначе слово уезжает вправо тем сильнее, чем оно длиннее. */
    margin-left: -50%;
    animation: fly-y .8s cubic-bezier(.35, .1, .5, 1) forwards;
}

@keyframes fly-x {
    to { transform: translateX(var(--dx)); }
}

@keyframes fly-y {
    0% {
        transform: translateY(0) scale(1) rotate(0deg);
        opacity: 1;
    }
    38% {
        transform: translateY(calc(var(--dy) * .2 - var(--lift))) scale(1.45) rotate(calc(var(--spin) * .4));
        opacity: 1;
    }
    74% { opacity: 1; }
    100% {
        transform: translateY(var(--dy)) scale(.38) rotate(var(--spin));
        opacity: 0;
    }
}

/*
 * Шариков в наборе нет: летят только знаки и слова. Безымянный кружок
 * ничего не сообщал, а у ресторана есть что показать.
 */

/* Слово набрано дисплейным шрифтом - тем же, что заголовки. */
.flyer--word {
    font-family: var(--display);
    font-size: 1rem;
    font-weight: 700;
    white-space: nowrap;
    text-shadow: 0 2px 12px color-mix(in srgb, var(--ground) 85%, transparent);
}

/* Подпись знака - разрядкой и золотом, как на самом знаке. */
.flyer--tag {
    font-family: var(--display);
    font-size: .62rem;
    font-weight: 700;
    letter-spacing: .18em;
    white-space: nowrap;
    color: var(--gold);
    text-shadow: 0 2px 12px color-mix(in srgb, var(--ground) 85%, transparent);
}

/* Знаки берутся в том же размере, в каком стоят в шапке. */
.flyer--mark img { display: block; width: 96px; height: auto; }
.flyer--mono img { display: block; width: 20px; height: auto; }
.flyer--badge img { display: block; width: 42px; height: auto; }

/* Кнопка ловит предмет - короткое сжатие, а не подпрыгивание: корзина
   стоит на месте, дёргаться ей незачем. */
.cartbtn.is-caught { animation: caught .28s var(--ease); }
@keyframes caught {
    0% { transform: scale(1); }
    40% { transform: scale(.88); }
    100% { transform: scale(1); }
}

@media (prefers-reduced-motion: reduce) {
    .flyer { display: none; }
}

/* --------------------------------------------- итог: сумма и обслуживание */
/* Промежуточные строки тише самого итога, а он отделён волосяной
   линией: глаз ищет одну цифру, и она должна быть одна. */
.cart__sum--sub {
    margin-bottom: .3rem;
    font-weight: 500;
    letter-spacing: .1em;
    color: var(--ink-faint);
}
.cart__sum--sub span:last-child { font-variant-numeric: tabular-nums; }
.cart__sum--sub + .cart__sum:not(.cart__sum--sub) {
    margin-top: .45rem;
    padding-top: .55rem;
    border-top: 1px solid var(--hair);
}
