/* =============================================
   REALIZACJE — Used on: realizacje, realizacja (podstrona projektu)
   v42 — sekcja "Jak pracujemy" (`.portfolio-process*`) USUNIETA na
   zyczenie klienta; razem z markupem wylecialy WSZYSTKIE jej reguly
   (blok glowny + nadpisania w `≤1024px` i `≤768px` + koncowy blok
   kierunku wejscia naglowka na telefonie). ZOSTAJA dwie rzeczy, ktore
   tylko wygladaja na jej pozostalosci, a sa WSPOLDZIELONE z pigulka
   lokalizacji na karcie galerii: `@keyframes portfolio-stat-float`
   (nazwa historyczna — dzis jedynym konsumentem jest
   `.portfolio-card__pill`) i wpis w bloku `prefers-reduced-motion`.
   Nie kasuj ich "przy okazji" — pigulka przestanie sie unosic i straci
   guard reduced-motion, TAKZE na `/realizacje/<slug>`.
   Sprzezone zmiany w `pages/realizacje.html`: usuniety markup sekcji,
   usuniety inline modul licznika `[data-count-target]` (obslugiwal
   wylacznie karte "11 000+") i skrocona tablica sekcji w module
   `data-reveal` do samej `.portfolio-gallery`.

   v29 — okragla ikona w pigulce lokalizacji (`.portfolio-card__pill-icon`)
   przeszla z PELNEGO pomaranczowego gradientu + bialej ikony na MIEKKIE,
   polprzezroczyste kolko `rgba(var(--orange-rgb), 0.12)` + POMARANCZOWA
   ikone. Zyczenie klienta ze zrzutem: "popraw ta okragla ikonke, aby
   wygladala jak ta z 1 screena" — wzorcem byla plakietka z cytatem na
   zdjeciu w sekcji "Dlaczego my" (`.why-us__badge-icon`, why-us.css:92),
   ktora uzywa dokladnie tej pary tlo/kolor. Proporcja ikony do kolka byla
   juz zgodna (20/40 = 0.5, wzorzec 26/53), wiec rozmiary sa NIETKNIETE —
   takze te w bloku `≤768px` (36px). Reszta pigulki (kremowe szklo z v27,
   ciemny tekst, unoszenie) bez zmian. UWAGA: pigulka renderuje sie takze
   na `/realizacje/<slug>` w sekcji "Inne realizacje", wiec zmiana dotyka
   obu stron ladujacych ten arkusz.

   v27 — pigulka lokalizacji na karcie (`.portfolio-card__pill`) przeszla
   z ciemnej, nieprzezroczystej na SZKLANA i UNOSZACA SIE — powierzchnia
   i ruch 1:1 z `.showroom__badge` / `.portfolio-process__stat`
   (`rgba(249,246,244,0.75)` + `blur(16px)` + miekki cien + keyframes
   `portfolio-stat-float`). Zyczenie klienta ze zrzutem: "ma wygladac tak
   samo jak plakietka z drugiego screena, czyli byc przezroczysta i sie
   unosic". Sprzezona zmiana, bez ktorej pigulka jest NIECZYTELNA:
   `.portfolio-card__pill-title` z `var(--white)` na `var(--dark-gray)`.
   Pomaranczowa pigulka ikony zostaje bez zmian — klient doprecyzowal
   zakres slowem "czyli" (powierzchnia + ruch), a okragla ikona i tak
   powtarza uklad `.showroom__badge-icon`. Ruch idzie na `transform`,
   ktory na tym elemencie jest wolny (reveal karty jedzie na `translate`,
   hover-lift na `transform` SAMEJ karty, nie pigulki). `animation: none`
   dopisane do bloku `prefers-reduced-motion` obok `.portfolio-process__stat`.
   UWAGA: pigulka renderuje sie takze na `/realizacje/<slug>` (sekcja
   "Inne realizacje"), wiec zmiana dotyka obu stron.

   v26 — karta galerii jest LINKIEM do `/realizacje/<slug>`, a nie
   przyciskiem otwierajacym lightbox. Cala sekcja `.portfolio-lightbox`
   zostala z tego arkusza USUNIETA — nic jej juz nie renderuje; podstrona
   realizacji ma wlasny, prostszy `.project-lightbox`
   (css/realizacja-single.css).

   Uklad wzorowany na greenspire.framer.website/project: hero split
   (naglowek lewa / opis + CTA prawa, jak kontakt.css v27), grid projektow
   2-kol (zdjecie ze szklana pigulka lokalizacji + biala karta opisu
   z wierszem meta) i pas social pod siatka.
   Wejscia: hero czysto CSS (nad zalamaniem), karty galerii wlasny IO
   w inline JS, pas social system `data-reveal`/`.eo-reveal`
   (wzorzec o-nas.css v283).

   UWAGA: arkusz laduje TAKZE podstrona `/realizacje/<slug>` — bierze
   z niego `.portfolio-card` (sekcja "Inne realizacje"), spinner
   `.portfolio-gallery__loading` i reguly `.eo-reveal`. Zmiana tych
   selektorow dotyka obu stron.
   ============================================= */

/* =============================================
   PAGE HERO — split: naglowek lewa, opis + CTA prawa
   `padding-top: 132px` jest FUNKCJONALNY — navbar w stanie --home-top
   stoi nad kremem (patrz gotcha o morphie navbara).
   ============================================= */
.portfolio-hero {
  padding: 132px 24px 48px;
  background: var(--white);
}

.portfolio-hero__container {
  max-width: var(--max-width-wide);
  margin: 0 auto;
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 400px);
  gap: 0 64px;
  align-items: start;
}

.portfolio-hero__heading {
  grid-column: 1;
  grid-row: 2;
  font-family: var(--font-family);
  font-size: 66px;
  font-weight: 500;
  color: var(--dark-gray);
  letter-spacing: -0.03em;
  line-height: 1.1;
  margin: 0;
  opacity: 0;
  animation: fadeInUp 0.9s var(--reveal-ease) 0.35s forwards;
}

.portfolio-hero__accent {
  color: inherit;
}

/* Prawa kolumna: opis + przycisk. Wyrownana GORA do gory naglowka
   (`align-items: start` na kontenerze) — kolumna jest wyzsza niz naglowek
   (subheading + CTA), wiec przy dawnym `align-items: end` jej gora wystawala
   ponad naglowek. Klient: subheading ma byc rowny wysokoscia z naglowkiem. */
.portfolio-hero__side {
  grid-column: 2;
  grid-row: 2;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 22px;
}

.portfolio-hero__subheading {
  font-family: var(--font-family);
  font-size: 18px;
  font-weight: 400;
  color: var(--gray-500);
  line-height: 1.6;
  margin: 0;
  opacity: 0;
  animation: fadeInUp 0.9s var(--reveal-ease) 0.55s forwards;
}

.portfolio-hero__cta {
  opacity: 0;
  animation: fadeInUp 0.9s var(--reveal-ease) 0.7s forwards;
}

/* Rozmiar 1:1 z przyciskiem "Odwiedz nasz salon" w sekcji `.cta-banner--dark`
   (cta-banner.css: font-size 17px / padding 16px 40px). Bazowe `.ihb--cta`
   (0,1,0) daje 19px/18px 44px; podwojona klasa (0,2,0) wygrywa niezaleznie od
   kolejnosci ladowania arkuszy. Brak media-query — wzorzec tez ma jeden rozmiar
   na wszystkich szerokosciach (`.cta-banner--dark .ihb--cta` nie ma progow). */
.ihb--cta.portfolio-hero__cta {
  font-size: 17px;
  padding: 16px 40px;
}

/* =============================================
   PORTFOLIO GALLERY — Filters + Grid
   ============================================= */
.portfolio-gallery {
  padding: 8px 24px 110px;
  background: var(--white);
  /* Cel kotwicy z przycisku hero — naglowek nie moze wjechac pod navbar */
  scroll-margin-top: 96px;
}

.portfolio-gallery__container {
  max-width: var(--max-width-wide);
  margin: 0 auto;
}

/* ---- Filters — floating bar (navbar-style), wyrownany do lewej ---- */
.portfolio-gallery__filters {
  display: flex;
  align-items: center;
  /* jedno zrodlo prawdy: padding paska i zasieg przyklejonych krawedzi
     (`::before`/`::after`) musza byc rowne, inaczej chip przewija sie POD
     padding i wynurza obok chevrona */
  --f-pad: 6px;
  /* `--f-gap` musi byc zmienna, bo ujemne marginesy krawedzi `::before`/
     `::after` MUSZA pochlonac takze przerwe gapu — sa stalymi flex-itemami,
     wiec bez tego doktadaja 2 × gap do toru przewijania (patrz v35) */
  --f-gap: 6px;
  /* szerokosc przyklejonej krawedzi — w JEDNYM miejscu, bo wystepuje takze
     w ujemnych marginesach `::before`/`::after` (musza sie znosic co do px) */
  --f-edge: 56px;
  gap: var(--f-gap);
  justify-content: space-between;
  margin: 0 0 40px;
  padding: var(--f-pad);
  background: rgba(249, 246, 244, 0.97);
  border-radius: var(--radius-md);
  box-shadow: 0 4px 24px rgba(0, 0, 0, 0.08), 0 1px 4px rgba(0, 0, 0, 0.04);
  width: 100%;
  /* Pasek przewija sie w POZIOMIE, gdy 7 pozycji nie miesci sie w jednej linii.
     To siatka bezpieczenstwa dla kazdej szerokosci: bez niej flexbox sciskal
     przyciski ponizej szerokosci ich tekstu i napisy NACHODZILY na siebie
     (patrz v33). Scrollbar jest ukryty, wiec sygnalem „jest wiecej" sa
     przyklejone krawedzie `::before`/`::after` nizej. */
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x proximity;
  scroll-padding: 0 var(--f-pad);
  scrollbar-width: none;
  -ms-overflow-style: none;
  opacity: 0;
  animation: fadeInUp 0.9s var(--reveal-ease) 0.8s forwards;
}

.portfolio-gallery__filters::-webkit-scrollbar {
  width: 0;
  height: 0;
  display: none;
}

/* Sygnal „pasek ma dalsze pozycje" — scrollbar jest ukryty, wiec bez tego
   uzytkownik widzi 4 filtry i pustke, i nie wie, ze sa jeszcze 3.
   Klasy nadaje inline JS w realizacje.html, wiec krawedz pojawia sie TYLKO
   po tej stronie, w ktora da sie jeszcze przewinac.
   Dlaczego przyklejony FLEX-ITEM, a nie `mask-image` na pasku (probowane,
   odrzucone): maska przycinala cien karty, a przede wszystkim samo
   wygaszenie bywa NIEWIDOCZNE — przy czesci szerokosci przy krawedzi wypada
   pusty odstep miedzy chipami i nie ma czego wygaszac. Chevron widac zawsze.
   Ujemny margines sprawia, ze element nie zajmuje miejsca w torze
   przewijania (nie powieksza scrollWidth).
   OBIE krawedzie sa w ukladzie ZAWSZE (`display: flex`), a klasa przelacza
   wylacznie `opacity` — `display: none → flex` jest nieanimowalne, wiec
   chevron RAZEM ze swoim jasnym tlem wskakiwal jedna klatka i czytalo sie
   to jak mrugniecie (v35). Netto zerowa szerokosc (width 44 + margin -44)
   sprawia, ze stala obecnosc nie rusza ukladu ani `scrollWidth`. */
.portfolio-gallery__filters::before,
.portfolio-gallery__filters::after {
  display: flex;
  position: sticky;
  z-index: 1;
  flex: 0 0 auto;
  width: var(--f-edge);
  align-self: stretch;
  align-items: center;
  font-size: 22px;
  line-height: 1;
  color: var(--gray-500);
  opacity: 0;
  transition: opacity 0.25s ease;
  pointer-events: none;
}

.portfolio-gallery__filters::before {
  content: '\2039';
  justify-content: flex-start;
  /* ujemny offset = krawedz siega BORDER-boxa; przy `left: 0` chip przewija
     sie pod padding paska i wynurza obok chevrona */
  left: calc(-1 * var(--f-pad));
  margin-right: calc(-1 * var(--f-edge) - var(--f-gap));
  padding-left: var(--f-pad);
  /* Pelne krycie do 46% (~26px) jest WYMOGIEM, nie estetyka: chevron konczy
     sie ~16px od krawedzi, a bez tego zapasu pomaranczowa pigulka aktywnego
     filtra przewijajaca sie pod krawedz prezwitywala tuz za znakiem i chevron
     czytal sie jak postawiony na pomaranczu (zgloszenie klienta, v36). */
  background: linear-gradient(to right, var(--white) 46%, rgba(249, 246, 244, 0));
}

.portfolio-gallery__filters::after {
  content: '\203A';
  justify-content: flex-end;
  right: calc(-1 * var(--f-pad));
  margin-left: calc(-1 * var(--f-edge) - var(--f-gap));
  padding-right: var(--f-pad);
  background: linear-gradient(to left, var(--white) 46%, rgba(249, 246, 244, 0));
}

.portfolio-gallery__filters.has-fade-start::before,
.portfolio-gallery__filters.has-fade-end::after {
  opacity: 1;
}

.portfolio-gallery__filter {
  font-family: var(--font-family);
  font-size: 16px;
  font-weight: 500;
  padding: 11px 22px;
  border: none;
  border-radius: var(--radius-sm);
  background: transparent;
  color: var(--gray-500);
  cursor: pointer;
  transition: background 0.25s ease, color 0.25s ease, box-shadow 0.25s ease;
  /* rowna szerokosc kazdego przycisku (i pomaranczowej pigulki .active)
     niezaleznie od dlugosci tekstu — kolumny 1fr. `min-width: max-content`
     jest PODLOGA, ponizej ktorej kolumna nie zejdzie: rowne kolumny mieszcza
     najdluzszy tekst dopiero od ~1433px, wiec bez tego caly zakres 769–1432px
     mial nachodzace napisy. Gdy podloga zaczyna wiazac, kolumny przestaja byc
     rowne — i tak ma byc. Mobile resetuje na auto. */
  flex: 1 1 0;
  min-width: max-content;
  scroll-snap-align: start;
  text-align: center;
  white-space: nowrap;
}

.portfolio-gallery__filter:hover {
  background: rgba(0, 0, 0, 0.04);
  color: var(--dark-gray);
}

.portfolio-gallery__filter:active {
  background: rgba(0, 0, 0, 0.07);
}

.portfolio-gallery__filter:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: 2px;
}

.portfolio-gallery__filter.active {
  background: var(--orange-gradient);
  color: var(--white);
  box-shadow: 0 4px 16px rgba(var(--orange-rgb), 0.25);
}

/* ---- Loading ---- */
.portfolio-gallery__loading {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding: 80px 0;
  color: var(--gray-500);
  font-family: var(--font-family);
  font-size: 15px;
}

.portfolio-gallery__spinner {
  width: 36px;
  height: 36px;
  border: 3px solid var(--border-color);
  border-top-color: var(--orange);
  border-radius: 50%;
  animation: gallerySpinner 0.7s linear infinite;
}

@keyframes gallerySpinner {
  to { transform: rotate(360deg); }
}

/* ---- Empty state ----
   Animacja restartuje przy kazdym przelaczeniu display: none → flex,
   wiec pusty stan pojawia sie tak samo miekko jak karty. */
.portfolio-gallery__empty {
  flex-direction: column;
  align-items: center;
  gap: 16px;
  padding: 80px 0;
  text-align: center;
  font-family: var(--font-family);
  font-size: 15px;
  color: var(--gray-500);
  animation: fadeInUp 0.45s var(--reveal-ease) both;
}

/* ---- Gallery Grid ---- */
.portfolio-gallery__grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 48px 24px;
  min-height: 60vh;
}

/* ---- „Zobacz wiecej" — doladowanie kolejnej partii 4 realizacji ----
   Wrapper jest chowany atrybutem `hidden` z JS, wiec regula `[hidden]`
   jest KONIECZNA: `display: flex` przebija domyslne `display: none`
   z arkusza przegladarki. */
.portfolio-gallery__more {
  display: flex;
  justify-content: center;
  margin-top: 56px;
}

.portfolio-gallery__more[hidden] {
  display: none;
}

/* Czas pobierania miniatur kolejnej partii — przycisk gasnie i jest
   zablokowany, zeby drugi klik nie doklejal dwoch partii naraz. */
.portfolio-gallery__more-btn.is-loading {
  opacity: 0.55;
  cursor: wait;
}

/* ---- Portfolio Card (zdjecie + pigulka tytulu + biala karta info) ----
   Stan ukryty NIE potrzebuje bramki klasowej: karty istnieja wylacznie
   dlatego, ze zbudowal je ten sam inline JS, ktory je odslania.
   Reveal jedzie na `translate`, hover-lift na `transform` — osobne
   wlasciwosci, wiec nie walcza o jedna deklaracje (wzorzec services v34). */
.portfolio-card {
  /* Karta jest `<a>` — resetujemy domyslny wyglad linku, zeby kolory
     i podkreslenia bral z wlasnych regul, nie z przegladarki. */
  display: block;
  color: inherit;
  text-decoration: none;
  cursor: pointer;
  opacity: 0;
  translate: 0 30px;
  transition: opacity 0.7s ease-out, translate 0.7s ease-out,
              transform 0.3s cubic-bezier(0.34, 1.56, 0.64, 1);
}

.portfolio-card.is-revealed {
  opacity: 1;
  translate: none;
}

/* Wyjscie przy zmianie filtra — MUSI stac PO `.is-revealed` (rowna
   specyficznosc, wygrywa kolejnoscia w zrodle). Karty schodza lekko
   W GORE (zasada "nic nie wjezdza z gory" dotyczy wejsc; wyjscie w gore
   + wejscie z dolu daje ciaglosc kierunku). Czas krotszy niz wejscie,
   zeby przelaczanie nie czekalo. */
.portfolio-card.is-leaving {
  opacity: 0;
  translate: 0 -14px;
  transition: opacity 0.22s ease, translate 0.22s ease;
  pointer-events: none;
}

.portfolio-card:hover {
  transform: translateY(-4px);
}

.portfolio-card:active {
  transform: translateY(-1px);
}

.portfolio-card:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: 4px;
  border-radius: var(--radius-lg);
}

.portfolio-card__media {
  position: relative;
  aspect-ratio: 6 / 5;
  border-radius: var(--radius-lg);
  overflow: hidden;
  background: var(--border-color);
}

.portfolio-card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  display: block;
  transition: transform 0.4s cubic-bezier(0.25, 0.46, 0.45, 0.94),
              opacity 0.5s ease;
}

/* Zdjecie wchodzi fadem po `load` (klase `is-loaded` nadaje inline JS
   galerii) — bez tego na tle `--border-color` widac szary prostokat,
   a fotka wskakuje skokowo.
   ZAWEZONE DO SIATKI GALERII CELOWO: te same klasy `.portfolio-card`
   renderuje sekcja „Inne realizacje" na `/realizacje/<slug>`, a TAMTEN
   skrypt `is-loaded` nie nadaje — regula bez `.portfolio-gallery__grid`
   ukrylaby tam zdjecia na zawsze. */
.portfolio-gallery__grid .portfolio-card__media img {
  opacity: 0;
}

.portfolio-gallery__grid .portfolio-card__media img.is-loaded {
  opacity: 1;
}

.portfolio-card:hover .portfolio-card__media img {
  transform: scale(1.05);
}

/* Szklana pigulka z ikona i lokalizacja — na dole zdjecia.
   Powierzchnia i ruch 1:1 z `.showroom__badge` / `.portfolio-process__stat`:
   polprzezroczysty krem + blur + miekki cien + unoszenie. */
.portfolio-card__pill {
  position: absolute;
  left: 18px;
  bottom: 18px;
  max-width: calc(100% - 36px);
  display: flex;
  align-items: center;
  gap: 12px;
  background: rgba(249, 246, 244, 0.75);
  -webkit-backdrop-filter: blur(16px);
  backdrop-filter: blur(16px);
  box-shadow: 0 20px 44px -14px rgba(0, 0, 0, 0.18);
  border-radius: var(--radius-md);
  padding: 10px 22px 10px 10px;
  animation: portfolio-stat-float 3s ease-in-out infinite;
  will-change: transform;
}

/* Miekkie, przezroczyste kolko z pomaranczowa ikona — 1:1 z
   `.why-us__badge-icon` (ta sama para: tlo `rgba(--orange-rgb, 0.12)`
   + `color: var(--orange)`). Ikona SVG ma 20px przy kolku 40px, czyli
   ta sama proporcja 0.5 co wzorzec (26/53). */
.portfolio-card__pill-icon {
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: var(--radius-full);
  background: rgba(var(--orange-rgb), 0.12);
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--orange);
}

/* Ciemny tekst — na kremowym szkle bialy bylby nieczytelny */
.portfolio-card__pill-title {
  font-family: var(--font-family);
  font-size: 16px;
  font-weight: 600;
  color: var(--dark-gray);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* Biala karta pod zdjeciem: sam wiersz meta.
   `.portfolio-card__desc` (opis clamp-2 z pola `opis`) usuniety 2026-07-30
   razem z polem w Sanity — karty galerii sa teraz identyczne z tymi w sekcji
   „Inne realizacje" na podstronie, ktore opisu nigdy nie renderowaly. */
.portfolio-card__body {
  margin-top: 12px;
  background: #ffffff;
  border-radius: var(--radius-lg);
  padding: 20px 22px;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
}

.portfolio-card__meta {
  display: flex;
}

.portfolio-card__meta-item {
  flex: 1;
  min-width: 0;
  display: flex;
  flex-direction: column;
  gap: 4px;
  padding-right: 14px;
}

.portfolio-card__meta-item + .portfolio-card__meta-item {
  border-left: 1px solid var(--border-color);
  padding-left: 16px;
}

.portfolio-card__meta-label {
  font-family: var(--font-family);
  font-size: 13px;
  font-weight: 400;
  color: var(--gray-500);
}

.portfolio-card__meta-value {
  font-family: var(--font-family);
  font-size: 15px;
  font-weight: 600;
  color: var(--dark-gray);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}

/* =============================================
   PORTFOLIO SOCIAL — pas z odnosnikami do FB / IG pod siatka galerii
   Biala karta na kremowym tle sekcji — `#ffffff`, a NIE `var(--white)`
   (token to krem #FAF9F4, wiec karta by zniknela; ta sama para co
   `.portfolio-card__body`).
   Kafel ikony powtarza konwencje ikon serwisu co do wartosci:
   40px / radius 5px / `rgba(var(--orange-rgb), 0.12)` + `var(--orange)`
   (`.why-us__feature-icon`, `.footer__back-to-top-icon`, `.door-types__item-arrow`).
   ============================================= */
.portfolio-social {
  margin-top: 64px;
}

/* Naglowek stoi NAD karta, a nie w srodku — uklad przepisany co do wartosci
   z sekcji „Opis" na podstronie realizacji (`.project__section-heading`
   + `.project__story` w realizacja-single.css), ktora klient wskazal
   zrzutem jako wzorzec. Zmiana tamtych wartosci rozjedzie oba miejsca.
   Zwykly naglowek, a NIE etykieta sekcji: klient wprost odrzucil tu
   konwencje `// …` („niepotrzebny jest nam label"), stad brak `::before`
   i brak `text-transform: capitalize`. */
.portfolio-social__heading {
  font-family: var(--font-family);
  font-size: 30px;
  font-weight: var(--heading-weight);
  color: var(--dark-gray);
  letter-spacing: -0.02em;
  line-height: 1.2;
  margin: 0 0 22px;
}

.portfolio-social__card {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 20px 40px;
  padding: 32px 34px;
  background: #ffffff;
  border-radius: var(--radius-lg);
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.04);
}

.portfolio-social__desc {
  font-family: var(--font-family);
  font-size: 17px;
  font-weight: 400;
  line-height: 1.6;
  color: var(--gray-500);
  margin: 0;
  /* 640px trzyma opis w JEDNEJ linii na desktopie (zmierzone ~505px przy
     17px); przy 1100px karta jest wezsza i tekst zawija sie naturalnie,
     bo `.portfolio-social` ma `flex-wrap`. Po zmianie tresci przemierz. */
  max-width: 640px;
}

.portfolio-social__links {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
}

.portfolio-social__link {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 10px 18px 10px 10px;
  border-radius: var(--radius-md);
  font-family: var(--font-family);
  font-size: 16px;
  font-weight: 500;
  color: var(--dark-gray);
  text-decoration: none;
  /* Bez wlasnego tla w ZADNYM stanie — klient odrzucil szara plame pod
     linkiem („to nie jest efekt premium"). Cala reakcja to uniesienie
     linku + zapalenie kafla ikony; nie dodawaj tu `background-color`. */
  background: transparent;
  transition: transform 0.25s ease;
  /* base.css wylacza globalnie podswietlenie dotkniecia, wiec `:active`
     nizej jest JEDYNA reakcja na stukniecie — nie usuwaj go. */
  -webkit-tap-highlight-color: transparent;
}

.portfolio-social__icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  flex: 0 0 auto;
  width: 40px;
  height: 40px;
  border-radius: 5px;
  background: rgba(var(--orange-rgb), 0.12);
  color: var(--orange);
  transition: background 0.25s ease, color 0.25s ease;
}

.portfolio-social__icon svg {
  width: 20px;
  height: 20px;
}

/* Hover bramkowany, bo przegladarki dotykowe zatrzaskuja `:hover`
   na ostatnio dotknietym elemencie (wzorzec services v29). */
@media (hover: hover) {
  .portfolio-social__link:hover {
    transform: translateY(-2px);
  }

  .portfolio-social__link:hover .portfolio-social__icon {
    background: var(--orange-gradient);
    color: var(--white);
  }
}

/* Reakcja na wcisniecie/stukniecie to DOCISNIECIE + zapalenie kafla ikony,
   a nie tlo pod linkiem. Na desktopie `:active` (0,2,0) wygrywa z `:hover`
   kolejnoscia w zrodle, wiec link opada z -2px i lekko sie zmniejsza;
   na dotyku (brak hoveru) zostaje samo docisniecie + gradient na ikonie. */
.portfolio-social__link:active {
  transform: translateY(0) scale(0.97);
}

.portfolio-social__link:active .portfolio-social__icon {
  background: var(--orange-gradient);
  color: var(--white);
}

.portfolio-social__link:focus-visible {
  outline: 2px solid var(--orange);
  outline-offset: 3px;
}

@keyframes portfolio-stat-float {
  0%, 100% { transform: translateY(0); }
  50% { transform: translateY(-8px); }
}

@media (prefers-reduced-motion: reduce) {
  .portfolio-card__pill { animation: none; }
}

/* =============================================
   SCROLL REVEAL — system `data-reveal` (wzorzec o-nas.css v283)
   Stan ukryty pod bramka `.eo-reveal` dodawana przez inline JS —
   brak/stary JS = tresc widoczna bez animacji.
   ============================================= */
.eo-reveal {
  --eo-reveal-dur: 0.7s;
  --eo-ease: ease-out;
  --eo-shift: 30px;
}

.eo-reveal [data-reveal] {
  opacity: 0;
  transform: translateY(var(--eo-shift));
  transition: opacity var(--eo-reveal-dur) var(--eo-ease),
              transform var(--eo-reveal-dur) var(--eo-ease);
}

/* Kierunki — MUSZA zostac po regule wyzej (rowna specyficznosc). */
.eo-reveal [data-reveal="left"]  { transform: translateX(calc(-1 * var(--eo-shift))); }
.eo-reveal [data-reveal="right"] { transform: translateX(var(--eo-shift)); }

.eo-reveal [data-reveal].is-revealed {
  opacity: 1;
  transform: none;
}

/* =============================================
   KEYFRAMES
   fadeInUp zyje w base.css; lokalny wariant BEZ ruchu dla reduced motion
   (base.css nie ma czystego fade — wzorzec kontakt.css v27).
   ============================================= */
@keyframes portfolioHeroFade {
  from { opacity: 0; }
  to { opacity: 1; }
}

/* =============================================
   RESPONSIVE
   ============================================= */
/* === Tablet (≤1024px) === */
@media (max-width: 1024px) {
  .portfolio-hero {
    padding: 118px 24px 40px;
  }

  .portfolio-hero__container {
    grid-template-columns: minmax(0, 1fr) minmax(0, 320px);
    gap: 0 40px;
  }

  .portfolio-hero__heading {
    font-size: 44px;
  }

  .portfolio-hero__subheading {
    font-size: 16px;
  }

  .portfolio-gallery__grid {
    gap: 36px 16px;
  }

  .portfolio-card__pill {
    left: 14px;
    bottom: 14px;
    max-width: calc(100% - 28px);
    gap: 10px;
    padding: 8px 18px 8px 8px;
  }

  .portfolio-card__pill-icon {
    width: 36px;
    height: 36px;
  }

  .portfolio-card__pill-title {
    font-size: 15px;
  }
}

/* === Mobile (≤768px) === */
@media (max-width: 768px) {
  .portfolio-hero {
    padding: 110px 20px 36px;
  }

  .portfolio-hero__container {
    grid-template-columns: 1fr;
    gap: 0;
  }

  .portfolio-hero__heading {
    font-size: 38px;
    grid-column: 1;
  }

  .portfolio-hero__side {
    grid-column: 1;
    grid-row: 3;
    margin-top: 18px;
    max-width: 480px;
    padding-bottom: 0;
    gap: 18px;
  }

  .portfolio-hero__subheading {
    font-size: 16px;
  }

  /* CTA „Odwiedz nasz salon" UKRYTY na telefonie (zyczenie klienta) —
     na desktopie zostaje bez zmian. Podwojona klasa (0,2,0), bo `.ihb`
     z navbar.css ma `display: inline-flex` przy tej samej specyficznosci
     (0,1,0) i wygrywaloby kolejnoscia ladowania arkuszy. */
  .portfolio-hero__cta.portfolio-hero__cta {
    display: none;
  }

  .portfolio-gallery {
    padding: 4px 16px 70px;
    scroll-margin-top: 88px;
  }

  /* Pasek filtrow na telefonie: JEDNA linia przewijana palcem, zamiast
     zawijania na 3 rzedy o nierownych szerokosciach (v33). Zawijanie dawalo
     126px wysokosci i „worek" niedopasowanych pigulek — teraz 46px. */
  .portfolio-gallery__filters {
    --f-pad: 5px;
    --f-gap: 4px;
    margin-bottom: 28px;
    flex-wrap: nowrap;
    width: 100%;
    justify-content: flex-start;
    scroll-padding: 0 5px;
    border-radius: var(--radius-md);
  }

  .portfolio-gallery__filter {
    font-size: 14px;
    padding: 10px 16px;
    border-radius: var(--radius-sm);
    /* pasek jest przewijany — przycisk ma szerokosc tresci i sie nie rozciaga;
       `nowrap` jest wymogiem, inaczej „Drzwi wewnetrzne" lamie sie w pigulce */
    flex: 0 0 auto;
    min-width: 0;
    white-space: nowrap;
  }

  .portfolio-gallery__grid {
    grid-template-columns: 1fr;
    gap: 28px;
  }

  .portfolio-gallery__more {
    margin-top: 36px;
  }

  .portfolio-card__body {
    padding: 18px;
  }

  /* Meta w 2 kolumnach z zawijaniem wartosci (jak w referencji na mobile) —
     3 kolumny z ellipsis ucinaly dluzsze kolory ("Woodeck Turner Oak"). */
  .portfolio-card__meta {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 14px 16px;
  }

  .portfolio-card__meta-item {
    padding-right: 0;
  }

  .portfolio-card__meta-item + .portfolio-card__meta-item {
    border-left: 0;
    padding-left: 0;
  }

  .portfolio-card__meta-item:nth-child(even) {
    border-left: 1px solid var(--border-color);
    padding-left: 16px;
  }

  .portfolio-card__meta-label {
    font-size: 12px;
  }

  .portfolio-card__meta-value {
    font-size: 14px;
    white-space: normal;
  }

  /* Pas social: kolumna. Linki zostaja obok siebie (dwa krotkie slowa
     mieszcza sie w jednej linii az do 320px), wiec `flex-wrap` na
     `.portfolio-social__links` jest tu tylko siatka bezpieczenstwa. */
  .portfolio-social {
    margin-top: 44px;
  }

  /* Te same progi co wzorzec: naglowek 30 → 26px, karta 32/34 → 24/20px. */
  .portfolio-social__heading {
    font-size: 26px;
    margin-bottom: 18px;
  }

  .portfolio-social__card {
    flex-direction: column;
    align-items: flex-start;
    gap: 18px;
    padding: 24px 20px;
  }

  .portfolio-social__desc {
    font-size: 16px;
  }

  .portfolio-social__link {
    font-size: 15px;
    padding: 8px 14px 8px 8px;
    gap: 8px;
  }

  .portfolio-social__icon {
    width: 36px;
    height: 36px;
  }

  .portfolio-social__icon svg {
    width: 18px;
    height: 18px;
  }
}

/* =============================================
   REDUCED MOTION
   Hero przechodzi na sam fade (bez ruchu), reveal zeruje dystans
   i skraca czas (ta sama zasada co base.css v131–132: mniej ruchu,
   nie brak przejscia).
   ============================================= */
@media (prefers-reduced-motion: reduce) {
  .portfolio-hero__heading,
  .portfolio-hero__subheading,
  .portfolio-hero__cta,
  .portfolio-gallery__filters {
    animation-name: portfolioHeroFade;
    animation-duration: 0.2s;
  }

  .portfolio-card {
    translate: none;
    transition-duration: 0.2s;
  }

  .portfolio-card.is-leaving {
    translate: none;
    transition-duration: 0.15s;
  }

  .portfolio-gallery__empty {
    animation-name: portfolioHeroFade;
    animation-duration: 0.2s;
  }

  /* Zostaje sama zmiana koloru kafla ikony — uniesienie linku social
     i docisniecie przy kliknieciu znikaja. */
  .portfolio-social__link,
  .portfolio-social__link:hover,
  .portfolio-social__link:active {
    transform: none;
  }

  .eo-reveal {
    --eo-reveal-dur: 0.2s;
    --eo-shift: 0px;
  }
}
