/* =========================================================================
   TYP OD WNĘTRZ - premium interior studio
   Design system: cozy-with-edge. Warm naturals, editorial type, hairlines.
   Display: Cormorant Garamond · UI/body: Hanken Grotesk · Accent: brass
   ========================================================================= */

:root {
  /* -- Color roles -- */
  --bone: #F5F0E8;          /* złamana biel - main light bg */
  --beige: #E9DFCF;         /* warm panels / cards */
  --sand: #DECDB4;          /* deeper warm panel */
  --taupe: #C9B79E;         /* hairlines, soft borders */
  --warm-gray: #8A8073;     /* secondary text on light */
  --graphite: #2A2723;      /* primary text / dark sections */
  --ink: #000000;           /* czysta czerń - hero overlay / stopka / ciemne sekcje */
  /* Hover ciemnych kafli MUSI być jaśniejszy od --ink, inaczej na czystej
     czerni nie ma czego rozjaśnić i kafle przestają reagować na kursor. */
  --ink-2: #0E0E0E;
  /* Te same kanały co --ink, tylko w rozbiciu: gradienty i przydymienia
     potrzebują wersji z alfą, a `rgba()` nie przyjmuje zmiennej z hexem. Bez tego
     ciemny kolor musiałby być wpisany na sztywno w kilkunastu miejscach i przy
     następnej zmianie palety część strony zostałaby w starym kolorze. */
  --ink-rgb: 0 0 0;
  --brass: #A9885E;         /* metallic accent */
  --brass-soft: #BE9C6E;    /* brass hover */
  --cream-on-dark: #EDE3D2; /* text on dark */
  --muted-on-dark: #A89E8C; /* secondary text on dark */

  /* -- Type -- */
  --display: "Cormorant Garamond", Georgia, serif;
  --ui: "Hanken Grotesk", system-ui, -apple-system, sans-serif;
  /* Cyfry (ceny, metraż, numery typów) NIE idą Cormorantem: jego cyfry są
     wąskie, o różnej wysokości i w cenniku wyglądają jak literówki. Liczby
     dostają grotesk z tabular-nums - równa szerokość znaków, jedna wysokość,
     kolumny cen stoją w pionie. Kroje zostają te same, zmienia się tylko
     to, którym z nich składamy liczby. */
  --num: "Hanken Grotesk", system-ui, -apple-system, sans-serif;

  /* -- Spacing -- */
  --gut: clamp(20px, 5vw, 72px);     /* page side gutter */
  --sect: clamp(88px, 12vw, 184px);  /* section vertical rhythm */
  --maxw: 1480px;

  /* -- Misc -- */
  --hair: 1px solid color-mix(in srgb, var(--taupe) 60%, transparent);
  --ease: cubic-bezier(0.22, 1, 0.36, 1);

  /* Strona jest na stałe JASNA (patrz skrypt w <head>). Bez tej deklaracji
     Chrome - zwłaszcza na Androidzie, gdzie działa to domyślnie - włącza
     „Auto Dark Mode" i sam przemalowuje beże na brąz, kiedy telefon ma ciemny
     motyw systemowy. To jedna linijka, która wypisuje nas z tej automatyki. */
  color-scheme: light;
}

/* ------------------------------- Reset ------------------------------- */
*, *::before, *::after { box-sizing: border-box; }
* { margin: 0; padding: 0; }
html { -webkit-text-size-adjust: 100%; scroll-behavior: smooth; }
body {
  font-family: var(--ui);
  background: var(--bone);
  color: var(--graphite);
  font-size: 17px;
  line-height: 1.6;
  font-weight: 400;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}
img, picture { display: block; max-width: 100%; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
input, select, textarea { font: inherit; color: inherit; }
::selection { background: var(--brass); color: var(--bone); }

/* ------------------------------- Typography ------------------------------- */
.display {
  font-family: var(--display);
  font-weight: 500;
  line-height: 0.98;
  letter-spacing: -0.01em;
  text-wrap: balance;
}
.kicker {
  font-family: var(--ui);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.26em;
  text-transform: uppercase;
  color: var(--brass);
  display: inline-flex;
  align-items: center;
  gap: 0.85em;
}
.kicker::before {
  content: "";
  width: 30px; height: 1px;
  background: currentColor;
  opacity: 0.65;
}
.lead { font-size: clamp(1.06rem, 1.6vw, 1.3rem); line-height: 1.55; color: var(--warm-gray); text-wrap: pretty; }

/* ------------------------------- Layout ------------------------------- */
.wrap { max-width: var(--maxw); margin-inline: auto; padding-inline: var(--gut); }
.section { padding-block: var(--sect); }
.section--dark { background: var(--ink); color: var(--cream-on-dark); }
/* Rytm strony: sekcje idą na zmianę złamana biel / cieplejszy beż, aż do
   stopki. Beż to --beige (ten sam panel co karty w kontakcie), a nie
   subtelniejszy odcień pośredni - przy tak długiej stronie słabszy kontrast gubił
   się i sąsiednie sekcje zlewały się w jedną płaszczyznę.
   .section--dark (opinie) stoi poza tym rytmem: to celowa przerwa, po
   której naprzemienność startuje od jasnej. */
.section--panel { background: var(--beige); }
/* Sekcja, która nie potrzebuje pełnego oddechu `--sect` - w opiniach treść
   jest jednym blokiem tekstu i listą, a nie siatką kafli, więc pełny margines
   robił z niej najwyższą sekcję strony. */
.section--tight { padding-block: clamp(56px, 6.5vw, 112px); }
.section--tight .shead { margin-bottom: clamp(26px, 3vw, 44px); }

/* ------------------------------- Buttons ------------------------------- */
.btn {
  --c: var(--graphite);
  position: relative;
  display: inline-flex;
  align-items: center;
  gap: 0.7em;
  padding: 1.02em 1.8em;
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0.13em;
  text-transform: uppercase;
  border-radius: 999px;
  overflow: hidden;
  isolation: isolate;
  transition: color 0.5s var(--ease), border-color 0.5s var(--ease);
  white-space: nowrap;
}
.btn .arr { transition: transform 0.5s var(--ease); }
.btn:hover .arr { transform: translateX(4px); }

.btn--solid { background: var(--graphite); color: var(--bone); }
.btn--solid::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: var(--brass);
  transform: translateY(101%);
  transition: transform 0.55s var(--ease);
}
.btn--solid:hover { color: var(--ink); }
.btn--solid:hover::before { transform: translateY(0); }

.btn--ghost { color: var(--c); border: 1px solid color-mix(in srgb, var(--c) 38%, transparent); }
.btn--ghost::before {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: var(--graphite);
  transform: scaleX(0); transform-origin: left;
  transition: transform 0.55s var(--ease);
}
.btn--ghost:hover { color: var(--bone); border-color: var(--graphite); }
.btn--ghost:hover::before { transform: scaleX(1); }
.btn--on-dark { --c: var(--cream-on-dark); }
.btn--on-dark::before { background: var(--brass); }
.btn--on-dark:hover { color: var(--ink); border-color: var(--brass); }

/* =========================================================================
   HEADER
   ========================================================================= */
.hdr {
  position: fixed; inset: 0 0 auto 0; z-index: 100;
  padding-block: clamp(16px, 2.2vw, 26px);
  transition: padding 0.5s var(--ease), background 0.5s var(--ease), box-shadow 0.5s var(--ease);
  color: var(--bone);
}
.hdr__row { display: flex; align-items: center; justify-content: space-between; gap: 24px; }
.hdr::after {
  content: ""; position: absolute; inset: 0; z-index: -1;
  background: color-mix(in srgb, var(--bone) 78%, transparent);
  backdrop-filter: blur(16px) saturate(1.1);
  -webkit-backdrop-filter: blur(16px) saturate(1.1);
  border-bottom: var(--hair);
  opacity: 0; transition: opacity 0.5s var(--ease);
}
.hdr.is-stuck { color: var(--graphite); padding-block: 13px; }
.hdr.is-stuck::after { opacity: 1; }

/* logo */
.logo { display: inline-flex; align-items: center; gap: 0.62em; }
.logo__mark {
  width: 34px; height: 34px; flex: none;
  display: grid; place-items: center;
  border: 1px solid currentColor; border-radius: 50%;
  font-family: var(--display); font-size: 1.18rem; font-weight: 600; line-height: 1;
  transition: background 0.5s var(--ease), color 0.5s var(--ease), border-color 0.5s var(--ease);
}
.hdr.is-stuck .logo__mark { border-color: var(--brass); color: var(--brass); }
.logo__txt { font-family: var(--display); font-size: 1.32rem; font-weight: 600; letter-spacing: 0.005em; line-height: 1; }
/* 10 px to dolna granica pisma na całej stronie - rozstrzelenie zeszło z 0.34em,
   żeby podpis po powiększeniu zajmował tyle samo miejsca co wcześniej */
.logo__txt small { display: block; font-family: var(--ui); font-size: 0.625rem; font-weight: 600; letter-spacing: 0.26em; text-transform: uppercase; opacity: 0.62; margin-top: 4px; }

/* nav */
.nav { display: flex; align-items: center; gap: clamp(20px, 2.4vw, 40px); }
.nav a {
  position: relative; font-size: 0.82rem; font-weight: 500; letter-spacing: 0.04em;
  padding-block: 6px; opacity: 0.92;
}
.nav a::after {
  content: ""; position: absolute; left: 50%; right: 50%; bottom: 0; height: 1px;
  background: var(--brass); transition: left 0.4s var(--ease), right 0.4s var(--ease);
}
.nav a:hover { opacity: 1; }
.nav a:hover::after { left: 0; right: 0; }

.hdr__cta { display: flex; align-items: center; gap: 14px; }

/* "Oblicz wycenę" przejmuje kolor nagłówka: nad filmem jest jasny (--bone),
   a po przewinięciu, gdy header dostaje jasne tło, staje się czarny
   (--graphite). Obsługuje to .hdr / .hdr.is-stuck - stąd currentColor,
   a nie kolor wpisany na sztywno. Ramka idzie za tekstem. */
.hdr__cta .btn--ghost { --c: currentColor; }

/* social - Instagram / TikTok */
.social { display: flex; align-items: center; gap: 6px; }
.social a {
  width: 36px; height: 36px; flex: none;
  display: grid; place-items: center;
  border: 1px solid color-mix(in srgb, currentColor 34%, transparent);
  border-radius: 50%;
  opacity: 0.92;
  transition: color 0.4s var(--ease), border-color 0.4s var(--ease), background 0.4s var(--ease), transform 0.4s var(--ease);
}
.social a:hover { color: var(--brass); border-color: var(--brass); transform: translateY(-2px); opacity: 1; }
.social svg { display: block; }

/* burger */
.burger { display: none; width: 30px; height: 18px; position: relative; }
.burger span { position: absolute; left: 0; height: 1.6px; width: 100%; background: currentColor; transition: transform 0.4s var(--ease), opacity 0.3s; }
.burger span:nth-child(1) { top: 0; }
.burger span:nth-child(2) { top: 50%; transform: translateY(-50%); }
.burger span:nth-child(3) { bottom: 0; }
body.menu-open .burger span:nth-child(1) { top: 50%; transform: translateY(-50%) rotate(45deg); }
body.menu-open .burger span:nth-child(2) { opacity: 0; }
body.menu-open .burger span:nth-child(3) { bottom: 50%; transform: translateY(50%) rotate(-45deg); }

/* mobile overlay
   Tło to nie płaski --ink, tylko ta sama „ciepła ciemność", którą ma hero
   i stopka: mosiężna poświata w lewym górnym rogu + delikatne rozjaśnienie
   ku górze. Dzięki temu menu czyta się jak część strony, a nie jak czarna
   plansza doklejona na wierzch. */
.mobile {
  position: fixed; inset: 0; z-index: 99;
  background:
    radial-gradient(118% 82% at 8% -6%, rgba(169,136,94,0.20), transparent 58%),
    linear-gradient(180deg, var(--ink-2) 0%, var(--ink) 62%);
  color: var(--cream-on-dark);
  display: flex; flex-direction: column; justify-content: center;
  padding: var(--gut);
  clip-path: inset(0 0 100% 0);
  transition: clip-path 0.7s var(--ease);
  pointer-events: none;
}
/* mosiężny włos pod nagłówkiem - domyka menu od góry */
.mobile::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 1px;
  background: linear-gradient(90deg, transparent, rgba(169,136,94,0.55) 24%, rgba(169,136,94,0.55) 72%, transparent);
  opacity: 0; transition: opacity 0.5s var(--ease) 0.25s;
}
body.menu-open .mobile { clip-path: inset(0 0 0 0); pointer-events: auto; }
body.menu-open .mobile::before { opacity: 1; }

/* Pozycje menu to indeks - numer w osobnej, wąskiej kolumnie, nazwa obok,
   włos pod spodem. Numer jest celowo drobny i uniesiony do wysokości
   wersalika: ma być sygnaturą, nie drugim napisem. */
.mobile__nav { display: flex; flex-direction: column; gap: 0; }
.mobile__nav a {
  position: relative;
  display: grid; grid-template-columns: 1.85em 1fr; align-items: baseline;
  font-family: var(--display); font-size: clamp(2.4rem, 11vw, 4.6rem); font-weight: 500; line-height: 1.06;
  padding-block: 0.16em;
  opacity: 0; transform: translateY(28px);
  transition: opacity 0.6s var(--ease), color 0.4s var(--ease);
}
.mobile__nav a span {
  font-family: var(--num); font-size: 0.625rem; font-weight: 600;
  letter-spacing: 0.16em; color: var(--brass);
  font-variant-numeric: tabular-nums lining-nums;
  transform: translateY(-0.72em);
  transition: color 0.4s var(--ease);
}
/* włos rozjeżdżający się w prawo razem z pojawieniem się pozycji */
.mobile__nav a::after {
  content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 1px;
  background: linear-gradient(90deg, rgba(169,136,94,0.42), rgba(169,136,94,0.07) 58%, transparent);
  transform: scaleX(0); transform-origin: left center;
  transition: transform 0.9s var(--ease);
}
body.menu-open .mobile__nav a::after { transform: scaleX(1); transition-delay: calc(var(--i) * 0.06s + 0.34s); }
.mobile__nav a:hover, .mobile__nav a:focus-visible { color: var(--brass-soft); }
.mobile__nav a:hover span, .mobile__nav a:focus-visible span { color: var(--brass-soft); }
body.menu-open .mobile__nav a { opacity: 1; transform: translateY(0); transition: opacity 0.6s var(--ease) calc(var(--i) * 0.06s + 0.2s), transform 0.6s var(--ease) calc(var(--i) * 0.06s + 0.2s); }
.mobile__foot { margin-top: clamp(36px, 6vh, 64px); display: flex; flex-wrap: wrap; gap: 28px; color: var(--muted-on-dark); font-size: 0.86rem; }
.mobile__foot a { color: var(--cream-on-dark); }

/* =========================================================================
   HERO
   ========================================================================= */
.hero { position: relative; min-height: 100svh; display: flex; align-items: flex-end; overflow: hidden; background: var(--ink); }
.hero__media { position: absolute; inset: 0; z-index: 0; }
.hero__video { display: block; width: 100%; height: 116%; object-fit: cover; object-position: center; will-change: transform; }
.hero__media::after {
  content: ""; position: absolute; inset: 0;
  background:
    linear-gradient(180deg, rgb(var(--ink-rgb) / 0.46) 0%, rgb(var(--ink-rgb) / 0.04) 26%, rgb(var(--ink-rgb) / 0.12) 56%, rgb(var(--ink-rgb) / 0.82) 100%),
    linear-gradient(95deg, rgb(var(--ink-rgb) / 0.5) 0%, rgb(var(--ink-rgb) / 0.0) 55%);
}
/* Blok tekstowy hero siedzi w LEWYM DOLNYM rogu: .hero jest flex-end (dół),
   .wrap trzyma lewą krawędź w jednej linii z resztą strony, a wąska kolumna
   poniżej nie pozwala treści rozjechać się na całą szerokość. */
/* Celowo ZDEJMUJEMY tu ograniczenia .wrap (max-width + margin-inline:auto),
   żeby hero mógł wyjść poza wspólną kolumnę 1480px.
   Odsunięcie od lewej to DOKŁADNIE średnia dwóch wariantów:
     --hero-col  = tak, jak liczy .wrap (kolumna 1480px + gutter)
     --hero-edge = pełny wyjazd do krawędzi kadru
   Efekt: ok. 163px @1920, 49px @1440, 35px @1024, 18px na telefonie. */
.hero__inner {
  --hero-col:  calc(max(0px, (100vw - var(--maxw)) / 2) + var(--gut));
  --hero-edge: clamp(16px, 1.8vw, 34px);
  position: relative; z-index: 2; width: 100%;
  max-width: none; margin-inline: 0;
  padding-inline: calc((var(--hero-col) + var(--hero-edge)) / 2);
  padding-bottom: clamp(52px, 9vh, 108px); padding-top: 160px;
}
.hero__kicker { color: var(--bone); opacity: 0.92; }
.hero__kicker::before { background: var(--brass); opacity: 1; }
.hero h1 {
  color: var(--bone);
  /* skala h3, nie h1 - znacznik zostaje <h1> ze względu na SEO */
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);
  line-height: 1.12;
  margin-top: 0.6em;
  max-width: 26ch;
}
.hero h1 em { font-style: italic; color: var(--brass-soft); }
/* wcięcie drugiej linii przeskalowane do mniejszego stopnia pisma */
.hero h1 .indent { display: inline-block; margin-left: clamp(14px, 2.6vw, 46px); }
/* margin-top celowo mały - podtytuł ma siedzieć TUŻ pod nagłówkiem.
   Odstęp do przycisków robi natomiast `gap`, nie ten margines. */
/* 56ch, nie 46. Przy 46ch kolumna miała 429 px, a pierwszy wiersz
   zaprojektowanego zdania („Tworzę wnętrza dopasowane do Ciebie - od układu
   funkcjonalnego") potrzebuje ~500 px: „funkcjonalnego" zostawało samo
   w drugim wierszu, a wymuszony <br> zaczynał trzeci. Akapit szedł na cztery
   wiersze o szerokościach 382/113/392/70 - dwie sieroty pod sobą, na każdej
   szerokości desktopu. Przy 56ch wraca podział z HTML: zdanie, <br>, zdanie.
   Bloki mobilne (max-width: 820px i 560px) nadpisują to niżej, więc telefon
   zostaje bez zmian. */
.hero__bottom { display: flex; flex-direction: column; align-items: flex-start; gap: clamp(18px, 2.6vh, 26px); margin-top: clamp(6px, 0.9vh, 12px); max-width: 56ch; }
.hero__sub { color: var(--cream-on-dark); max-width: 56ch; font-size: clamp(0.94rem, 1.05vw, 1.04rem); opacity: 0.9; }
.hero__actions { display: flex; flex-wrap: wrap; gap: 14px; }

/* scroll cue */
.hero__scroll {
  /* z prawej strony - lewy dolny róg zajmuje teraz blok tekstowy */
  position: absolute; right: var(--gut); bottom: clamp(20px, 4vh, 38px); z-index: 3;
  display: flex; align-items: center; gap: 12px; color: var(--bone);
  font-size: 0.68rem; letter-spacing: 0.24em; text-transform: uppercase; opacity: 0.8;
}
.hero__scroll i { display: block; width: 1px; height: 46px; background: linear-gradient(var(--bone), transparent); position: relative; overflow: hidden; }
.hero__scroll i::after { content: ""; position: absolute; top: -50%; left: 0; width: 100%; height: 50%; background: var(--brass); animation: scrolldrop 2.2s var(--ease) infinite; }
@keyframes scrolldrop { 0% { top: -50%; } 60%,100% { top: 100%; } }

/* hero entrance - visible is the BASE (no-JS / first paint shows content).
   .is-in flips opacity STATICALLY (instant, never depends on animation timing),
   so content is guaranteed visible the moment it's revealed. The keyframe
   animates transform only - pure motion polish. If a backgrounded tab ever
   throttles the animation, content is at most shifted, never invisible. */
.hero [data-anim] { opacity: 1; transform: none; }
html.js .hero [data-anim] { opacity: 0; }
html.js .hero.is-in [data-anim] {
  opacity: 1;
  animation: riseY 1s var(--ease) both;
  animation-delay: calc(var(--d, 0) * 1s);
}

@keyframes riseY {
  from { transform: translateY(34px); }
  to   { transform: translateY(0); }
}

/* trust strip */
.trust { border-top: var(--hair); }
/* pasek zaufania ma trzymać się sekcji pod spodem, a nie wisieć w połowie drogi */
.trust + .section { padding-top: clamp(40px, 5vw, 76px); }
.trust .wrap { display: flex; flex-wrap: wrap; gap: clamp(20px,4vw,60px); align-items: center; justify-content: space-between; padding-block: 26px; }
.trust span { font-size: 0.8rem; letter-spacing: 0.08em; color: var(--warm-gray); display: inline-flex; align-items: center; gap: 0.7em; }
.trust span b { color: var(--graphite); font-weight: 600; font-family: var(--display); font-size: 1.5rem; }

/* =========================================================================
   SECTION HEAD (shared)
   ========================================================================= */
.shead { display: grid; grid-template-columns: 1.1fr 0.9fr; gap: clamp(24px, 5vw, 80px); align-items: end; margin-bottom: clamp(44px, 6vw, 80px); }
.shead h2 { font-size: clamp(2.4rem, 5.4vw, 4.6rem); }
.shead .lead { padding-bottom: 0.3em; }
/* Nagłówek sekcji na czerni (opinie): --warm-gray z domyślnego `.lead` jest
   ciemnoszary i na czarnym tle praktycznie znika. */
.section--dark .shead h2 { color: var(--bone); }
.section--dark .lead { color: var(--muted-on-dark); }
/* Zdanie nad tabelą typów projektu wyrównane do prawej krawędzi siatki -
   domyka nagłówek sekcji z drugiej strony i prowadzi wzrok wprost na kafle.
   Krój zostaje ten sam co w pozostałych `.lead` (Hanken Grotesk). */
.offer__lead { text-align: right; }
@media (max-width: 860px){
  .shead { grid-template-columns: 1fr; }
  /* w jednej kolumnie tekst wraca do lewej - wyrównanie do prawej pod
     nagłówkiem wyglądałoby jak pomyłka, a nie jak decyzja */
  .offer__lead { text-align: left; }
}

/* =========================================================================
   INTRO / MANIFEST
   ========================================================================= */
.intro__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: color-mix(in srgb, var(--brass) 26%, var(--ink)); border: 1px solid color-mix(in srgb, var(--brass) 26%, var(--ink)); border-radius: 3px; overflow: hidden; margin-top: clamp(40px,6vw,72px); }
.intro__cell { background: var(--ink); color: var(--cream-on-dark); padding: clamp(26px, 3vw, 40px); transition: background 0.5s var(--ease); }
.intro__cell:hover { background: var(--ink-2); }
.intro__cell .n { font-family: var(--display); font-size: 1.1rem; color: var(--brass-soft); margin-bottom: 18px; }
.intro__cell h3 { font-family: var(--display); font-size: 1.6rem; font-weight: 500; line-height: 1.1; margin-bottom: 10px; color: var(--bone); }
.intro__cell p { font-size: 0.95rem; color: var(--muted-on-dark); }
@media (max-width: 900px){ .intro__grid { grid-template-columns: repeat(2,1fr); } }
@media (max-width: 520px){ .intro__grid { grid-template-columns: 1fr; } }

/* =========================================================================
   PORTFOLIO
   ========================================================================= */
.pf__filter { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: clamp(34px, 4vw, 56px); }
.chip {
  padding: 0.6em 1.25em; border-radius: 999px; border: var(--hair);
  font-size: 0.78rem; letter-spacing: 0.05em; color: var(--warm-gray);
  transition: all 0.4s var(--ease);
}
.chip:hover { color: var(--graphite); border-color: var(--graphite); }
.chip.is-on { background: var(--graphite); color: var(--bone); border-color: var(--graphite); }

.pf__grid { display: grid; grid-template-columns: repeat(12, 1fr); gap: clamp(14px, 1.6vw, 26px); }
/* Za mało kafli, żeby domknąć rząd (po filtrze kategorii zwykle jeden) -
   wtedy zamiast zostawiać dwie trzecie pustego rzędu po prawej, ustawiamy
   je na środku. Klasę dokłada app.js; proporcje kafli zostają te same,
   bo aspect-ratio z .tall / .wide działa też we flexie. */
.pf__grid.is-sparse { display: flex; flex-wrap: wrap; justify-content: center; }
.pf__grid.is-sparse .pf__item { flex: 0 1 clamp(260px, 31%, 430px); }
.pf__item { position: relative; overflow: hidden; background: var(--ink); border-radius: 2px; }
.pf__item.tall { grid-column: span 4; aspect-ratio: 4 / 5.2; }
.pf__item.wide { grid-column: span 8; aspect-ratio: 16 / 10.4; }
/* Widok jednej kategorii (klasa .is-cat dokładana przez app.js): osiem kafli,
   cztery i cztery. Siatka ma 12 kolumn, więc kafel bierze 3, a wspólne
   aspect-ratio daje im wszystkim dokładnie ten sam rozmiar - kadry z galerii
   mają różne proporcje, dopasowuje je object-fit: cover na .pf__img.
   Podpis jest mniejszy niż na dużych kaflach „Wszystkich", bo kafel jest
   węższy i „Komunikacja / Hole" nie zmieściłoby się w jednym wierszu. */
.pf__item.sq { grid-column: span 3; aspect-ratio: 4 / 5; }
.pf__grid.is-cat .pf__meta { padding: clamp(12px, 1.2vw, 18px); }
.pf__grid.is-cat .pf__meta h3 { font-size: clamp(1.02rem, 1.35vw, 1.4rem); }
.pf__grid.is-cat .pf__arrow { width: 36px; height: 36px; }
/* Kafle strony głównej to zwykłe <img>, nie <image-slot> - tak samo jak
   galeria na podstronie. Powód jest podwójny: <image-slot> wstawiał obrazek
   do shadow DOM z pustym alt i bez loading="lazy", więc sześć zdjęć spod
   pierwszego ekranu (2,9 MB) pobierało się od razu, a Grafika Google nie
   miała czego zaindeksować. */
.pf__item .pf__img { width: 100%; height: 100%; object-fit: cover; display: block; transition: transform 1.1s var(--ease); }
.pf__item:hover .pf__img { transform: scale(1.05); }
.pf__shade { position: absolute; inset: 0; background: linear-gradient(180deg, transparent 38%, rgb(var(--ink-rgb) / 0.0) 50%, rgb(var(--ink-rgb) / 0.74) 100%); opacity: 0; transition: opacity 0.6s var(--ease); pointer-events: none; }
.pf__item:hover .pf__shade { opacity: 1; }
.pf__meta { position: absolute; left: 0; right: 0; bottom: 0; padding: clamp(18px, 2vw, 30px); color: var(--bone); display: flex; align-items: flex-end; justify-content: space-between; gap: 16px; transform: translateY(12px); opacity: 0; transition: all 0.55s var(--ease); pointer-events: none; }
.pf__item:hover .pf__meta { transform: none; opacity: 1; }
.pf__meta h3 { font-family: var(--display); font-size: clamp(1.4rem, 2.2vw, 2.1rem); font-weight: 500; line-height: 1; }
.pf__meta p { font-size: 0.82rem; color: var(--cream-on-dark); opacity: 0.85; margin-top: 6px; }
.pf__cat { position: absolute; top: clamp(16px,1.6vw,22px); left: clamp(16px,1.6vw,22px); font-size: 0.66rem; letter-spacing: 0.2em; text-transform: uppercase; color: var(--bone); background: rgb(var(--ink-rgb) / 0.34); backdrop-filter: blur(6px); padding: 0.5em 0.9em; border-radius: 999px; opacity: 0; transition: opacity 0.5s var(--ease); }
.pf__item:hover .pf__cat { opacity: 1; }
.pf__arrow { width: 44px; height: 44px; border-radius: 50%; border: 1px solid rgba(245,240,232,0.5); display: grid; place-items: center; flex: none; }
/* Kafle kategorii schodzą do dwóch w rzędzie wcześniej niż kafle „Wszystkich"
   do jednego: przy czterech w rzędzie poniżej ~1000 px zdjęcie robi się
   miniaturką. Ośmiu kafli nie stawiamy w jednej kolumnie nawet na telefonie -
   to byłby ekran przewijania zamiast podglądu kategorii. */
@media (max-width: 1000px){
  .pf__item.sq { grid-column: span 6; }
}
@media (max-width: 760px){
  .pf__item.tall, .pf__item.wide { grid-column: span 12; }
  .pf__item.wide { aspect-ratio: 16/11; }
  .pf__item.tall { aspect-ratio: 4/4.4; }
}

/* =========================================================================
   BANNER - full-bleed statement (Omnires-style)
   ========================================================================= */
/* Zdjęcie i tekst leżą w tej samej komórce siatki: kadr nie jest przycinany -
   to on wyznacza wysokość sekcji, a napis nakłada się na jego dolną część. */
.banner { position: relative; display: grid; overflow: hidden; background: var(--ink); }
.banner__img { grid-area: 1 / 1; align-self: start; width: 100%; height: auto; z-index: 0; display: block; }
.banner::after { content: ""; position: absolute; inset: 0; z-index: 1; pointer-events: none;
  background: linear-gradient(180deg, rgb(var(--ink-rgb) / 0.22) 0%, rgb(var(--ink-rgb) / 0.08) 42%, rgb(var(--ink-rgb) / 0.84) 100%); }
/* Wcięcie od krawędzi i odstęp od dołu liczone tak samo jak w hero
   (patrz .hero__inner), żeby oba napisy stały w jednej linii pionowej. */
.banner__inner {
  --hero-col:  calc(max(0px, (100vw - var(--maxw)) / 2) + var(--gut));
  --hero-edge: clamp(16px, 1.8vw, 34px);
  grid-area: 1 / 1; align-self: end;
  position: relative; z-index: 2; width: 100%;
  max-width: none; margin-inline: 0;
  padding-inline: calc((var(--hero-col) + var(--hero-edge)) / 2);
  padding-block: clamp(52px, 9vh, 108px);
  color: var(--bone);
}
.banner__inner .kicker { color: var(--bone); opacity: 0.92; }
.banner__inner .kicker::before { background: var(--brass); opacity: 1; }
/* Napis w tej samej skali i rytmie co nagłówek w hero. */
.banner__inner h2 {
  color: var(--bone);
  font-size: clamp(1.5rem, 2.6vw, 2.25rem);
  line-height: 1.12;
  margin: 0.6em 0 clamp(20px, 2.6vh, 30px);
  max-width: 26ch;
}
.banner__inner h2 em { font-style: italic; color: var(--brass-soft); }
.banner__inner h2 .indent { display: inline-block; margin-left: clamp(14px, 2.6vw, 46px); }
/* Na telefonie napis ZOSTAJE NA ZDJĘCIU, tak samo jak na desktopie.
   Wcześniej banner rozpadał się tu na dwa bloki - kadr u góry, tekst pod nim
   na czarnym tle - i wyglądał jak osobny kafelek doklejony do fotografii.
   Powód był techniczny: zdjęcie ma 2000×845, więc przy 390 px szerokości
   schodzi do 158 px wysokości i napis nie ma na czym usiąść.
   Rozwiązanie: nadajemy sekcji własną wysokość i przycinamy kadr przez
   object-fit: cover (panorama traci boki, zostaje środek - kanapy, stolik
   i jadalnia w głębi). Tekst wraca na swoje miejsce, w lewy dolny róg. */
@media (max-width: 900px){
  /* Wysokość dobrana tak, żeby górne ~38% kadru zostało czystym zdjęciem,
     a blok tekstu (ok. 220 px) zmieścił się poniżej, w strefie przyciemnienia. */
  .banner { min-height: clamp(400px, 112vw, 540px); grid-template-rows: 1fr; }
  .banner__img {
    align-self: stretch;
    height: 100%;
    object-fit: cover;
    object-position: 50% 50%;
  }
  .banner__inner { padding-block: clamp(30px, 7vw, 46px); }
  /* Progi gradientu nie są „na oko" - policzone przez złożenie tego gradientu
     z realnymi pikselami zdjęcia w tym kadrze. Górne 42% kadru zostaje
     praktycznie czyste (alpha ≤ 0.05), potem 61-pikselowa rampa do 0.66 -
     na tyle długa, żeby nie było widać krawędzi, i na tyle mocna, żeby
     kremowy napis trzymał kontrast. Najciaśniej jest pod kickerem (drobny
     tekst, wymóg 4.5:1) - wychodzi 5.6:1 przy 320 px i 6.3:1 przy 390 px.
     Jeśli podmienisz zdjęcie na jaśniejsze, te progi trzeba przeliczyć. */
  .banner::after {
    background: linear-gradient(180deg,
      rgb(var(--ink-rgb) / 0.28) 0%,
      rgb(var(--ink-rgb) / 0.03) 20%,
      rgb(var(--ink-rgb) / 0.05) 42%,
      rgb(var(--ink-rgb) / 0.66) 56%,
      rgb(var(--ink-rgb) / 0.80) 76%,
      rgb(var(--ink-rgb) / 0.91) 100%);
  }
}

/* =========================================================================
   OFERTA - 8 typów
   ========================================================================= */
.offer__grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: color-mix(in srgb, var(--brass) 24%, var(--ink)); border: 1px solid color-mix(in srgb, var(--brass) 24%, var(--ink)); border-radius: 3px; overflow: hidden; }
.tcard { background: var(--ink); color: var(--cream-on-dark); padding: clamp(24px, 2vw, 34px); display: flex; flex-direction: column; gap: 16px; min-height: 280px; transition: background 0.5s var(--ease); position: relative; }
.tcard:hover { background: var(--ink-2); }
.tcard__top { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; }
.tcard__n { font-family: var(--num); font-size: 2rem; font-weight: 500; line-height: 0.86; letter-spacing: -0.03em; font-variant-numeric: tabular-nums lining-nums; color: var(--bone); }
.tcard__n small { font-size: 0.625rem; font-family: var(--ui); font-weight: 600; letter-spacing: 0.2em; color: var(--brass-soft); text-transform: uppercase; display: block; margin-bottom: 8px; }
.tcard h3 { font-family: var(--display); font-size: 1.42rem; font-weight: 500; line-height: 1.08; color: var(--bone); }
.tcard p { font-size: 0.88rem; color: var(--muted-on-dark); flex: 1; }
.tcard__price { display: flex; align-items: baseline; gap: 0.3em; padding-top: 14px; border-top: 1px solid rgba(201,183,158,0.24); }
.tcard__price b { font-family: var(--num); font-size: 1.52rem; font-weight: 600; letter-spacing: -0.02em; line-height: 1; font-variant-numeric: tabular-nums lining-nums; color: var(--brass-soft); }
.tcard__price span { font-family: var(--ui); font-size: 0.72rem; font-weight: 500; color: var(--muted-on-dark); letter-spacing: 0.06em; }
.tcard.is-featured { background: var(--ink-2); box-shadow: inset 0 0 0 1.5px var(--brass); z-index: 1; }
.tcard.is-featured:hover { background: var(--ink-2); }
.tcard.is-featured .badge { position: absolute; top: 22px; right: 24px; font-size: 0.625rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--brass-soft); }
@media (max-width: 1080px){ .offer__grid { grid-template-columns: repeat(2,1fr); } }
@media (max-width: 540px){ .offer__grid { grid-template-columns: 1fr; } }

/* Notki są trzy - „Łączenie typów", „Małe pomieszczenia" i Moodboard - i mają
   stać w JEDNYM rzędzie obok siebie (Szkic Projektu ma własny panel niżej, więc
   nie wchodzi tu jako czwarta, bo rząd rozpadłby się na 2 + 2). `max-width` na
   akapicie pilnuje, żeby przy szerokiej kolumnie wiersz nie zrobił się za długi. */
.offer__note { display: grid; grid-template-columns: repeat(3, 1fr); gap: clamp(20px,3vw,44px); margin-top: clamp(34px,4vw,56px); }
.offer__note > div { padding-top: 20px; border-top: 2px solid var(--graphite); }
.offer__note h4 { font-family: var(--display); font-size: 1.3rem; font-weight: 500; margin-bottom: 8px; }
.offer__note p { font-size: 0.9rem; color: var(--warm-gray); max-width: 52ch; }
/* Moodboard siedzi w notce, ale ma dwie ceny - każdy wariant w jednej linijce,
   żeby notka nie urosła do rozmiaru osobnego panelu jak Szkic Projektu. */
.note__prices { list-style: none; margin-top: 14px; display: grid; gap: 8px; max-width: 52ch; }
.note__prices li { display: flex; align-items: baseline; justify-content: space-between; gap: 14px; padding-top: 8px; border-top: 1px solid color-mix(in srgb, var(--graphite) 16%, transparent); font-size: 0.9rem; }
.note__prices span { color: var(--warm-gray); }
.note__prices b { font-family: var(--num); font-variant-numeric: tabular-nums; font-weight: 600; color: var(--brass); white-space: nowrap; }
/* Poniżej ~1080 px trzy kolumny robią się węższe niż akapit potrzebuje, więc
   schodzimy na dwie (trzecia notka ląduje w drugim rzędzie), a na wąskim
   ekranie na jedną. */
@media (max-width: 1080px){ .offer__note { grid-template-columns: repeat(2, 1fr); } }
@media (max-width: 820px){ .offer__note { grid-template-columns: 1fr; } }

/* Odnośnik do przykładowych składowych - pod kaflami typów, wyrównany do
   prawej jak „Zobacz pełne portfolio", żeby oba czytały się jak to samo
   „idź dalej". Na wąskim ekranie do lewej, bo inaczej wisi w powietrzu. */
.offer__more { margin-top: clamp(24px, 3vw, 40px); display: flex; justify-content: flex-end; }
@media (max-width: 700px){ .offer__more { justify-content: flex-start; } }

/* Szkic Projektu - osobna usługa pod tabelą typów. Beżowy panel odróżnia ją
   od ciemnych kafli: to inna forma współpracy i inna jednostka ceny
   (ryczałt za całość, a nie zł/m²), więc nie powinna udawać dziewiątego typu. */
.sketch {
  margin-top: clamp(28px, 3.5vw, 48px);
  padding: clamp(24px, 3vw, 40px);
  background: var(--beige);
  border-radius: 3px;
}
.sketch__title { font-family: var(--display); font-size: clamp(1.3rem, 2vw, 1.7rem); font-weight: 500; margin-bottom: clamp(18px, 2vw, 26px); }
.sketch__pkgs { display: grid; grid-template-columns: repeat(2, 1fr); gap: clamp(20px, 3vw, 44px); }
.sketch__pkg {
  display: flex; flex-direction: column; gap: 10px;
  padding-top: 16px;
  border-top: 1px solid color-mix(in srgb, var(--graphite) 22%, transparent);
}
.sketch__pkg h5 { font-family: var(--display); font-size: 1.16rem; font-weight: 600; line-height: 1.15; }
/* flex:1 wyrównuje ceny obu pakietów do jednej linii, mimo że opisy mają
   różną długość - inaczej „390 zł" wisiałoby wyżej niż „290 zł" */
.sketch__pkg p { font-size: 0.9rem; color: var(--warm-gray); flex: 1; }
.sketch__price { display: flex; align-items: baseline; gap: 0.35em; font-family: var(--num); font-variant-numeric: tabular-nums; }
.sketch__price b { font-size: clamp(1.5rem, 2.4vw, 2rem); font-weight: 600; color: var(--brass); line-height: 1; }
.sketch__price span { font-size: 0.78rem; color: var(--warm-gray); letter-spacing: 0.06em; }
.sketch__note { margin-top: clamp(20px, 2.4vw, 30px); padding-top: 16px; border-top: var(--hair); font-size: 0.84rem; color: var(--warm-gray); max-width: 80ch; }
/* Zdanie-zaczepka nad przyciskiem w sekcji „O mnie" - przycisk ma być krótki,
   więc pytanie zostaje osobnym akapitem. */
.about__cta { margin-top: 6px; }
@media (max-width: 700px){ .sketch__pkgs { grid-template-columns: 1fr; } }

/* =========================================================================
   KALKULATOR
   ========================================================================= */
.calc { display: grid; grid-template-columns: 1.05fr 0.95fr; gap: 1px; background: rgba(201,183,158,0.28); border: 1px solid rgba(201,183,158,0.4); border-radius: 4px; overflow: hidden; }
.calc__form { background: var(--bone); padding: clamp(28px, 3.4vw, 56px); }
.calc__out { background: var(--ink); color: var(--cream-on-dark); padding: clamp(28px, 3.4vw, 56px); display: flex; flex-direction: column; }
.field { margin-bottom: 26px; }
.field > label { display: block; font-size: 0.72rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--warm-gray); margin-bottom: 12px; }
.area-input { display: flex; align-items: baseline; gap: 10px; border-bottom: 1.5px solid var(--graphite); padding-bottom: 10px; }
.area-input input { width: 100%; border: none; background: none; font-family: var(--num); font-size: clamp(1.9rem, 4.2vw, 2.7rem); font-weight: 600; letter-spacing: -0.03em; font-variant-numeric: tabular-nums lining-nums; color: var(--graphite); outline: none; }
.area-input input::-webkit-outer-spin-button, .area-input input::-webkit-inner-spin-button { -webkit-appearance: none; }
.area-input input { -moz-appearance: textfield; }
.area-input span { font-size: 1rem; color: var(--warm-gray); white-space: nowrap; }
.range { width: 100%; margin-top: 18px; -webkit-appearance: none; appearance: none; height: 1.5px; background: var(--taupe); outline: none; }
.range::-webkit-slider-thumb { -webkit-appearance: none; width: 22px; height: 22px; border-radius: 50%; background: var(--graphite); cursor: pointer; transition: background .3s, transform .3s; }
.range::-webkit-slider-thumb:hover { background: var(--brass); transform: scale(1.12); }
.range::-moz-range-thumb { width: 22px; height: 22px; border: none; border-radius: 50%; background: var(--graphite); cursor: pointer; }

.types { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; }
.types button { aspect-ratio: 1; border: var(--hair); border-radius: 3px; display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 4px; transition: all 0.35s var(--ease); }
.types button .tn { font-family: var(--num); font-size: 1.16rem; font-weight: 600; letter-spacing: -0.02em; line-height: 1; font-variant-numeric: tabular-nums lining-nums; color: var(--graphite); }
.types button .tp { font-family: var(--num); font-size: 0.625rem; font-weight: 500; letter-spacing: 0.01em; font-variant-numeric: tabular-nums lining-nums; color: var(--warm-gray); }
.types button:hover { border-color: var(--graphite); }
.types button.is-on { background: var(--graphite); border-color: var(--graphite); }
.types button.is-on .tn { color: var(--bone); }
.types button.is-on .tp { color: var(--brass-soft); }
.types__name { margin-top: 12px; font-size: 0.9rem; color: var(--warm-gray); min-height: 1.4em; }
.types__name b { color: var(--graphite); font-weight: 600; }

/* text-align: left, bo <button> dziedziczy z UA wyśrodkowanie - widać to
   dopiero, gdy opis łamie się na dwa wiersze (czyli na telefonie). */
.toggle { display: flex; align-items: center; gap: 14px; cursor: pointer; padding: 16px 0; border-top: var(--hair); margin-top: 6px; text-align: left; }
.toggle__sw { width: 48px; height: 26px; border-radius: 999px; background: var(--taupe); position: relative; flex: none; transition: background 0.35s var(--ease); }
.toggle__sw::after { content: ""; position: absolute; top: 3px; left: 3px; width: 20px; height: 20px; border-radius: 50%; background: var(--bone); transition: transform 0.35s var(--ease); }
.toggle.is-on .toggle__sw { background: var(--brass); }
.toggle.is-on .toggle__sw::after { transform: translateX(22px); }
.toggle__txt b { display: block; font-weight: 600; font-size: 0.95rem; }
.toggle__txt span { font-size: 0.8rem; color: var(--warm-gray); }

/* output */
.calc__out .kicker { color: var(--brass-soft); }
.calc__out .kicker::before { background: var(--brass-soft); }
.out__label { font-size: 0.74rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--muted-on-dark); margin-bottom: 8px; }
.out__price { font-family: var(--num); font-weight: 600; line-height: 0.98; letter-spacing: -0.035em; font-variant-numeric: tabular-nums lining-nums; color: var(--bone); display: flex; align-items: baseline; gap: 0.22em; }
.out__price .val { font-size: clamp(2.5rem, 6.4vw, 4.2rem); }
.out__price .cur { font-size: clamp(1rem, 1.9vw, 1.4rem); font-weight: 500; letter-spacing: 0.02em; color: var(--brass-soft); }
.out__rows { margin: 26px 0; display: flex; flex-direction: column; gap: 0; }
.out__rows .r { display: flex; justify-content: space-between; gap: 16px; padding: 11px 0; border-bottom: 1px solid rgba(201,183,158,0.18); font-size: 0.9rem; }
.out__rows .r span:first-child { color: var(--muted-on-dark); }
.out__rows .r span:last-child { color: var(--cream-on-dark); font-variant-numeric: tabular-nums; }
.out__rows .r.discount span:last-child { color: var(--brass-soft); }
.disclaimer { font-size: 0.82rem; color: var(--muted-on-dark); line-height: 1.5; margin: 18px 0 26px; padding-left: 16px; border-left: 1px solid var(--brass); }
.calc__out .btn { width: 100%; justify-content: center; }
.calc__cta { margin-top: auto; }
.calc__small { /* below 10m message */ background: rgba(169,136,94,0.14); border: 1px solid rgba(190,156,110,0.4); border-radius: 4px; padding: 22px; font-size: 0.92rem; color: var(--cream-on-dark); line-height: 1.55; }
.calc__small b { color: var(--bone); font-weight: 600; }
.is-hidden { display: none !important; }
@media (max-width: 880px){ .calc { grid-template-columns: 1fr; } .types { grid-template-columns: repeat(4,1fr); } }
@media (max-width: 420px){ .types { grid-template-columns: repeat(4,1fr); gap: 6px; } }

/* =========================================================================
   PROCES - editorial steps
   ========================================================================= */
.proc__grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px; background: color-mix(in srgb, var(--taupe) 40%, transparent); border-top: var(--hair); border-left: var(--hair); }
/* Kafle kroków są czarne, mimo że sekcja stoi na beżowym takcie rytmu
   (.section--panel). Typografia w środku idzie więc na wersję
   „na ciemnym" - kość na nagłówki, przygaszony krem na opisy, jaśniejszy
   mosiądz na numery. Włos rozdzielający kafle zostaje na regule bazowej
   (taupe 40%): na czarnych kaflach czyta się jasno, a przy krawędzi siatki
   wtapia się w beż sekcji. */
.proc__step { background: var(--ink); padding: clamp(28px, 3vw, 46px); display: flex; gap: clamp(18px, 2vw, 30px); position: relative; }
.proc__step .pn { font-family: var(--display); font-size: clamp(1.6rem, 2.4vw, 2.3rem); color: var(--brass-soft); line-height: 1; flex: none; }
.proc__step h3 { font-family: var(--display); font-size: clamp(1.4rem, 2vw, 1.85rem); font-weight: 500; line-height: 1.08; margin-bottom: 10px; color: var(--bone); }
.proc__step p { font-size: 0.94rem; color: var(--muted-on-dark); }
@media (max-width: 720px){ .proc__grid { grid-template-columns: 1fr; } }

/* =========================================================================
   CZAS REALIZACJI
   ========================================================================= */
.timeline { border-top: var(--hair); }
.timeline__row { display: grid; grid-template-columns: auto 1fr auto; align-items: baseline; gap: clamp(16px, 4vw, 60px); padding: clamp(22px, 2.6vw, 34px) 0; border-bottom: var(--hair); transition: padding-left 0.5s var(--ease); }
.timeline__row:hover { padding-left: 14px; }
.timeline__row .idx { font-size: 0.74rem; letter-spacing: 0.16em; color: var(--brass); font-variant-numeric: tabular-nums; }
.timeline__row .lbl { font-family: var(--display); font-size: clamp(1.5rem, 3vw, 2.4rem); font-weight: 500; line-height: 1; }
.timeline__row .time { font-size: clamp(1rem, 1.6vw, 1.2rem); color: var(--warm-gray); white-space: nowrap; }
@media (max-width: 600px){ .timeline__row { grid-template-columns: 1fr; gap: 6px; } .timeline__row .idx { order: -1; } }

/* =========================================================================
   OPINIE - slider
   ========================================================================= */
/* Sekcja jest korespondencją, nie „kartami z opiniami": po lewej jedna
   wiadomość, po prawej spis nadawców, który zarazem przełącza slajdy.
   Spis celowo BEZ numerów - to lista osób, a nie sekwencja etapów. */
/* Te same proporcje i odstęp co `.shead` - spis nadawców staje wtedy dokładnie
   pod leadem nagłówka i prawa strona sekcji ma jedną oś zamiast dziury. */
/* minmax(0, …) jest tu konieczne: w kolumnie z wiadomością siedzi flexowy tor
   pięciu slajdów z `min-width:100%`, więc automatyczne minimum kolumny to suma
   ich min-contentów - bez tego kolumna puchnie i osie się rozjeżdżają. */
.rev { display: grid; grid-template-columns: minmax(0, 1.1fr) minmax(0, 0.9fr); gap: clamp(24px, 5vw, 80px); align-items: start; }
/* Okno slidera. Wysokość dokłada app.js pod aktywny slajd - i BEZ animacji.
   `transition: height` tu nie wolno: kiedy dokument jest niewidoczny (inna
   karta, zgaszony ekran) przejście nie postępuje, wysokość zostaje na starej
   wartości, a `overflow: hidden` ucina resztę wiadomości. To ta sama pułapka
   co z `aspect-ratio` w portfolio. Ruch i tak niesie przesuwanie poziome. */
.rev__view { overflow: hidden; }
.rev__track { display: flex; align-items: flex-start; transition: transform 0.7s var(--ease); }
.rev__slide { min-width: 100%; }
/* 70ch to wciąż poniżej granicy czytelności (~80 znaków), a na szerokim
   ekranie ścina najdłuższym wiadomościom kilkadziesiąt pikseli wysokości. */
.rev__msg, .rev__who { max-width: 70ch; }
/* Fraza wiodąca: pierwsze zdanie klienta. Cała reszta wiadomości jest
   groteskiem - kilkaset znaków kursywy Cormoranta to ściana, nie cytat. */
.rev__lead { font-family: var(--display); font-weight: 500; font-style: italic; font-size: clamp(1.35rem, 2.1vw, 1.95rem); line-height: 1.22; letter-spacing: -0.01em; color: var(--bone); text-wrap: balance; }
.rev__body { margin-top: clamp(14px, 1.5vw, 20px); color: color-mix(in srgb, var(--cream-on-dark) 78%, transparent); font-size: 1rem; line-height: 1.6; text-wrap: pretty; }
.rev__body p + p { margin-top: 0.8em; }
/* Podpis jak pod listem: włos nad spodem wiadomości, imię Cormorantem. */
.rev__who { display: flex; flex-wrap: wrap; align-items: baseline; gap: 4px 16px; margin-top: clamp(18px, 2vw, 26px); padding-top: 14px; border-top: 1px solid color-mix(in srgb, var(--brass) 34%, transparent); }
.rev__who .nm { font-family: var(--display); font-size: 1.32rem; font-weight: 600; color: var(--bone); }
/* Zakres projektu stoi w podświetlonym wierszu spisu obok - pod wiadomością
   byłby drugi raz to samo, o dwa centymetry dalej. Wraca dopiero na wąskim
   ekranie, gdzie spis zwija się do znaczników (patrz media query niżej). */
.rev__who .mt { display: none; color: var(--muted-on-dark); font-size: 0.88rem; }
/* Prawa kolumna trzyma spis i strzałki razem jako jeden element siatki.
   Osobne wiersze gridu odpadają: kolumna z wiadomością jest wyższa, więc
   nadmiar rozkładał się na wiersze i strzałki odjeżdżały od spisu. */
.rev__side { display: flex; flex-direction: column; }
.rev__nav { display: flex; gap: 12px; margin-top: clamp(20px, 2.4vw, 30px); }
.rev__nav button { width: 54px; height: 54px; border-radius: 50%; border: 1px solid rgba(201,183,158,0.34); color: var(--cream-on-dark); display: grid; place-items: center; transition: all 0.4s var(--ease); }
.rev__nav button:hover { background: var(--brass); border-color: var(--brass); color: var(--ink); }

/* Spis nadawców */
.rev__index { list-style: none; border-top: 1px solid color-mix(in srgb, var(--brass) 20%, transparent); }
.rev__index li { border-bottom: 1px solid color-mix(in srgb, var(--brass) 20%, transparent); }
.rev__pick { position: relative; display: flex; align-items: baseline; justify-content: space-between; gap: 18px; width: 100%; text-align: left; padding: 11px 0; font-family: var(--display); font-size: 1.14rem; line-height: 1.2; color: var(--muted-on-dark); transition: color 0.4s var(--ease), padding-left 0.5s var(--ease); }
.rev__pick .mt { flex: none; font-family: var(--ui); font-size: 0.78rem; letter-spacing: 0.02em; color: color-mix(in srgb, var(--muted-on-dark) 74%, transparent); text-align: right; }
.rev__pick:hover { color: var(--cream-on-dark); }
/* Aktywny nadawca odsuwa się od krawędzi i „wyciąga" mosiężny znacznik -
   ten sam ruch, co przy przewijaniu wiadomości, więc czytelnie się łączą. */
.rev__pick.is-on { color: var(--bone); padding-left: 30px; }
.rev__pick.is-on .mt { color: var(--muted-on-dark); }
.rev__pick.is-on::before { content: ""; position: absolute; left: 0; top: 1.15em; width: 18px; height: 1px; background: var(--brass-soft); }
.rev__pick:focus-visible { outline: 1px solid var(--brass-soft); outline-offset: 4px; }

/* =========================================================================
   CASE STUDIES
   ========================================================================= */
.cs { display: flex; flex-direction: column; gap: 1px; }
.cs__item { display: grid; grid-template-columns: 0.92fr 1.08fr; gap: 0; background: var(--bone); border: var(--hair); }
.cs__item:nth-child(even) { grid-template-columns: 1.08fr 0.92fr; }
.cs__item:nth-child(even) .cs__media { order: 2; }
.cs__media { position: relative; overflow: hidden; min-height: 380px; }
.cs__media .cs__img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* Case study bez zdjęcia (brak pola `img` w data/content.js) nie dostaje
   pustej kolumny na kadr - zamiast szarej dziury zostaje sam tekst.
   Wcześniej stał tam placeholder <image-slot> z podpisem „Rendering - ...",
   który widział każdy odwiedzający. */
.cs__item.is-textonly, .cs__item.is-textonly:nth-child(even) { grid-template-columns: 1fr; }
.cs__body { padding: clamp(28px, 3.4vw, 56px); display: flex; flex-direction: column; justify-content: center; }
.cs__tag { font-size: 0.7rem; letter-spacing: 0.2em; text-transform: uppercase; color: var(--brass); margin-bottom: 16px; }
.cs__body h3 { font-family: var(--display); font-size: clamp(1.8rem, 3vw, 2.6rem); font-weight: 500; line-height: 1.04; margin-bottom: clamp(20px, 2.4vw, 30px); }
.cs__block { display: flex; gap: 16px; padding: 15px 0; border-top: var(--hair); }
.cs__block .k { flex: none; width: 92px; font-size: 0.72rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--warm-gray); padding-top: 3px; }
.cs__block p { font-size: 0.96rem; color: var(--graphite); }

/* Opinia klientki pod opisem realizacji. Ten sam rytm co bloki wyżej
   (hairline + 92 px etykiety), ale głos klienta jest kursywą w kroju
   displayowym, żeby nie czytało się jak dalszy ciąg opisu. */
.cs__quote { margin: 0; align-items: flex-start; }
.cs__qbody { min-width: 0; }
.cs__quote blockquote { margin: 0; }
/* selektor musi być mocniejszy niż `.cs__block p` wyżej - inaczej fraza
   wiodąca dostaje 0,96 rem i przestaje się różnić od reszty cytatu */
.cs__quote .cs__qlead { font-family: var(--display); font-style: italic; font-size: clamp(1.16rem, 1.5vw, 1.4rem); line-height: 1.3; color: var(--graphite); text-wrap: pretty; }
.cs__quote blockquote p + p { margin-top: 0.7em; font-size: 0.92rem; line-height: 1.62; color: var(--warm-gray); }
.cs__quote figcaption { margin-top: 14px; font-family: var(--display); font-size: 1.1rem; font-weight: 600; color: var(--brass); }
.cs__quote figcaption::before { content: "— "; }

/* ---------------------- Karuzela „przed / po" ----------------------
   Kadry leżą na sobie i przenikają w miejscu: zdjęcie sprzed remontu i
   render są z tego samego punktu, więc jedno zmienia się w drugie.
   Karuzela jest pozycjonowana absolutnie, żeby - tak jak zwykły kadr -
   NIE wyznaczała wysokości wiersza; robi to kolumna z tekstem. */
.csx { position: absolute; inset: 0; }
.csx__stage { position: absolute; inset: 0; overflow: hidden; }
.csx__slide { position: absolute; inset: 0; margin: 0; opacity: 0; transition: opacity 0.9s var(--ease); }
.csx__slide.is-on { opacity: 1; }
.csx__slide img { width: 100%; height: 100%; object-fit: cover; display: block; }
/* przydymienie pod kropkami - inaczej giną na jasnym renderze */
.csx__stage::after { content: ""; position: absolute; left: 0; right: 0; bottom: 0; height: 110px; background: linear-gradient(to top, rgb(var(--ink-rgb) / 0.4), transparent); pointer-events: none; }

/* ta sama plakietka co znacznik kategorii na kaflu portfolio (.pf__cat) */
.csx__badge { position: absolute; top: clamp(14px,1.6vw,22px); left: clamp(14px,1.6vw,22px); padding: 0.5em 0.9em; border-radius: 999px; font-size: 0.66rem; letter-spacing: 0.2em; text-transform: uppercase; color: var(--bone); background: rgb(var(--ink-rgb) / 0.44); backdrop-filter: blur(6px); }

.csx__arw { position: absolute; top: 50%; transform: translateY(-50%); width: 44px; height: 44px; border-radius: 50%; display: grid; place-items: center; color: var(--cream-on-dark); background: rgb(var(--ink-rgb) / 0.34); border: 1px solid rgb(255 255 255 / 0.22); opacity: 0.78; transition: opacity 0.4s var(--ease), background 0.4s var(--ease), color 0.4s var(--ease); }
.csx__arw--p { left: 14px; }
.csx__arw--n { right: 14px; }
.csx:hover .csx__arw { opacity: 1; }
.csx__arw:hover { background: var(--brass); border-color: var(--brass); color: var(--ink); }
.csx__arw:focus-visible { opacity: 1; outline: 1px solid var(--brass-soft); outline-offset: 3px; }

.csx__dots { position: absolute; left: 0; right: 0; bottom: 16px; display: flex; justify-content: center; gap: 7px; }
.csx__dot { position: relative; width: 26px; height: 2px; background: rgb(255 255 255 / 0.42); transition: background 0.4s var(--ease), height 0.4s var(--ease); }
/* Kreska ma 2-3 px - palcem nie da się w nią trafić. Niewidoczny pseudoelement
   rozpycha pole dotyku do ~44 px w pionie; w poziomie tylko do połowy odstępu
   między kreskami, żeby sąsiednie pola na siebie nie wchodziły. */
.csx__dot::after { content: ""; position: absolute; inset: -21px -3px; }
.csx__dot:hover { background: var(--cream-on-dark); }
.csx__dot.is-on { height: 3px; background: var(--brass-soft); }
.csx__dot:focus-visible { outline: 1px solid var(--brass-soft); outline-offset: 5px; }

/* Bez ruchu: przenikanie znika, automat i tak się nie uruchamia (app.js). */
@media (prefers-reduced-motion: reduce) {
  .csx__slide { transition: none; }
}

@media (max-width: 820px){
  .cs__item, .cs__item:nth-child(even) { grid-template-columns: 1fr; }
  .cs__item:nth-child(even) .cs__media { order: 0; }
  .cs__media { min-height: 280px; }
  /* Kadry są pionowe, a tu media są osobnym wierszem, nie sąsiadem tekstu -
     stały pasek 280 px ucinałby z nich prawie wszystko. Proporcja pilnuje,
     żeby wysokość szła za szerokością ekranu. */
  .cs__media--x { min-height: 0; aspect-ratio: 5 / 6; max-height: 78vh; }
}

/* =========================================================================
   FAQ - accordion
   ========================================================================= */
.faq { border-top: var(--hair); }
.faq__item { border-bottom: var(--hair); }
.faq__q { width: 100%; text-align: left; display: flex; align-items: center; gap: 24px; padding: clamp(24px, 2.8vw, 36px) 0; }
.faq__q h3 { font-family: var(--display); font-weight: 500; font-size: clamp(1.35rem, 2.4vw, 2rem); line-height: 1.12; flex: 1; transition: color 0.4s var(--ease); }
.faq__item:hover .faq__q h3, .faq__item.is-open .faq__q h3 { color: var(--brass); }
.faq__ic { flex: none; width: 26px; height: 26px; position: relative; }
.faq__ic::before, .faq__ic::after { content: ""; position: absolute; background: currentColor; transition: transform 0.4s var(--ease), opacity 0.3s; }
.faq__ic::before { top: 50%; left: 0; width: 100%; height: 1.5px; transform: translateY(-50%); }
.faq__ic::after { left: 50%; top: 0; height: 100%; width: 1.5px; transform: translateX(-50%); }
.faq__item.is-open .faq__ic::after { opacity: 0; transform: translateX(-50%) rotate(90deg); }
.faq__a { display: grid; grid-template-rows: 0fr; transition: grid-template-rows 0.5s var(--ease); }
.faq__item.is-open .faq__a { grid-template-rows: 1fr; }
.faq__a > div { overflow: hidden; }
.faq__a p { max-width: 64ch; color: var(--warm-gray); font-size: 1.02rem; padding-bottom: clamp(24px, 2.8vw, 34px); }

/* =========================================================================
   KONTAKT - formularz
   ========================================================================= */
.contact { display: grid; grid-template-columns: 0.82fr 1.18fr; gap: clamp(32px, 5vw, 92px); }
.contact__aside h2 { font-size: clamp(2.2rem, 4.6vw, 3.8rem); margin-bottom: clamp(22px, 3vw, 34px); }
.contact__chan { display: flex; flex-direction: column; gap: 2px; margin-top: clamp(28px, 4vw, 44px); }
.contact__chan a, .contact__chan p { display: flex; align-items: baseline; justify-content: space-between; gap: 16px; padding: 16px 0; border-top: var(--hair); font-size: 1rem; }
.contact__chan a .v { font-family: var(--display); font-size: 1.3rem; transition: color 0.3s; }
.contact__chan a:hover .v { color: var(--brass); }
.contact__chan .k { font-size: 0.72rem; letter-spacing: 0.16em; text-transform: uppercase; color: var(--warm-gray); }

.form { background: var(--bone); border: var(--hair); border-radius: 4px; padding: clamp(26px, 3.2vw, 48px); }
.form__row { display: grid; grid-template-columns: 1fr 1fr; gap: clamp(16px, 2vw, 26px); }
.form__field { margin-bottom: clamp(18px, 2vw, 24px); }
.form__field.full { grid-column: 1 / -1; }
.form__field label { display: block; font-size: 0.72rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--warm-gray); margin-bottom: 9px; }
.form__field label .opt { color: var(--taupe); text-transform: none; letter-spacing: 0; font-size: max(0.8em, 0.625rem); }
.form__field input, .form__field select, .form__field textarea {
  width: 100%; background: transparent; border: none; border-bottom: 1.5px solid var(--taupe);
  padding: 10px 0; font-size: 1rem; color: var(--graphite); outline: none; border-radius: 0;
  transition: border-color 0.4s var(--ease);
}
.form__field textarea { resize: vertical; min-height: 96px; }
.form__field input:focus, .form__field select:focus, .form__field textarea:focus { border-color: var(--graphite); }
.form__field select { appearance: none; background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='12' height='8' viewBox='0 0 12 8'%3E%3Cpath d='M1 1l5 5 5-5' stroke='%238A8073' stroke-width='1.3' fill='none'/%3E%3C/svg%3E"); background-repeat: no-repeat; background-position: right 2px center; cursor: pointer; }
.form__check { display: flex; gap: 14px; align-items: flex-start; cursor: pointer; margin: 6px 0 26px; }
.form__check input { position: absolute; opacity: 0; width: 0; height: 0; }
.form__check .box { flex: none; width: 22px; height: 22px; border: 1.5px solid var(--taupe); border-radius: 3px; display: grid; place-items: center; margin-top: 2px; transition: all 0.3s var(--ease); }
.form__check .box svg { opacity: 0; transform: scale(0.5); transition: all 0.3s var(--ease); }
.form__check input:checked + .box { background: var(--graphite); border-color: var(--graphite); }
.form__check input:checked + .box svg { opacity: 1; transform: scale(1); }
.form__check span { font-size: 0.86rem; color: var(--warm-gray); line-height: 1.5; }
.form__check input:focus-visible + .box { outline: 2px solid var(--brass); outline-offset: 2px; }
.form__estimate { display: flex; align-items: center; gap: 14px; padding: 16px 18px; background: var(--beige); border-radius: 4px; margin-bottom: 24px; font-size: 0.9rem; }
.form__estimate .est-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--brass); flex: none; }
.form__estimate b { font-family: var(--num); font-size: 1rem; font-weight: 600; letter-spacing: -0.02em; font-variant-numeric: tabular-nums lining-nums; }
/* Load-bearing, dokładnie jak .lb[hidden] i .form__error[hidden] niżej:
   autorskie `display: flex` wygrywa z wbudowaną regułą [hidden] przeglądarki,
   więc bez tego ramka „Dołączona wstępna wycena: -" stoi w formularzu od
   załadowania strony, zanim ktokolwiek zaznaczy checkbox. */
.form__estimate[hidden] { display: none; }
.form .btn { justify-content: center; }
.form__error {
  margin-top: 16px; padding: 14px 18px; border-radius: 4px;
  background: color-mix(in srgb, #b5483a 10%, transparent);
  border: 1px solid color-mix(in srgb, #b5483a 34%, transparent);
  color: #8f3629; font-size: 0.88rem; line-height: 1.5;
}
.form__error[hidden] { display: none; }
.form__sent { display: none; text-align: center; padding: clamp(30px, 5vw, 60px) 20px; }
.form__sent.is-on { display: block; }
.form__sent .ic { width: 64px; height: 64px; border-radius: 50%; background: var(--brass); display: grid; place-items: center; margin: 0 auto 22px; color: var(--ink); }
.form__sent h3 { font-family: var(--display); font-size: 1.9rem; font-weight: 500; margin-bottom: 10px; }
.form__sent p { color: var(--warm-gray); max-width: 40ch; margin: 0 auto; }
@media (max-width: 900px){ .contact { grid-template-columns: 1fr; } }
@media (max-width: 540px){ .form__row { grid-template-columns: 1fr; } }

/* =========================================================================
   FOOTER (light, minimal - full version next pass)
   ========================================================================= */
.foot { background: var(--ink); color: var(--cream-on-dark); padding-block: clamp(56px, 7vw, 96px) 40px; }
.foot__top { display: grid; grid-template-columns: 1.4fr 1fr 1fr 1fr; gap: clamp(28px,4vw,60px); padding-bottom: clamp(40px,5vw,68px); border-bottom: 1px solid rgba(201,183,158,0.2); }
.foot__big { font-family: var(--display); font-size: clamp(2rem, 4.4vw, 3.4rem); font-weight: 500; line-height: 1.04; max-width: 16ch; }
.foot__big em { font-style: italic; color: var(--brass-soft); }
.foot__col h5 { font-size: 0.72rem; letter-spacing: 0.18em; text-transform: uppercase; color: var(--brass-soft); margin-bottom: 16px; }
.foot__col a, .foot__col p { display: block; color: var(--muted-on-dark); font-size: 0.95rem; margin-bottom: 9px; transition: color 0.3s; }
.foot__col a:hover { color: var(--cream-on-dark); }
.foot__col a.foot__link { display: flex; align-items: center; gap: 10px; }
.foot__link svg { flex: none; color: var(--brass-soft); transition: color 0.3s; }
.foot__link:hover svg { color: var(--cream-on-dark); }
.foot__bottom { display: flex; flex-wrap: wrap; justify-content: space-between; gap: 16px; padding-top: 28px; font-size: 0.82rem; color: var(--muted-on-dark); }
@media (max-width: 1040px){ .foot__top { grid-template-columns: repeat(3, 1fr); } .foot__big { grid-column: 1 / -1; } }
@media (max-width: 760px){ .foot__top { grid-template-columns: 1fr; } }

/* =========================================================================
   REVEAL animation
   ========================================================================= */
[data-reveal] { opacity: 1; transform: none; }
html.js [data-reveal] { opacity: 0; }
html.js [data-reveal].is-in { opacity: 1; animation: riseY 0.9s var(--ease) both; }
html.js [data-reveal][data-reveal-stagger] > * { opacity: 0; }
html.js [data-reveal][data-reveal-stagger].is-in > * {
  opacity: 1;
  animation: riseY 0.8s var(--ease) both;
  animation-delay: calc(var(--si, 0) * 0.07s);
}

@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { animation-duration: 0.001ms !important; transition-duration: 0.001ms !important; }
  [data-reveal], .hero [data-anim] { opacity: 1 !important; transform: none !important; }
}

/* responsive header */
@media (max-width: 1080px){
  .nav, .hdr__cta .btn { display: none; }
  .burger { display: block; }
}
/* na bardzo wąskich ekranach ikony zostają w menu mobilnym */
@media (max-width: 420px){
  .hdr__cta .social { display: none; }
}

/* =========================================================================
   O MNIE
   ========================================================================= */
.about { display: grid; grid-template-columns: 0.82fr 1.18fr; gap: clamp(28px, 5vw, 84px); align-items: center; }
.about__media { position: relative; aspect-ratio: 4 / 5; overflow: hidden; border-radius: 2px; background: var(--beige); }
.about__media img { width: 100%; height: 100%; object-fit: cover; object-position: 50% 40%; display: block; }
.about__body .kicker { margin-bottom: clamp(18px, 2.4vw, 26px); }
.about__body h2 { font-size: clamp(2rem, 4vw, 3.4rem); margin-bottom: clamp(16px, 2vw, 24px); }
.about__body .lead { margin-bottom: 16px; }
.about__txt { color: var(--warm-gray); max-width: 56ch; }
.about__txt + .about__txt { margin-top: 14px; }
.about__points { list-style: none; margin: clamp(24px, 3vw, 36px) 0; }
.about__points li { display: grid; grid-template-columns: 190px 1fr; gap: 18px; padding: 15px 0; border-top: var(--hair); }
.about__points li b { font-family: var(--display); font-weight: 600; font-size: 1.18rem; color: var(--graphite); line-height: 1.15; }
.about__points li span { font-size: 0.96rem; color: var(--warm-gray); }
@media (max-width: 860px){ .about { grid-template-columns: 1fr; } .about__points li { grid-template-columns: 1fr; gap: 4px; } }

/* portfolio - link do pełnego portfolio */
.pf__more { margin-top: clamp(28px, 4vw, 48px); display: flex; justify-content: flex-end; }

/* kontakt - notka o telefonie */
.contact__note { margin-top: clamp(18px, 2.4vw, 26px); padding-left: 16px; border-left: 1px solid var(--brass); font-size: 0.92rem; color: var(--warm-gray); line-height: 1.55; }

/* =========================================================================
   WERSJA MOBILNA / DOTYK
   Jedno miejsce na wszystko, co dotyczy telefonów i tabletów - dopisane na
   końcu pliku, więc nadpisuje reguły bazowe bez podbijania specyficzności.

   Trzy grupy:
     1. (hover: none)     - urządzenia dotykowe, niezależnie od szerokości
     2. (pointer: coarse) - palec zamiast myszy, więc większe cele dotykowe
     3. breakpointy szerokości - układ
   ========================================================================= */

/* ----------------------------- 1. DOTYK ----------------------------- */
/* Na telefonie nie ma "najechania kursorem", więc wszystko, co w wersji
   desktopowej pokazuje się dopiero na hover, musi być widoczne od razu -
   inaczej na kafelkach portfolio nie widać ani tytułu, ani kategorii. */
@media (hover: none) {
  .pf__shade { opacity: 1; }
  .pf__meta { opacity: 1; transform: none; }
  .pf__cat { opacity: 1; }
  /* efekty "na hover", które na dotyku tylko zostają zablokowane po tapnięciu */
  .pf__item:hover .pf__img { transform: none; }
  .timeline__row:hover { padding-left: 0; }
  .social a:hover { transform: none; }
}

/* Brak szarego prostokąta po tapnięciu (domyślny highlight w Chrome/Safari). */
body { -webkit-tap-highlight-color: transparent; }

/* Elementy siatki i flexa mają domyślnie min-width:auto, czyli "nie zwężaj
   mnie poniżej najszerszej treści". Na wąskim ekranie to właśnie ono wypychało
   oba panele kalkulatora poza kontener - a .calc ma overflow:hidden, więc
   prawa krawędź (m², przycisk CTA) była po prostu ucinana.
   Winowajcy to <input type="number"> (ma własną szerokość domyślną ~20 znaków)
   i .btn z white-space:nowrap. Zerowy min-width pozwala im się zwęzić. */
.calc__form, .calc__out, .tcard, .proc__step, .cs__body, .contact__aside, .form { min-width: 0; }
.area-input input { min-width: 0; }

/* Kotwice (#oferta, #wycena…) nie mogą chować się pod przyklejonym nagłówkiem. */
html { scroll-padding-top: 84px; }

/* Ekrany z "wcięciem" - treść nie wchodzi pod notch ani pasek gestów. */
@supports (padding: max(0px)) {
  .wrap {
    padding-left: max(var(--gut), env(safe-area-inset-left));
    padding-right: max(var(--gut), env(safe-area-inset-right));
  }
  .foot { padding-bottom: calc(40px + env(safe-area-inset-bottom)); }
}

/* ------------------------ 2. WIĘKSZE CELE DOTYKOWE ------------------------ */
/* Warunek jest podwójny celowo: palec zamiast myszy ALBO po prostu wąski
   ekran. Dzięki temu powiększone cele dostaje zarówno telefon, jak i wąskie
   okno na desktopie - a nie tylko urządzenia, które zgłaszają (pointer: coarse).
   Próg 1080px jest ten sam, przy którym nawigacja zamienia się w burgera.  */
@media (pointer: coarse), (max-width: 1080px) {
  /* Suwak metrażu: sam <input> ma raptem 2 px wysokości, więc palcem trafia
     się w niego przypadkiem. Wyściółka podnosi pole dotyku do 32 px, a
     background-clip: content-box zostawia tor tak samo cienki jak wcześniej. */
  .range {
    height: 32px;
    padding-block: 15px;
    background-color: var(--taupe);
    background-clip: content-box;
    margin-top: 8px;
  }
  .range::-webkit-slider-thumb { width: 28px; height: 28px; }
  .range::-moz-range-thumb { width: 28px; height: 28px; }
  /* checkboxy w formularzu */
  .form__check { margin-bottom: 22px; }
  .form__check .box { width: 24px; height: 24px; }
  /* Chipy filtra portfolio. Padding jest w `em`, a stopień pisma schodzi tu
     razem z resztą typografii mobilnej, więc sama wyściółka zostawiała
     pigułkę na 35 px - min-height trzyma pole dotyku niezależnie od pisma. */
  .chip { padding: 0.72em 1.3em; min-height: 44px; }
  .foot__col a { padding-block: 10px; margin-bottom: 0; }
  .contact__chan a { padding-block: 18px; }
  /* Okruszki na podstronach: sam wiersz tekstu ma 20 px. Wyściółka rośnie
     w górę i w dół, a ujemny margines oddaje te piksele układowi, więc
     odstępy w nagłówku podstrony zostają takie, jak były. */
  .crumbs a { display: inline-block; padding-block: 12px; margin-block: -12px; }
  /* „Otwórz plik PDF" - podkreślenie jest tu linią bazową kompozycji,
     więc pole dotyku rośnie wyłącznie w górę. */
  .smp__open { padding-top: 18px; margin-top: -18px; }
  /* Ikony społecznościowe: obwódka ma być kółkiem 36 px, bo tak wygląda
     nagłówek - więc powiększamy samo pole dotyku, nie rysunek. Pseudoelement
     rozpycha obszar klikalny do 44 px (prostokątem, nie kołem - w rogu
     kółka palcem trafia się najczęściej) i nie widać go na oczy. */
  .social a { position: relative; }
  .social a::after { content: ""; position: absolute; inset: -4px; }
}

/* ---------------------- 2b. TYPOGRAFIA NA TELEFONIE ---------------------- */
/* Skala z desktopu przeniesiona 1:1 na 390 px robi się krzykliwa: nagłówek
   sekcji ma tam 38 px, a mikro-etykiety są rozstrzelone na 0.26em i zajmują
   po dwa wiersze. Tutaj wszystko schodzi o klasę w dół - mniejszy stopień,
   lżejsza waga kroju, ciaśniejszy trakting. Treść bez zmian, tylko spokojniej.
   Blok stoi PRZED regułami układu, żeby sekcje mogły go u siebie nadpisać. */
@media (max-width: 640px) {
  .shead h2 { font-size: clamp(1.95rem, 8vw, 2.6rem); }
  .shead { margin-bottom: clamp(30px, 7vw, 48px); gap: 16px; }
  .about__body h2, .contact__aside h2 { font-size: clamp(1.9rem, 7.6vw, 2.6rem); }
  .foot__big { font-size: clamp(1.7rem, 7vw, 2.4rem); }

  /* duże nagłówki w lżejszej wadze - drobniejsze zostają na 500,
     bo przy 20 px Cormorant 400 robi się już za cienki */
  .hero h1, .shead h2, .about__body h2, .contact__aside h2,
  .banner__inner h2, .foot__big { font-weight: 400; }

  .lead { font-size: 1rem; line-height: 1.6; }
  .kicker { font-size: 0.66rem; letter-spacing: 0.2em; gap: 0.7em; }
  .kicker::before { width: 18px; }
}

/* =========================== 3. UKŁAD - BREAKPOINTY =========================== */

/* --------------------------- Nagłówek + menu --------------------------- */
@media (max-width: 1080px) {
  .hdr__row { gap: 14px; }
  /* burger dostaje pełne 44×44 px pola dotyku - same kreski zostają 30×18 */
  .burger { width: 44px; height: 44px; margin-right: -9px; }
  .burger span { left: 7px; width: 30px; }
  .burger span:nth-child(1) { top: 13px; }
  .burger span:nth-child(3) { bottom: 13px; }

  /* strona pod otwartym menu nie może się przewijać "w tle" */
  body.menu-open { overflow: hidden; }

  .mobile {
    /* justify-content:center przy dłuższej treści ucina górę i nie da się do
       niej doscrollować - dlatego centrujemy marginesami auto, które przy
       przepełnieniu same znikają. */
    justify-content: flex-start;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding-top: calc(var(--gut) + env(safe-area-inset-top, 0px) + 56px);
    padding-bottom: calc(var(--gut) + env(safe-area-inset-bottom, 0px));
  }
  /* Bez tego flex ściska dzieci, gdy menu jest wyższe niż ekran - przycisk
     CTA gubił wtedy wyściółkę i robił się płaski (29 px zamiast 50 px).
     Od przewijania jest overflow-y wyżej, nie kurczenie się elementów. */
  .mobile > * { flex: none; }
  .mobile__nav { margin-top: auto; }
  .mobile__nav a { font-size: clamp(1.6rem, 6.6vw, 3rem); }
  /* Numer (01-07) ma stały rozmiar w rem, a kolumna pod niego była podana
     w `em` - czyli skalowała się razem z nazwą pozycji. Po zmniejszeniu
     nazwy kolumna dalej miała 1.85em (~70 px), a sam numer tylko ~14 px:
     zostawało ~56 px martwej dziury i numery wisiały samotnie przy lewej
     krawędzi. Na telefonie kolumna idzie więc na rem - tak jak numer. */
  .mobile__nav a {
    grid-template-columns: 2.15rem 1fr;
    /* wysokość pozycji nie może zależeć od stopnia pisma, bo przy mniejszej
       czcionce wiersz spadał poniżej 44 px pola dotyku */
    padding-block: 9px;
  }
  /* mniejsza nazwa = niższy wersalik, więc dawne uniesienie o -0.72em
     wypychało numer prawie do włosa nad wierszem */
  .mobile__nav a span { transform: translateY(-0.3em); }
  .mobile__cta { align-self: flex-start; margin-top: clamp(26px, 4vh, 44px); }
  .mobile__foot {
    margin-bottom: auto;
    flex-direction: column;
    gap: 2px;
    margin-top: clamp(26px, 4vh, 48px);
  }
  /* linki w stopce menu miały 22 px wysokości - za mało, żeby trafić palcem */
  .mobile__foot a { padding-block: 7px; }
}

@media (max-width: 420px) {
  .logo__mark { width: 30px; height: 30px; font-size: 1.02rem; }
  .logo__txt { font-size: 1.14rem; }
  .logo__txt small { font-size: 0.625rem; letter-spacing: 0.13em; }
}

/* ------------------------------- HERO ------------------------------- */
@media (max-width: 820px) {
  /* Telefon dostaje pionowy plik 720×1280 (patrz skrypt przy <video>), więc
     kadr niemal dokładnie pokrywa ekran - nie potrzeba już zapasu 116%
     na paralaksę, która na dotyku i tak jest wyłączona. */
  .hero__video { height: 100%; }

  /* --- Napisy: minimalistycznie, żeby zostawić kadr filmowi ---------------
     Na telefonie blok tekstowy zasłaniał połowę wideo. Cała typografia
     schodzi o klasę w dół: lżejsza waga kroju, mniej rozstrzelona
     mikro-etykieta, węższy akapit i ciaśniejsze odstępy. Treść zostaje
     ta sama - zmienia się tylko jej „głośność". */
  /* Jeden mnożnik na cały blok tekstowy hero: rusza mikro-etykietą,
     nagłówkiem i akapitem naraz, więc ich wzajemne proporcje zostają
     takie, jak zaprojektowane. 1 = stopnie sprzed powiększenia. */
  .hero__inner {
    --hero-txt: 0.96;
    /* Bliżej lewej krawędzi niż wspólny gutter strony (16 -> 12 px): kolumna
       tekstu jest tu wąska, więc ma się trzymać brzegu kadru. */
    padding-inline: 12px;
    padding-top: clamp(84px, 16vh, 128px); padding-bottom: clamp(28px, 4.5vh, 56px);
  }

  /* Napisy są małe z wyboru, żeby kadr filmu został prawie nietknięty.
     Mnożnik szedł 1,6 -> 0,8 (o połowę), potem 0,8 -> 0,96 (+20%). Na
     ekranie 390 px nagłówek ma ~15,5 px, akapit ~12,6, mikro-etykieta ~10,1. */
  /* Sufit 1,1x na mikro-etykiecie pilnuje jej tylko przy wyższych mnożnikach:
     „Studio projektowe · Wrocław & online" to 36 wersalików i powyżej tego
     stopnia nie mieści się w jednym wierszu na 360-390 px, a złamane na dwa
     czyta się gorzej niż mniejsze. Przy 0,96 sufit nic nie robi. */
  .hero__kicker { font-size: calc(0.66rem * min(var(--hero-txt), 1.1)); letter-spacing: 0.06em; opacity: 0.8; }

  /* max-width w `ch` kurczy się razem z pismem, więc limit musi iść odwrotnie
     do mnożnika, żeby SZEROKOŚĆ kolumny w pikselach została ta sama:
     17ch przy 1x, ~26ch przy 1,6x. Przy małych mnożnikach (0,8–0,96) stoi
     luźne 52ch - nagłówek jest wtedy tak mały, że limitu i tak nie sięga,
     więc podział wiersza zaprojektowany w HTML (<br /> po „Dom bez stresu")
     zostaje nienaruszony, a limit nigdy nie łamie drugiej linii od siebie. */
  .hero h1 { font-size: calc(clamp(1.07rem, 4.13vw, 1.53rem) * var(--hero-txt)); font-weight: 400; line-height: 1.16; margin-top: 0.5em; max-width: 52ch; }

  /* twarde łamanie wiersza z desktopu psuje akapit na wąskim ekranie */
  .hero__sub br { display: none; }
  /* Akapit trzyma LEWĄ POŁOWĘ kadru: limit w `vw`, nie w `ch`, bo ma zależeć
     od szerokości ekranu, a nie od stopnia pisma - inaczej po powiększeniu
     tekstu kolumna rosła razem z nim i wiersze rozłaziły się na całą
     szerokość. Węziej = więcej wierszy, i o to tu chodzi. */
  .hero__sub { font-size: calc(0.82rem * var(--hero-txt)); line-height: 1.5; max-width: 60vw; opacity: 0.74; }

  .hero__bottom { gap: clamp(13px, 2vh, 20px); margin-top: 3px; }

  /* strzałka "Przewiń" siedzi w prawym dolnym rogu - na telefonie wchodzi
     w przyciski, a podpowiedź i tak jest zbędna */
  .hero__scroll { display: none; }

  /* Cień tylko tam, gdzie naprawdę leży tekst: góra prawie czysta, ciemnienie
     zaczyna się dopiero w dolnej jednej trzeciej kadru. */
  .hero__media::after {
    background:
      linear-gradient(180deg, rgb(var(--ink-rgb) / 0.4) 0%, rgb(var(--ink-rgb) / 0.03) 20%, rgb(var(--ink-rgb) / 0.08) 46%, rgb(var(--ink-rgb) / 0.66) 84%, rgb(var(--ink-rgb) / 0.86) 100%);
  }
}
@media (max-width: 560px) {
  /* Dwa pasy przycisków na całą szerokość ciążyły na kadrze - pigułki wracają
     do swojej naturalnej szerokości i drobniejszego stopnia pisma. */
  .hero__actions { width: auto; flex-direction: column; align-items: flex-start; gap: 6px; }
  /* Stopień pisma i pole dotyku: padding jest w `em`, więc sam font-size
     ustawiał tu całą pigułkę. Przy 0.34rem napis miał 5,4 px, a przycisk
     18 px wysokości - główne CTA strony było nieczytelne i za małe pod
     palec. 0.66rem (10,6 px) to nadal drobna pigułka na kadrze, a
     min-height: 44px daje wymagane pole dotyku niezależnie od pisma. */
  .hero__actions .btn { font-size: 0.66rem; letter-spacing: 0.16em; padding: 0.9em 1.6em; min-height: 44px; white-space: nowrap; }
  .hero__bottom { max-width: none; }
}

/* Dłuższe etykiety CTA ("Wyślij zapytanie z tą wyceną") nie mieszczą się na
   telefonie w jednym wierszu - pozwalamy im się złamać zamiast wystawać. */
@media (max-width: 560px) {
  .btn { white-space: normal; flex-wrap: wrap; justify-content: center; text-align: center; padding-inline: 1.4em; }
}

/* --------------------------- Pasek zaufania --------------------------- */
@media (max-width: 760px) {
  .trust .wrap { flex-direction: column; align-items: stretch; gap: 0; padding-block: 2px; }
  .trust span { justify-content: flex-start; padding-block: 15px; border-bottom: var(--hair); }
  .trust span:last-child { border-bottom: none; }
  .trust span b { font-size: 1.35rem; }
}

/* ------------------------------ Portfolio ------------------------------ */
@media (max-width: 760px) {
  /* Filtry na telefonie: siatka 3 x 2 (6 kategorii) zamiast poziomego paska -
     wszystkie kategorie widoczne od razu, bez przewijania w bok. */
  .pf__filter {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    gap: 8px;
  }
  .chip {
    padding: 0.65em 0.4em;
    text-align: center;
    font-size: 0.72rem;
    letter-spacing: 0.03em;
    white-space: nowrap;
  }
  /* Na 320 px „Pokoje dziecięce" w jednej linii nie mieści się w trzeciej
     kolumnie i rozpycha siatkę poza ekran - tam etykieta łamie się na dwa
     wiersze (rzędy siatki i tak mają wspólną wysokość). */
  @media (max-width: 400px) {
    .chip { white-space: normal; }
  }
  .pf__more { justify-content: flex-start; }
  /* Opis kafelka na stałe widoczny - nie tylko na urządzeniach dotykowych
     (blok @media (hover: none) wyżej), ale na każdym wąskim ekranie: przy
     jednej kolumnie kafelków hover i tak nie jest tu sposobem na czytanie. */
  .pf__shade, .pf__cat { opacity: 1; }
  .pf__meta { opacity: 1; transform: none; }
  .pf__shade { background: linear-gradient(180deg, transparent 40%, rgb(var(--ink-rgb) / 0.16) 58%, rgb(var(--ink-rgb) / 0.86) 100%); }
}
@media (max-width: 480px) {
  .pf__item.wide { aspect-ratio: 16/12; }
  .pf__item.tall { aspect-ratio: 4/4.8; }
  .pf__meta h3 { font-size: 1.45rem; }
  .pf__arrow { width: 38px; height: 38px; }
}

/* ------------------------------- Banner ------------------------------- */
@media (max-width: 640px) {
  /* „Każdy detal ma znaczenie – / od fugi po klamkę."
     Ograniczenie max-width: 20ch dusiło ten napis do 238 px, mimo że w kolumnie
     było 335 px – przez co zdanie łamało się w przypadkowym miejscu na trzy
     wiersze, a myślnik zostawał sam na końcu drugiego. Bez limitu szerokości
     wraca podział zaprojektowany w HTML: zdanie, <br>, kursywna klauzula. */
  .banner__inner h2 {
    /* Napis zajmował ćwiartkę kadru i konkurował ze zdjęciem, więc zszedł
       z 5.6vw na 2.8vw - ale ~11 px to na telefonie podpis, a nie hasło
       sekcji (pozostałe nagłówki mają tam 31 px). 3.85vw daje 15 px:
       nadal spokojniej niż kadr, już czytelnie. Cała trójka clamp idzie
       tym samym mnożnikiem, żeby proporcja trzymała się na każdej
       szerokości; wcięcie drugiego wiersza skaluje się razem z pismem. */
    font-size: clamp(0.81rem, 3.85vw, 1.33rem);
    max-width: none;
    line-height: 1.3;
  }
  .banner__inner h2 .indent { margin-left: 11px; }
  /* przycisk jak w hero - naturalna szerokość zamiast pasa na całą kolumnę */
  /* min-height jak w hero: padding w `em` jedzie za stopniem pisma, a sam
     nie dowozi pola dotyku - pigułka miała 38 px wysokości. */
  .banner__inner .btn { width: auto; font-size: 0.68rem; letter-spacing: 0.16em; padding: 0.88em 1.5em; min-height: 44px; white-space: nowrap; }
}

/* ------------------------------ Oferta ------------------------------ */
/* Na telefonie osiem ciemnych kafli jedno pod drugim robiło z tej sekcji
   czarną ścianę na 8 ekranów - w środku jasnej, beżowej strony.
   Zamiast tego składamy je jak CENNIK: jasne tło strony, włosowe linie,
   numer typu w lewej kolumnie, cena po prawej w tej samej linii co nazwa.
   Ten sam zestaw kolorów co reszta strony (bone / graphite / brass),
   ta sama typografia - zmienia się tylko forma. Kafle wracają od 641 px. */
@media (max-width: 640px) {
  .offer__grid {
    grid-template-columns: 1fr;
    gap: 0;
    background: none;
    border: none;
    border-radius: 0;
    border-top: 1px solid color-mix(in srgb, var(--taupe) 62%, transparent);
  }
  .tcard {
    min-height: 0;
    background: transparent;
    color: var(--graphite);
    padding: 17px 0;
    border-bottom: 1px solid color-mix(in srgb, var(--taupe) 62%, transparent);
    /* num | nazwa | cena  (opis idzie pod nazwą, przez dwie kolumny)
       row-gap = 0 celowo: wiersz na plakietkę jest pusty w 7 z 8 typów
       i nie ma zostawiać po sobie dziury - odstępy dają marginesy. */
    display: grid;
    grid-template-columns: 2.3rem minmax(0, 1fr) auto;
    column-gap: 12px;
    row-gap: 0;
    align-items: baseline;
  }
  .tcard:hover { background: transparent; }
  .tcard__top { grid-column: 1; grid-row: 1 / span 3; display: block; }
  .tcard__n {
    font-size: 1.24rem; font-weight: 600; line-height: 1; color: var(--brass);
  }
  .tcard__n small {
    font-size: 0.625rem; letter-spacing: 0.14em; color: var(--warm-gray); margin-bottom: 5px;
  }
  .tcard h3 { grid-column: 2; grid-row: 2; font-size: 1.06rem; line-height: 1.16; color: var(--graphite); }
  .tcard p { grid-column: 2 / -1; grid-row: 3; margin-top: 6px; font-size: 0.82rem; line-height: 1.5; color: var(--warm-gray); }
  .tcard__price {
    grid-column: 3; grid-row: 2; justify-self: end;
    border-top: none; padding-top: 0; gap: 0.28em; white-space: nowrap;
  }
  .tcard__price b { font-size: 1.06rem; color: var(--brass); }
  .tcard__price span { font-size: 0.625rem; color: var(--warm-gray); }

  /* „Najczęściej wybierany" - jedyny wiersz z podświetleniem: ciepły panel
     wypuszczony w gutter, żeby wyglądał jak wyróżnienie w cenniku, a nie
     jak obce pudełko. */
  .tcard.is-featured {
    background: color-mix(in srgb, var(--beige) 70%, transparent);
    box-shadow: none;
    border-radius: 3px;
    padding-inline: 13px;
    margin-inline: -13px;
    border-bottom-color: transparent;
  }
  /* .tcard.is-featured:hover z wersji desktopowej jest bardziej szczegółowy
     niż reguła wyżej - w wąskim oknie na myszy przemalowałby wiersz na ciemny */
  .tcard.is-featured:hover { background: color-mix(in srgb, var(--beige) 70%, transparent); }
  .tcard.is-featured .badge {
    position: static; display: block;
    grid-column: 2 / -1; grid-row: 1;
    margin-bottom: 7px;
    font-size: 0.625rem; letter-spacing: 0.16em; color: var(--brass);
  }
}

/* ----------------------------- Kalkulator ----------------------------- */
@media (max-width: 560px) {
  /* mniej wewnętrznego marginesu = więcej miejsca na kwadraty typów */
  .calc__form, .calc__out { padding: 24px 18px; }
  .types { gap: 6px; }
  /* grotesk jest szerszy od Cormoranta w tym samym stopniu, więc cyfry
     w kwadratach typów i wielka kwota schodzą o oczko niżej */
  .types button .tn { font-size: 1.02rem; }
  .types button .tp { font-size: 0.625rem; letter-spacing: -0.03em; }
  .out__price .val { font-size: clamp(2rem, 10vw, 2.9rem); }
  .out__rows .r { font-size: 0.85rem; gap: 12px; }
  .toggle__txt span { font-size: 0.78rem; }
  /* opis łamie się tu na 2-3 wiersze - przełącznik ma stać przy pierwszym,
     a nie dryfować na środek bloku tekstu */
  .toggle { align-items: flex-start; }
  .toggle__sw { margin-top: 3px; }
}
@media (max-width: 380px) {
  /* na najwęższych ekranach kwadraty typów robią się bardzo ciasne */
  .types { gap: 5px; }
  .types button .tn { font-size: 0.94rem; }
  .types button .tp { font-size: 0.625rem; letter-spacing: -0.04em; }
}

/* ------------------------------- Proces ------------------------------- */
@media (max-width: 560px) {
  .proc__step { padding: 24px 20px; gap: 14px; }
}

/* ---------------------------- Czas realizacji ---------------------------- */
@media (max-width: 600px) {
  .timeline__row { padding-block: 18px; }
  .timeline__row .time { color: var(--brass); font-size: 0.95rem; }
}

/* ------------------------------- Opinie ------------------------------- */
.rev__hint {
  display: none;
  margin-top: 14px;
  font-size: 0.72rem;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted-on-dark);
}
/* Poniżej tego progu spis nadawców nie mieści się obok wiadomości - schodzi
   pod nią i zamienia się w listwę znaczników (nazwiska zostają w aria-label
   przycisków, więc czytnik ekranu nadal wie, w co się klika). */
@media (max-width: 980px) {
  .rev { grid-template-columns: minmax(0, 1fr); gap: 26px; }
  /* jedna kolumna: wiadomość, pod nią strzałki, na końcu listwa znaczników -
     stąd column-reverse (w kodzie spis stoi przed strzałkami) */
  .rev__side { flex-direction: column-reverse; gap: 22px; }
  .rev__nav { margin-top: 0; }
  .rev__index { display: flex; flex-wrap: wrap; gap: 6px; border-top: none; }
  .rev__index li { border-bottom: none; }
  /* 26 px na znacznik: przy dziesięciu opiniach listwa mieści się w jednym
     rzędzie nawet na 360-pikselowym ekranie. */
  .rev__pick { width: 26px; height: 34px; padding: 0; gap: 0; }
  .rev__pick .nm, .rev__pick .mt { display: none; }
  /* zakres projektu wraca pod podpis - spis go tu już nie pokazuje */
  .rev__who .mt { display: inline; }
  .rev__pick::before { content: ""; position: absolute; left: 0; right: 0; top: 50%; height: 1px; background: color-mix(in srgb, var(--brass) 38%, transparent); transition: background 0.4s var(--ease), height 0.4s var(--ease); }
  .rev__pick:hover::before { background: var(--cream-on-dark); }
  .rev__pick.is-on { padding-left: 0; }
  .rev__pick.is-on::before { width: auto; height: 2px; background: var(--brass-soft); }
}
@media (max-width: 760px) {
  /* slider przesuwa się palcem (obsługa w app.js) - blokujemy tylko poziome
     przewijanie strony, pionowe ma działać normalnie */
  .rev__track { touch-action: pan-y; }
  .rev__lead { font-size: clamp(1.4rem, 5.6vw, 1.9rem); }
  .rev__body { font-size: 0.98rem; }
  .rev__nav { margin-top: 28px; gap: 10px; }
  .rev__nav button { width: 48px; height: 48px; }
  /* delikatna podpowiedź, że kartę można przesunąć palcem */
  .rev__hint { display: block; }
}

/* ---------------------------- Case studies ---------------------------- */
@media (max-width: 560px) {
  .cs__media { min-height: 220px; }
  .cs__body { padding: 26px 20px; }
  /* etykieta (Problem / Założenia…) nad tekstem - 92 px kolumny zjadałoby
     połowę szerokości telefonu */
  .cs__block { flex-direction: column; gap: 6px; }
  .cs__block .k { width: auto; padding-top: 0; }
  .csx__arw { width: 38px; height: 38px; }
  .csx__arw--p { left: 10px; }
  .csx__arw--n { right: 10px; }
  .csx__dot { width: 20px; }
}

/* -------------------------------- FAQ -------------------------------- */
@media (max-width: 560px) {
  .faq__q { gap: 16px; padding-block: 22px; }
  .faq__ic { width: 22px; height: 22px; }
  .faq__a p { font-size: 0.96rem; }
}

/* ------------------------------- Kontakt ------------------------------- */
@media (max-width: 560px) {
  .form { padding: 24px 18px; }
  /* adres e-mail jest dłuższy niż pół ekranu - etykieta idzie nad wartość */
  .contact__chan a, .contact__chan p { flex-direction: column; align-items: flex-start; gap: 5px; }
  .contact__chan a .v { font-size: 1.16rem; overflow-wrap: anywhere; }
  .form__sent h3 { font-size: 1.6rem; }
}

/* ------------------------------- Stopka ------------------------------- */
@media (max-width: 760px) {
  .foot__top { gap: 34px; }
  .foot__big { max-width: none; }
  .foot__bottom { flex-direction: column; gap: 8px; }
}

/* --------------------- Telefon w poziomie (landscape) --------------------- */
/* Niski i szeroki ekran: hero na 100svh zostawiłby na tekst kilkadziesiąt
   pikseli, więc oddajemy mu tyle, ile faktycznie potrzebuje. */
@media (max-height: 520px) and (orientation: landscape) {
  .hero { min-height: auto; }
  .hero__inner { padding-top: 104px; padding-bottom: 34px; }
  .hero h1 { font-size: 1.6rem; }
  .hero__actions { flex-direction: row; width: auto; }
  .mobile__nav a { font-size: clamp(1.5rem, 5vw, 2.2rem); }
}

/* =========================================================================
   PODSTRONA PORTFOLIO (portfolio.html)
   Ta sama paleta co strona główna, ale trzymana w jasnych beżach: podstrona
   nie ma ciemnego hero ani ciemnych kafli, więc zdjęcia są jedynym mocnym
   akcentem, a tło (bone / beige / sand) tylko je oprawia.
   ========================================================================= */

/* Nagłówek: bez filmu pod spodem jasny tekst byłby niewidoczny, więc na
   podstronie header od startu wygląda tak, jak na stronie głównej po
   przewinięciu (.is-stuck robi już tylko zmianę wysokości). */
.page-sub .hdr { color: var(--graphite); }
.page-sub .hdr::after { opacity: 1; }
.page-sub .logo__mark { border-color: var(--brass); color: var(--brass); }
.page-sub .nav a[aria-current="page"] { color: var(--brass); }
.page-sub .nav a[aria-current="page"]::after { left: 0; right: 0; }

/* ------------------------------- Nagłówek podstrony ------------------------------- */
.pghead {
  background: var(--beige);
  border-bottom: var(--hair);
  /* górny padding musi zmieścić przyklejony header (ok. 70 px) */
  padding-block: clamp(112px, 13vw, 176px) clamp(48px, 6vw, 84px);
}
.crumbs {
  display: flex; align-items: center; gap: 10px;
  font-size: 0.76rem; letter-spacing: 0.04em; color: var(--warm-gray);
  margin-bottom: clamp(22px, 3vw, 36px);
}
.crumbs a { border-bottom: 1px solid transparent; transition: border-color 0.35s var(--ease), color 0.35s var(--ease); }
.crumbs a:hover { color: var(--graphite); border-bottom-color: var(--brass); }
.crumbs span[aria-current] { color: var(--graphite); }
.pghead__h { font-size: clamp(2.6rem, 7vw, 5.6rem); margin-top: 18px; }
.pghead__lead { max-width: 56ch; margin-top: clamp(16px, 2vw, 24px); }

.pghead__stats {
  display: flex; flex-wrap: wrap; gap: clamp(24px, 4vw, 64px);
  margin-top: clamp(32px, 4vw, 52px);
  padding-top: clamp(24px, 3vw, 34px);
  border-top: var(--hair);
}
.pghead__stats div { display: flex; flex-direction: column; gap: 4px; }
.pghead__stats b {
  font-family: var(--num); font-variant-numeric: tabular-nums;
  font-size: clamp(1.5rem, 2.6vw, 2.1rem); font-weight: 600; line-height: 1;
  color: var(--brass);
}
.pghead__stats span { font-size: 0.76rem; letter-spacing: 0.14em; text-transform: uppercase; color: var(--warm-gray); }

/* ------------------------------- Lista projektów ------------------------------- */
.pfp__section { background: var(--bone); padding-block: clamp(52px, 7vw, 96px) clamp(20px, 3vw, 44px); }
.pfp__section .pf__filter { margin-bottom: clamp(40px, 5vw, 64px); }
/* Cała lista jest wyjęta ze scroll anchoringu. Chrome, gdy treść nad
   widokiem zniknie (zwinięcie galerii, przełączenie kategorii), sam koryguje
   pozycję przewijania i nadpisuje skok, który robi portfolio.js. Tu decyduje
   skrypt, nie przeglądarka. */
#pfpList { overflow-anchor: none; }

.pfp { padding-block: clamp(48px, 6vw, 88px); border-top: var(--hair); }
/* .is-first, a nie :first-child: po odfiltrowaniu kategorii pierwszy WIDOCZNY
   projekt nie może zaczynać się kreską i wcięciem wiszącymi w pustce. */
.pfp.is-first { padding-top: 0; border-top: 0; }
/* wejście z linku „zobacz projekt" - delikatne podświetlenie celu */
.pfp.is-linked > .pfp__head { position: relative; }
.pfp.is-linked > .pfp__head::before {
  content: ""; position: absolute; left: calc(var(--gut) * -0.4); top: -6px; bottom: -6px;
  width: 2px; background: var(--brass);
}

.pfp__head {
  display: grid; grid-template-columns: 1.35fr 0.65fr;
  gap: clamp(24px, 4vw, 64px); align-items: start;
  margin-bottom: clamp(26px, 3.4vw, 46px);
}
.pfp__idx {
  display: block; font-family: var(--num); font-variant-numeric: tabular-nums;
  font-size: 0.72rem; font-weight: 600; letter-spacing: 0.24em;
  color: var(--brass); margin-bottom: 12px;
}
.pfp__head h2 { font-size: clamp(1.9rem, 4vw, 3.4rem); }

.pfp__facts { display: grid; gap: 14px; padding-top: 6px; }
.pfp__facts > div { display: flex; justify-content: space-between; gap: 16px; padding-bottom: 12px; border-bottom: var(--hair); }
.pfp__facts dt { font-size: 0.68rem; letter-spacing: 0.2em; text-transform: uppercase; color: var(--warm-gray); }
.pfp__facts dd { font-size: 0.92rem; text-align: right; }

/* Galeria: ściana zdjęć w kolumnach (CSS columns), a nie siatka.
   Zdjęć jest kilkaset i mają różne proporcje - w siatce o równych rzędach
   albo trzeba by je przycinać, albo zostawałyby dziury pod niższymi kadrami.
   W kolumnach każdy kadr zachowuje własny kształt i nic się nie kadruje.

   Wysokość kadru bierze się z atrybutów width/height na <img> (wymiary są
   w danych, patrz tools/GalleryIndex.java), więc miejsce jest zarezerwowane
   zanim zdjęcie się pobierze - układ nie skacze przy doczytywaniu. */
.pfp__gallery { columns: 3; column-gap: clamp(12px, 1.6vw, 24px); }
.pfp__shot {
  break-inside: avoid;
  margin: 0 0 clamp(12px, 1.6vw, 24px);
  position: relative; overflow: hidden; border-radius: 2px;
  background: var(--sand);
}
/* Kadr jest przyciskiem otwierającym podgląd - kasujemy wygląd <button>,
   zostaje samo zdjęcie. `display: block` na obu, inaczej linia bazowa tekstu
   zostawia pod zdjęciem kilkupikselowy pasek tła. */
.pfp__open {
  display: block; width: 100%; padding: 0; border: 0; background: none;
  cursor: zoom-in; color: inherit; font: inherit;
}
.pfp__open:focus-visible { outline: 2px solid var(--brass); outline-offset: 3px; }
.pfp__shot img {
  display: block; width: 100%; height: auto;
  transition: transform 1.1s var(--ease);
}
.pfp__shot:hover img { transform: scale(1.04); }
.pfp__shot::after {
  /* cienka ramka na zdjęciu - trzyma jasne kadry przy jasnym tle */
  content: ""; position: absolute; inset: 0; pointer-events: none;
  border: 1px solid color-mix(in srgb, var(--taupe) 45%, transparent);
  border-radius: 2px;
}

/* Kadry poza pierwszą dwunastką. display:none, a nie visibility/opacity -
   ukrytych w ten sposób zdjęć przeglądarka NIE POBIERA, a o to tu chodzi:
   w HTML-u są od razu (widzi je wyszukiwarka i Ctrl+F), ale wejście na
   podstronę kosztuje kilkanaście miniatur zamiast czterystu. */
.pfp__shot.is-extra { display: none; }
.pfp.is-open .pfp__shot.is-extra { display: block; }

.pfp__more { display: flex; align-items: center; gap: clamp(14px, 2vw, 24px); flex-wrap: wrap; margin-top: clamp(6px, 1vw, 14px); }
.pfp__more-note { font-size: 0.78rem; letter-spacing: 0.12em; text-transform: uppercase; color: var(--warm-gray); }
/* Strzałka przy „pokaż wszystkie" celuje w dół, a po rozwinięciu w górę -
   to jedyny sygnał kierunku, bo sam napis zmienia się dopiero po kliknięciu. */
.pfp__more-btn .arr { transition: transform 0.4s var(--ease); }
.pfp__more-btn[aria-expanded="true"] .arr { transform: rotate(180deg); }
.pfp.is-open .pfp__more-note { display: none; }

.pfp__empty { color: var(--warm-gray); padding-block: clamp(30px, 5vw, 60px); }

.pfp__cta-row { display: flex; flex-wrap: wrap; align-items: center; gap: clamp(18px, 3vw, 34px); }

/* ------------------------------- Podgląd zdjęcia (lightbox) -------------------------------
   Kafel w siatce ma najwyżej ~500 px, więc zdjęcie musi dać się otworzyć
   w pełnym kadrze. Strzałki chodzą po JEDNEJ kategorii - patrz portfolio.js. */
.lb {
  position: fixed; inset: 0; z-index: 300;
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-rows: 1fr auto;
  align-items: center;
  gap: clamp(8px, 2vw, 24px);
  padding: clamp(14px, 3vw, 34px);
  background: rgba(20, 18, 16, 0.94);
  /* Tło strony pod spodem jest jasne - podgląd świadomie jest ciemny, żeby
     wizualizacje czytały się tak, jak na ciemnym tle w kaflach. */
}
/* KONIECZNE. `display: grid` powyżej jest regułą autorską, więc bije wbudowane
   [hidden] { display: none } przeglądarki - bez tego podgląd zostawał na
   ekranie po zamknięciu (element miał hidden=true, a i tak był widoczny,
   tyle że z wyczyszczonym zdjęciem, czyli jako ikonka zepsutego obrazka). */
.lb[hidden] { display: none; }
/* Kadr może być pionowy 4:5 - ograniczamy WYSOKOŚĆ, nie szerokość, inaczej
   pionowe zdjęcie wychodzi poza ekran i trzeba je przewijać. */
.lb__stage { grid-row: 1; grid-column: 2; display: flex; align-items: center; justify-content: center; min-height: 0; height: 100%; }
.lb__img { max-width: 100%; max-height: 100%; width: auto; height: auto; object-fit: contain; border-radius: 2px; }

.lb__btn {
  display: grid; place-items: center;
  /* Dolna granica 44 px, nie 40: na telefonie 5vw zawsze schodzi do minimum,
     a to jedyne sterowanie galerią w powiększeniu. */
  width: clamp(44px, 5vw, 52px); height: clamp(44px, 5vw, 52px);
  border: 1px solid rgba(245, 240, 232, 0.28); border-radius: 50%;
  background: rgba(245, 240, 232, 0.06); color: var(--bone);
  cursor: pointer; transition: background 0.3s var(--ease), border-color 0.3s var(--ease);
}
.lb__btn:hover { background: rgba(245, 240, 232, 0.16); border-color: rgba(245, 240, 232, 0.5); }
.lb__btn:focus-visible { outline: 2px solid var(--brass); outline-offset: 3px; }
.lb__prev { grid-row: 1; grid-column: 1; }
.lb__next { grid-row: 1; grid-column: 3; }
.lb__close { position: absolute; top: clamp(14px, 3vw, 34px); right: clamp(14px, 3vw, 34px); }
/* Jedno zdjęcie w kategorii - strzałki nie mają dokąd prowadzić. */
.lb.is-single .lb__nav { visibility: hidden; }

.lb__bar {
  grid-row: 2; grid-column: 1 / -1;
  display: flex; align-items: baseline; justify-content: center; gap: 16px;
  padding-top: clamp(10px, 1.5vw, 16px);
  color: rgba(245, 240, 232, 0.72);
}
.lb__cat { font-size: 0.78rem; letter-spacing: 0.16em; text-transform: uppercase; }
.lb__count { font-family: var(--num); font-variant-numeric: tabular-nums; font-size: 0.86rem; color: var(--bone); }

/* Blokada przewijania tła pod otwartym podglądem. */
body.lb-open { overflow: hidden; }

@media (max-width: 620px) {
  /* Na telefonie strzałki schodzą pod zdjęcie: po bokach zjadałyby kadr,
     a i tak wygodniej przesuwa się palcem (obsłużone w portfolio.js).
     Dolny rząd to ‹ | licznik | › - licznik MUSI mieć własną kolumnę,
     inaczej rozciąga się na całą szerokość i przykrywa obie strzałki. */
  .lb { grid-template-columns: auto 1fr auto; grid-template-rows: 1fr auto; }
  .lb__stage { grid-row: 1; grid-column: 1 / -1; }
  .lb__prev { grid-row: 2; grid-column: 1; }
  .lb__bar  { grid-row: 2; grid-column: 2; padding-top: 0; }
  .lb__next { grid-row: 2; grid-column: 3; }
}

/* ------------------------------- Responsywność ------------------------------- */
@media (max-width: 900px) {
  .pfp__head { grid-template-columns: 1fr; gap: 22px; }
  .pfp__facts { grid-template-columns: repeat(3, 1fr); gap: 12px; }
  .pfp__facts > div { flex-direction: column; justify-content: flex-start; gap: 4px; }
  .pfp__facts dd { text-align: left; }
  .pfp__gallery { columns: 2; }
}
@media (max-width: 620px) {
  /* Na telefonie zostają dwie kolumny, a nie jedna: przy 138 zdjęciach
     w kategorii jednokolumnowa galeria to kilometry przewijania, a kafle
     i tak są klikalnymi miniaturami, nie ostateczną formą oglądania. */
  .pfp__gallery { columns: 2; column-gap: 8px; }
  .pfp__shot { margin-bottom: 8px; }
  .pfp__shot:hover img { transform: none; }
  .pfp__facts { grid-template-columns: 1fr 1fr; }
  .pghead__stats { gap: 20px 32px; }
  .pfp.is-linked > .pfp__head::before { display: none; }
}

/* =========================================================================
   PODSTRONA: PRZYKŁADOWE SKŁADOWE PROJEKTU (przykladowy-projekt.html)
   Lista plików PDF renderowanych przez PDF.js (samples.js). Każda składowa
   to nagłówek z zakresem i opisem plus stos stron dokumentu.
   ========================================================================= */
.smp__section { padding-top: clamp(40px, 5vw, 76px); }
.smp__list { display: flex; flex-direction: column; gap: clamp(48px, 6vw, 92px); }

.smp__head {
  display: flex; flex-wrap: wrap; align-items: end; justify-content: space-between;
  gap: 14px clamp(24px, 4vw, 60px);
  padding-bottom: 18px; margin-bottom: clamp(20px, 2.6vw, 32px);
  border-bottom: var(--hair);
}
.smp__scope { display: block; font-size: 0.72rem; letter-spacing: 0.22em; text-transform: uppercase; color: var(--brass); margin-bottom: 10px; }
.smp__title { font-family: var(--display); font-size: clamp(1.8rem, 3.2vw, 2.8rem); font-weight: 500; line-height: 1.05; }
.smp__note { max-width: 56ch; margin-top: 10px; color: var(--warm-gray); text-wrap: pretty; }
.smp__open { flex: none; font-size: 0.86rem; letter-spacing: 0.04em; color: var(--graphite); border-bottom: 1px solid color-mix(in srgb, var(--taupe) 70%, transparent); padding-bottom: 3px; transition: color 0.35s var(--ease), border-color 0.35s var(--ease); }
.smp__open:hover { color: var(--brass); border-color: var(--brass); }

/* Stos stron. Papier dostaje własne tło i cień, żeby na beżu strony było
   widać, gdzie kończy się jedna kartka, a zaczyna druga. */
.smp__doc { display: flex; flex-direction: column; align-items: center; gap: clamp(14px, 2vw, 26px); }
/* Strona nigdy nie przekracza 80% wysokości okna: pionowe A4 rozciągnięte na
   szerokość kolumny wychodziło poza ekran i trzeba było przewijać jeden
   dokument przez kilka ruchów. Poziome rysunki są niższe, więc ich to nie
   dotyczy. Wyśrodkowanie robi flex (align-items), NIE `margin-inline: auto`
   z `max-width` - patrz pułapka opisana przy portfolio. */
.smp__page {
  display: block; width: auto; max-width: 100%; height: auto; max-height: 80vh;
  background: #fff;
  border: 1px solid color-mix(in srgb, var(--taupe) 55%, transparent);
  box-shadow: 0 18px 40px -30px rgba(0, 0, 0, 0.55);
}
.smp__status { color: var(--warm-gray); font-size: 0.92rem; padding-block: clamp(24px, 4vw, 48px); }
.smp__status--err { color: var(--graphite); }
.smp__status a { border-bottom: 1px solid var(--brass); }

.smp__empty { color: var(--warm-gray); padding-block: clamp(30px, 5vw, 60px); }

@media (max-width: 620px) {
  .smp__head { align-items: start; }
  .smp__open { order: 3; }
}

/* ------------------------------ Harmonogram (przykład) ------------------------------ */
/* Wiersz mówi trzy rzeczy naraz: kiedy, po czyjej stronie i co. Kolumna „kto"
   jest tu najważniejsza - pokazuje, że terminy wiążą obie strony, a nie tylko
   projektanta. Etapy z płatnością dostają mosiężny znacznik po prawej. */
.sched__note { max-width: 68ch; color: var(--warm-gray); margin-bottom: clamp(24px, 3vw, 38px); text-wrap: pretty; }
.sched { list-style: none; border-top: var(--hair); }
.sched__row {
  display: grid; grid-template-columns: auto auto 1fr auto; align-items: baseline;
  gap: 4px clamp(16px, 2.6vw, 40px);
  padding: clamp(14px, 1.8vw, 20px) 0;
  border-bottom: var(--hair);
  transition: padding-left 0.5s var(--ease);
}
.sched__row:hover { padding-left: 12px; }
.sched__date { display: flex; flex-direction: column; gap: 2px; min-width: 6.5em; }
.sched__date b { font-family: var(--num); font-size: 1.02rem; font-weight: 600; font-variant-numeric: tabular-nums lining-nums; letter-spacing: -0.01em; }
.sched__date i { font-style: normal; font-size: 0.72rem; letter-spacing: 0.1em; text-transform: uppercase; color: var(--warm-gray); }
/* „Ja" i „Ty" różnią się kolorem, nie tylko literą - przy przewijaniu widać
   rytm: kto kogo czeka. */
.sched__who {
  min-width: 2.2em; font-size: 0.72rem; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase;
  padding-bottom: 2px; border-bottom: 1px solid currentColor;
}
.sched__who[data-who="Ja"] { color: var(--graphite); }
.sched__who[data-who="Ty"] { color: var(--brass); }
.sched__what { text-wrap: pretty; }
.sched__pay {
  flex: none; font-size: 0.72rem; letter-spacing: 0.14em; text-transform: uppercase;
  color: var(--brass); white-space: nowrap;
}
.sched__row.is-pay { background: linear-gradient(90deg, color-mix(in srgb, var(--brass) 7%, transparent), transparent 62%); }

@media (max-width: 700px) {
  /* Na telefonie data i „kto" idą w jeden rząd nad opisem - cztery kolumny
     zwężone do szerokości ekranu robiły z opisu pionowy makaron. */
  .sched__row { grid-template-columns: auto auto 1fr; gap: 6px 14px; padding-block: 16px; }
  .sched__date { flex-direction: row; align-items: baseline; gap: 8px; min-width: 0; }
  .sched__what { grid-column: 1 / -1; }
  /* znacznik wpłaty wraca do pierwszego rzędu, do prawej krawędzi - pod
     opisem lądował w środku wiersza i wyglądał jak zgubiony */
  .sched__pay { grid-row: 1; grid-column: 3; justify-self: end; }
  .sched__row:hover { padding-left: 0; }
}
/* Legenda kolumny „kto" - bez niej etykiety JA/TY trzeba zgadywać. */
.sched__legend { display: flex; flex-wrap: wrap; gap: 8px clamp(18px, 3vw, 36px); margin-bottom: clamp(16px, 2vw, 24px); font-size: 0.86rem; color: var(--warm-gray); }
.sched__legend span span { margin-right: 0.5em; }
/* Informacja pod skróconym podglądem wielostronicowego pliku. */
.smp__more { align-self: flex-start; font-size: 0.86rem; color: var(--warm-gray); }
.smp__more a { border-bottom: 1px solid var(--brass); color: var(--graphite); }
.smp__more a:hover { color: var(--brass); }

/* =========================================================================
   DOKUMENTY - polityka prywatności i polityka cookies
   Dwie kolumny: przyklejony spis treści i kolumna tekstu o szerokości ~72
   znaków (dłuższy wiersz w tak długim dokumencie gubi się przy powrocie do
   lewej krawędzi). Numeracja sekcji idzie z licznika CSS, a nie z treści -
   dopisanie punktu w środku dokumentu nie wymaga przenumerowania niczego
   ręcznie, ani w tekście, ani w spisie.
   ========================================================================= */
.legal { padding-block: clamp(52px, 7vw, 96px) clamp(80px, 9vw, 140px); }
.legal__grid {
  display: grid;
  grid-template-columns: minmax(190px, 252px) minmax(0, 1fr);
  gap: clamp(28px, 4.5vw, 88px);
  align-items: start;
}

/* ------------------------------- Spis treści ------------------------------- */
.legal__toc { position: sticky; top: 92px; }
.legal__toc h2 {
  font-family: var(--ui); font-size: 0.68rem; font-weight: 600;
  letter-spacing: 0.22em; text-transform: uppercase; color: var(--warm-gray);
  padding-bottom: 14px; margin-bottom: 14px; border-bottom: var(--hair);
}
.legal__toc ol { list-style: none; counter-reset: toc; display: grid; gap: 9px; }
.legal__toc a {
  display: grid; grid-template-columns: 2.1em 1fr; align-items: baseline;
  font-size: 0.86rem; line-height: 1.35; color: var(--warm-gray);
  transition: color 0.35s var(--ease);
}
.legal__toc a::before {
  counter-increment: toc; content: counter(toc, decimal-leading-zero);
  font-family: var(--num); font-variant-numeric: tabular-nums;
  font-size: 0.7rem; font-weight: 600; letter-spacing: 0.1em; color: var(--taupe);
  transition: color 0.35s var(--ease);
}
.legal__toc a:hover { color: var(--graphite); }
.legal__toc a:hover::before { color: var(--brass); }

/* ------------------------------- Kolumna tekstu ------------------------------- */
.legal__body { max-width: 74ch; counter-reset: sec; }
.legal__body > section { padding-top: clamp(34px, 4vw, 56px); scroll-margin-top: 96px; }
.legal__body > section + section { border-top: var(--hair); margin-top: clamp(34px, 4vw, 56px); }
.legal__body h2 {
  font-family: var(--display); font-weight: 500; line-height: 1.05;
  font-size: clamp(1.5rem, 2.6vw, 2.1rem); letter-spacing: -0.01em;
  display: grid; grid-template-columns: 2.4em 1fr; align-items: baseline;
  margin-bottom: clamp(16px, 2vw, 24px);
}
.legal__body h2::before {
  counter-increment: sec; content: counter(sec, decimal-leading-zero);
  font-family: var(--num); font-variant-numeric: tabular-nums;
  font-size: 0.72rem; font-weight: 600; letter-spacing: 0.2em; color: var(--brass);
}
.legal__body h3 {
  font-family: var(--ui); font-size: 0.96rem; font-weight: 600;
  margin: clamp(22px, 2.6vw, 30px) 0 8px;
}
.legal__body p { margin-bottom: 14px; text-wrap: pretty; }
.legal__body p:last-child, .legal__body ul:last-child, .legal__body ol:last-child { margin-bottom: 0; }
.legal__body a:not(.btn) {
  color: var(--graphite); border-bottom: 1px solid var(--brass);
  transition: color 0.35s var(--ease);
}
.legal__body a:not(.btn):hover { color: var(--brass); }
.legal__body ul, .legal__body ol { margin: 0 0 14px; padding-left: 0; list-style: none; display: grid; gap: 9px; }
/* Znacznik jest ustawiony absolutnie, a nie jako pierwsza kolumna gridu:
   w gridzie każdy element potomny <li> (a więc każde <b> i każdy odsyłacz
   w treści) stawał się osobnym elementem siatki i wypadał do nowego wiersza -
   „NIP:" zostawało samo nad numerem. */
.legal__body li { position: relative; padding-left: 1.6em; text-wrap: pretty; }
.legal__body li::before { position: absolute; left: 0; top: 0; content: "\2014"; color: var(--brass); }
.legal__body ol { counter-reset: li; }
.legal__body ol > li::before {
  counter-increment: li; content: counter(li) ".";
  font-family: var(--num); font-variant-numeric: tabular-nums;
  font-size: 0.86rem; font-weight: 600; color: var(--brass);
}

/* Data ostatniej zmiany - w dokumencie prawnym to nie ozdoba, tylko
   informacja o tym, którą wersję czyta odwiedzający. */
.legal__stamp {
  display: flex; flex-wrap: wrap; gap: 8px clamp(20px, 3vw, 40px);
  font-size: 0.76rem; letter-spacing: 0.04em; color: var(--warm-gray);
  padding-top: clamp(18px, 2.4vw, 26px); margin-top: clamp(26px, 3vw, 36px);
  border-top: var(--hair);
}
.legal__stamp b { font-family: var(--num); font-weight: 600; color: var(--graphite); }

/* Wyróżniona uwaga - to, co czytelnik ma zapamiętać, nawet jeśli reszty
   sekcji nie przeczyta. */
.legal__note {
  background: var(--beige); border-left: 2px solid var(--brass);
  padding: clamp(18px, 2.4vw, 26px) clamp(18px, 2.6vw, 30px);
  margin: clamp(18px, 2.4vw, 26px) 0; font-size: 0.94rem;
}
.legal__note b { display: block; margin-bottom: 6px; }
.legal--panel .legal__note { background: var(--bone); }

/* Tabele: odbiorcy danych i wykaz ciasteczek. Tabela ma własny pasek
   przewijania w poziomie - na telefonie trzy kolumny nie zmieszczą się
   w 360 px, a cała strona nie może przez to jechać bokiem. */
.legal__tblwrap { overflow-x: auto; margin: clamp(16px, 2vw, 24px) 0; border-top: var(--hair); }
.legal__tbl { width: 100%; min-width: 520px; border-collapse: collapse; font-size: 0.88rem; }
.legal__tbl th, .legal__tbl td { text-align: left; vertical-align: top; padding: 13px 18px 13px 0; border-bottom: var(--hair); }
.legal__tbl th {
  font-size: 0.68rem; font-weight: 600; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--warm-gray); white-space: nowrap;
}
.legal__tbl td b { font-family: var(--num); font-weight: 600; }
.legal__tbl tr:last-child td { border-bottom: 0; }

/* Odsyłacz do drugiego dokumentu - obie polityki czyta się razem. */
.legal__pair {
  display: flex; flex-wrap: wrap; gap: 14px;
  padding-top: clamp(28px, 3.4vw, 44px); margin-top: clamp(28px, 3.4vw, 44px);
  border-top: var(--hair);
}

@media (max-width: 900px) {
  /* Spis treści przestaje być kolumną i staje się nagłówkiem dokumentu:
     przyklejony pasek na wysokości ekranu telefonu zjadłby pół widoku. */
  .legal__grid { grid-template-columns: minmax(0, 1fr); gap: clamp(26px, 5vw, 40px); }
  .legal__toc { position: static; padding-bottom: clamp(22px, 4vw, 32px); border-bottom: var(--hair); }
  .legal__toc ol { grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 9px 22px; }
  .legal__body { max-width: none; }
}
@media (max-width: 560px) {
  .legal__toc ol { grid-template-columns: minmax(0, 1fr); }
  /* Numer sekcji wraca nad nagłówek - w kolumnie o szerokości 320 px
     odbierał tytułowi 2,4em, przez co dwuwyrazowy nagłówek łamał się na trzy. */
  .legal__body h2 { grid-template-columns: minmax(0, 1fr); gap: 6px; }
}

/* Odnośniki do dokumentów prawnych w stopce, w kolumnie „Dane firmy" -
   oddzielone kreską, żeby nie zlewały się z NIP-em i REGON-em. */
.foot__legal { margin-top: 16px; padding-top: 14px; border-top: 1px solid rgba(201, 183, 158, 0.2); }
/* Odnośnik do polityki prywatności przy zgodzie w formularzu. Kliknięcie
   linku nie przełącza checkboksa - przeglądarka nie aktywuje etykiety, gdy
   celem kliknięcia jest element interaktywny, a <a href> nim jest. */
.form__check a { color: var(--graphite); border-bottom: 1px solid var(--brass); }
.form__check a:hover { color: var(--brass); }
