/* ══════════════════════════════════════════════════════════════════════════
   VAPEOWO — system wizualny sklepu.
   Serwowany pod /shop/app.css, dolaczany przez blok HTML na mssg.me.

   ── Jezyk projektowy: "aparatura" ─────────────────────────────────────────
   Sklep sprzedaje sprzet, wiec interfejs udaje kartę katalogową urządzeń,
   a nie stronę z promocjami. Stad:
     • ziarno i siatka linii — powierzchnia ma fakturę, nie jest płaskim tłem,
     • etykiety pisane maszynowo (mono, wersaliki, spacja) — jak opis techniczny,
     • numeracja pozycji 01…09 — katalog, nie feed,
     • produkt stoi na "plincie" z poświatą — ekspozycja, nie miniaturka,
     • żółty wyłącznie jako sygnał (cena, jedno CTA, wskaźnik) — nigdy jako tło.

   ── Reguly techniczne ─────────────────────────────────────────────────────
   1. Wszystko zakresowane na #vp — strona mssg.me ma wlasne style.
   2. Animujemy tylko `transform`, `opacity`, `filter`.
   3. Mobile-first, media queries wylacznie w gore.
   ══════════════════════════════════════════════════════════════════════════ */

/* Kroje hostujemy U SIEBIE (/shop/fonts), zamiast ładować z Google: jeden
   serwer mniej, od którego zależy wygląd strony, brak śledzenia klientów przez
   cudzy serwer i o jedno połączenie mniej przy pierwszym wejściu. Plik jest
   pobierany z wyprzedzeniem (`preload` w <head>), więc podmiana kroju dzieje
   się na tyle wcześnie, że praktycznie jej nie widać.

/* DWA KROJE, DWIE ROLE.

   Wcześniej jeden krój (Plus Jakarta Sans) robił nagłówki, treść i ceny naraz.
   Bez kontrastu między rolami wszystko wyglądało jednakowo ważne, czyli
   nieważne — to był główny powód, dla którego strona sprawiała wrażenie
   taniego szablonu.

   ARCHIVO trzyma nagłówki, nazwy produktów i ceny. Jest wąski, więc długa
   nazwa („Oxva Xlim Pro 3 + Lq MerryMi 30ml") mieści się na telefonie
   w jednej linii zamiast łamać się na trzy.

   INSTRUMENT SANS niesie treść, opisy i formularze. Ma szerokie, spokojne
   litery i znika w tle — dokładnie to, czego oczekuje się od tekstu, który ma
   być przeczytany, a nie podziwiany.

   Oba to wersje ZMIENNE: jeden plik obsługuje wszystkie grubości, więc dwa
   kroje kosztują mniej niż wcześniej kosztował jeden w kilku odmianach. */
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 500 700;
  font-display: swap;
  src: url('fonts/archivo-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Archivo';
  font-style: normal;
  font-weight: 500 700;
  font-display: swap;
  src: url('fonts/archivo-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('fonts/instrument-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
    U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191,
    U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Instrument Sans';
  font-style: normal;
  font-weight: 400 600;
  font-display: swap;
  src: url('fonts/instrument-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
    U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020,
    U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

#vp {
  /* ── Powierzchnie ───────────────────────────────────────────────────── */
  --void: #08080a;
  --panel: #0d0d10;
  --raise: #131318;
  --raise-2: #1a1a20;
  --edge: rgba(255, 255, 255, .07);
  --edge-2: rgba(255, 255, 255, .14);

  /* ── Tekst ──────────────────────────────────────────────────────────── */
  --ink: #fbfbfc;
  --dim: #adadb6;
  --faint: #74747f;

  /* ── Sygnał ─────────────────────────────────────────────────────────── */
  /* Akcent zszedł z neonowej żółci (#f5d90a) na stłumione złoto. Tamten żółty
     to najczęstszy kolor akcentu w gotowych szablonach — świeci mocniej niż
     zdjęcia produktów i to on najbardziej ciągnął stronę w stronę „zrobionej
     automatem". Złoto ma ten sam ciężar w hierarchii (dalej jest najjaśniejszym
     punktem na ciemnym tle), ale czyta się jako materiał, nie jako podświetlenie.

     Nazwa zmiennej zostaje `--volt`: używa jej kilkadziesiąt reguł, a zmiana
     samej nazwy nic nie wnosi poza ryzykiem przeoczenia którejś. */
  --volt: #e3b23c;
  --volt-2: #f2cd70;
  --volt-dim: rgba(227, 178, 60, .14);
  --ok: #4ade80;
  --bad: #fb7185;
  --discord: #5865f2;

  /* ── Kształt ────────────────────────────────────────────────────────── */
  --r-xs: 8px;
  --r-sm: 12px;
  --r: 18px;
  --r-lg: 26px;
  --pill: 999px;
  --gut: 20px;
  --max: 1280px;
  /* Wysokosc przyklejonego paska. Hero wsuwa sie POD niego (ujemny margines),
     wiec jego gorny odstep MUSI byc wiekszy od tej wartosci — inaczej pierwsza
     linia hero („Sklep otwarty") lezy pod logotypem i oba napisy sie zlewaja. */
  --nav-h: 62px;

  /* ── Ruch ───────────────────────────────────────────────────────────── */
  --fast: 130ms cubic-bezier(.25, .8, .35, 1);
  --mid: 280ms cubic-bezier(.25, .8, .35, 1);
  --slow: 620ms cubic-bezier(.16, 1, .3, 1);

  /* KROJE — patrz komentarz przy @font-face na górze pliku. */
  --sans: 'Instrument Sans', -apple-system, BlinkMacSystemFont,
          'Segoe UI Variable Text', 'Segoe UI', Roboto, system-ui, sans-serif;
  --display: 'Archivo', -apple-system, BlinkMacSystemFont,
             'Segoe UI Variable Display', 'Segoe UI', sans-serif;
  /* KODY I NUMERY — ten sam krój co reszta strony.

     Wcześniej szły krojem maszynowym (JetBrains Mono). Numer zamówienia, numer
     przesyłki i kod paczkomatu wyglądały wtedy jak wklejone z terminala:
     kwadratowe, obce, z innej rodziny niż wszystko dookoła. Sklep ma wyglądać
     jak sklep, nie jak konsola.

     „Kodowość" niosą teraz odstępy między znakami, a nie inny krój — numer
     nadal czyta się znak po znaku (i łatwiej go przepisać), ale należy do tej
     samej rodziny co cena obok. */
  --mono: var(--display);
  /* LICZBY — ceny, sumy, ilości. Idą krojem nagłówkowym: cena ma być
     najmocniejszym elementem karty, a wąski Archivo daje jej ciężar bez
     rozpychania kafelka. `--mono` zostaje wyłącznie dla tego, co NAPRAWDĘ jest
     kodem: numerów zamówień, przesyłek i kodów paczkomatów. */
  --num: var(--display);

  position: relative;
  isolation: isolate;
  background: var(--void);
  color: var(--ink);
  font-family: var(--sans);
  font-size: 17px;
  line-height: 1.5;
  letter-spacing: -.01em;
  /* WYGLADZANIE CZCIONEK — swiadomie zostawiamy domyslne.
     `-webkit-font-smoothing: antialiased` wylacza subpikselowy rendering
     i na Windowsie zamienia bialy tekst na ciemnym tle w cienkie, wyblakle
     litery — dokladnie to wyglada jak „rozmazane". Efekt jest najmocniejszy
     tam, gdzie drobnego tekstu jest najwiecej, czyli w koszyku i formularzu
     zamowienia. Na macOS ta wlasciwosc bywa poprawa, na Windowsie jest
     pogorszeniem, a wiekszosc klientow jest na Windowsie i Androidzie. */
  text-rendering: optimizeLegibility;
  /* `tnum` trzyma cyfry w równych kolumnach, żeby ceny nie skakały przy
     przeliczaniu koszyka. Kerning i ligatury zostawiamy krojowi — oba mają
     je dopracowane i nie trzeba nic nadpisywać. */
  font-variant-numeric: tabular-nums;
  font-kerning: normal;
  overflow-x: clip;
}

/* ── Wyjście z kolumny hostingu ────────────────────────────────────────────
   mssg.me to platforma typu link-in-bio: KAŻDĄ stronę zamyka w kontenerze
   o sztywnej szerokości 600 px, niezależnie od okna przeglądarki. Bez tego
   cały układ desktopowy — siatka czterech kolumn, panel boczny, dwukolumnowe
   hero — nigdy by się nie pokazał, bo sklep dostawałby 600 px i renderował się
   w wersji telefonowej także na monitorze.

   Szerokość i przesunięcie wpisuje skrypt (`breakOut()` w app.js) na podstawie
   POMIARU rodzica. Nie używamy `100vw`: ta jednostka liczy szerokość razem
   z paskiem przewijania, więc blok wychodziłby kilka pikseli za krawędź.
   Zmienne są puste, dopóki skrypt nie ustali, że hosting nas faktycznie
   ogranicza — w podglądzie lokalnym reguła nic nie zmienia. */
#vp.broke-out {
  width: var(--bleed-w);
  /* Twardy sufit na wypadek, gdyby `--bleed-w` było większe od ekranu:
     przeglądarka i tak przytnie do szerokości okna. Sam skrypt też tego
     pilnuje, ale ta reguła działa nawet ze starym, zakeszowanym app.js. */
  max-width: 100vw;
  margin-left: var(--bleed-x);
}

#vp *, #vp *::before, #vp *::after { box-sizing: border-box; }
#vp h1, #vp h2, #vp h3, #vp p, #vp ul, #vp li { margin: 0; padding: 0; list-style: none; }

/* Nagłówki na wariancie DISPLAY tego samego kroju — różni je waga i ciaśniejsze
   światło, nie inny krój. Trzymamy listę w jednym miejscu, żeby dobór był
   spójny i łatwy do zmiany. */
#vp .hero h1,
#vp .sec-head h2,
#vp .sheet-h h2,
#vp .card-body h3,
#vp .pick-body h3,
#vp .pv h3,
#vp .line .nm {
  font-family: var(--display);
  /* 600, nie 700. Archivo jest wąski i gęsty — w 700 nazwy produktów robią
     się ciężkie i zlewają w czarną plamę. Pełna grubość zostaje dla tego,
     co MA krzyczeć: nagłówka strony i ceny. */
  font-weight: 600;
  letter-spacing: -.03em;
  line-height: 1.15;
}
#vp .hero h1 { font-weight: 700; }

/* INTERLINIA WEDŁUG ROLI.
   Nagłówek to jedna myśl — linie mogą stać blisko siebie (1.15). Treść czyta
   się linia po linii i potrzebuje powietrza (1.6), inaczej oko gubi początek
   następnego wiersza. Wcześniej wszystko dziedziczyło jedną wartość 1.5:
   dla nagłówków za luźno, dla opisów za ciasno. */
#vp p,
#vp .note,
#vp .pv-desc,
#vp .lede,
#vp .faq-a,
#vp .consent { line-height: 1.6; }

/* ETYKIETY. Wersaliki w małym rozmiarze bez rozstrzelenia czytają się jak
   ciąg znaków, nie jak słowo — światło między literami jest tu obowiązkowe. */
#vp .tag,
#vp .sec-label { letter-spacing: .1em; }
/* ══ LICZBY ════════════════════════════════════════════════════════════════
   Kwoty, ilości, numery i kody to JEDNA rodzina razem z resztą strony —
   Archivo, cyfry tabelaryczne, bez wyjątków. Wcześniej numer zamówienia
   i kod paczkomatu szły krojem maszynowym, a część kwot miała lżejszą
   grubość niż tekst obok; efekt był taki, jakby liczby pochodziły z innego
   projektu niż strona.

   Kwota ma być NAJMOCNIEJSZYM elementem tam, gdzie stoi: to po nią klient
   sięga wzrokiem, zanim przeczyta cokolwiek innego. Stąd pełna grubość
   i ciasne światło — wąski Archivo znosi jedno i drugie bez rozpychania. */
#vp .cost b,
#vp .pick-cost b,
#vp .dock .sum,
#vp .pv-sum b,
#vp .bulk-tot b,
#vp .rrow.sum span:last-child,
#vp .prof-stats b,
#vp .lp,
#vp .demo-cena {
  font-family: var(--num);
  font-weight: 700;
  letter-spacing: -.04em;
  font-variant-numeric: tabular-nums;
}

/* Kwoty drugorzędne (pozycje rachunku, ceny w wierszach koszyka): ta sama
   rodzina, o stopień lżej — mają być czytelne, ale nie konkurować z sumą. */
#vp .rrow span:last-child,
#vp .line .u,
#vp .pay .fee,
#vp .bulk,
#vp .pick-bulk {
  font-family: var(--num);
  font-weight: 600;
  font-variant-numeric: tabular-nums;
}

/* Numery i kody (zamówienie, przesyłka, paczkomat). „Kodowość" niosą
   ODSTĘPY, nie inny krój: znak po znaku łatwiej przepisać, a całość dalej
   należy do tej samej rodziny co cena obok. */
#vp .ord .id,
#vp .ord .trk,
#vp .paczka-h .id,
#vp .lk-kod,
#vp .saved .d b {
  font-family: var(--num);
  font-weight: 600;
  letter-spacing: .04em;
  font-variant-numeric: tabular-nums;
}

/* `textarea` MUSI tu być razem z `input`. Bez tego przeglądarka wstawia
   w polu tekstowym swój domyślny krój maszynowy — i pole na uwagi do
   zamówienia wyglądało jak okno terminala pośrodku formularza. */
#vp button, #vp input, #vp textarea, #vp select {
  font: inherit; letter-spacing: inherit; color: inherit;
  border: 0; background: none; -webkit-tap-highlight-color: transparent;
}
#vp button { cursor: pointer; }
#vp img { display: block; max-width: 100%; }
#vp a { color: inherit; text-decoration: none; }
#vp .hide { display: none !important; }

#vp :focus { outline: none; }
#vp :focus-visible {
  outline: 2px solid var(--volt);
  outline-offset: 3px;
  border-radius: var(--r-xs);
}

#vp .shell { width: 100%; max-width: var(--max); margin-inline: auto; padding-inline: var(--gut); }

/* ══════════════════════════════════════════════════════════════════════════
   FAKTURA — ziarno + siatka linii.
   Jeden szczegół, który najmocniej odróżnia zaprojektowaną stronę od
   domyślnego szablonu: powierzchnia przestaje być idealnie płaska.
   ══════════════════════════════════════════════════════════════════════════ */
#vp .grain {
  position: fixed;
  inset: -50%;
  z-index: 1;
  pointer-events: none;
  opacity: .04;
  mix-blend-mode: overlay;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Siatka cienkich linii w hero.
   Wcześniej miała `max-width: var(--max)` i `margin-inline: auto`, czyli
   kończyła się na 1280 px i wyśrodkowywała. Na szerokim monitorze dawało to
   dwa widoczne pionowe szwy — teksturę było widać tylko w środku ekranu.
   Teraz idzie przez całe hero, a odstęp linii jest STAŁY (320 px = 1280/4),
   więc rytm zgadza się z siatką treści przy dowolnej szerokości okna.
   Maska w obu osiach wygasza krawędzie, zamiast je ucinać. */
#vp .rules {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image: linear-gradient(90deg,
    var(--edge) 0 1px, transparent 1px 100%);
  background-size: 320px 100%;
  opacity: .5;
  -webkit-mask-image: linear-gradient(180deg, transparent, #000 8%, #000 82%, transparent),
                      linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  mask-image: linear-gradient(180deg, transparent, #000 8%, #000 82%, transparent),
              linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  -webkit-mask-composite: source-in;
  mask-composite: intersect;
}

#vp main, #vp .nav, #vp .dock { position: relative; z-index: 2; }

/* ══════════════════════════════════════════════════════════════════════════
   ELEMENTY TYPOGRAFICZNE
   ══════════════════════════════════════════════════════════════════════════ */

/* Etykieta pomocnicza — sygnatura marki przy sekcjach, statusach i danych.

   Szła krojem maszynowym, wersalikami, z szerokim rozstrzeleniem. Ten zestaw
   trzech cech naraz to najczęstszy znak rozpoznawczy szablonu: wygląda
   „technicznie" zamiast czytać się jak słowo. Zostaje sam kroj firmowy
   w mocniejszej wadze i delikatnym rozstrzeleniu — etykieta dalej jest drugim
   planem, ale należy do tej samej rodziny co reszta strony. */
#vp .tag {
  font-family: var(--sans);
  font-size: 12px;
  font-weight: 600;
  letter-spacing: .07em;
  text-transform: uppercase;
  color: var(--dim);
}

#vp .num { font-family: var(--num); font-variant-numeric: tabular-nums; letter-spacing: -.02em; }

/* Cienka linia „ładowania" — motyw napięcia, przewija się pod nagłówkiem. */
#vp .charge {
  position: relative;
  height: 1px;
  background: var(--edge);
  overflow: hidden;
}
#vp .charge::after {
  content: "";
  position: absolute;
  inset: 0 auto 0 0;
  width: 30%;
  background: linear-gradient(90deg, transparent, var(--volt), transparent);
  animation: vp-charge 4.5s cubic-bezier(.6, 0, .4, 1) infinite;
}
@keyframes vp-charge {
  0% { transform: translateX(-100%); }
  60%, 100% { transform: translateX(430%); }
}

/* ══════════════════════════════════════════════════════════════════════════
   PASEK POSTĘPU ZAPYTAŃ
   ══════════════════════════════════════════════════════════════════════════ */
#vp .bar {
  position: fixed; inset: 0 auto auto 0; z-index: 100;
  height: 2px; width: 100%;
  background: linear-gradient(90deg, var(--volt), var(--volt-2));
  transform: scaleX(0); transform-origin: 0 50%;
  opacity: 0;
  transition: transform var(--slow), opacity var(--fast);
}
#vp .bar.on { opacity: 1; transform: scaleX(.72); }
#vp .bar.done { opacity: 0; transform: scaleX(1); transition: transform 200ms, opacity 300ms 120ms; }

/* ══════════════════════════════════════════════════════════════════════════
   NAWIGACJA
   ══════════════════════════════════════════════════════════════════════════ */
#vp .nav {
  position: sticky; top: 0; z-index: 60;
  background: rgba(8, 8, 10, .68);
  backdrop-filter: blur(20px) saturate(180%);
  -webkit-backdrop-filter: blur(20px) saturate(180%);
  box-shadow: 0 1px 0 0 transparent;
  transition: box-shadow var(--mid), background var(--mid);
}
#vp .nav.lifted { box-shadow: 0 1px 0 0 var(--edge); background: rgba(8, 8, 10, .88); }

#vp .nav-in {
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  height: var(--nav-h);
  max-width: var(--max); margin-inline: auto;
  padding-inline: var(--gut);
}

/* Znak marki: monogram w ramce + wordmark rozstrzelony. */
#vp .brand { display: inline-flex; align-items: center; gap: 11px; }
#vp .brand .mark {
  position: relative;
  display: grid; place-items: center;
  width: 30px; height: 30px;
  border: 1px solid var(--edge-2);
  border-radius: var(--r-xs);
  background: linear-gradient(150deg, var(--raise), var(--panel));
  overflow: hidden;
}
#vp .brand .mark svg { width: 15px; height: 15px; color: var(--volt); }
#vp .brand .mark::after {
  content: "";
  position: absolute; inset: 0;
  background: radial-gradient(70% 60% at 50% 120%, rgba(227, 178, 60, .35), transparent 70%);
}
/* Wgrane logo zastepuje blyskawice. Zdejmujemy ramke, tlo i poswiate — te
   ozdobniki byly oprawa dla ikonki, a pod prawdziwym znakiem marki wygladaja
   jak obca naklejka doklejona do logo. */
#vp .brand .mark.img {
  border: 0; background: none; width: 34px; height: 34px;
}
#vp .brand .mark.img::after { content: none; }
#vp .brand .mark.img img { width: 100%; height: 100%; object-fit: contain; }

#vp .brand .word {
  font-size: 15px; font-weight: 700;
  letter-spacing: .2em; text-transform: uppercase;
}

#vp .nav-r { display: flex; align-items: center; gap: 8px; }

#vp .icon-btn {
  position: relative;
  display: grid; place-items: center;
  width: 42px; height: 42px;
  border-radius: var(--pill);
  color: var(--ink);
  transition: background var(--fast), transform var(--fast);
}
#vp .icon-btn:hover { background: var(--raise); }
#vp .icon-btn:active { transform: scale(.92); }
#vp .icon-btn svg { width: 20px; height: 20px; }

#vp .count {
  position: absolute; top: 2px; right: 1px;
  min-width: 19px; height: 19px; padding-inline: 5px;
  display: grid; place-items: center;
  border-radius: var(--pill);
  background: var(--volt); color: #17130a;
  font-family: var(--num);
  font-size: 12px; font-weight: 500; letter-spacing: 0;
  transform: scale(0);
  transition: transform 300ms cubic-bezier(.3, 1.6, .5, 1);
}
#vp .count.on { transform: scale(1); }
#vp .count.bump { animation: vp-bump 460ms cubic-bezier(.3, 1.5, .5, 1); }
@keyframes vp-bump { 42% { transform: scale(1.4); } 100% { transform: scale(1); } }

/* Kafelek konta */
#vp .me {
  display: inline-flex; align-items: center; gap: 9px;
  height: 42px; padding: 0 15px 0 4px;
  border-radius: var(--pill);
  border: 1px solid var(--edge);
  background: var(--panel);
  transition: border-color var(--fast), background var(--fast), transform var(--fast);
}
#vp .me:hover { border-color: var(--edge-2); background: var(--raise); }
#vp .me:active { transform: scale(.97); }
#vp .me .av {
  width: 34px; height: 34px; border-radius: var(--pill);
  object-fit: cover; background: var(--raise-2);
}
/* Monogram zamiast domyslnego logo Discorda — patrz avatarHTML() w app.js. */
#vp .av-mono {
  display: grid; place-items: center; flex: none;
  border-radius: var(--pill);
  background: linear-gradient(150deg, var(--raise-2), var(--panel));
  box-shadow: inset 0 0 0 1px var(--edge-2);
  color: var(--ink);
  font-weight: 600; letter-spacing: -.02em;
  user-select: none;
}
#vp .me .av.av-mono { font-size: 15px; }

/* Nazwa konta i ranga były 12,5 px i 10 px, ranga dodatkowo monospace'em
   w kolorze sygnałowym — nie dało się tego przeczytać, a żółty krzyczał
   w miejscu, które niczego nie sprzedaje. Teraz normalny krój, większy stopień
   i spokojny kolor. */
/* Nazwa konta MUSI mieć sufit szerokości i ucinanie wielokropkiem.
   Nicki z Discorda potrafią mieć 30 znaków i emoji; bez tego chip rozpychał
   pasek, wypychał koszyk poza ekran, a na telefonie nazwa łamała się na dwie
   linie i rozjeżdżała cały nagłówek. */
/* Chip kurczy się do miejsca, które ZOSTAŁO po logotypie i koszyku — sufit
   liczony w `vw` tego nie wiedział i nazwa nadal wychodziła poza ekran. */
#vp .nav-in > *, #vp .nav-r > * { min-width: 0; }
#vp .nav-r { min-width: 0; }
#vp .brand { flex: 0 0 auto; }
#vp .me { flex: 0 1 auto; min-width: 0; max-width: 100%; }
#vp .me .who {
  display: flex; flex-direction: column; align-items: flex-start;
  min-width: 0; line-height: 1.2;
}
#vp .me .who b,
#vp .me .who span {
  max-width: 100%;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#vp .me .who b { font-size: 15px; font-weight: 600; letter-spacing: -.01em; }
#vp .me .who span { font-size: 12px; color: var(--dim); letter-spacing: -.005em; }

/* Przycisk Discorda — logo buduje rozpoznawalność i zaufanie. */
#vp .discord-btn {
  display: inline-flex; align-items: center; gap: 9px;
  height: 42px; padding-inline: 16px;
  border-radius: var(--pill);
  background: var(--discord); color: #fff;
  font-size: 13px; font-weight: 600; white-space: nowrap;
  box-shadow: 0 6px 22px -8px rgba(88, 101, 242, .85);
  transition: transform var(--fast), filter var(--fast);
}
#vp .discord-btn:hover { filter: brightness(1.12); }
#vp .discord-btn:active { transform: scale(.97); }
#vp .discord-btn svg { width: 19px; height: 19px; }
#vp .discord-btn.wide { width: 100%; height: 54px; justify-content: center; font-size: 15px; }

/* ══════════════════════════════════════════════════════════════════════════
   HERO
   ══════════════════════════════════════════════════════════════════════════ */
#vp .hero {
  position: relative;
  margin-top: calc(-1 * var(--nav-h));
  padding-block: calc(var(--nav-h) + 56px) 0;
  overflow: hidden;
}
#vp .hero-bg {
  position: absolute; inset: 0; z-index: -2;
  background-size: cover; background-position: 62% 30%;
  opacity: 0; transform: scale(1.08);
  transition: opacity 1100ms ease, transform 1800ms cubic-bezier(.16, 1, .3, 1);
}
#vp .hero-bg.on { opacity: 1; transform: scale(1); }
#vp .hero::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background:
    radial-gradient(90% 70% at 78% 22%, rgba(227, 178, 60, .13), transparent 62%),
    linear-gradient(180deg, rgba(8, 8, 10, .72) 0%, rgba(8, 8, 10, .58) 40%, var(--void) 96%);
}

#vp .hero-grid { display: grid; gap: 30px; }

#vp .kicker {
  display: inline-flex; align-items: center; gap: 9px;
  margin-bottom: 26px;
  padding: 7px 14px 7px 10px;
  border: 1px solid var(--edge);
  border-radius: var(--pill);
  background: rgba(255, 255, 255, .035);
  backdrop-filter: blur(8px);
}
#vp .kicker .led {
  width: 6px; height: 6px; border-radius: var(--pill);
  background: var(--ok);
  animation: vp-led 2.6s ease-out infinite;
}
#vp .kicker.shut .led { background: var(--bad); animation: none; }
@keyframes vp-led {
  0% { box-shadow: 0 0 0 0 rgba(74, 222, 128, .55); }
  70% { box-shadow: 0 0 0 8px rgba(74, 222, 128, 0); }
  100% { box-shadow: 0 0 0 0 rgba(74, 222, 128, 0); }
}

#vp .hero h1 {
  font-size: clamp(2.9rem, 12.5vw, 6.4rem);
  line-height: .92;
  font-weight: 700;
  letter-spacing: -.05em;
  max-width: 13ch;
  text-wrap: balance;
}
/* Ostatnie słowo bez ozdób. Wcześniej podkreślała je żółta kreska — czytała się
   jak przypadkowy pasek wklejony pod tekst i odciągała wzrok od tego, co ma
   naprawdę przyciągać: przycisku zakupu. Nagłówek ma być czytelny, akcent
   kolorystyczny należy do ceny i przycisku. */
#vp .hero h1 .under {
  display: inline;
  white-space: nowrap;
}
#vp .hero h1 .under-off::after {
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: .1em;
  height: .07em;
  border-radius: 2px;
  background: var(--volt);
  transform: scaleX(0); transform-origin: 0 50%;
  animation: vp-underline 900ms cubic-bezier(.16, 1, .3, 1) 420ms forwards;
}
@keyframes vp-underline { to { transform: scaleX(1); } }

#vp .lede {
  margin-top: 22px;
  max-width: 44ch;
  font-size: clamp(1rem, 3.7vw, 1.2rem);
  line-height: 1.6;
  color: var(--dim);
  text-wrap: pretty;
}

#vp .hero-cta { display: flex; flex-wrap: wrap; gap: 11px; margin-top: 34px; }

/* ── Przyciski ──────────────────────────────────────────────────────────── */
#vp .btn {
  position: relative;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
  height: 54px; padding-inline: 28px;
  border-radius: var(--pill);
  font-size: 15px; font-weight: 600; letter-spacing: -.012em; white-space: nowrap;
  overflow: hidden;
  transition: transform var(--fast), background var(--fast),
              border-color var(--fast), opacity var(--fast), box-shadow var(--fast);
}
#vp .btn:active { transform: scale(.975); }
#vp .btn[disabled] { pointer-events: none; }
#vp .btn-volt[disabled] {
  background: var(--raise-2); color: var(--faint); box-shadow: none;
}
#vp .btn-volt[disabled]::after { display: none; }
#vp .btn svg { width: 17px; height: 17px; }

#vp .btn-volt {
  background: var(--volt); color: #17130a;
  box-shadow: 0 10px 34px -12px rgba(227, 178, 60, .8);
}
#vp .btn-volt:hover { background: var(--volt-2); box-shadow: 0 12px 40px -10px rgba(227, 178, 60, .95); }
/* Refleks przebiegający po przycisku przy najechaniu. */
#vp .btn-volt::after {
  content: "";
  position: absolute; inset: 0;
  background: linear-gradient(105deg, transparent 30%, rgba(255, 255, 255, .55) 48%, transparent 66%);
  transform: translateX(-120%);
  transition: transform 720ms cubic-bezier(.16, 1, .3, 1);
}
#vp .btn-volt:hover::after { transform: translateX(120%); }

#vp .btn-line { border: 1px solid var(--edge-2); color: var(--ink); }
#vp .btn-line:hover { background: var(--raise); border-color: rgba(255, 255, 255, .24); }

#vp .btn-full { width: 100%; }

/* ── Parametry pod hero — czytane jak tabliczka znamionowa ──────────────── */
#vp .specs {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 18px;
  margin-top: 40px;
  padding-top: 26px;
  border-top: 1px solid var(--edge);
}
#vp .specs div {
  display: flex; flex-direction: column; align-items: flex-start; gap: 6px;
  padding: 0;
  border: 0;
}
#vp .specs svg { width: 20px; height: 20px; color: var(--volt); }
#vp .specs b {
  display: block;
  font-size: 15px;
  font-weight: 650;
  letter-spacing: -.015em;
  color: var(--ink);
}
#vp .specs span { font-size: 13px; line-height: 1.45; color: var(--dim); }
#vp .specs span { display: block; margin-top: 5px; padding-right: 12px; }

/* ── Polecana pozycja w hero ─────────────────────────────────────────────────
   Wcześniej wisiał tu obrazek produktu na obracających się pierścieniach.
   Wyglądał jak dekoracja: nie było wiadomo, co to, ile kosztuje i że da się to
   kupić. Teraz jest zwykła karta oferty — pierwsza rzecz na ekranie prowadzi
   prosto do koszyka. Pierścienie i poświata zostają w HTML (ten sam blok na
   mssg.me), ale są ukryte. */
#vp .stage { position: relative; margin-top: 8px; }
#vp .stage.hide { display: none; }
#vp .stage .halo,
#vp .stage .ring { display: none; }

#vp .pick {
  display: flex; flex-direction: column;
  border-radius: var(--r);
  background: var(--panel);
  box-shadow: inset 0 0 0 1px var(--edge);
  overflow: hidden;
}
#vp .pick-lbl {
  padding: 14px 18px 0;
  color: var(--dim);
}
#vp .pick-art {
  /* Ten sam portret 4:5 co w katalogu — jedno zdjecie ma wygladac tak samo
     wszedzie. Wczesniej 4:3 przycinalo pionowe zdjecia produktow (butelki,
     urzadzenia) i polecany towar mial ucieta gore albo dol. */
  aspect-ratio: 4 / 5;
  margin: 12px 18px 0;
  border-radius: var(--r-sm);
  overflow: hidden;
  background: radial-gradient(70% 56% at 50% 60%, rgba(255, 255, 255, .05), transparent 70%), var(--raise);
  cursor: pointer;
}
#vp .pick-art img {
  width: 100%; height: 100%;
  /* `contain`: to jest WITRYNA sklepu — produkt musi byc widoczny w calosci.
     Ucieta etykieta na pierwszym zdjeciu, ktore widzi klient, to najgorsze
     mozliwe pierwsze wrazenie. */
  object-fit: contain;
  padding: 8px;
  transition: transform var(--slow);
}
@media (hover: hover) and (pointer: fine) {
  #vp .pick-art:hover img { transform: scale(1.05); }
}
#vp .pick-body { padding: 16px 18px 18px; }
#vp .pick-body h3 { font-size: 20px; font-weight: 600; letter-spacing: -.025em; }
#vp .pick-cat { display: block; margin-top: 5px; color: var(--faint); }
#vp .pick-row {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; margin-top: 16px; flex-wrap: wrap;
}
#vp .pick-cost { display: flex; flex-direction: column; gap: 3px; }
#vp .pick-cost b {
  font-family: var(--num); font-size: 24px; font-weight: 650;
  letter-spacing: -.04em; white-space: nowrap;
}
#vp .pick-bulk { font-family: var(--num); font-size: 12px; color: var(--ok); }
#vp .pick-row .btn-volt { height: 46px; padding-inline: 22px; }

/* ── Pasek przewijany z hasłami ─────────────────────────────────────────── */
#vp .ticker {
  margin-top: 54px;
  border-top: 1px solid var(--edge);
  border-bottom: 1px solid var(--edge);
  overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 12%, #000 88%, transparent);
}
#vp .ticker-track {
  display: flex; align-items: center;
  padding-block: 15px;
  width: max-content;
  /* `will-change` trzyma pasek na własnej warstwie GPU — bez tego przy
     zapętleniu potrafił drgnąć na słabszym sprzęcie. */
  will-change: transform;
  animation: vp-ticker 34s linear infinite;
}
#vp .ticker:hover .ticker-track { animation-play-state: paused; }
/* Odstęp jako STAŁY margines KAŻDEGO elementu, nie `gap` toru. `gap` wstawia
   przerwę tylko MIĘDZY elementami, więc obie połowy listy miały o jeden odstęp
   inne szerokości — a że pętla przesuwa tor o dokładnie 50%, na złączeniu robił
   się skok. Jednakowy margines na każdym haśle sprawia, że -50% trafia idealnie
   w początek drugiej kopii i przewijanie jest bezszwowe. */
#vp .ticker span {
  display: inline-flex; align-items: center; gap: 11px; white-space: nowrap;
  margin-right: 42px;
}
#vp .ticker span::before {
  content: ""; width: 4px; height: 4px; border-radius: 50%;
  background: var(--volt); flex: none;
}
@keyframes vp-ticker { to { transform: translateX(-50%); } }

/* ══════════════════════════════════════════════════════════════════════════
   KATALOG
   ══════════════════════════════════════════════════════════════════════════ */
#vp .catalog { padding-block: 74px 110px; }

#vp .sec-head {
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: 24px; margin-bottom: 26px;
}
#vp .sec-head h2 {
  margin-top: 12px;
  font-size: clamp(1.7rem, 6.4vw, 2.6rem);
  font-weight: 700; letter-spacing: -.04em; line-height: 1.02;
}
#vp .sec-head .count-note { text-align: right; white-space: nowrap; }

/* Kategorie: filtr w formie listy technicznej z ruchomym wskaźnikiem. */
#vp .tabs {
  position: sticky; top: 62px; z-index: 40;
  display: flex; gap: 4px;
  margin-bottom: 34px;
  padding-block: 12px;
  overflow-x: auto; scrollbar-width: none;
  background: rgba(8, 8, 10, .9);
  backdrop-filter: blur(18px); -webkit-backdrop-filter: blur(18px);
  box-shadow: inset 0 -1px 0 0 var(--edge);
  scroll-snap-type: x proximity;
}
#vp .tabs::-webkit-scrollbar { display: none; }

#vp .tab {
  position: relative; flex: none;
  display: inline-flex; align-items: baseline; gap: 8px;
  padding: 9px 15px;
  border-radius: var(--r-xs);
  font-size: 15px; font-weight: 500; letter-spacing: -.015em;
  color: var(--faint); white-space: nowrap;
  scroll-snap-align: start;
  transition: color var(--mid), background var(--fast);
}
#vp .tab:hover { color: var(--dim); background: rgba(255, 255, 255, .03); }
#vp .tab.on { color: var(--ink); }
#vp .tab i {
  font-style: normal;
  font-family: var(--num); font-size: 12px;
  color: var(--faint); letter-spacing: .04em;
}
#vp .tab.on i { color: var(--volt); }

#vp .ink {
  position: absolute; left: 0; bottom: 6px;
  height: 2px; width: 1px; border-radius: 2px;
  background: var(--volt);
  transform-origin: 0 50%; transform: scaleX(0);
  transition: transform var(--mid);
  will-change: transform;
}

#vp .grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; }

/* ── Karta produktu ─────────────────────────────────────────────────────── */
#vp .card {
  position: relative;
  display: flex; flex-direction: column;
  border-radius: var(--r);
  background: linear-gradient(180deg, var(--panel) 0%, #0a0a0c 100%);
  /* Górna hairline jak krawędź szkła — daje głębię bez rysowania ramki. */
  box-shadow:
    inset 0 1px 0 0 rgba(255, 255, 255, .06),
    inset 0 0 0 1px var(--edge);
  overflow: hidden;
  opacity: 0; transform: translateY(18px);
  transition: opacity var(--slow), transform var(--slow), box-shadow var(--mid);
}
#vp .card.in { opacity: 1; transform: none; }
#vp .card:hover {
  box-shadow:
    inset 0 1px 0 0 rgba(255, 255, 255, .1),
    inset 0 0 0 1px var(--edge-2),
    0 22px 50px -26px rgba(0, 0, 0, .95);
}

#vp .stagelet {
  position: relative;
  /* NIE KURCZYC. Karta jest kolumna flex i wyrownuje sie do najwyzszej
     w rzedzie; bez tego zdjecie oddawalo swoja wysokosc na rzecz tresci
     i kadry miały rozne wielkosci mimo tych samych proporcji. */
  flex: none;
  /* PORTRET 4:5, nie kwadrat. Na telefonie wyzszy kadr zajmuje wiecej ekranu,
     wiec zdjecie produktu jest wieksze i lepiej sprzedaje — to jedna z lepiej
     udokumentowanych roznic w handlu mobilnym. Ten sam format trzymamy na
     karcie polecanego i w widoku produktu, zeby jedno zdjecie wygladalo
     wszedzie tak samo. */
  aspect-ratio: 4 / 5;
  overflow: hidden;
  background: radial-gradient(72% 58% at 50% 62%, rgba(255, 255, 255, .045), transparent 70%);
}
#vp .stagelet img {
  width: 100%; height: 100%;
  /* `contain` w calym sklepie: kafelek, karta polecanego i widok produktu maja
     pokazywac ten sam kadr. `cover` przycinal etykiety i nazwy smakow — a to
     wlasnie po nich klient rozpoznaje towar. */
  object-fit: contain;
  padding: 10px;
  /* ZAOKRAGLENIE ROGOW ZDJECIA.
     Czesc zdjec od dostawcow to gotowe GRAFIKI REKLAMOWE z wlasnym, kolorowym
     tlem (zielonym, rozowym). Po zdjeciu bialego marginesu zostaje z nich
     kolorowy prostokat, ktory na ciemnej karcie wyglada jak wklejka
     przyklejona na sile.

     Zaokraglenie zamienia ten prostokat w element karty — czyta sie jako
     celowy kafelek, a nie blad. Na zdjeciach z wycietym tlem nie widac go
     wcale, bo rogi sa tam przezroczyste. Jedna regula, dwa pozadane skutki. */
  border-radius: 14px;
  transition: transform var(--slow);
}
#vp .card:hover .stagelet img { transform: scale(1.06) translateY(-4px); }
/* Kafelek otwiera kartę produktu — kursor to sygnalizuje. */
#vp .stagelet[data-open], #vp .card-body h3[data-open] { cursor: pointer; }

#vp .stagelet .void-art {
  position: absolute; inset: 0;
  display: grid; place-items: center;
}
#vp .stagelet .void-art::before {
  content: ""; width: 46%; aspect-ratio: 1; border-radius: 50%;
  border: 1px dashed var(--edge-2);
}

/* Zdjęcie, które nie chciało się wczytać (wygasły link, usunięty plik).
   Chowamy je razem z ikonką przeglądarki i tekstem alternatywnym, a na jego
   miejscu stawiamy tę samą zaślepkę, co przy produkcie bez zdjęcia —
   patrz `pilnujZdjec()` w app.js. */
#vp img.img-brak { visibility: hidden; }
#vp .bez-zdjecia { position: relative; }
#vp .bez-zdjecia::after {
  content: ""; position: absolute; top: 50%; left: 50%;
  width: 46%; max-width: 160px; aspect-ratio: 1; border-radius: 50%;
  border: 1px dashed var(--edge-2);
  transform: translate(-50%, -50%);
  pointer-events: none;
}

/* Numer pozycji — katalog, nie feed. */
#vp .idx {
  position: absolute; top: 12px; right: 13px;
  font-family: var(--num); font-size: 12px;
  color: var(--faint); letter-spacing: .08em;
}

/* Odczyt dostępności */
#vp .avail {
  position: absolute; left: 12px; bottom: 12px;
  display: inline-flex; align-items: center; gap: 7px;
  height: 25px; padding-inline: 10px;
  border-radius: var(--r-xs);
  background: rgba(8, 8, 10, .74);
  backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px);
  box-shadow: inset 0 0 0 1px var(--edge);
  font-family: var(--num); font-size: 12px; letter-spacing: .09em;
  text-transform: uppercase; color: var(--dim);
}
#vp .avail i { width: 5px; height: 5px; border-radius: 50%; background: var(--ok); font-style: normal; }
#vp .avail.low { color: var(--volt-2); }
#vp .avail.low i { background: var(--volt); }
#vp .avail.out { color: var(--bad); }
#vp .avail.out i { background: var(--bad); }

#vp .card-body { display: flex; flex-direction: column; gap: 10px; padding: 15px 15px 16px; flex: 1; }
#vp .card-body .cat { color: var(--faint); }
#vp .card-body h3 {
  font-size: 15px; font-weight: 600; letter-spacing: -.024em; line-height: 1.25;
}
#vp .card-body .note {
  font-size: 13px; line-height: 1.5; color: var(--faint);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}

/* Warianty */
#vp .chips { display: flex; flex-wrap: wrap; gap: 6px; }
#vp .chip {
  padding: 5px 11px;
  border-radius: var(--r-xs);
  box-shadow: inset 0 0 0 1px var(--edge);
  background: var(--raise);
  font-size: 12px; font-weight: 500; color: var(--dim);
  transition: box-shadow var(--fast), color var(--fast), background var(--fast), transform var(--fast);
}
#vp .chip:hover { box-shadow: inset 0 0 0 1px var(--edge-2); color: var(--ink); }
#vp .chip:active { transform: scale(.94); }
#vp .chip.on { box-shadow: inset 0 0 0 1px rgba(227, 178, 60, .6); background: var(--volt-dim); color: var(--volt-2); }
/* Wyprzedany smak: WIDOCZNIE niedostepny, ale nadal do kliknięcia.
   Po wybraniu klient widzi cenę i może zapisać się na powiadomienie o powrocie
   — to jedyna sensowna akcja, jaka mu została, więc nie wolno jej blokować.
   Przekreślenie i wyszarzenie mówią „nie ma", kursor mówi „ale możesz kliknąć". */
#vp .chip.out { opacity: .5; text-decoration: line-through; cursor: pointer; }

#vp .card-foot {
  display: flex; align-items: baseline; justify-content: space-between; gap: 10px;
  margin-top: auto; padding-top: 10px;
}
#vp .cost { display: flex; flex-direction: column; gap: 3px; }
#vp .cost b { font-family: var(--num); font-size: 17px; font-weight: 650;
              letter-spacing: -.04em; white-space: nowrap; }
#vp .cost .bulk { font-family: var(--num); font-size: 12px; color: var(--ok); letter-spacing: .02em; }

/* ── Pasek zakupu ────────────────────────────────────────────────────────────
   Jawny przycisk z napisem zamiast okrągłego „+", które rozwijało się dopiero
   po najechaniu — na dotyku nie dawało się tego odkryć. Po dodaniu przycisk
   zamienia się w licznik, więc ilość reguluje się na kafelku. */
#vp .buy { margin-top: 12px; }
#vp .btn-buy {
  display: flex; align-items: center; justify-content: center; gap: 9px;
  width: 100%; height: 44px;
  border-radius: var(--r-xs);
  background: var(--raise-2);
  box-shadow: inset 0 0 0 1px var(--edge-2);
  color: var(--ink);
  font-size: 13px; font-weight: 600; letter-spacing: -.01em;
  transition: background var(--fast), color var(--fast), transform var(--fast),
              box-shadow var(--fast);
}
#vp .btn-buy svg { width: 17px; height: 17px; flex: none; }
@media (hover: hover) and (pointer: fine) {
  #vp .btn-buy:hover { background: var(--volt); color: #17130a; box-shadow: none; }
}
#vp .btn-buy:active { transform: scale(.97); }
#vp .btn-buy[disabled] {
  background: var(--raise); color: var(--faint);
  box-shadow: inset 0 0 0 1px var(--edge);
  pointer-events: none; font-weight: 500;
}

/* Stan „już w koszyku" — licznik plus potwierdzenie. */
#vp .buy.in-cart {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  animation: vp-pop 240ms cubic-bezier(.25, .8, .35, 1);
}
@keyframes vp-pop { from { transform: scale(.96); opacity: .6; } }
#vp .card-step { height: 44px; border-radius: var(--r-xs); background: var(--raise-2); }
#vp .card-step button { width: 40px; height: 44px; }
#vp .card-step b { min-width: 30px; font-size: 15px; }
#vp .card-step button[disabled] { opacity: .3; pointer-events: none; }
#vp .in-cart-note {
  display: inline-flex; align-items: center; gap: 6px;
  font-family: var(--num); font-size: 12px; letter-spacing: .05em;
  text-transform: uppercase; color: var(--ok); white-space: nowrap;
}
#vp .in-cart-note svg { width: 12px; height: 12px; }

/* Szkielet */
#vp .skel {
  border-radius: var(--r);
  background: var(--panel);
  box-shadow: inset 0 0 0 1px var(--edge);
  overflow: hidden;
}
#vp .skel .s-img { aspect-ratio: 1 / 1; }
#vp .skel .s-l { height: 10px; border-radius: 5px; margin: 13px 15px 0; }
#vp .skel .s-l.a { width: 38%; }
#vp .skel .s-l.b { width: 76%; height: 13px; }
#vp .skel .s-l.c { width: 52%; margin-bottom: 20px; }
#vp .s-img, #vp .s-l {
  background: linear-gradient(100deg, var(--raise) 28%, var(--raise-2) 48%, var(--raise) 68%);
  background-size: 260% 100%;
  animation: vp-shimmer 1.6s ease-in-out infinite;
}
@keyframes vp-shimmer { from { background-position: 170% 0; } to { background-position: -70% 0; } }

#vp .empty {
  grid-column: 1 / -1;
  display: flex; flex-direction: column; align-items: center; gap: 14px;
  padding: 78px 20px;
  text-align: center; color: var(--faint); font-size: 15px;
}
#vp .empty .glyph {
  width: 66px; height: 66px; border-radius: 50%;
  display: grid; place-items: center;
  box-shadow: inset 0 0 0 1px var(--edge);
  background: radial-gradient(closest-side, rgba(227, 178, 60, .08), transparent);
}
#vp .empty .glyph svg { width: 26px; height: 26px; color: var(--faint); }

/* ══════════════════════════════════════════════════════════════════════════
   PASEK ZAKUPU (telefon)
   ══════════════════════════════════════════════════════════════════════════ */
#vp .dock {
  position: fixed; left: 12px; right: 12px;
  bottom: calc(12px + env(safe-area-inset-bottom));
  z-index: 55;
  display: flex; align-items: center; justify-content: space-between; gap: 14px;
  height: 60px; padding: 0 8px 0 20px;
  border-radius: var(--pill);
  background: rgba(19, 19, 24, .86);
  backdrop-filter: blur(26px) saturate(190%);
  -webkit-backdrop-filter: blur(26px) saturate(190%);
  box-shadow: inset 0 0 0 1px var(--edge-2), 0 20px 54px -16px rgba(0, 0, 0, .92);
  transform: translateY(150%); opacity: 0;
  transition: transform var(--mid), opacity var(--mid);
}
#vp .dock.on { transform: none; opacity: 1; }
#vp .dock .l { display: flex; flex-direction: column; align-items: flex-start; line-height: 1.2; }
#vp .dock .sum { font-family: var(--num); font-size: 17px; font-weight: 650; letter-spacing: -.035em; }
#vp .dock .go {
  display: inline-flex; align-items: center; gap: 8px;
  height: 44px; padding-inline: 20px;
  border-radius: var(--pill);
  background: var(--volt); color: #17130a;
  font-size: 15px; font-weight: 600;
}
#vp .dock .go svg { width: 16px; height: 16px; }

/* ══════════════════════════════════════════════════════════════════════════
   PANEL (koszyk / checkout / profil)
   ══════════════════════════════════════════════════════════════════════════ */
#vp .scrim {
  position: fixed; inset: 0; z-index: 70;
  background: rgba(3, 3, 4, .68);
  backdrop-filter: blur(5px); -webkit-backdrop-filter: blur(5px);
  opacity: 0; pointer-events: none;
  transition: opacity var(--mid);
}
#vp .scrim.on { opacity: 1; pointer-events: auto; }

#vp .sheet {
  position: fixed; z-index: 75;
  display: flex; flex-direction: column;
  background: var(--panel);
  inset: auto 0 0 0;
  max-height: 93svh;
  border-radius: var(--r-lg) var(--r-lg) 0 0;
  box-shadow: inset 0 1px 0 0 var(--edge-2), 0 -30px 80px -24px rgba(0, 0, 0, .9);
  transform: translateY(101%);
  transition: transform var(--slow);
  /* BEZ `will-change`. Trzymane na stale wymusza osobna warstwe na GPU takze
     wtedy, gdy panel stoi nieruchomo — a tekst na takiej warstwie traci
     subpikselowe wygladzanie i wyglada na rozmyty. Przegladarka i tak tworzy
     warstwe na czas animacji `transform` i zwalnia ja po niej, wiec podpowiedz
     nic nie wnosila poza rozmyciem calego koszyka. */
}
#vp .sheet.on { transform: none; }

/* Koszyk i zamówienie jako osobna strona, nie wysuwany panel.
   Wymiary bierzemy z widocznego obszaru (`--vv*`, ustawiane przez skrypt
   z `visualViewport`), a nie z wysokości strony — patrz komentarz przy
   `dopasuj()` w app.js. Wartości zapasowe działają wszędzie tam, gdzie
   przeglądarka nie zna `visualViewport`. */
#vp .sheet.pelny {
  top: 0; left: 0;
  right: auto; bottom: auto;
  width: 100%;
  height: var(--vvh, 100svh);
  max-height: none;
  border-radius: 0;
  box-shadow: none;
}
/* ── iPHONE I KLAWIATURA ───────────────────────────────────────────────────
   Na iOS (Safari i Chrome, bo to ten sam silnik) klawiatura NIE skraca okna.
   System przesuwa natomiast cały widoczny obszar w górę, żeby pokazać pole —
   a `position: fixed` trzyma się okna, nie widoku. Panel zostaje więc tam,
   gdzie było okno: ucieka poza ekran, pole ląduje pod klawiaturą, a strona
   pod spodem jeździ swoim życiem. Stąd wszystkie cztery objawy naraz.

   `visualViewport.offsetTop` mówi, o ile system przesunął widok. Przesuwamy
   panel o dokładnie tyle samo — wtedy trzyma się tego, co klient widzi.
   Robimy to transformem, nie `top`: `top` liczy się od okna, które już jest
   przesunięte, więc dokładałby to przesunięcie drugi raz. */
#vp .sheet.pelny.on { transform: translate3d(0, var(--vvy, 0px), 0); }
/* Podążanie za widokiem musi być NATYCHMIASTOWE. Animowane zamienia zwykłe
   przewinięcie w gonitwę panelu za ekranem — to jest to „drganie". */
#vp .sheet.pelny.klawiatura { transition: none; }
/* Zmiana wysokosci przy wejsciu klawiatury ma byc NATYCHMIASTOWA. Animowana
   wygladalaby jak szarpniecie, bo klawiatura i tak wjezdza wlasna animacja
   systemowa — dwie naraz to dokladnie ten „glitch". */
#vp .sheet.pelny { transition: transform var(--slow); }
#vp .sheet.pelny .grip { display: none; }
/* Nagłówek zostaje przyklejony u góry — na pełnej stronie klient musi widzieć,
   gdzie jest i jak wyjść, nawet po przewinięciu długiego koszyka. */
#vp .sheet.pelny .sheet-h {
  position: sticky; top: 0; z-index: 2;
  background: var(--panel);
  box-shadow: inset 0 -1px 0 0 var(--edge);
}

#vp .grip { width: 40px; height: 4px; margin: 10px auto 0; border-radius: var(--pill); background: var(--edge-2); flex: none; }

#vp .sheet-h {
  display: flex; align-items: center; gap: 10px;
  padding: 15px 14px 15px 20px;
  border-bottom: 1px solid var(--edge);
  flex: none;
}
#vp .sheet-h h2 { flex: 1; font-size: 17px; font-weight: 600; letter-spacing: -.03em; }

/* `min-height: 0` NIE jest ozdobnikiem. Element w kolumnie flex domyślnie nie
   kurczy się poniżej swojej zawartości — lista pozycji rozpychała więc panel
   od środka i stopka z kwotą i przyciskiem wychodziła POD ekran. Przy otwartej
   klawiaturze, gdy miejsca jest o połowę mniej, wyglądało to tak, jakby
   „przycisk zamawiam znikał", a pole lądowało pod klawiaturą. */
#vp .sheet-b {
  flex: 1; min-height: 0;
  overflow-y: auto; overscroll-behavior: contain;
  padding: 8px 20px;
}
#vp .sheet-f {
  flex: none;
  padding: 16px 20px calc(18px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--edge);
  background: linear-gradient(180deg, #0a0a0c, var(--panel));
}

/* ── Pasek do darmowej wysyłki ──────────────────────────────────────────── */
#vp .freeship {
  margin: 6px 0 14px;
  padding: 13px 15px;
  border-radius: var(--r-sm);
  background: var(--raise);
  box-shadow: inset 0 0 0 1px var(--edge);
}
#vp .freeship .t { display: flex; justify-content: space-between; gap: 12px; margin-bottom: 9px; font-size: 13px; color: var(--dim); }
#vp .freeship .t b { color: var(--ink); font-weight: 600; }
#vp .freeship .t > span:first-child { display: inline-flex; align-items: center; gap: 7px; }
#vp .freeship .t svg { width: 13px; height: 13px; flex: none; color: var(--ok); }
#vp .freeship .rail { height: 4px; border-radius: var(--pill); background: var(--raise-2); overflow: hidden; }
#vp .freeship .fill {
  height: 100%; border-radius: var(--pill);
  background: linear-gradient(90deg, rgba(227, 178, 60, .5), var(--volt));
  transform-origin: 0 50%; transform: scaleX(0);
  transition: transform 800ms cubic-bezier(.16, 1, .3, 1);
}
/* Po osiagnieciu progu pasek nie niesie juz informacji — zwija sie do
   jednej linii potwierdzenia, zeby nie zjadac wysokosci koszyka. */
#vp .freeship.done {
  padding: 10px 14px;
  box-shadow: inset 0 0 0 1px rgba(74, 222, 128, .28);
  background: linear-gradient(90deg, rgba(74, 222, 128, .07), transparent 62%), var(--raise);
}
#vp .freeship.done .t { margin-bottom: 0; }
#vp .freeship.done .t b { color: var(--ok); }
#vp .freeship.done .t .tag { display: none; }
#vp .freeship.done .rail { display: none; }

/* ── Placeholder braku zdjęcia ──────────────────────────────────────────────
   Dopóki produkt nie ma zdjęcia, pokazujemy inicjał na markowym tle zamiast
   pustego boksu z ikonką. Wygląda celowo — cztery takie w koszyku nie robią
   już wrażenia niedokończonego szablonu. */
#vp .ph {
  position: relative; display: grid; place-items: center; overflow: hidden;
  background:
    radial-gradient(130% 130% at 28% 0%, rgba(227, 178, 60, .08), transparent 58%),
    linear-gradient(158deg, var(--raise-2), var(--panel));
  box-shadow: inset 0 0 0 1px var(--edge);
}
#vp .ph::after {
  content: ""; position: absolute; inset: 0;
  background: radial-gradient(80% 60% at 50% 120%, rgba(255, 255, 255, .05), transparent 70%);
}
#vp .ph span {
  position: relative; font-family: var(--display); font-weight: 700;
  color: var(--dim); letter-spacing: -.05em; line-height: 1;
  opacity: .85;
}
#vp .line .ph.pic { width: 78px; height: 78px; border-radius: var(--r-xs); }
#vp .line .ph.pic span { font-size: 34px; }
#vp .card-ph { position: absolute; inset: 0; }
#vp .card-ph span { font-size: clamp(52px, 15vw, 92px); }

/* ── Pozycje koszyka ────────────────────────────────────────────────────────
   Każda pozycja to własna karta, a nie wiersz oddzielony kreską: przy dwóch
   produktach lista wyglądała jak tabelka, a nie jak zawartość koszyka. */
#vp .line {
  display: grid; grid-template-columns: 78px 1fr; gap: 15px;
  margin-bottom: 10px; padding: 14px;
  border-radius: var(--r-sm);
  background: var(--raise);
  box-shadow: inset 0 0 0 1px var(--edge);
  animation: vp-in 340ms cubic-bezier(.25, .8, .35, 1) backwards;
  transition: box-shadow var(--fast);
}
@keyframes vp-in { from { opacity: 0; transform: translateY(10px); } }
#vp .line:last-child { margin-bottom: 0; }
@media (hover: hover) and (pointer: fine) {
  #vp .line:hover { box-shadow: inset 0 0 0 1px var(--edge-2); }
}
#vp .line .pic {
  width: 78px; height: 78px; border-radius: var(--r-xs);
  object-fit: cover; background: var(--raise-2);
  box-shadow: inset 0 0 0 1px var(--edge);
}
#vp .line .pic-x { display: grid; place-items: center; color: var(--faint); }
#vp .line .col { display: flex; flex-direction: column; gap: 11px; min-width: 0; }
#vp .line .row1 { display: flex; justify-content: space-between; gap: 12px; align-items: flex-start; }
#vp .line .nm { font-size: 15px; font-weight: 600; letter-spacing: -.015em; line-height: 1.35; }
#vp .line .vr { margin-top: -4px; font-size: 12px; color: var(--dim); }
/* Kwota nie ma prawa złamać się w połowie. */
#vp .line .vr .u { white-space: nowrap; font-family: var(--num); font-size: 12px; }
/* Oszczędność z progu hurtowego — widoczna dokładnie tam, gdzie powstała. */
#vp .bulk-win {
  display: inline-flex; align-items: center; gap: 5px;
  margin-left: 8px; padding: 2px 8px;
  border-radius: var(--pill);
  background: rgba(74, 222, 128, .1);
  box-shadow: inset 0 0 0 1px rgba(74, 222, 128, .28);
  font-family: var(--num); font-size: 12px; letter-spacing: .02em;
  color: var(--ok); white-space: nowrap;
}
#vp .bulk-win svg { width: 11px; height: 11px; }
#vp .line .lp { font-family: var(--num); font-size: 15px; font-weight: 650; letter-spacing: -.03em; white-space: nowrap; }
#vp .line .row2 { display: flex; justify-content: space-between; align-items: center; gap: 12px; }

#vp .stepper {
  display: inline-flex; align-items: center;
  border-radius: var(--pill);
  box-shadow: inset 0 0 0 1px var(--edge);
  background: var(--raise);
  overflow: hidden;
}
#vp .stepper button {
  width: 32px; height: 32px; display: grid; place-items: center; color: var(--dim);
  transition: background var(--fast), color var(--fast);
}
#vp .stepper button:hover { background: var(--raise-2); color: var(--ink); }
#vp .stepper button:active { transform: scale(.88); }
#vp .stepper svg { width: 13px; height: 13px; }
#vp .stepper b { min-width: 28px; text-align: center; font-family: var(--num); font-size: 13px; font-weight: 650; }
/* Pole ilości — wygląda jak liczba w środku steppera, ale można w nie wpisać.
   Oszczędza setki kliknięć przy zamówieniach hurtowych. */
#vp .stepper .qin {
  width: 44px; min-width: 44px; text-align: center; border: 0; background: transparent;
  color: var(--ink); font-family: var(--num); font-size: 13px; font-weight: 650;
  padding: 6px 2px; -moz-appearance: textfield; appearance: textfield;
  transition: box-shadow var(--fast), background var(--fast);
}
#vp .stepper .qin::-webkit-outer-spin-button,
#vp .stepper .qin::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
#vp .stepper .qin:focus {
  outline: none; background: var(--raise-2);
  box-shadow: inset 0 -2px 0 0 var(--volt);
}

/* Usuwanie: ikona kosza zamiast słowa „Usuń" wciśniętego w róg wiersza. */
#vp .drop-line {
  display: inline-flex; align-items: center; justify-content: center;
  width: 34px; height: 34px;
  border-radius: var(--r-xs);
  color: var(--faint);
  transition: color var(--fast), background var(--fast);
}
#vp .drop-line svg { width: 15px; height: 15px; }
#vp .drop-line:hover { color: var(--bad); background: rgba(251, 113, 133, .1); }
#vp .drop-line:active { transform: scale(.9); }

/* ── Rachunek ───────────────────────────────────────────────────────────── */
#vp .receipt { margin-bottom: 16px; }
#vp .rrow {
  display: flex; justify-content: space-between; align-items: baseline; gap: 14px;
  padding: 5px 0;
  font-size: 13px; color: var(--dim);
}
#vp .rrow span:last-child { font-family: var(--num); color: var(--ink); letter-spacing: -.02em; }
#vp .rrow.free span:last-child { color: var(--ok); }
#vp .rrow.sum {
  margin-top: 10px; padding-top: 14px;
  border-top: 1px dashed var(--edge-2);
  font-size: 15px; color: var(--ink);
}
#vp .rrow.sum span:last-child { font-size: 24px; font-weight: 500; letter-spacing: -.045em; }

#vp .todo {
  display: flex; align-items: center; justify-content: center; gap: 8px;
  margin-bottom: 10px;
  font-size: 12px; color: var(--faint); text-align: center;
}
#vp .todo svg { width: 14px; height: 14px; flex: none; }

#vp .fineprint { margin-top: 12px; text-align: center; font-size: 12px; line-height: 1.55; color: var(--faint); }
#vp .fineprint a { color: var(--dim); text-decoration: underline; text-underline-offset: 2px; }

/* ── Pusty koszyk ───────────────────────────────────────────────────────── */
#vp .blank {
  display: flex; flex-direction: column; align-items: center;
  padding: 60px 20px 50px; text-align: center;
}
#vp .blank .orb {
  position: relative;
  width: 108px; height: 108px; margin-bottom: 26px;
  display: grid; place-items: center;
}
#vp .blank .orb::before, #vp .blank .orb::after {
  content: ""; position: absolute; border-radius: 50%; border: 1px dashed var(--edge-2);
}
#vp .blank .orb::before { inset: 0; animation: vp-spin 24s linear infinite; }
#vp .blank .orb::after { inset: 18px; border-style: solid; border-color: var(--edge); }
#vp .blank .orb svg { width: 32px; height: 32px; color: var(--faint); }
#vp .blank h3 { font-size: 17px; font-weight: 600; letter-spacing: -.03em; }
#vp .blank p { margin-top: 8px; max-width: 30ch; font-size: 13px; color: var(--faint); line-height: 1.55; }
#vp .blank .btn { margin-top: 24px; }

/* ── Formularz ──────────────────────────────────────────────────────────── */
#vp .fields { display: flex; flex-direction: column; gap: 11px; margin-bottom: 20px; }
#vp .field { position: relative; }
#vp .field input {
  width: 100%; height: 62px;
  padding: 24px 46px 8px 16px;
  border-radius: var(--r-sm);
  box-shadow: inset 0 0 0 1px var(--edge);
  background: var(--raise);
  font-size: 15px; letter-spacing: -.01em;
  transition: box-shadow var(--fast), background var(--fast);
}
#vp .field input::placeholder { color: transparent; }
#vp .field input:hover { box-shadow: inset 0 0 0 1px var(--edge-2); }
#vp .field input:focus { box-shadow: inset 0 0 0 1.5px rgba(227, 178, 60, .65); background: var(--raise-2); }
#vp .field label {
  position: absolute; left: 17px; top: 20px;
  font-size: 15px; color: var(--faint);
  pointer-events: none; transform-origin: 0 0;
  transition: transform var(--fast), color var(--fast);
}
#vp .field input:focus + label,
#vp .field input:not(:placeholder-shown) + label {
  transform: translateY(-12px) scale(.72); color: var(--dim);
}
/* Znacznik poprawności pojawia się od razu po wpisaniu właściwej wartości. */
#vp .field .state {
  position: absolute; right: 15px; top: 50%;
  transform: translateY(-50%) scale(.5);
  opacity: 0;
  transition: transform var(--mid), opacity var(--fast);
}
#vp .field .state svg { width: 18px; height: 18px; color: var(--ok); }
#vp .field.good .state { opacity: 1; transform: translateY(-50%) scale(1); }
#vp .field.bad input { box-shadow: inset 0 0 0 1.5px rgba(251, 113, 133, .65); }
#vp .field .hint { margin: 7px 4px 0; font-size: 12px; color: var(--faint); }
#vp .field.bad .hint { color: var(--bad); }

#vp .hp { position: absolute !important; left: -9999px; top: 0; width: 1px; height: 1px; opacity: 0; pointer-events: none; }

/* ── Metody płatności ───────────────────────────────────────────────────── */
#vp .pays { display: flex; flex-direction: column; gap: 7px; margin-bottom: 18px; }
#vp .pay {
  display: flex; align-items: center; gap: 13px;
  padding: 14px 16px;
  border-radius: var(--r-sm);
  box-shadow: inset 0 0 0 1px var(--edge);
  background: var(--raise);
  text-align: left;
  transition: box-shadow var(--fast), background var(--fast), transform var(--fast);
}
#vp .pay:hover { box-shadow: inset 0 0 0 1px var(--edge-2); }
#vp .pay:active { transform: scale(.99); }
#vp .pay.on { box-shadow: inset 0 0 0 1.5px rgba(227, 178, 60, .6); background: var(--volt-dim); }
#vp .pay .dot {
  width: 18px; height: 18px; flex: none;
  border-radius: 50%;
  box-shadow: inset 0 0 0 1.5px var(--edge-2);
  display: grid; place-items: center;
  transition: box-shadow var(--fast);
}
#vp .pay .dot::after {
  content: ""; width: 9px; height: 9px; border-radius: 50%;
  background: var(--volt);
  transform: scale(0);
  transition: transform 240ms cubic-bezier(.3, 1.6, .5, 1);
}
#vp .pay.on .dot { box-shadow: inset 0 0 0 1.5px var(--volt); }
#vp .pay.on .dot::after { transform: scale(1); }
#vp .pay .txt { flex: 1; min-width: 0; }
#vp .pay .txt b { display: block; font-size: 15px; font-weight: 600; letter-spacing: -.02em; }
#vp .pay .txt span { font-size: 12px; color: var(--faint); }
#vp .pay .fee { font-family: var(--num); font-size: 12px; color: var(--dim); white-space: nowrap; }
#vp .pay .fee.zero { color: var(--ok); }

/* ── Zgody ──────────────────────────────────────────────────────────────── */
#vp .consents { display: flex; flex-direction: column; gap: 12px; margin-bottom: 16px; }
#vp .consent { display: flex; gap: 12px; align-items: flex-start; font-size: 13px; line-height: 1.5; color: var(--dim); cursor: pointer; }
#vp .consent input { position: absolute; opacity: 0; width: 0; height: 0; }
#vp .consent .box {
  width: 20px; height: 20px; flex: none; margin-top: 0;
  border-radius: 6px;
  box-shadow: inset 0 0 0 1.5px var(--edge-2);
  display: grid; place-items: center;
  transition: background var(--fast), box-shadow var(--fast);
}
#vp .consent .box svg { width: 12px; height: 12px; color: #0a0a0b; transform: scale(0); transition: transform 220ms cubic-bezier(.3, 1.7, .5, 1); }
#vp .consent input:checked + .box { background: var(--volt); box-shadow: inset 0 0 0 1.5px var(--volt); }
#vp .consent input:checked + .box svg { transform: scale(1); }
#vp .consent input:focus-visible + .box { outline: 2px solid var(--volt); outline-offset: 3px; }
#vp .consent a { color: var(--ink); text-decoration: underline; text-underline-offset: 2px; }

/* ── Alert ──────────────────────────────────────────────────────────────── */
#vp .alert {
  display: flex; gap: 11px; align-items: flex-start;
  margin-bottom: 14px; padding: 13px 15px;
  border-radius: var(--r-sm);
  box-shadow: inset 0 0 0 1px rgba(251, 113, 133, .32);
  background: rgba(251, 113, 133, .09);
  font-size: 13px; color: #ffccd4;
  animation: vp-shake 360ms cubic-bezier(.36, .07, .19, .97);
}
#vp .alert svg { width: 16px; height: 16px; flex: none; margin-top: 1px; }
@keyframes vp-shake {
  10%, 90% { transform: translateX(-1.5px); }
  30%, 70% { transform: translateX(2.5px); }
  50% { transform: translateX(-2.5px); }
}

/* ── Potwierdzenie ──────────────────────────────────────────────────────── */
/* Ekran „Zamówienie przyjęte”. Nazwa `done-screen`, a nie samo `done`:
   `.done` to też stan „próg osiągnięty” na pasku ładowania, pasku darmowej
   wysyłki i dopisku w koszyku. Wspólna nazwa dawała im marginesy tego
   ekranu (56 px u góry) i rozsadzała pasek koszyka na dole strony. */
#vp .done-screen { padding: 56px 8px 44px; text-align: center; }
#vp .done-screen .seal {
  position: relative;
  width: 92px; height: 92px; margin: 0 auto 28px;
  display: grid; place-items: center;
}
#vp .done-screen .seal::before {
  content: ""; position: absolute; inset: 0; border-radius: 50%;
  background: radial-gradient(closest-side, rgba(74, 222, 128, .18), transparent);
  animation: vp-pulse-ring 2.6s ease-out infinite;
}
@keyframes vp-pulse-ring { 0% { transform: scale(.85); opacity: 1; } 100% { transform: scale(1.35); opacity: 0; } }
#vp .done-screen .seal .disc {
  position: relative;
  width: 72px; height: 72px; border-radius: 50%;
  display: grid; place-items: center;
  background: rgba(74, 222, 128, .12);
  box-shadow: inset 0 0 0 1px rgba(74, 222, 128, .35);
  animation: vp-pop 560ms cubic-bezier(.2, 1.6, .4, 1) backwards;
}
@keyframes vp-pop { from { transform: scale(.4); opacity: 0; } }
#vp .done-screen .seal svg { width: 32px; height: 32px; color: var(--ok); }
#vp .done-screen h3 { font-size: 24px; font-weight: 700; letter-spacing: -.035em; }
#vp .done-screen .ref {
  display: inline-flex; align-items: center; gap: 10px;
  margin: 16px 0 18px; padding: 9px 16px;
  border-radius: var(--r-xs);
  box-shadow: inset 0 0 0 1px var(--edge);
  background: var(--raise);
  font-family: var(--num); font-size: 13px;
}
#vp .done-screen p { font-size: 15px; color: var(--dim); max-width: 32ch; margin-inline: auto; line-height: 1.6; }

/* ══════════════════════════════════════════════════════════════════════════
   PROFIL
   ══════════════════════════════════════════════════════════════════════════ */
#vp .profile { padding-top: 10px; }
#vp .prof-top { display: flex; align-items: center; gap: 16px; margin-bottom: 20px; }
#vp .prof-av {
  position: relative;
  width: 72px; height: 72px; flex: none;
  display: grid; place-items: center;
}
#vp .prof-av .face { width: 60px; height: 60px; border-radius: 50%; object-fit: cover; background: var(--raise-2); }
#vp .prof-av .face.av-mono { font-size: 24px; }
/* Pierścień postępu do następnej rangi rysowany kołowym gradientem. */
#vp .prof-av .ring {
  position: absolute; inset: 0; border-radius: 50%;
  background: conic-gradient(var(--volt) var(--p, 0%), var(--edge) 0);
  -webkit-mask: radial-gradient(closest-side, transparent 84%, #000 85%);
  mask: radial-gradient(closest-side, transparent 84%, #000 85%);
  transition: --p 900ms ease;
}
#vp .prof-id { min-width: 0; }
#vp .prof-id b { display: block; font-size: 20px; font-weight: 700; letter-spacing: -.032em; }
#vp .prof-id .since {
  display: block; margin-top: 8px;
  font-size: 12px; color: var(--faint); line-height: 1.5;
}
/* Reguła `.prof-id b` ustawia nazwę konta na 19 px w bloku — daty w tej linii
   dziedziczyły to i każda lądowała w osobnym, wielkim wierszu. */
#vp .prof-id .since b {
  display: inline; font-size: 12px; font-weight: 600;
  color: var(--dim); letter-spacing: 0;
}
#vp .prof-id .rank {
  display: inline-flex; align-items: center; gap: 7px;
  margin-top: 6px; padding: 4px 11px;
  border-radius: var(--pill);
  background: var(--volt-dim);
  box-shadow: inset 0 0 0 1px rgba(227, 178, 60, .28);
  font-size: 12px; font-weight: 600; color: var(--volt-2);
  white-space: nowrap;
}

/* Jedna karta na liczby i postęp rangi.
   Wcześniej były to trzy osobne prostokąty jeden pod drugim (statystyki,
   ranga, kalendarium), a statystyki dodatkowo rozdzielone pionowymi liniami.
   Ekran czytało się jak arkusz kalkulacyjny: same ramki, żadnej hierarchii.
   Teraz liczby i postęp mieszkają razem, bo jedno wynika z drugiego, a rytm
   robią odstępy — nie kreski. */
#vp .prof-card {
  margin-bottom: 8px;
  border-radius: var(--r);
  background: var(--raise);
  box-shadow: inset 0 0 0 1px var(--edge);
  overflow: hidden;
}
#vp .prof-stats {
  display: grid; grid-template-columns: repeat(3, 1fr);
  gap: 4px; padding: 18px 18px 6px;
}
#vp .prof-stats div { min-width: 0; }
#vp .prof-stats b {
  display: block;
  font-family: var(--num); font-size: 20px; font-weight: 650;
  letter-spacing: -.035em; line-height: 1.1;
}
/* Podpis pod liczbą to opis, nie etykieta formularza — wersaliki z rozstrzelonym
   odstępem robiły z trzech krótkich słów trzy bloki hałasu. Małe litery czyta
   się od razu, a liczba nad nimi i tak przyciąga wzrok pierwsza. */
#vp .prof-stats span {
  display: block; margin-top: 5px;
  font-size: 12px; color: var(--faint); letter-spacing: 0;
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}

#vp .prof-next { padding: 14px 18px 18px; }
#vp .prof-next .t {
  display: flex; flex-wrap: wrap; align-items: baseline;
  justify-content: space-between;
  gap: 4px 14px; margin-bottom: 9px;
  font-size: 13px; color: var(--dim);
}
#vp .prof-next .t > span:first-child { min-width: 0; }
#vp .prof-next .t b { color: var(--ink); font-weight: 650; }
#vp .prof-next .t .left {
  font-family: var(--num); font-size: 12px; color: var(--volt-2); white-space: nowrap;
}
#vp .prof-next .rail { height: 5px; border-radius: var(--pill); background: var(--void); overflow: hidden; }
#vp .prof-next .fill {
  height: 100%; border-radius: var(--pill);
  background: linear-gradient(90deg, rgba(227, 178, 60, .45), var(--volt));
  transform-origin: 0 50%; transform: scaleX(0);
  transition: transform 900ms cubic-bezier(.16, 1, .3, 1) 150ms;
}

/* Karta dla list w koncie (najczęściej kupowane, ostatnio kupione).
   Gołe wiersze na tle panelu wyglądały jak tekst zgubiony między sekcjami. */
#vp .card-soft {
  padding: 6px 16px;
  border-radius: var(--r);
  background: var(--raise);
  box-shadow: inset 0 0 0 1px var(--edge);
}

/* Zapisane dane wysyłki */
#vp .saved {
  display: flex; align-items: center; gap: 12px;
  margin-bottom: 22px; padding: 14px 18px;
  border-radius: var(--r);
  background: var(--raise);
  box-shadow: inset 0 0 0 1px var(--edge);
}
#vp .saved svg { width: 17px; height: 17px; color: var(--faint); flex: none; }
#vp .saved .d { flex: 1; min-width: 0; }
#vp .saved .d b { display: block; font-family: var(--mono); font-size: 13px; letter-spacing: .04em; }
#vp .saved .clear { font-size: 12px; color: var(--faint); }
#vp .saved .clear:hover { color: var(--bad); }

/* Tryb anonimowy — jeden wiersz z wyjasnieniem i przelacznikiem. Stan „on”
   znaczy „jestes ukryty", wiec zaznaczamy go kolorem marki, nie ostrzegawczym:
   to wybor klienta, a nie problem do naprawienia. */
#vp .privacy {
  display: flex; align-items: center; gap: 14px;
  margin-bottom: 22px; padding: 16px 18px;
  border-radius: var(--r);
  background: var(--raise);
  box-shadow: inset 0 0 0 1px var(--edge);
}
#vp .privacy.on { box-shadow: inset 0 0 0 1px var(--volt-dim), inset 3px 0 0 0 var(--volt); }
#vp .privacy .d { flex: 1; min-width: 0; }
#vp .privacy .d b { display: block; font-size: 13px; font-weight: 650; letter-spacing: -.015em; }
#vp .privacy .d .tag { display: block; margin-top: 4px; text-transform: none; letter-spacing: 0; }
#vp .privacy .btn { flex: none; padding: 9px 18px; font-size: 13px; }
#vp .privacy .btn[disabled] { opacity: .55; pointer-events: none; }

/* Historia zamówień */
#vp .ord {
  padding: 15px 0;
  border-bottom: 1px solid var(--edge);
}
#vp .ord:last-child { border-bottom: 0; }
#vp .ord .h { display: flex; align-items: center; justify-content: space-between; gap: 12px; }
#vp .ord .id { font-family: var(--mono); font-size: 13px; letter-spacing: .04em; }
#vp .ord .meta { margin-top: 7px; font-size: 13px; color: var(--faint); }
#vp .ord .meta b { font-family: var(--num); color: var(--dim); font-weight: 650; }
#vp .ord .trk { display: inline-flex; align-items: center; gap: 8px; margin-top: 9px; font-family: var(--mono); font-size: 12px; letter-spacing: .04em; color: var(--dim); }
#vp .ord .trk svg { width: 14px; height: 14px; }
#vp .ord .kill {
  margin-top: 11px; padding: 6px 13px;
  border-radius: var(--pill);
  box-shadow: inset 0 0 0 1px rgba(251, 113, 133, .32);
  font-size: 12px; color: var(--bad);
  transition: background var(--fast);
}
#vp .ord .kill:hover { background: rgba(251, 113, 133, .1); }

#vp .status {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 5px 11px;
  border-radius: var(--pill);
  font-family: var(--num); font-size: 12px; letter-spacing: .08em; text-transform: uppercase;
  white-space: nowrap;
  box-shadow: inset 0 0 0 1px var(--edge);
  color: var(--dim); background: var(--raise);
}
#vp .status i { width: 5px; height: 5px; border-radius: 50%; background: currentColor; font-style: normal; }
#vp .status.awaiting_acceptance { color: #c4b5fd; box-shadow: inset 0 0 0 1px rgba(196, 181, 253, .3); }
#vp .status.accepted { color: var(--volt-2); box-shadow: inset 0 0 0 1px rgba(227, 178, 60, .3); }
#vp .status.paid, #vp .status.completed { color: var(--ok); box-shadow: inset 0 0 0 1px rgba(74, 222, 128, .3); }
#vp .status.sent { color: #7dd3fc; box-shadow: inset 0 0 0 1px rgba(125, 211, 252, .3); }
#vp .status.rejected, #vp .status.cancelled { color: var(--bad); box-shadow: inset 0 0 0 1px rgba(251, 113, 133, .3); }

#vp .signout {
  width: 100%; height: 46px;
  margin-top: 6px;
  border-radius: var(--pill);
  box-shadow: inset 0 0 0 1px var(--edge);
  font-size: 13px; color: var(--dim);
  transition: box-shadow var(--fast), color var(--fast);
}
#vp .signout:hover { box-shadow: inset 0 0 0 1px var(--edge-2); color: var(--ink); }

/* Zachęta do logowania */
#vp .gate { padding: 46px 4px 30px; text-align: center; }
#vp .gate .badge {
  width: 76px; height: 76px; margin: 0 auto 24px;
  border-radius: 22px;
  display: grid; place-items: center;
  background: rgba(88, 101, 242, .13);
  box-shadow: inset 0 0 0 1px rgba(88, 101, 242, .35);
}
#vp .gate .badge svg { width: 36px; height: 36px; color: #a5adff; }
#vp .gate h3 { font-size: 20px; font-weight: 700; letter-spacing: -.032em; }
#vp .gate p { margin-top: 10px; font-size: 13px; color: var(--dim); max-width: 32ch; margin-inline: auto; line-height: 1.6; }
#vp .gate ul { margin-top: 22px; display: flex; flex-direction: column; gap: 11px; text-align: left; }
#vp .gate li { display: flex; align-items: center; gap: 11px; font-size: 13px; color: var(--dim); }
#vp .gate li svg { width: 16px; height: 16px; color: var(--volt); flex: none; }

/* ══════════════════════════════════════════════════════════════════════════
   PASEK SEKCJI (Katalog / Ranking / Discord)
   ══════════════════════════════════════════════════════════════════════════ */
#vp .secnav {
  display: flex; gap: 10px;
  max-width: var(--max); margin-inline: auto;
  padding: 26px var(--gut) 0;
}
#vp .sec {
  flex: 1;
  display: inline-flex; align-items: center; justify-content: center; gap: 9px;
  height: 52px;
  border-radius: var(--r-sm);
  background: var(--panel);
  box-shadow: inset 0 0 0 1px var(--edge);
  font-size: 13px; font-weight: 600; letter-spacing: -.01em;
  color: var(--dim);
  transition: box-shadow var(--fast), color var(--fast), transform var(--fast),
              background var(--fast);
}
#vp .sec svg { width: 17px; height: 17px; }
@media (hover: hover) and (pointer: fine) {
  #vp .sec:hover { color: var(--ink); background: var(--raise); box-shadow: inset 0 0 0 1px var(--edge-2); }
}
#vp .sec:active { transform: scale(.97); }

/* ══════════════════════════════════════════════════════════════════════════
   RANKING KLIENTÓW
   ══════════════════════════════════════════════════════════════════════════ */
#vp .lead-note {
  display: flex; gap: 11px; align-items: flex-start;
  margin: 4px 0 18px; padding: 13px 15px;
  border-radius: var(--r-sm);
  background: var(--raise);
  box-shadow: inset 0 0 0 1px var(--edge);
  font-size: 13px; color: var(--dim); line-height: 1.55;
}
#vp .lead-note svg { width: 16px; height: 16px; flex: none; margin-top: 1px; color: var(--volt); }

#vp .leads { display: flex; flex-direction: column; }
#vp .lead {
  display: grid; grid-template-columns: 34px 44px minmax(0, 1fr) auto;
  gap: 13px; align-items: center;
  padding: 14px 4px;
  border-bottom: 1px solid var(--edge);
  animation: vp-in 340ms cubic-bezier(.25, .8, .35, 1) backwards;
}
#vp .lead:last-child { border-bottom: 0; }
#vp .lead .pl {
  font-family: var(--num); font-size: 15px; font-weight: 650;
  color: var(--faint); letter-spacing: -.02em; text-align: center;
}
#vp .lead .lav {
  width: 44px; height: 44px; border-radius: 50%;
  object-fit: cover; background: var(--raise-2);
}
#vp .lead .lav.av-mono { font-size: 17px; border-radius: 50%; }
#vp .lead .who { min-width: 0; display: flex; flex-direction: column; gap: 4px; }
#vp .lead .who b {
  font-size: 15px; font-weight: 600; letter-spacing: -.02em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#vp .lead .amt { font-family: var(--num); font-size: 15px; font-weight: 650; letter-spacing: -.03em; white-space: nowrap; }

/* Podium — miejsca 1-3 dostają kolor numeru i cienką obwódkę awatara. */
#vp .lead.podium.p1 .pl { color: var(--volt); }
#vp .lead.podium.p2 .pl { color: #d7d7de; }
#vp .lead.podium.p3 .pl { color: #d8a47f; }
#vp .lead.podium.p1 .lav { box-shadow: 0 0 0 2px rgba(227, 178, 60, .55); }
#vp .lead.podium.p2 .lav { box-shadow: 0 0 0 2px rgba(215, 215, 222, .4); }
#vp .lead.podium.p3 .lav { box-shadow: 0 0 0 2px rgba(216, 164, 127, .4); }
#vp .lead.podium.p1 .amt { color: var(--volt); }

/* Własny wiersz — klient od razu widzi siebie. (Nie `.me` — ta klasa należy
   do przycisku konta w nawigacji i niesie sztywną wysokość 42 px.) */
#vp .lead.mine {
  margin-inline: -10px; padding-inline: 14px;
  border-radius: var(--r-sm); border-bottom-color: transparent;
  background: var(--volt-dim);
  box-shadow: inset 0 0 0 1px rgba(227, 178, 60, .25);
}

/* ══════════════════════════════════════════════════════════════════════════
   ZAKŁADKA DISCORD
   ══════════════════════════════════════════════════════════════════════════ */
#vp .dsc { padding-top: 6px; }
#vp .dsc-top {
  display: flex; align-items: center; justify-content: space-between;
  margin-bottom: 20px;
}
#vp .dsc-top > svg {
  width: 52px; height: 52px; padding: 12px;
  border-radius: 16px; color: #a5adff;
  background: rgba(88, 101, 242, .13);
  box-shadow: inset 0 0 0 1px rgba(88, 101, 242, .35);
}
#vp .dsc .live {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 7px 13px;
  border-radius: var(--pill);
  background: var(--raise);
  box-shadow: inset 0 0 0 1px var(--edge);
  font-family: var(--num); font-size: 12px; letter-spacing: .04em;
  color: var(--dim);
}
#vp .dsc .live i {
  width: 6px; height: 6px; border-radius: 50%;
  background: var(--ok); font-style: normal;
  animation: vp-led 2.6s ease-out infinite;
}
#vp .dsc h3 { font-size: 20px; font-weight: 700; letter-spacing: -.032em; }
#vp .dsc p { margin-top: 10px; font-size: 13px; color: var(--dim); line-height: 1.65; }
#vp .perks { margin-top: 20px; display: flex; flex-direction: column; gap: 11px; }
#vp .perks li { display: flex; align-items: flex-start; gap: 11px; font-size: 13px; color: var(--dim); line-height: 1.5; }
#vp .perks li svg { width: 15px; height: 15px; flex: none; margin-top: 2px; color: var(--ok); }

#vp .btn-discord {
  background: var(--discord); color: #fff;
  display: inline-flex; align-items: center; justify-content: center; gap: 10px;
}
#vp .btn-discord svg { width: 19px; height: 19px; }
#vp .btn-discord:hover { filter: brightness(1.12); }

/* ══════════════════════════════════════════════════════════════════════════
   KARTA PRODUKTU — galeria i cennik hurtowy
   ══════════════════════════════════════════════════════════════════════════ */
#vp .gal { margin: 2px 0 18px; }
#vp .gal-main {
  position: relative;
  /* TE SAME proporcje co kafelek w katalogu (4:5). Wczesniej bylo 4:3, wiec
     to samo zdjecie po kliknieciu bylo kadrowane inaczej niz na kafelku —
     zwlaszcza zdjecia pionowe (butelki, urzadzenia) traci wtedy gore i dol.
     Klient widzial „ladnie" na liscie i „zle" po wejsciu w produkt. */
  aspect-ratio: 4 / 5;
  border-radius: var(--r-sm);
  overflow: hidden;
  background: radial-gradient(72% 58% at 50% 62%, rgba(255, 255, 255, .045), transparent 70%), var(--raise);
  box-shadow: inset 0 0 0 1px var(--edge);
}
#vp .gal-main img {
  width: 100%; height: 100%;
  /* `contain`, nie `cover`: w widoku produktu klient oglada TOWAR i musi
     zobaczyc go w calosci — obciete krawedzie opakowania albo ucieta nazwa
     smaku to dokladnie ten moment, w ktorym rezygnuje z zakupu. Puste boki
     wypelnia gradient kadru, wiec nie robia sie z tego czarne pasy. */
  object-fit: contain;
  padding: 10px;
  animation: vp-fadein 260ms ease;
}
@keyframes vp-fadein { from { opacity: 0; } }
#vp .gal-main.void { display: grid; place-items: center; }

#vp .gnav {
  position: absolute; top: 50%; transform: translateY(-50%);
  width: 38px; height: 38px;
  display: grid; place-items: center;
  border-radius: 50%;
  color: var(--ink);
  background: rgba(8, 8, 10, .62);
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  box-shadow: inset 0 0 0 1px var(--edge-2);
  transition: background var(--fast), transform var(--fast);
}
#vp .gnav.l { left: 10px; }
#vp .gnav.r { right: 10px; }
#vp .gnav svg { width: 16px; height: 16px; }
#vp .gnav:hover { background: rgba(8, 8, 10, .85); }
#vp .gnav:active { transform: translateY(-50%) scale(.92); }
#vp .gcount {
  position: absolute; right: 12px; bottom: 10px;
  padding: 5px 10px; border-radius: var(--pill);
  background: rgba(8, 8, 10, .62);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  box-shadow: inset 0 0 0 1px var(--edge-2);
}

#vp .thumbs {
  display: flex; gap: 8px; margin-top: 10px;
  overflow-x: auto; padding-bottom: 4px;
  scrollbar-width: none;
}
#vp .thumbs::-webkit-scrollbar { display: none; }
#vp .th {
  width: 58px; height: 58px; flex: none;
  border-radius: 10px; overflow: hidden;
  box-shadow: inset 0 0 0 1px var(--edge);
  opacity: .55;
  transition: opacity var(--fast), box-shadow var(--fast), transform var(--fast);
}
#vp .th img { width: 100%; height: 100%; object-fit: cover; }
#vp .th:hover { opacity: .85; }
#vp .th:active { transform: scale(.94); }
#vp .th.on { opacity: 1; box-shadow: inset 0 0 0 2px var(--volt); }

/* Znacznik liczby zdjęć na kafelku katalogu. */
#vp .shots {
  position: absolute; top: 12px; left: 12px;
  display: inline-flex; align-items: center; gap: 5px;
  padding: 5px 9px; border-radius: var(--pill);
  background: rgba(8, 8, 10, .62);
  backdrop-filter: blur(8px); -webkit-backdrop-filter: blur(8px);
  box-shadow: inset 0 0 0 1px var(--edge-2);
}
#vp .shots svg { width: 11px; height: 11px; }

/* Opis i stan na karcie produktu */
#vp .pv h3 { margin-top: 8px; font-size: 20px; font-weight: 700; letter-spacing: -.032em; }
#vp .pv-desc { margin-top: 12px; font-size: 13px; color: var(--dim); line-height: 1.65; }
/* Nagłówek nad przyciskami wariantów — mówi, CO klient wybiera. */
#vp .pv-cecha { margin: 18px 0 8px; }

#vp .pv-chips { margin-top: 16px; }
#vp .pv-stock {
  display: inline-flex; align-items: center; gap: 8px;
  margin-top: 12px; padding: 6px 12px;
  border-radius: var(--pill);
  background: var(--raise);
  box-shadow: inset 0 0 0 1px rgba(74, 222, 128, .3);
  font-family: var(--num); font-size: 12px; letter-spacing: .05em;
  text-transform: uppercase; color: var(--ok);
}
#vp .pv-stock i { width: 5px; height: 5px; border-radius: 50%; background: currentColor; font-style: normal; }
#vp .pv-stock.low { color: var(--volt-2); box-shadow: inset 0 0 0 1px rgba(227, 178, 60, .3); }
#vp .pv-stock.out { color: var(--bad); box-shadow: inset 0 0 0 1px rgba(251, 113, 133, .3); }
#vp .pv-stock.out svg { width: 13px; height: 13px; }

/* Cennik hurtowy — tabela progów z aktywnym wierszem. */
#vp .whole {
  margin-top: 20px;
  border-radius: var(--r-sm);
  background: var(--raise);
  box-shadow: inset 0 0 0 1px var(--edge);
  overflow: hidden;
}
#vp .wh-head {
  display: flex; justify-content: space-between;
  padding: 12px 15px 0;
}
#vp table.wh { width: 100%; border-collapse: collapse; margin-top: 8px; }
#vp .wh td { padding: 11px 15px; border-top: 1px solid var(--edge); font-size: 13px; }
#vp .wh .q { font-family: var(--num); font-size: 12px; letter-spacing: .02em; color: var(--dim); }
#vp .wh .p { text-align: right; font-family: var(--num); font-weight: 650; letter-spacing: -.02em; white-space: nowrap; }
#vp .wh .s { width: 56px; text-align: right; font-family: var(--num); font-size: 12px; color: var(--faint); }
#vp .wh tr { transition: background var(--fast); }
#vp .wh tr.on { background: var(--volt-dim); }
#vp .wh tr.on .q, #vp .wh tr.on .p { color: var(--volt); }
#vp .wh tr.on .s { color: var(--volt-2); }

/* Stopka karty produktu: ilość + suma */
#vp .pv-buy {
  display: flex; align-items: center; justify-content: space-between;
  gap: 14px; margin-bottom: 14px;
}
#vp .stepper.big button { width: 42px; height: 42px; }
#vp .stepper.big b { min-width: 36px; font-size: 15px; }
#vp .stepper.big .qin { min-width: 52px; width: 52px; font-size: 15px; }
#vp .pv-sum { display: flex; flex-direction: column; align-items: flex-end; gap: 3px; }
#vp .pv-sum b { font-family: var(--num); font-size: 20px; font-weight: 650; letter-spacing: -.03em; white-space: nowrap; }

/* ══════════════════════════════════════════════════════════════════════════
   STATYSTYKI PROFILU
   ══════════════════════════════════════════════════════════════════════════ */
#vp .sec-label {
  display: flex; align-items: center; gap: 8px;
  margin: 24px 0 10px;
}
#vp .sec-label svg { width: 13px; height: 13px; color: var(--faint); }

#vp .span-row {
  display: flex; align-items: center; gap: 11px;
  margin-bottom: 14px; padding: 12px 15px;
  border-radius: var(--r-sm);
  background: var(--raise);
  box-shadow: inset 0 0 0 1px var(--edge);
}
#vp .span-row svg { width: 15px; height: 15px; flex: none; color: var(--faint); }
#vp .span-row b { color: var(--ink); font-weight: 600; }

/* Najczęściej kupowane — poziome paski udziału. */
#vp .favs { display: flex; flex-direction: column; gap: 14px; padding-top: 14px; padding-bottom: 14px; }
#vp .fav {
  display: grid; grid-template-columns: minmax(0, 1fr) 76px auto;
  gap: 12px; align-items: center;
  animation: vp-in 340ms cubic-bezier(.25, .8, .35, 1) backwards;
}
#vp .fav .nm {
  font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
/* Nazwa `.meter`, a NIE `.bar`: `.bar` to pasek postępu przewijania na górze
   strony, który jest `position: fixed` — element wypadał wtedy z siatki
   wiersza, kolumna zwężała się do zera i paska udziału w ogóle nie było widać. */
#vp .fav .meter {
  height: 4px; border-radius: var(--pill);
  background: var(--raise-2); overflow: hidden;
}
#vp .fav .meter i {
  display: block; width: 100%; height: 100%;
  border-radius: var(--pill);
  background: linear-gradient(90deg, rgba(227, 178, 60, .45), var(--volt));
  transform-origin: 0 50%;
}
#vp .fav .qy { font-family: var(--num); font-size: 12px; color: var(--dim); white-space: nowrap; }

/* Ostatnio kupione */
#vp .recents { display: flex; flex-direction: column; }
#vp .recents .rec:first-child { padding-top: 12px; }
#vp .recents .rec:last-child { padding-bottom: 12px; }
#vp .rec {
  display: flex; justify-content: space-between; align-items: center; gap: 12px;
  padding: 10px 0;
  border-bottom: 1px solid var(--edge);
  font-size: 13px;
}
#vp .rec:last-child { border-bottom: 0; }
#vp .rec .nm { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }

/* ══════════════════════════════════════════════════════════════════════════
   PŁATNOŚĆ LITECOINEM
   ══════════════════════════════════════════════════════════════════════════ */
#vp .pay-crypto {
  margin-top: 22px; padding: 18px;
  border-radius: var(--r-sm);
  background: var(--raise);
  box-shadow: inset 0 0 0 1px var(--edge-2);
  animation: vp-in 400ms cubic-bezier(.25, .8, .35, 1) 120ms backwards;
}
#vp .pc-head {
  display: flex; align-items: center; gap: 9px;
  font-size: 13px; font-weight: 600;
}
#vp .pc-head svg { width: 18px; height: 18px; color: var(--volt); }

#vp .pc-amount {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin: 14px 0 18px;
}
#vp .pc-amount b {
  font-family: var(--num); font-size: 20px; font-weight: 650;
  letter-spacing: -.03em; color: var(--volt); word-break: break-all;
}

#vp .pc-label { display: block; margin-bottom: 7px; }
#vp .pc-addr {
  display: flex; align-items: stretch; gap: 8px;
}
#vp .pc-addr code {
  flex: 1; min-width: 0;
  padding: 11px 13px;
  border-radius: var(--r-xs);
  background: var(--void);
  box-shadow: inset 0 0 0 1px var(--edge);
  font-family: var(--num); font-size: 12px; letter-spacing: -.01em;
  /* Adres portfela musi dać się przeczytać w całości — łamiemy go, zamiast
     ucinać wielokropkiem. Pomyłka w jednym znaku to utracone pieniądze. */
  word-break: break-all; line-height: 1.5;
}
#vp .pc-copy {
  display: inline-flex; align-items: center; gap: 7px;
  padding: 0 14px; flex: none;
  border-radius: var(--r-xs);
  background: var(--raise-2);
  box-shadow: inset 0 0 0 1px var(--edge-2);
  font-size: 13px; font-weight: 600; color: var(--ink);
  transition: background var(--fast), color var(--fast), box-shadow var(--fast);
}
#vp .pc-copy svg { width: 14px; height: 14px; }
#vp .pc-copy:hover { background: var(--volt); color: #17130a; box-shadow: none; }
#vp .pc-copy.ok { background: var(--ok); color: #05240f; box-shadow: none; }

#vp .pc-note {
  margin: 14px 0 16px;
  font-size: 13px; color: var(--dim); line-height: 1.6;
}
#vp .pay-crypto .btn-line { gap: 9px; }
#vp .pay-crypto .btn-line svg { width: 15px; height: 15px; }

/* ══════════════════════════════════════════════════════════════════════════
   SZKIELET WCZYTYWANIA
   ══════════════════════════════════════════════════════════════════════════ */
#vp .skels { display: flex; flex-direction: column; gap: 12px; padding-top: 6px; }
#vp .skel {
  height: 64px; border-radius: var(--r-sm);
  background: linear-gradient(100deg, var(--raise) 40%, var(--raise-2) 50%, var(--raise) 60%);
  background-size: 220% 100%;
  animation: vp-shimmer 1.2s linear infinite;
}
@keyframes vp-shimmer { to { background-position: -120% 0; } }
@media (prefers-reduced-motion: reduce) {
  #vp .skel { animation: none; }
}

/* ══════════════════════════════════════════════════════════════════════════
   POWIADOMIENIE
   ══════════════════════════════════════════════════════════════════════════ */
#vp .toast {
  position: fixed; left: 50%;
  bottom: calc(88px + env(safe-area-inset-bottom));
  z-index: 95;
  display: flex; align-items: center; gap: 11px;
  max-width: min(92vw, 420px);
  padding: 13px 19px;
  border-radius: var(--pill);
  background: rgba(26, 26, 32, .95);
  backdrop-filter: blur(22px); -webkit-backdrop-filter: blur(22px);
  box-shadow: inset 0 0 0 1px var(--edge-2), 0 18px 48px -14px rgba(0, 0, 0, .85);
  font-size: 13px;
  transform: translate(-50%, 20px); opacity: 0; pointer-events: none;
  transition: transform var(--mid), opacity var(--mid);
}
#vp .toast.on { transform: translate(-50%, 0); opacity: 1; }
#vp .toast svg { width: 16px; height: 16px; flex: none; color: var(--ok); }
#vp .toast.bad svg { color: var(--bad); }

/* ══════════════════════════════════════════════════════════════════════════
   STOPKA
   ══════════════════════════════════════════════════════════════════════════ */
#vp .foot {
  padding: 44px 0 calc(112px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--edge);
}
#vp .foot-in { display: flex; flex-direction: column; gap: 20px; }
#vp .foot .sig { display: flex; align-items: center; gap: 11px; }
#vp .foot .links { display: flex; flex-wrap: wrap; gap: 8px 20px; }
#vp .foot .links a { font-size: 13px; color: var(--dim); transition: color var(--fast); }
#vp .foot .links a:hover { color: var(--ink); }
#vp .foot .fine { font-size: 12px; line-height: 1.7; color: var(--faint); max-width: 52ch; }

/* ══════════════════════════════════════════════════════════════════════════
   TABLET
   ══════════════════════════════════════════════════════════════════════════ */
@media (min-width: 620px) {
  #vp { --gut: 32px; }
  #vp .grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; }
  #vp .stage { min-height: 380px; }
  #vp .specs div { padding-right: 20px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   DESKTOP
   ══════════════════════════════════════════════════════════════════════════ */
@media (min-width: 1000px) {
  #vp { --gut: 44px; }
  #vp { --nav-h: 74px; }
  #vp .hero { padding-block: calc(var(--nav-h) + 76px) 0; }

  /* Układ dwukolumnowy: treść po lewej, ekspozycja po prawej. */
  #vp .hero-grid {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, .95fr);
    align-items: center;
    gap: 40px;
    min-height: 74svh;
  }
  #vp .hero h1 { font-size: clamp(3.6rem, 5.4vw, 5.4rem); max-width: 12ch; }
  #vp .stage { min-height: 500px; margin-top: 0; }
  /* UWAGA: nie ograniczamy tu szerokosci `img`. Dawna regula
     `width: min(26vw, 310px)` pochodzila z czasow, gdy w hero „plywalo”
     samo zdjecie produktu. Dzis stoi tam KARTA polecanego, a ta regula
     bila w `.pick-art img` — zdjecie przestawalo wypelniac kadr i zostawal
     ciemny pas z prawej. Kadrowaniem zajmuje sie `object-fit: cover`. */

  #vp .specs { grid-template-columns: repeat(3, minmax(0, 200px)); }

  #vp .grid { grid-template-columns: repeat(4, minmax(0, 1fr)); gap: 18px; }
  #vp .tabs { top: 74px; }
  #vp .catalog { padding-block: 92px 130px; }

  #vp .dock { display: none; }

  #vp .sheet {
    inset: 0 0 0 auto;
    width: min(470px, 100%);
    max-height: none;
    border-radius: 0;
    box-shadow: inset 1px 0 0 0 var(--edge-2), -30px 0 90px -26px rgba(0, 0, 0, .9);
    transform: translateX(101%);
  }
  #vp .grip { display: none; }

  /* ── KOSZYK NA DUŻYM EKRANIE ─────────────────────────────────────────────
     Układ, który mają wszystkie duże sklepy: po lewej lista pozycji, po
     prawej przyklejone podsumowanie z przyciskiem. Klient widzi jednocześnie,
     CO kupuje i ILE zapłaci — nie musi przewijać w dół po kwotę i w górę po
     zawartość.

     Robimy to samym CSS-em: nagłówek, treść i stopka już istnieją, więc
     wystarczy ułożyć je w siatkę zamiast w kolumnę. Na telefonie zostaje
     kolumna — tam dwie kolumny obok siebie nie mają prawa bytu. */
  #vp .sheet.pelny {
    inset: 0;
    width: 100%;
    display: grid;
    grid-template-columns: minmax(0, 1fr) 360px;
    grid-template-rows: auto minmax(0, 1fr);
    column-gap: 32px;
    align-content: start;
    padding-inline: max(24px, calc((100% - 1100px) / 2));
    background: var(--void);
  }
  #vp .sheet.pelny .sheet-h {
    grid-column: 1 / -1;
    padding-inline: 0;
    background: transparent;
  }
  #vp .sheet.pelny .sheet-b {
    padding: 24px 0 40px;
    min-height: 0;
  }
  /* Podsumowanie jako karta, nie pasek na dole ekranu. */
  #vp .sheet.pelny .sheet-f {
    position: sticky; top: 92px;
    align-self: start;
    margin-top: 24px;
    padding: 20px;
    border: 0; border-radius: var(--r);
    background: var(--panel);
    box-shadow: inset 0 0 0 1px var(--edge);
  }
  /* Wąskie okno (1000-1240 px) nie mieści dwóch kolumn z sensownymi
     marginesami — wracamy do jednej. */
  @media (max-width: 1240px) {
    #vp .sheet.pelny {
      grid-template-columns: minmax(0, 1fr);
      padding-inline: 24px;
    }
    /* Jedna kolumna na całą szerokość monitora rozjeżdża wiersz: nazwa przy
       lewej krawędzi, cena przy prawej, między nimi pół metra pustki.
       Trzymamy treść w kolumnie o czytelnej szerokości. */
    #vp .sheet.pelny .sheet-h,
    #vp .sheet.pelny .sheet-b,
    #vp .sheet.pelny .sheet-f {
      width: 100%; max-width: 760px; margin-inline: auto;
    }
    #vp .sheet.pelny .sheet-f { position: static; margin-top: 0; padding-inline: 0; }
  }

  #vp .toast { left: auto; right: 32px; bottom: 32px; transform: translate(0, 20px); }
  #vp .toast.on { transform: translate(0, 0); }

  #vp .foot { padding-bottom: 60px; }
  #vp .foot-in { flex-direction: row; align-items: flex-start; justify-content: space-between; gap: 40px; }
}

@media (min-width: 1360px) {
  #vp .grid { gap: 22px; }
}

/* Szanujemy systemowe ograniczenie ruchu. */
@media (prefers-reduced-motion: reduce) {
  #vp *, #vp *::before, #vp *::after {
    animation-duration: .01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .01ms !important;
  }
  #vp .card, #vp .hero-bg { opacity: 1; transform: none; }
  #vp .hero h1 .under::after { transform: scaleX(1); }
}

/* ══════════════════════════════════════════════════════════════════════════
   DOWÓD SPOŁECZNY W HERO
   ══════════════════════════════════════════════════════════════════════════
   Pod przyciskami było puste miejsce. Konkretne liczby plus twarze z rankingu
   mówią nowemu klientowi, że nie jest pierwszy — a to działa lepiej niż każde
   hasło marketingowe. Wstawiany dopiero po odpowiedzi serwera, więc nie skacze
   przy wczytywaniu: dopóki nie ma danych, `.soc` ma zerową wysokość. */
#vp .soc {
  display: flex; align-items: center; gap: 13px; flex-wrap: wrap;
  max-height: 0; opacity: 0; overflow: hidden;
  transition: max-height var(--mid), opacity var(--mid), margin var(--mid);
}
#vp .soc.on { max-height: 80px; opacity: 1; margin-top: 26px; }

#vp .soc-faces { display: inline-flex; }
#vp .soc-av {
  width: 30px; height: 30px; border-radius: 50%;
  object-fit: cover; background: var(--raise-2);
  box-shadow: 0 0 0 2px var(--void);
}
/* Nakładka: awatary zachodzą na siebie jak grupa ludzi, nie jak lista. */
#vp .soc-faces .soc-av + .soc-av { margin-left: -10px; }
#vp .soc-av.av-mono { font-size: 12px; border-radius: 50%; }

#vp .soc-txt {
  display: inline-flex; align-items: center; gap: 8px; flex-wrap: wrap;
  font-size: 13px; color: var(--dim);
}
#vp .soc-txt svg { width: 14px; height: 14px; flex: none; color: var(--ok); }
#vp .soc-txt b { color: var(--ink); font-weight: 600; }

/* ══════════════════════════════════════════════════════════════════════════
   SZCZEGÓŁY ZAMÓWIENIA KLIENTA
   ══════════════════════════════════════════════════════════════════════════ */
#vp .ord { position: relative; cursor: pointer; transition: box-shadow var(--fast); }
#vp .ord-more {
  position: absolute; top: 50%; right: 2px; transform: translateY(-50%);
  color: var(--faint); transition: transform var(--fast), color var(--fast);
}
#vp .ord-more svg { width: 15px; height: 15px; }
@media (hover: hover) and (pointer: fine) {
  #vp .ord:hover .ord-more { color: var(--ink); transform: translateY(-50%) translateX(2px); }
}

#vp .od-top { display: flex; align-items: center; justify-content: space-between; gap: 12px; }

#vp .ois { display: flex; flex-direction: column; }
#vp .oi {
  display: grid; grid-template-columns: minmax(0, 1fr) auto auto;
  gap: 12px; align-items: baseline;
  padding: 11px 0; border-bottom: 1px solid var(--edge);
}
#vp .oi:last-child { border-bottom: 0; }
#vp .oi-n { font-size: 13px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
#vp .oi-q { white-space: nowrap; }
#vp .oi-t { font-family: var(--num); font-size: 13px; letter-spacing: -.02em; white-space: nowrap; }

#vp .facts { display: grid; gap: 10px; grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }
#vp .fact {
  display: grid; grid-template-columns: auto 1fr; gap: 4px 10px; align-items: center;
  padding: 12px 14px; border-radius: var(--r-sm);
  background: var(--raise); box-shadow: inset 0 0 0 1px var(--edge);
}
#vp .fact svg { width: 15px; height: 15px; grid-row: span 2; color: var(--faint); }
#vp .fact b { font-size: 13px; font-weight: 600; word-break: break-all; }

/* Przebieg zamówienia — pionowa os z kropkami. */
#vp .steps { display: flex; flex-direction: column; }
#vp .step { display: grid; grid-template-columns: auto 1fr; gap: 12px; padding-bottom: 16px; position: relative; }
#vp .step:last-child { padding-bottom: 0; }
#vp .step .dot {
  width: 9px; height: 9px; margin-top: 5px; border-radius: 50%;
  background: var(--raise-2); box-shadow: inset 0 0 0 1px var(--edge-2);
}
#vp .step:first-child .dot { background: var(--volt); box-shadow: none; }
/* Kreska laczaca kropki — rysowana na kropce, wiec nie potrzebuje elementu. */
#vp .step:not(:last-child) .dot::after {
  content: ""; position: absolute; left: 4px; top: 14px; bottom: -5px;
  border-left: 1px solid var(--edge);
}
#vp .step b { display: block; font-size: 13px; font-weight: 500; line-height: 1.45; }
#vp .step .tag { display: block; margin-top: 3px; }

/* ══════════════════════════════════════════════════════════════════════════
   WŁASNE MIEJSCE W RANKINGU
   ══════════════════════════════════════════════════════════════════════════ */
#vp .lead-me {
  display: grid; grid-template-columns: 34px minmax(0, 1fr) auto;
  gap: 13px; align-items: center;
  margin-top: 18px; padding: 15px 14px;
  border-radius: var(--r-sm);
  background: var(--volt-dim);
  box-shadow: inset 0 0 0 1px rgba(227, 178, 60, .25);
}
#vp .lead-me .pl { font-family: var(--num); font-size: 15px; color: var(--volt); text-align: center; }
#vp .lead-me .who { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
#vp .lead-me .who b { font-size: 15px; font-weight: 600; }
#vp .lead-me .gap { font-size: 12px; color: var(--dim); text-align: right; }
#vp .lead-me .gap b { font-family: var(--num); color: var(--volt); white-space: nowrap; }

/* ══════════════════════════════════════════════════════════════════════════
   ZAMÓWIENIE HURTOWE
   ══════════════════════════════════════════════════════════════════════════ */
#vp .bulk { display: flex; flex-direction: column; gap: 10px; }
#vp .blk {
  padding: 14px; border-radius: var(--r-sm);
  background: var(--raise); box-shadow: inset 0 0 0 1px var(--edge);
  animation: vp-in 340ms cubic-bezier(.25, .8, .35, 1) backwards;
}
#vp .blk-h { display: grid; grid-template-columns: 46px minmax(0, 1fr); gap: 12px; align-items: center; }
#vp .blk-h img, #vp .blk-x {
  width: 46px; height: 46px; border-radius: var(--r-xs);
  object-fit: cover; background: var(--raise-2);
  box-shadow: inset 0 0 0 1px var(--edge);
}
#vp .blk-id { min-width: 0; }
#vp .blk-id b { display: block; font-size: 13px; font-weight: 600; letter-spacing: -.015em; }
#vp .blk-id .tag { display: block; margin-top: 4px; }
#vp .blk-r {
  display: flex; align-items: center; justify-content: space-between;
  gap: 12px; margin-top: 12px;
}
#vp .blk-sum { display: flex; flex-direction: column; align-items: flex-end; gap: 2px; }
#vp .blk-sum b { font-family: var(--num); font-size: 15px; font-weight: 650; letter-spacing: -.03em; white-space: nowrap; }

/* Rozbicie na smaki wewnątrz kafelka produktu. Nagłówek mówi CO kupujesz,
   te wiersze — ile którego smaku. Suma z nich napędza próg hurtowy. */
#vp .blk-vars {
  display: flex; flex-direction: column;
  margin-top: 12px; padding-top: 10px;
  border-top: 1px dashed var(--edge);
}
#vp .bvar {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 5px 0; min-width: 0;
}
#vp .bvar + .bvar { border-top: 1px solid var(--edge); }
#vp .bvar-n {
  min-width: 0; font-size: 13px; color: var(--ink);
  display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap;
}
#vp .bvar-n .tag { flex: none; }
#vp .stepper.sm button { width: 28px; height: 28px; }
#vp .stepper.sm .qin { width: 40px; min-width: 40px; font-size: 13px; padding: 4px 2px; }
#vp .blk-cnt { font-size: 13px; color: var(--dim); }
#vp .blk-cnt b { margin: 0 2px; font-family: var(--num); font-size: 15px; font-weight: 650; color: var(--ink); }
#vp .blk-cnt .tag { display: block; margin-top: 2px; }
#vp .blk-next { display: block; margin-top: 8px; color: var(--volt); }
#vp .blk-next:empty { display: none; }

#vp .bulk-tot {
  display: flex; align-items: baseline; gap: 10px; flex-wrap: wrap;
  margin-bottom: 14px; padding-top: 14px;
  border-top: 1px dashed var(--edge-2);
}
#vp .bulk-tot b { font-family: var(--num); font-size: 24px; font-weight: 650; letter-spacing: -.04em; }
#vp .bulk-tot .ok { color: var(--ok); }

/* ══════════════════════════════════════════════════════════════════════════
   TELEFON — kompaktowe hero (max-width: 640px)
   Na mssg.me klienci są głównie na telefonach. Domyślne hero rosło do ~1177px
   (nagłówek + karta polecanego + statystyki), przez co katalog startował dopiero
   ok. 1550px w dół — użytkownik scrollował i „nie widział produktów”. Tu hero
   jest przycięte, a kartę polecanego chowamy: te same produkty są tuż niżej
   w katalogu, więc na telefonie to tylko zbędna wysokość.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
  #vp .hero { padding-block: calc(var(--nav-h) + 20px) 0; }
  #vp .hero-grid { gap: 16px; }
  #vp .kicker { margin-bottom: 14px; }
  #vp .hero-cta { margin-top: 20px; }
  #vp .pick, #vp .stage { display: none; }
  #vp .catalog { padding-block: 34px 88px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   OPINIE KLIENTÓW
   Prawdziwe oceny zebrane przez bota po dostawie. Poziomy rail zamiast siatki:
   opinie czyta się „przelotem”, a rail nie rozpycha strony w pionie i na
   telefonie działa naturalnym swipe’em.
   ══════════════════════════════════════════════════════════════════════════ */
#vp .reviews { padding-block: 8px 96px; }

/* `nowrap` trzymał ocenę w jednej linii, ale na wąskim telefonie (320 px)
   wychodziła poza kartę. Pozwalamy jej się zawinąć — czytelność wygrywa
   z symetrią, a na szerszych ekranach i tak zostaje w jednym rzędzie. */
#vp .rev-score {
  display: flex; align-items: center; gap: 10px;
  flex-wrap: wrap; min-width: 0; max-width: 100%;
}
#vp .rev-score b {
  font-family: var(--display); font-size: 34px; font-weight: 700;
  letter-spacing: -.04em; line-height: 1;
}

#vp .stars { display: inline-flex; gap: 2px; }
#vp .stars .st { color: var(--edge-2); display: inline-flex; }
/* Zdobyta gwiazdka jest WYPEŁNIONA, nie tylko obrysowana — pusty kontur
   czytało się jak ocenę niepełną. `ico()` rysuje sam obrys, więc wypełnienie
   dokładamy tutaj. */
#vp .stars .st svg { fill: none; }
#vp .stars .st.on { color: var(--volt); }
#vp .stars .st.on svg { fill: currentColor; }
#vp .stars svg { width: 14px; height: 14px; }

#vp .rev-rail {
  display: grid; grid-auto-flow: column; grid-auto-columns: minmax(268px, 1fr);
  gap: 14px; margin-top: 22px;
  overflow-x: auto; overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  padding-bottom: 6px;
  scrollbar-width: none;
}
#vp .rev-rail::-webkit-scrollbar { display: none; }

#vp .rev {
  scroll-snap-align: start;
  display: flex; flex-direction: column; gap: 12px;
  padding: 18px;
  border-radius: var(--r-sm);
  background: var(--panel);
  box-shadow: inset 0 0 0 1px var(--edge);
  /* Wejście: stagger 45 ms, tylko transform+opacity (GPU). */
  animation: vp-in 340ms cubic-bezier(.23, 1, .32, 1) backwards;
  transition: box-shadow var(--fast);
}
@media (hover: hover) and (pointer: fine) {
  #vp .rev:hover { box-shadow: inset 0 0 0 1px var(--edge-2); }
}
#vp .rev p {
  font-size: 15px; line-height: 1.55; color: var(--ink);
  /* Komentarze bywają długie — trzymamy równą wysokość kart. */
  display: -webkit-box; -webkit-line-clamp: 5; -webkit-box-orient: vertical;
  overflow: hidden;
}
#vp .rev footer { display: flex; align-items: center; gap: 9px; margin-top: auto; }
#vp .rev-av {
  display: grid; place-items: center; flex: none;
  width: 28px; height: 28px; border-radius: 50%;
  background: linear-gradient(150deg, var(--raise-2), var(--panel));
  box-shadow: inset 0 0 0 1px var(--edge);
  font-family: var(--display); font-size: 12px; font-weight: 700; color: var(--dim);
}
#vp .rev-nm { font-size: 13px; font-weight: 600; letter-spacing: -.01em; }
#vp .rev-ok {
  display: inline-flex; align-items: center; gap: 4px; margin-left: auto;
  font-size: 12px; color: var(--ok); letter-spacing: .04em;
}
#vp .rev-ok svg { width: 11px; height: 11px; }

@media (max-width: 640px) {
  #vp .reviews { padding-block: 4px 72px; }
  #vp .rev-rail { grid-auto-columns: 82%; }
}

/* ══════════════════════════════════════════════════════════════════════════
   PASEK KORZYŚCI (nad katalogiem)
   Odpowiedź na „czemu mam kupić właśnie tutaj”, zanim klient zobaczy ceny.
   Konkrety zamiast ogólników — ogólniki czyta się jak wypełniacz.
   ══════════════════════════════════════════════════════════════════════════ */
#vp .perks {
  display: grid; gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(216px, 1fr));
  padding-block: 30px 6px;
}
#vp .perk {
  display: flex; flex-direction: column; gap: 7px;
  padding: 17px 18px;
  border-radius: var(--r-sm);
  background: var(--panel);
  box-shadow: inset 0 0 0 1px var(--edge);
  animation: vp-in 340ms cubic-bezier(.23, 1, .32, 1) backwards;
}
#vp .perk-i {
  display: grid; place-items: center;
  width: 32px; height: 32px; margin-bottom: 2px;
  border-radius: var(--r-xs);
  background: rgba(227, 178, 60, .1);
  box-shadow: inset 0 0 0 1px rgba(227, 178, 60, .22);
  color: var(--volt);
}
#vp .perk-i svg { width: 16px; height: 16px; }
#vp .perk b { font-size: 15px; font-weight: 600; letter-spacing: -.015em; }
#vp .perk span:not(.perk-i) { font-size: 13px; line-height: 1.5; color: var(--dim); }

@media (max-width: 640px) {
  #vp .perks { grid-template-columns: 1fr 1fr; gap: 9px; padding-block: 22px 2px; }
  #vp .perk { padding: 13px 14px; }
  #vp .perk span:not(.perk-i) { font-size: 12px; }
}

/* ── „Co dalej" po złożeniu zamówienia ──────────────────────────────────────
   Klient dostawał numer i kwotę, ale nie wiedział, czy ma czekać, czy gdzieś
   pisać. Trzy kroki mówią wprost, co się dzieje — w tym że bot zakłada mu
   prywatny kanał na Discordzie. */
#vp .next { display: flex; flex-direction: column; gap: 2px; margin-top: 20px; }
#vp .next li {
  display: flex; align-items: flex-start; gap: 12px;
  padding: 13px 14px;
  border-radius: var(--r-sm);
  background: var(--raise);
  box-shadow: inset 0 0 0 1px var(--edge);
  animation: vp-in 320ms cubic-bezier(.23, 1, .32, 1) backwards;
}
#vp .next-i {
  display: grid; place-items: center; flex: none;
  width: 28px; height: 28px; border-radius: 50%;
  background: rgba(227, 178, 60, .1);
  box-shadow: inset 0 0 0 1px rgba(227, 178, 60, .22);
  color: var(--volt);
}
#vp .next-i svg { width: 14px; height: 14px; }
#vp .next-t { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
#vp .next-t b { font-size: 13px; font-weight: 600; letter-spacing: -.015em; }
#vp .next-t span { font-size: 12px; line-height: 1.45; color: var(--dim); }

/* ── Kody PaySafeCard ───────────────────────────────────────────────────────
   Sekcja pojawia się tylko po wybraniu PSC. Jeden kod rzadko pokrywa całe
   zamówienie, więc pól może być kilka. */
#vp .psc { display: none; margin-bottom: 16px; }
#vp .psc.on { display: block; }
#vp .psc > .tag { display: block; margin-bottom: 9px; }
#vp .psc .hint { margin-top: 8px; font-size: 12px; line-height: 1.45; color: var(--faint); }

#vp .psc-row { display: flex; gap: 8px; margin-bottom: 8px; }
#vp .psc-in {
  flex: 1; min-width: 0;
  height: 46px; padding: 0 14px;
  border: 0; border-radius: var(--r-sm);
  background: var(--raise);
  box-shadow: inset 0 0 0 1px var(--edge);
  color: var(--ink);
  font-family: var(--num); font-size: 15px; letter-spacing: .06em;
  transition: box-shadow var(--fast), background var(--fast);
}
#vp .psc-in::placeholder { color: var(--faint); letter-spacing: 0; }
#vp .psc-in:focus {
  outline: none; background: var(--raise-2);
  box-shadow: inset 0 0 0 1px var(--edge-2), 0 0 0 3px rgba(227, 178, 60, .12);
}
#vp .psc-del {
  flex: none; width: 46px; height: 46px;
  display: grid; place-items: center;
  border-radius: var(--r-sm);
  background: var(--raise);
  box-shadow: inset 0 0 0 1px var(--edge);
  color: var(--dim);
  transition: color var(--fast), background var(--fast), transform var(--fast);
}
#vp .psc-del:active { transform: scale(.94); }
@media (hover: hover) and (pointer: fine) {
  #vp .psc-del:hover { color: var(--bad); background: var(--raise-2); }
}
#vp .psc-del svg { width: 15px; height: 15px; }

#vp .btn-sm { height: 40px; padding-inline: 14px; gap: 7px; font-size: 13px; }
#vp .btn-sm svg { width: 13px; height: 13px; }

/* ── Kafelki: równe wysokości i limit wariantów ─────────────────────────────
   Produkt z 18 smakami rozpychał kartę na pół ekranu, a sąsiad z dwoma miał
   wielką dziurę — siatka wyglądała na zepsutą. Kafelki wyrównujemy do
   najwyższego w wierszu, a nadmiar wariantów chowamy za „+N wariantów”,
   które otwiera widok produktu (tam jest miejsce na pełną listę). */
#vp .grid { align-items: stretch; }
#vp .card { height: 100%; }

/* Opis nie może rozpychać kafelka — dwie linijki i tyle. */
#vp .card-body .note { min-height: 0; }

/* Chip „+N wariantów” — zaproszenie do karty produktu, nie kolejny wariant,
   więc wygląda inaczej: sama krawędź, bez wypełnienia. */
#vp .chip-more {
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--edge-2);
  color: var(--dim);
  font-variant-numeric: tabular-nums;
}
@media (hover: hover) and (pointer: fine) {
  #vp .chip-more:hover { color: var(--ink); box-shadow: inset 0 0 0 1px var(--volt); }
}

@media (max-width: 640px) {
  /* DWIE kolumny + bestseller na pelna szerokosc. Sam bestseller dostaje
     witryne z duzym zdjeciem, a reszta katalogu zostaje do przejrzenia jednym
     rzutem oka, bez przewijania przez kilkanascie ekranow. */
  #vp .grid { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 10px; }
  #vp .card-body { padding: 13px 13px 14px; gap: 8px; }
  #vp .card-body h3 { font-size: 15px; }
}

/* ── Kod rabatowy w zamówieniu ──────────────────────────────────────────── */
#vp .promo { margin-bottom: 16px; }
#vp .promo > .tag { display: block; margin-bottom: 9px; }
#vp .promo-row { display: flex; gap: 8px; }
#vp .promo-row input {
  flex: 1; min-width: 0; height: 46px; padding: 0 14px;
  border: 0; border-radius: var(--r-sm);
  background: var(--raise); box-shadow: inset 0 0 0 1px var(--edge);
  color: var(--ink); font-family: var(--num); font-size: 15px; letter-spacing: .08em;
  text-transform: uppercase;
  transition: box-shadow var(--fast), background var(--fast);
}
#vp .promo-row input::placeholder { letter-spacing: 0; text-transform: none; color: var(--faint); }
#vp .promo-row input:focus {
  outline: none; background: var(--raise-2);
  box-shadow: inset 0 0 0 1px var(--edge-2), 0 0 0 3px rgba(227, 178, 60, .12);
}
#vp .promo-row .btn { flex: none; height: 46px; padding-inline: 18px; }
#vp .promo-msg { margin-top: 7px; font-size: 12px; line-height: 1.45; min-height: 0; }
#vp .promo-msg.ok { color: var(--ok); }
#vp .promo-msg.bad { color: var(--bad); }

/* Rabat w rachunku — na zielono, żeby oszczędność było widać od razu. */
#vp .rrow.save span:last-child { color: var(--ok); }

/* ══════════════════════════════════════════════════════════════════════════
   RANKING — podium zamiast tabelki
   Lista wierszy rozdzielonych kreskami czytała się jak arkusz, a nie jak
   ranking: nie było widać, że pierwsze miejsce jest czymś więcej niż wierszem
   numer jeden. Podium dostaje kartę, złotą obwódkę i większy awatar; reszta
   zostaje kompaktowa, żeby kontrast robił robotę.
   ══════════════════════════════════════════════════════════════════════════ */
#vp .lead {
  border-bottom: 0;
  margin-bottom: 6px;
  padding: 12px 14px;
  border-radius: var(--r-sm);
  background: var(--panel);
  box-shadow: inset 0 0 0 1px var(--edge);
  transition: box-shadow var(--fast), transform var(--fast);
}
@media (hover: hover) and (pointer: fine) {
  #vp .lead:hover { box-shadow: inset 0 0 0 1px var(--edge-2); }
}

/* Numer miejsca jako „medal" — kółko, nie sama cyfra. */
#vp .lead .pl {
  display: grid; place-items: center;
  width: 30px; height: 30px; border-radius: 50%;
  background: var(--raise-2);
  box-shadow: inset 0 0 0 1px var(--edge);
  font-size: 13px;
}

/* Pierwsze miejsce — realnie wyróżnione, nie tylko innym kolorem cyfry. */
#vp .lead.podium.p1 {
  padding: 16px 14px;
  background:
    linear-gradient(100deg, rgba(227, 178, 60, .10), transparent 58%),
    var(--panel);
  box-shadow: inset 0 0 0 1px rgba(227, 178, 60, .32);
}
#vp .lead.podium.p1 .pl {
  background: var(--volt); color: #17130a; font-weight: 700;
  box-shadow: 0 0 0 4px rgba(227, 178, 60, .12);
}
#vp .lead.podium.p1 .lav { width: 50px; height: 50px; }
#vp .lead.podium.p1 .who b { font-size: 17px; }
#vp .lead.podium.p1 .amt { font-size: 17px; }

#vp .lead.podium.p2 .pl { background: rgba(215, 215, 222, .16); color: #e6e6ec; }
#vp .lead.podium.p3 .pl { background: rgba(216, 164, 127, .16); color: #e3bda0; }

/* Własny wiersz zostaje wyraźny, ale nie krzyczy głośniej niż pierwsze miejsce. */
#vp .lead.mine { margin-inline: 0; padding-inline: 14px; }

/* Podpis pod nazwą („02 zamówienia · Stały klient") ma zostać w jednej linii —
   złamany na dwie rozpycha wiersz i psuje rytm listy. */
#vp .lead .who .tag {
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
  font-size: 12px; letter-spacing: .05em;
}

/* ══════════════════════════════════════════════════════════════════════════
   TELEFON — sklep ma pokazywać PRODUKTY, nie nagłówki
   Pomiar na 375×812 pokazał, że katalog zaczynał się dopiero na 1136 px:
   hero 687 + secnav 78 + korzyści 350. Klient przewijał półtora ekranu samych
   wstępów, zanim zobaczył pierwszy produkt. Poniżej tniemy każdy z tych bloków
   do rozmiaru, który niesie treść, a nie powietrze.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
  /* ── Hero: nagłówek zamiast plakatu ──────────────────────────────────── */
  #vp .hero { padding-block: calc(var(--nav-h) + 18px) 0; }
  #vp .hero h1 {
    /* 46,9 px na szerokości 375 px to trzy słowa na linię i 86 px wysokości. */
    font-size: clamp(2rem, 8.6vw, 2.5rem);
    line-height: 1.04;
  }
  #vp .lede { font-size: 15px; line-height: 1.5; max-width: 34ch; }
  #vp .hero-cta { margin-top: 18px; gap: 8px; }
  /* Dwa przyciski obok siebie zamiast jeden pod drugim (119 px → ~50 px). */
  #vp .hero-cta .btn { flex: 1; min-width: 0; justify-content: center; padding-inline: 14px; }
  /* Pasek „10 pozycji · 200 zł · 24 h” powtarza to, co mówią karty korzyści. */
  #vp .specs { display: none; }

  /* ── Korzyści: rząd przewijany, nie ściana kafelków ──────────────────── */
  #vp .perks {
    display: grid; grid-auto-flow: column; grid-auto-columns: 62%;
    gap: 8px; padding-block: 16px 2px;
    overflow-x: auto; scroll-snap-type: x mandatory;
    scrollbar-width: none;
  }
  #vp .perks::-webkit-scrollbar { display: none; }
  #vp .perk { scroll-snap-align: start; padding: 12px 13px; gap: 5px; }
  #vp .perk-i { width: 26px; height: 26px; }
  #vp .perk-i svg { width: 13px; height: 13px; }
  #vp .perk b { font-size: 13px; }
  /* Opis zostaje w DOM (czyta go screen reader), ale nie rozpycha kafelka. */
  #vp .perk span:not(.perk-i) {
    font-size: 12px; line-height: 1.4;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
  }

  /* ── Nawigacja sekcji: niżej i zwarciej ──────────────────────────────── */
  #vp .secnav { padding-block: 10px; }

  /* ── Cel dotyku: minimum 44 px (mierzone zakładki miały 40) ──────────── */
  #vp .tabs .tab { min-height: 44px; }
  /* Wybór smaku to główna interakcja na karcie — chip musi być wygodny
     w kciuku. 34 px trafiało się z trudem; 42 px mieści się w normie dotyku. */
  #vp .chip {
    min-height: 42px; display: inline-flex; align-items: center;
    padding-inline: 13px; font-size: 13px;
  }
}

@media (max-width: 640px) {
  /* ── Nagłówek katalogu: mniej ceremonii, szybciej do towaru ──────────── */
  #vp .catalog { padding-block: 20px 80px; }
  /* Etykieta „KATALOG" nad tytułem „Wszystkie produkty" mówi to samo dwa razy. */
  #vp .catalog .sec-head .tag:first-child { display: none; }
  #vp .sec-head { margin-bottom: 14px; align-items: center; }
  #vp .sec-head h2 { margin-top: 0; font-size: 1.45rem; }
  #vp .tabs { padding-block: 8px; }
}

@media (max-width: 640px) {
  /* Ostatnie cięcia, żeby pierwszy produkt wchodził na ekran po JEDNYM
     przesunięciu palcem (mierzone: 1385 px → ~760 px od góry strony). */
  #vp .hero { padding-block: calc(var(--nav-h) + 10px) 0; }
  /* Podtytuł: dwie linijki wystarczą, trzecia to już powietrze. */
  #vp .lede {
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden;
  }
  #vp .secnav { padding-block: 6px; }
  #vp .secnav button { padding-block: 9px; }
}

/* ── Skróty sekcji: dwa rzędy po dwa zamiast czterech w linii ──────────────
   Cztery przyciski obok siebie potrzebują 400 px, a telefon daje 375 — ostatni
   („Discord") wystawał poza ekran i nie dało się go dotknąć. Zawijamy do siatki
   2×2: każdy przycisk ma wtedy ~50% szerokości i pełną wysokość dotyku. */
@media (max-width: 640px) {
  #vp .secnav { flex-wrap: wrap; gap: 8px; }
  #vp .sec {
    flex: 1 1 calc(50% - 4px);
    min-width: 0;
    padding-inline: 8px;
  }
}

/* ── Notatka do zamówienia ────────────────────────────────────────────────
   Pole wieloliniowe korzysta z tej samej mechaniki „pływającej” etykiety co
   pozostałe pola formularza — inaczej odstawałoby od reszty kasy. */
#vp .field textarea {
  width: 100%; min-height: 84px;
  padding: 26px 16px 10px;
  border-radius: var(--r-sm);
  box-shadow: inset 0 0 0 1px var(--edge);
  background: var(--raise);
  color: var(--ink);
  font: inherit; font-size: 15px; letter-spacing: -.01em;
  resize: vertical;
  transition: box-shadow var(--fast), background var(--fast);
}
#vp .field textarea::placeholder { color: transparent; }
#vp .field textarea:hover { box-shadow: inset 0 0 0 1px var(--edge-2); }
#vp .field textarea:focus {
  box-shadow: inset 0 0 0 1.5px rgba(227, 178, 60, .65);
  background: var(--raise-2); outline: none;
}
#vp .field textarea:focus + label,
#vp .field textarea:not(:placeholder-shown) + label {
  transform: translateY(-12px) scale(.72); color: var(--dim);
}

/* ── Zestaw: wybór zawartości ─────────────────────────────────────────────
   Klient sam wybiera smak/kolor każdego składnika. Układ celowo taki sam jak
   chipy wariantów przy zwykłym produkcie — to ta sama czynność, więc nie ma
   powodu, żeby wyglądała inaczej. */
#vp .bundle-pick {
  margin-top: 20px; padding-top: 18px;
  border-top: 1px solid var(--edge);
  display: flex; flex-direction: column; gap: 14px;
}
#vp .bp-row { display: flex; flex-direction: column; gap: 8px; }
#vp .bp-name {
  font-size: 13px; font-weight: 600; letter-spacing: -.01em; color: var(--ink);
}
#vp .bp-name .tag { margin-left: 4px; }
/* Wariant bez stanu zostaje widoczny — klient ma wiedzieć, że smak istnieje. */
#vp .chip.out { opacity: .5; cursor: pointer; text-decoration: line-through; }

/* Wybór widoczny na wierszu koszyka — bez niego klient nie wie, co zamawia. */
#vp .line-opts {
  margin-top: 3px; font-size: 12px; color: var(--dim);
  line-height: 1.35;
}

/* ══════════════════════════════════════════════════════════════════════════
   KOSZYK NA TELEFONIE
   Wiersz zajmował 155 px, więc na ekranie mieściły się cztery pozycje i nic
   poza nimi — ani kwoty, ani przycisku dalej. Zbijamy go do ~104 px: mniejsza
   miniatura, nazwa i kwota w jednej linii, sterowanie ilością tuż pod nią.
   Nazwa wraca na zwykłą wagę — waga display w tym rozmiarze była
   ciasny i źle się czytał.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 640px) {
  #vp .line {
    grid-template-columns: 56px 1fr;
    gap: 12px; padding: 11px; margin-bottom: 8px;
  }
  #vp .line .pic { width: 56px; height: 56px; }
  #vp .line .col { gap: 7px; }

  /* Nazwa: krój tekstowy, dwie linie maksymalnie, potem wielokropek. */
  #vp .line .nm {
    font-family: var(--sans);
    font-size: 15px; font-weight: 600; line-height: 1.3;
    display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
    overflow: hidden;
  }
  #vp .line .lp { font-size: 15px; }
  #vp .line .vr { margin-top: 0; font-size: 12px; line-height: 1.3; }
  /* Oszczędność hurtowa schodzi do własnej linii — obok ceny się nie mieściła. */
  #vp .bulk-win { margin-left: 0; margin-top: 4px; }

  /* Sterowanie ilością: niższe, ale nadal wygodne w kciuku (44 px). */
  #vp .line .row2 { gap: 8px; }
  #vp .stepper { height: 38px; }
  #vp .stepper button { width: 38px; }
  #vp .line .qin { width: 40px; font-size: 15px; }
  #vp .drop-line { width: 38px; height: 38px; }

  /* Podsumowanie pod listą — czytelne kwoty zamiast drobnego druku. */
  #vp .sheet-f .rrow { font-size: 13px; }
  #vp .sheet-f .rrow.sum { font-size: 17px; font-weight: 650; }
}

/* ══════════════════════════════════════════════════════════════════════════
   WYDAJNOSC
   ══════════════════════════════════════════════════════════════════════════
   Strona byla plynna na mocnym laptopie i ciezka na telefonie. Trzy zrodla
   kosztu, kazde rozwiazane osobno:

   1. KARTY POZA EKRANEM. Katalog potrafi miec kilkadziesiat kart, a kazda ma
      gradient, cienie i zdjecie. `content-visibility: auto` pozwala
      przegladarce pominac uklad i rysowanie tych, ktorych nie widac.
      `contain-intrinsic-size` podaje ich przewidywana wysokosc, zeby pasek
      przewijania nie skakal.

   2. ROZMYCIE TLA POD PALCEM. `backdrop-filter` na paskach przyklejonych do
      ekranu (gorny pasek, dolny przycisk koszyka, panel boczny) kaze
      przegladarce przerysowywac rozmycie przy KAZDEJ klatce przewijania.
      Na telefonie zamieniamy je na zwykle, gestsze tlo — roznicy prawie nie
      widac, a przewijanie przestaje sie szarpac.

   3. ANIMACJE BEZ KONCA. Osiem ozdobnych animacji chodzilo non stop, takze
      gdy nic sie nie dzialo. Na waskich ekranach zostawiamy stan koncowy.
   ══════════════════════════════════════════════════════════════════════════ */
#vp .card {
  content-visibility: auto;
  contain-intrinsic-size: auto 520px;
}

@media (max-width: 860px) {
  #vp .nav, #vp .dock, #vp .sheet, #vp .scrim {
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }
  #vp .charge, #vp .led, #vp .ticker-track,
  #vp .blank .orb::before, #vp .halo, #vp .ring {
    animation: none;
  }
  /* Poswiaty pod produktem sa najdrozszym pojedynczym efektem na stronie —
     rozmycie liczone na duzej powierzchni przy kazdej klatce. Na telefonie
     zostaje sam gradient, bez filtra. */
  #vp .stage .halo { filter: none; }
}

/* Ekrany dotykowe bez precyzyjnego wskaznika nie korzystaja ze stanow hover,
   a ich obsluga i tak kosztuje przy przewijaniu. */
@media (hover: none) {
  #vp .card:hover { box-shadow: inset 0 1px 0 0 rgba(255, 255, 255, .06),
                                inset 0 0 0 1px var(--edge); }
}

/* ── Gwarancje przy przycisku „Zamawiam" ──────────────────────────────────
   Sygnaly zaufania dzialaja tylko wtedy, gdy sa TAM, gdzie zapada decyzja.
   W stopce strony nikt ich nie czyta. Ikona po lewej, zdanie po prawej,
   pierwsze slowa pogrubione — dzieki temu da sie je omiesc wzrokiem. */
#vp .gwarancje {
  display: grid;
  gap: 10px;
  margin: 16px 0 0;
  padding: 14px;
  border-radius: var(--r);
  background: rgba(255, 255, 255, .02);
  box-shadow: inset 0 0 0 1px var(--edge);
}
#vp .gwarancje li {
  display: flex;
  align-items: flex-start;
  gap: 10px;
  font-size: 13px;
  line-height: 1.45;
  color: var(--dim);
}
#vp .gwarancje li b { color: var(--ink); font-weight: 650; }
#vp .gwarancje svg { width: 17px; height: 17px; flex: none; margin-top: 1px; color: var(--volt); }

/* Wybrany wariant w historii zamowien klienta — drugi plan pod nazwa. */
#vp .oi-w {
  display: block;
  margin-top: 2px;
  font-style: normal;
  font-size: 12px;
  color: var(--dim);
}

/* ── Opinie: pas na telefonie, siatka na komputerze ───────────────────────
   Poziomy pas z ukrytym paskiem przewijania dziala palcem, ale MYSZA nie ma
   czym go przesunac — kolko przewija strone w pionie. Na komputerze wszystko
   poza pierwszym ekranem bylo wiec dla klienta niewidoczne. Od 861 px uklad
   zmienia sie w zwykla siatke: opinie po prostu leza obok siebie i widac je
   wszystkie, bez zgadywania, ze cos jest „dalej w prawo". */
@media (min-width: 861px) {
  #vp .rev-rail {
    grid-auto-flow: row;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    grid-auto-columns: auto;
    overflow-x: visible;
    scroll-snap-type: none;
    gap: 16px;
  }
}

/* Nadmiar opinii czeka pod przyciskiem — dwa rzedy wystarcza, zeby przekonac,
   a nie rozpychaja strony na kilka ekranow. */
#vp .rev-ukryta { display: none; }
#vp .rev-wiecej { display: flex; justify-content: center; margin-top: 22px; }

/* ── Paczki w drodze (konto klienta) ──────────────────────────────────────
   Sekcja istnieje dla jednej sytuacji: klient stoi przed paczkomatem
   i potrzebuje kodu. Wszystko jest wiec podporzadkowane temu, zeby kod dalo
   sie przeczytac z wyciagnietej reki i skopiowac jednym dotknieciem. */
#vp .paczki { display: grid; gap: 12px; margin-bottom: 8px; }

#vp .paczka {
  padding: 14px;
  border-radius: var(--r-sm);
  background: var(--panel);
  box-shadow: inset 0 0 0 1px var(--edge);
}
#vp .paczka-h {
  display: flex; align-items: center; justify-content: space-between;
  gap: 10px; margin-bottom: 12px;
}
#vp .paczka-h .id { font-family: var(--mono); font-size: 13px; letter-spacing: .04em; color: var(--dim); }

/* Kod: najwiekszy element na karcie. Cyfry rozstrzelone, zeby dalo sie je
   czytac pojedynczo — przy paczkomacie przepisuje sie znak po znaku. */
#vp .kod {
  display: flex; flex-direction: column; align-items: center; gap: 4px;
  width: 100%; padding: 14px 12px;
  border: 0; border-radius: var(--r-sm); cursor: pointer;
  background: var(--volt-dim);
  box-shadow: inset 0 0 0 1px rgba(227, 178, 60, .35);
  transition: transform var(--fast), box-shadow var(--fast);
}
#vp .kod b {
  font-size: 34px; font-weight: 700; letter-spacing: .16em;
  color: var(--volt-2); font-variant-numeric: tabular-nums;
}
#vp .kod:active { transform: scale(.985); }
@media (hover: hover) and (pointer: fine) {
  #vp .kod:hover { box-shadow: inset 0 0 0 1px rgba(227, 178, 60, .6); }
}

#vp .kod-czeka {
  display: flex; align-items: center; gap: 9px;
  padding: 12px; border-radius: var(--r-sm);
  background: rgba(255, 255, 255, .02);
  font-size: 13px; color: var(--dim);
}
#vp .kod-czeka svg { width: 16px; height: 16px; flex: none; color: var(--faint); }

#vp .paczka-d { display: grid; gap: 7px; margin-top: 12px; }
#vp .paczka-d div { display: flex; align-items: center; gap: 9px; font-size: 13px; color: var(--dim); }
#vp .paczka-d svg { width: 15px; height: 15px; flex: none; color: var(--faint); }
#vp .paczka-d span { word-break: break-all; }

/* ══════════════════════════════════════════════════════════════════════════
   PANEL ZAMOWIENIA NA TELEFONIE
   ══════════════════════════════════════════════════════════════════════════
   Objaw: przy wypelnianiu danych zostawalo malenkie okienko do przewijania.
   Zlozyly sie na to trzy rzeczy naraz:

   1. `93svh` to WYSOKOSC MINIMALNA viewportu (small viewport height) — liczona
      tak, jakby pasek adresu byl zawsze rozwiniety. Panel byl wiec nizszy, niz
      mial miejsce. `dvh` bierze wysokosc RZECZYWISTA i oddaje te kilkadziesiat
      pikseli z powrotem.

   2. Stopka rosla: podsumowanie, przycisk i trzy gwarancje. Wszystko to jest
      `flex: none`, wiec kazdy dolozony wiersz zabieral miejsce formularzowi,
      az zostawal z niego paseczek.

   3. Klawiatura zaslania dol ekranu i skraca viewport jeszcze bardziej.

   Rozwiazanie: panel korzysta z pelnej dostepnej wysokosci, stopka na telefonie
   trzyma tylko to, co niezbedne do zaplaty, a gwarancje przenosimy do tresci
   (robi to skrypt) — sa wazne, ale nie musza byc przyklejone do dolu.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 860px) {
  #vp .sheet {
    /* `dvh` z zapasem na `svh` dla starszych przegladarek. */
    max-height: 93svh;
    max-height: 96dvh;
  }

  /* Tresc dostaje wyrazne minimum, zeby panel nie zapadal sie do paska. */
  #vp .sheet-b {
    min-height: 42dvh;
    padding: 8px 16px;
    scroll-padding-bottom: 96px;
  }
  /* ...ALE NIE przy otwartej klawiaturze. `42dvh` liczy się od pełnej
     wysokości okna, a nie od tego, co zostaje nad klawiaturą — na ekranie
     812 px to 341 px, czyli więcej, niż cały panel ma wtedy do dyspozycji.
     Treść rozpychała więc panel od środka i stopka z kwotą i przyciskiem
     „Zamawiam" lądowała POD klawiaturą. To był drugi powód, dla którego
     koszyk na iPhonie wyglądał na rozbity. */
  #vp .sheet.klawiatura .sheet-b { min-height: 0; }

  /* Stopka: ciasniej, bez odbierania miejsca tresci. */
  #vp .sheet-f { padding: 12px 16px calc(12px + env(safe-area-inset-bottom)); }
  #vp .sheet-f .btn-full { margin-top: 10px; }

  /* Gwarancje przeniesione do tresci — w stopce zjadaly ~140 px. */
  #vp .sheet-b .gwarancje { margin: 14px 0 4px; }
}

/* ── KLAWIATURA NA TELEFONIE ───────────────────────────────────────────────
   Dwie trzecie klientów zamawia z telefonu, a tam klawiatura zabiera połowę
   ekranu. Na to, co zostaje, przypadał wtedy przyklejony nagłówek, pełny
   rachunek (produkty, wysyłka, dopłata, suma), przycisk i drobny druk —
   na samo pole, w które klient właśnie pisze, zostawał pasek kilku linii.

   Przy otwartej klawiaturze zostaje więc TO, CO NIEZBĘDNE: kwota do zapłaty
   w jednej linii obok przycisku. Rozbicie rachunku, drobny druk i ozdobniki
   wracają, gdy tylko klawiatura się schowa — a kwota jest widoczna przez cały
   czas, bo to jedyna liczba, którą klient sprawdza przed wysłaniem. */
#vp .sheet.klawiatura { max-height: var(--kb, 96dvh); }
/* Na pelnym ekranie o wysokosci decyduje `--vvh` (realny widoczny obszar),
   wiec `max-height` z `--kb` tylko by go dublowal i zostawial pasek pustki. */
#vp .sheet.pelny.klawiatura { max-height: none; }
#vp .sheet.klawiatura .gwarancje,
#vp .sheet.klawiatura .grip { display: none; }

/* Stopka kurczy się z rachunku do jednego paska. */
#vp .sheet.klawiatura .sheet-f {
  padding: 10px 16px calc(10px + env(safe-area-inset-bottom));
}
#vp .sheet.klawiatura .sheet-f .receipt {
  display: flex; align-items: baseline; gap: 10px; margin: 0 0 8px;
}
#vp .sheet.klawiatura .sheet-f .rrow:not(.sum) { display: none; }
#vp .sheet.klawiatura .sheet-f .rrow.sum {
  flex: 1; margin: 0; padding: 0; border: 0;
}
#vp .sheet.klawiatura .sheet-f .fineprint,
#vp .sheet.klawiatura .sheet-f .freeship,
#vp .sheet.klawiatura .sheet-f .todo { display: none; }
#vp .sheet.klawiatura .sheet-f .btn-full { margin-top: 0; padding: 13px 20px; }

/* Nagłówek na pełnym ekranie też się kurczy — przy klawiaturze każdy
   piksel pionu jest wart więcej niż tytuł panelu w pełnym rozmiarze. */
#vp .sheet.klawiatura .sheet-h { padding-top: 10px; padding-bottom: 10px; }
#vp .sheet.klawiatura .sheet-h h2 { font-size: 15px; }

/* ── Ocena sklepu w naglowku ──────────────────────────────────────────────
   Element pojawia sie dopiero, gdy skrypt ma prawdziwe dane (`.on`) — pusty
   placeholder w naglowku wygladalby jak niedokonczona strona. */
#vp .ocena {
  display: none;
  align-items: center; gap: 9px; flex-wrap: wrap;
  margin: 0 0 20px;
  padding: 9px 14px 9px 12px;
  border: 0; border-radius: var(--pill); cursor: pointer;
  background: rgba(227, 178, 60, .1);
  box-shadow: inset 0 0 0 1px rgba(227, 178, 60, .28);
  text-align: left;
  transition: box-shadow var(--fast), transform var(--fast);
}
#vp .ocena.on { display: inline-flex; }
#vp .ocena b { font-size: 15px; font-weight: 700; color: var(--ink); }
#vp .ocena span { font-size: 13px; color: var(--dim); }
#vp .ocena .stars svg { width: 15px; height: 15px; }
#vp .ocena:active { transform: scale(.985); }
@media (hover: hover) and (pointer: fine) {
  #vp .ocena:hover { box-shadow: inset 0 0 0 1px rgba(227, 178, 60, .55); }
}
@media (max-width: 520px) {
  #vp .ocena {
    width: 100%;
    justify-content: flex-start;
    gap: 6px 8px;
    padding: 8px 12px;
  }
  #vp .ocena .stars svg { width: 13px; height: 13px; }
  #vp .ocena b { font-size: 15px; }
  #vp .ocena span { flex-basis: 100%; font-size: 12px; }
}

/* ── Wysylka jeszcze dzis ─────────────────────────────────────────────────
   Komunikat pod przyciskiem CTA. Wersja „pilne" (przed godzina graniczna) ma
   akcent i ikone kuriera; po godzinie schodzi do spokojnej informacji — bo to
   juz nie jest powod do pospiechu, tylko uczciwe uprzedzenie. */
#vp .wysylka {
  display: flex; align-items: center; gap: 9px; flex-wrap: wrap;
  margin: 14px 0 0;
  font-size: 13px; color: var(--dim);
}
#vp .wysylka b { color: var(--ink); font-weight: 650; }
#vp .wysylka svg { width: 17px; height: 17px; flex: none; color: var(--faint); }
#vp .wysylka.pilne svg { color: var(--volt); }
#vp .wysylka.pilne b { color: var(--volt-2); }

/* ── Podpowiedz o darmowej wysylce na pasku koszyka ───────────────────────
   Trzecia linia w docku, pokazywana tylko gdy do progu zostalo niewiele.
   Pusta nie zajmuje miejsca, wiec pasek nie skacze. */
#vp .dock-fs { display: none; font-size: 12px; color: var(--dim); line-height: 1.2; }
#vp .dock-fs.on { display: block; }
#vp .dock-fs b { color: var(--volt-2); font-weight: 650; }
#vp .dock-fs.done { color: var(--ok); }
#vp .dock-fs svg { width: 12px; height: 12px; vertical-align: -1px; margin-right: 4px; }


/* ══════════════════════════════════════════════════════════════════════════
   TELEFON — DOPRACOWANIE
   ══════════════════════════════════════════════════════════════════════════
   Strona dzialala na telefonie, ale byla ciasna: elementy stykaly sie ze soba,
   przyciski mialy rozne wysokosci, a dolny pasek koszyka zaslanial ostatni
   kafelek. Zmiany ponizej nie dokladaja niczego nowego — daja oddech temu, co
   juz jest, i wyrownuja cele dotyku do 44 px, ponizej ktorych trafia sie
   kciukiem obok.
   ══════════════════════════════════════════════════════════════════════════ */
@media (max-width: 860px) {
  /* Oddech miedzy sekcjami — na telefonie wszystko szlo jednym ciagiem. */
  #vp .catalog { padding-block: 26px 34px; }
  #vp .sec-head { margin-bottom: 18px; }

  /* Kafelki: wiecej powietrza w srodku i wieksza nazwa produktu. */
  #vp .card-body { padding: 14px; gap: 9px; }
  #vp .card-body h3 { font-size: 15px; line-height: 1.25; }
  #vp .grid { gap: 14px; }

  /* Cena i dowod spoleczny jedno pod drugim — obok siebie sie nie mieszcza
     i lamaly sie w brzydki sposob. */
  #vp .card-foot { flex-direction: column; align-items: flex-start; gap: 6px; }

  /* Cele dotyku. Ponizej 44 px kciuk trafia obok — to nie estetyka, tylko
     liczba zamowien, ktore nie doszly do skutku. */
  #vp .btn-buy { min-height: 44px; }
  #vp .chip { min-height: 34px; padding: 0 12px; }
  #vp .icon-btn { width: 42px; height: 42px; }

  /* Dolny pasek koszyka zaslanial ostatni rzad kafelkow — dokladamy zapas
     na jego wysokosc, zeby dalo sie doscrollowac do konca katalogu. */
  #vp main { padding-bottom: calc(96px + env(safe-area-inset-bottom)); }

  /* Naglowek: mniej pionu, wiecej tresci nad zgieciem ekranu.

     UWAGA: gorny odstep MUSI zawierac wysokosc paska nawigacji. Hero ma
     ujemny `margin-top`, zeby jego tlo przechodzilo pod przezroczysty pasek —
     wiec padding rowny 26px wpychal „SKLEP OTWARTY" prosto na logo. Ten blad
     widac tylko na telefonie, bo na desktopie obowiazuje regula bazowa. */
  #vp .hero { padding-block: calc(var(--nav-h) + 18px) 30px; }
  #vp .hero h1 { font-size: clamp(2rem, 8.4vw, 2.7rem); line-height: 1.06; }
  #vp .lede { font-size: 15px; line-height: 1.55; }
  #vp .hero-cta { gap: 10px; }
  #vp .hero-cta .btn { flex: 1; justify-content: center; min-height: 48px; }

  /* Ocena i komunikat o wysylce — czytelne, ale nie krzyczace. */
  #vp .ocena { margin-bottom: 16px; }
  #vp .wysylka { font-size: 13px; }
}

/* Bardzo waskie ekrany (iPhone SE i podobne) — jeden kafelek w rzedzie
   czyta sie lepiej niz dwa sciesnione do 150 px. */
@media (max-width: 380px) {
  /* Dwie kolumny zostaja — bestseller i tak zajmuje pelna szerokosc, wiec
     pierwszy ekran jest czytelny, a reszta katalogu nie rozciaga sie na
     kilkanascie ekranow przewijania. */
  #vp .grid { gap: 10px; }
  #vp .card-body { padding: 12px; }
  #vp .card-body h3 { font-size: 15px; }
  #vp .card.hero-card .card-body h3 { font-size: 17px; }
}

/* Pasek korzysci na telefonie: jeden pod drugim, w rzedzie sie nie miesci. */
@media (max-width: 640px) {
  #vp .specs { grid-template-columns: 1fr; gap: 14px; margin-top: 32px; padding-top: 22px; }
  #vp .specs div { flex-direction: row; align-items: flex-start; gap: 11px; }
  #vp .specs svg { margin-top: 2px; }
  #vp .specs b { display: inline; }
  #vp .specs div > div { display: flex; flex-direction: column; }
}

/* ── Wyrozniony bestseller ────────────────────────────────────────────────
   Pierwszy kafelek w widoku „Wszystko" zajmuje cala szerokosc siatki. Na
   telefonie to najwazniejsze miejsce na stronie: klient widzi jeden produkt
   duzo, zamiast dwoch po polowie. Ponizej wraca zwykla siatka. */
#vp .card.hero-card { grid-column: 1 / -1; }
#vp .card.hero-card .card-body h3 { font-size: 20px; }
#vp .card.hero-card .cost b { font-size: 24px; }

@media (min-width: 861px) {
  /* Na duzym ekranie wyrozniony zajmuje dwie kolumny z czterech — nadal sie
     wybija, ale nie rozpycha calego rzedu na jeden produkt. */
  #vp .card.hero-card { grid-column: span 2; }
  /* KADR WYROZNIONEGO KAFELKA.
     Bylo tu 16:10 — pole szersze niz wysokie. Zdjecia produktow sa pionowe
     (4:5), wiec przy `contain` produkt zajmowal polowe szerokosci pola,
     a reszta byla pustym tlem: najwazniejszy kafelek na stronie pokazywal
     najmniejszy produkt.

     Kwadrat to kompromis miedzy pionowym zdjeciem a szerokoscia dwoch kolumn:
     produkt jest duzy, a karta nie urasta do dwukrotnosci sasiadow i nie
     rozpycha rzedu. */
  #vp .card.hero-card .stagelet { aspect-ratio: 1 / 1; }
  /* Zdjecie ma kadr 4:5 z zapasem tla nad i pod produktem. W kwadracie
     `contain` pomniejszalo je jeszcze raz — hit tygodnia wychodzil mniejszy
     niz produkty obok. `cover` obcina tylko ten zapas tla, a produkt
     (78% wysokosci kadru) miesci sie w calosci. */
  #vp .card.hero-card .stagelet img { object-fit: cover; padding: 0; border-radius: 0; }
}

/* Plakietka „Hit tygodnia" — na zdjeciu wyroznionego kafelka, po przeciwnej
   stronie niz wskaznik dostepnosci, zeby nic na siebie nie nachodzilo. */
#vp .hit {
  position: absolute; top: 12px; right: 12px;
  display: inline-flex; align-items: center; gap: 5px;
  padding: 6px 11px; border-radius: var(--pill);
  background: var(--volt); color: #17130a;
  font-weight: 700; letter-spacing: .02em;
  box-shadow: 0 8px 24px -10px rgba(227, 178, 60, .9);
}
#vp .hit svg { width: 12px; height: 12px; }

/* ── Ocena w naglowku: zwarty uklad ───────────────────────────────────────
   Gwiazdki rozjezdzaly sie na cala szerokosc, bo `.ocena` jest kontenerem
   flex z `flex-wrap` i traktowala kazdy element jako osobna kolumne. Blok
   gwiazdek ma trzymac sie razem i stac obok noty, a podpis schodzi pod spod. */
#vp .ocena .stars {
  display: inline-flex;
  flex: none;
  gap: 3px;
}
#vp .ocena { align-items: center; row-gap: 2px; }
#vp .ocena b { flex: none; margin-left: 2px; }

/* ── Cele dotyku ──────────────────────────────────────────────────────────
   Ponizej 40 px kciuk trafia obok — a kazde nietrafienie w wybor smaku albo
   w koszyk to zamowienie, ktore nie doszlo do skutku. */
@media (max-width: 860px) {
  #vp .icon-btn { min-width: 44px; min-height: 44px; }
  #vp .chip { min-height: 40px; padding: 0 14px; }
  #vp .stepper { height: 44px; }
  #vp .stepper button { width: 44px; }
  #vp .th { width: 64px; height: 64px; }
}

/* ── Pasek narzedzi katalogu ──────────────────────────────────────────────
   Szukanie i porzadek. Dwa pola, bez ozdobnikow — ich zadaniem jest skrocic
   droge do produktu, a nie byc kolejna sekcja do przewijania. */
#vp .narzedzia {
  display: flex; gap: 10px; align-items: center;
  margin: 4px 0 14px;
  /* Miejsce zarezerwowane od pierwszej klatki — dzieki temu wypelnienie paska
     przez skrypt nie przesuwa katalogu w dol. Pusty (bez zawartosci) nie
     zajmuje nic, wiec przy wylaczonym JS nie zostaje dziura. */
  min-height: 0;
}
#vp .narzedzia:not(:empty) { min-height: 44px; }
#vp .szukajka {
  position: relative; flex: 1; min-width: 0;
  display: flex; align-items: center; gap: 9px;
  padding: 0 12px;
  height: 44px;
  border-radius: var(--r-sm);
  background: var(--raise);
  box-shadow: inset 0 0 0 1px var(--edge);
  transition: box-shadow var(--fast);
}
#vp .szukajka:focus-within { box-shadow: inset 0 0 0 1.5px rgba(227, 178, 60, .55); }
#vp .szukajka svg { width: 17px; height: 17px; color: var(--faint); flex: none; }
#vp .szukajka input {
  flex: 1; min-width: 0;
  border: 0; background: none; outline: none;
  color: var(--ink); font-size: 15px; font-family: inherit;
}
/* Systemowy „x" w polu typu search bywa niewidoczny na ciemnym tle —
   rysujemy wlasny, o wygodnym rozmiarze dla kciuka. */
#vp .szukajka input::-webkit-search-cancel-button { display: none; }
#vp .szukajka .czysc {
  display: grid; place-items: center;
  width: 30px; height: 30px; flex: none;
  border: 0; border-radius: 50%; cursor: pointer;
  background: var(--raise-2); color: var(--dim);
}
#vp .szukajka .czysc svg { width: 12px; height: 12px; }

#vp .sortowanie {
  flex: none; height: 44px; padding: 0 12px;
  border: 0; border-radius: var(--r-sm); cursor: pointer;
  background: var(--raise); color: var(--dim);
  box-shadow: inset 0 0 0 1px var(--edge);
  font-size: 13px; font-family: inherit;
}
#vp .sortowanie:focus { outline: none; box-shadow: inset 0 0 0 1.5px rgba(227, 178, 60, .55); }

#vp .pusto-akcja { display: flex; justify-content: center; margin-top: 16px; }

@media (max-width: 520px) {
  /* Na waskim ekranie sortowanie schodzi pod pole szukania — obok siebie
     zostawialyby na wpisywanie ze 120 px. */
  #vp .narzedzia { flex-wrap: wrap; }
  #vp .szukajka { flex-basis: 100%; }
  #vp .sortowanie { flex: 1; }
}

/* Przelacznik „Na stanie" — obok sortowania. Wylaczony domyslnie: wyprzedana
   pozycja mowi klientowi, ze produkt istnieje i wroci. */
#vp .filtr {
  display: inline-flex; align-items: center; gap: 7px; flex: none;
  height: 44px; padding: 0 14px;
  border: 0; border-radius: var(--r-sm); cursor: pointer;
  background: var(--raise); color: var(--dim);
  box-shadow: inset 0 0 0 1px var(--edge);
  font-size: 13px; font-family: inherit;
  transition: color var(--fast), box-shadow var(--fast), background var(--fast);
}
#vp .filtr svg { width: 15px; height: 15px; opacity: .45; }
#vp .filtr.on {
  color: var(--ink);
  background: var(--volt-dim);
  box-shadow: inset 0 0 0 1px rgba(227, 178, 60, .5);
}
#vp .filtr.on svg { opacity: 1; color: var(--volt); }

/* ── Podobne produkty w widoku produktu ───────────────────────────────────
   Trzy kafelki w rzedzie, male i bez opisow — to podpowiedz na wypadek, gdy
   ten produkt nie pasuje, a nie druga strona sklepu. */
#vp .pv-sekcja { margin-top: 22px; }
#vp .podobne { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; margin-top: 10px; }
#vp .podobny {
  display: flex; flex-direction: column; gap: 6px;
  padding: 8px; border: 0; cursor: pointer; text-align: left;
  border-radius: var(--r-sm);
  background: var(--raise);
  box-shadow: inset 0 0 0 1px var(--edge);
  transition: box-shadow var(--fast), transform var(--fast);
}
#vp .podobny img, #vp .podobny-ph {
  width: 100%; aspect-ratio: 1 / 1; object-fit: contain;
  border-radius: 8px; background: var(--raise-2);
}
#vp .podobny-n {
  font-size: 12px; font-weight: 600; line-height: 1.25; color: var(--ink);
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; overflow: hidden;
}
#vp .podobny-c { font-size: 13px; font-weight: 650; color: var(--volt-2); }
#vp .podobny:active { transform: scale(.97); }
@media (hover: hover) and (pointer: fine) {
  #vp .podobny:hover { box-shadow: inset 0 0 0 1px var(--edge-2); }
}

/* Linki w stopce i pola wyboru mialy 20-25 px wysokosci — palcem trafia sie
   w nie przypadkiem. Powiekszamy sam OBSZAR DOTYKU, nie tekst, wiec wyglad
   zostaje bez zmian. */
@media (max-width: 860px) {
  #vp .links a { display: inline-flex; align-items: center; min-height: 40px; }
  #vp .field.check label,
  #vp .zgody label { min-height: 40px; display: flex; align-items: center; gap: 10px; }
  #vp .zgody input[type="checkbox"],
  #vp .field.check input[type="checkbox"] { width: 22px; height: 22px; flex: none; }
}

/* ── Rowna wysokosc kafelkow ──────────────────────────────────────────────
   Chipy na kafelku musza byc JEDNOLINIJKOWE. Nazwy smaków bywaja calymi
   listami i lamane na kilka linii rozjezdzaly caly rzad kart. W widoku
   produktu chipy zostaja pelne — tam jest na to miejsce. */
/* Smaki na kafelku: zawijaja sie w dol, WSZYSTKIE widoczne.

   Karty w rzedzie i tak wyrownuja sie do najwyzszej (siatka), a cena
   i przycisk siedza przyklejone do dolu — dlatego rozna liczba smakow nie
   rozjezdza juz ukladu: to, na co klient patrzy (cena, przycisk), jest
   w kazdej karcie na tej samej wysokosci.

   Kazdy chip zostaje JEDNOLINIJKOWY. Czesc nazw smakow to cale listy
   („Blueberry Ice • Strawberry Ice • Watermelon Ice") i zlamane na trzy linie
   potrafily zrobic z jednego chipa pol kafelka. */
#vp .card .chips {
  flex-wrap: wrap;
  align-content: flex-start;
}
#vp .card .chips .chip {
  flex: none;
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
#vp .card .chip {
  max-width: 100%;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Tresc karty rozciaga sie, a cena i przycisk siadaja na dole — dzieki temu
   karty w rzedzie koncza sie na tej samej wysokosci niezaleznie od tego, ile
   maja opisu i wariantow. */
#vp .card-body { flex: 1; display: flex; flex-direction: column; }
#vp .card-body .card-foot { margin-top: auto; }
#vp .card-body .note {
  display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical;
  overflow: hidden;
}

/* ══════════════════════════════════════════════════════════════════════════
   STABILNOSC UKLADU I PRZEWIJANIE
   ══════════════════════════════════════════════════════════════════════════
   1. SKAKANIE. Ocena, komunikat o wysylce i pasek narzedzi pojawiaja sie
      dopiero po odpowiedzi serwera. Wstawione w gotowy uklad PRZESUWAJA
      wszystko pod soba — klient czyta naglowek i tekst ucieka mu w dol.
      Rezerwujemy im miejsce od pierwszej klatki: element jest niewidoczny,
      ale zajmuje swoja wysokosc (`visibility`, nie `display`).

   2. PRZEWIJANIE W BOK. Zakladki kategorii, tasma i miniatury przewijaja sie
      poziomo. Bez `overscroll-behavior-x` gest kontynuowany po dojechaniu do
      konca przechodzi na CALA strone i wyglada, jakby uklad sie rozjezdzal.
   ══════════════════════════════════════════════════════════════════════════ */
#vp .ocena {
  display: inline-flex;
  visibility: hidden;
  min-height: 42px;
}
#vp .ocena.on { visibility: visible; }

#vp .wysylka { min-height: 22px; }

#vp .tabs,
#vp .ticker,
#vp .thumbs,
#vp .secnav,
#vp .rev-rail {
  overscroll-behavior-x: contain;
  overscroll-behavior-y: auto;
}

/* Gest w poziomie na paskach nie moze przewijac strony w pionie i odwrotnie —
   przegladarka wybiera os na starcie gestu i trzyma sie jej. */
#vp .tabs, #vp .thumbs, #vp .rev-rail { touch-action: pan-x; }
#vp main { touch-action: pan-y; }

/* ── Najczęstsze pytania ─────────────────────────────────────────────────────
   Sekcja stoi nad stopką i ma być łatwa do omiecenia wzrokiem: same pytania
   widoczne od razu, odpowiedzi po kliknięciu. Rozwinięte od początku zajęłyby
   pół ekranu i klient przewinąłby je bez czytania.

   `<details>` zamiast własnego rozwijania jest tu świadome: działa bez
   JavaScriptu, czytniki ekranu znają ten element, a wyszukiwarka widzi treść
   odpowiedzi także wtedy, gdy pytanie jest zwinięte. */
#vp .faq { padding-block: 8px 64px; }

#vp .faq-lista {
  display: grid;
  gap: 10px;
  /* Dwie kolumny tam, gdzie jest miejsce — pytania są krótkie i w jednej
     kolumnie na szerokim ekranie zostawiałyby pustą prawą połowę. */
  grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
  align-items: start;
}

#vp .faq-p {
  border: 1px solid var(--edge);
  border-radius: var(--r-sm);
  background: var(--raise);
  overflow: hidden;
  transition: border-color .18s ease;
}

#vp .faq-p[open] { border-color: color-mix(in srgb, var(--volt) 40%, var(--edge)); }

#vp .faq-p summary {
  cursor: pointer;
  padding: 15px 44px 15px 17px;
  font-weight: 650;
  font-size: 15px;
  color: var(--ink);
  position: relative;
  /* Domyślny trójkącik przeglądarki wygląda inaczej w każdej z nich; rysujemy
     własny znacznik, żeby sekcja była spójna wszędzie. */
  list-style: none;
}
#vp .faq-p summary::-webkit-details-marker { display: none; }

#vp .faq-p summary::after {
  content: "";
  position: absolute;
  right: 18px; top: 50%;
  width: 9px; height: 9px;
  margin-top: -6px;
  border-right: 2px solid var(--volt);
  border-bottom: 2px solid var(--volt);
  transform: rotate(45deg);
  transition: transform .2s ease;
}
#vp .faq-p[open] summary::after { transform: rotate(-135deg); margin-top: -2px; }

#vp .faq-p summary:hover { background: color-mix(in srgb, var(--volt) 6%, transparent); }

#vp .faq-p p {
  margin: 0;
  padding: 0 17px 16px;
  color: var(--dim);
  font-size: 15px;
  line-height: 1.62;
}

@media (max-width: 640px) {
  #vp .faq { padding-block: 4px 44px; }
  #vp .faq-lista { grid-template-columns: 1fr; }
  #vp .faq-p summary { font-size: 15px; padding: 14px 40px 14px 15px; }
}

/* ── Podstrony treści (regulamin, dostawa, kontakt) ──────────────────────────
   Tu klient CZYTA, a nie przegląda. Reguły są więc inne niż w katalogu:
   węższa kolumna, większy odstęp między wierszami, wyraźne nagłówki sekcji.
   Tekst regulaminu w układzie zaprojektowanym pod karty produktów byłby
   ścianą liter, przez którą nikt nie przechodzi — a to właśnie ten tekst
   klient czyta wtedy, gdy się waha. */
#vp .tresc { padding: 4px 0 24px; }

#vp .tresc-sek { margin-bottom: 26px; }
#vp .tresc-sek:last-child { margin-bottom: 6px; }

#vp .tresc-sek h3 {
  margin: 0 0 10px;
  font-size: 15px;
  font-weight: 700;
  color: var(--ink);
  letter-spacing: -.01em;
}

#vp .tresc p {
  margin: 0 0 10px;
  color: var(--dim);
  font-size: 15px;
  /* 1.68 zamiast domyślnych ~1.4: dłuższy tekst na ciemnym tle potrzebuje
     więcej powietrza między wierszami, inaczej oko gubi linię. */
  line-height: 1.68;
}

#vp .tresc-lista {
  margin: 0 0 10px;
  padding: 0;
  list-style: none;
}

#vp .tresc-lista li {
  position: relative;
  padding-left: 18px;
  margin-bottom: 8px;
  color: var(--dim);
  font-size: 15px;
  line-height: 1.62;
}

/* Złota kropka zamiast punktora przeglądarki — ten sam akcent, co w całym
   sklepie, i nie zmienia rozmiaru razem z tekstem. */
#vp .tresc-lista li::before {
  content: "";
  position: absolute;
  left: 2px; top: 9px;
  width: 5px; height: 5px;
  border-radius: 50%;
  background: var(--volt);
}

#vp .tresc .btn { margin: 4px 0 10px; }

/* Stopka: linki podstron obok siebie, z odstępem wygodnym dla palca. */
#vp .foot .links a { white-space: nowrap; }

@media (max-width: 640px) {
  #vp .tresc p, #vp .tresc-lista li { font-size: 15px; }
  #vp .tresc-sek { margin-bottom: 22px; }
}

/* ── Zapis na powrót towaru ──────────────────────────────────────────────────
   Przycisk „Powiadom mnie" stoi tam, gdzie normalnie jest „Dodaj do koszyka",
   ale MUSI wyglądać inaczej — inaczej klient klika go odruchowo, sądząc że
   kupuje. Stąd obrys zamiast wypełnienia: widoczny, ale nieudający zakupu.

   Po zapisaniu przycisk zmienia się w potwierdzenie ze złotą ramką i haczykiem
   — klient ma widzieć, że zadziałało, bez czytania komunikatu. */
#vp .btn.czeka {
  border-color: var(--volt);
  color: var(--volt);
  background: var(--volt-dim);
}

#vp .btn.czeka::before {
  content: "✓";
  margin-right: 8px;
  font-weight: 800;
}

/* ── Ruch: reakcja na dotyk ──────────────────────────────────────────────────
   ZASADA: odpowiedź na WCIŚNIĘCIE, nie na puszczenie.
   Element, który reaguje dopiero po oderwaniu palca, sprawia wrażenie
   opóźnionego, nawet gdy nic nie trwa dłużej. Wciśnięcie ma być widoczne
   natychmiast — to jedna z tych rzeczy, których nikt nie zauważa, dopóki
   ich nie ma. */
/* `touch-action` i efekt wcisniecia TYLKO na elementach, ktore sie klika.
   Na calej karcie produktu potrafilo to przeszkadzac w przewijaniu listy
   palcem — a przewijanie jest wazniejsze niz efekt wcisniecia. */
#vp .btn,
#vp .icon-btn,
#vp .chip,
#vp .dock,
#vp .faq-p summary {
  /* Krótko i bez opóźnienia — reakcja ma być natychmiastowa. */
  transition: transform 110ms cubic-bezier(.2, .8, .3, 1),
              background-color 140ms ease,
              border-color 140ms ease,
              opacity 140ms ease;
  /* Bez tego przeglądarka na telefonie dokłada własne podświetlenie
     i ~300 ms zwłoki przy dotknięciu. */
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

#vp .btn:active { transform: scale(.965); }
#vp .icon-btn:active { transform: scale(.9); }
#vp .chip:active { transform: scale(.94); }
/* Karta bez efektu wcisniecia — patrz uwaga wyzej. */
#vp .dock:active { transform: scale(.985); }

/* Panel prowadzony palcem. Przejście CSS musi wtedy zniknąć — inaczej walczy
   z ruchem sterowanym z JavaScriptu i panel „gumuje się" za palcem zamiast
   trzymać się go 1:1. */
#vp .sheet.ciagniety {
  transition: none;
  /* Podpowiedź dla przeglądarki TYLKO na czas gestu: warstwa na GPU jest
     wtedy potrzebna, a po puszczeniu klasa znika i tekst wraca do pełnej
     ostrości. */
  will-change: transform;
}
#vp .sheet.ciagniety .sheet-b { overflow-y: hidden; }
#vp .scrim.ciagniety { transition: none; }

/* Uchwyt panelu ma zapraszać do chwycenia — powiększa się pod palcem. */
#vp .grip {
  transition: width 160ms cubic-bezier(.2, .8, .3, 1),
              background-color 160ms ease;
}
#vp .sheet.ciagniety .grip { width: 56px; background: var(--volt); }

/* Licznik w koszyku: krótkie „kopnięcie" w chwili dodania produktu.
   Potwierdza, że kliknięcie zadziałało, bez zabierania miejsca na komunikat. */
@keyframes vp-kopniecie {
  0%   { transform: scale(1); }
  35%  { transform: scale(1.5); }
  70%  { transform: scale(.92); }
  100% { transform: scale(1); }
}
#vp .count.kopnij { animation: vp-kopniecie 420ms cubic-bezier(.2, .8, .3, 1); }

/* Produkt „lecący" do koszyka — obraz-duch podążający po łuku.
   Pokazuje, DOKĄD trafił produkt; bez tego dodanie do koszyka jest zdarzeniem
   bez miejsca w przestrzeni. */
#vp .lot {
  position: fixed;
  z-index: 90;
  border-radius: var(--r-sm);
  object-fit: contain;
  pointer-events: none;
  will-change: transform, opacity;
}

/* Uszanowanie ustawienia systemowego. „Mniej ruchu" nie znaczy „bez reakcji":
   zostają natychmiastowe zmiany stanu, znika to, co jedzie przez ekran. */
@media (prefers-reduced-motion: reduce) {
  #vp .btn, #vp .card, #vp .icon-btn, #vp .chip, #vp .dock { transition: none; }
  #vp .btn:active, #vp .icon-btn:active, #vp .chip:active,
  #vp .card:active, #vp .dock:active { transform: none; opacity: .82; }
  #vp .count.kopnij { animation: none; }
  #vp .lot { display: none; }
}

/* ── Darmowa wysyłka ─────────────────────────────────────────────────────────
   Drugi segment znacznika „Sklep otwarty" w nagłówku. Złoto sklepu, oddzielone
   cienką kreską — czyta się jako jedna, spójna informacja o stanie sklepu,
   a nie jak doklejony baner promocyjny. */
#vp .kicker .kicker-free {
  display: inline-flex; align-items: center; gap: 6px;
  padding-left: 11px; margin-left: 2px;
  border-left: 1px solid var(--edge);
  color: var(--volt);
}
#vp .kicker .kicker-free svg { width: 13px; height: 13px; flex: none; }

/* W koszyku: bez paska postępu, tylko jedna linijka potwierdzenia. */
#vp .freeship.gratis .t { margin-bottom: 0; }
#vp .freeship.gratis svg { width: 15px; height: 15px; color: var(--volt); }

@media (max-width: 360px) {
  /* Na najwęższych telefonach obie informacje w jednej pigułce nie mieszczą
     się w linii — zostawiamy tylko darmową wysyłkę, bo to ona sprzedaje. */
  #vp .kicker:has(.kicker-free) > .tag:not(.kicker-free) { display: none; }
  #vp .kicker .kicker-free { border-left: 0; padding-left: 0; margin-left: 0; }
}


/* ══════════════════════════════════════════════════════════════════════════
   TELEFON — PORZĄDKI (wrzesień 2026)
   ══════════════════════════════════════════════════════════════════════════
   Jeden blok zamiast kolejnych warstw poprawek rozsianych po pliku. Stoi na
   końcu arkusza, więc przy tej samej precyzji selektorów wygrywa z regułami
   wyżej — nie trzeba ich szukać ani przebijać `!important`.

   Cel, zmierzony na 375 px: pierwszy produkt był 1203 px od góry, czyli
   dopiero po półtora ekranu. Klient przewijał nagłówek, oceny, liczniki
   i dwa rzędy kafelków, zanim zobaczył cokolwiek do kupienia. */

/* ── Pasek koszyka na dole ekranu ──────────────────────────────────────────
   Liczba pozycji, kwota i dopisek o wysyłce stały jeden pod drugim — trzy
   linie w pigułce wysokiej na 60 px. Gdy dopisek stał się stały (darmowa
   wysyłka), tekst wystawał nad i pod pasek i nachodził na treść strony.
   Liczba i kwota idą teraz w jednej linii, dopisek pod nimi: dwie linie
   mieszczą się z zapasem. */
#vp .dock .l {
  display: grid;
  grid-template-columns: auto auto;
  justify-content: start;
  align-items: baseline;
  column-gap: 8px;
  row-gap: 2px;
  min-width: 0;
}
#vp .dock .l .dock-fs { grid-column: 1 / -1; white-space: nowrap; }

@media (max-width: 640px) {
  /* ── Skróty sekcji: jeden rząd jak pasek w aplikacji ──────────────────────
     Siatka 2×2 zajmowała 124 px. Cztery ikony z podpisem w jednym rzędzie
     mieszczą się na każdym telefonie i zajmują połowę tego. */
  #vp .secnav {
    display: grid;
    grid-template-columns: repeat(4, minmax(0, 1fr));
    gap: 6px;
    padding-block: 10px 0;
  }
  #vp .sec {
    flex-direction: column;
    gap: 5px;
    height: 60px;
    padding: 0 4px;
    font-size: 12px;
    letter-spacing: 0;
  }
  #vp .sec svg { width: 18px; height: 18px; }

  /* ── „Dlaczego tu": same tytuły ───────────────────────────────────────────
     Tytuł niesie całą informację („Darmowa wysyłka", „Wysyłka w 24 h").
     Opisy pod nimi rozciągały sekcję do 151 px przed katalogiem. */
  /* Czysta siatka 2×2 zamiast przewijanego rzędu. Rząd miał dwie gryzące się
     reguły (stałe dwie kolumny + kolumny „62%”): dwa pierwsze kafelki
     wychodziły wąskie, dwa kolejne szerokie, a przyciąganie przewijania
     dosuwało pierwszy kafelek do samej krawędzi ekranu. Cztery krótkie
     tytuły mieszczą się naraz — nie ma czego chować za przewijaniem. */
  #vp .perks {
    display: grid;
    grid-auto-flow: row;
    grid-template-columns: repeat(2, minmax(0, 1fr));
    grid-auto-columns: auto;
    overflow: visible;
    scroll-snap-type: none;
    gap: 8px;
    padding-block: 16px 0;
    margin-top: 0;
  }
  #vp .perk {
    flex-direction: row;
    align-items: center;
    gap: 9px;
    padding: 11px 12px;
  }
  #vp .perk b { font-size: 13px; line-height: 1.25; }
  #vp .perk span:not(.perk-i) { display: none; }
  #vp .perk-i { flex: none; }

  /* ── Nagłówek ───────────────────────────────────────────────────────────── */
  /* Pełny opis zamiast ucięcia w pół zdania. Wielokropek po „wysyłamy tego…"
     wyglądał jak błąd, a to jedyne zdanie mówiące, jak u nas się kupuje. */
  #vp .lede {
    display: block;
    -webkit-line-clamp: unset;
    overflow: visible;
    max-width: none;
    font-size: 15px;
    line-height: 1.5;
  }
  #vp .ticker { margin-top: 26px; }

  /* ── Katalog ────────────────────────────────────────────────────────────── */
  #vp .tabs { margin-bottom: 16px; }
  /* Kafelek „hitu" w kwadracie: na telefonie zajmował 733 px — cały ekran
     na jeden produkt. Kwadrat oddaje ~80 px, a produkt nadal jest duży.
     Zdjęcie przycinamy tylko o zapas tła (jak na komputerze, wyżej). */
  #vp .card.hero-card .stagelet { aspect-ratio: 1 / 1; }
  #vp .card.hero-card .stagelet img { object-fit: cover; padding: 0; border-radius: 0; }

  /* ── Przyciski pod kciuk ───────────────────────────────────────────────────
     +/− ilości miały 32 px wysokości. Zalecane minimum dla dotyku to 44 px;
     40 px trzyma rozmiar karty, a trafia się już pewnie. */
  #vp .stepper button { width: 40px; height: 40px; }
}

/* ── Najmniejszy tekst ───────────────────────────────────────────────────────
   Plakietki „Na stanie" miały 10 px, „zakup potwierdzony" 9,5 px — na
   telefonie na granicy czytelności, a to akurat informacje, które sprzedają. */
#vp .avail { font-size: 12px; }
#vp .rev-ok { font-size: 12px; }
#vp .bulk, #vp .in-cart-note { font-size: 12px; }

/* ══════════════════════════════════════════════════════════════════════════
   WYSZUKIWARKA PACZKOMATÓW
   Lista pod polem, nie nakładka: na telefonie klawiatura zasłania połowę
   ekranu, a rozwijana nakładka lądowałaby dokładnie pod nią.
   ══════════════════════════════════════════════════════════════════════════ */
#vp .lk-tools {
  display: flex; align-items: center; gap: 12px; flex-wrap: wrap;
  margin: -6px 0 10px;
}
#vp .btn.sm { padding: 8px 14px; font-size: 13px; }
#vp .btn.sm svg { width: 14px; height: 14px; }
#vp .lk-tools .tag { text-transform: none; letter-spacing: 0; font-weight: 500; }
#vp .lk-tools .tag.bad { color: var(--bad); }

#vp .lk-list {
  display: flex; flex-direction: column;
  margin-bottom: 16px;
  max-height: 280px; overflow-y: auto;
  border-radius: var(--r);
  background: var(--raise);
  box-shadow: inset 0 0 0 1px var(--edge);
  -webkit-overflow-scrolling: touch;
}
#vp .lk-item {
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  width: 100%; padding: 12px 15px; text-align: left;
  transition: background var(--fast);
}
#vp .lk-item + .lk-item { box-shadow: inset 0 1px 0 0 var(--edge); }
#vp .lk-item:hover, #vp .lk-item:focus-visible { background: var(--raise-2); }
#vp .lk-main { min-width: 0; }
#vp .lk-main b {
  display: block; font-size: 13px; font-weight: 600; letter-spacing: -.015em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#vp .lk-sub {
  display: block; margin-top: 3px; font-size: 12px; color: var(--faint);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
#vp .lk-meta {
  flex: none; display: flex; flex-direction: column; align-items: flex-end; gap: 3px;
}
#vp .lk-dyst { font-family: var(--num); font-size: 12px; font-weight: 650; color: var(--volt-2); }
#vp .lk-kod { font-family: var(--mono); font-size: 12px; letter-spacing: .04em; color: var(--dim); }
#vp .lk-247 {
  padding: 1px 6px; border-radius: var(--pill);
  background: rgba(74, 222, 128, .12); color: var(--ok);
  font-size: 12px; font-weight: 700; letter-spacing: .04em;
}

/* ══════════════════════════════════════════════════════════════════════════
   KATALOG JAKO OSOBNA STRONA (/sklep)
   ══════════════════════════════════════════════════════════════════════════
   Pod adresem /sklep klient przyszedl ogladac produkty. Dostawal nad nimi
   cala strone glowna: hero, pasek ogloszen, kafle sekcji, korzysci i kafelek
   polecanego. Zmierzone na telefonie: pierwszy produkt 1115 px od gory, czyli
   poltora ekranu przewijania, zanim pojawi sie cokolwiek do kupienia.

   Po ukryciu tych blokow siatka zaczyna sie 319 px od gory — zaraz pod
   wyszukiwarka i filtrami. Klase `katalog` nadaje app.js na podstawie adresu,
   wiec strona glowna zostaje nietknieta. */
#vp.katalog .hero,
#vp.katalog .ticker,
#vp.katalog .secnav,
#vp.katalog .perks,
#vp.katalog .stage { display: none; }

/* ══════════════════════════════════════════════════════════════════════════
   KAFELEK PRODUKTU NA TELEFONIE — PORZADKI
   ══════════════════════════════════════════════════════════════════════════
   Zmierzony kafelek mial 546 px przy ekranie 812 px, czyli pol produktu na
   ekran. Rozklad: zdjecie 203, chipy wariantow 86, stopka z cena 57, przycisk
   44, opis 39, kategoria 18.

   Zabieramy to, co nie pomaga w decyzji:
     * KATEGORIA — ta sama na kazdym kafelku, a nad siatka stoja filtry,
     * NUMER POZYCJI — ozdobnik,
     * ZAWIJANIE CHIPOW — dwa smaki w kolumnie 162 px lamaly sie na trzy
       rzedy; jeden rzad przewijany w bok daje te sama informacje w 40 px.
   Efekt: 546 -> 470 px, a kafelki bez opisu 590 -> 423 px. */
@media (max-width: 640px) {
  #vp .card-body { gap: 8px; padding: 12px 12px 13px; }
  #vp .card-body .cat { display: none; }
  #vp .card .idx { display: none; }
  #vp .card .chips {
    flex-wrap: nowrap; overflow-x: auto;
    scrollbar-width: none; -ms-overflow-style: none;
    scroll-snap-type: x proximity;
  }
  #vp .card .chips::-webkit-scrollbar { display: none; }
  #vp .card .chip { white-space: nowrap; flex: none; scroll-snap-align: start; }
}

/* ══════════════════════════════════════════════════════════════════════════
   STRONA GLOWNA (/) — MNIEJ, ALE MOCNIEJ
   ══════════════════════════════════════════════════════════════════════════
   Zmierzone na telefonie PRZED: hero 968 px (wiecej niz caly ekran), w tym
   blok korzysci 207 px powtarzajacy sekcje nizej i kafelek polecanego 675 px
   powtarzajacy pierwszy kafelek katalogu. Cala strona 3391 px.

   Strona glowna ma odpowiedziec na trzy pytania: co to za sklep, czy mozna mu
   ufac, gdzie kupic. Reszta — caly katalog, FAQ, ranking — ma wlasne adresy.

   Na komputerze zostawiamy hero z kafelkiem polecanego: tam jest na to
   miejsce w drugiej kolumnie i nie spycha niczego w dol. */
@media (max-width: 900px) {
  /* Korzysci z hero znikaja — te same trzy rzeczy stoja nizej w sekcji
     `perks`, tylko zwiezlej. Dwa razy to samo na jednym ekranie to szum. */
  #vp.dom .hero .specs { display: none; }
  /* Kafelek polecanego produktu: na telefonie to 675 px na jeden produkt,
     ktory i tak jest pierwszy w siatce nizej. */
  #vp.dom .hero .stage { display: none; }
}

@media (max-width: 900px) {
  /* Pasek z haslami (EKSPRES / PACZKOMAT / BLIK) to ozdobnik — te same
     obietnice stoja nizej w korzysciach, konkretniej i bez ruchu. */
  #vp.dom .ticker { display: none; }
  /* Kafle sekcji (Katalog / Hurt / Ranking / Discord) to trzeci poziom
     nawigacji na jednym ekranie — obok paska u gory i paska koszyka na dole.
     Na telefonie zostawiamy jedno wyjscie: przycisk „Zobacz katalog". */
  #vp.dom .secnav { display: none; }
  /* Wyszukiwarka, filtry i zakladki kategorii naleza do KATALOGU. Na stronie
     glownej pokazujemy bestsellery — kto chce szukac, klika w katalog. */
  #vp.dom .narzedzia,
  #vp.dom .tabs { display: none; }
}

/* FAQ ma wlasny adres (/pomoc). Na stronie glownej zabieralo 426 px i
   odciagalo od produktow — klient, ktory ma pytanie, trafi tam z menu. */
#vp.dom .faq { display: none; }

/* /pomoc — same pytania i odpowiedzi, bez katalogu i hero. */
#vp.pomoc .hero,
#vp.pomoc .ticker,
#vp.pomoc .secnav,
#vp.pomoc .perks,
#vp.pomoc .stage,
#vp.pomoc .catalog { display: none; }

/* Na stronie glownej pokazujemy PIERWSZE SZESC pozycji. Kto chce wiecej,
   klika w katalog — i tam dostaje filtry, wyszukiwarke i cala reszte. */
#vp.dom #vp-grid > .card:nth-of-type(n+7) { display: none; }

#vp .do-katalogu {
  display: flex; width: 100%; margin-top: 22px;
  /* Wyjscie z sekcji, nie glowne wezwanie — dlatego obrys, nie zloto. */
}

/* ══════════════════════════════════════════════════════════════════════════
   KARTA PRODUKTU JAKO PODSTRONA (/produkt/...)
   ══════════════════════════════════════════════════════════════════════════
   Ten sam widok co dotad (galeria, warianty, progi hurtowe, przycisk zakupu),
   ale bez oprawy panelu: bez przyciemnionego tla, bez uchwytu do przeciagania
   i bez wrazenia nakladki nad czyms innym. Karta produktu to miejsce, w ktore
   klient wchodzi z Google i z linku, wiec ma wygladac jak strona, a nie jak
   okienko, ktore zaraz zniknie.

   Nie przepisujemy tu ani jednej linijki logiki — zmienia sie wylacznie to,
   jak ten sam element jest osadzony na stronie. */
#vp.karta .scrim { display: none; }
/* Cala tresc strony glownej znika — karta produktu jest tu jedyna trescia.
   Ukrywamy `main` w calosci, bo same sekcje zostawialy jeszcze pusty pas
   z jego marginesow (zmierzone 96 px nad naglowkiem karty). */
#vp.karta main { display: none; }

/* Panel zamkniety jest chowany przesunieciem poza ekran. Po zmianie na
   `position: static` to przesuniecie przestaje dzialac, wiec pusty panel
   wyswietlalby sie w tresci strony. Chowamy go wprost. */
#vp.karta .sheet:not(.on) { display: none; }

#vp.karta .sheet {
  position: static;
  transform: none;
  max-height: none;
  width: min(1120px, 100%);
  margin: 0 auto;
  border-radius: 0;
  background: transparent;
  box-shadow: none;
  /* Panel nasluchuje gestow, ale na stronie nie ma czego przeciagac. */
  touch-action: auto;
}
#vp.karta .sheet .grip { display: none; }
#vp.karta .sheet-h {
  position: sticky; top: 0; z-index: 5;
  background: rgba(8, 8, 10, .86);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
}
#vp.karta .sheet-b { overflow: visible; }

@media (min-width: 900px) {
  /* GALERIA PO LEWEJ, ZAKUP PO PRAWEJ — jak na karcie produktu w duzym
     sklepie. Wczesniej wszystko szlo jedna kolumna: samo zdjecie mialo
     1210 px wysokosci, a cena i przycisk laduly pod nim, poza ekranem. */
  #vp.karta .sheet-b {
    display: grid;
    grid-template-columns: minmax(0, 1.05fr) minmax(330px, .95fr);
    gap: 30px 40px;
    align-items: start;
    padding-inline: 28px;
  }
  /* Zdjecie zostaje w polu widzenia, gdy klient czyta opis i wybiera smak. */
  #vp.karta .sheet-b > .gal { position: sticky; top: 88px; }
  /* Opis, warianty i hurt siedza w prawej kolumnie; „podobne" idzie na cala
     szerokosc, bo to juz osobna sekcja pod karta. */
  #vp.karta .sheet-b > .sec-label,
  #vp.karta .sheet-b > .podobne,
  #vp.karta .sheet-b > .bulk { grid-column: 1 / -1; }

  /* Pasek zakupu przyklejony do dolu — cena i przycisk sa pod reka niezaleznie
     od tego, jak daleko klient zjechal. */
  #vp.karta .sheet-f {
    position: sticky; bottom: 0;
    width: min(1120px, 100%); margin-inline: auto;
    background: rgba(8, 8, 10, .9);
    backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
    box-shadow: 0 -1px 0 var(--edge);
  }
}

/* ══════════════════════════════════════════════════════════════════════════
   WEJSCIE NA STRONE — SZUKANIE I KATEGORIE OD RAZU
   ══════════════════════════════════════════════════════════════════════════
   Klient wchodzi z konkretna potrzeba: „mango", „kartridz", „cos do 50 zl".
   Hero z samym haslem kazal mu najpierw zjechac przez pol ekranu, zeby w ogole
   zobaczyc produkty. Pole szukania i kategorie stoja teraz pod haslem — obie
   drogi prowadza do katalogu z gotowym filtrem (/sklep?q=… albo /sklep?kat=…),
   wiec taki adres da sie tez wyslac komus dalej. */
#vp .wejscie { margin-top: 20px; display: grid; gap: 14px; }

#vp .szukajka.duza {
  display: flex; align-items: center; gap: 10px;
  height: 54px; padding: 0 8px 0 16px;
  border-radius: var(--pill);
  background: rgba(255, 255, 255, .05);
  box-shadow: inset 0 0 0 1px var(--edge-2);
  transition: box-shadow 200ms ease, background 200ms ease;
}
#vp .szukajka.duza:focus-within {
  background: rgba(255, 255, 255, .07);
  box-shadow: inset 0 0 0 1.5px rgba(227, 178, 60, .55);
}
#vp .szukajka.duza svg { width: 18px; height: 18px; color: var(--faint); flex: none; }
#vp .szukajka.duza input {
  flex: 1; min-width: 0; height: 100%;
  font-size: 15px; color: var(--ink); background: none; border: 0; outline: none;
}
#vp .szukajka.duza input::placeholder { color: var(--faint); }
#vp .szukajka.duza .btn { height: 40px; padding-inline: 20px; flex: none; }

/* Kategorie jako kafle z licznikiem: klient od razu widzi, czego i ile jest,
   zamiast domyslac sie z nazw zakladek gdzies nizej. */
#vp .kat-kafle {
  display: grid; grid-template-columns: repeat(auto-fit, minmax(140px, 1fr)); gap: 8px;
}
#vp .kat-kafel {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  padding: 13px 15px; border-radius: 14px;
  background: rgba(255, 255, 255, .035);
  box-shadow: inset 0 0 0 1px var(--edge);
  transition: background 200ms ease, box-shadow 200ms ease,
              transform 160ms cubic-bezier(.23, 1, .32, 1);
}
#vp .kat-kafel .n { font-size: 15px; font-weight: 600; letter-spacing: -.01em; }
#vp .kat-kafel .ile {
  font-family: var(--num); font-size: 12px; color: var(--faint);
  font-variant-numeric: tabular-nums;
}
#vp .kat-kafel:active { transform: scale(.985); }
@media (hover: hover) and (pointer: fine) {
  #vp .kat-kafel:hover {
    background: var(--volt-dim);
    box-shadow: inset 0 0 0 1px rgba(227, 178, 60, .4);
  }
}

@media (max-width: 640px) {
  #vp .szukajka.duza { height: 50px; padding-left: 14px; }
  #vp .szukajka.duza .btn { height: 38px; padding-inline: 16px; font-size: 15px; }
  #vp .kat-kafle { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}

/* ══════════════════════════════════════════════════════════════════════════
   POTWIERDZENIE WIEKU
   ══════════════════════════════════════════════════════════════════════════
   Pierwsza rzecz, ktora widzi nowy odwiedzajacy. Ma byc spokojna i szybka do
   odklikniecia: jedno pytanie, dwa przyciski, zadnego straszenia. Pokazuje sie
   raz na pol roku, wiec staly klient widzi ja praktycznie nigdy.

   Tlo jest rozmyte, a nie czarne: przez bramke widac, ze za nia JEST sklep —
   to zachęca do potwierdzenia zamiast zamkniecia karty. */
#vp .wiek {
  position: fixed; inset: 0; z-index: 120;
  display: grid; place-items: center; padding: 20px;
  background: rgba(6, 6, 8, .72);
  backdrop-filter: blur(18px) saturate(120%);
  -webkit-backdrop-filter: blur(18px) saturate(120%);
  animation: wiek-wejscie 260ms cubic-bezier(.16, 1, .3, 1);
}
#vp .wiek.znika { opacity: 0; transition: opacity 240ms ease; }

#vp .wiek-karta {
  width: min(420px, 100%); padding: 30px 26px 26px;
  border-radius: 22px; text-align: center;
  background: linear-gradient(180deg, rgba(255, 255, 255, .06), rgba(255, 255, 255, .02)),
              var(--panel);
  box-shadow: inset 0 0 0 1px var(--edge-2), 0 40px 90px -40px rgba(0, 0, 0, .95);
  animation: wiek-karta 320ms cubic-bezier(.16, 1, .3, 1);
}
#vp .wiek-karta h2 {
  margin-top: 14px;
  font-family: var(--display); font-size: 24px; font-weight: 700;
  letter-spacing: -.03em; line-height: 1.15;
}
#vp .wiek-karta p {
  margin-top: 10px; font-size: 15px; color: var(--dim); line-height: 1.6;
}
#vp .wiek-akcje { display: grid; gap: 10px; margin-top: 22px; }
#vp .wiek-akcje .btn { width: 100%; }

@keyframes wiek-wejscie { from { opacity: 0; } }
/* Od 0.96, nie od zera: nic w prawdziwym swiecie nie pojawia sie z niczego. */
@keyframes wiek-karta {
  from { opacity: 0; transform: scale(.96) translateY(8px); }
}
@media (prefers-reduced-motion: reduce) {
  #vp .wiek, #vp .wiek-karta { animation: none; }
}

/* Pusty element zajmuje miejsce tak samo jak pelny. Ocena sklepu pojawia sie
   dopiero, gdy sa opinie — do tego czasu zostawiala 42 px dziury miedzy
   opisem a przyciskami (widoczne jako „przerwa bez powodu" w hero). */
#vp .ocena:empty,
#vp .soc:empty,
#vp .specs:empty,
#vp .wysylka:empty { display: none; }

/* ══════════════════════════════════════════════════════════════════════════
   PAS DISCORDA
   ══════════════════════════════════════════════════════════════════════════
   Nie „nasze social media", tylko czesc drogi zakupowej: tam potwierdzamy
   zamowienie, tam idzie numer paczki, tam klient dostaje odpowiedz. Dlatego
   dostaje wlasny blok przed stopka, a nie ikonke miedzy innymi ikonkami.

   Jeden akcent na sekcje: zloto jest tylko na przycisku. Tlo to spokojna
   plyta, zeby pas nie konkurowal z produktami nad nim. */
#vp .pas-dc { margin-top: 56px; }
#vp .pas-dc-in {
  display: grid; gap: 22px; align-items: center;
  padding: 30px 26px; border-radius: 22px;
  background: linear-gradient(180deg, rgba(255, 255, 255, .05), rgba(255, 255, 255, .015));
  box-shadow: inset 0 0 0 1px var(--edge);
}
#vp .pas-dc-t > svg { width: 34px; height: 34px; color: #8b9dff; }
#vp .pas-dc h2 {
  margin-top: 14px;
  font-family: var(--display); font-size: 24px; font-weight: 700;
  letter-spacing: -.03em; line-height: 1.15;
}
#vp .pas-dc p {
  margin-top: 10px; max-width: 52ch;
  font-size: 15px; color: var(--dim); line-height: 1.6;
}
#vp .pas-dc .btn { justify-self: start; }

@media (min-width: 760px) {
  #vp .pas-dc { margin-top: 88px; }
  /* Na szerokim ekranie tekst i wezwanie w jednym rzedzie — blok zostaje
     niski i nie rozpycha konca strony. */
  #vp .pas-dc-in { grid-template-columns: minmax(0, 1fr) auto; padding: 34px 32px; }
  #vp .pas-dc .btn { justify-self: end; }
}

/* ── Rytm sekcji ────────────────────────────────────────────────────────────
   Kazda sekcja strony glownej ma ten sam odstep od poprzedniej. Wczesniej
   kazda przynosila wlasny margines (26, 44, 54, 62 px) i strona czytala sie
   jak sklejona z kawalkow — bo byla. */
#vp.dom .perks { margin-top: 44px; }
#vp.dom .catalog { margin-top: 56px; }
@media (min-width: 760px) {
  #vp.dom .perks { margin-top: 72px; }
  #vp.dom .catalog { margin-top: 88px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   KATALOG — PASEK NARZEDZI POD REKA
   ══════════════════════════════════════════════════════════════════════════
   Zakladki kategorii byly juz przyklejone, ale wyszukiwarka, filtr „na stanie"
   i sortowanie odjezdzaly z ekranem. Klient, ktory zjechal do polowy listy
   i chcial zawezic wybor, musial wracac na gore. Pod adresem /sklep caly pasek
   zostaje na miejscu. */
#vp.katalog .narzedzia {
  position: sticky; top: 62px; z-index: 41;
  margin: 0; padding-block: 10px;
  background: rgba(8, 8, 10, .92);
  backdrop-filter: blur(14px); -webkit-backdrop-filter: blur(14px);
}
/* Zakladki schodza pod pasek, zeby sie nie nachodzily. */
#vp.katalog .tabs { top: 116px; }

@media (min-width: 861px) {
  #vp.katalog .narzedzia { top: 74px; }
  #vp.katalog .tabs { top: 128px; }
}

/* ══════════════════════════════════════════════════════════════════════════
   WEJSCIE KAFELKOW
   ══════════════════════════════════════════════════════════════════════════
   Kaskada 40 ms: siatka sklada sie na oczach zamiast blysnac w calosci.
   Ruch jest krotki (320 ms) i tylko przy pierwszym rysowaniu — przy kazdym
   przefiltrowaniu listy bylby juz wylacznie opoznieniem miedzy klikiem
   a wynikiem. Nic nie startuje od zera: karta jest widoczna od 0.98 skali,
   wiec nawet przerwana animacja nie zostawia pustego miejsca. */
@media (prefers-reduced-motion: no-preference) {
  #vp .grid.wchodzi > .card {
    opacity: 0;
    animation: karta-wjazd 320ms cubic-bezier(.16, 1, .3, 1) forwards;
  }
  #vp .grid.wchodzi > .card:nth-child(2) { animation-delay: 40ms; }
  #vp .grid.wchodzi > .card:nth-child(3) { animation-delay: 80ms; }
  #vp .grid.wchodzi > .card:nth-child(4) { animation-delay: 120ms; }
  #vp .grid.wchodzi > .card:nth-child(5) { animation-delay: 160ms; }
  #vp .grid.wchodzi > .card:nth-child(n+6) { animation-delay: 200ms; }
}
@keyframes karta-wjazd {
  from { opacity: 0; transform: translateY(10px) scale(.98); }
  to { opacity: 1; transform: none; }
}
