/* catalog.css — Maya Cake inspired catalog styles */

/* Brand palette — the four colours everything here is built from.
 *
 *   Espresso Ink      #1A1817  text, the sign's outlines, interface buttons
 *   Oat Milk / Crema  #F7F5F0  the catalogue's ground, button underlays
 *   Burnt Terracotta  #D95A32  «Замовити», the dot in the logo, delivery
 *   Fresh Sage        #4A6B5D  «В наявності», a confirmed накладна
 *
 * The greens here were Tailwind's #16a34a, which is a different, colder green
 * and belonged to nothing. Sage is the brand's positive colour and this is
 * what it is for.
 */
:root {
  --cat-bg: #F7F5F0;          /* Oat Milk / Crema */
  --cat-card: #FFFFFF;
  --cat-text: #1A1817;        /* Espresso Ink */
  --cat-text2: #6B7280;
  --cat-text3: #9CA3AF;
  --cat-border: #F0EDE8;
  --cat-accent: #1A1817;      /* Espresso Ink; a tenant's branding.accent overrides */
  --cat-accent-hover: #333;
  --cat-warm: #F5F0EA;
  --cat-warm2: #EDE8E0;
  --cat-danger: #B91C1C;
  --cat-sage: #4A6B5D;        /* Fresh Sage — «в наявності», a done набір */
  --cat-sage-lo: #EDF2EF;
  --cat-radius: 16px;
  --cat-radius-sm: 10px;
  --cat-max-w: 100%;
  --cat-font: 'Inter', -apple-system, BlinkMacSystemFont, system-ui, sans-serif;
}

*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
* { -webkit-tap-highlight-color: transparent; }

::selection { background: var(--cat-warm2); color: var(--cat-text); }

button, summary, a { outline: none; }
button:focus-visible, summary:focus-visible, a:focus-visible,
.cat-flavor-pick:focus-visible, .cat-tab:focus-visible {
  outline: 2px solid var(--cat-text);
  outline-offset: 2px;
}

/* ── Selects ──
   Left alone, a select renders as an OS widget — grey gradient and system
   arrow on macOS, its own metrics everywhere — which looked nothing like the
   text inputs sitting directly above it in the requisites form. This resets it
   and rebuilds the same box those inputs use. */
select {
  appearance: none; -webkit-appearance: none;
  width: 100%; cursor: pointer;
  font-family: var(--cat-font); font-size: .92rem;
  /* `normal` is what the text inputs resolve to, so a select stacked among
     them comes out the same 40px tall — no magic number to drift. */
  line-height: normal;
  color: var(--cat-text);
  /* Room on the right for the chevron, so a long option label can never run
     underneath it. */
  padding: 10px 34px 10px 12px;
  border: 1px solid var(--cat-border);
  border-radius: var(--cat-radius-sm);
  background-color: var(--cat-card);
  /* appearance:none takes the system arrow with it, so the chevron is drawn
     here. Inline SVG rather than a glyph or a pseudo-element: a select cannot
     carry ::after, and background-image cannot read currentColor — hence the
     literal --cat-text3 value in the stroke. */
  background-image:
    url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='8'><path d='M1 1.5 6 6.5 11 1.5' fill='none' stroke='%239CA3AF' stroke-width='1.8' stroke-linecap='round'/></svg>");
  background-repeat: no-repeat;
  background-position: right 12px center;
}
select:focus { outline: none; border-color: var(--cat-text2); }
select:disabled { opacity: .55; cursor: not-allowed; }
/* A multi-row select is a list, not a dropdown: no chevron to leave room for. */
select[multiple], select[size]:not([size="1"]) {
  background-image: none; padding-right: 12px;
}

/* ── App shell ── */
body {
  margin: 0;
  font-family: var(--cat-font);
  color: var(--cat-text);
  -webkit-font-smoothing: antialiased;
}
.catalog-app {
  width: 100%; max-width: var(--cat-max-w);
  min-height: 100dvh; background: var(--cat-bg);
  position: relative; margin: 0 auto;
  font-family: var(--cat-font);
  color: var(--cat-text);
  line-height: 1.4;
  -webkit-font-smoothing: antialiased;
  overflow-x: clip;  /* keep slide animations from triggering horizontal scroll */
}

/* ── Header ── */
.cat-header {
  position: sticky; top: 0; z-index: 10;
  background: var(--cat-bg);
  border-bottom: 1px solid var(--cat-border);
}
.cat-header-top {
  display: flex; align-items: center; justify-content: space-between;
  padding: 14px 16px 0; gap: 8px;
}
.cat-header-left {
  display: flex; align-items: center; gap: 8px;
  min-width: 0;
}
.cat-logo { height: 36px; flex-shrink: 0; }
.cat-header-label {
  font-size: .82rem; font-weight: 600; color: var(--cat-text2);
  white-space: nowrap;
}
.cat-header-right {
  display: flex; align-items: center; gap: 4px;
  flex-shrink: 0;
}
.cat-header-cart {
  position: relative; background: none; border: none;
  font-size: 1.2rem; cursor: pointer; padding: 8px 0 2px;
  color: var(--cat-text);
}
.cat-header-cart .badge {
  position: absolute; top: -4px; right: -6px;
  background: var(--cat-accent); color: #fff;
  font-size: .6rem; font-weight: 700;
  width: 16px; height: 16px; border-radius: 50%;
  display: none; align-items: center; justify-content: center;
}
.cat-header-cart .badge.show { display: flex; }
.cat-tabs-row {
  display: flex; align-items: center; gap: 8px;
  padding: 12px 16px; min-width: 0;
}
.cat-tabs-special {
  display: flex; gap: 4px; flex-shrink: 0;
  padding-right: 8px; border-right: 1px solid var(--cat-border);
}
.cat-tab-special {
  flex-shrink: 0;
  width: 34px; height: 34px;
  border-radius: 50%; border: 1.5px solid var(--cat-border);
  background: var(--cat-card); color: var(--cat-text2);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; transition: all .15s; padding: 0;
}
.cat-tab-special:hover { border-color: var(--cat-text3); color: var(--cat-text); }
.cat-tab-special.active {
  background: var(--cat-accent); color: #fff;
  border-color: var(--cat-accent);
}
.cat-tabs {
  display: flex; gap: 6px; overflow-x: auto; min-width: 0;
  padding: 0; -webkit-overflow-scrolling: touch;
  scrollbar-width: none;
  flex: 1;
  margin-right: -16px;
  margin-left: -8px;
  padding-left: 8px;
}
.cat-tabs::-webkit-scrollbar { display: none; }
.cat-tab {
  flex-shrink: 0; padding: 8px 18px;
  border-radius: 24px; border: 1.5px solid var(--cat-border);
  font-family: var(--cat-font);
  font-size: .8rem; font-weight: 500;
  background: var(--cat-card); color: var(--cat-text2);
  cursor: pointer; transition: all .15s;
}
.cat-tab:hover { border-color: var(--cat-text3); }
.cat-tab.active {
  background: var(--cat-accent); color: #fff;
  border-color: var(--cat-accent);
}
/* Two levels in one strip: the top-level tab sits on a darker fill, the
   sub-category tabs stay on the card colour and a shade lighter. */
.cat-tab-top {
  background: var(--cat-warm2);
  border-color: var(--cat-warm2);
  color: var(--cat-text);
  font-weight: 600;
}
/* :not(.active) so hovering the selected tab doesn't undo its accent border
   -- both selectors are the same specificity and this one comes later. */
.cat-tab-top:not(.active):hover { border-color: var(--cat-text3); }
.cat-tab-sub {
  padding: 8px 14px;
  font-weight: 400;
  color: var(--cat-text3);
}
/* Marks where a group of sub-categories ends. Only groups get one: a strip of
   nothing but top-level tabs has no boundaries to draw. */
.cat-tab-div {
  flex-shrink: 0; align-self: center;
  width: 1px; height: 22px;
  background: var(--cat-border);
  margin: 0 4px;
}

/* ── Product list ── */
.cat-list { padding: 0 16px 40px; }
/* The for.cafe mark in the footer. Inline with the text rather than a block
   above it: the shop's name is the line that matters there, and the platform's
   sign is a footnote to it. */
.cat-footer-mark {
  vertical-align: -3px;
  margin-right: 5px;
  opacity: .85;
}

.cat-footer {
  padding: 20px 16px 120px;
  text-align: center;
  font-size: .7rem; color: var(--cat-text3);
  letter-spacing: .02em; line-height: 1.6;
  border-top: 1px solid var(--cat-border);
}
/* Underlined rather than coloured: the accent belongs to the tenant's brand,
   and a credit line is the last thing in the catalogue that should claim it. */
.cat-footer-link {
  color: var(--cat-text2);
  text-decoration: underline;
  text-underline-offset: 2px;
}
.cat-footer-link:hover { color: var(--cat-text); }
.cat-section-title {
  font-size: .75rem; font-weight: 600; letter-spacing: .08em;
  text-transform: uppercase; color: var(--cat-text3);
  margin: 20px 0 10px; padding-bottom: 6px;
  border-bottom: 1px solid var(--cat-border);
}
/* Top-level heading above a run of sub-category sections. Emitted only when
   a product actually sits in a sub-category — products hanging straight off
   a parent keep the single section title. */
.cat-parent-title {
  font-size: 1.05rem; font-weight: 700; letter-spacing: .01em;
  color: var(--cat-text); margin: 30px 0 2px;
}
.cat-parent-title + .cat-section-title { margin-top: 8px; }
.cat-card {
  display: flex; gap: 14px;
  background: var(--cat-card); border-radius: var(--cat-radius);
  padding: 14px; margin-bottom: 10px;
  border: 1px solid var(--cat-border);
  cursor: pointer; transition: all .15s;
  overflow: hidden;
}
.cat-card:hover { border-color: #D1CCC4; }
.cat-card:active { transform: scale(.985); }
.cat-card-body { flex: 1; min-width: 0; display: flex; flex-direction: column; }
.cat-card-name { font-size: .92rem; font-weight: 600; margin-bottom: 4px; }
.cat-card-price {
  font-weight: 500;
  color: var(--cat-text2);
  margin-left: .25em;
  white-space: nowrap;
}
.cat-card-desc {
  font-size: .78rem; color: var(--cat-text2); line-height: 1.4;
  display: -webkit-box; -webkit-line-clamp: 4;
  -webkit-box-orient: vertical; overflow: hidden;
  margin-bottom: auto;
}
.cat-card-icons { display: flex; gap: 4px; margin-top: 8px; }
.cat-allergen-icon {
  width: 26px; height: 26px; border-radius: 6px;
  background: var(--cat-warm); display: flex;
  align-items: center; justify-content: center;
  flex-shrink: 0; overflow: hidden;
}
.cat-allergen-icon img { width: 20px; height: 20px; object-fit: contain; }
.cat-allergen-icon .icon-text {
  font-size: .55rem; color: var(--cat-text3); font-weight: 600;
  text-align: center; line-height: 1.1;
}
.cat-card-thumb-slot {
  /* Reserves a 118px-wide flex column on the right side. Stretches to
     card height, with a minimum so the image (sized to card height at
     natural aspect) never gets narrower than the slot — that's the
     "no gap on the right" guarantee.
     LQIP url is set inline; CSS handles cover-positioning.
     `overflow: hidden` confines the loading-state `filter: blur` halo
     within the slot — without it the blur bloom bled leftward into
     the description area as a faint grey strip. */
  width: 118px;
  align-self: stretch;
  min-height: 118px;
  margin: -14px -14px -14px 0;
  flex-shrink: 0;
  position: relative;
  overflow: hidden;
  background-size: cover;
  background-position: center;
}
.cat-card-thumb {
  /* Fills the slot exactly and lets object-fit do the cropping, which keeps
     the subject centred. The old rule sized the image to the slot's height at
     natural aspect (`width: auto; min-width: 100%`) and pinned it to `left:
     0`, so on a card tall enough to stretch the slot past 118px the image was
     scaled up and then cropped entirely off its right-hand side — the subject
     drifted left and the far edge of the photo was lost. `cover` also keeps
     the "no gap on the right" guarantee for any aspect ratio, so this still
     holds for remote images that aren't pre-squared. */
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  display: block;
  object-fit: cover;
  /* Anchored left: the slot is narrower than it is tall on a card with a long
     description, so `cover` has to drop some width. Cropping from the left
     would eat into the photo's near edge, which is the side that reads as the
     seam against the description column -- so the overflow is taken off the
     right (and top/bottom) instead. */
  object-position: left center;
}
.cat-card-no-img {
  width: 90px; height: 90px; border-radius: var(--cat-radius-sm);
  background: var(--cat-warm); flex-shrink: 0;
  display: flex; align-items: center; justify-content: center;
  color: var(--cat-text3); font-size: .65rem;
}
.cat-card-flavors-hint {
  font-size: .72rem; color: var(--cat-text3); font-style: italic;
  margin-top: 2px;
}
.cat-card-count {
  font-size: .72rem; color: var(--cat-text3);
  margin-top: 2px;
}

/* ── Overlay / Modal ── */
.cat-overlay {
  position: fixed; inset: 0; z-index: 100;
  background: rgba(26,26,26,.3);
  display: none; justify-content: center; align-items: flex-end;
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
  overflow: hidden;
}
.cat-overlay.open { display: flex; }
.cat-modal {
  width: 100%; max-width: var(--cat-max-w);
  max-height: 92dvh; background: var(--cat-card);
  border-radius: 20px 20px 0 0;
  overflow-y: auto; overscroll-behavior: contain;
  animation: catSlideUp .3s cubic-bezier(.22,1,.36,1);
  touch-action: pan-y;
}
@keyframes catSlideUp {
  from { transform: translateY(100%); }
  to { transform: translateY(0); }
}
.cat-modal-header {
  position: sticky; top: 0; z-index: 3;
  /* Floats over the top of the photo rather than sitting in a white bar above
     it, so the image reaches the top edge of the sheet. The gradient keeps the
     handle legible against a light or dark photo; the negative margin pulls
     the image up underneath. */
  background: linear-gradient(
    to bottom, rgba(255, 255, 255, .75), rgba(255, 255, 255, 0)
  );
  padding: 10px 0 22px;
  margin-bottom: -36px;
  flex-shrink: 0; touch-action: none;
  cursor: grab;
  user-select: none; -webkit-user-select: none;
}
/* Products with no photo have nothing to float over, so the header keeps its
   own solid background and normal flow. */
.cat-modal-header.no-photo {
  background: var(--cat-card);
  padding: 10px 0 6px;
  margin-bottom: 0;
}
.cat-modal-header.dragging { cursor: grabbing; }
.cat-modal-peek {
  position: absolute;
  bottom: 0; left: 50%;
  transform: translate(-50%, 0);
  pointer-events: auto;  /* absorb stray taps so they don't hit the overlay backdrop */
  animation: none;
  overflow: hidden;
  will-change: transform;
}
.cat-modal-handle {
  width: 36px; height: 4px; border-radius: 2px;
  /* Sits on top of the photo, so it needs its own contrast rather than the
     border colour, which vanishes against a pale shot. */
  background: rgba(0, 0, 0, .22); margin: 0 auto;
}
.cat-modal-header.no-photo .cat-modal-handle {
  background: var(--cat-border);
}

/* ── Share ──
   The button sits at the right end of the product's name, which is what it acts
   on. `align-items: flex-start` keeps it on the name's first line when the name
   wraps to two. */
.cat-modal-title {
  display: flex; align-items: flex-start; gap: 10px;
}
.cat-modal-title .cat-modal-name { flex: 1; min-width: 0; }
/* The menu is positioned against this, not against the title row, so it drops
   from the button rather than from wherever the name happens to end. */
.cat-share-wrap { position: relative; flex-shrink: 0; }
.cat-modal-share {
  width: 32px; height: 32px; border-radius: 50%;
  border: none; background: var(--cat-warm);
  color: var(--cat-text); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  transition: background .15s, color .15s;
}
.cat-modal-share:hover { background: var(--cat-warm2); }
.cat-modal-share.open { background: var(--cat-accent); color: #fff; }
/* Catches the tap that dismisses the menu. Fixed, so it covers the sheet and
   the backdrop both; below the menu's own z-index so the button and the menu
   stay clickable through it. */
.cat-share-scrim { position: fixed; inset: 0; z-index: 2; }
.cat-share-menu {
  position: absolute; top: calc(100% + 6px); right: 0; z-index: 4;
  min-width: 208px; padding: 6px;
  background: var(--cat-card); border: 1px solid var(--cat-border);
  border-radius: var(--cat-radius-sm);
  box-shadow: 0 8px 28px rgba(0, 0, 0, .16);
  display: flex; flex-direction: column;
  /* Its own keyframes, not catFadeUp: that one carries translateX(-50%) for
     the toast and the cart bar, which are centred with left:50%. Borrowed by
     something anchored to the right, it drew the menu half its own width to
     the left and let it snap into place when the animation ended. */
  animation: catMenuIn .16s ease-out;
}
@keyframes catMenuIn {
  from { opacity: 0; transform: translateY(-6px); }
  to { opacity: 1; transform: translateY(0); }
}
.cat-share-item {
  background: none; border: none; cursor: pointer;
  padding: 10px 12px; border-radius: 8px;
  font: inherit; font-size: .85rem; color: var(--cat-text);
  text-align: left;
}
.cat-share-item:hover { background: var(--cat-warm); }

.cat-modal-img {
  /* Fill the width and take the photo's own height, so a tall shot is shown
     tall instead of being letterboxed into a fixed 4:3 box. Past max-height
     the box stops growing and object-fit crops the top and bottom rather
     than squashing the subject. */
  width: 100%;
  height: auto;
  max-height: 70vh;
  object-fit: cover;
  object-position: center;
  background-size: cover; background-position: center;
}

/* Loading state visuals for image-bearing elements:
   - LQIP background-image is set inline (a 40 px variant of the real
     photo) — what the user actually sees while waiting.
   - We blur the element while it's still loading and transition the
     blur away when the foreground arrives, for a smooth focus-in.
   - Pulsing color is the fallback for elements with no LQIP (modal
     thumb strip cells inherit the strip's color before their own
     onload fires). */
@keyframes cat-img-pulse {
  0%, 100% { background-color: var(--cat-warm); }
  50%      { background-color: var(--cat-warm2); }
}
/* LQIP backgrounds (set inline on slot/main) make a flat warm tone
   redundant — and visually noisy when the foreground is still lazy
   and the LQIP is already showing. Reserve the pulse-color fallback
   for the modal thumb strip only, where there is no LQIP to begin
   with. */
.cat-modal-thumbs img:not(.loaded) {
  animation: cat-img-pulse 1.2s ease-in-out infinite;
  background-color: var(--cat-warm);
}
.cat-card-thumb-slot,
img.cat-modal-img {
  transition: filter .3s ease;
}
.cat-card-thumb-slot:not(.loaded) {
  filter: blur(12px);
}
img.cat-modal-img:not(.loaded) {
  filter: blur(18px);
}
.cat-card-thumb-slot.loaded {
  background-color: transparent;
}
.cat-modal-img-placeholder {
  width: 100%; aspect-ratio: 4/3;
  background: var(--cat-warm);
  display: flex; align-items: center; justify-content: center;
  color: var(--cat-text3); font-size: .85rem;
}
.cat-modal-thumbs {
  display: flex; gap: 6px; padding: 10px 16px 0;
  overflow-x: auto; scrollbar-width: none;
}
.cat-modal-thumbs::-webkit-scrollbar { display: none; }
.cat-modal-thumbs img {
  height: 56px; width: 56px; object-fit: cover;
  border-radius: 8px; flex-shrink: 0;
  opacity: .5; cursor: pointer; transition: all .15s;
  border: 2px solid transparent;
}
.cat-modal-thumbs img.sel { opacity: 1; border-color: var(--cat-accent); }

.cat-modal-body { padding: 16px; }
.cat-modal-name { font-size: 1.15rem; font-weight: 700; margin-bottom: 4px; }
.cat-modal-price { font-size: 1rem; font-weight: 600; margin-bottom: 6px; }
.cat-modal-meta {
  font-size: .78rem; color: var(--cat-text3); margin-bottom: 12px;
  display: flex; gap: 12px;
}
.cat-modal-desc {
  font-size: .85rem; color: var(--cat-text2); line-height: 1.55;
  margin-bottom: 16px;
}
.cat-modal-desc p { margin: 0 0 .6em; }
.cat-modal-desc p:last-child { margin-bottom: 0; }
.cat-modal-desc strong, .cat-modal-desc b { color: var(--cat-text); }

/* Expandable sections (Maya style) */
.cat-accordion { border-top: 1px solid var(--cat-border); }
.cat-acc-header {
  display: flex; justify-content: space-between; align-items: center;
  padding: 14px 0; cursor: pointer;
  font-size: .85rem; font-weight: 600; color: var(--cat-text);
}
.cat-acc-header .arrow {
  transition: transform .2s; font-size: .75rem; color: var(--cat-text3);
}
.cat-acc-header.open .arrow { transform: rotate(180deg); }
.cat-acc-body {
  display: none; padding: 0 0 14px;
  font-size: .82rem; color: var(--cat-text2); line-height: 1.55;
}
.cat-acc-body.open { display: block; }
.cat-acc-icons { display: flex; gap: 8px; flex-wrap: wrap; padding: 2px 0; }
.cat-acc-icon {
  display: flex; align-items: center; gap: 5px;
  padding: 5px 10px; border-radius: 8px;
  background: var(--cat-warm); font-size: .78rem; color: var(--cat-text2);
}
.cat-acc-icon img { width: 22px; height: 22px; object-fit: contain; flex-shrink: 0; }
.cat-acc-icon .icon-text {
  font-size: .65rem; color: var(--cat-text3); font-weight: 600;
  width: 22px; text-align: center; line-height: 1.1;
}
.cat-nut-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 6px; }
.cat-nut-item {
  padding: 8px 10px; background: var(--cat-warm); border-radius: 8px;
  font-size: .8rem;
}
.cat-nut-item span { display: block; font-weight: 600; color: var(--cat-text); }
.cat-flavors-list { display: flex; flex-wrap: wrap; gap: 6px; }
.cat-flavor-tag {
  padding: 4px 10px; border-radius: 20px;
  background: var(--cat-warm); font-size: .78rem; color: var(--cat-text2);
}

/* ── Qty + Add button ── */
.cat-modal-footer {
  display: flex; gap: 12px; align-items: center;
  padding: 14px 16px 30px;
  border-top: 1px solid var(--cat-border);
}
.cat-qty {
  display: flex; align-items: center;
  background: var(--cat-warm); border-radius: var(--cat-radius-sm); overflow: hidden;
}
.cat-qty button {
  width: 42px; height: 44px; border: none; background: transparent;
  font-family: var(--cat-font); font-size: 1.1rem; font-weight: 500;
  color: var(--cat-text); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.cat-qty button:hover { background: var(--cat-warm2); }
.cat-qty span {
  width: 28px; text-align: center;
  font-size: .95rem; font-weight: 600;
}
.cat-btn-add {
  flex: 1; height: 48px; border: none; border-radius: var(--cat-radius-sm);
  background: var(--cat-accent); color: #fff;
  font-family: var(--cat-font); font-size: .9rem; font-weight: 600;
  cursor: pointer; transition: background .15s;
  letter-spacing: .01em;
}
.cat-btn-add:hover { background: var(--cat-accent-hover); }
.cat-btn-add:active { opacity: .85; }
.cat-btn-add.disabled {
  background: var(--cat-border); color: var(--cat-text3); cursor: not-allowed;
}

/* ── Cart bar ── */
.cat-cart-bar {
  position: fixed; bottom: 0; left: 50%; transform: translateX(-50%);
  width: calc(100% - 32px); max-width: calc(var(--cat-max-w) - 32px);
  padding: 15px 20px; border-radius: var(--cat-radius);
  background: var(--cat-accent); color: #fff;
  font-family: var(--cat-font); font-size: .88rem; font-weight: 600;
  display: none; justify-content: space-between; align-items: center;
  margin-bottom: 16px; cursor: pointer;
  box-shadow: 0 4px 24px rgba(0,0,0,.15);
  animation: catFadeUp .25s ease-out;
  z-index: 50;
}
.cat-cart-bar.show { display: flex; }
@keyframes catFadeUp {
  from { opacity: 0; transform: translateX(-50%) translateY(20px); }
  to { opacity: 1; transform: translateX(-50%) translateY(0); }
}
.cat-cart-bar .arrow { font-size: 1rem; opacity: .7; }

/* ── Cart panel ── */
.cat-cart-overlay {
  position: fixed; inset: 0; z-index: 200;
  background: rgba(26,26,26,.3);
  display: none; justify-content: center; align-items: flex-end;
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
}
.cat-cart-overlay.open { display: flex; }
.cat-cart-panel {
  width: 100%; max-width: var(--cat-max-w);
  max-height: calc(100dvh - 50px); background: var(--cat-card);
  border-radius: 20px 20px 0 0;
  display: flex; flex-direction: column;
  overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: none;
  animation: catSlideUp .3s cubic-bezier(.22,1,.36,1);
}
.cat-cart-panel::-webkit-scrollbar { display: none; }

/* ── Sheet shell (cart, orders) ── */
.cat-sheet-header {
  position: sticky; top: 0; z-index: 2;
  background: var(--cat-card);
  padding: 8px 16px 0;
  flex-shrink: 0; touch-action: none;
  cursor: grab;
  user-select: none; -webkit-user-select: none;
  /* Scroll cue. The shadow is the sheet's own background colour, so it is
     invisible against empty sheet and only shows as a soft fade where a row
     has scrolled underneath — no JS, no scroll listener, nothing to keep in
     sync with a re-render. */
  box-shadow: 0 6px 8px -2px var(--cat-card);
}
.cat-sheet-header.dragging { cursor: grabbing; }
.cat-sheet-handle {
  width: 36px; height: 4px; border-radius: 2px;
  background: var(--cat-border); margin: 0 auto 10px;
  pointer-events: none;
}
.cat-sheet-title-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; padding-bottom: 12px;
  border-bottom: 1px solid var(--cat-border);
}
.cat-sheet-header > .cat-sheet-title {
  /* bare title (e.g. orders panel) carries its own divider */
  padding-bottom: 12px;
  border-bottom: 1px solid var(--cat-border);
}
.cat-sheet-title {
  margin: 0;
  font-size: 1rem; font-weight: 700;
}
.cat-sheet-clear {
  background: none; border: none;
  font-family: var(--cat-font); font-size: .78rem; font-weight: 500;
  color: var(--cat-text3); cursor: pointer;
  padding: 4px 8px; border-radius: 6px;
}
.cat-sheet-clear:hover { color: var(--cat-danger); }
.cat-sheet-body {
  padding: 4px 16px 16px;
  flex: 1 0 auto;
}
.cat-sheet-footer {
  position: sticky; bottom: 0; z-index: 2;
  background: var(--cat-card);
  padding: 12px 16px calc(env(safe-area-inset-bottom, 0px) + 16px);
  border-top: 1px solid var(--cat-border);
  flex-shrink: 0;
  /* Mirror of the header's cue — see there. */
  box-shadow: 0 -6px 8px -2px var(--cat-card);
}
/* Top-aligned, so the price and the × sit on the product name's line and the
   text block starts at the top whether the row below the name is a stepper
   (a single item) or a «N смаків · N шт» summary (a group head, which has no
   stepper to centre against). */
.cat-cart-item {
  display: flex; align-items: flex-start; gap: 10px;
  padding: 12px 0; border-bottom: 1px solid var(--cat-border);
}
.cat-ci-thumb {
  width: 56px; height: 56px; border-radius: 10px;
  object-fit: cover; flex-shrink: 0;
}
.cat-ci-body { flex: 1; min-width: 0; }
.cat-cart-item-name { font-size: .88rem; font-weight: 500; }
/* A cart line's photo and name open the product. Only those two: the row also
   carries the stepper and the ×, where a tap means something else. No underline
   — the cart is a list of things the shopper chose, and dressing their names as
   links makes it read like a page of navigation. */
.cat-ci-thumb.tappable,
.cat-cart-item-name.tappable { cursor: pointer; }
.cat-ci-flavor {
  display: inline-block; font-size: .72rem; color: var(--cat-text2);
  background: var(--cat-warm); padding: 1px 8px; border-radius: 8px;
  margin-top: 2px;
}
/* Not a flavour but a promise of one, so it reads as pending rather than as a
   chosen thing sitting next to chosen things. */
.cat-ci-flavor.random { font-style: italic; color: var(--cat-text3); }
.cat-ci-removed {
  display: inline-block; font-size: .72rem; color: var(--cat-danger);
  background: rgba(176, 0, 0, 0.08); padding: 1px 8px; border-radius: 8px;
  margin-top: 2px;
}
.cat-cart-item.removed {
  padding: 8px 0; align-items: center;
}
.cat-cart-item.removed .cat-cart-item-name {
  opacity: .55; text-decoration: line-through;
}
.cat-cart-item-meta { font-size: .78rem; color: var(--cat-text2); margin-top: 2px; }
/* One product's flavours as a single card: the product identity in the head,
   a compact per-flavour row underneath. The rows sit inside the card's
   bottom border, so they use a lighter inner rule instead of their own. */
.cat-cart-group { padding: 12px 0; border-bottom: 1px solid var(--cat-border); }
/* Same top alignment as .cat-cart-item — the head is that shape exactly:
   [thumb][name over a second line][sum][×]. */
.cat-cg-head { display: flex; align-items: flex-start; gap: 10px; }
/* Only a token indent: stepper + price + × already eat ~180px of a 328px
   sheet, so aligning the rows under the head's text (66px) left too little
   for the name and «Лаванда-чорниця» wrapped to two lines. The hairlines
   and the head above them carry the nesting instead. */
.cat-cg-rows { padding: 6px 0 0 16px; }
/* Same 10px gap as .cat-cart-item, so the row's price column lands on the
   same x as a single item's price instead of 2px right of it. */
.cat-cg-row {
  display: flex; align-items: center; gap: 10px;
  padding: 6px 0;
}
.cat-cg-row + .cat-cg-row { border-top: 1px solid var(--cat-warm2); }
.cat-cg-row:first-child { border-top: 1px solid var(--cat-warm2); }
/* Matches .cat-flavor-name in the picker: the cart is showing back exactly
   what the customer chose there, so the two lists should read alike. */
.cat-cg-name {
  flex: 1; min-width: 0; font-size: .85rem; color: var(--cat-text2);
}
/* Fixed width so the steppers line up in a column: without it a ₴160 row
   pushes its own stepper left of the ₴40 rows either side. */
/* A rung below a standalone line: the head above already states the group's
   figure, so these recede to the same weight and colour as the flavour names
   they sit beside. */
.cat-cg-row .cat-cart-item-price {
  font-size: .82rem; font-weight: 500; color: var(--cat-text2);
  min-width: 4.2em; text-align: right;
}
.cat-cg-thumb {
  width: 28px; height: 28px; border-radius: 6px;
  object-fit: cover; flex-shrink: 0;
}
.cat-ci-bottom {
  display: flex; align-items: center; justify-content: space-between;
  margin-top: 6px; gap: 8px;
}
/* «залишилось 6 шт» — how many of this product can still be ordered for the
   chosen day. Quiet by default: it is context, not a warning. `.at` is when the
   cart has taken all of them, which is also when the + next to it goes dead —
   the colour is what explains the dead button. */
.cat-ci-limit { font-size: .72rem; color: var(--cat-text3); white-space: nowrap; }
.cat-ci-limit.at { color: var(--cat-danger); }
.cat-ci-qty {
  display: flex; align-items: center;
  background: var(--cat-warm); border-radius: 8px; overflow: hidden;
}
.cat-ci-qty button {
  width: 30px; height: 28px; border: none; background: transparent;
  font-family: var(--cat-font); font-size: .9rem; font-weight: 500;
  color: var(--cat-text); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.cat-ci-qty button:hover { background: var(--cat-warm2); }
.cat-ci-qty span {
  width: 22px; text-align: center; font-size: .82rem; font-weight: 600;
}
/* Reads as the plain number it replaced until focused. 2.6em fits three
   digits — wholesale quantities run past 99 — and the field is centred so it
   stays visually identical to the old <span> at one digit. */
.cat-ci-qty-input {
  width: 2.6em; height: 24px; padding: 0;
  border: none; background: transparent;
  font-family: var(--cat-font); font-size: .82rem; font-weight: 600;
  color: var(--cat-text); text-align: center;
  appearance: none; -webkit-appearance: none;
}
/* Height comes from the rule above rather than the text's line box, so the
   focus ring is a proportionate rounded rect inside the 28px stepper instead
   of a band pinched around the digits. */
.cat-ci-qty-input:focus {
  outline: none;
  background: var(--cat-card);
  border-radius: 6px;
  box-shadow: inset 0 0 0 1.5px var(--cat-text);
}
.cat-btn-remove {
  border: none; background: transparent; color: var(--cat-text3);
  font-size: .8rem; cursor: pointer; padding: 4px;
  transition: color .15s; flex-shrink: 0;
}
/* In the top-aligned rows the button's own 4px of padding lands its glyph 3px
   below the name and the price beside it. Negative margin rather than less
   padding, so the tap target keeps its size. Flavour rows are centred and
   need no correction. */
.cat-cart-item > .cat-btn-remove,
.cat-cg-head > .cat-btn-remove { margin-top: -3px; }
.cat-btn-remove:hover { color: var(--cat-danger); }

/* ── Bundles ──
   A bundle is a product, so it needs no card of its own — these style the
   set builder inside the product modal: the size pills, the contents of a
   fixed set, and the pick list of a build-your-own one. */
.cat-bundle-sizes {
  display: flex; gap: 6px; flex-wrap: wrap;
  margin-bottom: 14px;
}
.cat-size-btn {
  padding: 6px 14px; border-radius: 16px;
  border: 1px solid var(--cat-border);
  background: var(--cat-card);
  font-family: var(--cat-font);
  font-size: .78rem; font-weight: 500; color: var(--cat-text2);
  cursor: pointer; transition: all .12s;
}
.cat-size-btn.active {
  background: var(--cat-accent); color: #fff; border-color: var(--cat-accent);
}
.cat-bundle-contents {
  background: var(--cat-warm); border-radius: var(--cat-radius);
  padding: 10px 12px; margin-bottom: 14px;
}
.cat-bundle-contents-title {
  font-size: .7rem; font-weight: 600; text-transform: uppercase;
  letter-spacing: .04em; color: var(--cat-text3);
  margin-bottom: 6px;
}
.cat-bundle-row {
  display: flex; gap: 8px; align-items: baseline;
  font-size: .82rem; padding: 2px 0;
}
.cat-bundle-row-qty {
  font-weight: 700; font-variant-numeric: tabular-nums;
  color: var(--cat-text2); min-width: 24px;
}
.cat-bundle-row-name { min-width: 0; }
/* What the pieces cost bought loose, struck through next to what the set
   costs — the only honest way to show a saving is to show both numbers. */
.cat-bundle-saving {
  margin-top: 6px; font-size: .74rem; color: var(--cat-text3);
  text-decoration: line-through;
}
.cat-bundle-note {
  margin-top: 6px; font-size: .74rem; color: var(--cat-text3);
}
.cat-bundle-picker { margin-bottom: 14px; }
/* The «здивуйте мене» row. Tinted and italic so it reads as a different kind of
   choice from the flavours under it — it is not one of them, it is a decision
   to let someone else choose. */
.cat-pick-item.random {
  background: var(--cat-warm);
  border-radius: var(--cat-radius);
}
.cat-pick-item.random .cat-pick-name { font-style: italic; }
.cat-pick-item.random .cat-pick-img {
  display: flex; align-items: center; justify-content: center;
  color: var(--cat-text3);
}

/* ── Flavor picker ── */
.cat-flavor-picker {
  margin-bottom: 16px;
}
.cat-flavor-pick {
  display: inline-block; padding: 6px 14px; margin: 3px 4px 3px 0;
  border-radius: 20px; border: 1.5px solid var(--cat-border);
  background: var(--cat-card); font-family: var(--cat-font);
  font-size: .82rem; color: var(--cat-text2); cursor: pointer;
  transition: all .15s;
}
.cat-flavor-pick:hover { border-color: var(--cat-text3); }
.cat-flavor-pick.selected {
  background: var(--cat-accent); color: #fff; border-color: var(--cat-accent);
}
/* «Випадковий смак» among the named ones: italic and dashed, because it is not
   one of them — it is the choice not to choose. Selected, it goes solid like any
   other pick; it is a real answer once given. */
.cat-flavor-pick.random {
  font-style: italic; border-style: dashed;
}
.cat-flavor-pick.random.selected { border-style: solid; font-style: normal; }
.cat-flavor-pick:disabled, .cat-flavor-pick.disabled {
  opacity: .45;
  text-decoration: line-through;
  cursor: not-allowed;
}
.cat-flavor-pick:disabled:hover, .cat-flavor-pick.disabled:hover {
  border-color: var(--cat-border);
}

/* The printed minimum, shown for products that use the plain qty stepper.
   The multi-flavour picker carries its own counter instead. */
.cat-min-note {
  font-size: .78rem; color: var(--cat-text3);
  background: var(--cat-warm); border-radius: 8px;
  padding: 8px 10px; margin-bottom: 14px;
}

/* ── Multi-flavour picker ──
   Used when a product's minimum is counted across its own flavours
   (macarons: ten in any mix), so each flavour needs its own count and the
   header carries the running total against the minimum. */
.cat-flavor-picker-title {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; margin-bottom: 8px;
}
.cat-flavor-counter {
  font-size: .8rem; font-weight: 700; color: var(--cat-text3);
  padding: 2px 8px; border-radius: 20px; background: var(--cat-warm);
}
.cat-flavor-counter.ok { color: var(--cat-sage); background: var(--cat-sage-lo); }
.cat-flavor-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; padding: 6px 0;
  border-bottom: 1px solid var(--cat-border);
}
.cat-flavor-row:last-child { border-bottom: 0; }
.cat-flavor-row.disabled { opacity: .45; text-decoration: line-through; }
/* «Випадковий смак» — the first row, and not one of the flavours under it. Set
   apart because it is a different kind of choice: not "this one" but "you
   choose". The dice stands where the others carry a thumbnail, so the column
   still lines up. */
.cat-flavor-row.random {
  background: var(--cat-warm);
  border-radius: var(--cat-radius);
  /* The negative margin is the point: the tint needs padding to be a band
     rather than a stripe, and padding pushed this row's dice and name 8px in
     while every flavour under it started flush. Pulling the box out by exactly
     what it pads in keeps one content column down the list and lets the
     highlight sit wider than the rows it leads. */
  padding: 6px 8px;
  margin: 0 -8px 4px;
  border-bottom: 0;
}
.cat-flavor-row.random .cat-flavor-name { font-style: italic; }
.cat-flavor-dice {
  flex-shrink: 0;
  width: 34px; height: 34px; margin-right: 10px;
  display: flex; align-items: center; justify-content: center;
  color: var(--cat-text3);
}
.cat-flavor-thumb {
  flex-shrink: 0;
  width: 34px; height: 34px; margin-right: 10px;
  border-radius: 8px; object-fit: cover;
  background: var(--cat-warm);
}
.cat-flavor-name { font-size: .85rem; color: var(--cat-text2); flex: 1; }
.cat-flavor-qty { display: flex; align-items: center; gap: 10px; }
.cat-flavor-qty button {
  width: 28px; height: 28px; border-radius: 50%;
  border: 1.5px solid var(--cat-border); background: var(--cat-card);
  font-family: var(--cat-font); font-size: 1rem; line-height: 1;
  color: var(--cat-text2); cursor: pointer;
}
.cat-flavor-qty button:disabled { opacity: .35; cursor: not-allowed; }
.cat-flavor-qty b { min-width: 1.4em; text-align: center; font-size: .9rem; }

/* ── Custom picker ── */
.cat-pick-counter {
  text-align: center; font-size: .85rem; font-weight: 600;
  color: var(--cat-text2); margin: 10px 0;
  padding: 8px; background: var(--cat-warm); border-radius: 8px;
}
.cat-pick-counter.done { color: var(--cat-sage); background: var(--cat-sage-lo); }
.cat-pick-list { display: flex; flex-direction: column; gap: 6px; }
.cat-pick-item {
  display: flex; align-items: center; gap: 10px;
  padding: 8px; background: var(--cat-warm); border-radius: var(--cat-radius-sm);
}
.cat-pick-img {
  width: 44px; height: 44px; border-radius: 8px;
  overflow: hidden; flex-shrink: 0; background: var(--cat-card);
}
.cat-pick-img img { width: 100%; height: 100%; object-fit: cover; }
.cat-pick-name { flex: 1; font-size: .82rem; font-weight: 500; }
.cat-pick-qty {
  display: flex; align-items: center; gap: 0;
  background: var(--cat-card); border-radius: 8px; overflow: hidden;
}
.cat-pick-qty button {
  width: 32px; height: 32px; border: none; background: transparent;
  font-family: var(--cat-font); font-size: 1rem; font-weight: 500;
  color: var(--cat-text); cursor: pointer;
  display: flex; align-items: center; justify-content: center;
}
.cat-pick-qty button:disabled { color: var(--cat-border); cursor: default; }
.cat-pick-qty button:not(:disabled):hover { background: var(--cat-warm); }
.cat-pick-qty span {
  width: 22px; text-align: center; font-size: .85rem; font-weight: 600;
}

/* ── Unavailable / low stock ── */
/* Out-of-stock cards stay tappable so the modal can show details; the
   modal's Add button is what stops the purchase. */
.cat-card.unavailable {
  opacity: .55; position: relative;
}
.cat-card.unavailable::after {
  content: 'Немає в наявності';
  position: absolute; top: 8px; right: 8px;
  font-size: .65rem; font-weight: 600; color: var(--cat-danger);
  background: #FEF2F2; padding: 2px 8px; border-radius: 6px;
}
.cat-card.low-stock {
  position: relative;
}
.cat-card.low-stock::after {
  content: 'Закінчується';
  position: absolute; top: 8px; right: 8px;
  font-size: .65rem; font-weight: 600; color: #B45309;
  background: #FEF3C7; padding: 2px 8px; border-radius: 6px;
}

/* ── Recommendations ── */
.cat-banner {
  margin: 12px 0; padding: 14px 16px;
  background: var(--cat-warm); border-radius: var(--cat-radius);
  display: flex; align-items: center; gap: 12px;
  cursor: pointer; transition: all .15s;
}
.cat-banner:hover { background: var(--cat-warm2); }
.cat-banner-icon { font-size: 1.3rem; flex-shrink: 0; }
.cat-banner-body { flex: 1; }
.cat-banner-title { font-size: .88rem; font-weight: 600; }
.cat-banner-sub { font-size: .75rem; color: var(--cat-text2); }

.cat-recs {
  display: grid; gap: 8px;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  margin: 12px 0;
}
.cat-rec-card {
  display: flex; align-items: center; gap: 10px;
  padding: 10px 12px;
  background: var(--cat-warm); border-radius: var(--cat-radius);
  cursor: pointer; transition: background .15s;
  min-width: 0;
}
.cat-rec-card:hover { background: var(--cat-warm2); }
.cat-rec-icon {
  font-size: 1.4rem; flex-shrink: 0;
  width: 44px; height: 44px;
  display: flex; align-items: center; justify-content: center;
  background: var(--cat-card); border-radius: var(--cat-radius-sm);
}
.cat-rec-thumb {
  width: 44px; height: 44px; border-radius: var(--cat-radius-sm);
  object-fit: cover; background: var(--cat-warm2); flex-shrink: 0;
}
.cat-rec-body { flex: 1; min-width: 0; }
.cat-rec-label {
  font-size: .68rem; font-weight: 600; color: var(--cat-text3);
  text-transform: uppercase; letter-spacing: .04em;
}
.cat-rec-title {
  font-size: .88rem; font-weight: 600; margin-top: 1px;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cat-rec-sub { font-size: .75rem; color: var(--cat-text2); }

/* ── Special-mode views (search / favorites / untried) ── */
.cat-search-bar { padding: 12px 0 10px; }
.cat-search-bar input {
  width: 100%; box-sizing: border-box;
  padding: 10px 14px;
  border-radius: var(--cat-radius);
  border: 1px solid var(--cat-border);
  background: var(--cat-card);
  color: var(--cat-text);
  font: inherit; font-size: .9rem;
  -webkit-appearance: none;
}
.cat-search-bar input:focus {
  outline: none; border-color: var(--cat-text3);
}
.cat-empty {
  padding: 32px 8px; text-align: center;
  color: var(--cat-text3); font-size: .85rem;
}

/* ── View-mode swipe transitions ── */
@keyframes catSlideInLeft {
  from { transform: translateX(-100%); opacity: 0; }
  to   { transform: translateX(0);     opacity: 1; }
}
@keyframes catSlideInRight {
  from { transform: translateX(100%);  opacity: 0; }
  to   { transform: translateX(0);     opacity: 1; }
}
.cat-list.slide-in-left  { animation: catSlideInLeft  220ms cubic-bezier(.2,.8,.2,1); }
.cat-list.slide-in-right { animation: catSlideInRight 220ms cubic-bezier(.2,.8,.2,1); }

/* ── Profile / Admin / Orders ── */
.cat-profile-btn,
.cat-admin-btn {
  background: none; border: 1px solid var(--cat-border);
  border-radius: 50%; width: 28px; height: 28px;
  display: flex; align-items: center; justify-content: center;
  cursor: pointer; font-size: .85rem; color: var(--cat-text2);
  transition: all .15s; margin-right: 6px;
}
.cat-profile-btn:hover,
.cat-admin-btn:hover { border-color: var(--cat-text3); }
.cat-profile-btn.has-orders { border-color: var(--cat-accent); color: var(--cat-accent); }
.cat-orders-panel {
  width: 100%; max-width: var(--cat-max-w);
  max-height: calc(100dvh - 50px); background: var(--cat-card);
  border-radius: 20px 20px 0 0;
  display: flex; flex-direction: column;
  overflow-y: auto; overscroll-behavior: contain;
  scrollbar-width: none;
  animation: catSlideUp .3s cubic-bezier(.22,1,.36,1);
}
.cat-orders-panel::-webkit-scrollbar { display: none; }
.cat-order-card {
  margin-bottom: 4px;
  background: var(--cat-warm); border-radius: 8px;
  overflow: hidden;
}
.cat-order-card > summary {
  padding: 8px 10px;
  display: grid; grid-template-columns: 1fr auto 28px;
  column-gap: 8px; row-gap: 2px; align-items: center;
  cursor: pointer;
  list-style: none;
  user-select: none; -webkit-user-select: none;
}
.cat-order-card > summary::-webkit-details-marker { display: none; }
.cat-order-card[open] > summary {
  border-bottom: 1px solid var(--cat-border);
}
.cat-order-date {
  font-size: .72rem; color: var(--cat-text3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.cat-order-total {
  font-size: .82rem; font-weight: 700; color: var(--cat-text);
  white-space: nowrap; font-variant-numeric: tabular-nums;
}
.cat-order-summary {
  grid-column: 1 / -1;
  font-size: .76rem; color: var(--cat-text2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.cat-order-summary .unavail { color: var(--cat-danger); text-decoration: line-through; }
.cat-order-repeat {
  width: 28px; height: 28px;
  border: 1px solid var(--cat-border); background: var(--cat-card);
  border-radius: 6px; cursor: pointer;
  display: flex; align-items: center; justify-content: center;
  font: inherit; font-size: 1rem; color: var(--cat-text2);
  transition: all .12s ease; padding: 0;
}
.cat-order-repeat:hover { color: var(--cat-text); border-color: var(--cat-text3); }

/* Expanded order detail */
.cat-order-detail {
  padding: 8px 10px;
  display: flex; flex-direction: column; gap: 4px;
}
.cat-order-detail-item {
  display: grid; grid-template-columns: 1fr auto;
  gap: 10px; align-items: baseline;
  font-size: .8rem; color: var(--cat-text);
}
.cat-order-detail-item .price {
  font-weight: 600; font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
/* A line whose product is out of stock, hidden or retired. Struck through so
   the state is obvious inside the expanded order, matching the collapsed
   summary — «Повторити» will skip it or offer a replacement. */
.cat-order-detail-item.unavail { color: var(--cat-text3); }
.cat-order-detail-item.unavail > span:first-child { text-decoration: line-through; }
.cat-order-detail-item.unavail .price {
  text-decoration: line-through; font-weight: 500;
}
.cat-order-detail-sub {
  font-size: .72rem; color: var(--cat-text2);
  margin-left: 0; padding-left: 0;
  line-height: 1.45;
}

/* ── Repeat order preview ── */
.cat-rep-list { display: flex; flex-direction: column; gap: 2px; }
.cat-rep-line {
  display: flex; justify-content: space-between; align-items: flex-start;
  padding: 10px 0; border-bottom: 1px solid var(--cat-border);
  gap: 8px;
}
.cat-rep-line:last-child { border-bottom: none; }
.cat-rep-ok { flex: 1; min-width: 0; }
.cat-rep-name { font-size: .85rem; font-weight: 500; }
.cat-rep-meta { font-size: .75rem; color: var(--cat-text2); }
.cat-rep-price { font-size: .85rem; font-weight: 700; white-space: nowrap; flex-shrink: 0; }
.cat-rep-price.struck { text-decoration: line-through; color: var(--cat-text3); font-weight: 500; }
.cat-rep-line.unavail { border-bottom: none; padding-bottom: 4px; }
.cat-rep-struck { flex: 1; min-width: 0; }
.cat-rep-struck .cat-rep-name {
  text-decoration: line-through; color: var(--cat-text3);
}
.cat-rep-badge {
  display: inline-block; margin-top: 2px;
  font-size: .65rem; font-weight: 600; color: var(--cat-danger);
  background: #FEF2F2; padding: 1px 6px; border-radius: 4px;
}
.cat-rep-options { padding: 4px 0 10px 0; border-bottom: 1px solid var(--cat-border); }
.cat-rep-options-label {
  font-size: .72rem; font-weight: 600; color: var(--cat-text3);
  margin-bottom: 4px;
}
.cat-rep-chosen { padding: 4px 0 10px 0; border-bottom: 1px solid var(--cat-border); }
.cat-rep-hint {
  font-size: .78rem; color: var(--cat-text3); text-align: center;
  margin-top: 8px; font-style: italic;
}
.cat-replacement {
  display: flex; align-items: center; gap: 8px;
  padding: 7px 10px; margin-top: 4px;
  background: var(--cat-warm); border-radius: 8px;
  font-size: .8rem; color: var(--cat-text);
  cursor: pointer; transition: all .15s;
}
.cat-replacement:hover { background: var(--cat-warm2); }
.cat-replacement.selected {
  background: var(--cat-warm2); border: 1.5px solid var(--cat-accent);
}
.cat-replacement img {
  width: 36px; height: 36px; border-radius: 6px; object-fit: cover; flex-shrink: 0;
}
.cat-replacement-price { margin-left: auto; font-weight: 700; font-size: .8rem; }
.cat-rep-change {
  margin-left: 4px; font-size: .7rem; color: var(--cat-text3);
  cursor: pointer;
}

/* ── Cart recommendation ── */
.cat-cart-recs { margin-top: 12px; padding-top: 12px; }
.cat-cart-recs-title { font-size: .78rem; font-weight: 600; color: var(--cat-text3); margin-bottom: 8px; }
.cat-cart-rec-item {
  display: flex; align-items: center; gap: 10px;
  padding: 8px; margin-bottom: 6px;
  background: var(--cat-warm); border-radius: var(--cat-radius-sm);
  cursor: pointer; transition: all .15s;
}
.cat-cart-rec-item:hover { background: var(--cat-warm2); }
.cat-cart-rec-item img { width: 40px; height: 40px; border-radius: 8px; object-fit: cover; }
.cat-cart-rec-info { flex: 1; }
.cat-cart-rec-name { font-size: .82rem; font-weight: 500; }
.cat-cart-rec-price { font-size: .78rem; font-weight: 700; }
.cat-cart-rec-add {
  padding: 4px 12px; border-radius: 8px; border: none;
  background: var(--cat-accent); color: #fff;
  font-family: var(--cat-font); font-size: .72rem; font-weight: 600;
  cursor: pointer;
}

/* ── Prices ── */
.cat-modal-price {
  font-size: 1.15rem; font-weight: 700; color: var(--cat-text); margin-bottom: 8px;
}
.cat-cart-item-right {
  display: flex; align-items: center; gap: 10px; flex-shrink: 0;
}
/* Money reads in three steps: line prices, then subtotals, then the one
   figure being committed to. Line prices used to be 700 — the boldest text in
   the sheet, heavier than the totals they add up to, which read the hierarchy
   backwards. */
.cat-cart-item-price {          /* 1 — a line */
  font-size: .85rem; font-weight: 500; color: var(--cat-text);
  white-space: nowrap;
}
.cat-cg-head .cat-cart-item-price {   /* 2 — a group's subtotal */
  font-size: .9rem; font-weight: 600;
}
/* Footer summary lines. Both totals and the single-zone fee share this shape,
   so every figure in the footer sits in one right-hand money column. */
.cat-sum-line {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px; padding: 4px 0 10px; width: 100%;
  background: none; border: none; text-align: left;
  font: inherit; font-size: .95rem; font-weight: 600; color: var(--cat-text);
}
.cat-sum-line.muted { font-size: .9rem; font-weight: 400; color: var(--cat-text2); }
/* Разом, Доставка and До сплати are one sum read down the page, so they share
   this shape and differ only in weight. The label may carry a second line —
   the zone and the day — without pushing the amount out of the column. */
.cat-sum-label { display: flex; flex-direction: column; gap: 1px; min-width: 0; }
.cat-sum-sub {
  font-size: .76rem; font-weight: 400; color: var(--cat-text2);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
/* The delivery row is a button when it folds; nothing about it should look
   like one, so the only tell is a chevron on the label. The word «Змінити»
   sat where the amount now goes, and the amount has the better claim to that
   column — it is the middle figure of Разом → Доставка → До сплати. */
.cat-foot-head { cursor: pointer; }
.cat-sum-head { display: inline-flex; align-items: center; gap: 5px; }
/* The chevron every <select> on this page already draws — same path, same
   1.8 stroke, same round caps — so the one control that expands looks like the
   ones that drop down. A ▾ glyph is a filled triangle and reads far heavier;
   two rotated borders needed a per-state nudge to stay centred and looked
   wrong open. An SVG rotates about its own centre and needs neither. */
/* Right when closed, down when open — the convention the admin's category tree
   already uses, and the one that reads as "this contains something" rather
   than as an up/down toggle. The path is drawn pointing down, so closed is the
   rotated state, and the box is square so the glyph does not walk sideways as
   it turns. */
.cat-caret {
  flex-shrink: 0; color: var(--cat-text2);
  transform: rotate(-90deg);
  transition: transform .2s ease;
}
.cat-caret.open { transform: rotate(0deg); }
/* The delivery block, a labelled section between the order and what is owed.
   Hairlines rather than a card: it is a division of the footer, not an object
   sitting in it. */
.cat-foot-section {
  border-top: 1px solid var(--cat-border);
  padding: 8px 0 10px;
}
/* Kept for the admin-facing sections that still use it; the cart footer's
   delivery heading is a .cat-sum-line now, so it reads with Разом and До
   сплати instead of as a small uppercase label of its own. */
.cat-foot-section-title {
  font-size: .7rem; font-weight: 600; letter-spacing: .07em;
  text-transform: uppercase; color: var(--cat-text3);
  margin-bottom: 6px;
}
/* Inside the section the hint is a note on the lines above it, so it reads
   from the left like they do — the centring only made sense when it floated
   alone above the button. */
.cat-foot-section .cat-ship-hint {
  text-align: left; margin-bottom: 6px;
}
/* The final total — the one figure the customer is committing to, so it keeps
   the heavy rule and the largest type in the footer. */
.cat-cart-total {
  display: flex; align-items: baseline; justify-content: space-between;
  gap: 10px;
  padding: 10px 0 12px;
  font-size: 1.15rem; font-weight: 700; color: var(--cat-text);
  border-top: 2px solid var(--cat-text);
}
/* Was the muted grey treatment for money floors — which are blockers, so they
   now share the box below with every other reason checkout is disabled. */
/* A blocker, not a hint: this is the reason checkout is disabled, so it gets
   weight, colour and an icon rather than the muted grey of the advisory
   lines above. */
.cat-cart-block {
  display: flex; align-items: flex-start; gap: 9px;
  margin: 0 0 10px; padding: 10px 12px;
  border-radius: var(--cat-radius-sm);
  background: #FEF2F2; border: 1px solid #FBD5D5;
  color: var(--cat-danger);
  font-size: .84rem; font-weight: 600; line-height: 1.4;
  text-align: left;
}
.cat-cart-block-body { min-width: 0; }
/* A list for what it is — several reasons — but not indented and not
   bulleted: the icon on the left is already the marker, and an indent inside a
   box this narrow just loses characters off the right. */
.cat-cart-block-body ul {
  margin: 0; padding-left: 0; list-style: none;
  font-weight: 500;
}
.cat-cart-block-body li { margin-bottom: 2px; }
.cat-cart-block-body li:last-child { margin-bottom: 0; }
.cat-cart-block-icon {
  flex-shrink: 0;
  width: 18px; height: 18px; margin-top: 1px;
  border-radius: 50%;
  background: var(--cat-danger); color: #fff;
  font-size: .72rem; font-weight: 700;
  display: flex; align-items: center; justify-content: center;
}
/* Delivery-fee line + free-shipping / fulfilment hints in the cart footer. */
.cat-cart-feeline {
  display: flex; justify-content: space-between; align-items: baseline;
  font-size: .9rem; color: var(--cat-text2);
  padding: 4px 0; margin-bottom: 4px;
}
.cat-ship-hint {
  margin-bottom: 10px;
  font-size: .82rem; line-height: 1.35; color: var(--cat-accent, var(--cat-text3));
  text-align: center;
}
/* Folded, the delivery row is the section: it carries the top hairline the
   open section would have had. */
.cat-foot-folded { border-top: 1px solid var(--cat-border); padding-top: 10px; }

/* ── The cart on a small phone ──
   Measured on a 320×700 screen: the footer took 602px of the 650px sheet,
   leaving 320px for the cart itself — the customer scrolls a sliver of their
   own order under a wall of controls. None of the trims below remove
   anything; they take the air out of the parts that are always on screen so
   the lines get it back.

   Keyed on height as well as width: a wide-but-short phone in landscape has
   exactly the same problem. */
@media (max-width: 380px), (max-height: 740px) {
  .cat-foot-section { padding: 6px 0 6px; }
  .cat-foot-section-title { margin-bottom: 4px; }
  .cat-date-pick { padding: 2px 0; margin-bottom: 4px; }
  .cat-comment-pick { margin-bottom: 4px; }
  /* One row instead of two. It is optional and usually empty; typing still
     scrolls inside it, and the drag handle is still there to grow it. */
  .cat-comment-input { min-height: 0; padding: 7px 10px; }
  .cat-comment-input:not(:focus) { height: 36px; }
  .cat-zone-opt { padding-top: 7px; padding-bottom: 7px; }
  .cat-cart-total { padding-top: 6px; }
  /* The blockers stay red and stay above the button — only tighter. */
  .cat-cart-block { padding: 8px 10px; font-size: .8rem; line-height: 1.35; }
  /* nothing to re-indent here now — the list is flush at every width */
}

/* Delivery zone choice. Rendered as buttons with a radio glyph rather than
   real <input type=radio>: the whole row has to be tappable on a phone, and
   the footer is re-rendered from state on every change, which would fight a
   native input's own checked state. */
/* One line per zone: radio, label, and the price in the same right-hand money
   column as every other figure in the footer. Single-row rather than a
   label-over-subline stack — the price *is* the detail, so a second line was
   restating it. */
/* No box and no inner padding: the rows span the footer exactly like the
   delivery-fee line and the total, so every price in the footer shares one
   right edge. A bordered container would inset them by its border + padding. */
.cat-zone-pick { margin-bottom: 6px; }
.cat-zone-opt {
  /* flex-wrap so the advice can sit on its own line *inside* the chosen row:
     radio + label + price stay on line one, centred against each other, and
     the advice takes a full-width second line. Stacking the label and advice
     in a nested column instead would drag the price off the label's line. */
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px; width: 100%;
  padding: 9px 0; text-align: left; cursor: pointer;
  font-family: var(--cat-font);
  background: transparent; border: none;
}
.cat-zone-opt + .cat-zone-opt { border-top: 1px solid var(--cat-border); }
.cat-zone-radio {
  flex-shrink: 0; width: 16px; height: 16px; border-radius: 50%;
  border: 1.5px solid var(--cat-border);
}
.cat-zone-opt.active .cat-zone-radio {
  border-color: var(--cat-text);
  /* Inset ring rather than a nested element — one box, no extra markup. */
  box-shadow: inset 0 0 0 3.5px var(--cat-card), inset 0 0 0 16px var(--cat-text);
}
.cat-zone-label {
  flex: 1; min-width: 0;
  font-size: .85rem; color: var(--cat-text2);
}
.cat-zone-price { font-size: .85rem; color: var(--cat-text3); white-space: nowrap; }
/* Only the chosen row commits to full contrast; the rest stay light so the
   selection reads at a glance without a fill or a heavier border. */
.cat-zone-opt.active .cat-zone-label { color: var(--cat-text); font-weight: 500; }
.cat-zone-opt.active .cat-zone-price { color: var(--cat-text); font-weight: 600; }
/* The free-delivery advice, on its own line within the chosen row and indented
   to the label column (radio 16px + the row's 10px gap). */
.cat-zone-advice {
  flex-basis: 100%; margin: -4px 0 0 26px;
  font-size: .78rem; line-height: 1.35; color: var(--cat-text2);
}

/* A way into the requisites form from the cart itself. */
.cat-req-link { margin-bottom: 10px; }
.cat-req-link button {
  width: 100%; cursor: pointer;
  font-family: var(--cat-font); font-size: .82rem; font-weight: 500;
  color: var(--cat-text2); text-align: left;
  background: transparent; border: 0;
  text-decoration: underline;
}
.cat-req-link button:hover { color: var(--cat-text); border-color: var(--cat-text3); }

/* Order comment. Sits directly above the order button — the last thing the
   customer passes on their way out. */
.cat-comment-pick { margin-bottom: 10px; }
.cat-comment-input {
  width: 100%; resize: vertical;
  font-family: var(--cat-font); font-size: .85rem; line-height: 1.35;
  color: var(--cat-text); background: var(--cat-card);
  padding: 9px 12px; border-radius: 10px;
  border: 1.5px solid var(--cat-border);
}
.cat-comment-input::placeholder { color: var(--cat-text3); }
.cat-comment-input:focus { outline: none; border-color: var(--cat-text); }

/* Delivery-date row. Label left, field right, matching .cat-cart-feeline's
   split so the footer's rows share one rhythm. */
/* The field sits straight after its label rather than being pushed to the far
   right: it is the label's value, not a figure in the money column, and a gap
   the width of the sheet between the two made them read as unrelated. */
.cat-date-pick {
  display: flex; align-items: center; justify-content: flex-start;
  gap: 10px; padding: 4px 0; margin-bottom: 8px;
}
.cat-date-pick label { font-size: .9rem; color: var(--cat-text2); }
.cat-date-input {
  font-family: var(--cat-font); font-size: .88rem; font-weight: 600;
  color: var(--cat-text);
  padding: 7px 10px; border-radius: 8px;
  border: 1.5px solid var(--cat-border); background: var(--cat-card);
  /* iOS renders date inputs at a fixed intrinsic width and ignores the
     inherited line-height; both need pinning or the field sits taller than
     the row and clips its own text. */
  min-height: 34px; line-height: 1.2;
  appearance: none; -webkit-appearance: none;
}
.cat-date-input:focus {
  outline: none; border-color: var(--cat-text);
}
/* A supplier with delivery days renders the picker as a list of them instead
   of a date field. `appearance: none` above takes the native arrow with it,
   so the caret is drawn back on — without it the control reads as a text box
   that mysteriously refuses typing. */
select.cat-date-input {
  padding-right: 28px;
  background-image: linear-gradient(45deg, transparent 50%, var(--cat-text2) 50%),
                    linear-gradient(135deg, var(--cat-text2) 50%, transparent 50%);
  background-position: calc(100% - 15px) 47%, calc(100% - 10px) 47%;
  background-size: 5px 5px, 5px 5px;
  background-repeat: no-repeat;
}

/* ── Telegram Login prompt ── */
.cat-login-overlay {
  position: fixed; inset: 0; z-index: 300;
  background: rgba(26,26,26,.45);
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
  backdrop-filter: blur(4px); -webkit-backdrop-filter: blur(4px);
  animation: catFadeIn .15s ease-out;
}
@keyframes catFadeIn { from { opacity: 0; } to { opacity: 1; } }
.cat-login-card {
  width: 100%; max-width: 320px;
  background: var(--cat-card); border-radius: var(--cat-radius);
  padding: 28px 24px 20px;
  display: flex; flex-direction: column; align-items: center; gap: 8px;
  text-align: center;
  box-shadow: 0 12px 40px rgba(0,0,0,.18);
  animation: catSlideUp .25s cubic-bezier(.22,1,.36,1);
}
.cat-login-title {
  font-size: 1.05rem; font-weight: 700; color: var(--cat-text);
  margin: 0; line-height: 1.3;
}
.cat-login-sub {
  font-size: .82rem; color: var(--cat-text2); margin: 0 0 8px;
  line-height: 1.4;
}
.cat-login-widget {
  min-height: 48px;
  display: flex; align-items: center; justify-content: center;
  font-size: .82rem; color: var(--cat-text3);
}
.cat-login-cancel {
  background: none; border: none;
  font-family: var(--cat-font); font-size: .85rem; color: var(--cat-text3);
  cursor: pointer; padding: 8px 14px; margin-top: 4px;
}
.cat-login-cancel:hover { color: var(--cat-text); }

/* Login CTA inside the orders panel for anonymous users */
.cat-orders-login {
  padding: 32px 16px 20px;
  display: flex; flex-direction: column; align-items: center; gap: 16px;
  text-align: center;
}
.cat-orders-login p {
  font-size: .88rem; color: var(--cat-text2); margin: 0;
  max-width: 240px; line-height: 1.4;
}
.cat-btn-tg-login {
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  background: #2AABEE; color: #fff;
  border: none; border-radius: 999px;
  padding: 12px 22px;
  font-family: var(--cat-font); font-size: .9rem; font-weight: 600;
  cursor: pointer; transition: background .15s;
  letter-spacing: .01em;
}
.cat-btn-tg-login:hover { background: #1F95D3; }
.cat-btn-tg-login:active { opacity: .9; }
.cat-btn-tg-login svg { flex-shrink: 0; }

/* ── Customer profile / legal-details sheet ── */
.cat-profile-intro {
  font-size: .85rem; color: var(--cat-text2);
  margin: 0 0 14px; line-height: 1.45;
  background: var(--cat-warm); padding: 10px 12px;
  border-radius: var(--cat-radius-sm);
}
.cat-profile-form {
  display: flex; flex-direction: column; gap: 12px; margin-top: 12px;
}
.cat-profile-field {
  display: flex; flex-direction: column; gap: 4px;
}
.cat-profile-field > span {
  font-size: .76rem; font-weight: 600; color: var(--cat-text2);
  letter-spacing: .01em;
}
.cat-profile-field > span em {
  color: var(--cat-danger); font-style: normal; margin-left: 2px;
}
.cat-profile-field input,
.cat-profile-field textarea {
  font: inherit; font-size: .92rem;
  padding: 10px 12px;
  border: 1px solid var(--cat-border);
  border-radius: var(--cat-radius-sm);
  background: #fff; color: var(--cat-text);
  font-family: var(--cat-font);
}
.cat-profile-field input:focus,
.cat-profile-field textarea:focus {
  outline: none; border-color: var(--cat-text2);
}
.cat-profile-field textarea {
  resize: vertical; min-height: 56px;
}
.cat-profile-hint {
  font-size: .75rem; color: var(--cat-text3);
  margin: 0; line-height: 1.4;
}
.cat-profile-hint em { color: var(--cat-danger); font-style: normal; }
.cat-profile-actions {
  display: flex; gap: 8px; margin-top: 4px;
  justify-content: flex-end;
}
.cat-profile-cancel {
  background: none; border: none;
  font-family: var(--cat-font); font-size: .9rem; color: var(--cat-text2);
  cursor: pointer; padding: 10px 14px; border-radius: var(--cat-radius-sm);
}
.cat-profile-cancel:hover { color: var(--cat-text); background: var(--cat-warm); }

/* The framed storefront's substitute for «Увійти через Telegram»: the Login
   Widget cannot work in a nested frame, so guest checkout keeps the form and
   this opens the shop at the top level instead. Styled as the cancel control
   is — it is the same weight of choice, beside the form rather than in it. */
.cat-guest-open {
  display: block; text-align: center; text-decoration: none;
  font-family: var(--cat-font); font-size: .9rem; color: var(--cat-text2);
  padding: 10px 14px; border-radius: var(--cat-radius-sm);
}
.cat-guest-open:hover { color: var(--cat-text); background: var(--cat-warm); }

/* In the login card it is the only way forward, so it reads as the action
   rather than as a secondary control beside a form. */
.cat-login-card .cat-guest-open {
  margin: 4px 0 2px;
  background: var(--cat-accent);
  color: #fff;
  font-weight: 600;
}
.cat-login-card .cat-guest-open:hover { background: var(--cat-accent-hover); color: #fff; }

/* ── Shared product card (/p/<id>) ──
   The server-rendered page a shared link opens. Same tokens as the catalogue so
   a tenant's branding follows the link, but its own layout: this is one product
   on a page of its own, read by somebody who may never have seen the shop —
   hence the brand header at the top and the two ways in at the bottom.

   No JavaScript takes part. The page has to render for a link-preview crawler
   and inside whatever browser a forwarded link is opened in. */
.cat-pp {
  width: 100%; max-width: var(--cat-max-w);
  margin: 0 auto; background: var(--cat-card);
  min-height: 100dvh;
}
.cat-pp-header {
  padding: 12px 16px; border-bottom: 1px solid var(--cat-border);
}
.cat-pp-brand {
  display: flex; align-items: center; gap: 10px;
  text-decoration: none; color: var(--cat-text);
  font-size: .95rem; font-weight: 600;
}
.cat-pp-hero {
  width: 100%; height: auto; max-height: 70vh;
  object-fit: cover; object-position: center; display: block;
}
.cat-pp-thumbs {
  display: flex; gap: 6px; padding: 8px 16px 0;
  overflow-x: auto; scrollbar-width: none;
}
.cat-pp-thumbs::-webkit-scrollbar { display: none; }
.cat-pp-thumbs img {
  width: 64px; height: 64px; object-fit: cover;
  border-radius: 8px; display: block;
}
.cat-pp-body { padding: 16px; }
.cat-pp-crumb {
  font-size: .72rem; letter-spacing: .06em; text-transform: uppercase;
  color: var(--cat-text3); margin-bottom: 6px;
}
.cat-pp-name {
  font-size: 1.3rem; font-weight: 700; line-height: 1.25;
  color: var(--cat-text);
}
.cat-pp-meta {
  display: flex; flex-wrap: wrap; align-items: center; gap: 10px;
  margin-top: 8px; font-size: .85rem; color: var(--cat-text2);
}
.cat-pp-price { font-size: 1.05rem; font-weight: 700; color: var(--cat-text); }
.cat-pp-out {
  padding: 3px 8px; border-radius: 20px;
  background: var(--cat-warm2); color: var(--cat-text2);
  font-size: .75rem; font-weight: 600;
}
.cat-pp-desc {
  margin-top: 12px; font-size: .88rem; line-height: 1.6;
  color: var(--cat-text2);
}
.cat-pp-desc p { margin-bottom: 8px; }
.cat-pp-section {
  margin-top: 16px; padding-top: 14px;
  border-top: 1px solid var(--cat-border);
  font-size: .84rem; color: var(--cat-text2); line-height: 1.5;
}
.cat-pp-section-title {
  font-size: .75rem; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--cat-text3); margin-bottom: 8px;
}
.cat-pp-chips { display: flex; flex-wrap: wrap; gap: 6px; }
.cat-pp-chip {
  padding: 4px 10px; border-radius: 20px;
  background: var(--cat-warm); font-size: .78rem; color: var(--cat-text2);
}
.cat-pp-actions {
  display: flex; flex-direction: column; gap: 8px; padding: 4px 16px 8px;
}
.cat-pp-btn {
  display: block; padding: 14px; border-radius: var(--cat-radius-sm);
  background: var(--cat-accent); color: #fff;
  font-size: .95rem; font-weight: 600; text-align: center;
  text-decoration: none;
}
.cat-pp-btn-alt {
  background: var(--cat-warm); color: var(--cat-text);
}
.cat-pp .cat-footer { border-top: none; padding-bottom: 32px; }

@media (min-width: 640px) {
  :root { --cat-max-w: 600px; }
  .catalog-app { box-shadow: 0 0 0 1px var(--cat-border), 0 8px 40px rgba(0,0,0,.12); }
  .cat-pp { box-shadow: 0 0 0 1px var(--cat-border), 0 8px 40px rgba(0,0,0,.12); }
}
