/* Uses Telegram's theme CSS variables so the app matches the user's Telegram theme automatically. */
:root {
  --bg: var(--tg-theme-bg-color, #ffffff);
  --text: var(--tg-theme-text-color, #111111);
  --hint: var(--tg-theme-hint-color, #999999);
  --link: var(--tg-theme-link-color, #2481cc);
  --button: var(--tg-theme-button-color, #2481cc);
  --button-text: var(--tg-theme-button-text-color, #ffffff);
  --secondary-bg: var(--tg-theme-secondary-bg-color, #f2f2f7);
  /* Height reserved for the fixed tab bar. Used by the body padding and by any
     bottom-pinned action bar, so the two can never disagree.
     The inset matters: the tab bar pads itself by env(safe-area-inset-bottom) (see
     .tabbar), so on a device with a home indicator it is taller than its 82px base.
     Reserving only the base clipped whatever sat at the end of the page - which is
     how the cart's Total block ended up cut off. */
  --tabbar-base-h: 82px;
  --tabbar-h: calc(var(--tabbar-base-h) + env(safe-area-inset-bottom, 0px));
}

* { box-sizing: border-box; }
/* Nothing may scroll the page sideways. Any row that is too wide for the screen
   (the admin tab bar, the category chips) has to scroll inside its own box instead -
   otherwise the whole layout slides left/right and the fixed chrome detaches.

   The clamp lives on <html> ONLY, deliberately. Putting overflow-x on <body> too
   turns body into a scroll container, and then position:sticky resolves its `bottom`
   against body's padding box - which already excludes the tab-bar strip via
   padding-bottom. The tab bar got counted twice, so .pdp-actionbar floated ~82px too
   high and sat on top of the content above it (this is what clipped the cart's Total
   block, and what reduced the checkout total to a thin blue sliver). */
html {
  max-width: 100vw;
  overflow-x: hidden;
}
body { max-width: 100vw; }
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
  background: var(--secondary-bg);
  color: var(--text);
  padding-bottom: var(--tabbar-h); /* room for the larger tab bar */
}

.topbar {
  position: sticky; top: 0; z-index: 10;
  background: var(--bg);
  padding: 10px 12px;
  display: flex; flex-direction: column; gap: 8px;
  border-bottom: 1px solid rgba(0,0,0,0.06);
}
/* Store wordmark: letter-spaced caps read as a logotype without needing an image. */
.brand {
  font-weight: 700; font-size: 16px;
  letter-spacing: 0.08em; text-transform: uppercase;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

/* Collapsible wrapper: only shown on the catalog tab (toggled from app.js).
   Animating max-height/opacity gives a smooth appear/disappear instead of a hard cut. */
.search-bar-wrap {
  overflow: hidden;
  max-height: 44px;
  opacity: 1;
  transition: max-height 0.22s ease, opacity 0.18s ease, margin-top 0.22s ease;
}
.search-bar-wrap.collapsed {
  max-height: 0;
  opacity: 0;
  margin-top: -8px; /* cancels the header's gap so it collapses flush */
  pointer-events: none;
}
.search-input {
  width: 100%; padding: 10px 12px; border-radius: 10px; border: none;
  background: var(--secondary-bg); color: var(--text); font-size: 15px;
}

/* The extra bottom padding gives the last card in any view a little air above the
   tab bar instead of ending flush against it. */
.view { padding: 12px 12px 16px; }

/* ---------- Icons ---------- */
/* All interface icons are inline SVG (see icons.js). They size with the surrounding
   text and inherit its colour, so no per-context overrides are needed. */
.icon {
  width: 1.15em; height: 1.15em;
  display: inline-block; vertical-align: -0.2em; flex-shrink: 0;
}
/* Larger, muted icon for empty states. */
.empty-icon { width: 40px; height: 40px; display: block; margin: 0 auto 10px; opacity: 0.45; }

/* ---------- Universal back button ---------- */
/* Top-left on every nested view so users never depend on the tab bar to go up. */
.back-btn {
  display: inline-flex; align-items: center; gap: 4px;
  margin-bottom: 12px; padding: 8px 14px 8px 10px;
  border: none; border-radius: 999px;
  background: var(--bg); color: var(--text);
  font-size: 14px; font-weight: 600; font-family: inherit; cursor: pointer;
  box-shadow: 0 1px 3px rgba(0,0,0,0.06);
  transition: transform 0.12s ease;
}
.back-btn:active { transform: scale(0.96); }
.back-btn .icon { width: 1.05em; height: 1.05em; }

/* Tab-switch animation: app.js restarts this by toggling the class off/on
   (forcing a reflow in between) every time the route changes. */
@keyframes viewFadeIn {
  from { opacity: 0; transform: translateY(8px); }
  to { opacity: 1; transform: translateY(0); }
}
.view.view-transition {
  animation: viewFadeIn 0.22s ease;
}

.grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
.card {
  background: var(--bg); border-radius: 16px; overflow: hidden; cursor: pointer;
  display: flex; flex-direction: column;
  box-shadow: 0 1px 4px rgba(0,0,0,0.06);
  transition: transform 0.14s ease, box-shadow 0.18s ease;
}
.card:active { transform: scale(0.98); }
.card-media { position: relative; }
.card img, .card-media-placeholder {
  width: 100%; aspect-ratio: 1/1; object-fit: cover;
  background: var(--secondary-bg); display: block;
}
.card-oos {
  position: absolute; left: 8px; bottom: 8px;
  padding: 3px 9px; border-radius: 999px;
  background: rgba(0,0,0,0.62); color: #fff; font-size: 11px; font-weight: 600;
}
.card-badges { display: flex; flex-wrap: wrap; gap: 4px; margin: 0 0 6px; }
.card-badge {
  padding: 2px 8px; border-radius: 6px; background: var(--secondary-bg);
  color: var(--hint); font-size: 11px; font-weight: 600; white-space: nowrap;
  overflow: hidden; text-overflow: ellipsis; max-width: 100%;
}
.fav-toggle {
  position: absolute; top: 6px; right: 6px;
  background: rgba(255,255,255,0.85); border: none; border-radius: 50%;
  width: 30px; height: 30px; line-height: 0; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  color: var(--hint);
  transition: transform 0.12s ease, color 0.18s ease;
}
.fav-toggle:active { transform: scale(0.88); }
/* Favorited state reads as red everywhere it appears. */
.fav-toggle.is-fav, .btn.secondary.is-fav, .tab-icon-heart { color: #ff3b30; }
.card-body { padding: 10px 11px 12px; display: flex; flex-direction: column; flex: 1; }
.card-title {
  font-size: 14px; font-weight: 600; margin: 0 0 6px; line-height: 1.3;
  /* Two lines max keeps every card in a row the same height. */
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.card-brand {
  font-size: 10px; color: var(--hint); margin: 0 0 3px;
  text-transform: uppercase; letter-spacing: 0.05em; font-weight: 700;
}
.card-price { font-size: 15px; font-weight: 800; margin: auto 0 0; }

/* ---------- Product specs ---------- */
.spec-table { display: flex; flex-direction: column; }
.spec-row {
  display: flex; align-items: baseline; justify-content: space-between; gap: 12px;
  padding: 7px 0; border-bottom: 1px solid rgba(0,0,0,0.06); font-size: 14px;
}
.spec-row:last-child { border-bottom: none; }
.spec-key { color: var(--hint); flex-shrink: 0; }
.spec-value { font-weight: 600; text-align: right; }

.filters { display: flex; gap: 8px; overflow-x: auto; margin-bottom: 10px; padding-bottom: 4px; }

/* Catalog-only header row (category chips + sort). Lives inside the sticky .topbar,
   so it floats above the scrolling grid with no positioning math. Collapses on other
   tabs using the same max-height/opacity technique as the search bar. */
.catalog-bar-wrap {
  display: flex; align-items: center; gap: 8px;
  overflow: hidden;
  max-height: 44px;
  opacity: 1;
  transition: max-height 0.22s ease, opacity 0.18s ease, margin-top 0.22s ease;
}
.catalog-bar-wrap.collapsed {
  max-height: 0;
  opacity: 0;
  margin-top: -8px; /* cancels the header's gap so it collapses flush */
  pointer-events: none;
}

/* Horizontally swipeable category chips - all categories are rendered at once
   and the row scrolls rather than wrapping. */
.chip-bar {
  display: flex; gap: 8px; flex: 1; min-width: 0;
  overflow-x: auto; scroll-behavior: smooth;
  -webkit-overflow-scrolling: touch;
  scrollbar-width: none; /* the row is swiped, so the bar is just visual noise */
}
.chip-bar::-webkit-scrollbar { display: none; }
/* Desktop drag-to-scroll (see enableDragScroll in catalog.js). */
.chip-bar { cursor: grab; }
.chip-bar.dragging { cursor: grabbing; scroll-behavior: auto; user-select: none; }
/* Deliberately NOT disabling pointer-events on the chips while dragging: if the
   class ever stuck (a cancelled gesture used to do exactly that on touch devices)
   every category became permanently untappable. The drag-vs-click distinction is
   handled by the data-dragged flag in the click handler instead. */
.chip {
  flex: 0 0 auto; white-space: nowrap;
  padding: 8px 14px; border-radius: 999px; border: none;
  background: var(--bg); color: var(--text);
  font-size: 14px; font-weight: 500; cursor: pointer;
  box-shadow: 0 1px 3px rgba(0,0,0,0.06);
  transition: background 0.18s ease, color 0.18s ease, transform 0.12s ease;
}
.chip:active { transform: scale(0.94); }
.chip.active { background: var(--button); color: var(--button-text); font-weight: 600; }

/* Custom select: hides the native control chrome (which looks out of place next to
   the app's rounded cards) but keeps the native picker UX on mobile. */
.select-custom { position: relative; flex: 0 0 auto; }
.select-custom::after {
  content: "▾";
  position: absolute; right: 10px; top: 50%; transform: translateY(-50%);
  pointer-events: none; color: var(--hint); font-size: 12px;
}
.select-custom select {
  appearance: none; -webkit-appearance: none; -moz-appearance: none;
  padding: 8px 28px 8px 12px; border-radius: 999px; border: none;
  background: var(--bg); color: var(--text);
  font-size: 14px; font-family: inherit; cursor: pointer;
  box-shadow: 0 1px 3px rgba(0,0,0,0.06);
}
.select-custom.compact select { border-radius: 10px; font-size: 13px; padding: 6px 26px 6px 10px; }
.select-custom select:focus { outline: 2px solid var(--link); outline-offset: 1px; }

/* ---------- Compact sort control ---------- */
/* A small circular button so the category chips get nearly the whole row; the
   options appear in a drop-down anchored beneath it. */
.sort-control { position: relative; flex: 0 0 auto; }
.sort-button {
  width: 36px; height: 36px; border-radius: 50%; border: none;
  background: var(--bg); color: var(--text);
  display: flex; align-items: center; justify-content: center;
  font-size: 17px; line-height: 1; cursor: pointer; padding: 0;
  box-shadow: 0 1px 3px rgba(0,0,0,0.08);
  transition: transform 0.12s ease, background 0.18s ease, color 0.18s ease;
}
.sort-button:active { transform: scale(0.9); }
.sort-control.open .sort-button { background: var(--button); color: var(--button-text); }
.sort-icon { pointer-events: none; width: 18px; height: 18px; }

/* Positioned against .topbar (sticky = a positioned ancestor) so it escapes the
   category bar's overflow clipping. */
.sort-menu {
  position: absolute; top: calc(100% - 4px); left: 12px; z-index: 30;
  min-width: 210px; padding: 6px;
  background: var(--bg); border-radius: 14px;
  box-shadow: 0 8px 28px rgba(0,0,0,0.18);
  display: none;
}
.sort-menu.open { display: block; animation: sortMenuIn 0.16s ease; }
@keyframes sortMenuIn {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: translateY(0); }
}
.sort-option {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  width: 100%; padding: 10px 12px; border: none; border-radius: 10px;
  background: none; color: var(--text);
  font-size: 14px; font-family: inherit; text-align: left; cursor: pointer;
  white-space: nowrap;
}
.sort-option:active { background: var(--secondary-bg); }
.sort-option.active { color: var(--link); font-weight: 600; }
.sort-tick { color: var(--link); line-height: 0; }

.btn {
  display: inline-block; padding: 12px 16px; border-radius: 12px; border: none;
  background: var(--button); color: var(--button-text); font-weight: 600; font-size: 15px; cursor: pointer;
}
.btn.secondary { background: var(--secondary-bg); color: var(--text); }
.btn.block { width: 100%; text-align: center; }
.btn:disabled { opacity: 0.5; cursor: not-allowed; }

.tabbar {
  position: fixed; bottom: 0; left: 0; right: 0; z-index: 10;
  display: flex; background: var(--bg); border-top: 1px solid rgba(0,0,0,0.06);
  padding: 8px 4px calc(env(safe-area-inset-bottom, 0px) + 8px);
}
.tab {
  flex: 1; padding: 6px 4px; background: none; border: none; color: var(--hint);
  font-size: 12px; cursor: pointer; position: relative;
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  transition: color 0.2s ease, transform 0.12s ease;
}
.tab:active { transform: scale(0.92); }
.tab-icon-wrap { position: relative; display: inline-flex; }
/* SVG icon set: inherits the tab's colour via currentColor, so active/inactive
   states need no separate assets. */
.tab-icon {
  width: 24px; height: 24px; display: block;
  transition: transform 0.18s ease, stroke-width 0.18s ease;
}
.tab.active .tab-icon { transform: scale(1.1); stroke-width: 2.2; }
/* Favourites stays red in both states, and fills in once the tab is active. */
.tab-icon-heart { color: #ff3b30; }
.tab.active .tab-icon-heart { fill: #ff3b30; }
.tab-label { font-size: 12px; }
.tab.active { color: var(--link); font-weight: 600; }
.badge {
  position: absolute; top: -4px; right: -10px; background: #ff3b30; color: #fff;
  font-size: 10px; border-radius: 10px; padding: 1px 5px; min-width: 14px; text-align: center;
}
.hidden { display: none !important; }

/* ---------- Product detail page ---------- */
.pdp { display: flex; flex-direction: column; gap: 10px; }
.pdp-media { position: relative; border-radius: 18px; overflow: hidden; background: var(--bg); }
.pdp-gallery { display: flex; overflow-x: auto; scroll-snap-type: x mandatory; scrollbar-width: none; }
.pdp-gallery::-webkit-scrollbar { display: none; }
.pdp-gallery img { width: 100%; flex: 0 0 100%; scroll-snap-align: start; aspect-ratio: 1/1; object-fit: cover; display: block; }
.pdp-gallery-empty { aspect-ratio: 1/1; width: 100%; background: var(--secondary-bg); }
.pdp-fav {
  position: absolute; top: 10px; right: 10px;
  width: 40px; height: 40px; border-radius: 50%; border: none;
  background: rgba(255,255,255,0.92); color: #8e8e93;
  display: flex; align-items: center; justify-content: center; cursor: pointer; padding: 0;
  box-shadow: 0 2px 8px rgba(0,0,0,0.12);
  transition: transform 0.12s ease, color 0.18s ease;
}
.pdp-fav svg { width: 21px; height: 21px; }
.pdp-fav:active { transform: scale(0.88); }
.pdp-fav.is-fav { color: #ff3b30; }
.pdp-count {
  position: absolute; bottom: 10px; right: 10px;
  padding: 3px 9px; border-radius: 999px;
  background: rgba(0,0,0,0.55); color: #fff; font-size: 12px; font-weight: 600;
}

.pdp-headline { background: var(--bg); border-radius: 16px; padding: 14px; }
.pdp-brand {
  color: var(--hint); margin: 0 0 4px; font-size: 12px;
  text-transform: uppercase; letter-spacing: 0.05em; font-weight: 600;
}
.pdp-title { font-size: 21px; font-weight: 700; margin: 0 0 10px; line-height: 1.25; }
.pdp-price-row { display: flex; align-items: center; justify-content: space-between; gap: 10px; }
.pdp-price { font-size: 24px; font-weight: 800; }
.pdp-category {
  padding: 4px 11px; border-radius: 999px; background: var(--secondary-bg);
  color: var(--hint); font-size: 12px; font-weight: 600;
}
.pdp-description { margin: 0; white-space: pre-wrap; line-height: 1.55; font-size: 14px; }

.size-row { display: flex; gap: 8px; flex-wrap: wrap; }
.size-chip {
  min-width: 48px; padding: 10px 14px; border-radius: 12px;
  border: 1.5px solid transparent; background: var(--bg); color: var(--text);
  cursor: pointer; font-size: 14px; font-weight: 600; font-family: inherit;
  transition: border-color 0.16s ease, color 0.16s ease, transform 0.12s ease;
}
.size-chip:active { transform: scale(0.94); }
.size-chip.selected { border-color: var(--link); color: var(--link); }
.size-chip.oos { opacity: 0.35; text-decoration: line-through; cursor: not-allowed; }
/* Flavour names vary wildly in length ("Mint" vs "Blue Raspberry Ice Extreme"), so
   they go in a fixed two-column grid instead of a free-flowing row: every chip is the
   same width and height, and long names ellipsize rather than stretching the layout. */
.flavor-grid {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 8px;
}
.flavor-grid .size-chip {
  min-width: 0; width: 100%;
  display: flex; align-items: center; justify-content: center;
  min-height: 48px; padding: 10px 12px;
  text-align: center;
  /* Chips in a row stretch to the tallest, so a wrapped two-line name keeps the
     row aligned instead of leaving a ragged edge. */
  height: 100%;
}
/* Names are shown in full: the block grows in height rather than clipping the text.
   Width stays uniform because the grid columns are equal. */
.flavor-grid .chip-text {
  display: block; width: 100%;
  white-space: normal;
  overflow-wrap: anywhere;   /* a single very long word breaks instead of overflowing */
  line-height: 1.25;
  font-size: 13px;
}
/* Three across once there's room for it. */
@media (min-width: 480px) {
  .flavor-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); }
}

/* ---------- Admin: flavour editor ---------- */
.flavor-row { display: flex; align-items: center; gap: 8px; margin-bottom: 8px; }
.flavor-row-fields { flex: 1; display: grid; grid-template-columns: 1fr 1fr 72px; gap: 6px; min-width: 0; }
.flavor-row-fields input {
  width: 100%; min-width: 0; padding: 9px 10px; border-radius: 10px;
  border: 1.5px solid transparent; background: var(--secondary-bg);
  color: var(--text); font-size: 14px; font-family: inherit;
}
.flavor-row-fields input:focus { outline: none; border-color: var(--link); }
.flavor-remove { flex-shrink: 0; }
.stock-note { font-size: 13px; color: var(--hint); margin: 10px 0 0; }

/* Pinned primary action, held clear of the fixed tab bar. The bottom padding is
   what keeps the button itself off the tab bar's top edge once the page is scrolled
   all the way down. */
.pdp-actionbar {
  position: sticky; bottom: var(--tabbar-h); z-index: 8;
  margin: 14px -12px 0; padding: 10px 12px 14px;
  background: var(--secondary-bg);
}
/* Total line inside the pinned bar (checkout). Kept as plain type on the bar's own
   background - a filled card here would read as a divider slab again. */
.actionbar-total {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  margin-bottom: 8px;
}
.actionbar-total-label {
  font-size: 12px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--hint);
}
.actionbar-total-value { font-size: 19px; font-weight: 700; letter-spacing: -0.01em; }

.btn.added { background: #34c759; }

/* ---------- Cart ---------- */
.cart-list { display: flex; flex-direction: column; gap: 10px; }
.cart-card {
  display: flex; gap: 12px; background: var(--bg);
  border-radius: 16px; padding: 12px; box-shadow: 0 1px 4px rgba(0,0,0,0.06);
}
.cart-thumb { flex: 0 0 72px; }
.cart-thumb img, .cart-thumb-placeholder {
  width: 72px; height: 72px; border-radius: 12px; object-fit: cover;
  background: var(--secondary-bg); display: block;
}
.cart-card-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 8px; }
.cart-card-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.cart-card-title { margin: 0; font-size: 15px; font-weight: 600; line-height: 1.3; }
.cart-remove {
  border: none; background: none; color: var(--hint);
  font-size: 16px; line-height: 0; cursor: pointer; padding: 2px 4px; flex-shrink: 0;
}
.cart-remove:active { color: #ff3b30; }
.cart-card-bottom { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-top: auto; }
.qty-stepper {
  display: inline-flex; align-items: center; gap: 2px;
  background: var(--secondary-bg); border-radius: 10px; padding: 2px;
}
.qty-stepper button {
  width: 30px; height: 30px; border: none; border-radius: 8px;
  background: none; color: var(--text); font-size: 17px; cursor: pointer; font-family: inherit;
}
.qty-stepper button:active { background: var(--bg); }
.qty-stepper button:disabled { opacity: 0.4; }
.qty-value { min-width: 26px; text-align: center; font-size: 14px; font-weight: 700; }
.cart-line-total { font-size: 15px; font-weight: 700; }
/* Breathing room between the item list and the totals block - they used to sit
   flush against each other. */
.cart-total { align-items: center; margin-top: 16px; }
.cart-total-sub { margin: 2px 0 0; font-size: 12px; opacity: 0.85; }

/* ---------- Favorites ---------- */
.fav-list { display: flex; flex-direction: column; gap: 10px; }
.fav-card {
  display: flex; align-items: center; gap: 12px; cursor: pointer;
  background: var(--bg); border-radius: 16px; padding: 12px;
  box-shadow: 0 1px 4px rgba(0,0,0,0.06);
  transition: transform 0.14s ease;
}
.fav-card:active { transform: scale(0.99); }
.fav-thumb { flex: 0 0 68px; }
.fav-thumb img, .fav-thumb-placeholder {
  width: 68px; height: 68px; border-radius: 12px; object-fit: cover;
  background: var(--secondary-bg); display: block;
}
.fav-body { flex: 1; min-width: 0; display: flex; flex-direction: column; gap: 6px; }
.fav-title {
  margin: 0; font-size: 15px; font-weight: 600; line-height: 1.3;
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
.fav-body .card-badge { align-self: flex-start; }
.fav-bottom { display: flex; align-items: center; gap: 8px; }
.fav-price { font-size: 15px; font-weight: 700; }
.fav-oos {
  padding: 2px 8px; border-radius: 6px;
  background: rgba(142,142,147,0.18); color: #6d6d72; font-size: 11px; font-weight: 600;
}
/* Filled heart doubles as the un-favourite control. */
.fav-remove {
  flex-shrink: 0; width: 36px; height: 36px; border: none; border-radius: 50%;
  background: rgba(255,59,48,0.10); color: #ff3b30;
  line-height: 0; cursor: pointer; padding: 0;
  display: flex; align-items: center; justify-content: center;
  transition: transform 0.12s ease, background 0.18s ease;
}
.fav-remove:active { transform: scale(0.88); background: rgba(255,59,48,0.2); }

/* ---------- Forms ---------- */
.form-card { background: var(--bg); border-radius: 16px; padding: 14px; margin-bottom: 10px; }
.form-card .order-block-label { margin-bottom: 10px; }
.form-grid-2 { display: flex; gap: 10px; }
.form-grid-2 .form-field { flex: 1; min-width: 0; }
.form-field { margin-bottom: 12px; }
.form-field label { display: block; font-size: 13px; color: var(--hint); margin-bottom: 5px; }
.form-field input, .form-field textarea {
  width: 100%; padding: 11px 12px; border-radius: 12px;
  border: 1.5px solid transparent; background: var(--secondary-bg);
  color: var(--text); font-size: 15px; font-family: inherit;
  transition: border-color 0.16s ease;
}
.form-field input:focus, .form-field textarea:focus { outline: none; border-color: var(--link); }
.form-field input.invalid, .form-field textarea.invalid { border-color: #ff3b30; }

/* ---------- Admin: product list ---------- */
.prod-list { display: flex; flex-direction: column; gap: 10px; }
.prod-card {
  display: flex; gap: 12px; background: var(--bg);
  border-radius: 16px; padding: 12px; box-shadow: 0 1px 4px rgba(0,0,0,0.06);
}
.prod-card.inactive { opacity: 0.62; }
.prod-thumb { flex: 0 0 64px; }
.prod-thumb img, .prod-thumb-placeholder {
  width: 64px; height: 64px; border-radius: 12px; object-fit: cover;
  background: var(--secondary-bg); display: block;
}
.prod-body { flex: 1; min-width: 0; }
.prod-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.prod-title { margin: 0; font-size: 15px; font-weight: 600; line-height: 1.3; }
.prod-state {
  flex-shrink: 0; padding: 2px 8px; border-radius: 6px;
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em;
}
.prod-state.on { background: rgba(52,199,89,0.16); color: #248a3d; }
.prod-state.off { background: rgba(142,142,147,0.18); color: #6d6d72; }
.prod-meta { margin: 3px 0 8px; font-size: 12px; color: var(--hint); }
.prod-stats { display: flex; flex-wrap: wrap; align-items: center; gap: 10px; margin-bottom: 10px; }
.prod-price { font-size: 16px; font-weight: 700; }
.prod-stat { font-size: 12px; color: var(--hint); }
.prod-stat.zero strong { color: #ff3b30; }
.prod-actions { justify-content: flex-start; }

/* Per-variant stock breakdown under the aggregated total. */
.prod-variants { display: flex; flex-wrap: wrap; gap: 5px; margin-bottom: 10px; }
.prod-variant {
  display: inline-flex; align-items: center; gap: 5px; max-width: 100%;
  padding: 2px 8px; border-radius: 6px;
  background: var(--secondary-bg); font-size: 11px;
}
.prod-variant-name {
  color: var(--hint); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 120px;
}
.prod-variant-stock { font-weight: 700; }
.prod-variant.zero .prod-variant-stock { color: #ff3b30; }

.profile-header {
  display: flex; align-items: center; gap: 14px;
  background: var(--bg); border-radius: 14px; padding: 16px; margin-bottom: 16px;
}

/* Accent hero card - the single high-contrast surface on the profile screen.
   --hero-fg is what every child reads for its colour, so a role theme only has to
   override the background and this one variable. */
.profile-hero {
  --hero-fg: var(--button-text);
  position: relative; overflow: hidden;
  display: flex; align-items: center; gap: 14px;
  border-radius: 18px; padding: 18px; margin-bottom: 12px;
  background: var(--button); color: var(--hero-fg);
}

/* Role themes. Fixed colours rather than Telegram's theme variables: the banner's
   whole job is to encode the role, so it must not shift with the user's theme.
   Same hues as the role badges in the admin user list. */
.profile-hero.role-user {
  --hero-fg: #ffffff;
  background: linear-gradient(135deg, #5aa9f5 0%, #2481cc 100%);
}
.profile-hero.role-admin {
  --hero-fg: #ffffff;
  background: linear-gradient(135deg, #8054d8 0%, #4b23a3 100%);
}
.profile-hero.role-super {
  --hero-fg: #ffffff;
  background: linear-gradient(135deg, #ffab2e 0%, #f07800 100%);
}
/* Soft highlight so the panel isn't a flat block of colour. */
.profile-hero::after {
  content: ""; position: absolute; right: -40px; top: -60px;
  width: 170px; height: 170px; border-radius: 50%;
  background: rgba(255,255,255,0.12); pointer-events: none;
}
.profile-hero .profile-avatar {
  width: 66px; height: 66px;
  background: rgba(255,255,255,0.2);
  box-shadow: 0 0 0 3px rgba(255,255,255,0.28);
}
.profile-hero .profile-avatar-fallback { color: var(--hero-fg); }
.profile-hero .profile-info { position: relative; z-index: 1; }
.profile-hero .profile-name { font-size: 19px; }
.profile-hero .profile-meta { color: var(--hero-fg); opacity: 0.85; }
.profile-badge {
  position: relative; z-index: 1; align-self: flex-start;
  padding: 3px 9px; border-radius: 999px;
  background: rgba(255,255,255,0.22); color: var(--hero-fg);
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em;
}
/* Same warm amber as .admin-tag.super in the admin user list, so the role reads
   identically wherever it appears. */
.profile-badge.super { background: #ff9500; color: #fff; }
/* ...except on the orange hero, where amber-on-amber would vanish - invert it there. */
.profile-hero.role-super .profile-badge.super { background: #ffffff; color: #d96c00; }
.profile-stats { margin-bottom: 12px; }
.profile-avatar {
  width: 64px; height: 64px; border-radius: 50%; overflow: hidden; flex-shrink: 0;
  background: var(--secondary-bg); display: flex; align-items: center; justify-content: center;
}
.profile-avatar img { width: 100%; height: 100%; object-fit: cover; }
.profile-avatar-fallback { font-size: 26px; font-weight: 700; color: var(--hint); }
.profile-info { flex: 1; min-width: 0; }
.profile-name { font-size: 18px; font-weight: 700; margin: 0 0 4px; }
.profile-meta { font-size: 13px; color: var(--hint); margin: 0; }

.profile-menu { display: flex; flex-direction: column; gap: 8px; }
.profile-menu-item {
  display: flex; align-items: center; gap: 12px; width: 100%;
  background: var(--bg); border: none; border-radius: 12px; padding: 14px;
  font-size: 15px; color: var(--text); cursor: pointer; text-align: left;
  transition: transform 0.12s ease;
}
.profile-menu-item:active { transform: scale(0.98); }
.profile-menu-item .pmi-icon { font-size: 20px; width: 24px; text-align: center; }
.profile-menu-item .pmi-label { flex: 1; }
.profile-menu-item .pmi-chevron { color: var(--hint); line-height: 0; }
.profile-menu-item .pmi-badge {
  font-size: 11px; color: var(--hint); background: var(--secondary-bg); padding: 2px 8px; border-radius: 10px;
}
.profile-menu-item.soon { cursor: default; opacity: 0.65; }
.profile-menu-item .pmi-value { font-size: 14px; color: var(--hint); margin-right: 2px; }

/* ---------- Language picker ---------- */
.lang-subtitle { color: var(--hint); font-size: 14px; margin: -6px 0 14px; }
.lang-list { display: flex; flex-direction: column; gap: 8px; }
.lang-option {
  display: flex; align-items: center; gap: 12px; width: 100%;
  background: var(--bg); border: 2px solid transparent; border-radius: 12px; padding: 14px;
  font-size: 15px; font-family: inherit; color: var(--text); cursor: pointer; text-align: left;
  transition: border-color 0.18s ease, transform 0.12s ease;
}
.lang-option:active { transform: scale(0.98); }
.lang-option.selected { border-color: var(--link); font-weight: 600; }
/* Two-letter tag instead of a flag emoji: flags render inconsistently (and some
   platforms drop them entirely). */
.lang-tag {
  min-width: 34px; padding: 3px 7px; border-radius: 7px;
  background: var(--secondary-bg); color: var(--hint);
  font-size: 12px; font-weight: 700; letter-spacing: 0.04em; text-align: center;
}
.lang-tag .icon { width: 16px; height: 16px; vertical-align: -0.15em; }
.lang-name { flex: 1; }
.lang-check { color: var(--link); line-height: 0; min-width: 18px; }

.order-status { display: inline-block; padding: 2px 10px; border-radius: 20px; font-size: 12px; font-weight: 700; background: var(--secondary-bg); }
.order-timestamp { color: var(--hint); font-size: 13px; margin: 6px 0; }
.section-heading { font-size: 20px; font-weight: 700; margin: 0 0 12px; }

/* ---------- Order status badges ---------- */
/* Colours are fixed rather than theme-derived: they carry meaning (grey = accepted,
   yellow = processing, green = done, red = cancelled) and must stay recognisable in
   both light and dark Telegram themes. */
.status-badge {
  display: inline-flex; align-items: center; gap: 5px;
  padding: 4px 11px; border-radius: 999px;
  font-size: 12px; font-weight: 700; line-height: 1.4; white-space: nowrap;
}
.status-badge::before {
  content: ""; width: 6px; height: 6px; border-radius: 50%; background: currentColor;
}
.status-accepted   { background: rgba(142,142,147,0.16); color: #6d6d72; }
.status-processing { background: rgba(255,179,0,0.18);   color: #b37400; }
.status-completed  { background: rgba(52,199,89,0.16);   color: #248a3d; }
.status-cancelled  { background: rgba(255,59,48,0.14);   color: #d70015; }

/* ---------- Order history cards ---------- */
.order-list { display: flex; flex-direction: column; gap: 10px; }
.order-card {
  background: var(--bg); border-radius: 16px; overflow: hidden;
  box-shadow: 0 1px 4px rgba(0,0,0,0.06);
}
/* Non-expandable usages (e.g. the admin order list, which navigates instead of
   expanding) carry their own padding since .order-card itself has none. */
.order-card-flat { padding: 12px; cursor: pointer; }
.order-card-head {
  display: flex; align-items: center; gap: 10px; padding: 14px;
  cursor: pointer; transition: background 0.18s ease;
}
.order-card-head:active { background: var(--secondary-bg); }
.order-card-main { flex: 1; min-width: 0; }
.order-card-top { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
.order-number { font-size: 15px; font-weight: 700; }
.order-card-summary { margin: 4px 0 0; font-size: 14px; color: var(--text); }
.order-chevron {
  color: var(--hint); flex-shrink: 0; line-height: 0;
  transition: transform 0.22s ease;
}
.order-card.expanded .order-chevron { transform: rotate(90deg); }

/* Collapsed by default; the expanded body slides in. */
.order-card-body { display: none; padding: 0 14px 14px; }
.order-card.expanded .order-card-body { display: block; animation: orderExpand 0.22s ease; }
@keyframes orderExpand {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: translateY(0); }
}

/* Each key fact gets its own tinted block so it reads at a glance. */
.order-blocks { display: flex; flex-direction: column; gap: 10px; }
.order-block { background: var(--secondary-bg); border-radius: 12px; padding: 12px; }
.order-block-row { display: flex; gap: 10px; }
.order-block-row .order-block { flex: 1; min-width: 0; }
.order-block-label {
  margin: 0 0 6px; font-size: 11px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.05em; color: var(--hint);
}
.order-block-value { margin: 0 0 2px; font-size: 14px; word-break: break-word; }
.order-block-value.muted { color: var(--hint); font-size: 13px; }

.order-items { display: flex; flex-direction: column; gap: 10px; }
.order-item { display: flex; align-items: flex-start; justify-content: space-between; gap: 10px; }
.order-item-info { flex: 1; min-width: 0; }
.order-item-title { margin: 0 0 6px; font-size: 14px; font-weight: 600; }
.order-item-meta { display: flex; gap: 6px; flex-wrap: wrap; }
.order-item-price { font-size: 14px; font-weight: 700; white-space: nowrap; }

/* The chosen size is called out as a pill so it stands apart from the title. */
.size-badge {
  display: inline-block; padding: 3px 10px; border-radius: 8px;
  background: var(--button); color: var(--button-text);
  font-size: 12px; font-weight: 700; letter-spacing: 0.02em;
}
.qty-badge {
  display: inline-block; padding: 3px 9px; border-radius: 8px;
  background: var(--bg); color: var(--hint); font-size: 12px; font-weight: 600;
}

/* Total gets the strongest visual weight in the expanded card. */
.order-total-block {
  display: flex; align-items: center; justify-content: space-between;
  background: var(--button); color: var(--button-text);
}
.order-total-block .order-block-label { margin: 0; color: var(--button-text); opacity: 0.85; }
/* Lighter than the old 800: the size already carries the emphasis, and the heavy
   weight made the figure look blunt next to the rest of the type. */
.order-total-value { margin: 0; font-size: 22px; font-weight: 600; letter-spacing: -0.01em; }

.order-detail-head { display: flex; align-items: center; justify-content: space-between; gap: 10px; margin-bottom: 12px; }

/* ---------- Admin: users ---------- */
.admin-count { font-size: 13px; color: var(--hint); margin: 0 0 10px; }
.user-list { display: flex; flex-direction: column; gap: 8px; }
.user-row {
  display: flex; align-items: center; gap: 12px;
  background: var(--bg); border-radius: 12px; padding: 12px; cursor: pointer;
  transition: transform 0.12s ease;
}
.user-row:active { transform: scale(0.99); }
.user-avatar {
  width: 40px; height: 40px; border-radius: 50%; flex-shrink: 0;
  background: var(--secondary-bg); color: var(--hint);
  display: flex; align-items: center; justify-content: center;
  font-size: 17px; font-weight: 700;
}
.user-row-info { flex: 1; min-width: 0; }
.user-row-name { margin: 0 0 2px; font-size: 15px; font-weight: 600; }
.user-row-meta { margin: 0; font-size: 12px; color: var(--hint); }
.user-row-right { display: flex; align-items: center; gap: 6px; flex-shrink: 0; }
.user-row-spent { font-size: 14px; font-weight: 700; }
.admin-tag {
  display: inline-block; padding: 1px 7px; border-radius: 6px; margin-left: 4px;
  background: var(--button); color: var(--button-text); font-size: 10px; font-weight: 700;
  text-transform: uppercase; letter-spacing: 0.04em; vertical-align: middle;
}

/* ---------- Admin: categories ---------- */
.cat-list { display: flex; flex-direction: column; gap: 8px; }
.cat-row {
  display: flex; align-items: center; gap: 10px;
  background: var(--bg); border-radius: 12px; padding: 12px;
}
.cat-row-info { flex: 1; min-width: 0; }
.cat-row-name { margin: 0 0 4px; font-size: 15px; font-weight: 600; }
.cat-row-meta { margin: 0 0 2px; font-size: 12px; color: var(--hint); }
.cat-lang {
  display: inline-block; padding: 0 5px; border-radius: 4px; margin-right: 2px;
  background: var(--secondary-bg); font-size: 10px; font-weight: 700; letter-spacing: 0.03em;
}
.cat-empty-badge {
  display: inline-block; padding: 1px 7px; border-radius: 6px; margin-left: 6px;
  background: rgba(52,199,89,0.16); color: #248a3d; font-size: 10px; font-weight: 700;
}

.stat-row { display: flex; gap: 10px; margin-bottom: 10px; }
.stat-card { flex: 1; background: var(--bg); border-radius: 12px; padding: 14px; text-align: center; }
.stat-value { margin: 0 0 2px; font-size: 20px; font-weight: 800; }
.stat-label { margin: 0; font-size: 12px; color: var(--hint); }

.breakdown-row { display: flex; flex-wrap: wrap; gap: 8px; }
.breakdown-item {
  display: flex; align-items: center; gap: 6px;
  background: var(--secondary-bg); border-radius: 10px; padding: 6px 10px;
}
.breakdown-count { font-size: 15px; font-weight: 700; }

.location-list { display: flex; flex-direction: column; gap: 8px; }
.location-item {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  font-size: 14px;
}
.location-count { color: var(--hint); font-size: 13px; white-space: nowrap; }

/* Segmented control for the admin panel's top-level panes - the active pane gets
   a filled background so the current section is obvious at a glance. */
.seg {
  display: flex; gap: 4px; padding: 4px; margin-bottom: 12px;
  background: var(--bg); border-radius: 12px;
  /* Scrolls itself once the tabs no longer fit, instead of pushing the page wider.
     Scrollbar hidden - the row is swiped/dragged, so the bar is only noise. */
  flex-wrap: nowrap;
  overflow-x: auto;
  -webkit-overflow-scrolling: touch;
  overscroll-behavior-x: contain;  /* don't chain the swipe to the page */
  scrollbar-width: none;
  cursor: grab;
}
.seg::-webkit-scrollbar { display: none; }
.seg.dragging { cursor: grabbing; user-select: none; }
.seg-btn {
  /* grow to share the width when the tabs fit, but never shrink below their label -
     shrinking is what made the row overflow the viewport in the first place. */
  flex: 1 0 auto;
  white-space: nowrap;
  padding: 9px 12px; border: none; border-radius: 9px;
  background: transparent; color: var(--hint);
  font-size: 14px; font-weight: 600; font-family: inherit; cursor: pointer;
  transition: background 0.18s ease, color 0.18s ease;
}
.seg-btn.active { background: var(--button); color: var(--button-text); }

/* Compact pill buttons used for table row actions (Edit / duplicate / delete). */
.row-actions { display: flex; gap: 6px; justify-content: flex-end; }
.btn-chip {
  padding: 6px 12px; border-radius: 999px; border: none;
  background: var(--secondary-bg); color: var(--text);
  font-size: 13px; font-family: inherit; cursor: pointer; white-space: nowrap;
  transition: transform 0.12s ease, opacity 0.18s ease;
}
.btn-chip:active { transform: scale(0.94); }
.btn-chip:disabled { opacity: 0.5; cursor: not-allowed; }
.btn-chip.danger { color: #ff3b30; }

.admin-order-head { display: flex; justify-content: space-between; align-items: center; gap: 10px; }
.admin-section { background: var(--bg); border-radius: 12px; padding: 12px; margin-bottom: 10px; }
.admin-section-title {
  margin: 0 0 8px; font-size: 12px; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.04em; color: var(--hint);
}
.admin-order-item {
  display: flex; justify-content: space-between; gap: 10px;
  padding: 6px 0; border-bottom: 1px solid rgba(0,0,0,0.06); font-size: 14px;
}
.admin-order-item:last-child { border-bottom: none; }
.admin-order-item.total { font-weight: 700; padding-top: 10px; }

/* ---------- Order comments ---------- */
.comment-list { display: flex; flex-direction: column; gap: 8px; margin-bottom: 10px; }
.comment {
  background: var(--bg); border-radius: 10px; padding: 9px 11px;
  border-left: 3px solid var(--hint);
}
/* Admin replies are visually distinct from the customer's own notes. */
.comment.from-admin { border-left-color: var(--link); }
.comment-head {
  display: flex; align-items: baseline; justify-content: space-between; gap: 8px; margin-bottom: 3px;
}
.comment-author { font-size: 12px; font-weight: 700; }
.comment-time { font-size: 11px; color: var(--hint); white-space: nowrap; }
.comment-text { margin: 0; font-size: 14px; line-height: 1.4; white-space: pre-wrap; word-break: break-word; }

.comment-form { display: flex; flex-direction: column; gap: 8px; }
.comment-input {
  width: 100%; padding: 10px 12px; border-radius: 10px;
  border: 1.5px solid transparent; background: var(--bg);
  color: var(--text); font-size: 14px; font-family: inherit; resize: vertical;
}
.comment-input:focus { outline: none; border-color: var(--link); }
.comment-send { align-self: flex-end; padding: 8px 18px; font-size: 14px; }

/* Discreet destructive action, parked at the bottom of the admin order view. */
.btn-danger-ghost {
  display: block; width: 100%; margin-top: 14px; padding: 12px;
  border: 1px solid rgba(255,59,48,0.35); border-radius: 14px;
  background: none; color: #ff3b30;
  font-size: 14px; font-family: inherit; cursor: pointer;
  transition: background 0.18s ease;
}
.btn-danger-ghost:active { background: rgba(255,59,48,0.10); }

.admin-tag.super { background: #ff9500; }
.ban-tag {
  display: inline-block; padding: 1px 7px; border-radius: 6px; margin-left: 4px;
  background: rgba(255,59,48,0.14); color: #d70015;
  font-size: 10px; font-weight: 700; text-transform: uppercase; vertical-align: middle;
}
.user-row.banned { opacity: 0.6; }

.chat-hint { font-size: 12px; color: var(--hint); margin: 0 0 8px; line-height: 1.4; }
.chat-btn { width: 100%; border-radius: 14px; margin-top: 4px;
  display: inline-flex; align-items: center; justify-content: center; gap: 8px; }

.empty-state { text-align: center; color: var(--hint); padding: 40px 20px; }

table.admin-table { width: 100%; border-collapse: collapse; font-size: 13px; }
table.admin-table th, table.admin-table td { text-align: left; padding: 6px 4px; border-bottom: 1px solid rgba(0,0,0,0.06); }

/* ---------- Flavour-linked product image ---------- */
.pdp-flavor-image { width: 100%; aspect-ratio: 1/1; background: var(--secondary-bg); }
.pdp-flavor-image img {
  width: 100%; height: 100%; object-fit: cover; display: block;
  transition: opacity 0.18s ease;
}
/* Brief dip while the new flavour's image loads, so the swap reads as intentional
   rather than as a flicker. */
.pdp-flavor-image img.swapping { opacity: 0.35; }

/* ---------- Admin: order editor ---------- */
.order-item-row {
  display: flex; flex-direction: column; gap: 6px;
  padding: 10px; margin-bottom: 8px;
  background: var(--secondary-bg); border-radius: 12px;
}
.order-item-row-bottom { display: flex; align-items: center; gap: 6px; }
.order-item-row .e_qty {
  width: 72px; padding: 9px 10px; border-radius: 10px;
  border: 1.5px solid transparent; background: var(--bg);
  color: var(--text); font-size: 14px; font-family: inherit; text-align: center;
}
.order-item-row .e_qty:focus { outline: none; border-color: var(--link); }
.order-item-remove { flex-shrink: 0; }

/* Provenance/payment markers on the admin order list. */
.manual-tag, .paid-tag {
  display: inline-block; margin-left: 6px; padding: 1px 7px; border-radius: 6px;
  font-size: 10px; font-weight: 700; text-transform: uppercase; letter-spacing: 0.03em;
  vertical-align: middle;
}
.manual-tag { background: rgba(255,149,0,0.18); color: #b36b00; }
.paid-tag { background: rgba(52,199,89,0.16); color: #248a3d; }

/* Flavour rows gained an image field, so they stack rather than sit on one line. */
.flavor-row { flex-wrap: wrap; }
.flavor-row .f_flavor_image {
  flex: 1 1 100%; padding: 9px 10px; border-radius: 10px;
  border: 1.5px solid transparent; background: var(--secondary-bg);
  color: var(--text); font-size: 13px; font-family: inherit;
}
.flavor-row .f_flavor_image:focus { outline: none; border-color: var(--link); }
