/* ============================================================================
   Кафе «Вифания» — visual system
   ----------------------------------------------------------------------------
   THESIS: The Camp Vifania menu poster, on screen. A vermilion field, bone
     plates, everything set in black — hierarchy comes from size, weight and
     tracking, never from a second hue or a soft shadow.
   OWN-WORLD: Vermilion (#FE4836) · bone (#E1D7CB) · black. One family, Inter:
     Black uppercase and tight for every title, regular sentence-case for
     reading. Hard rectangles, hairlines instead of elevation, zero radius.
   STORY: The guest scrolls a photographed menu, taps a drink, tunes size /
     add-ons, and sends the order — cart and status read like a receipt.
   FIRST VIEWPORT: brand bar → the section title huge, black, uppercase on the
     bare red → the first drink as a bone plate with a black «Заказать».
   FORM: photographed single-column menu (mobile-first), widening to a card
     grid; the drink card is the atom repeated across every surface.
   Mode: Operate (guest completes an order) with poster loudness on browse.
   COLOUR RULE: small text on vermilion is black or --ink-soft/--muted only —
     both are AA there (4.9:1 / 4.6:1). No grey exists in this palette.
   ============================================================================ */

:root {
  /* This palette is vermilion-on-bone in every light. Saying so keeps the guest's
     OS dark mode out of the one thing we don't control: Telegram's login iframe
     reads prefers-color-scheme from us and would otherwise paint its canvas
     black, boxing the button on the red header. */
  color-scheme: light;
  /* Surfaces */
  --red:          #fe4836;  /* page ground */
  --bone:         #e1d7cb;  /* plates: cards, panels, bars */
  --bone-sunk:    #d2c6b6;  /* inputs / recessed fields */
  --paper:        #ffffff;  /* photo backing */
  --line:         rgba(0, 0, 0, .22); /* hairlines and dividers */

  /* Ink */
  --ink:          #000000;  /* primary text + primary buttons */
  --ink-soft:     #2a1109;  /* secondary text — AA on red and on bone */
  --muted:        #3a1a12;  /* tertiary / meta — AA on red and on bone */
  --accent:       #000000;  /* eyebrows, links, badges: black, not a hue */
  --danger:       #000000;  /* alarm reads as inversion, not as a colour */

  /* Elevation — a poster has none; the tokens stay so call sites don't churn */
  --shadow-sm: none;
  --shadow-md: none;
  --shadow-lg: none;

  /* Radii */
  --r-card: 0;
  --r-ctrl: 0;
  --r-pill: 0;

  /* Type */
  --font-display: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-body:    "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  --font-mono:    "JetBrains Mono", ui-monospace, monospace;

  --wrap: 960px;
  /* One source of truth: the bar's own height, the body padding that reserves
     it, and the item page's sticky CTA all sit on this. */
  --tabbar-h: 56px;
}

* { box-sizing: border-box; }

html { -webkit-text-size-adjust: 100%; }

body {
  margin: 0;
  background: var(--red);
  color: var(--ink);
  font-family: var(--font-body);
  font-size: 16px;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

img { max-width: 100%; display: block; }

a { color: inherit; text-decoration: none; }

/* ---- Typography helpers ------------------------------------------------- */
/* Every title in the system is the same move: Inter Black, uppercase, tracked
   in rather than out, set solid. Size is the only variable. */
h1, h2, h3 {
  font-family: var(--font-display);
  font-weight: 900;
  line-height: .94;
  letter-spacing: -.02em;
  text-transform: uppercase;
  margin: 0 0 .5rem;
}

.display {                       /* big page title */
  font-family: var(--font-display);
  font-weight: 900;
  font-size: clamp(2.6rem, 11vw, 4.4rem);
  line-height: .88;
  letter-spacing: -.035em;
  text-transform: uppercase;
  margin: 0;
}

.eyebrow {                       /* small tracked uppercase label */
  font-family: var(--font-body);
  font-weight: 700;
  font-size: .72rem;
  letter-spacing: .16em;
  text-transform: uppercase;
  color: var(--accent);
  margin: 0;
}

.muted { color: var(--muted); font-size: .9rem; }

/* One ring for everything. The 3px offset lands it on the red field even when
   the control itself is a black slab, so it never disappears into its own fill. */
:focus-visible { outline: 3px solid var(--ink); outline-offset: 3px; }

/* ---- Icons -------------------------------------------------------------- */
/* Sprite lives inline at the top of <body>; every icon is a <use> of it and
   inherits size from font-size and colour from currentColor. */
.ico-sprite { display: none; }
.ico {
  width: 1em;
  height: 1em;
  flex: none;
  fill: none;
  stroke: currentColor;
  stroke-width: 1.6;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.visually-hidden {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* ---- App shell / header ------------------------------------------------- */
.topbar {
  position: sticky;
  top: 0;
  z-index: 30;
  display: flex;
  flex-wrap: wrap;              /* never let header contents overflow sideways */
  align-items: center;
  gap: 10px 12px;
  padding: 12px clamp(16px, 5vw, 28px);
  background: var(--red);
  border-bottom: 2px solid var(--ink);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: .5ch;
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 1.35rem;
  letter-spacing: -.02em;
  text-transform: uppercase;
  color: var(--ink);
  line-height: 1;
}
.brand .brand-mark {
  width: 32px;
  height: 32px;
  flex: none;
  border-radius: 8px;
  object-fit: cover;
}

.topbar-spacer { flex: 1; }

.topbar-actions { display: flex; align-items: center; gap: 10px; }

/* Account chip + logout in the header */
.account {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.account-name {
  font-weight: 600;
  font-size: .84rem;
  color: var(--ink-soft);
  max-width: 9ch;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.logout-form { margin: 0; }

/* Cart pill button in header */
.cart-link {
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding: 10px 16px;
  border-radius: var(--r-pill);
  background: var(--ink);
  color: var(--bone);
  font-weight: 800;
  font-size: .78rem;
  letter-spacing: .04em;
  text-transform: uppercase;
}
.cart-link .cart-ico { font-size: 1.05rem; }
.cart-badge {
  min-width: 20px;
  height: 20px;
  padding: 0 6px;
  border-radius: var(--r-pill);
  background: var(--accent);
  color: var(--bone);
  font-size: .72rem;
  font-weight: 700;
  line-height: 20px;
  text-align: center;
}

/* On mobile the bottom tab bar already carries the cart (with its badge), so
   the header cart pill is redundant — hiding it keeps the header on one line. */
@media (max-width: 719px) {
  .cart-link { display: none; }
}

/* Text links row (desktop secondary nav) */
.topnav { display: none; gap: 22px; }
.topnav a {
  font-weight: 600;
  font-size: .82rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--ink-soft);
  padding: 6px 0;
  border-bottom: 2px solid transparent;
}
.topnav a:hover { color: var(--ink); border-color: var(--accent); }

@media (min-width: 720px) {
  .topnav { display: inline-flex; }
}

/* Shop-closed banner */
.shop-closed-banner {
  background: var(--ink);
  color: var(--bone);
  text-align: center;
  padding: 10px 16px;
  font-weight: 600;
  font-size: .85rem;
  letter-spacing: .02em;
}

/* ---- Main column -------------------------------------------------------- */
main {
  max-width: var(--wrap);
  margin: 0 auto;
  /* Small bottom padding: the tab bar's reserved strip is the real gap there.
     Restored to 48px at 720px, where the tab bar goes away. */
  padding: clamp(20px, 5vw, 40px) clamp(16px, 5vw, 28px) 24px;
}

.page-head { margin-bottom: 28px; }
.page-head .eyebrow { margin-bottom: 10px; }

/* ---- Buttons ------------------------------------------------------------ */
button, .btn {
  font-family: var(--font-body);
  font-weight: 800;
  font-size: .88rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  line-height: 1.2;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 52px;
  padding: 15px 24px;
  border-radius: var(--r-ctrl);
  border: 2px solid var(--ink);
  background: var(--ink);
  color: var(--bone);
  cursor: pointer;
  transition: background .12s ease, color .12s ease;
}
/* No lift, no glow: the only state change a flat poster has is inversion. */
button:hover, .btn:hover { background: var(--bone); color: var(--ink); }
button:active, .btn:active { background: var(--bone-sunk); color: var(--ink); }

.btn-block { width: 100%; }
.btn-total { font-weight: 600; opacity: .72; }
/* Компактный вариант для шапки: 52px кнопка задирает её. 44px — нижняя
   граница тач-цели, ниже опускаться нельзя. */
.btn-sm {
  min-height: 44px;
  padding: 10px 14px;
  font-size: .78rem;
}

.btn-ghost {
  background: transparent;
  color: var(--ink);
  border-color: var(--ink);
}
.btn-ghost:hover { background: var(--bone-sunk); color: var(--ink); box-shadow: none; }

/* Removing is the destructive move, so it is the one control that goes red —
   red on black, the only place in the system where the field colour is ink. */
.btn-danger {
  background: transparent;
  color: var(--danger);
  border-color: var(--ink);
}
.btn-danger:hover { background: var(--ink); color: var(--red); box-shadow: none; }

.btn-disabled, button:disabled, .btn:disabled {
  background: var(--bone-sunk);
  border-color: var(--bone-sunk);
  color: var(--muted);
  cursor: not-allowed;
  pointer-events: none;
}

/* ---- Forms -------------------------------------------------------------- */
input, select, textarea {
  font-family: var(--font-body);
  font-size: 16px;                    /* keeps iOS from zooming on focus */
  color: var(--ink);
  background: var(--bone);
  border: 2px solid var(--ink);
  border-radius: var(--r-ctrl);
  padding: 13px 15px;
  width: 100%;
}
/* The ring comes from the global :focus-visible rule — a text field matches it
   on click as well, so nothing here may reset `outline`. */
/* Только поля ввода: у чекбокса и радио заливка — это само состояние, и
   сокращённый background сбросил бы им и галочку. */
input:not([type="checkbox"]):not([type="radio"]):focus,
select:focus, textarea:focus { background: var(--bone-sunk); }
textarea { resize: vertical; }

input[type="number"] { width: auto; }

/* Родной чекбокс здесь — белая клякса в сером кольце: ни белого, ни серого в
   палитре нет, и невыбранная строка кричала громче собственной подписи. Рисуем
   сами теми же тремя цветами: костяная плашка в чёрной рамке, выбранное —
   чёрное. Под forced-colors всё возвращается системе (правило ниже). */
input[type="checkbox"], input[type="radio"] {
  appearance: none;
  -webkit-appearance: none;
  width: 22px; height: 22px;
  padding: 0;
  margin: 0;
  flex: none;
  border: 2px solid var(--ink);
  background: var(--bone) center / 14px no-repeat;
  cursor: pointer;
  transition: background-color .12s ease;
}
input[type="radio"] { border-radius: 50%; }
input[type="checkbox"]:checked, input[type="radio"]:checked { background-color: var(--ink); }
/* Точка радио — костяной зазор внутри чёрного круга. */
input[type="radio"]:checked { box-shadow: inset 0 0 0 3px var(--bone); }
input[type="checkbox"]:checked {
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Cpath d='M3 8.4l3.4 3.4L13 4.8' fill='none' stroke='%23e1d7cb' stroke-width='2.6' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}
/* В режиме принудительных цветов свои заливки не значат ничего — отдаём
   контролы системе целиком, иначе выбранное станет неотличимо от пустого. */
@media (forced-colors: active) {
  input[type="checkbox"], input[type="radio"] {
    appearance: auto;
    -webkit-appearance: auto;
  }
}

.field { display: flex; flex-direction: column; gap: 8px; }
.field > span, .field-label {
  font-weight: 700;
  font-size: .72rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
}

/* ---- Generic card ------------------------------------------------------- */
.card {
  background: var(--bone);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  padding: 22px;
  box-shadow: var(--shadow-sm);
}

.notice {
  background: var(--bone);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  padding: 18px 20px;
  box-shadow: var(--shadow-sm);
  margin: 18px 0;
}

/* Empty / centered state */
.empty-state {
  text-align: center;
  padding: 48px 20px;
  color: var(--muted);
}
.empty-state .empty-emoji { display: block; font-size: 2.4rem; margin: 0 auto 12px; opacity: .55; stroke-width: 1.3; }

/* ---- Menu sections + grid ---------------------------------------------- */
.menu-section { margin-bottom: 40px; }
/* The last section's gap would stack on top of main's own bottom padding. */
.menu-section:last-child { margin-bottom: 0; }
.menu-section-head {
  display: flex;
  align-items: baseline;
  gap: 12px;
  margin-bottom: 18px;
}
.menu-section-head h2 {
  font-size: clamp(2.2rem, 9vw, 3rem);
  margin: 0;
}
.menu-section-count {
  font-size: .8rem;
  color: var(--muted);
  font-weight: 600;
}

.menu-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 22px;
}
@media (min-width: 560px) {
  .menu-grid { grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 24px; }
}

/* ---- Drink card (the atom) --------------------------------------------- */
.menu-card {
  display: flex;
  flex-direction: column;
  background: var(--bone);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  overflow: hidden;
  transition: background .16s ease;
}
/* Flat plate, flat response: the card darkens a shade and its CTA inverts.
   Nothing lifts — there is no light source in this system. */
.menu-card:hover, .menu-card:focus-within { background: var(--bone-sunk); }
.menu-card-link { display: flex; flex-direction: column; height: 100%; color: inherit; }

.menu-card-photo {
  position: relative;
  aspect-ratio: 1 / 1;
  background: var(--bone-sunk);
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
}
.menu-card-photo img { width: 100%; height: 100%; object-fit: cover; }
.photo-placeholder { font-size: 3rem; opacity: .35; stroke-width: 1.2; }

.menu-card-body {
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding: 18px 18px 20px;
  flex: 1;
}
.menu-card-name {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 1.5rem;
  line-height: .96;
  letter-spacing: -.025em;
  text-transform: uppercase;
  color: var(--ink);
  margin: 0;
}
.menu-card-cat {
  font-weight: 700;
  font-size: .68rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--accent);
}
.menu-card-desc {
  color: var(--ink-soft);
  font-size: .9rem;
  margin: 2px 0 0;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
}
.menu-card-foot {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  margin-top: auto;         /* pin price+CTA to card bottom so rows align */
  padding-top: 14px;
}
.menu-card-price {
  font-weight: 700;
  font-size: 1.05rem;
  color: var(--ink);
  white-space: nowrap;
}
.menu-card-price .cur { color: var(--muted); font-weight: 600; }

.card-cta {                       /* fake button inside the card link */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 11px 18px;
  border: 2px solid var(--ink);
  border-radius: var(--r-ctrl);
  background: var(--ink);
  color: var(--bone);
  font-weight: 800;
  font-size: .8rem;
  letter-spacing: .04em;
  text-transform: uppercase;
  transition: background .12s ease, color .12s ease;
}
.menu-card-link:hover .card-cta { background: var(--bone); color: var(--ink); }

/* Sold-out treatment */
.soldout-badge {
  position: absolute;
  top: 12px; left: 12px;
  background: var(--ink);
  color: var(--bone);
  font-weight: 700;
  font-size: .68rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  padding: 6px 12px;
  border-radius: var(--r-pill);
}
.menu-card.is-soldout .menu-card-photo img,
.item-hero.is-soldout img { filter: grayscale(1); opacity: .72; }
.menu-card.is-soldout .menu-card-name { color: var(--muted); }
.menu-card.is-soldout .card-cta { background: var(--bone-sunk); color: var(--ink-soft); }

/* ---- Item detail -------------------------------------------------------- */
.item-detail { max-width: 620px; margin: 0 auto; }
.item-hero {
  position: relative;
  aspect-ratio: 1 / 1;
  border-radius: var(--r-card);
  overflow: hidden;
  background: var(--bone-sunk);
  display: flex;
  align-items: center;
  justify-content: center;
  margin-bottom: 22px;
}
.item-hero img { width: 100%; height: 100%; object-fit: cover; }

.item-detail h1 {
  font-size: clamp(2.4rem, 9vw, 3.4rem);
  margin: 0 0 6px;
}
.item-detail .eyebrow { margin-bottom: 12px; }
.item-desc { color: var(--ink-soft); font-size: 1.02rem; margin: 0 0 14px; }
.item-price {
  font-weight: 700;
  font-size: 1.4rem;
  color: var(--ink);
  margin: 0 0 4px;
}
.item-price .cur { color: var(--muted); font-weight: 600; font-size: 1.1rem; }

/* Add-to-cart form */
.item-form {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin: 18px 0 0;
}

.qty-field {
  display: flex;
  align-items: center;
  gap: 14px;
}
.qty-label {
  font-weight: 700;
  font-size: .74rem;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--muted);
}
/* One pill: −, the count, +. The buttons are the touch target — the native
   number spinners are far under 44px and unusable on a phone. */
.qty-stepper {
  margin-left: auto;
  display: flex;
  align-items: center;
  background: var(--bone);
  border: 2px solid var(--ink);
  border-radius: var(--r-pill);
  box-shadow: var(--shadow-sm);
  overflow: hidden;
}
.qty-stepper:has(input:focus-visible) {
  border-color: var(--ink);
}
.qty-step {
  width: 46px;
  min-height: 46px;
  padding: 0;
  border: 0;
  border-radius: 0;
  background: transparent;
  color: var(--ink);
  font-size: 1.3rem;
  font-weight: 400;
}
.qty-step:hover { background: var(--bone-sunk); box-shadow: none; }
.qty-step:disabled { color: rgba(0, 0, 0, .3); background: transparent; cursor: default; }
.qty-step:disabled:active { transform: none; }
.qty-field input[type="number"] {
  width: 44px;
  min-height: 46px;
  padding: 0;
  border: 0;
  border-radius: 0;
  text-align: center;
  font-weight: 700;
  font-size: 1.05rem;
  background: transparent;
  appearance: textfield;
  -moz-appearance: textfield;
}
.qty-field input[type="number"]:focus { box-shadow: none; }
.qty-field input[type="number"]::-webkit-outer-spin-button,
.qty-field input[type="number"]::-webkit-inner-spin-button {
  -webkit-appearance: none;
  margin: 0;
}

/* Option groups (single = radio, multi = checkbox). The plate IS the group: no
   border for the legend to interrupt, and the legend is the plate's own heading,
   ruled off in black. A bordered fieldset put the label half in, half out. */
.option-group {
  border: 0;
  border-radius: var(--r-card);
  padding: 0;
  margin: 0;
  background: var(--bone);
}
.option-group legend {
  /* float, а не display: block: у <legend> своя модель отрисовки, и только
     всплытие делает из него обычный блок во всю ширину плашки. */
  float: left;
  width: 100%;
  padding: 15px 16px 11px;
  margin: 0;
  font-weight: 800;
  font-size: .72rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--ink);
  border-bottom: 2px solid var(--ink);
}
/* Всплывший legend не занимает высоту — без этого первая строка легла бы под него. */
.option-group::after { content: ""; display: table; clear: both; }
/* Строки во всю ширину плашки: разделители доходят до края, а выбранная строка
   заливается целиком, а не висит скруглённой пилюлей посередине. */
.option-choice {
  display: flex;
  align-items: center;
  gap: 14px;
  min-height: 52px;
  padding: 8px 16px;
  margin: 0;
  cursor: pointer;
  border-bottom: 1px solid var(--line);
  font-size: 1rem;
  transition: background .12s ease;
}
.option-group .option-choice:last-child { border-bottom: none; }
/* Without this a picked add-on reads only off its 22px box — the row itself has
   to carry the state so the selection is scannable at a glance. */
.option-choice:has(:checked) { background: var(--bone-sunk); }
.option-choice:has(:checked) .opt-name { font-weight: 700; }
.option-choice .opt-delta {
  margin-left: auto;
  color: var(--accent);
  font-weight: 700;
  font-size: .9rem;
}

/* Add-to-cart bar. On mobile it pins above the tab bar: with six options the
   button otherwise sits below the fold, and it is the only action on the page.
   Positioned so the toast inside it can hang off its top edge. */
.item-cta { position: relative; display: flex; flex-direction: column; gap: 8px; }
/* 150 MDL on screen and 840 MDL on the button is arithmetic the guest cannot
   check — the bar spells it out whenever the two differ. */
.cta-breakdown {
  margin: 0;
  text-align: center;
  font-size: .82rem;
  font-weight: 600;
  color: var(--muted);
  font-variant-numeric: tabular-nums;
}

@media (max-width: 719px) {
  .item-cta {
    position: fixed;
    left: 0; right: 0;
    bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom, 0px));
    z-index: 35;
    gap: 6px;
    padding: 10px clamp(16px, 5vw, 28px) 12px;
    background: var(--red);
    border-top: 2px solid var(--ink);
  }
  .item-cta .btn-block { margin: 0 auto; max-width: 620px; }
  /* The bar is out of flow — keep it from covering the end of the page. Two
     stacked buttons make it ~134px tall; this has to clear that. */
  .item-detail { padding-bottom: 160px; }
}

/* Toast slot: floats off the top edge of the action bar, so it never needs to
   know how tall that bar is and never pushes the button around. Both partials
   land here — the confirmation dismisses itself, the error must not, since it
   is the reason the order did not go through. */
#cart-summary {
  position: absolute;
  bottom: 100%;
  left: 0;
  right: 0;
  padding: 0 clamp(16px, 5vw, 28px) 10px;
  pointer-events: none;
}
#cart-summary p {
  margin: 0 auto;
  width: max-content;
  max-width: 100%;
  pointer-events: auto;
}
.add-ok, .cart-error {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 11px 18px;
  border-radius: var(--r-pill);
  box-shadow: var(--shadow-lg);
  font-size: .88rem;
  font-weight: 600;
}
.add-ok {
  background: var(--ink);
  color: var(--bone);
  animation: toast 4.5s ease-out forwards;
}
.add-ok .ico { font-size: 1.05rem; stroke-width: 2.6; }
.add-ok a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
/* Vermilion on black — the palette's own alarm, and the only inversion of the
   page's own colours anywhere in the system. */
.cart-error { background: var(--ink); color: var(--red); font-weight: 800; }

/* visibility at the end, not just opacity: a faded-out toast must stop taking
   taps meant for the options behind it. */
@keyframes toast {
  0%   { opacity: 0; transform: translateY(10px); }
  7%   { opacity: 1; transform: none; }
  88%  { opacity: 1; transform: none; }
  100% { opacity: 0; transform: translateY(10px); visibility: hidden; }
}
@media (prefers-reduced-motion: reduce) {
  .add-ok { animation-name: toast-still; }
  @keyframes toast-still {
    0%, 88% { opacity: 1; }
    100% { opacity: 0; visibility: hidden; }
  }
}

/* ---- Cart --------------------------------------------------------------- */
.cart { max-width: 620px; margin: 0 auto; }
#cart-lines { margin: 0 0 8px; }

.cart-line {
  display: flex;
  gap: 14px;
  padding: 16px;
  background: var(--bone);
  border: 1px solid var(--line);
  border-radius: var(--r-card);
  box-shadow: var(--shadow-sm);
  margin-bottom: 14px;
}
/* The photo the guest chose from, so a line is recognised before it is read. */
.cart-line-thumb {
  width: 64px;
  height: 64px;
  flex: none;
  object-fit: cover;
  border-radius: var(--r-ctrl);
  background: var(--bone-sunk);
}
.cart-line-thumb.is-empty { padding: 16px; font-size: 32px; color: var(--muted); opacity: .5; }
.cart-line-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.cart-line-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
}
.cart-line-name {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 1.2rem;
  letter-spacing: -.02em;
  text-transform: uppercase;
  color: var(--ink);
}
.cart-line-price { font-weight: 700; white-space: nowrap; text-align: right; }
/* Under the line's own price, where a receipt puts it — in the button row it
   was squeezing the stepper on a phone. */
.cart-line-unit {
  display: block;
  margin-top: 2px;
  font-weight: 500;
  font-size: .78rem;
  color: var(--muted);
}
.cart-line-meta { color: var(--ink-soft); font-size: .9rem; }
.cart-line-meta span { display: block; }
.cart-line-actions {
  display: flex;
  align-items: center;
  gap: 12px;
  margin-top: 4px;
}
.cart-line-actions form { margin: 0; }
/* flex: none — the stepper is a touch target, so it keeps its size and whatever
   else is on the row gives way instead. */
.cart-line .qty-stepper { margin-left: 0; flex: none; }
.cart-line .qty-step { width: 48px; min-height: 44px; font-size: 1.15rem; flex: none; }
.qty-count { min-width: 40px; text-align: center; font-weight: 700; font-size: 1.05rem; }
/* Quiet, and last: removing is the one move on this card that cannot be undone,
   so it does not get to be the loudest thing on it. */
.cart-line-actions .cart-line-remove { margin-left: auto; }
.cart-line .btn-remove {
  width: 40px;
  min-height: 40px;
  padding: 0;
  font-size: 1.05rem;
  background: transparent;
  border-color: transparent;
  color: var(--muted);
}
.cart-line .btn-remove:hover { background: var(--bone-sunk); color: var(--danger); box-shadow: none; }

/* A receipt's subtotal line, not a second dark slab: the espresso weight below
   belongs to the one action on the page. */
.cart-total-bar {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  padding: 4px 4px 12px;
  border-bottom: 1px solid var(--line);
  color: var(--ink);
}
.cart-total-bar .label {
  font-weight: 700;
  font-size: .74rem;
  letter-spacing: .14em;
  text-transform: uppercase;
  color: var(--muted);
}
.cart-total-bar .amount { font-weight: 700; font-size: 1.5rem; }
.cart-total-bar .amount .cur { opacity: .6; font-weight: 600; font-size: 1.1rem; }

.cart-foot { display: flex; flex-direction: column; gap: 14px; margin-top: 20px; }
.empty-state p { margin: 0 0 18px; }

/* Same pattern as the item page: past three or four lines the total and the way
   on are both below the fold, and the guest is scrolling to find them. */
/* Scoped to the cart page on purpose: checkout includes the same fragment, and a
   bar bolted over the bottom of that page covers the form it is standing on. */
@media (max-width: 719px) {
  .cart .cart-foot {
    position: fixed;
    left: 0; right: 0;
    bottom: calc(var(--tabbar-h) + env(safe-area-inset-bottom, 0px));
    z-index: 35;
    gap: 8px;
    margin: 0;
    padding: 10px clamp(16px, 5vw, 28px) 12px;
    background: var(--red);
    border-top: 2px solid var(--ink);
  }
  .cart .cart-foot .btn-block, .cart .cart-foot .cart-total-bar { margin: 0 auto; max-width: 620px; width: 100%; }
  .cart .cart-total-bar { border-bottom: 0; padding: 0 4px; }
  /* The bar is out of flow — keep it off the end of the list. */
  .cart { padding-bottom: 128px; }
}

/* ---- Checkout ----------------------------------------------------------- */
.checkout { max-width: 620px; margin: 0 auto; }
/* Checkout is where «Оформить заказ» leads — on it that button is a link to the
   page you are already on, sitting above the confirm it duplicates. The fragment
   is re-rendered by htmx on every quantity edit, so this has to be CSS. */
.checkout .cart-foot .btn-block { display: none; }
.checkout-form {
  display: flex;
  flex-direction: column;
  gap: 20px;
  margin-top: 24px;
}
.checkout-form .field span { margin-bottom: 2px; }

/* ---- Order confirmation ------------------------------------------------- */
/* These pages carry a sentence and a way on, and nothing else — top-anchored they
   read as a paragraph abandoned above a screen of nothing. */
.order-confirm {
  max-width: 560px;
  min-height: 56vh;
  margin: 0 auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
  text-align: center;
}
.order-confirm .confirm-icon {
  font-size: 3rem;
  display: block;
  margin: 0 auto 12px;
  color: var(--accent);
  stroke-width: 1.2;
  opacity: .85;
}
.order-confirm .error-illustration,
.order-confirm .confirmation-illustration {
  display: block;
  width: clamp(190px, 46vw, 300px);
  height: auto;
  max-height: 32vh;
  margin: 0 auto 18px;
  object-fit: contain;
}
/* The widget is an iframe of Telegram's own making — it can only be centred and
   given room, never restyled. */
.login-action { margin-top: 22px; display: flex; justify-content: center; min-height: 46px; }
.order-confirm .confirm-num { color: var(--accent); }
.order-confirm .confirm-meta { color: var(--ink-soft); }
/* Замыкающая строка с действием — на обеих страницах-итогах. */
.page-actions { margin-top: 26px; }

/* ---- Orders list / order card ------------------------------------------ */
.order-list {
  display: flex;
  flex-direction: column;
  gap: 18px;
  max-width: 640px;
  margin: 0 auto;
}
.order-card { padding: 22px; }
.order-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 14px;
}
.order-num {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 1.4rem;
  letter-spacing: -.02em;
  text-transform: uppercase;
  color: var(--ink);
}
.order-items { list-style: none; margin: 0 0 14px; padding: 0; }
.order-items > li {
  padding: 8px 0;
  border-bottom: 1px solid var(--line);
  font-size: .96rem;
}
.order-items > li:last-child { border-bottom: none; }
.order-items .sub { color: var(--muted); font-size: .85rem; }
.order-note {
  margin: 0 0 14px;
  padding: 12px 14px;
  background: var(--bone-sunk);
  border-radius: var(--r-ctrl);
  color: var(--ink-soft);
  font-size: .92rem;
}
.order-card form { margin: 0; }

/* Status badge (off-path terminal states). No hue tells the state apart here —
   the Russian label does, and the fill says only «finished» (solid) or
   «stopped» (outline). */
.status-badge {
  display: inline-block;
  font-weight: 800;
  font-size: .74rem;
  letter-spacing: .1em;
  text-transform: uppercase;
  padding: 7px 14px;
  border-radius: var(--r-pill);
  background: transparent;
  border: 2px solid var(--ink);
  color: var(--ink);
}
.status-badge.status-done { background: var(--ink); color: var(--bone); }

/* ---- Status stepper ----------------------------------------------------- */
.stepper {
  list-style: none;
  display: flex;
  gap: 6px;
  margin: 0 0 16px;
  padding: 0;
}
.stepper .step {
  flex: 1;
  position: relative;
  padding-top: 22px;
  font-weight: 700;
  font-size: .68rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  text-align: center;
  color: var(--muted);
}
.stepper .step::before {
  content: "";
  position: absolute;
  top: 4px; left: 50%;
  transform: translateX(-50%);
  width: 13px; height: 13px;
  border-radius: 50%;
  background: var(--line);
  z-index: 1;
}
.stepper .step:not(:first-child)::after {
  content: "";
  position: absolute;
  top: 10px; right: 50%;
  width: 100%; height: 2px;
  background: var(--line);
}
.stepper .step-done, .stepper .step-current { color: var(--ink); }
.stepper .step-done::before, .stepper .step-current::before { background: var(--accent); }
.stepper .step-done:not(:first-child)::after { background: var(--accent); }
.stepper .step-current::before { box-shadow: 0 0 0 4px rgba(0, 0, 0, .22); }

/* ---- Staff queue -------------------------------------------------------- */
.staff-operations {
  --red: #000000;
  --bone: #141414;
  --bone-sunk: #1b1b1b;
  --line: rgba(225, 215, 203, .18);
  --ink: #e1d7cb;
  --ink-soft: #cdc2b4;
  --muted: #b3a99c;
  --accent: #fe4836;
  --danger: #fe4836;
  padding-bottom: 0;
  background: var(--red);
  color: var(--ink);
}
.staff-topbar {
  gap: 12px 18px;
  background: var(--bone);
  border-color: var(--line);
}
.staff-topbar .brand { color: var(--accent); }
.staff-brand-role {
  padding-left: .75rem;
  border-left: 1px solid var(--line);
  color: var(--muted);
  font-size: .68rem;
  font-weight: 700;
  letter-spacing: .12em;
}
.staff-topnav {
  display: inline-flex;
  align-items: center;
  gap: 18px;
}
.staff-topnav a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--ink-soft);
  font-size: .78rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.staff-topnav a:hover { color: var(--accent); }
.staff-account {
  max-width: 14ch;
  overflow: hidden;
  color: var(--muted);
  font-size: .8rem;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.staff-topbar .btn-ghost {
  border-color: var(--line);
  color: var(--ink-soft);
}
.staff-topbar .btn-ghost:hover {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--bone);
}
.staff-operations main { padding-bottom: 48px; }
.staff-operations .page-head { max-width: 640px; margin-right: auto; margin-left: auto; }
.staff-operations .eyebrow { color: var(--accent); }
.staff-queue-feedback { margin: 0; }
.staff-queue-feedback:empty { display: none; }
.staff-queue-feedback.notice--warning,
.staff-queue-feedback.notice--error { border-color: var(--accent); }
.staff-operations .card {
  position: relative;
  border-color: var(--line);
  background: var(--bone);
  color: var(--ink);
}
.staff-operations .order-card--arrived::before {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 5px;
  background: var(--accent);
  pointer-events: none;
  animation: staff-order-arrived 2.4s ease-out both;
}
@keyframes staff-order-arrived {
  0%, 55% { opacity: 1; }
  100% { opacity: 0; }
}
.staff-operations .order-num,
.staff-operations .status-badge { color: var(--ink); }
.staff-operations .status-badge { border-color: var(--ink); }
.order-card-links {
  display: flex;
  justify-content: flex-end;
  margin: -4px 0 6px;
}
.order-detail-link {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: var(--ink-soft);
  font-size: .75rem;
  font-weight: 700;
  letter-spacing: .06em;
  text-transform: uppercase;
}
.order-detail-link:hover { color: var(--accent); }
.staff-operations .status-actions button {
  border-color: var(--accent);
  background: var(--accent);
  color: #000000;
}
.staff-operations .status-actions button:disabled {
  opacity: .6;
  cursor: wait;
}
.staff-operations .status-actions button:hover {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--bone);
}
.staff-operations .status-actions .btn-secondary {
  border-color: var(--line);
  background: var(--bone-sunk);
  color: var(--ink);
}
.staff-operations .status-actions .btn-secondary:hover {
  border-color: var(--ink);
  background: var(--ink);
  color: var(--bone);
}
.staff-operations .status-actions .btn-danger {
  border-color: var(--accent);
  background: transparent;
  color: var(--accent);
}
.staff-operations .status-actions .btn-danger:hover {
  background: var(--accent);
  color: #000000;
}
.staff-operations .empty-state { border-color: var(--line); background: var(--bone); }

.status-actions {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
  margin-top: 16px;
}
.status-actions form { margin: 0; }
.status-actions button { width: 100%; min-height: 48px; padding: 12px 14px; font-size: .82rem; }
.status-actions .act-ready,
.status-actions .act-cancel { grid-column: 1 / -1; }
.status-actions .btn-secondary {
  background: var(--bone);
  color: var(--ink);
  border-color: var(--line);
}
.status-actions .btn-secondary:hover { background: var(--bone-sunk); box-shadow: none; }

@media (max-width: 719px) {
  .staff-topbar { align-items: center; padding: 10px 16px; }
  .staff-topbar .brand { flex: 1 0 auto; }
  .staff-topnav {
    order: 3;
    width: 100%;
    gap: 0;
    border-top: 1px solid var(--line);
  }
  .staff-topnav a {
    flex: 1;
    justify-content: center;
    padding: 4px;
    font-size: .7rem;
    text-align: center;
  }
  .staff-topbar .topbar-spacer { display: none; }
  .staff-account { margin-left: auto; }
  .staff-operations main { padding-bottom: 32px; }
}

@media (prefers-reduced-motion: reduce) {
  .staff-operations .order-card--arrived::before {
    animation: none;
    opacity: 0;
  }
}

/* ---- Bottom tab bar (mobile) ------------------------------------------- */
.tabbar {
  position: fixed;
  left: 0; right: 0; bottom: 0;
  z-index: 40;
  display: flex;
  background: var(--red);
  border-top: 2px solid var(--ink);
  padding-bottom: env(safe-area-inset-bottom, 0px);
}
.tabbar a {
  position: relative;
  flex: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 3px;
  padding: 9px 4px;
  min-height: var(--tabbar-h);
  justify-content: center;
  font-weight: 700;
  font-size: .66rem;
  letter-spacing: .06em;
  text-transform: uppercase;
  color: var(--muted);
}
/* Without a second hue, «where am I» has to be carried by the fill: the current
   tab is the inverted one. A colour shift alone is invisible here — every label
   in this palette is already black. */
.tabbar a.is-active { background: var(--ink); color: var(--bone); }
.tabbar a:active { background: var(--bone-sunk); color: var(--ink); }
.tabbar-icon { font-size: 1.4rem; }
.tabbar-badge {
  position: absolute;
  top: 5px; left: 50%;
  margin-left: 7px;
  min-width: 18px; height: 18px;
  padding: 0 5px;
  border-radius: var(--r-pill);
  background: var(--accent);
  color: var(--bone);
  font-size: .68rem;
  font-weight: 700;
  line-height: 18px;
  text-align: center;
}
/* Black on the inverted tab would be black on black. */
.tabbar a.is-active .tabbar-badge { background: var(--bone); color: var(--ink); }

body { padding-bottom: calc(var(--tabbar-h) + 12px + env(safe-area-inset-bottom, 0px)); }

@media (min-width: 720px) {
  .tabbar { display: none; }
  body { padding-bottom: 0; }
  main { padding-bottom: 48px; }
}
