/* hurtownianozy.pl — warstwa projektowa, style komponentów.
   Przeniesione z systemu projektowego (Claude Design). Tam komponenty są
   w Reakcie i stylują się przez `style={{…}}`; tu te same wartości żyją
   jako klasy, bo sklep renderuje się serwerowo i nie ładuje JavaScriptu
   do wyświetlenia treści (§10.2).

   Zasada z kontraktu obowiązuje bez zmian: szablon nie liczy cen ani rabatów.
   Ten arkusz też niczego nie liczy — reaguje wyłącznie na klasy i atrybuty,
   które ustawił silnik. */

/* ============================ Reset i dokument ============================ */
*,*::before,*::after{box-sizing:border-box}
html{-webkit-text-size-adjust:100%}
body{margin:0;font:var(--type-body);color:var(--text-body);background:var(--surface-page);-webkit-font-smoothing:antialiased}
h1,h2,h3,h4{font-family:var(--font-display);color:var(--text-strong);letter-spacing:var(--tracking-tight);margin:0}
p{margin:0}
img{max-width:100%;height:auto;display:block}
a{color:var(--text-link);text-decoration:none}
a:hover{color:var(--text-link-hover);text-decoration:underline;text-underline-offset:2px}
:focus-visible{outline:none;box-shadow:var(--focus-ring);border-radius:var(--radius-sm)}
::selection{background:var(--brand-100);color:var(--steel-900)}
table{border-collapse:collapse}
[hidden]{display:none!important}
ul,ol{margin:0;padding:0;list-style:none}
button{font:inherit}

/* Treść wyłącznie dla czytników — `clip-path` zamiast wyniesienia w lewo,
   bo <caption> tabeli wyniesione na -9999px potrafi rozciągnąć dokument. */
.sr-only{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;
  clip-path:inset(50%);white-space:nowrap;border:0}
.skip-link{position:absolute;left:-9999px}
.skip-link:focus{left:var(--space-4);top:var(--space-4);z-index:10;background:var(--surface-card);
  padding:var(--space-2) var(--space-4);border-radius:var(--radius-sm);box-shadow:var(--shadow-md)}

/* Kadry na zdjęcia. `img{width:100%;height:100%}` samo nie wystarczy, bo
   liczy sto procent od <picture> — a ten jest elementem liniowym o szerokości
   zawartości, więc procent wracał do naturalnego rozmiaru zdjęcia. Pionowe
   zdjęcie wychodziło wtedy poza ramkę i było ucinane przez `overflow:hidden`
   zamiast wpasować się w kwadrat.

   Kadry z `display:grid` mają wysokość z `aspect-ratio`, ale wiersz siatki
   wymierza się treścią, więc procentowa wysokość dziecka jest w nich cykliczna
   i przeglądarka traktuje ją jak `auto`. Pozycjonowanie bezwzględne wyjmuje
   <picture> z tej zależności i daje mu kadr o znanym rozmiarze; resztę robi
   `object-fit:contain`, czyli wpasowanie w środek bez rozciągania i przycinania.

   `.product__thumb` to zwykły blok z własnym `aspect-ratio` — jego wysokość
   jest znana wprost i wystarczy `display:block`. */
.product__figure picture,
.card__thumb picture,
.cart-line__thumb picture{position:absolute;inset:0;width:100%;height:100%}
.product__thumb picture{display:block;width:100%;height:100%}

/* ================================ Ikony ================================== */
/* Glif Lucide jako maska CSS — dziedziczy currentColor, więc kolor bierze
   się z tekstu, a nie z pliku. */
.ico{display:inline-block;flex:none;width:20px;height:20px;background:currentColor;
  -webkit-mask-repeat:no-repeat;mask-repeat:no-repeat;
  -webkit-mask-position:center;mask-position:center;
  -webkit-mask-size:contain;mask-size:contain;
  -webkit-mask-image:var(--ico);mask-image:var(--ico)}
.ico--sm{width:16px;height:16px}
.ico--xs{width:14px;height:14px}
.ico--lg{width:24px;height:24px}
.ico--brand{color:var(--brand-500)}

/* =============================== Układ =================================== */
.container{max-width:var(--container-max);margin:0 auto;padding:0 var(--container-pad)}
.page{padding-block:var(--space-8) var(--space-16);display:flex;flex-direction:column;gap:var(--section-gap)}
.page > h1{font:var(--type-h1)}

/* ============================== Nagłówek ================================= */
.site-header{background:var(--surface-card);border-bottom:1px solid var(--border-default)}

.service-bar{background:var(--surface-dark);color:var(--steel-400)}
/* Interlinia 1 była bezpieczna, dopóki komunikaty mieściły się w jednym wierszu.
   Na telefonie każdy się zawija i wiersze sklejają się ogonkami — stąd 1.4
   i osobny, mniejszy odstęp między wierszami niż między kolumnami. */
.service-bar__inner{max-width:var(--container-max);margin:0 auto;padding:0 var(--container-pad);
  min-height:36px;display:flex;align-items:center;gap:var(--space-2) var(--space-6);flex-wrap:wrap;
  font:var(--weight-medium) var(--text-2xs)/1.4 var(--font-body)}
.service-bar__item{display:inline-flex;align-items:center;gap:6px;padding-block:var(--space-2)}
.service-bar__item--end{margin-left:auto}
/* Trzy komunikaty w jednym rzędzie to desktop. Na telefonie zawijały się do
   trzech wierszy i zjadały 150 px — jedną piątą ekranu — zanim pokazało się
   logo. Zostaje ten jeden, który mówi o pieniądzach. */
@media (max-width:760px){
  .service-bar__item--wide,.service-bar__item--end{display:none}
  .service-bar__inner{justify-content:center}
}

.header-main{max-width:var(--container-max);margin:0 auto;padding:var(--space-4) var(--container-pad);
  display:flex;align-items:center;gap:var(--space-6);flex-wrap:wrap}
.header-main__logo{flex:none}
.header-main__logo img{height:34px;width:auto}
.header-main__actions{margin-left:auto;display:flex;align-items:center;gap:var(--space-3)}
.header-main__link{display:inline-flex;align-items:center;gap:6px;color:var(--text-body);
  font:var(--weight-medium) var(--text-xs)/1 var(--font-body)}

.cart-button{display:inline-flex;align-items:center;gap:10px;height:44px;padding:0 var(--space-4);
  background:var(--metal-face);border:1px solid var(--border-strong);border-radius:var(--radius-sm);
  box-shadow:var(--bevel-light),var(--shadow-xs);color:var(--text-strong);text-decoration:none;
  transition:var(--transition-control)}
.cart-button:hover{text-decoration:none;border-color:var(--steel-400);box-shadow:var(--bevel-light),var(--shadow-sm)}
.cart-button__icon{position:relative;display:inline-flex}
.cart-button__count{position:absolute;top:-6px;right:-8px;min-width:17px;height:17px;padding:0 4px;
  display:grid;place-items:center;border-radius:var(--radius-pill);background:var(--brand-500);
  color:#fff;font:var(--weight-bold) 10px/1 var(--font-mono)}
.cart-button__labels{display:flex;flex-direction:column;align-items:flex-start}
.cart-button__caption{font:var(--weight-semibold) var(--text-2xs)/1.1 var(--font-body);color:var(--text-muted)}
.cart-button__total{font:var(--weight-bold) var(--text-xs)/1.1 var(--font-display);color:var(--text-strong)}

/* Kategorie są w drzewie: trzy działy w pasku, podkategorie w panelu pod nim.
   Wcześniej stało tu 17 płaskich pozycji, które nie mieściły się w jednym
   rzędzie — hierarchia rozwiązała problem układu przy okazji rozwiązywania
   właściwego problemu, czyli tego, że nie było widać, gdzie jest towar. */
.main-nav{border-top:1px solid var(--border-subtle);background:var(--surface-sunken);
  position:relative;z-index:30}
.main-nav__list{max-width:var(--container-max);margin:0 auto;padding:var(--space-1) var(--container-pad);
  display:flex;gap:2px;flex-wrap:wrap}
.main-nav__item{position:relative}
.main-nav__link{display:inline-flex;align-items:center;gap:5px;height:40px;padding:0 var(--space-4);
  border-radius:var(--radius-sm);
  font:var(--weight-semibold) var(--text-sm)/1 var(--font-body);color:var(--text-body);
  white-space:nowrap;transition:var(--transition-control)}
.main-nav__link:hover{color:var(--text-strong);text-decoration:none;background:var(--steel-100)}
.main-nav__link[aria-current="page"]{font-weight:var(--weight-semibold);color:var(--text-strong);
  background:var(--surface-card);box-shadow:inset 0 -2px 0 var(--brand-500),var(--shadow-xs)}

/* Megamenu. Otwiera je :hover albo :focus-within, więc działa i myszą,
   i klawiaturą, i bez ani jednej linii JavaScriptu. */
.mega{position:absolute;top:100%;left:0;z-index:40;min-width:280px;
  display:grid;gap:var(--space-1);padding:var(--space-3);
  background:var(--surface-card);border:1px solid var(--border-default);
  border-radius:0 0 var(--radius-md) var(--radius-md);box-shadow:var(--shadow-lg);
  opacity:0;visibility:hidden;transform:translateY(-4px);
  transition:opacity .12s ease,transform .12s ease,visibility .12s}
.main-nav__item:hover > .mega,
.main-nav__item:focus-within > .mega{opacity:1;visibility:visible;transform:none}
.mega__list{display:grid;gap:1px}
.mega__link{display:flex;align-items:center;justify-content:space-between;gap:var(--space-4);
  padding:8px var(--space-3);border-radius:var(--radius-sm);
  font:var(--type-small);color:var(--text-body);white-space:nowrap}
.mega__link:hover{background:var(--surface-sunken);color:var(--text-strong);text-decoration:none}
.mega__link[aria-current="page"]{font-weight:var(--weight-semibold);color:var(--text-strong)}
.mega__count{font:var(--weight-medium) var(--text-2xs)/1 var(--font-mono);color:var(--text-muted)}
.mega__all{display:flex;align-items:center;gap:6px;margin-top:var(--space-2);
  padding:8px var(--space-3);border-top:1px solid var(--border-subtle);
  font:var(--weight-semibold) var(--text-xs)/1.2 var(--font-body);color:var(--brand-600)}

/* ========================== Wyszukiwarka ================================= */
.site-search{display:flex;align-items:center;gap:0;flex:1 1 320px;max-width:560px}
.site-search label{position:absolute;left:-9999px}
.site-search input{flex:1;height:var(--control-h-md);padding:0 var(--space-4);
  font:var(--type-small);color:var(--text-strong);
  background:var(--surface-card);border:1px solid var(--border-strong);
  border-right:0;border-radius:var(--radius-sm) 0 0 var(--radius-sm);
  box-shadow:var(--shadow-inset-well);transition:var(--transition-control)}
.site-search input::placeholder{color:var(--text-muted)}
.site-search input:focus{outline:none;border-color:var(--brand-400);box-shadow:var(--focus-ring)}
.site-search button{height:var(--control-h-md);padding:0 var(--space-4);cursor:pointer;
  display:inline-flex;align-items:center;gap:6px;
  font:var(--weight-semibold) var(--text-sm)/1 var(--font-body);color:var(--text-inverse);
  background:linear-gradient(180deg,var(--brand-400) 0%,var(--brand-500) 55%,var(--brand-600) 100%);
  border:1px solid var(--brand-600);border-radius:0 var(--radius-sm) var(--radius-sm) 0;
  box-shadow:var(--bevel-on-dark);transition:var(--transition-control)}
.site-search button:active{transform:var(--press-scale)}

/* ============================= Przyciski ================================= */
.btn{display:inline-flex;align-items:center;justify-content:center;gap:8px;
  height:var(--control-h-md);padding:0 18px;cursor:pointer;white-space:nowrap;
  font:var(--weight-semibold) var(--text-sm)/1 var(--font-body);letter-spacing:.01em;
  border-radius:var(--radius-sm);text-decoration:none;transition:var(--transition-control)}
.btn:hover{text-decoration:none}
.btn:active{transform:var(--press-scale)}
.btn[disabled]{opacity:.45;cursor:not-allowed}

.btn--primary{color:var(--text-inverse);border:1px solid var(--brand-600);
  background:linear-gradient(180deg,var(--brand-400) 0%,var(--brand-500) 55%,var(--brand-600) 100%);
  box-shadow:var(--bevel-on-dark),var(--shadow-brand)}
.btn--primary:hover{color:var(--text-inverse);
  background:linear-gradient(180deg,var(--brand-500) 0%,var(--brand-600) 55%,var(--brand-700) 100%)}

.btn--secondary{background:var(--metal-face);color:var(--text-strong);
  border:1px solid var(--border-strong);box-shadow:var(--bevel-light),var(--shadow-xs)}
.btn--secondary:hover{color:var(--text-strong);border-color:var(--steel-400)}

.btn--dark{background:var(--metal-dark);color:var(--text-inverse);
  border:1px solid var(--steel-950);box-shadow:var(--bevel-on-dark),var(--shadow-md)}
.btn--dark:hover{color:var(--text-inverse)}

.btn--ghost{background:transparent;color:var(--text-body);border:1px solid transparent;box-shadow:none}
.btn--ghost:hover{color:var(--text-strong);background:var(--surface-sunken)}

.btn--sm{height:var(--control-h-sm);padding:0 12px;font:var(--weight-semibold) var(--text-xs)/1 var(--font-body);gap:6px}
.btn--lg{height:var(--control-h-lg);padding:0 26px;font:var(--weight-semibold) var(--text-base)/1 var(--font-body);gap:10px}
.btn--block{display:flex;width:100%}

/* ============================ Plakietki ================================== */
.badge{display:inline-flex;align-items:center;gap:4px;padding:3px 7px;border-radius:var(--radius-xs);
  font:var(--weight-semibold) var(--text-3xs)/1.1 var(--font-body);letter-spacing:var(--tracking-wide);
  text-transform:uppercase;white-space:nowrap}
.badge--neutral{background:var(--steel-100);color:var(--steel-700)}
.badge--brand{background:var(--brand-500);color:#fff;box-shadow:var(--bevel-on-dark)}
.badge--dark{background:var(--surface-dark);color:var(--steel-25);box-shadow:var(--bevel-on-dark)}
.badge--warning{background:var(--amber-50);color:var(--amber-500)}
.badge--success{background:var(--green-50);color:var(--green-500)}

.chip{display:inline-flex;align-items:center;gap:6px;height:28px;padding:0 10px;
  border-radius:var(--radius-pill);background:var(--surface-sunken);
  border:1px solid var(--border-default);color:var(--text-body);
  font:var(--weight-medium) var(--text-xs)/1 var(--font-body);text-decoration:none;
  white-space:nowrap}
.chip[aria-current="true"]{background:var(--surface-dark);border-color:var(--surface-dark);
  color:var(--steel-0);font-weight:var(--weight-semibold)}
.chip:hover{border-color:var(--border-strong);color:var(--text-strong);text-decoration:none}

/* ========================== Blok ceny (§2) =============================== */
/* Cztery przypadki z kontraktu §1.1 rozstrzyga silnik; tu tylko prezentacja.
   Cena sprzedaży pokazuje się zawsze — nie ma reguły, która ją ukrywa. */
.price{display:flex;flex-direction:column;gap:2px}
.price__catalog{display:flex;align-items:baseline;gap:8px;font-size:var(--text-xs);color:var(--price-catalog)}
.price__catalog s{font-family:var(--font-body)}
.price__catalog-label{letter-spacing:var(--tracking-caps);text-transform:uppercase;
  font-weight:var(--weight-semibold);font-size:var(--text-3xs)}
.price__row{display:flex;align-items:baseline;gap:10px;flex-wrap:wrap}
.price__current{font:var(--type-price);color:var(--price-current);letter-spacing:var(--tracking-tight)}
.price__discount{font:var(--weight-bold) var(--text-xs)/1 var(--font-body);color:#fff;
  background:var(--brand-500);padding:4px 7px;border-radius:var(--radius-xs);box-shadow:var(--bevel-on-dark)}
.price__per-unit{font:var(--type-mono);color:var(--text-muted)}
.price__omnibus{font-size:var(--text-2xs);color:var(--price-omnibus);font-family:var(--font-body)}

.price--sm .price__current{font:var(--weight-bold) var(--text-md)/1.1 var(--font-display)}
.price--sm .price__catalog{font-size:var(--text-2xs)}
.price--lg .price__current{font:var(--weight-bold) var(--text-3xl)/1.05 var(--font-display)}
.price--lg .price__catalog{font-size:var(--text-sm)}

.savings{color:var(--price-savings);font:var(--weight-semibold) var(--text-xs)/1.4 var(--font-body)}

/* ========================== Dostępność =================================== */
.stock{display:inline-flex;align-items:center;gap:6px;font:var(--weight-medium) var(--text-xs)/1 var(--font-body)}
.stock::before{content:"";width:7px;height:7px;border-radius:var(--radius-pill);background:currentColor}
.stock--in{color:var(--stock-in)}
.stock--low{color:var(--stock-low)}
.stock--out{color:var(--stock-out)}
/* Towar od dostawcy: do kupienia, ale nie „od ręki". Kropka pusta w środku —
   zielona plamka obiecywałaby wysyłkę w 24 h, szara sugerowałaby brak. */
.stock--supplier{color:var(--stock-low)}
.stock--supplier::before{background:transparent;box-shadow:inset 0 0 0 2px currentColor}
/* Na kafelku listingu długi napis nie może rozpychać siatki. */
.card__foot .stock--supplier{font-size:var(--text-2xs);align-items:flex-start}
.card__foot .stock--supplier::before{margin-top:4px;flex:none}

/* ========================= Kafelek produktu ============================== */
.card{display:flex;flex-direction:column;gap:10px;height:100%;
  background:var(--surface-card);border:1px solid var(--border-default);
  border-radius:var(--radius-lg);padding:var(--card-pad);box-shadow:var(--shadow-xs);
  transition:box-shadow var(--dur-base) var(--ease-out),transform var(--dur-base) var(--ease-out),
             border-color var(--dur-fast) var(--ease-out)}
.card:hover{box-shadow:var(--shadow-lg);transform:var(--lift-hover);border-color:var(--border-strong)}
.card__link{display:block;color:inherit;text-decoration:none}
.card__link:hover{text-decoration:none;color:inherit}

/* Kadr zdjęcia: przedmiot na jasnym tle, podcień pod spodem. */
.card__thumb{position:relative;aspect-ratio:1;display:grid;place-items:center;
  background:var(--surface-sunken);border-radius:var(--radius-md);overflow:hidden}
.card__thumb img{width:100%;height:100%;object-fit:contain;mix-blend-mode:multiply;padding:var(--space-3)}
.card__badges{position:absolute;top:8px;left:8px;display:flex;flex-direction:column;gap:4px;align-items:flex-start}

.card__meta{display:flex;align-items:center;justify-content:space-between;gap:8px}
.card__brand{font:var(--weight-semibold) var(--text-2xs)/1 var(--font-body);
  letter-spacing:var(--tracking-wide);text-transform:uppercase;color:var(--text-muted)}
.card__sku{font:var(--type-mono);color:var(--steel-400)}
.card__name{font:var(--weight-semibold) var(--text-sm)/1.35 var(--font-body);
  color:var(--text-strong);text-wrap:pretty;letter-spacing:normal}
.card__foot{margin-top:auto;display:flex;flex-direction:column;gap:10px}
/* Przycisk w kafelku przechodzi z secondary na primary dopiero przy najechaniu. */
.card:hover .card__cta{color:var(--text-inverse);border-color:var(--brand-600);
  background:linear-gradient(180deg,var(--brand-400) 0%,var(--brand-500) 55%,var(--brand-600) 100%);
  box-shadow:var(--bevel-on-dark),var(--shadow-brand)}

.rating{display:inline-flex;align-items:center;gap:4px;font:var(--type-mono);color:var(--text-muted)}
.rating__stars{color:var(--amber-500);display:inline-flex;gap:1px}

/* ============================== Siatki =================================== */
/* Kafelek ma trzymać stałą szerokość ~300 px, a liczba kolumn ma się do niej
   dopasować. Sztywne `repeat(3,1fr)` dawało kafelki po 420 px, gdy kolumna
   filtrów była pusta, i po 320 px, gdy się pojawiała — ten sam listing
   wyglądałby inaczej zależnie od tego, czy produkty mają już parametry. */
.grid-products{display:grid;gap:var(--grid-gutter);
  grid-template-columns:repeat(auto-fill,minmax(min(268px,100%),1fr))}
.grid-products--5{grid-template-columns:repeat(auto-fill,minmax(min(228px,100%),1fr))}
.grid-categories{display:grid;gap:var(--grid-gutter);
  grid-template-columns:repeat(auto-fill,minmax(min(240px,100%),1fr))}

/* ========================== Nagłówek sekcji ============================== */
.section{display:flex;flex-direction:column;gap:var(--space-5)}
.section__head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-4)}
.section__title{font:var(--type-h2);position:relative;padding-left:var(--space-3)}
.section__title::before{content:"";position:absolute;left:0;top:.15em;bottom:.15em;width:3px;
  border-radius:var(--radius-pill);background:var(--brand-500)}
.section__more{font:var(--weight-semibold) var(--text-sm)/1 var(--font-body);
  display:inline-flex;align-items:center;gap:6px}

/* ============================ Strona główna ============================== */
.hero{background:var(--surface-dark);background-image:var(--spotlight);color:var(--steel-25);
  border-radius:var(--radius-xl);padding:clamp(28px,7vw,64px) clamp(18px,5vw,48px);
  display:flex;flex-direction:column;gap:var(--space-5);align-items:flex-start}
/* „hurtownianozy.pl" to jeden nierozdzielny wyraz — kropka w środku nie jest
   miejscem łamania. Stopień pisma skaluje się tokenem, a break-word jest siatką
   bezpieczeństwa na wypadek nazwy dłuższej niż ta. */
.hero h1{font:var(--type-hero);color:var(--steel-0);max-width:20ch;overflow-wrap:break-word}
.hero p{color:var(--steel-400);max-width:60ch}
.hero__eyebrow{font:var(--weight-semibold) var(--text-2xs)/1 var(--font-body);
  letter-spacing:var(--tracking-caps);text-transform:uppercase;color:var(--brand-400)}

.usp-bar{display:grid;grid-template-columns:repeat(3,1fr);gap:var(--grid-gutter)}
.usp{display:flex;gap:var(--space-3);align-items:flex-start;padding:var(--space-4);
  background:var(--surface-card);border:1px solid var(--border-default);border-radius:var(--radius-lg);
  box-shadow:var(--shadow-xs)}
.usp__icon{color:var(--brand-500)}
.usp__title{font:var(--weight-semibold) var(--text-sm)/1.3 var(--font-body);color:var(--text-strong)}
.usp__text{font:var(--type-small);color:var(--text-muted)}
@media (max-width:760px){.usp-bar{grid-template-columns:1fr}}

.cat-tile{display:flex;flex-direction:column;gap:var(--space-2);padding:var(--space-4);
  background:var(--surface-card);border:1px solid var(--border-default);border-radius:var(--radius-lg);
  box-shadow:var(--shadow-xs);color:inherit;text-decoration:none;transition:var(--transition-control)}
.cat-tile:hover{text-decoration:none;color:inherit;border-color:var(--border-strong);
  box-shadow:var(--shadow-md);transform:var(--lift-hover)}
.cat-tile__name{font:var(--weight-semibold) var(--text-sm)/1.3 var(--font-body);color:var(--text-strong)}
.cat-tile__count{font:var(--type-mono);color:var(--text-muted)}

/* ============================== Listing ================================== */
/* Domyślnie jedna kolumna na pełną szerokość. Kolumnę filtrów rezerwujemy
   dopiero wtedy, gdy filtry naprawdę są — przy pustych atrybutach produktów
   `filters.njk` nie renderuje niczego i listing zostawał w wąskim pasie 264 px,
   z pustą prawą połową strony.
   minmax(0,1fr) zamiast 1fr: bez tego siatka kafelków rozpycha kolumnę
   ponad dostępną szerokość. */
.listing{display:grid;grid-template-columns:minmax(0,1fr);gap:var(--space-8);align-items:start}
.listing:has(> .listing__aside){grid-template-columns:264px minmax(0,1fr)}
@media (max-width:960px){
  .listing,.listing:has(> .listing__aside){grid-template-columns:minmax(0,1fr)}
}
/* Kolumna filtrów zostaje na swoim miejscu u góry listingu i przewija się
   razem ze stroną — wcześniej `position:sticky` ciągnęło ją za widokiem
   i menu kategorii wędrowało w dół razem z przewijaniem. */
.listing__aside{display:flex;flex-direction:column;gap:var(--space-5)}
/* Ten sam kontener niesie odstępy między grupami na desktopie i przewijanie
   w szufladzie na telefonie — jedne znaczniki, dwa układy. */
.listing__aside-scroll{display:flex;flex-direction:column;gap:var(--space-5)}
.listing__main{display:flex;flex-direction:column;gap:var(--space-5)}
.listing__bar{display:flex;align-items:center;justify-content:space-between;gap:var(--space-4);flex-wrap:wrap}
.listing__count{font:var(--type-small);color:var(--text-muted)}

.filter-group{border:1px solid var(--border-default);border-radius:var(--radius-lg);
  background:var(--surface-card);padding:var(--space-4);display:flex;flex-direction:column;gap:var(--space-3)}
.filter-group__title{font:var(--weight-semibold) var(--text-xs)/1 var(--font-body);
  letter-spacing:var(--tracking-wide);text-transform:uppercase;color:var(--text-muted)}
.filter-group__option{display:flex;align-items:center;justify-content:space-between;gap:var(--space-2);
  font:var(--type-small);color:var(--text-body);padding-block:2px}
.filter-group__option a{color:inherit}
.filter-group__option a.is-selected{font-weight:var(--weight-semibold);color:var(--text-strong)}
.filter-group__count{font:var(--type-mono);color:var(--steel-400)}
.filter-chips{display:flex;flex-wrap:wrap;gap:var(--space-2)}
/* Słowniki z Media Jet są otwarte — „Stal" ma 190 wartości. Pierwsza dziesiątka
   pokrywa większość wyborów, reszta czeka pod <details>, żeby kolumna filtrów
   nie była trzy razy dłuższa niż listing, który filtruje. */
.filter-more > summary{cursor:pointer;font:var(--weight-medium) var(--text-xs)/1 var(--font-body);
  color:var(--brand-600);padding-block:var(--space-2)}
.filter-more[open] > summary{color:var(--text-muted)}

.sorting{display:inline-flex;align-items:center;gap:var(--space-2);font:var(--type-small)}
.sorting select{height:var(--control-h-sm);padding:0 var(--space-3);font:var(--type-small);
  color:var(--text-strong);background:var(--surface-card);border:1px solid var(--border-strong);
  border-radius:var(--radius-sm);box-shadow:var(--shadow-inset-well)}
/* Pięć chipów sortowania to 534 px — półtora ekranu telefonu. Zawijanie ich
   w dwa rzędy rozpycha pasek nad listingiem w pionie, więc zamiast tego jadą
   poziomym pasem, tak jak w każdej aplikacji sklepowej. Przewijanie zatrzymuje
   się na krawędzi chipa, a nie w połowie słowa. */
@media (max-width:960px){
  .sorting{display:flex;flex:1 1 100%;min-width:0;
    overflow-x:auto;overscroll-behavior-x:contain;scroll-snap-type:x proximity;
    scrollbar-width:none;-webkit-overflow-scrolling:touch;
    padding-bottom:2px;margin-inline:calc(var(--container-pad) * -1);
    padding-inline:var(--container-pad)}
  .sorting::-webkit-scrollbar{display:none}
  .sorting .chip{flex:none;scroll-snap-align:start}
  /* Ikona suwaków dubluje tę na przycisku „Filtry" obok — na telefonie
     zabiera 24 px i nic nie wnosi. */
  .sorting > .ico{display:none}
}

.pagination{display:flex;gap:var(--space-1);align-items:center;justify-content:center;flex-wrap:wrap;
  padding-top:var(--space-4)}
.pagination a,.pagination span{min-width:36px;height:36px;padding:0 var(--space-2);
  display:inline-flex;align-items:center;justify-content:center;border-radius:var(--radius-sm);
  border:1px solid var(--border-default);background:var(--surface-card);color:var(--text-body);
  font:var(--weight-medium) var(--text-sm)/1 var(--font-body);text-decoration:none}
.pagination a:hover{border-color:var(--border-strong);color:var(--text-strong);text-decoration:none}
.pagination [aria-current="page"]{background:var(--surface-dark);border-color:var(--surface-dark);
  color:var(--steel-0);font-weight:var(--weight-semibold)}

.breadcrumbs{font:var(--type-small);color:var(--text-muted)}
.breadcrumbs ol{display:flex;flex-wrap:wrap;gap:var(--space-2);align-items:center}
.breadcrumbs li:not(:last-child)::after{content:"·";margin-left:var(--space-2);color:var(--steel-300)}
.breadcrumbs a{color:var(--text-muted)}
.breadcrumbs a:hover{color:var(--text-brand)}

/* =========================== Karta produktu ============================== */
.product{display:grid;grid-template-columns:minmax(0,1.1fr) minmax(0,1fr);gap:var(--space-10);
  align-items:start}
@media (max-width:960px){.product{grid-template-columns:1fr}}
.product__gallery{display:flex;flex-direction:column;gap:var(--space-3)}
/* Zdjęcie główne wypełnia całą szerokość kolumny i kończy się dokładnie tam,
   gdzie pasek miniatur — stąd zero paddingu na obrazku. Ramka rysuje kadr,
   `contain` pilnuje proporcji, więc zdjęcie panoramiczne dostaje pas u góry
   i u dołu zamiast być przycięte. */
.product__figure{position:relative;aspect-ratio:1;display:grid;place-items:center;
  background:var(--surface-sunken);border:1px solid var(--border-default);
  border-radius:var(--radius-lg);overflow:hidden;cursor:zoom-in}
.product__figure img{width:100%;height:100%;object-fit:contain;mix-blend-mode:multiply}
/* Lupa pojawia się dopiero, gdy skrypt galerii przejmie kliknięcie — bez
   JavaScriptu link prowadzi wprost do pliku i obietnica powiększenia w miejscu
   byłaby nieprawdziwa. */
.product__zoom{position:absolute;right:var(--space-3);bottom:var(--space-3);display:none;
  place-items:center;width:36px;height:36px;border-radius:var(--radius-pill);
  background:var(--surface-card);border:1px solid var(--border-default);
  box-shadow:var(--shadow-sm);color:var(--text-muted);transition:color var(--dur-fast) var(--ease-out)}
.js-gallery .product__zoom{display:grid}
.product__figure:hover .product__zoom{color:var(--text-brand)}

.product__thumbs{display:grid;grid-template-columns:repeat(6,1fr);gap:var(--space-2)}
.product__thumb{display:block;aspect-ratio:1;background:var(--surface-sunken);
  border:1px solid var(--border-default);border-radius:var(--radius-md);overflow:hidden;
  padding:var(--space-1);transition:border-color var(--dur-fast) var(--ease-out)}
.product__thumb img{width:100%;height:100%;object-fit:contain;mix-blend-mode:multiply}
.product__thumb:hover{border-color:var(--border-strong)}
.product__thumb.is-active{border-color:var(--brand-500);box-shadow:inset 0 0 0 1px var(--brand-500)}
@media (max-width:560px){.product__thumbs{grid-template-columns:repeat(5,1fr)}}

/* ------------------------------- Lightbox -------------------------------- */
/* Pełnoekranowa galeria z powiększaniem — układ i gesty jak w lightboxie
   ostrenoze.pl: licznik w lewym górnym rogu, zamknięcie w prawym, strzałki
   przy krawędziach ekranu, pasek miniatur na dole. <dialog> zamiast zwykłej
   nakładki daje uwięzienie focusu i zamykanie Escape'em bez linijki JS-a. */
.lightbox{width:100vw;max-width:100vw;height:100dvh;max-height:100dvh;margin:0;padding:0;
  border:0;background:rgb(0 0 0 / .95);color:#fff;overflow:hidden;
  -webkit-user-select:none;user-select:none}
.lightbox::backdrop{background:rgb(0 0 0 / .95)}
body.lightbox-open{overflow:hidden}

/* Górny pasek leży na zdjęciu, więc dostaje własny cień pod spodem — na jasnej
   fotografii sam biały tekst byłby nieczytelny. */
.lightbox__topbar{position:absolute;inset:0 0 auto 0;z-index:2;
  display:flex;align-items:center;justify-content:space-between;
  padding:var(--space-3) var(--space-4);
  background:linear-gradient(to bottom,rgb(0 0 0 / .5),transparent)}
.lightbox__counter{font:var(--type-mono);color:rgb(255 255 255 / .9)}
.lightbox__close{display:grid;place-items:center;width:40px;height:40px;padding:0;
  border:0;border-radius:var(--radius-pill);background:none;color:#fff;
  cursor:pointer;opacity:.8;transition:opacity var(--dur-fast) var(--ease-out)}
.lightbox__close:hover{opacity:1;background:rgb(255 255 255 / .12)}

/* `touch-action:none` oddaje skryptowi wszystkie gesty — bez tego przeglądarka
   przechwytuje szczypanie i przewijanie, zanim dojdzie do naszych obsług. */
.lightbox__stage{position:absolute;inset:0;display:grid;place-items:center;
  overflow:hidden;touch-action:none}
.lightbox__img{max-width:92vw;max-height:82dvh;width:auto;height:auto;object-fit:contain;
  will-change:transform;-webkit-user-drag:none}
.lightbox__img.is-zoomed{cursor:grab}
.lightbox__img.is-zoomed:active{cursor:grabbing}

.lightbox__nav{position:absolute;top:50%;transform:translateY(-50%);z-index:2;
  display:grid;place-items:center;width:48px;height:48px;
  border:1px solid rgb(255 255 255 / .2);border-radius:var(--radius-pill);
  background:rgb(255 255 255 / .1);color:#fff;cursor:pointer;
  transition:background var(--dur-fast) var(--ease-out)}
.lightbox__nav:hover{background:rgb(255 255 255 / .25)}
.lightbox__nav--prev{left:var(--space-4)}
.lightbox__nav--next{right:var(--space-4)}

/* `safe center` zamiast `center`: przy kilkunastu zdjęciach pasek jest szerszy
   od ekranu, a wyśrodkowana zawartość ucieka wtedy poza początek kontenera
   i pierwszej miniatury nie da się doscrollować. */
.lightbox__thumbs{position:absolute;inset:auto 0 0 0;z-index:2;
  display:flex;align-items:center;justify-content:safe center;gap:var(--space-2);
  padding:var(--space-3) var(--space-4);overflow-x:auto;
  background:linear-gradient(to top,rgb(0 0 0 / .6),transparent)}
.lightbox__thumb{flex:none;width:56px;height:56px;padding:0;overflow:hidden;
  border:2px solid transparent;border-radius:var(--radius-sm);
  background:rgb(255 255 255 / .06);cursor:pointer;opacity:.5;
  transition:opacity var(--dur-fast) var(--ease-out),border-color var(--dur-fast) var(--ease-out)}
.lightbox__thumb:hover{opacity:.85}
.lightbox__thumb.is-active{opacity:1;border-color:#fff}
.lightbox__thumb img{width:100%;height:100%;object-fit:cover}

/* Podpowiedź o sposobie powiększania — pojawia się raz i sama gaśnie. */
.lightbox__hint{position:absolute;left:50%;bottom:104px;z-index:3;
  transform:translateX(-50%);padding:var(--space-2) var(--space-4);
  border-radius:var(--radius-pill);background:rgb(0 0 0 / .6);
  color:rgb(255 255 255 / .9);font:var(--type-small);white-space:nowrap;
  pointer-events:none;opacity:0;transition:opacity .5s var(--ease-out)}
.lightbox__hint.is-visible{opacity:1}

/* Na dotyku zdjęcia zmienia się machnięciem, więc strzałki tylko zabierałyby
   miejsce nad paskiem miniatur. */
@media (max-width:768px){
  .lightbox__nav{display:none}
  .lightbox__img{max-width:100vw;max-height:78dvh}
  .lightbox__thumb{width:44px;height:44px}
  .lightbox__hint{bottom:88px}
}
@media (prefers-reduced-motion:reduce){
  .lightbox__hint{transition:none}
}

.product__aside{display:flex;flex-direction:column;gap:var(--space-4)}
/* Główne cechy pod boksem z ceną. Ikona nie zawija się razem z tekstem
   (`flex:none`), a punkt wielowierszowy trzyma wyrównanie do lewej krawędzi
   tekstu, nie do ikony. */
.product__usp{display:flex;flex-direction:column;gap:var(--space-2)}
.product__usp li{display:flex;gap:var(--space-2);align-items:flex-start;font:var(--type-small)}
.product__usp .ico{flex:none;margin-top:2px}
.product__usp b{font-weight:var(--weight-semibold);color:var(--text-strong)}
.product__brand{font:var(--weight-semibold) var(--text-2xs)/1 var(--font-body);
  letter-spacing:var(--tracking-wide);text-transform:uppercase;color:var(--text-muted)}
.product__title{font:var(--type-h1);font-size:var(--text-2xl)}
.product__sku{font:var(--type-mono);color:var(--text-muted)}
.product__buy{display:flex;flex-direction:column;gap:var(--space-3);padding:var(--space-4);
  background:var(--surface-card);border:1px solid var(--border-default);border-radius:var(--radius-lg);
  box-shadow:var(--shadow-sm)}
/* Stepper 66 px + „Dodaj do koszyka" z `white-space:nowrap` to 291 px minimum,
   więc przy kolumnie 312 px cały blok zakupu rozpychał siatkę karty produktu.
   Przycisk dostaje prawo zejść pod stepper zamiast rozpychać stronę. */
.product__buy-row{display:flex;gap:var(--space-3);align-items:center;flex-wrap:wrap}
.product__buy-row .btn{flex:1 1 180px}
.product__section{display:flex;flex-direction:column;gap:var(--space-4)}
.product__section h2{font:var(--type-h2)}
.prose{font:var(--type-body);color:var(--text-body);max-width:75ch}
.prose h2,.prose h3{margin-top:var(--space-6);margin-bottom:var(--space-2)}
/* Śródtytuły opisu produktu schodzą o stopień pod „Opis produktu". Bez tego
   brały domyślne 24 px bold przeglądarki, czyli tyle samo co tytuł sekcji nad
   nimi, tylko grubszym krojem — pierwszy śródtytuł czytał się jako ważniejszy
   od nagłówka, pod który należy. Reguła jest zawężona do karty produktu:
   opis kategorii czy wpis bloga stoją bez tytułu sekcji nad sobą i tam h2
   ma prawo być pełnowymiarowe. */
.product-detail__desc .prose h2{font:var(--type-h3)}
.product-detail__desc .prose h3{font:var(--weight-semibold) var(--text-base)/var(--leading-snug) var(--font-display)}
/* Opis zaczyna się śródtytułem, tabela obok zaczyna się nagłówkiem grupy.
   Górny margines pierwszego śródtytułu zsuwał oba bloki względem siebie. */
.prose > :first-child{margin-top:0}
.prose p{margin-bottom:var(--space-3)}
.prose ul{list-style:disc;padding-left:var(--space-6);margin-bottom:var(--space-3)}
.prose > :last-child{margin-bottom:0}

/* Ilość: stepper z systemu projektowego, w wersji bez JavaScriptu. */
.qty{display:inline-flex;align-items:center;height:var(--control-h-md);
  border:1px solid var(--border-strong);border-radius:var(--radius-sm);
  background:var(--surface-card);box-shadow:var(--shadow-inset-well);overflow:hidden}
.qty input{width:64px;height:100%;border:0;text-align:center;background:transparent;
  font:var(--weight-semibold) var(--text-sm)/1 var(--font-mono);color:var(--text-strong)}
.qty input:focus{outline:none}

/* ===================== Parametry obok opisu (desktop) ==================== */
/* Dwa bloki o różnych apetytach na szerokość. Tabela parametrów to nazwa plus
   krótka wartość — na pełnych 1232 px za „56 HRC" zostawało 600 px pustki.
   Proza ma twardą miarę 75ch i na pełnej szerokości kończyła się w 2/3 wiersza.
   Postawione obok siebie zasypują nawzajem swoje pustki, a karta produktu
   skraca się o pełny ekran przewijania.
   Kolumna opisu wypada ~712 px, czyli dokładnie tyle, ile zajmuje jego 75ch —
   proza wypełnia swoją kolumnę co do piksela, nic nie trzeba dociskać. */
.product-detail{display:grid;grid-template-columns:minmax(0,1fr) minmax(340px,480px);
  gap:var(--space-10);align-items:start}
/* Opis stoi w DOM po parametrach (na telefonie specyfikacja ma być pierwsza),
   więc na desktopie wraca na lewo jawnym przypisaniem. Bez `grid-row` siatka
   nie cofa się do wiersza wyżej i opis spadłby pod tabelę. */
.product-detail__desc{grid-column:1;grid-row:1}
.product-detail__spec{grid-column:2;grid-row:1}
/* Produkt bez opisu: sama tabela nie ma powodu zajmować 1232 px, więc zostaje
   w swojej kolumnie — tyle że po lewej, żeby nie wisiała przy prawej krawędzi. */
.product-detail--spec-only{grid-template-columns:minmax(340px,480px) minmax(0,1fr)}
.product-detail--spec-only .product-detail__spec{grid-column:1}
@media (max-width:960px){
  .product-detail{grid-template-columns:1fr;gap:var(--section-gap)}
  .product-detail__desc,.product-detail__spec{grid-column:1;grid-row:auto}
}

/* ========================= Tabela parametrów ============================= */
/* §10.2 — parametry w <table> z nagłówkami; parser czyta to jednoznacznie. */
/* Wartości parametrów przychodzą ze słowników Media Jet i nikt nie obiecał,
   że będą krótkie. Dziś najdłuższa („milibdenowo-wanadowa") łamie się na
   dywizie i tabela się mieści; pierwsza dłuższa bez dywizu rozepchnęłaby stronę,
   więc tabela dostaje własne przewijanie zamiast wypychać dokument. */
.attributes-wrap{width:100%;overflow-x:auto;overscroll-behavior-x:contain}
.attributes{width:100%;border:1px solid var(--border-default);border-radius:var(--radius-lg);
  overflow:hidden;background:var(--surface-card)}
.attributes th,.attributes td{padding:var(--space-2) var(--space-4);text-align:left;
  border-bottom:1px solid var(--border-subtle);font:var(--type-small)}
/* Nagłówek grupy zastąpił <caption> osobnej tabeli — wygląda tak samo, ale jest
   wierszem wewnątrz jednej karty, więc grupy nie rozpadają się na sześć pudełek. */
.attributes__group th{padding:var(--space-2) var(--space-4);
  font:var(--weight-semibold) var(--text-2xs)/1.4 var(--font-body);
  letter-spacing:var(--tracking-wide);text-transform:uppercase;color:var(--text-muted);
  background:var(--surface-sunken);border-top:1px solid var(--border-default);
  border-bottom:1px solid var(--border-default);width:auto}
.attributes tbody:first-of-type .attributes__group th{border-top:0}
.attributes th[scope="row"]{font-weight:var(--weight-medium);color:var(--text-body);width:44%}
.attributes td{font-family:var(--font-mono);color:var(--text-strong)}
.attributes tbody:last-of-type tr:last-child th,
.attributes tbody:last-of-type tr:last-child td{border-bottom:0}

/* ================================ FAQ ==================================== */
.faq{display:flex;flex-direction:column;gap:var(--space-2)}
.faq__item{border:1px solid var(--border-default);border-radius:var(--radius-md);
  background:var(--surface-card);padding:var(--space-4)}
.faq__q{font:var(--weight-semibold) var(--text-sm)/1.35 var(--font-body);color:var(--text-strong);
  margin-bottom:var(--space-2)}
.faq__a{font:var(--type-small);color:var(--text-body)}

/* =============================== Koszyk ================================== */
.cart{display:grid;grid-template-columns:minmax(0,1fr) 340px;gap:var(--space-8);align-items:start}
@media (max-width:960px){.cart{grid-template-columns:1fr}}
.cart__lines{display:flex;flex-direction:column;gap:var(--space-3)}
/* Kolumna `auto` z prawej niesie napis „rabat ilościowy na 1 szt. po 115,50 zł",
   czyli 247 px treści. Przy `1fr` bez dolnej granicy algorytm siatki oddawał jej
   całą wolną przestrzeń i środkowa kolumna schodziła do zera — nazwa, cena
   i stepper lądowały jedno pod drugim, literami na cenie z prawej.
   `minmax(140px,1fr)` daje środkowi podłogę, poniżej której nie zejdzie. */
.cart-line{display:grid;grid-template-columns:88px minmax(140px,1fr) auto;gap:var(--space-4);
  align-items:center;
  padding:var(--space-4);background:var(--surface-card);border:1px solid var(--border-default);
  border-radius:var(--radius-lg);box-shadow:var(--shadow-xs)}
/* Układ telefonowy stoi niżej, za resztą reguł `.cart-line__*` — inaczej
   nadpisywałyby go deklaracje z dalszej części pliku. */
.cart-line__thumb{position:relative;aspect-ratio:1;background:var(--surface-sunken);
  border-radius:var(--radius-md);display:grid;place-items:center;overflow:hidden}
.cart-line__thumb img{width:100%;height:100%;object-fit:contain;padding:var(--space-2);mix-blend-mode:multiply}
.cart-line__body{display:flex;flex-direction:column;gap:var(--space-2);min-width:0}
.cart-line__name{font:var(--weight-semibold) var(--text-sm)/1.35 var(--font-body);color:var(--text-strong)}
.cart-line__controls{display:flex;align-items:center;gap:var(--space-3);flex-wrap:wrap}
.cart-line__right{display:flex;flex-direction:column;align-items:flex-end;gap:var(--space-1);text-align:right}
.cart-line__total{font:var(--weight-bold) var(--text-md)/1.1 var(--font-display);color:var(--text-strong)}
.cart-line__remove{background:none;border:0;cursor:pointer;color:var(--text-muted);
  display:inline-flex;align-items:center;gap:4px;font:var(--type-small);padding:0}
.cart-line__remove:hover{color:var(--red-500)}

/* Na telefonie trzy kolumny nie mają prawa się zmieścić: sama miniatura,
   stepper i cena zjadają całą szerokość, a na nazwę produktu zostaje zero.
   Podsumowanie wiersza schodzi więc pod spód, oddzielone kreską, i zostaje
   dosunięte do prawej — tam, gdzie oko szuka kwoty. */
@media (max-width:640px){
  .cart-line{grid-template-columns:72px minmax(0,1fr);gap:var(--space-3);align-items:start}
  .cart-line__right{grid-column:1/-1;padding-top:var(--space-3);
    border-top:1px solid var(--border-subtle)}
}

.cart__summary{position:sticky;top:var(--space-4);display:flex;flex-direction:column;gap:var(--space-3);
  padding:var(--space-5);background:var(--surface-card);border:1px solid var(--border-default);
  border-radius:var(--radius-lg);box-shadow:var(--shadow-sm)}
.cart__summary h2{font:var(--type-h3)}
.cart__row{display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-4);
  font:var(--type-small)}
.cart__row--total{padding-top:var(--space-3);border-top:1px solid var(--border-default);
  font:var(--weight-bold) var(--text-lg)/1.2 var(--font-display);color:var(--text-strong)}
.cart__empty{display:flex;flex-direction:column;gap:var(--space-4);align-items:flex-start;
  padding:var(--space-12);background:var(--surface-sunken);border-radius:var(--radius-lg)}

/* Rabat ilościowy §2.5 — komunikat progu i oznaczenie objętych sztuk. */
.promo-hint{display:flex;align-items:center;gap:var(--space-2);padding:var(--space-3) var(--space-4);
  background:var(--surface-brand-soft);border:1px solid var(--brand-200);border-radius:var(--radius-md);
  color:var(--brand-700);font:var(--weight-medium) var(--text-sm)/1.4 var(--font-body)}
.promo-hint .ico{color:var(--brand-500)}
.promo{color:var(--price-discount);font:var(--weight-semibold) var(--text-xs)/1.4 var(--font-body)}

/* =============================== Alerty ================================== */
.alerts{display:flex;flex-direction:column;gap:var(--space-2)}
.alert{display:flex;align-items:flex-start;gap:var(--space-3);padding:var(--space-3) var(--space-4);
  border-radius:var(--radius-md);border:1px solid;font:var(--type-small)}
.alert--info{background:var(--blue-50);border-color:#C5D6EC;color:var(--blue-500)}
.alert--success{background:var(--green-50);border-color:#BFE0CB;color:var(--green-500)}
.alert--warning{background:var(--amber-50);border-color:#F0D9AE;color:var(--amber-500)}
.alert--error{background:var(--red-50);border-color:#F0C4C0;color:var(--red-500)}

/* =============================== Stopka ================================== */
.site-footer{margin-top:var(--section-gap);background:var(--surface-dark);color:var(--steel-400);
  background-image:var(--spotlight)}
.site-footer__inner{max-width:var(--container-max);margin:0 auto;padding:var(--space-12) var(--container-pad);
  display:grid;grid-template-columns:repeat(4,1fr);gap:var(--space-8)}
@media (max-width:760px){.site-footer__inner{grid-template-columns:repeat(2,1fr)}}
.site-footer h2{font:var(--weight-semibold) var(--text-2xs)/1 var(--font-body);
  letter-spacing:var(--tracking-caps);text-transform:uppercase;color:var(--steel-0);
  margin-bottom:var(--space-4)}
.site-footer a{color:var(--steel-400);font:var(--type-small)}
.site-footer a:hover{color:var(--brand-400)}
.site-footer li{padding-block:3px}
/* `height:30px` przy globalnym `max-width:100%` ścieskało znak w poziomie,
   gdy kolumna stopki była węższa niż 148 px. Limit na wysokość zamiast
   sztywnej wysokości zachowuje proporcje w obie strony. */
.site-footer__logo{filter:invert(1) brightness(1.6);height:auto;max-height:30px;
  width:auto;max-width:100%;margin-bottom:var(--space-4)}
.site-footer__bottom{border-top:1px solid var(--border-dark)}
.site-footer__bottom .container{padding-block:var(--space-4);display:flex;justify-content:space-between;
  gap:var(--space-4);flex-wrap:wrap;font-size:var(--text-2xs)}

/* ============================ Strony błędów ============================== */
.error-page{padding-block:var(--space-20);display:flex;flex-direction:column;gap:var(--space-5);
  align-items:flex-start;max-width:60ch}
.error-page__code{font:var(--type-hero);color:var(--brand-500)}

/* ===================== Szuflady (telefon, bez JS) ======================== */
/*
   Wzorzec zapożyczony z ostrenoze.pl, gdzie offcanvas z kategoriami i filtrami
   sprawdza się w praktyce — ale zbudowany inaczej. Tam otwiera go Bootstrap,
   a filtry są renderowane dwa razy: osobno do sidebara i osobno do szuflady.
   Tu jest jeden komplet znaczników i ukryty checkbox: stan trzyma przeglądarka,
   nie skrypt, więc szuflada działa też przy zablokowanym JavaScripcie.
*/
/* Checkbox zostaje w drzewie i jest osiągalny tabulatorem — spacja otwiera
   i zamyka szufladę. Gdyby dostał `hidden`, kliknięcie w etykietę nadal by
   działało, ale klawiatura straciłaby do niego dostęp. Widoczny znacznik
   fokusu przenosimy na etykietę, bo sam checkbox ma zerowy rozmiar. */
.drawer-toggle{position:absolute;width:1px;height:1px;opacity:0;margin:0}
.drawer-toggle:focus-visible + .site-header .burger,
.drawer-toggle:focus-visible + .listing .filters-open{box-shadow:var(--focus-ring)}

.burger{display:none;align-items:center;gap:8px;height:40px;padding:0 var(--space-3);
  cursor:pointer;user-select:none;border:1px solid var(--border-strong);
  border-radius:var(--radius-sm);background:var(--metal-face);box-shadow:var(--bevel-light),var(--shadow-xs);
  font:var(--weight-semibold) var(--text-xs)/1 var(--font-body);color:var(--text-strong)}
.burger:focus-visible{outline:none;box-shadow:var(--focus-ring)}

.drawer-scrim{display:none;position:fixed;inset:0;z-index:50;
  background:rgb(15 23 30 / .5);cursor:pointer}
.drawer{position:fixed;top:0;bottom:0;left:0;z-index:60;width:min(87vw,360px);
  display:none;flex-direction:column;background:var(--surface-card);
  box-shadow:var(--shadow-lg);transform:translateX(-100%);
  transition:transform .18s ease-out}
#menu-toggle:checked ~ .drawer-scrim,
#menu-toggle:checked ~ .drawer{display:flex}
#menu-toggle:checked ~ .drawer{transform:none}

.drawer__head{display:flex;align-items:center;justify-content:space-between;gap:var(--space-4);
  padding:var(--space-4);border-bottom:1px solid var(--border-default);flex:none}
.drawer__title{font:var(--type-h3);color:var(--text-strong)}
.drawer__close{display:grid;place-items:center;width:40px;height:40px;cursor:pointer;
  border-radius:var(--radius-sm);border:1px solid var(--border-default);background:var(--surface-sunken)}
.drawer__body{flex:1;overflow-y:auto;overscroll-behavior:contain;padding:var(--space-2) var(--space-4)}
.drawer__group{padding-block:var(--space-3);border-bottom:1px solid var(--border-subtle)}
.drawer__group:last-child{border-bottom:0}
.drawer__dept{display:flex;align-items:center;justify-content:space-between;gap:var(--space-3);
  padding-block:var(--space-2);
  font:var(--weight-bold) var(--text-base)/1.2 var(--font-display);color:var(--text-strong)}
.drawer__subs{display:grid;gap:1px;margin-top:var(--space-1)}
.drawer__sub{display:flex;align-items:center;justify-content:space-between;gap:var(--space-3);
  /* 44 px to najmniejszy cel, który da się trafić kciukiem bez celowania. */
  min-height:44px;padding:0 var(--space-2);border-radius:var(--radius-sm);
  font:var(--type-small);color:var(--text-body)}
.drawer__sub:hover,.drawer__sub[aria-current="page"]{background:var(--surface-sunken);
  color:var(--text-strong);text-decoration:none}
.drawer__count{font:var(--weight-medium) var(--text-2xs)/1 var(--font-mono);color:var(--text-muted)}
.drawer__foot{flex:none;display:flex;flex-wrap:wrap;gap:var(--space-3);
  padding:var(--space-4);border-top:1px solid var(--border-default);
  background:var(--surface-sunken);font:var(--type-small)}

/* Przycisk otwierający filtry — tylko tam, gdzie kolumna filtrów się chowa. */
.filters-open{display:none;align-items:center;gap:8px;height:var(--control-h-sm);padding:0 var(--space-4);
  cursor:pointer;user-select:none;border:1px solid var(--border-strong);border-radius:var(--radius-sm);
  background:var(--metal-face);box-shadow:var(--bevel-light),var(--shadow-xs);
  font:var(--weight-semibold) var(--text-xs)/1 var(--font-body);color:var(--text-strong)}
.filters-open:focus-visible{outline:none;box-shadow:var(--focus-ring)}
.drawer__head--filters,.drawer__foot--filters{display:none}

@media (max-width:960px){
  .burger{display:inline-flex}
  .main-nav{display:none}
  .filters-open{display:inline-flex}

  /* Cele dotyku. 28 px chipa i 32 px przycisku w kafelku trafia się palcem
     dopiero za drugim razem — 40 px to minimum, przy którym się nie celuje,
     a stronicowanie dostaje pełne 44 px, bo sąsiednie numery stoją tuż obok. */
  .chip{height:36px;padding:0 14px}
  .btn--sm{height:40px;padding:0 16px}
  .filters-open{height:40px}
  .pagination a,.pagination span{min-width:44px;height:44px}

  /* Belka nagłówka zostaje pod ręką przy przewijaniu długiego listingu —
     w sklepie z 1721 nożami to jest różnica między „wróć na górę" a jednym
     kliknięciem w kategorie. */
  .header-main{position:sticky;top:0;z-index:25;background:var(--surface-card);
    border-bottom:1px solid var(--border-subtle);gap:var(--space-3)}
  .header-main__logo{order:2;margin-inline:auto}
  .header-main__actions{order:3;margin-left:0}
  .burger{order:1}
  .site-search{order:4;flex-basis:100%}
  .burger__label{position:absolute;left:-9999px}
  .header-main__link{display:none}
  .cart-button__labels{display:none}

  /* Kolumna filtrów staje się szufladą od prawej. Znaczniki te same. */
  .listing__aside{position:fixed;top:0;bottom:0;right:0;left:auto;z-index:60;
    width:min(90vw,380px);display:none;flex-direction:column;gap:0;
    background:var(--surface-card);box-shadow:var(--shadow-lg);
    transform:translateX(100%);transition:transform .18s ease-out}
  .listing__aside-scroll{flex:1;overflow-y:auto;overscroll-behavior:contain;
    padding:var(--space-4);display:flex;flex-direction:column;gap:var(--space-4)}
  .drawer__head--filters{display:flex}
  .drawer__foot--filters{display:flex;justify-content:space-between;align-items:center}
  .drawer__foot--filters .btn{flex:1}
  #filters-toggle:checked ~ .listing .listing__aside{display:flex;transform:none}
  #filters-toggle:checked ~ .listing .drawer-scrim--filters{display:block}
  /* Wewnątrz szuflady grupy nie potrzebują własnych ramek — mają już jedną. */
  .listing__aside .filter-group{border:0;padding:0;border-bottom:1px solid var(--border-subtle);
    padding-bottom:var(--space-4);border-radius:0}
}

/* Strona pod szufladą nie przewija się razem z nią. */
html:has(.drawer-toggle:checked){overflow:hidden}

/* Siatka bezpieczeństwa na treść, której nie piszemy sami: nazwy produktów
   od dostawcy, opisy kategorii, pytania w Q&A. Pojedynczy wyraz dłuższy niż
   kolumna ma się złamać, a nie wypchnąć całą stronę poza ekran. */
.card__name,.cart-line__name,.product__title,.faq__q,.prose,.brand-head__text h1{
  overflow-wrap:break-word}

@media (prefers-reduced-motion:reduce){
  .drawer,.listing__aside,.mega{transition:none}
}

/* ========================== Marki i serie ================================ */
/* Jeden pas: tytuł — opis — logo. Opis bierze całą wolną szerokość, logo
   dociąga do prawej krawędzi także wtedy, gdy opisu nie ma. */
.brand-head{display:flex;align-items:center;gap:var(--space-6) var(--space-8);flex-wrap:wrap}
.brand-head__logo{height:64px;width:auto;object-fit:contain;flex:none;margin-left:auto}
/* `flex:none` trzymało ten blok na szerokości max-content, więc nazwa marki
   w wersalikach („KNIVES BY PABIŚ DANIEL PABIŚ" — 524 px) wychodziła poza ekran
   i nie miała prawa się zawinąć. Domyślne `flex:0 1 auto` nie rośnie, więc
   desktop wygląda tak samo, ale na wąskim ekranie wolno mu się skurczyć. */
.brand-head__text{display:flex;flex-direction:column;gap:var(--space-2);min-width:0}
.brand-head__text h1{font:var(--type-h1)}
.brand-head__meta{font:var(--type-small);color:var(--text-muted)}
.brand-head__desc{flex:1 1 32ch;max-width:68ch;font:var(--type-small);color:var(--text-muted)}
.brand-head__desc > :last-child{margin-bottom:0}

/* Wąsko opis nie zmieści się obok tytułu — schodzi pod spód, ale logo
   zostaje w pierwszym wierszu przy prawej krawędzi. */
@media (max-width:900px){
  .brand-head{gap:var(--space-4) var(--space-6)}
  .brand-head__desc{flex-basis:100%;max-width:75ch;order:3}
  .brand-head__logo{height:48px}
}
.series-head__brand{font:var(--weight-semibold) var(--text-xs)/1 var(--font-body);
  letter-spacing:var(--tracking-wide);text-transform:uppercase;color:var(--text-muted)}
.product__series a{color:var(--text-muted)}

.series-strip{display:flex;flex-direction:column;gap:var(--space-3)}
.series-strip__title{font:var(--weight-semibold) var(--text-xs)/1 var(--font-body);
  letter-spacing:var(--tracking-wide);text-transform:uppercase;color:var(--text-muted)}
.series-strip__list{display:flex;flex-wrap:wrap;gap:var(--space-2)}

/* Kafelek marki jest polem na logo, a nie na tekst — logo ma być czytelne,
   więc dostaje białe tło i stały wiersz na podpis pod spodem. */
.brand-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:var(--space-4)}
.brand-tile{display:flex;flex-direction:column;align-items:center;justify-content:center;
  gap:var(--space-3);min-height:140px;padding:var(--space-4);
  background:var(--surface-card);border:1px solid var(--border-default);
  border-radius:var(--radius-lg);box-shadow:var(--shadow-xs);
  color:var(--text-body);text-align:center;transition:var(--transition-control)}
.brand-tile:hover{text-decoration:none;border-color:var(--steel-400);box-shadow:var(--shadow-sm)}
.brand-tile__logo{max-height:56px;width:auto;object-fit:contain;mix-blend-mode:multiply}
.brand-tile__name{font:var(--weight-bold) var(--text-base)/1.2 var(--font-display);color:var(--text-strong)}
.brand-tile__meta{font:var(--type-mono);color:var(--text-muted)}

/* ---------------------------------------------------------------------------
   Poradniki

   Kafelek artykułu jest siostrą karty produktu, nie osobnym wynalazkiem: ta
   sama powierzchnia, ta sama krawędź, ten sam promień. Blog w sklepie, który
   wygląda jak wklejony z innego serwisu, czyta się jak reklama.

   Kolumna treści ma stałe 68ch. Wiersz dłuższy niż ~75 znaków traci czytelnik
   między końcem jednej linii a początkiem następnej, a artykuł filarowy ma
   4–6 tysięcy znaków, więc to nie jest różnica kosmetyczna.
   --------------------------------------------------------------------------- */
.post-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:var(--space-6)}
.post-grid--compact{grid-template-columns:repeat(auto-fill,minmax(220px,1fr));gap:var(--space-4)}

.post-tile{display:flex;flex-direction:column;overflow:hidden;
  background:var(--surface-card);border:1px solid var(--border-default);
  border-radius:var(--radius-lg);box-shadow:var(--shadow-xs);
  transition:var(--transition-control)}
.post-tile:hover{border-color:var(--steel-400);box-shadow:var(--shadow-sm)}
.post-tile__thumb{display:block;aspect-ratio:16/9;background:var(--surface-sunken)}
.post-tile__thumb img{width:100%;height:100%;object-fit:cover}
.post-tile__body{display:flex;flex-direction:column;gap:var(--space-2);padding:var(--space-4)}
.post-tile__meta{font:var(--type-mono);color:var(--text-muted)}
.post-tile__title{font:var(--weight-bold) var(--text-lg)/1.25 var(--font-display)}
.post-tile__title a{color:var(--text-strong)}
.post-tile__title a:hover{color:var(--text-link-hover)}
.post-tile__excerpt{font:var(--type-small);color:var(--text-muted)}

.article{display:flex;flex-direction:column;gap:var(--space-6);max-width:72ch}
.article__head{display:flex;flex-direction:column;gap:var(--space-3)}
.article__head h1{font:var(--type-h1)}
.article__meta{font:var(--type-mono);color:var(--text-muted)}
.article__lead{font:var(--text-lg)/1.55 var(--font-body);color:var(--text-body)}
.article__figure{margin:0;border-radius:var(--radius-lg);overflow:hidden}
.article__figure img{width:100%;height:auto;display:block}
.article__body{max-width:68ch}
.article__foot{display:flex;flex-direction:column;gap:var(--space-3);
  padding-top:var(--space-4);border-top:1px solid var(--border-subtle)}

/* Spis treści pokazujemy dopiero od trzech nagłówków (warunek jest w szablonie) —
   przy dwóch to ozdoba, która odsuwa pierwszy akapit poniżej ekranu. */
.toc{padding:var(--space-4) var(--space-5);background:var(--surface-sunken);
  border:1px solid var(--border-subtle);border-radius:var(--radius-md)}
.toc__title{font:var(--weight-semibold) var(--text-xs)/1 var(--font-body);
  letter-spacing:var(--tracking-wide);text-transform:uppercase;color:var(--text-muted);
  margin-bottom:var(--space-3)}
.toc__list{list-style:none;display:flex;flex-direction:column;gap:var(--space-2);margin:0;padding:0}
.toc__item--h3{padding-left:var(--space-4)}
.toc__item a{font:var(--type-small)}

/* ---------------------------------------------------------------------------
   Formularze i konto klienta

   Do tej pory motyw miał tylko jedno pole tekstowe — wyszukiwarkę w nagłówku.
   Konto wprowadza formularze wielopolowe, więc kontrolki dostają wreszcie
   wspólny wygląd: ta sama wysokość co przyciski, to samo obramowanie co karty,
   ten sam pierścień fokusu. Bez JavaScriptu — komunikat błędu przychodzi
   z serwera i stoi przy polu, którego dotyczy (§10.2).
   --------------------------------------------------------------------------- */
.form{display:flex;flex-direction:column;gap:var(--space-4)}
.form__row{display:grid;grid-template-columns:repeat(auto-fit,minmax(220px,1fr));gap:var(--space-4)}
.form__actions{display:flex;align-items:center;gap:var(--space-3);flex-wrap:wrap;
  padding-top:var(--space-2)}

.field{display:flex;flex-direction:column;gap:6px}
.field__label{font:var(--weight-semibold) var(--text-sm)/1.2 var(--font-body);color:var(--text-strong)}
.field__req{color:var(--brand-500)}
.field input[type=text],.field input[type=email],.field input[type=tel],
.field input[type=password],.field input[type=number],.field select{
  width:100%;height:var(--control-h-md);padding:0 var(--space-3);
  font:var(--text-sm)/1 var(--font-body);color:var(--text-strong);
  background:var(--surface-card);border:1px solid var(--border-default);
  border-radius:var(--radius-md);transition:var(--transition-control)}
.field input:focus,.field select:focus{outline:none;border-color:var(--brand-400);box-shadow:var(--focus-ring)}
.field__help{font:var(--text-xs)/1.4 var(--font-body);color:var(--text-muted)}
.field__error{font:var(--weight-semibold) var(--text-xs)/1.4 var(--font-body);color:var(--red-500)}
.field--invalid input,.field--invalid select{border-color:var(--red-500)}

/* Zgoda i inne przełączniki: pole obok etykiety, nie nad nią. */
.field--check{flex-direction:row;align-items:flex-start;gap:var(--space-3)}
.field--check input{width:18px;height:18px;margin-top:2px;accent-color:var(--brand-500);flex:none}
.field--check .field__label{font-weight:var(--weight-regular)}

/* Logowanie i rejestracja: wąska kolumna, bo formularz na całą szerokość
   ekranu czyta się gorzej niż ten sam formularz w kolumnie tekstu. */
.auth{display:flex;flex-direction:column;gap:var(--space-6);
  max-width:520px;margin:0 auto;width:100%}
.auth__card{display:flex;flex-direction:column;gap:var(--space-5);
  padding:var(--space-6);background:var(--surface-card);
  border:1px solid var(--border-default);border-radius:var(--radius-lg);
  box-shadow:var(--shadow-sm)}
.auth__aside{display:flex;flex-direction:column;gap:var(--space-2);
  font:var(--type-small);color:var(--text-muted);text-align:center}
.auth--wide{max-width:720px}

/* Konto: nawigacja z boku, treść obok. Poniżej 860 px nawigacja przechodzi
   nad treść jako pasek — na telefonie kolumna boczna zjadałaby pół ekranu. */
.account{display:grid;grid-template-columns:220px 1fr;gap:var(--space-8);align-items:start}
.account__nav{display:flex;flex-direction:column;gap:2px;position:sticky;top:var(--space-4)}
.account__nav a{display:block;padding:var(--space-3);border-radius:var(--radius-md);
  font:var(--weight-semibold) var(--text-sm)/1.2 var(--font-body);color:var(--text-body)}
.account__nav a:hover{background:var(--surface-sunken);text-decoration:none;color:var(--text-strong)}
.account__nav a[aria-current=page]{background:var(--surface-brand-soft);color:var(--brand-600)}
.account__body{display:flex;flex-direction:column;gap:var(--section-gap)}
.account__panel{display:flex;flex-direction:column;gap:var(--space-4);
  padding:var(--space-6);background:var(--surface-card);
  border:1px solid var(--border-default);border-radius:var(--radius-lg);box-shadow:var(--shadow-xs)}
.account__panel h2{font:var(--type-h3)}
.account__note{font:var(--type-small);color:var(--text-muted)}
.account__facts{display:flex;flex-direction:column;gap:var(--space-2);margin:0;padding:0;list-style:none}
.account__facts dt{font:var(--weight-semibold) var(--text-2xs)/1 var(--font-body);
  letter-spacing:var(--tracking-caps);text-transform:uppercase;color:var(--text-muted)}
.account__facts dd{margin:0 0 var(--space-3) 0;font:var(--text-sm)/1.5 var(--font-body);color:var(--text-strong)}

.address-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:var(--space-4)}
.address{display:flex;flex-direction:column;gap:var(--space-3);padding:var(--space-4);
  background:var(--surface-card);border:1px solid var(--border-default);
  border-radius:var(--radius-md)}
.address--default{border-color:var(--brand-400);box-shadow:inset 3px 0 0 var(--brand-500)}
.address__head{display:flex;align-items:baseline;justify-content:space-between;gap:var(--space-2)}
.address__label{font:var(--weight-semibold) var(--text-sm)/1.2 var(--font-body);color:var(--text-strong)}
.address__lines{font:var(--type-small);color:var(--text-body);display:flex;flex-direction:column;gap:2px}
.address__actions{display:flex;gap:var(--space-2);flex-wrap:wrap;margin-top:auto;
  padding-top:var(--space-2);border-top:1px solid var(--border-subtle)}
.address__actions button{background:none;border:0;padding:0;cursor:pointer;
  font:var(--weight-semibold) var(--text-xs)/1 var(--font-body);color:var(--text-link)}
.address__actions button:hover{color:var(--text-link-hover)}
.address__actions .address__remove{color:var(--text-muted)}
.address__actions .address__remove:hover{color:var(--red-500)}

@media (max-width:860px){
  .account{grid-template-columns:1fr;gap:var(--space-6)}
  .account__nav{position:static;flex-direction:row;flex-wrap:wrap;gap:var(--space-2);
    padding-bottom:var(--space-2);border-bottom:1px solid var(--border-subtle)}
}

/* ---------------------------------------------------------------------------
   Baza wiedzy

   Kafelek hasła to nie kafelek marki, choć z daleka wygląda podobnie. Pod
   nazwą marki stoi liczba produktów i kod kraju — dwa symbole, więc krój
   monospace i wyśrodkowanie mają sens. Pod nazwą hasła stoi zdanie definicji,
   a proza wyśrodkowana i pisana monospace czyta się dwa razy wolniej. To jest
   akurat ten tekst, który ma przekonać do wejścia w hasło.

   Definicja na stronie hasła stoi pod nagłówkiem, na pełnej szerokości kolumny
   tekstu — nie w bocznej kolumnie jak opis marki. Człowiek, który wpisał „co to
   jest vg-10", ma dostać odpowiedź bez przewijania i bez szukania jej wzrokiem.
   --------------------------------------------------------------------------- */
.kb-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(280px,1fr));gap:var(--space-4)}
.kb-tile{display:flex;flex-direction:column;gap:var(--space-2);padding:var(--space-4);
  background:var(--surface-card);border:1px solid var(--border-default);
  border-radius:var(--radius-lg);box-shadow:var(--shadow-xs);
  color:var(--text-body);transition:var(--transition-control)}
.kb-tile:hover{text-decoration:none;border-color:var(--steel-400);box-shadow:var(--shadow-sm)}
.kb-tile__name{font:var(--weight-bold) var(--text-base)/1.25 var(--font-display);color:var(--text-strong)}
.kb-tile__excerpt{font:var(--type-small);color:var(--text-muted)}

.kb-head{display:flex;flex-direction:column;gap:var(--space-3);margin-bottom:var(--space-6)}
.kb-head h1{font:var(--type-h1)}
.kb-head__meta{font:var(--type-small);color:var(--text-muted)}
.kb-lead{max-width:68ch;
  font:var(--weight-regular) var(--text-md)/var(--leading-normal) var(--font-body);
  color:var(--text-strong)}

/* Wiersz opisujący hasło otwarte teraz musi być rozpoznawalny bez czytania,
   inaczej tabela porównawcza zmusza do szukania siebie w pierwszej kolumnie. */
.attributes tr[aria-current] > *{background:var(--surface-brand-soft)}
