/*
 * Kroje pisma stoja na wlasnym serwerze (assets/fonts, budowane przez
 * tools/fonts.py). Wczesniej szly z Google Fonts i kosztowaly lancuch dwoch
 * polaczen przed pierwsza litera: arkusz z fonts.googleapis.com wskazywal
 * dopiero pliki na fonts.gstatic.com. Do tego 258 kB, bo Newsreader jest
 * krojem dwuosiowym z pelnym zestawem znakow. Teraz to 88 kB w dwoch plikach
 * spod tego samego adresu, wstepnie wczytywanych z <head>.
 *
 * Zakresy grubosci sa dokladnie te, ktore deklarowal arkusz Google, wiec
 * scinanie ciezszych wartosci (font-weight: 750 i 780 w tym pliku) dziala
 * tak samo jak wczesniej.
 */
@font-face {
  font-family: 'Manrope';
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url('/assets/fonts/manrope.woff2') format('woff2');
}

@font-face {
  font-family: 'Newsreader';
  font-style: normal;
  font-weight: 500 700;
  font-display: swap;
  src: url('/assets/fonts/newsreader.woff2') format('woff2');
}

/*
 * Znak klienta (mark-gold.webp) to zloto ~#e0a532 na czerni. Wczesniej zloto
 * robilo na stronie cala robote kolorystyczna — przyciski, liczby, szyny,
 * punktory — i przez to caly uklad czytal sie jak szablon "premium
 * nieruchomosci". Teraz jest odwrotnie: pracuje czern, a zloto jest dodatkiem.
 *
 * Neutrale sa prawie bezbarwne (chroma 3-10%), zeby zloto bylo jedynym
 * nasyconym punktem na ekranie. Wczesniejszy krem miał 28% nasycenia i to on
 * dawal efekt "wygenerowanego" tla.
 *
 * --accent to akcent KONTEKSTOWY: na jasnym tle czern, a wewnatrz ciemnych
 * pasow przelacza sie na zloto (blok ".band, .tone-navy, .cta, .foot" nizej),
 * bo czerni na czerni po prostu nie widac. Dzieki temu kazde var(--accent)
 * w tym pliku dziala w obu kontekstach bez pisania wyjatkow przy kazdej regule.
 */
:root {
  /*
   * Biel, czern i zloto. Wczesniej neutrale mialy odcien piaskowy (hue 30-40,
   * nasycenie 4-10%) i to wlasnie ten kremowy papier kazal czytac strone jako
   * wydruk, a nie jako strone. Teraz tlo jest czysta biela, wszystkie szarosci
   * sa bezbarwne, a jedynym nasyconym kolorem na ekranie zostaje zloto ze znaku.
   * Podzial 60/30/10 wychodzi sam: biel niesie strone, czern robi typografie
   * i ciemne pasy, zloto zostaje na akcenty i pojedyncze liczby.
   */
  --bg: 0 0% 100%;
  --surface: 0 0% 100%;
  --surface-2: 0 0% 97%;
  --surface-3: 0 0% 93%;
  --ink: 0 0% 7%;
  --ink-2: 0 0% 27%;
  /* 43% to 5,1:1 na bieli i 4,9:1 na --surface-2, czyli AA takze na pasach. */
  --muted: 0 0% 43%;
  --brand: 0 0% 6%;
  --brand-2: 0 0% 13%;
  --brand-3: 0 0% 30%;

  /* Akcent podstawowy: czern. */
  --accent: 0 0% 8%;
  --accent-2: 0 0% 18%;
  --accent-ink: 0 0% 8%;
  --accent-lt: 0 0% 36%;
  --accent-soft: 0 0% 96%;

  /* Zloto ze znaku. Uzywane oszczednie i zawsze swiadomie. */
  --gold: 41 74% 54%;
  --gold-2: 38 70% 42%;
  --gold-ink: 34 66% 29%;
  --gold-lt: 43 82% 70%;

  /*
   * Tekst na ciemnych powierzchniach. Bylo tu kilkanascie wartosci wpisanych
   * wprost, wszystkie z odcieniem 32-38 stopni i nasyceniem 4-6% — czyli ten
   * sam kremowy nalot, ktory zniknal juz z jasnej czesci strony. Na czerni
   * widac go slabiej, ale to nadal jest trzeci kolor w palecie, ktora ma miec
   * dwa i zloto. Kontrast na --brand: 17:1, 10:1 i 5,9:1, czyli AA nawet dla
   * najciemniejszego stopnia.
   */
  --on-dark: 0 0% 92%;
  --on-dark-2: 0 0% 74%;
  --on-dark-3: 0 0% 58%;

  --line: 0 0% 90%;
  --line-2: 0 0% 80%;
  --sh-1: 0 0 0 1px hsl(var(--line));
  --sh-2: 0 0 0 1px hsl(var(--line-2));
  --sh-3: 0 0 0 1.5px hsl(var(--ink) / 0.72);
  /*
   * Promienie. Wczesniej wszystko bylo na zero i uklad czytal sie jak
   * dokument zlozony w edytorze tekstu, a nie jak strona — same prostokaty
   * na plaskim tle. Promien jest maly, wiec nie zabiera powagi, ale wystarczy,
   * zeby kafelek, przycisk i pole formularza wygladaly na element interfejsu.
   */
  --r-sm: 6px;
  --r: 10px;
  --r-lg: 14px;
  --r-xl: 20px;
  --r-pill: 999px;
  --sans: 'Manrope', ui-sans-serif, system-ui, sans-serif;
  --serif: 'Newsreader', 'Times New Roman', Georgia, serif;
  --pad: clamp(20px, 5vw, 52px);
  --max: 1260px;

  /*
   * Drabinka odstepow. Wczesniej kazda sekcja miala wlasny clamp() —
   * bylo ich okolo pieciudziesieciu i roznily sie o cztery piksele bez
   * powodu. Szczeble sa zakotwiczone w wartosciach, ktore juz tu byly,
   * wiec przejscie na tokeny nie przestroilo rytmu. --pad zostaje osobno:
   * to rynna strony, nie rytm pionowy.
   */
  --s-1: 8px;
  --s-2: 12px;
  --s-3: clamp(14px, 2vw, 18px);
  --s-4: clamp(18px, 2.4vw, 26px);
  --s-5: clamp(22px, 3vw, 34px);
  --s-6: clamp(28px, 3.6vw, 44px);
  --s-7: clamp(34px, 4.4vw, 56px);
  --s-8: clamp(40px, 5vw, 68px);
  --s-9: clamp(54px, 6vw, 96px);
  /*
   * Rytm sekcji. 96 px z gory i z dolu dawalo na stronie glownej ponad
   * 11 000 px wysokosci — oferty zaczynaly sie dopiero na trzecim ekranie.
   * 72 px czyta sie tak samo spokojnie, a skraca droge do tresci o kilkaset
   * pikseli na kazdej sekcji.
   */
  --sec: clamp(42px, 4.6vw, 72px);

  /* Wysokosc naglowka byla wpisana na sztywno w czterech miejscach. */
  --head-h: 78px;

  /*
   * Mocniejszy ease-out niz wbudowane krzywe: ruch startuje od razu,
   * wiec interfejs odpowiada w momencie, w ktorym patrzy sie najuwazniej.
   * --ease-out jest do krotkich reakcji (nacisniecie, podswietlenie).
   */
  --ease: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-out: cubic-bezier(0.33, 1, 0.68, 1);
}

/*
 * Przelacznik akcentu dla ciemnych powierzchni. Czern jako akcent dziala
 * tylko na papierze; na czarnym pasie znika, wiec tam akcentem zostaje zloto
 * ze znaku. To jedno miejsce zastepuje kilkadziesiat wyjatkow rozsianych
 * po pliku — kazde var(--accent) nizej samo trafia we wlasciwy kolor.
 */
.band,
.tone-navy,
.cta,
.foot,
.consent,
.float-contact__main,
.lightbox,
.hero__stamp,
.calc__out,
.offers-toggle:hover {
  --accent: var(--gold);
  --accent-2: var(--gold);
  --accent-ink: var(--gold);
  --accent-lt: var(--gold-lt);
}

*,
*::before,
*::after {
  box-sizing: border-box;
}

* {
  margin: 0;
}

html {
  -webkit-text-size-adjust: 100%;
  scroll-behavior: smooth;
}

/*
 * Tlo. Byla tu siatka milimetrowa w kremowym odcieniu — mialo to nawiazywac
 * do operatow szacunkowych, a czytalo sie jak papier w kratke pod tekstem.
 * Zostaje czysta biel. Cala glebia strony ma teraz pochodzic z tresci:
 * z ciemnych pasow, ze zdjec i z cieni pod kafelkami, a nie z deseniu.
 */
body {
  position: relative;
  background-color: hsl(var(--bg));
  color: hsl(var(--ink));
  font-family: var(--sans);
  font-size: 1rem;
  line-height: 1.7;
  font-weight: 450;
  letter-spacing: -0.005em;
  -webkit-font-smoothing: antialiased;
  overflow-x: hidden;
}

/*
 * Tlo stoi, gdy na wierzchu jest menu, arkusz filtrow albo lightbox.
 * Klasa zamiast stylu inline: trzy mechanizmy potrafia trzymac blokade
 * naraz i zdejmuje ja dopiero ostatni z nich (lockScroll w main.js).
 */
body.is-locked {
  overflow: hidden;
}

/*
 * Ziarno na calej stronie tez znikneło. Przy kremowym tle bylo niewidoczne,
 * ale polozone na bieli przez mix-blend-mode: multiply robilo z niej brudna
 * szarosc — bialy ekran przestawal byc bialy. Czystej bieli nie da sie
 * poprawic warstwa szumu na wierzchu.
 */

img,
svg,
video {
  display: block;
  max-width: 100%;
}

img {
  height: auto;
}

a {
  color: inherit;
  text-decoration: none;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

button {
  background: none;
  border: 0;
  cursor: pointer;
}

ul,
ol {
  list-style: none;
  padding: 0;
}

/* Naglowki na kroju dekoracyjnym. Trackingu nie zaciskamy tak mocno jak przy
   grotesku — serif ma wlasny rytm i przy -0.035em zaczyna sie zlepiac. */
h1,
h2,
h3,
h4 {
  font-family: var(--serif);
  font-weight: 600;
  line-height: 1.05;
  letter-spacing: -0.022em;
  text-wrap: balance;
}

:focus-visible {
  outline: 2px solid hsl(var(--accent-2));
  outline-offset: 3px;
  border-radius: 2px;
}

::selection {
  background: hsl(var(--accent));
  color: hsl(var(--surface));
}

.wrap {
  width: 100%;
  max-width: var(--max);
  margin-inline: auto;
  padding-inline: var(--pad);
}

.sec {
  padding-block: var(--sec);
}

.sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  font-size: 0.7rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: hsl(var(--accent-ink));
}

.eyebrow::before {
  content: '';
  width: 30px;
  height: 3px;
  background: hsl(var(--accent));
}

.h1 {
  font-size: clamp(2.6rem, 6.2vw, 4.6rem);
}

.h2 {
  font-size: clamp(2rem, 4.2vw, 3.25rem);
}

.h3 {
  font-size: clamp(1.35rem, 2.2vw, 1.75rem);
}

.lead {
  font-size: clamp(1.02rem, 1.35vw, 1.17rem);
  line-height: 1.72;
  color: hsl(var(--ink-2));
  max-width: 62ch;
}

.sec__head {
  display: flex;
  flex-direction: column;
  gap: 14px;
  margin-bottom: var(--s-6);
  max-width: 62ch;
}

.btn {
  --btn-bg: transparent;
  --btn-fg: hsl(var(--ink));
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 52px;
  padding: 0 28px;
  border-radius: var(--r);
  background: var(--btn-bg);
  color: var(--btn-fg);
  font-size: 0.94rem;
  font-weight: 650;
  letter-spacing: -0.01em;
  white-space: nowrap;
  isolation: isolate;
  overflow: hidden;
  transition: transform 0.16s var(--ease-out), box-shadow 0.24s var(--ease), opacity 0.18s linear;
}

.btn > span,
.btn > svg {
  position: relative;
  z-index: 2;
}

.btn svg {
  width: 18px;
  height: 18px;
  flex: none;
}

.btn::after {
  content: '';
  position: absolute;
  inset: 0;
  z-index: 1;
  background: hsl(0 0% 100% / 0.14);
  opacity: 0;
  transition: opacity 0.18s var(--ease-out);
}

.btn--primary {
  --btn-bg: hsl(var(--brand));
  --btn-fg: #fff;
  box-shadow: 0 2px 4px hsl(var(--brand) / 0.18), 0 14px 28px -10px hsl(var(--brand) / 0.5);
}

.btn--primary::after {
  background: hsl(var(--accent) / 0.24);
}

/*
 * Glowne CTA. Wypelnienie jest czarne jak .btn--primary, ale dostaje zlota
 * krawedz od spodu — tyle zlota, zeby bylo wiadomo, ze to ten wazniejszy
 * przycisk, i nie wiecej.
 */
.btn--gold {
  --btn-bg: hsl(var(--accent));
  --btn-fg: #fff;
  box-shadow: inset 0 -3px 0 hsl(var(--gold)), 0 2px 4px hsl(var(--ink) / 0.18),
    0 16px 30px -12px hsl(var(--ink) / 0.5);
}

.band .btn--gold,
.tone-navy .btn--gold,
.cta .btn--gold,
.foot .btn--gold {
  box-shadow: none;
}

.band .btn--gold:hover,
.tone-navy .btn--gold:hover,
.cta .btn--gold:hover,
.foot .btn--gold:hover {
  box-shadow: 0 14px 28px -16px hsl(0 0% 0% / 0.85);
}

.btn--gold::after {
  background: hsl(var(--ink) / 0.1);
}

.btn--gold:hover {
  box-shadow: inset 0 -3px 0 hsl(var(--gold)), 0 4px 8px hsl(var(--ink) / 0.2),
    0 24px 44px -14px hsl(var(--ink) / 0.55);
}

.btn--line {
  --btn-fg: hsl(var(--ink));
  box-shadow: inset 0 0 0 1.5px hsl(var(--ink) / 0.2);
}

.btn--line::after {
  background: hsl(var(--accent) / 0.16);
}

.btn--line:hover {
  box-shadow: inset 0 0 0 1.5px hsl(var(--accent-2) / 0.65);
}

.btn--ghost {
  --btn-fg: hsl(var(--ink-2));
}

.btn--ghost::after {
  background: hsl(var(--accent) / 0.16);
}

.btn--sm {
  min-height: 42px;
  padding: 0 18px;
  font-size: 0.86rem;
}

.btn--full {
  width: 100%;
}

.btn:hover {
  transform: translateY(-2px);
}

.btn:hover::after {
  opacity: 1;
}

.btn--primary:hover {
  box-shadow: 0 4px 8px hsl(var(--brand) / 0.2), 0 22px 40px -12px hsl(var(--brand) / 0.55);
}

/*
 * Na czarnym pasie czarny przycisk znika, wiec podstawowe CTA odwraca sie na
 * papier. Zlota krawedz zostaje ta sama co na jasnym tle, wiec przycisk jest
 * rozpoznawalny jako ten sam element w obu kontekstach.
 */
.band .btn--primary,
.tone-navy .btn--primary,
.foot .btn--primary,
.doradca .btn--primary {
  --btn-bg: hsl(var(--surface));
  --btn-fg: hsl(var(--ink));
  box-shadow: inset 0 -3px 0 hsl(var(--gold)), 0 2px 4px hsl(0 0% 0% / 0.4),
    0 18px 34px -14px hsl(0 0% 0% / 0.75);
}

.band .btn--primary::after,
.tone-navy .btn--primary::after,
.foot .btn--primary::after,
.doradca .btn--primary::after {
  background: hsl(var(--ink) / 0.12);
}

/*
 * Na ciemnym tle --accent to zloto, wiec .btn--gold dostalby biale litery na
 * zlocie — 2,1:1, nieczytelne. Na pasach i na belce zgody jedzie ten sam
 * papierowy przycisk co .btn--primary.
 */
.band .btn--gold,
.tone-navy .btn--gold,
.cta .btn--gold,
.foot .btn--gold,
.consent .btn--gold {
  --btn-bg: hsl(var(--surface));
  --btn-fg: hsl(var(--ink));
  box-shadow: inset 0 -3px 0 hsl(var(--gold));
}

.band .btn--gold:hover,
.tone-navy .btn--gold:hover,
.cta .btn--gold:hover,
.foot .btn--gold:hover,
.consent .btn--gold:hover {
  box-shadow: inset 0 -3px 0 hsl(var(--gold)), 0 14px 28px -16px hsl(0 0% 0% / 0.85);
}

.band .btn--primary:hover,
.tone-navy .btn--primary:hover,
.foot .btn--primary:hover {
  box-shadow: inset 0 -3px 0 hsl(var(--gold)), 0 4px 8px hsl(0 0% 0% / 0.42),
    0 26px 46px -16px hsl(0 0% 0% / 0.8);
}

/* Obrys w kolorze atramentu ginal na ciemnym pasie tak samo jak wypelnienie. */
.band .btn--line,
.tone-navy .btn--line,
.foot .btn--line {
  --btn-fg: #fff;
  box-shadow: inset 0 0 0 1.5px hsl(0 0% 100% / 0.28);
}

.band .btn--line:hover,
.tone-navy .btn--line:hover,
.foot .btn--line:hover {
  box-shadow: inset 0 0 0 1.5px hsl(var(--accent) / 0.8);
}

/*
 * Hover unosi przycisk o 2 px, a :active podmienialo caly transform na samo
 * skalowanie — klikniecie zrzucalo przycisk na dol i dopiero potem go
 * sciskalo. Nacisniecie ma byc dociazeniem tego samego ruchu, nie jego
 * skasowaniem, wiec uniesienie zostaje, tylko mniejsze.
 */
.btn:active {
  transform: translateY(-1px) scale(0.98);
}

.btn[disabled] {
  opacity: 0.5;
  pointer-events: none;
}

.head {
  position: sticky;
  top: 0;
  z-index: 90;
  background: hsl(var(--bg) / 0.86);
  backdrop-filter: blur(18px) saturate(1.4);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
  box-shadow: 0 1px 0 hsl(var(--line) / 0);
  transition: box-shadow 0.3s var(--ease), background-color 0.3s var(--ease);
}

body.home .head {
  background: hsl(var(--bg) / 0);
  backdrop-filter: none;
  -webkit-backdrop-filter: none;
}

body.home .head.is-stuck {
  background: hsl(var(--bg) / 0.88);
  backdrop-filter: blur(18px) saturate(1.4);
  -webkit-backdrop-filter: blur(18px) saturate(1.4);
}

.head.is-stuck {
  box-shadow: 0 1px 0 hsl(var(--line)), 0 10px 28px -22px hsl(var(--ink) / 0.5);
}

.head.is-stuck .head__in::after {
  transform: scaleX(1);
}

.head__in::after {
  content: '';
  position: absolute;
  inset: auto 0 -1px;
  height: 2px;
  background: hsl(var(--accent));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.6s var(--ease);
}

.head__in {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: clamp(16px, 3vw, 40px);
  height: var(--head-h);
}

.head__brand {
  display: contents;
}

.nav__logo {
  display: flex;
  align-items: center;
  gap: 11px;
  flex: none;
  margin-inline-end: auto;
}

.nav__logo img {
  height: 38px;
  width: 38px;
  flex: none;
  object-fit: cover;
  background: hsl(var(--ink));
}

.brandword {
  display: grid;
  line-height: 1.16;
}

.brandword b {
  font-family: var(--serif);
  font-size: 1.02rem;
  font-weight: 750;
  letter-spacing: -0.035em;
  white-space: nowrap;
}

/*
 * Ponizej 360 px dopisek pod nazwiskiem nie miescil sie w wierszu naglowka
 * i wypychal przycisk menu poza ekran — cala strona dostawala wtedy pasek
 * przewijania w poziomie. Na tej szerokosci samo nazwisko wystarczy;
 * czym sie zajmuje, mowi pierwszy ekran dwie linijki nizej.
 */
@media (max-width: 359px) {
  .brandword i {
    display: none;
  }
}

.brandword i {
  font-style: normal;
  font-size: 0.58rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: hsl(var(--accent-ink));
  white-space: nowrap;
}

.nav__links {
  display: none;
  align-items: center;
  justify-content: center;
  gap: clamp(12px, 1.6vw, 26px);
}

.nav__links a {
  position: relative;
  font-size: 0.92rem;
  font-weight: 600;
  color: hsl(var(--ink-2));
  padding-block: 6px;
  transition: color 0.2s var(--ease);
}

.nav__links a::after {
  content: '';
  position: absolute;
  left: 0;
  bottom: 0;
  width: 100%;
  height: 2px;
  background: hsl(var(--gold));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.32s var(--ease);
}

.nav__links a:hover,
.nav__links a[aria-current='page'] {
  color: hsl(var(--ink));
}

.nav__links a:hover::after,
.nav__links a[aria-current='page']::after {
  transform: scaleX(1);
}

.head__cta {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: 10px;
  grid-column: -2;
}

.nav__tel {
  display: none;
}

.nav__phone-link {
  color: hsl(var(--ink)) !important;
  font-weight: 750 !important;
  font-variant-numeric: tabular-nums;
}

.nav__contact {
  display: none;
}

.nav__burger {
  display: grid;
  place-content: center;
  gap: 5px;
  width: 44px;
  height: 44px;
  border-radius: 12px;
  box-shadow: inset 0 0 0 1px hsl(var(--line-2));
}

.nav__burger i {
  display: block;
  width: 18px;
  height: 1.6px;
  background: hsl(var(--ink));
  transition: transform 0.32s var(--ease), opacity 0.2s linear;
}

.nav__burger[aria-expanded='true'] i:first-child {
  transform: translateY(3.3px) rotate(45deg);
}

.nav__burger[aria-expanded='true'] i:last-child {
  transform: translateY(-3.3px) rotate(-45deg);
}

.menu {
  position: fixed;
  inset: 78px 0 auto;
  z-index: 89;
  background: hsl(var(--surface));
  border-block-end: 1px solid hsl(var(--line));
  box-shadow: var(--sh-2);
  padding: 20px var(--pad) 32px;
  display: grid;
  gap: 2px;
  transform: translateY(-12px);
  opacity: 0;
  visibility: hidden;
  transition: transform 0.34s var(--ease), opacity 0.24s linear, visibility 0.34s;
}

.menu.is-open {
  transform: translateY(0);
  opacity: 1;
  visibility: visible;
}

.menu a {
  font-family: var(--serif);
  font-size: 1.4rem;
  letter-spacing: -0.03em;
  padding-block: 10px;
}

.menu__sep {
  height: 1px;
  background: hsl(var(--line));
  margin-block: 14px;
}

.menu a[href^='tel'],
.menu a[href^='mailto'] {
  font-family: var(--sans);
  font-size: 0.95rem;
  font-weight: 600;
  color: hsl(var(--ink-2));
  padding-block: 4px;
}

.hero {
  position: relative;
  min-height: clamp(540px, 76svh, 760px);
  display: grid;
  align-items: center;
  padding-block: clamp(30px, 5vw, 68px) clamp(44px, 6vw, 84px);
  overflow: hidden;
}

/*
 * Siatka jest juz na body i ciagnie sie przez cala strone. Hero dostaje tylko
 * dogeszczenie po stronie zdjecia, zeby pierwszy ekran mial mocniejszy grunt
 * — bez powielania linii, bo dwie siatki o roznym punkcie zaczepienia
 * daja more.
 */
/*
 * Dogeszczenie po stronie zdjecia. Na kremowym tle bylo widac je jako lekkie
 * swiatlo; na bieli te sama warstwa robila szara plame w prawym gornym rogu.
 * Zostaje ledwie wyczuwalny cien od dolu, ktory osadza zdjecie na stronie.
 */
.hero::before {
  content: '';
  position: absolute;
  inset: 0;
  background: radial-gradient(100% 70% at 72% 95%, hsl(var(--ink) / 0.05) 0%, transparent 60%);
  pointer-events: none;
}

.hero__in {
  position: relative;
  z-index: 2;
  display: grid;
  gap: var(--s-7);
}

.hero__copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 20px;
}

/*
 * Wejscie pierwszego ekranu. Wczesniej robil to GSAP, przez co zdjecie
 * i tekst czekaly na 116 kB biblioteki: przy wolnym laczu bylo widac ekran
 * gotowy, a potem skok do stanu ukrytego i dopiero animacje. Tu nie ma
 * czego czekac — animacja startuje razem z pierwszym odmalowaniem i zawsze
 * dobiega do konca, wiec nie da sie zostac w stanie niewidocznym.
 *
 * Poza tym blokiem nic sie nie zmienia: przy ograniczonym ruchu deklaracji
 * po prostu nie ma, a strona jest kompletna od pierwszej klatki.
 */
@media (prefers-reduced-motion: no-preference) {
  .hero__media-in {
    animation: hero-media 1.2s cubic-bezier(0.65, 0, 0.35, 1) both;
  }

  .hero__copy > * {
    animation: hero-copy 0.85s var(--ease) both;
    animation-delay: 0.25s;
  }

  /* Kaskada po kolejnosci w ukladzie, a nie po numerze wpisanym w znacznik:
     puste gniazda (np. brak dopisku nad naglowkiem) znikaja po stronie
     serwera i kaskada ma sie wtedy zsunac, a nie zostawic dziure. */
  .hero__copy > *:nth-child(2) { animation-delay: 0.37s; }
  .hero__copy > *:nth-child(3) { animation-delay: 0.49s; }
  .hero__copy > *:nth-child(4) { animation-delay: 0.61s; }
  .hero__copy > *:nth-child(5) { animation-delay: 0.73s; }
}

@keyframes hero-media {
  from {
    clip-path: inset(100% 0% 0% 0%);
    transform: scale(1.03);
  }
  to {
    clip-path: inset(0% 0% 0% 0%);
    transform: none;
  }
}

@keyframes hero-copy {
  from {
    opacity: 0;
    transform: translateY(22px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.hero__title {
  display: grid;
  font-size: clamp(2.3rem, 4.6vw, 4rem);
  line-height: 1.02;
  letter-spacing: -0.025em;
  max-width: 15ch;
}

.hero__title span {
  display: block;
}

.hero__title span i {
  font-style: inherit;
  background-image: linear-gradient(hsl(var(--gold) / 0.55), hsl(var(--gold) / 0.55));
  background-repeat: no-repeat;
  background-position: 0 88%;
  background-size: 100% 0.18em;
  -webkit-box-decoration-break: clone;
  box-decoration-break: clone;
}

.hero__lead {
  max-width: 46ch;
}

/* Pole moze zostac puste w panelu - wtedy nie zostawia dziury w ukladzie. */
.hero__lead:empty {
  display: none;
}

.hero__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-block-start: 6px;
}

/*
 * Wyszukiwarka w pierwszym ekranie.
 *
 * Klient nie ma tu szukac wzrokiem, gdzie sa oferty — ma wpisac miasto i cene
 * i kliknac. Formularz idzie metoda GET prosto na /nieruchomosci, wiec dziala
 * nawet z wylaczonym skryptem, a wynik ma wlasny adres do wyslania dalej.
 * Nazwy pol (miasto, typ, cena) sa te same, ktore czyta pasek filtrow tam,
 * na miejscu — nie ma drugiego slownika parametrow do utrzymania.
 */
.qsearch {
  width: 100%;
  max-width: 560px;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 10px;
  margin-block-start: 4px;
  padding: var(--s-3);
  border: 1px solid hsl(var(--line));
  border-radius: var(--r-lg);
  background: hsl(var(--surface) / 0.92);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  box-shadow: 0 24px 60px -40px hsl(var(--ink) / 0.55);
}

.qsearch__f {
  display: grid;
  gap: 5px;
  min-width: 0;
}

.qsearch__f label {
  font-size: 0.72rem;
  font-weight: 750;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: hsl(var(--muted));
}

.qsearch__f select,
.qsearch__f input {
  width: 100%;
  min-width: 0;
  min-height: 46px;
  padding: 0 12px;
  border: 1px solid hsl(var(--line-2));
  border-radius: var(--r-sm);
  background: hsl(var(--surface));
  color: hsl(var(--ink));
  font: inherit;
  font-size: 0.94rem;
}

/* Strzalka rysowana, nie systemowa — inaczej kazda przegladarka daje inna. */
.qsearch__f select {
  appearance: none;
  -webkit-appearance: none;
  padding-inline-end: 34px;
  background-image: linear-gradient(45deg, transparent 50%, hsl(var(--ink-2)) 50%), linear-gradient(135deg, hsl(var(--ink-2)) 50%, transparent 50%);
  background-position: calc(100% - 18px) 21px, calc(100% - 13px) 21px;
  background-size: 5px 5px;
  background-repeat: no-repeat;
}

.qsearch__f select:focus-visible,
.qsearch__f input:focus-visible {
  outline: 2px solid hsl(var(--gold));
  outline-offset: 1px;
  border-color: hsl(var(--gold));
}

.qsearch__go {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 9px;
  min-height: 46px;
  padding: 0 20px;
  border: 0;
  border-radius: var(--r-sm);
  background: hsl(var(--ink));
  color: #fff;
  font: inherit;
  font-size: 0.94rem;
  font-weight: 700;
  cursor: pointer;
  box-shadow: inset 0 -3px 0 hsl(var(--gold));
  transition: transform 0.16s var(--ease-out), background 0.2s linear;
}

.qsearch__go svg {
  width: 17px;
  height: 17px;
  flex: none;
}

.qsearch__go:hover {
  transform: translateY(-2px);
  background: hsl(var(--brand-2));
}

.qsearch__go:active {
  transform: none;
}

/* Wariant przy ofertach: rozciaga sie na cala szerokosc sekcji. */
.qsearch--wide {
  max-width: none;
  margin-block-end: var(--s-5);
}

@media (min-width: 560px) {
  .qsearch {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    align-items: end;
  }
}

@media (min-width: 900px) {
  /* Trzy pola i przycisk w jednym rzedzie — pasek, a nie formularz. */
  .qsearch--wide {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) auto;
    gap: 14px;
  }
}

@media (prefers-reduced-motion: reduce) {
  .qsearch__go {
    transition: none;
  }
}

.hero__proof {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 10px 26px;
  margin-block-start: 14px;
  padding-block-start: 20px;
  border-block-start: 1px solid hsl(var(--line));
  width: 100%;
  max-width: 46ch;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.02em;
  color: hsl(var(--ink-2));
}

.hero__proof span {
  display: inline-flex;
  align-items: center;
  gap: 8px;
}

/*
 * Wczesniej kazdy dowod mial przed soba czarny kwadracik. Trzy kwadraciki
 * jeden pod drugim to punktowana lista z edytora tekstu — dokladnie ten
 * detal, ktory kazal czytac cala strone jako wydruk. Teraz to etykiety
 * ze zlota kreska, ustawione w wiersz.
 */
.hero__proof span::before {
  content: '';
  width: 14px;
  height: 2px;
  flex: none;
  border-radius: var(--r-pill);
  background: hsl(var(--gold));
}

.hero__media {
  position: relative;
  aspect-ratio: 1 / 1;
}

.hero__media::before {
  content: '';
  position: absolute;
  inset: clamp(14px, 2vw, 26px) calc(clamp(14px, 2vw, 26px) * -1) calc(clamp(14px, 2vw, 26px) * -1) clamp(14px, 2vw, 26px);
  border: 1.5px solid hsl(var(--accent) / 0.85);
  border-radius: var(--r-lg);
  pointer-events: none;
}

/*
 * Przesunieta ramka za kadrem ma sens tylko pod zdjeciem: dodaje mu glebi.
 * Za czarna plyta ze znakiem czyta sie jak zabladzony prostokat, wiec tam
 * jej nie ma.
 */
.hero__media:has(.ph--brand)::before {
  display: none;
}

.hero__media-in {
  position: relative;
  z-index: 2;
  width: 100%;
  height: 100%;
  overflow: hidden;
  border-radius: var(--r-lg);
  background: hsl(var(--surface-3));
  box-shadow: 0 34px 80px -46px hsl(var(--ink) / 0.6), var(--sh-2);
}

.hero__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.hero__media-in::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, hsl(var(--brand) / 0.34), transparent 46%);
  pointer-events: none;
}

.hero__stamp {
  position: absolute;
  z-index: 3;
  left: 0;
  bottom: clamp(18px, 3vw, 30px);
  display: grid;
  gap: 8px;
  justify-items: start;
  padding: 16px clamp(18px, 2vw, 24px);
  border-radius: 0 var(--r) var(--r) 0;
  background: hsl(var(--ink));
  color: #fff;
  box-shadow: 0 20px 44px -26px hsl(var(--ink) / 0.9);
}

/*
 * Znak w oryginalnym pliku, nie przerysowany. Zloto na czerni to jedyny uklad,
 * w ktorym ten logotyp dziala, wiec czarna tabliczka na zdjeciu jest jedynym
 * miejscem w pierwszym ekranie, gdzie moze stanac w calosci.
 *
 * Selektor musi byc mocniejszy niz `.hero__media img`, ktore rozciaga zdjecie
 * na caly kadr — bez tego znak dostawal 100% szerokosci i wychodzil poza
 * tabliczke.
 */
.hero__media .hero__stamp-logo {
  width: clamp(150px, 15vw, 196px);
  height: auto;
}

/*
 * Plyta ze znakiem w miejscu brakujacego portretu. Nie jest kadrem
 * zastepczym w zwyklym sensie: ma wygladac na swiadomy blok marki, wiec
 * dostaje pelna czern, znak w srodku i jedna linijke wyjasnienia pod nim.
 */
.ph.ph--brand {
  background: hsl(var(--brand));
  box-shadow: none;
  gap: var(--s-4);
}

.ph.ph--brand::before {
  inset: 16px;
  border-color: hsl(var(--gold) / 0.3);
}

.ph.ph--brand .ph__logo {
  position: relative;
  width: min(62%, 320px);
  height: auto;
}

.ph.ph--brand .ph__label {
  position: relative;
  color: hsl(0 0% 100% / 0.62);
}

.hero__stamp b {
  font-size: 0.92rem;
  font-weight: 750;
  letter-spacing: -0.02em;
}

.hero__stamp span {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: hsl(var(--accent));
}

.hero__media .ph:not(.ph--brand) {
  background: hsl(var(--surface));
}

.hero__media .ph::before {
  inset: clamp(18px, 2.5vw, 32px);
}

/* Plyta ze znakiem ma wlasny, ciasniejszy margines ramki. */
.hero__media .ph.ph--brand::before {
  inset: clamp(14px, 1.8vw, 24px);
}

.hero__media .ph__mark {
  width: clamp(72px, 10vw, 132px);
  height: clamp(72px, 10vw, 132px);
  opacity: 0.22;
}

.hero__media .ph__label {
  font-size: clamp(0.88rem, 1vw, 1rem);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.hero__badge {
  position: absolute;
  z-index: 2;
  left: clamp(16px, 3vw, 26px);
  bottom: clamp(16px, 3vw, 26px);
  right: clamp(16px, 3vw, 26px);
  display: flex;
  align-items: center;
  gap: 14px;
  padding: 14px 18px;
  border-radius: var(--r);
  background: hsl(var(--surface) / 0.94);
  backdrop-filter: blur(10px);
  box-shadow: var(--sh-2);
}

.hero__badge svg {
  width: 26px;
  height: 26px;
  flex: none;
  color: hsl(var(--brand));
}

.hero__badge b {
  display: block;
  font-size: 0.9rem;
  font-weight: 750;
  line-height: 1.35;
}

.hero__badge span {
  font-size: 0.78rem;
  color: hsl(var(--muted));
  line-height: 1.45;
}

/*
 * Brak zdjecia ma wygladac na decyzje, nie na awarie. Wczesniej byl to
 * brudny szaro-brazowy gradient ze szrafura 135 stopni — na stronie ofert
 * siedem takich kafelkow obok siebie czytalo sie jak blad druku.
 * Zostaje kosc sloniowa i odsunieta zlota ramka, ten sam motyw co przy
 * zdjeciu w hero.
 */
.ph {
  position: relative;
  display: flex;
  width: 100%;
  height: 100%;
  min-height: 100%;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: var(--s-2);
  background: hsl(var(--surface));
  box-shadow: inset 0 0 0 1px hsl(var(--line));
  color: hsl(var(--accent-ink));
}

.ph::before {
  content: '';
  position: absolute;
  inset: 12px;
  border: 1px solid hsl(var(--accent) / 0.38);
}

/*
 * Przyciemnienie od dolu istnieje po to, zeby tekst byl czytelny na zdjeciu.
 * Nad placeholderem nie ma zadnego tekstu — zostawal tylko brudny szary
 * gradient na kosci sloniowej.
 */
.about__media:has(.ph)::after,
.hero__media-in:has(.ph)::after {
  display: none;
}

/* Kadr ma juz swoja obwodke — druga tuz obok czyta sie jak podwojna ramka. */
.about__media .ph,
.hero__media-in .ph {
  box-shadow: none;
}

.ph__mark {
  position: relative;
  width: 30px;
  height: 30px;
  color: hsl(var(--accent-2));
}

.ph__label {
  position: relative;
  font-size: 0.64rem;
  font-weight: 700;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: hsl(var(--muted));
}

.stats {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 1px;
  background: hsl(var(--line));
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--sh-1);
}

.stat {
  background: hsl(var(--surface));
  padding: var(--s-5) var(--s-4);
  display: flex;
  flex-direction: column;
  gap: 4px;
}

.stat b {
  font-family: var(--serif);
  font-size: clamp(2.1rem, 3.6vw, 3rem);
  font-weight: 780;
  line-height: 1;
  letter-spacing: -0.05em;
  color: hsl(var(--ink));
  font-variant-numeric: tabular-nums;
}

.stat span {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: hsl(var(--muted));
  line-height: 1.45;
}

.tone-navy .stats {
  background: hsl(0 0% 100% / 0.16);
  box-shadow: none;
}

.tone-navy .stat {
  background: hsl(var(--brand));
  padding-inline: clamp(4px, 1.6vw, 26px);
}

.tone-navy .stat:first-child {
  padding-inline-start: 0;
}

/*
 * Liczby zostaja w papierze, nie w zlocie. Cztery duze zlote liczby to byl
 * najglosniejszy element strony i to one ciagnely caly uklad w strone szablonu.
 */
.tone-navy .stat b {
  color: hsl(var(--surface));
}

.tone-navy .stat span {
  color: hsl(var(--on-dark-2));
}

.usp {
  background: hsl(var(--surface-2));
  border-block: 1px solid hsl(var(--line));
}

/*
 * Trzy kompetencje. Wczesniej aktywny wiersz dostawal pasek z lewej,
 * a jego numer puchnal 1,75 raza — skok wielkosci wygladal jak usterka
 * i rozpychal odstep miedzy numerem a tytulem. Teraz numery maja jeden
 * rozmiar, a to, gdzie jestes, pokazuje szyna po lewej: wypelnia sie
 * w miare schodzenia po liscie. Ruch niesie informacje, zamiast machac.
 */
.comp {
  position: relative;
  padding-inline-start: 22px;
  border-block-start: 1px solid hsl(var(--line));
}

/*
 * Trzy kompetencje na duzym ekranie. Wczesniej naglowek stal nad lista,
 * a lista zajmowala lewa polowe szerokosci — prawa polowa sekcji byla pusta
 * przez cala jej wysokosc. Pusto po prawej i tekst po lewej to uklad kartki
 * z edytora tekstu. Teraz naglowek trzyma sie lewej kolumny i zostaje w polu
 * widzenia, a lista dostaje reszte szerokosci.
 */
@media (min-width: 1024px) {
  .wrap:has(> .comp) {
    display: grid;
    grid-template-columns: minmax(0, 0.78fr) minmax(0, 1.22fr);
    gap: clamp(36px, 4vw, 72px);
    align-items: start;
  }

  .wrap:has(> .comp) > .sec__head {
    position: sticky;
    top: calc(var(--head-h) + 28px);
    margin-bottom: 0;
  }

  .wrap:has(> .comp) > .comp {
    border-block-start: 0;
  }
}

/* Tor szyny. */
.comp::before {
  content: '';
  position: absolute;
  inset-block: 0;
  left: 0;
  width: 2px;
  background: hsl(var(--line));
}

/* Wypelnienie szyny — siega konca wiersza, na ktorym stoi wzrok. */
.comp::after {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  width: 2px;
  height: 100%;
  background: linear-gradient(hsl(var(--accent)), hsl(var(--accent-2)));
  transform-origin: top center;
  transform: scaleY(var(--comp-progress, 0));
  transition: transform 0.55s var(--ease);
}

.comp__item {
  position: relative;
  display: grid;
  grid-template-columns: auto 1fr;
  align-items: baseline;
  gap: 8px 26px;
  padding-block: var(--s-5);
  border-block-end: 1px solid hsl(var(--line));
  transition: padding-inline-start 0.42s var(--ease);
}

/*
 * Poswiata wchodzi od szyny, nie znikad — dlatego siega pod nia.
 * Byla robiona akcentem, czyli na jasnym tle czernia rozcienczona do 13%.
 * Czern rozcienczona to szarosc, a szare tlo pod wierszem czyta sie jak
 * brud na ekranie, nie jak podswietlenie. Zloto w tym samym rozcienczeniu
 * jest cieplem, a nie zabrudzeniem — i jest tym samym kolorem, ktorym
 * pracuja kreski przy uprawnieniach ponizej.
 */
.comp__item::before {
  content: '';
  position: absolute;
  inset-block: 0;
  inset-inline: -22px 0;
  background: linear-gradient(90deg, hsl(var(--gold) / 0.16), hsl(var(--gold) / 0.05) 42%, transparent 72%);
  opacity: 0;
  transition: opacity 0.42s var(--ease);
}

.comp__item.is-active {
  padding-inline-start: 16px;
}

.comp__item.is-active::before {
  opacity: 1;
}

.comp__n,
.comp__body,
.comp__meta {
  position: relative;
}

.comp__n {
  font-family: var(--serif);
  font-size: clamp(2rem, 3.2vw, 2.9rem);
  font-weight: 750;
  letter-spacing: -0.05em;
  /* 0.16 dawalo 1,4:1 — numeru praktycznie nie bylo widac. 0.48 to prog 3:1. */
  color: hsl(var(--ink) / 0.48);
  line-height: 1;
  transition: color 0.42s var(--ease), transform 0.42s var(--ease);
}

.comp__item.is-active .comp__n {
  color: hsl(var(--accent-2));
  transform: translateY(-3px);
}

.comp__body h3 {
  position: relative;
  display: inline-block;
  font-size: 1.28rem;
  margin-block-end: 8px;
}

/*
 * Podkreslenie wjezdza spod tytulu, a nie pojawia sie gotowe. Kolor jest
 * ten sam, co kreska pod naglowkiem w hero: zloto podkresla, czern buduje.
 * Czarna kreska pod czarnym naglowkiem byla tylko pogrubieniem tego samego.
 */
.comp__body h3::after {
  content: '';
  position: absolute;
  inset-inline: 0;
  bottom: -3px;
  height: 2px;
  background: hsl(var(--gold));
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.45s var(--ease);
}

.comp__item.is-active .comp__body h3::after {
  transform: scaleX(1);
}

.comp__body p {
  color: hsl(var(--ink-2));
  font-size: 0.96rem;
  max-width: 56ch;
}

/*
 * Kursor podswietla wiersz, nad ktorym stoi. Tylko kursor: na dotyku :hover
 * zostaje przyklejony do ostatnio dotknietego wiersza, wiec obok wiersza,
 * na ktorym stoi wzrok (.is-active), swiecil sie drugi — a szyna po lewej
 * wskazywala jeszcze inny. Palec nie "najezdza" i nie ma tu czego obslugiwac.
 */
@media (hover: hover) {
  .comp__item:hover {
    padding-inline-start: 16px;
  }

  .comp__item:hover::before {
    opacity: 1;
  }

  .comp__item:hover .comp__n {
    color: hsl(var(--accent-2));
    transform: translateY(-3px);
  }

  .comp__item:hover .comp__body h3::after {
    transform: scaleX(1);
  }
}

/*
 * Uprawnienia i staz. Wczesniej wisialy w prawym gornym rogu wiersza, wyrownane
 * do niczego i zlozone wersalikami — czytaly sie jak ozdoba, a nie jak
 * konkret, ktorym sa. Teraz stoja pod akapitem, ktory opisuja, zwyklym pismem;
 * zlota kreska wystarcza, zeby oddzielic je od tresci.
 */
.comp__meta {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-block-start: var(--s-2);
  font-style: normal;
  font-size: 0.82rem;
  font-weight: 600;
  letter-spacing: 0;
  text-transform: none;
  color: hsl(var(--muted));
  transition: color 0.42s var(--ease);
}

.comp__meta::before {
  content: '';
  width: 18px;
  height: 1px;
  flex: none;
  background: hsl(var(--gold));
}

.comp__item:hover .comp__meta,
.comp__item.is-active .comp__meta {
  color: hsl(var(--ink-2));
}

.grid-3 {
  display: grid;
  gap: var(--s-4);
  grid-template-columns: minmax(0, 1fr);
}

.card {
  position: relative;
}

.card__link {
  display: flex;
  flex-direction: column;
  height: 100%;
  background: hsl(var(--surface));
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--sh-1);
  transition: transform 0.26s var(--ease), box-shadow 0.26s var(--ease);
}

.card__link:hover {
  transform: translateY(-5px);
  box-shadow: 0 0 0 1px hsl(var(--accent-2) / 0.6), 0 26px 50px -34px hsl(var(--ink) / 0.7);
}

.card__media {
  position: relative;
  display: block;
  aspect-ratio: 3 / 2;
  overflow: hidden;
  background: hsl(var(--surface-3));
}

.card__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.5s var(--ease);
}

.card__link:hover .card__media img {
  transform: scale(1.045);
}

.card__media::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, hsl(var(--ink) / 0.4), transparent 48%);
  pointer-events: none;
}

.card__tags {
  position: absolute;
  z-index: 2;
  left: 14px;
  top: 14px;
  display: flex;
  gap: 6px;
}

.card__tag {
  padding: 5px 11px;
  border-radius: var(--r-pill);
  background: hsl(var(--surface) / 0.94);
  backdrop-filter: blur(6px);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: hsl(var(--ink));
}

.card__tag--rent {
  background: hsl(var(--accent));
  color: hsl(var(--surface));
}

.card__badge {
  position: absolute;
  z-index: 2;
  right: 14px;
  top: 14px;
  padding: 5px 11px;
  border-radius: var(--r-pill);
  font-size: 0.68rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  background: hsl(var(--surface));
  color: hsl(var(--accent-ink));
  box-shadow: inset 0 0 0 1.5px hsl(var(--accent-2) / 0.7);
}

.card__badge--sprzedana {
  background: hsl(var(--ink) / 0.92);
  color: #fff;
  box-shadow: none;
}

.card__body {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding: var(--s-4);
  flex: 1;
}

.card__loc {
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: hsl(var(--muted));
}

.card__title {
  font-size: 1.24rem;
  line-height: 1.22;
  /* Dwie linie miejsca zawsze — w rzędzie kafelków ceny stoją wtedy
     na jednej wysokości, niezależnie od długości tytułów. */
  min-height: 2.44em;
}

.card__price {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 4px 10px;
  margin-block-start: 2px;
}

.card__price b {
  font-family: var(--serif);
  font-size: 1.5rem;
  font-weight: 780;
  letter-spacing: -0.04em;
  color: hsl(var(--ink));
  font-variant-numeric: tabular-nums;
}

.card__price i {
  font-style: normal;
  font-size: 0.8rem;
  font-weight: 600;
  color: hsl(var(--muted));
  font-variant-numeric: tabular-nums;
}

.card__facts {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin-block-start: 4px;
}

.card__facts span {
  padding: 4px 10px;
  border-radius: var(--r-sm);
  background: hsl(var(--surface-2));
  font-size: 0.79rem;
  font-weight: 600;
  color: hsl(var(--ink-2));
  font-variant-numeric: tabular-nums;
}

.card__more {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  margin-block-start: auto;
  padding-block-start: 16px;
  font-size: 0.8rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: hsl(var(--accent-ink));
}

.card__more svg {
  width: 17px;
  height: 17px;
  transition: transform 0.34s var(--ease);
}

.card__link:hover .card__more svg {
  transform: translateX(4px);
}

.sec__more {
  display: flex;
  justify-content: center;
  margin-block-start: var(--s-7);
}

/*
 * Sześć ofert widać od razu, reszta czeka pod przyciskiem. Kafelki spoza
 * szóstki są w źródle strony zawsze — chowa je dopiero klasa, którą dokłada
 * skrypt. Bez skryptu widać po prostu wszystkie i nie ma martwego przycisku.
 */
/*
 * Ile ofert widac przed rozwinieciem.
 *
 * Ponizej 900 px siatka ma jedna kolumne, wiec kazda kolejna oferta to kolejny
 * pelny ekran przewijania. Trzy pokazuja, ze oferty sa i jak wygladaja; po
 * wiecej idzie sie przyciskiem albo do katalogu z filtrami. Od 900 px kafelki
 * stoja po trzy w rzedzie i szesc miesci sie w dwoch rzedach, wiec nic to
 * nie kosztuje.
 */
@media (max-width: 899px) {
  .grid-3.is-collapsed .card--extra-sm {
    display: none;
  }
}

@media (min-width: 900px) {
  .grid-3.is-collapsed .card--extra {
    display: none;
  }
}

.offers-toggle {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 100%;
  padding: var(--s-5);
  border: 0;
  background: hsl(var(--surface-2));
  color: hsl(var(--ink));
  font: inherit;
  text-align: start;
  box-shadow: var(--sh-1);
  cursor: pointer;
  transition: transform 0.26s var(--ease), box-shadow 0.26s var(--ease), background 0.2s linear, color 0.2s linear;
}

.offers-toggle[hidden] {
  display: none;
}

.offers-toggle b {
  font-family: var(--serif);
  font-size: clamp(2.4rem, 4vw, 3.2rem);
  font-weight: 600;
  letter-spacing: -0.04em;
  line-height: 1;
  color: hsl(var(--accent-2));
  transition: color 0.2s linear;
}

.offers-toggle span {
  font-size: 0.94rem;
  font-weight: 650;
  letter-spacing: -0.01em;
}

.offers-toggle svg {
  width: 20px;
  height: 20px;
  margin-block-start: 2px;
  color: hsl(var(--muted));
  transition: transform 0.26s var(--ease), color 0.2s linear;
}

.offers-toggle:hover {
  background: hsl(var(--ink));
  color: #fff;
  transform: translateY(-2px);
  box-shadow: 0 4px 8px hsl(var(--brand) / 0.16), 0 22px 40px -14px hsl(var(--brand) / 0.5);
}

.offers-toggle:hover b,
.offers-toggle:hover svg {
  color: hsl(var(--accent));
}

.offers-toggle:hover svg {
  transform: translateY(3px);
}

.offers-toggle:active {
  transform: scale(0.99);
}

@media (min-width: 640px) {
  .offers-toggle {
    grid-column: span 2;
  }
}

.svc-list {
  display: grid;
  gap: 0 var(--s-7);
  grid-template-columns: minmax(0, 1fr);
}

.svc {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding-block: clamp(20px, 2.2vw, 28px) clamp(22px, 2.6vw, 32px);
  border-block-start: 1px solid hsl(var(--line-2));
}

.svc::before {
  content: '';
  position: absolute;
  inset-block-start: -1px;
  inset-inline: 0;
  height: 1px;
  background: hsl(var(--accent-2));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform 0.45s var(--ease);
}

.svc:hover::before {
  transform: scaleX(1);
}

/* Wycena i hipoteka to trzon oferty — wyroznia je zlota kreska u gory
   i zlote punktory, nie inne tlo. To jedyne miejsce na liscie uslug,
   w ktorym zloto w ogole wystepuje. */
.svc--flag {
  border-block-start-color: hsl(var(--gold));
  border-block-start-width: 2px;
}

.svc--flag .svc__list li::before {
  background: hsl(var(--gold));
}

.svc__title {
  font-size: 1.08rem;
}

.svc__text {
  font-size: 0.86rem;
  color: hsl(var(--ink-2));
}

.svc__list {
  display: grid;
  gap: 7px;
  margin-block-start: 6px;
}

.svc__list li {
  position: relative;
  padding-inline-start: 22px;
  font-size: 0.8rem;
  font-weight: 550;
  color: hsl(var(--ink-2));
  line-height: 1.55;
}

.svc__list li::before {
  content: '';
  position: absolute;
  left: 4px;
  top: 0.6em;
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: hsl(var(--accent) / 0.5);
}

.steps {
  display: grid;
  gap: var(--s-3);
}

.step {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 10px;
  min-height: 220px;
  padding: var(--s-5);
  background: hsl(0 0% 100% / 0.06);
  box-shadow: inset 0 0 0 1px hsl(0 0% 100% / 0.13);
  overflow: hidden;
  transition: transform 0.42s var(--ease), background-color 0.42s var(--ease);
}

.step::after {
  content: '';
  position: absolute;
  inset: auto 0 0 0;
  width: 100%;
  height: 3px;
  border-radius: 0;
  background: hsl(var(--accent));
  transform: scaleX(0.18);
  transform-origin: left;
  box-shadow: none;
  transition: transform 0.42s var(--ease);
}

.step:hover {
  transform: translateY(-5px);
  background: hsl(0 0% 100% / 0.1);
}

.step:hover::after {
  transform: scaleX(1);
}

.step__num {
  font-family: var(--serif);
  font-size: 2.05rem;
  font-weight: 780;
  line-height: 1;
  letter-spacing: -0.05em;
  color: hsl(var(--accent));
  font-variant-numeric: tabular-nums;
}

.step__title {
  font-size: 1.14rem;
}

.step__text {
  font-size: 0.92rem;
  color: hsl(var(--ink-2));
}

.band .step__text {
  color: hsl(var(--on-dark-2));
}

.band + .band {
  padding-block-start: 0;
}

.band {
  background: hsl(var(--brand));
  color: #fff;
  position: relative;
  overflow: hidden;
}

.band::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: repeating-linear-gradient(90deg, hsl(0 0% 100% / 0.05) 0, hsl(0 0% 100% / 0.05) 1px, transparent 1px, transparent 25%);
  opacity: 0.5;
}

.band .wrap {
  position: relative;
  z-index: 2;
}

.band .eyebrow,
.tone-navy .eyebrow,
.cta .eyebrow {
  color: hsl(var(--accent));
}

.band .eyebrow::before,
.tone-navy .eyebrow::before,
.cta .eyebrow::before {
  background: hsl(var(--accent));
}

.band .lead,
.tone-navy .lead {
  color: hsl(var(--on-dark-2));
}

.tone-navy {
  background: hsl(var(--brand));
  color: #fff;
}

.tone-white {
  background: hsl(var(--surface));
  border-block: 1px solid hsl(var(--line));
}

.sec__head--row {
  max-width: none;
}

.sec__head--row > div {
  display: flex;
  flex-direction: column;
  gap: 14px;
}

.sec__head--row .btn {
  align-self: flex-start;
}

.offers-more {
  display: grid;
  grid-template-columns: auto 1fr auto;
  align-items: center;
  gap: var(--s-4);
  width: 100%;
  padding: var(--s-5);
  background: hsl(var(--ink));
  color: #fff;
  transition: transform 0.32s var(--ease);
}

.offers-more img {
  width: clamp(92px, 13vw, 172px);
  height: auto;
  opacity: 0.92;
}

.offers-more span {
  display: grid;
  gap: 3px;
}

.offers-more b {
  font-size: clamp(1rem, 1.5vw, 1.16rem);
  font-weight: 700;
  letter-spacing: -0.02em;
}

.offers-more i {
  font-style: normal;
  font-size: 0.82rem;
  color: hsl(var(--on-dark-3));
}

.offers-more svg {
  width: 22px;
  height: 22px;
  flex: none;
  color: hsl(var(--accent));
  transition: transform 0.32s var(--ease);
}

.offers-more:hover {
  transform: translateY(-2px);
  box-shadow: inset 0 -3px 0 hsl(var(--accent));
}

.offers-more:hover svg {
  transform: translateX(5px);
}

/*
 * Dwa pasy logotypow mijaja sie w przeciwnych kierunkach. Jeden pas czytal sie
 * jak lista, ktora sama sobie ucieka; dwa dzialaja jak ruch w tle i pozwalaja
 * dac znakom wiecej miejsca, bo pas jest o polowe krotszy niz sekcja.
 */
.banks {
  display: grid;
  gap: clamp(10px, 1.2vw, 14px);
  margin-block-start: var(--s-7);
  overflow: hidden;
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}

.banks__track {
  display: flex;
  width: max-content;
  animation: slide 52s linear infinite;
}

/*
 * Ten sam przebieg puszczony wstecz: pas startuje z -50% i wraca do zera,
 * czyli jedzie w prawo. Wolniej niz gorny, zeby oba nie wygladaly na
 * dwie polowy jednego mechanizmu.
 */
.banks__track--rev {
  animation-duration: 64s;
  animation-direction: reverse;
}

.banks__row {
  display: flex;
  align-items: stretch;
  gap: clamp(10px, 1.2vw, 14px);
  padding-inline-end: clamp(10px, 1.2vw, 14px);
}

.banks__item {
  display: grid;
  place-items: center;
  flex: none;
  width: clamp(150px, 14vw, 192px);
  height: 76px;
  padding-inline: clamp(14px, 1.6vw, 20px);
  background: hsl(var(--surface));
  box-shadow: inset 0 0 0 1px hsl(var(--ink) / 0.07);
  transition: box-shadow 0.32s var(--ease);
}

.banks__item img {
  max-width: 100%;
  max-height: 46px;
  width: auto;
  height: auto;
  object-fit: contain;
  filter: grayscale(1);
  opacity: 0.66;
  transition: opacity 0.32s var(--ease), filter 0.32s var(--ease);
}

/*
 * Na dotyku nie ma "zejscia kursorem": stan hover zostawal przyklejony do
 * ostatnio dotknietego kafelka i wygladal jak zaznaczenie, ktorego nie da sie
 * cofnac. Reszta hoverow na stronie stoi w tym samym guardzie.
 */
@media (hover: hover) {
  .banks__item:hover {
    box-shadow: inset 0 0 0 1px hsl(var(--accent-2) / 0.5);
  }

  .banks__item:hover img {
    filter: grayscale(0);
    opacity: 1;
  }
}

.banks-sec {
  background: hsl(var(--surface));
  border-block: 1px solid hsl(var(--line));
}

.banks-sec .banks__item {
  background: hsl(var(--bg));
}

.banks-sec .banks {
  mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 6%, #000 94%, transparent);
}

@keyframes slide {
  to {
    transform: translateX(-50%);
  }
}

/*
 * Pas staje pod kursorem, zeby dalo sie odczytac logotyp. Tylko pod kursorem:
 * na dotyku przegladarka zostawia :hover przyklejony do ostatnio dotknietego
 * miejsca, wiec zwykle przewiniecie palcem przez pas zatrzymywalo go na dobre
 * — az do tapniecia gdzie indziej. Jedyny ruch na stronie wygladal wtedy
 * na zepsuty.
 */
@media (hover: hover) {
  .banks:hover .banks__track {
    animation-play-state: paused;
  }
}

.about__grid {
  display: grid;
  gap: var(--s-7);
  align-items: center;
}

.about__media {
  position: relative;
  border-radius: var(--r-xl);
  overflow: hidden;
  box-shadow: var(--sh-3);
  aspect-ratio: 4 / 5;
}

.about__media img {
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.about__media::after {
  content: '';
  position: absolute;
  inset: 0;
  background: linear-gradient(to top, hsl(var(--ink) / 0.42), transparent 48%);
}

.about__copy {
  display: flex;
  flex-direction: column;
  gap: 20px;
}

.about__text {
  display: grid;
  gap: 18px;
  color: hsl(var(--ink-2));
  font-size: 1rem;
  max-width: 62ch;
}

/*
 * Wariant dla /o-mnie: szesc akapitow obok jednego portretu w pionie
 * dawalo portret plywajacy w pustce na wysokosc calej kolumny. Szyna
 * ze zdjeciem i podpisem jedzie z tekstem, zamiast czekac na jego koniec.
 */
.about__rail {
  display: flex;
  flex-direction: column;
  gap: var(--s-5);
}

@media (min-width: 900px) {
  .about__grid--long {
    grid-template-columns: minmax(0, 0.72fr) minmax(0, 1.28fr);
    align-items: start;
  }

  .about__grid--long .about__rail {
    position: sticky;
    top: calc(var(--head-h) + var(--s-5));
  }

  .about__grid--long .about__media {
    aspect-ratio: 3 / 4;
  }
}

/* Portret w pionie ma sens, kiedy jest na nim czlowiek. Pusta ramka 4/5 to
   pol tysiaca pikseli niczego — do czasu wgrania zdjecia kadr jest nizszy. */
.about__media:has(.ph) {
  aspect-ratio: 4 / 3;
}

/* Rytm dlugiego tekstu: pierwszy akapit prowadzi, czwarty otwiera drugi
   ruch. Bez ingerencji w tresc — akapity przychodza z panelu. */
.about__grid--long .about__text {
  gap: var(--s-4);
}

.about__grid--long .about__text > p:first-child {
  font-size: clamp(1.08rem, 1.4vw, 1.2rem);
  line-height: 1.62;
  color: hsl(var(--ink));
}

.about__grid--long .about__text > p:nth-child(4) {
  padding-block-start: var(--s-5);
  border-block-start: 1px solid hsl(var(--line));
}

/*
 * Polityka prywatnosci: dziewiec naglowkow, kazdy z tym samym marginesem
 * wpisanym w atrybut style. Odstep jest cecha dokumentu, nie kazdego
 * naglowka z osobna.
 */
.legal {
  max-width: 72ch;
}

.legal > .h3 {
  margin-block-start: var(--s-6);
}

.legal > .h3:first-of-type {
  margin-block-start: 0;
}

.about__sign {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding-block-start: 22px;
  border-block-start: 1px solid hsl(var(--line));
}

.about__sign::before {
  content: '';
  position: absolute;
  left: 0;
  top: -2px;
  width: 56px;
  height: 3px;
  background: hsl(var(--accent));
}

.about__sign b {
  font-family: var(--serif);
  font-size: 1.3rem;
  font-weight: 750;
  letter-spacing: -0.035em;
}

.about__sign span {
  font-size: 0.84rem;
  color: hsl(var(--muted));
  font-weight: 600;
}

.lics {
  display: grid;
  gap: 1px;
  background: hsl(var(--line));
  border-radius: var(--r-lg);
  overflow: hidden;
  margin-block-start: 8px;
  box-shadow: var(--sh-1);
}

.lic {
  background: hsl(var(--surface));
  padding: 16px 20px;
  display: flex;
  flex-wrap: wrap;
  justify-content: space-between;
  gap: 4px 16px;
}

.lic__k {
  font-size: 0.83rem;
  font-weight: 650;
  color: hsl(var(--ink-2));
}

.lic__v {
  font-size: 0.83rem;
  font-weight: 700;
  color: hsl(var(--brand));
}

/*
 * Plyta z uprawnieniami przy sekcji o wycenach.
 *
 * `.lics` samo w sobie zostaje jasna tabelka — uzywa jej jeszcze strona 404
 * jako listy odnosnikow. Dowod uprawnien dostaje wlasny wariant: czern,
 * zlote wartosci, ten sam jezyk co plyta ze znakiem w pierwszym ekranie
 * i karta z rata w kalkulatorze. Kolumna obok ma 490 px tekstu, wiec plyta
 * staje na jej srodku: pustka rozklada sie nad i pod nia po rowno, zamiast
 * zbierac sie w jednym miejscu pod spodem.
 */
.lics--proof {
  gap: 0;
  padding: var(--s-5);
  background: hsl(var(--brand));
  box-shadow: none;
}

.lics__head {
  display: block;
  margin-block-end: var(--s-3);
  font-size: 0.72rem;
  font-weight: 750;
  letter-spacing: 0.16em;
  text-transform: uppercase;
  color: hsl(var(--gold));
}

.lics--proof .lic {
  background: none;
  padding: 14px 0;
  border-block-start: 1px solid hsl(0 0% 100% / 0.12);
}

/* Pierwszy wiersz styka sie z naglowkiem — kreska nad nim dzieli dwa razy. */
.lics--proof .lic:first-of-type {
  border-block-start: 0;
  padding-block-start: 0;
}

.lics--proof .lic__k {
  color: hsl(var(--on-dark-2));
}

.lics--proof .lic__v {
  color: hsl(var(--gold));
  font-variant-numeric: tabular-nums;
}

/* Od 900 px sekcja jest dwukolumnowa, wiec od 900 px plyta ma stac na srodku. */
@media (min-width: 900px) {
  .about__grid--rev .lics--proof {
    align-self: center;
  }
}

/*
 * Druga kolumna bywa pusta: plyta z uprawnieniami znika, gdy w panelu nie ma
 * ani numeru licencji, ani polisy.
 *
 * Wczesniej tresc szla wtedy na srodek w slupku na 62 znaki. Zamykalo to
 * dziure po sasiedzie, ale kosztem jedynego naglowka w tej sekcji: wysrodkowana
 * kolumna czyta sie jak wtracenie, a nie jak wypowiedz, i lamie rytm strony,
 * gdzie kazda inna sekcja zaczyna sie przy lewej krawedzi.
 *
 * Teraz sekcja zajmuje cala szerokosc. Naglowek idzie przez oba pasy i to on
 * jest tu zdarzeniem; pod nim lead i tekst stoja obok siebie, wiec szerokosc
 * jest wypelniona trescia, a nie rozciagnietym wierszem — dwie kolumny po
 * kilkadziesiat znakow czytaja sie, jeden wiersz na 1300 px nie.
 */
.about__grid:has(> .about__copy:only-child) {
  grid-template-columns: minmax(0, 1fr);
}

.about__grid:has(> .about__copy:only-child) .about__copy {
  display: grid;
  gap: var(--s-4) var(--s-7);
  align-items: start;
  grid-template-areas:
    'tytul'
    'lead'
    'tresc'
    'akcje';
}

.about__grid:has(> .about__copy:only-child) .about__copy > .h2 {
  grid-area: tytul;
  max-width: 24ch;
}

.about__grid:has(> .about__copy:only-child) .about__copy > .lead {
  grid-area: lead;
}

.about__grid:has(> .about__copy:only-child) .about__text {
  grid-area: tresc;
  max-width: none;
}

.about__grid:has(> .about__copy:only-child) .hero__actions {
  grid-area: akcje;
}

/*
 * Dwa pasy dopiero od 900 px. Nizej kolumny mialyby po trzydziesci znakow
 * i tekst rozpadlby sie na slupki po dwa slowa.
 */
@media (min-width: 900px) {
  .about__grid:has(> .about__copy:only-child) .about__copy {
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    grid-template-areas:
      'tytul tytul'
      'lead  tresc'
      'akcje tresc';
    align-content: start;
  }

  /* Naglowek na calej szerokosci ma miejsce na jeden wiersz, wiec limit
     znakow z ukladu jednokolumnowego tylko by go lamal w polowie. */
  .about__grid:has(> .about__copy:only-child) .about__copy > .h2 {
    max-width: none;
  }

  /* Lead jest krotszy od tekstu obok. Bez tego przyciski wisialy w pustce
     pod nim, zamiast konczyc lewy pas. */
  .about__grid:has(> .about__copy:only-child) .hero__actions {
    align-self: start;
  }
}

.calc {
  display: grid;
  gap: var(--s-6);
  align-items: start;
}

.calc__panel {
  background: hsl(var(--surface));
  border-radius: var(--r-xl);
  padding: var(--s-5);
  box-shadow: var(--sh-2);
  display: grid;
  gap: 22px;
}

.field {
  display: grid;
  gap: 9px;
}

.field__top {
  display: flex;
  justify-content: space-between;
  align-items: baseline;
  gap: 12px;
}

.field label {
  font-size: 0.86rem;
  font-weight: 650;
  color: hsl(var(--ink-2));
}

.field__val {
  font-family: var(--serif);
  font-size: 1.1rem;
  font-weight: 600;
  color: hsl(var(--brand));
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

/*
 * Tor suwaka byl jednolicie szary na calej dlugosci, wiec jedyna informacja
 * o polozeniu byl sam uchwyt. Przebyta czesc dostaje kolor akcentu (czern na
 * bialej karcie, zloto na ciemnym tle) — wartosc widac katem oka, bez
 * czytania liczby obok. Procent wchodzi z JS-a jako --p; bez skryptu tor
 * zostaje szary i suwak dziala tak samo.
 */
input[type='range'] {
  -webkit-appearance: none;
  appearance: none;
  width: 100%;
  height: 6px;
  border-radius: 999px;
  background:
    linear-gradient(hsl(var(--range-fill, var(--accent))), hsl(var(--range-fill, var(--accent)))) 0 50% /
      var(--p, 0%) 100% no-repeat,
    hsl(var(--surface-3));
  cursor: pointer;
}

/*
 * Biala karta suwakow stoi w czarnym pasie, wiec dziedziczy stamtad zloto
 * jako akcent — a jasne zloto na bieli to 2:1, czyli tor ledwo widoczny.
 * Wypelnienie schodzi wiec o stopien nizej, do --gold-2: nadal zloto, ale
 * 4,4:1 na bieli, czyli widoczne takze pod slonce na telefonie.
 */
.calc__panel {
  --range-fill: var(--gold-2);
}

input[type='range']::-webkit-slider-thumb {
  -webkit-appearance: none;
  width: 24px;
  height: 24px;
  border-radius: 50%;
  background: hsl(var(--brand));
  border: 4px solid hsl(var(--surface));
  box-shadow: 0 2px 8px hsl(var(--brand) / 0.42);
  transition: transform 0.2s var(--ease);
}

input[type='range']::-webkit-slider-thumb:hover {
  transform: scale(1.12);
}

input[type='range']::-moz-range-thumb {
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: hsl(var(--brand));
  border: 4px solid hsl(var(--surface));
  box-shadow: 0 2px 8px hsl(var(--brand) / 0.42);
}

/*
 * Panel z wynikiem.
 *
 * Mial tlo `--brand`, czyli DOKLADNIE to samo, co ciemny pas pod nim. Karta
 * byla wiec niewidzialna: po lewej stala biala karta z suwakami, a po prawej
 * luzny tekst zaczynajacy sie o wlasny margines nizej. Wygladalo to na blad
 * wyrownania, a bylo brakiem powierzchni. Teraz to rozjasnienie pasa plus
 * wlosowa obwodka — obie karty maja te sama krawedz i zaczynaja sie w tej
 * samej linii.
 */
.calc__out {
  display: grid;
  gap: 14px;
  padding: var(--s-5);
  border-radius: var(--r-xl);
  background: hsl(0 0% 100% / 0.055);
  color: #fff;
  box-shadow: inset 0 0 0 1px hsl(0 0% 100% / 0.11);
}

.calc__k {
  font-size: 0.76rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: hsl(var(--accent) / 0.9);
}

.calc__big {
  font-family: var(--serif);
  font-size: clamp(2.6rem, 5.5vw, 3.6rem);
  font-weight: 600;
  line-height: 1;
  letter-spacing: -0.04em;
  font-variant-numeric: tabular-nums;
}

.calc__rows {
  display: grid;
  gap: 1px;
  background: hsl(0 0% 100% / 0.14);
  border-radius: var(--r);
  overflow: hidden;
  margin-block-start: 6px;
}

.calc__row {
  display: flex;
  justify-content: space-between;
  gap: 14px;
  padding: 12px 16px;
  /* Karta jest teraz jasniejsza od pasa, wiec wiersze musza byc ciemniejsze
     od karty — inaczej tabela zlewa sie z tlem, na ktorym lezy. */
  background: hsl(0 0% 0% / 0.28);
  font-size: 0.88rem;
}

.calc__row span {
  color: hsl(var(--on-dark-2));
}

.calc__row b {
  font-weight: 700;
  font-variant-numeric: tabular-nums;
}

.calc__note {
  font-size: 0.78rem;
  color: hsl(var(--on-dark-3));
  line-height: 1.6;
}

/*
 * Opinie jada same w prawo, dopoki nikt ich nie tknie. Po pierwszym klikniecu,
 * swipie albo kolku przesuw gasnie na dobre i zostaja strzalki z zatrzaskiem —
 * tekstu, ktory sam ucieka, nikt nie doczyta do konca. Oba tryby przelacza
 * main.js; tu jest tylko to, co je od siebie odroznia.
 */
.quotes {
  border-block-start: 1px solid hsl(var(--line));
  padding-block-start: var(--s-5);
}

.quotes__track {
  --fade-s: 0;
  --fade-e: 0;
  /* Na telefonie stale 64 px zjadaloby jedna czwarta kafelka. */
  --fade-w: min(64px, 9vw);
  /*
   * Od lewej kafelki wyjezdzaja, wiec wygaszenie ma je tylko rozpuscic, a nie
   * przykrywac. Przy tych samych 64 px siegalo pierwszych znakow w kazdym
   * wierszu i pierwsza opinia — ta, ktora widac przed ruszeniem toru — czytala
   * sie jak wyblakla. 24 px miesci sie w marginesie kafelka (26 px), wiec
   * gasnie sama krawedz, a tekst zostaje czarny.
   */
  --fade-w-s: min(24px, 4vw);
  display: grid;
  grid-auto-flow: column;
  grid-auto-columns: min(82%, 320px);
  gap: var(--s-4);
  overflow-x: auto;
  overscroll-behavior-x: contain;
  scroll-snap-type: x mandatory;
  /* Cien kafelka jest rysowany poza obrysem — bez marginesu tor go obcina. */
  padding-block: 3px 6px;
  scrollbar-width: none;
  /*
   * Krawedz gasnie tam, gdzie lista sie nie konczy: kafelek uciety w polowie
   * czyta sie jak blad skladu, a wygaszony — jak zapowiedz dalszego ciagu.
   * Wartosci 0/1 ustawia skrypt, wiec strona bez niego nie ma czego blakac.
   */
  -webkit-mask-image: linear-gradient(
    90deg,
    #0000 0,
    #000 calc(var(--fade-s) * var(--fade-w-s)),
    #000 calc(100% - var(--fade-e) * var(--fade-w)),
    #0000 100%
  );
  mask-image: linear-gradient(
    90deg,
    #0000 0,
    #000 calc(var(--fade-s) * var(--fade-w-s)),
    #000 calc(100% - var(--fade-e) * var(--fade-w)),
    #0000 100%
  );
}

/*
 * W trybie samoczynnym zatrzask musi zniknac: tor jedzie ulamkami piksela,
 * a `mandatory` sciagaloby go po kazdej klatce na najblizszy kafelek.
 */
.quotes__box.is-auto .quotes__track {
  scroll-snap-type: none;
}

.quotes__track::-webkit-scrollbar {
  display: none;
}

.quotes__track > .quote {
  scroll-snap-align: start;
}

/* Na telefonie tor siega krawedzi ekranu: widac, ze cos jest dalej. */
@media (max-width: 699px) {
  .quotes__track {
    scroll-padding-inline: var(--pad);
    margin-inline: calc(var(--pad) * -1);
    padding-inline: var(--pad);
  }
}

@media (min-width: 700px) {
  .quotes__track {
    grid-auto-columns: calc((100% - var(--s-4)) / 2);
  }
}

@media (min-width: 1100px) {
  .quotes__track {
    grid-auto-columns: calc((100% - var(--s-4) * 2) / 3);
  }
}

/*
 * Pasek postepu zamiast kropek: przy kilkunastu opiniach kropki sa rzedem
 * niecelnych celow, a kreska od razu mowi, ile listy zostalo.
 */
.quotes__bar {
  display: flex;
  align-items: center;
  gap: var(--s-4);
  margin-block-start: var(--s-4);
}

.quotes__bar[hidden] {
  display: none;
}

.quotes__rail {
  position: relative;
  flex: 1;
  height: 3px;
  border-radius: 999px;
  background: hsl(var(--line-2));
  overflow: hidden;
}

.quotes__rail i {
  position: absolute;
  inset-block: 0;
  left: 0;
  width: 100%;
  border-radius: inherit;
  background: linear-gradient(90deg, hsl(var(--accent-2)), hsl(var(--accent)));
  transform-origin: left center;
  transform: scaleX(0);
  transition: transform 0.3s var(--ease-out);
}

/* Sam przesuw rysuje pasek co klatke — dolozone wygladzanie robi z niego opoznienie. */
.quotes__box.is-auto .quotes__rail i {
  transition: none;
}

.quotes__nav {
  display: flex;
  flex: none;
  gap: 8px;
}

.qnav {
  display: grid;
  place-items: center;
  width: 48px;
  height: 48px;
  padding: 0;
  border: 0;
  background: transparent;
  color: hsl(var(--ink));
  box-shadow: inset 0 0 0 1.5px hsl(var(--ink) / 0.2);
  cursor: pointer;
  transition: transform 0.16s var(--ease-out), box-shadow 0.24s var(--ease), background 0.18s linear, color 0.18s linear,
    opacity 0.18s linear;
}

.qnav svg {
  width: 18px;
  height: 18px;
}

.qnav[data-quotes-prev] svg {
  transform: scaleX(-1);
}

.qnav:hover:not(:disabled) {
  background: hsl(var(--ink));
  color: hsl(var(--surface));
  box-shadow: inset 0 0 0 1.5px hsl(var(--ink));
  transform: translateY(-2px);
}

.qnav:active:not(:disabled) {
  transform: scale(0.97);
}

.qnav:disabled {
  opacity: 0.32;
  cursor: default;
}

.quote {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: var(--s-5) var(--s-4) var(--s-4);
  background: hsl(var(--surface));
  box-shadow: var(--sh-1), inset 0 3px 0 hsl(var(--accent)), inset 0 0 0 1px hsl(var(--ink) / 0.07);
  transition: transform 0.2s var(--ease-out), box-shadow 0.24s var(--ease);
}

/*
 * Tor staje pod kursorem, wiec kafelek pod nim ma to potwierdzic:
 * lekkie uniesienie i glebszy cien. Bez tego pauza wyglada jak zacinka.
 */
@media (hover: hover) {
  .quote:hover {
    transform: translateY(-2px);
    box-shadow: var(--sh-2), 0 14px 30px -18px hsl(var(--ink) / 0.45), inset 0 3px 0 hsl(var(--accent)),
      inset 0 0 0 1px hsl(var(--ink) / 0.12);
  }
}

@media (prefers-reduced-motion: reduce) {
  .quote {
    transition: none;
  }
}

.quote::before {
  content: '\201E';
  position: absolute;
  top: 0.16em;
  right: 0.26em;
  left: auto;
  font-family: var(--serif);
  font-size: 3.4rem;
  font-weight: 750;
  line-height: 1;
  color: hsl(var(--accent) / 0.28);
}

.quote__stars {
  display: flex;
  gap: 3px;
}

.quote__stars svg {
  width: 14px;
  height: 14px;
  fill: hsl(var(--gold));
}

.quote__text {
  font-family: var(--serif);
  font-size: 1.1rem;
  text-wrap: pretty;
  font-weight: 400;
  line-height: 1.55;
  letter-spacing: -0.015em;
  color: hsl(var(--ink));
}

.quote__by {
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin-block-start: auto;
  padding-block-start: 8px;
}

.quote__by b {
  font-size: 0.9rem;
  font-weight: 700;
}

.quote__by span {
  font-size: 0.8rem;
  color: hsl(var(--muted));
}

.cta {
  position: relative;
  overflow: hidden;
  background: hsl(var(--brand));
  color: #fff;
  border-radius: var(--r-xl);
  padding: var(--s-8);
  display: grid;
  gap: 22px;
  justify-items: start;
  box-shadow: var(--sh-3);
}

/*
 * Bylo tu 48-pikselowe kratkowanie przycinane ukosna maska. Na czerni
 * czytalo sie jak siatka pomocnicza zostawiona przez pomylke, a nie jak
 * teksture. Zostaje ta sama glebia, ale bez rysunku: zlota poswiata
 * wychodzaca zza przyciskow.
 */
.cta::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image:
    radial-gradient(680px 480px at 88% 118%, hsl(var(--gold) / 0.2), transparent 64%),
    radial-gradient(520px 420px at 0% -20%, hsl(0 0% 100% / 0.06), transparent 62%);
}

.cta > * {
  position: relative;
  z-index: 2;
}

.cta h2 {
  max-width: 20ch;
}

.cta p {
  color: hsl(var(--on-dark-2));
  max-width: 54ch;
}

.cta__actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-block-start: 4px;
}

.cta .btn--primary {
  --btn-bg: hsl(var(--accent));
  --btn-fg: hsl(var(--ink));
  box-shadow: 0 16px 34px -14px hsl(var(--accent) / 0.5);
}

.cta .btn--primary::after {
  background: hsl(var(--ink) / 0.1);
}

.cta .btn--line {
  --btn-fg: #fff;
  box-shadow: inset 0 0 0 1.5px hsl(0 0% 100% / 0.32);
}

.cta .btn--line:hover {
  box-shadow: inset 0 0 0 1.5px hsl(var(--accent) / 0.9);
}

.cta .btn--line::after {
  background: hsl(0 0% 100% / 0.12);
}

.contact__grid {
  display: grid;
  gap: var(--s-7);
  align-items: start;
}

.cinfos {
  display: grid;
  gap: 1px;
  background: hsl(var(--line));
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--sh-1);
}

.cinfo {
  display: flex;
  flex-direction: column;
  gap: 3px;
  padding: 18px 22px;
  background: hsl(var(--surface));
  transition: background-color 0.24s var(--ease);
}

.cinfo:not(.cinfo--plain):hover {
  background: hsl(var(--accent-soft));
}

/*
 * Telefon i e-mail sa odnosnikami, adres i godziny nie — a w spoczynku
 * wygladaly identycznie. Strzalka i zloty kolor wartosci mowia, ktory
 * wiersz cos robi po dotknieciu.
 */
.cinfo:not(.cinfo--plain) {
  position: relative;
  padding-inline-end: 46px;
}

.cinfo:not(.cinfo--plain) .cinfo__v {
  color: hsl(var(--accent-ink));
}

.cinfo:not(.cinfo--plain)::after {
  content: '';
  position: absolute;
  right: 22px;
  top: 50%;
  width: 8px;
  height: 8px;
  border-top: 1.5px solid hsl(var(--accent-2));
  border-right: 1.5px solid hsl(var(--accent-2));
  transform: translateY(-50%) rotate(45deg);
  transition: transform 0.18s var(--ease-out);
}

@media (hover: hover) and (pointer: fine) {
  .cinfo:not(.cinfo--plain):hover::after {
    transform: translate(3px, -50%) rotate(45deg);
  }
}

.cinfo__k {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: hsl(var(--muted));
}

.cinfo__v {
  font-size: 1rem;
  font-weight: 650;
  color: hsl(var(--ink));
}

.form {
  display: grid;
  gap: 16px;
  background: hsl(var(--surface));
  border-radius: var(--r-xl);
  padding: var(--s-5);
  box-shadow: 0 18px 56px -34px hsl(var(--brand) / 0.45), var(--sh-1);
}

.form__row {
  display: grid;
  gap: 18px;
}

.inp {
  display: grid;
  gap: 7px;
}

.inp label {
  font-size: 0.82rem;
  font-weight: 650;
  color: hsl(var(--ink-2));
}

.inp label span {
  color: hsl(var(--accent-2));
}

.inp input,
.inp select,
.inp textarea {
  width: 100%;
  min-height: 50px;
  padding: 13px 16px;
  border-radius: var(--r);
  border: 1.5px solid hsl(var(--line-2));
  background: hsl(var(--surface));
  font-size: 0.95rem;
  transition: border-color 0.24s var(--ease), box-shadow 0.24s var(--ease);
}

.inp textarea {
  min-height: 132px;
  resize: vertical;
  line-height: 1.6;
}

.inp select {
  appearance: none;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23786f68' stroke-width='2'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 18px;
  padding-inline-end: 42px;
  cursor: pointer;
}

.inp input:hover,
.inp select:hover,
.inp textarea:hover {
  border-color: hsl(var(--ink) / 0.35);
}

.inp input:focus,
.inp select:focus,
.inp textarea:focus {
  outline: none;
  border-color: hsl(var(--accent-2));
  box-shadow: 0 0 0 4px hsl(var(--accent) / 0.28);
}

.check {
  display: flex;
  align-items: flex-start;
  gap: 11px;
  cursor: pointer;
}

.check input {
  appearance: none;
  flex: none;
  /* Zgoda RODO jest polem obowiazkowym, wiec musi byc tak samo latwa do
     trafienia jak przycisk wysylki: 24 px zamiast dotychczasowych 21. */
  width: 24px;
  height: 24px;
  border-radius: 6px;
  border: 1.5px solid hsl(var(--line-2));
  background: hsl(var(--surface));
  cursor: pointer;
  transition: background-color 0.2s var(--ease), border-color 0.2s var(--ease);
}

.check input:checked {
  background: hsl(var(--brand)) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23fff' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12 5 5 9-10'/%3E%3C/svg%3E") center / 14px no-repeat;
  border-color: hsl(var(--brand));
}

.check span {
  font-size: 0.79rem;
  line-height: 1.6;
  color: hsl(var(--muted));
}

.check a {
  color: hsl(var(--brand));
  text-decoration: underline;
  text-underline-offset: 2px;
}

.form__msg {
  font-size: 0.87rem;
  font-weight: 650;
  padding: 12px 16px;
  border-radius: var(--r);
  display: none;
}

.form__msg.is-ok {
  display: block;
  background: hsl(152 60% 96%);
  color: hsl(155 65% 24%);
}

.form__msg.is-err {
  display: block;
  background: hsl(2 80% 97%);
  color: hsl(2 68% 44%);
}

/*
 * Mapa przy 16/10 rosla do ~810 px i byla najwiekszym elementem strony
 * kontaktowej — wieksza niz formularz, do ktorego ma prowadzic. Na
 * telefonie 4/3 jest jeszcze uzyteczne, na desktopie wystarczy pas.
 */
.map {
  overflow: hidden;
  box-shadow: var(--sh-2);
  aspect-ratio: 4 / 3;
  background: hsl(var(--surface-3));
  margin-block-start: var(--s-7);
}

/* Stala wysokosc, nie proporcja: przy aspect-ratio max-height sciagalo
   razem z wysokoscia takze szerokosc i mapa odjezdzala od prawej krawedzi. */
@media (min-width: 900px) {
  .map {
    aspect-ratio: auto;
    height: 340px;
  }
}

.map iframe {
  width: 100%;
  height: 100%;
  border: 0;
  border-radius: var(--r-lg);
}

.foot {
  position: relative;
  background: hsl(var(--ink));
  color: hsl(var(--on-dark-2));
  padding-block: clamp(52px, 6vw, 82px) 30px;
  box-shadow: inset 0 3px 0 hsl(var(--accent));
}

.foot__in {
  display: grid;
  gap: var(--s-7);
}

.foot__logo {
  display: flex;
  align-items: center;
  gap: 12px;
}

.foot__logo img {
  height: 42px;
  width: auto;
}

.foot__logo .brandword b {
  color: #fff;
  font-size: 1.14rem;
}

.foot__logo .brandword i {
  color: hsl(var(--accent) / 0.8);
}

.foot__role {
  margin-block-start: 12px;
  font-size: 0.87rem;
  color: hsl(var(--on-dark-3));
  max-width: 30ch;
}

.foot__social {
  display: flex;
  gap: 14px;
  margin-block-start: 16px;
}

.foot__social a {
  font-size: 0.83rem;
  font-weight: 650;
  color: hsl(var(--on-dark-2));
  transition: color 0.22s var(--ease);
}

.foot__social a:hover {
  color: #fff;
}

.foot__nav {
  display: grid;
  gap: 30px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 170px), 1fr));
}

.foot__nav > div {
  display: grid;
  gap: 9px;
  align-content: start;
}

.foot__nav h3 {
  font-family: var(--sans);
  font-size: 0.73rem;
  font-weight: 700;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: hsl(var(--accent));
  margin-block-end: 4px;
}

.foot__nav a,
.foot__nav span {
  font-size: 0.87rem;
  color: hsl(var(--on-dark-2));
  line-height: 1.55;
}

.foot__nav a {
  /* 24 px to najmniejszy cel, jaki da sie pewnie trafic kciukiem (WCAG 2.5.8).
     Sam tekst przy 0.87rem daje 22 px i odnosniki w stopce lezaly tuz pod
     progiem — odstep miedzy nimi zostaje ten sam, rosnie tylko pole trafienia. */
  display: flex;
  align-items: center;
  min-height: 24px;
  transition: color 0.22s var(--ease), transform 0.28s var(--ease);
  width: fit-content;
}

.foot__nav a:hover {
  color: #fff;
  transform: translateX(3px);
}

.foot__legal {
  display: grid;
  gap: 8px;
  padding-block-start: 28px;
  border-block-start: 1px solid hsl(0 0% 100% / 0.12);
  font-size: 0.78rem;
  color: hsl(var(--on-dark-3));
}

/* 44% dawalo 3,8:1 na czerni stopki — ponizej progu AA dla tekstu. */
.foot__reg {
  color: hsl(var(--on-dark-3));
}

.foot__legal a {
  color: hsl(var(--on-dark-2));
  text-decoration: underline;
  text-underline-offset: 3px;
  transition: color 0.22s var(--ease);
}

.foot__legal a:hover {
  color: #fff;
}

/*
 * Naglowek podstrony. Na /nieruchomosci zjadal caly pierwszy ekran i pasek
 * filtrow zaczynal sie dopiero pod nim — czyli szukanie zaczynalo sie od
 * przewijania. Krotszy oddech u gory zostawia filtry w polu widzenia od razu.
 */
.page__head {
  padding-block: clamp(26px, 3.4vw, 46px) var(--s-5);
  background: linear-gradient(180deg, hsl(var(--surface-2)), hsl(var(--bg)));
  border-block-end: 1px solid hsl(var(--line));
}

.page__head .h1 {
  font-size: clamp(1.95rem, 4vw, 2.9rem);
}

/*
 * Ograniczenie szerokosci musi siedziec na dzieciach, nie na .wrap.
 * Wczesniej bylo na tym samym elemencie co margin-inline:auto z .wrap,
 * wiec caly naglowek podstrony byl po cichu wysrodkowany: H1 stalo
 * jedna trzecia od lewej, a przycisk powrotu i tresc pod spodem przy
 * prawdziwej krawedzi. Trzy rozne krawedzie na jednej stronie.
 */
.page__head-in {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-3);
}

.page__head-in .h1 {
  max-width: 20ch;
}

.page__head-in .lead {
  max-width: 58ch;
}

.filters {
  position: sticky;
  top: var(--head-h);
  z-index: 40;
  background: hsl(var(--bg) / 0.9);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
  border-block-end: 1px solid hsl(var(--line));
  padding-block: 16px;
  transition: box-shadow 0.3s var(--ease);
}

.float-contact {
  position: fixed;
  right: clamp(14px, 2vw, 28px);
  bottom: clamp(14px, 2vw, 28px);
  z-index: 95;
  display: grid;
  gap: 8px;
  justify-items: end;
}

.float-contact a {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding-inline: 18px;
  font-size: 0.85rem;
  font-weight: 750;
  box-shadow: 0 18px 42px -20px hsl(var(--ink) / 0.6), var(--sh-1);
  transition: transform 0.18s var(--ease-out);
}

.float-contact a:hover {
  transform: translateY(-2px);
}

.float-contact__main {
  background: hsl(var(--ink));
  color: #fff;
  box-shadow: 0 18px 42px -20px hsl(var(--ink) / 0.7), inset 0 -3px 0 hsl(var(--accent));
}

.float-contact__tel {
  background: hsl(var(--surface) / 0.94);
  backdrop-filter: blur(12px);
  color: hsl(var(--ink));
  font-variant-numeric: tabular-nums;
}

.filters__in {
  display: grid;
  gap: 12px;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 168px), 1fr));
  align-items: end;
}

/*
 * Na telefonie szesc pol w przypietym pasku zjadalo jedna trzecia ekranu
 * i nie dalo sie ich obsluzyc kciukiem. Ponizej 720 px pasek zwija sie do
 * jednego przycisku, a pola wjezdzaja od dolu jako arkusz.
 */
.filters__toggle,
.filters__done,
.filters__veil {
  display: none;
}

@media (max-width: 719px) {
  /* backdrop-filter na pasku robi z niego blok zawierajacy dla position:fixed
     — arkusz i przesłona kotwiczyly sie do paska zamiast do okna. Na telefonie
     pasek to i tak tylko przycisk, wiec rozmycie nie ma czego rozmywac. */
  .filters {
    background: hsl(var(--bg));
    backdrop-filter: none;
    -webkit-backdrop-filter: none;
  }

  .filters__toggle {
    display: inline-flex;
    align-items: center;
    gap: 10px;
    width: 100%;
    min-height: 48px;
    padding-inline: 16px;
    background: hsl(var(--surface));
    box-shadow: inset 0 0 0 1.5px hsl(var(--ink) / 0.2);
    font-size: 0.92rem;
    font-weight: 700;
    letter-spacing: -0.01em;
    color: hsl(var(--ink));
    transition: box-shadow 0.18s var(--ease-out);
  }

  .filters__toggle svg {
    width: 18px;
    height: 18px;
    flex: none;
    color: hsl(var(--accent-2));
  }

  .filters__toggle b {
    margin-inline-start: auto;
    min-width: 22px;
    padding: 2px 7px;
    background: hsl(var(--accent));
    color: hsl(var(--surface));
    font-size: 0.76rem;
    font-weight: 750;
    font-variant-numeric: tabular-nums;
  }

  .filters__veil {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 96;
    background: hsl(var(--ink) / 0.5);
    opacity: 0;
    visibility: hidden;
    transition: opacity 0.24s var(--ease-out), visibility 0.24s;
  }

  .filters__in {
    position: fixed;
    z-index: 97;
    inset: auto 0 0 0;
    grid-template-columns: minmax(0, 1fr);
    gap: 14px;
    max-height: 84svh;
    overflow-y: auto;
    overscroll-behavior: contain;
    padding: var(--s-5) var(--pad) calc(var(--s-5) + env(safe-area-inset-bottom));
    background: hsl(var(--surface));
    box-shadow: 0 -30px 60px -28px hsl(var(--ink) / 0.55);
    transform: translateY(100%);
    visibility: hidden;
    transition: transform 0.32s var(--ease), visibility 0.32s;
  }

  /* Uchwyt: jedyny znak, ze to arkusz, ktory da sie zamknac. */
  .filters__in::before {
    content: '';
    justify-self: center;
    width: 44px;
    height: 4px;
    margin-block-end: 4px;
    background: hsl(var(--line-2));
  }

  .filters.is-open .filters__in {
    transform: translateY(0);
    visibility: visible;
  }

  .filters.is-open .filters__veil {
    opacity: 1;
    visibility: visible;
  }

  .filters__done {
    display: inline-flex;
    margin-block-start: 4px;
  }

  .filters__meta {
    margin-block-start: 12px;
  }
}

.filters .inp input,
.filters .inp select {
  min-height: 46px;
  padding-block: 11px;
  font-size: 0.9rem;
}

.filters__meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 12px;
  margin-block-start: 14px;
  font-size: 0.85rem;
  font-weight: 600;
  color: hsl(var(--muted));
}

.filters__reset {
  font-size: 0.83rem;
  font-weight: 700;
  color: hsl(var(--brand));
  text-decoration: underline;
  text-underline-offset: 3px;
}

.filters__tools {
  display: flex;
  align-items: center;
  gap: 16px;
}

/*
 * Wejscie do asystenta w pasku filtrow. Wyglada jak drugi odnosnik obok
 * "Wyczysc filtry", a nie jak trzeci przycisk konkurujacy z "Pokaz oferty" —
 * to jest wyjscie awaryjne dla kogos, kto nie wie, co ustawic, a nie glowna
 * droga przez strone.
 */
.filters__ask {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  border: 0;
  padding: 0;
  background: none;
  font: inherit;
  font-size: 0.83rem;
  font-weight: 700;
  color: hsl(var(--brand));
  cursor: pointer;
  transition: color 0.18s linear;
}

.filters__ask svg {
  width: 15px;
  height: 15px;
  color: hsl(var(--gold-2));
  transition: transform 0.24s var(--ease);
}

.filters__ask:hover {
  color: hsl(var(--ink));
}

.filters__ask:hover svg {
  transform: translateY(-2px);
}

/* Wartownik nad przypietym paskiem. Nic nie zajmuje i nic nie pokazuje —
   sluzy tylko za punkt odniesienia dla IntersectionObserver. */
.filters__sentinel {
  display: block;
  height: 1px;
  margin-block-end: -1px;
}

/* Pasek stoi w ukladzie: bez cienia. Pasek przyklejony do naglowka: z cieniem,
   inaczej na dlugiej liscie nie widac, ze cos nad trescia w ogole jest. */
.filters.is-stuck {
  box-shadow: 0 18px 34px -30px hsl(var(--ink) / 0.85);
}

/* Blysk po tym, jak filtry przestawi asystent. Bez tego lista zmienia sie
   pod oknem czatu i nie widac, ze cokolwiek zrobil klikniety odnosnik. */
@media (prefers-reduced-motion: no-preference) {
  .filters.is-flash::after {
    content: '';
    position: absolute;
    inset: 0;
    pointer-events: none;
    background: hsl(var(--gold) / 0.16);
    animation: filters-flash 0.9s var(--ease) forwards;
  }

  [data-count].is-bump {
    display: inline-block;
    animation: count-bump 0.42s var(--ease);
  }
}

@keyframes filters-flash {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

@keyframes count-bump {
  0% {
    transform: translateY(0);
  }
  38% {
    transform: translateY(-4px);
  }
  100% {
    transform: translateY(0);
  }
}

/*
 * Doradca nad filtrami.
 *
 * Filtry odsiewaja po liczbach, a czlowiek, ktory pierwszy raz kupuje
 * mieszkanie, ma zwykle zdanie, nie liczby. Pas jest ciemny, bo ma sie
 * odciac od bieli katalogu i od samego paska filtrow — to jedyne miejsce
 * na tej stronie, ktore proponuje inna droge niz szesc pol wyboru.
 */
.doradca {
  position: relative;
  isolation: isolate;
  overflow: hidden;
  background: hsl(var(--brand));
  color: hsl(var(--on-dark));
  border-block-end: 1px solid hsl(var(--brand-2));
}

/*
 * Plaska czern czyta sie jak dziura miedzy naglowkiem a filtrami. Jedno
 * miekkie zloto w lewym gornym rogu daje pasowi glebie i zwiazuje go ze
 * znakiem marki. Rusza sie bardzo wolno i o kilka procent — ma byc widoczne
 * dopiero wtedy, gdy ktos na nie patrzy, nigdy katem oka.
 */
.doradca::before {
  content: '';
  position: absolute;
  z-index: -1;
  inset: -30% -10% auto -20%;
  height: 180%;
  background: radial-gradient(46% 60% at 18% 0%, hsl(var(--gold) / 0.16), transparent 70%);
  pointer-events: none;
}

@media (prefers-reduced-motion: no-preference) {
  .doradca::before {
    animation: doradca-drift 26s ease-in-out infinite alternate;
  }
}

@keyframes doradca-drift {
  from {
    transform: translate3d(0, 0, 0);
  }
  to {
    transform: translate3d(6%, 3%, 0);
  }
}

.doradca__in {
  width: 100%;
  max-width: var(--max);
  margin-inline: auto;
  padding-inline: var(--pad);
  padding-block: clamp(22px, 3vw, 32px);
  display: grid;
  gap: 14px;
}

.doradca__copy {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  max-width: 74ch;
}

.doradca__mark {
  flex: none;
  display: grid;
  place-items: center;
  width: 34px;
  height: 34px;
  border-radius: var(--r-sm);
  background: hsl(var(--gold) / 0.14);
  color: hsl(var(--gold));
}

.doradca__mark svg {
  width: 18px;
  height: 18px;
}

.doradca__copy p {
  font-size: 0.92rem;
  line-height: 1.65;
  color: hsl(var(--on-dark-2));
}

.doradca__copy b {
  color: hsl(var(--on-dark));
  font-weight: 700;
}

.doradca__form {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
}

.doradca__q {
  flex: 1 1 320px;
  min-height: 50px;
  padding: 12px 16px;
  border: 0;
  border-radius: var(--r-sm);
  background: hsl(0 0% 100% / 0.06);
  box-shadow: inset 0 0 0 1px hsl(0 0% 100% / 0.16);
  color: hsl(var(--on-dark));
  font: inherit;
  font-size: 0.92rem;
  transition: box-shadow 0.22s var(--ease), background 0.22s linear;
}

.doradca__q::placeholder {
  color: hsl(var(--on-dark-3));
}

.doradca__q:focus {
  outline: none;
  background: hsl(0 0% 100% / 0.1);
  box-shadow: inset 0 0 0 1.5px hsl(var(--gold) / 0.85);
}

.doradca__go {
  flex: none;
  min-height: 50px;
}

.doradca__chips {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
}

.doradca__chips button {
  border: 0;
  border-radius: var(--r-pill);
  padding: 8px 14px;
  background: hsl(0 0% 100% / 0.05);
  box-shadow: inset 0 0 0 1px hsl(0 0% 100% / 0.14);
  color: hsl(var(--on-dark-2));
  font: inherit;
  font-size: 0.78rem;
  font-weight: 600;
  cursor: pointer;
  transition: transform 0.18s var(--ease-out), box-shadow 0.18s var(--ease), color 0.18s linear;
}

.doradca__chips button:hover {
  transform: translateY(-2px);
  color: hsl(var(--on-dark));
  box-shadow: inset 0 0 0 1px hsl(var(--gold) / 0.65);
}

.doradca__note {
  font-size: 0.74rem;
  line-height: 1.55;
  color: hsl(var(--on-dark-3));
  max-width: 78ch;
}

.empty__ai {
  margin-block-start: 18px;
}

.empty {
  grid-column: 1 / -1;
  text-align: center;
  padding: clamp(48px, 7vw, 90px) 24px;
  background: hsl(var(--surface));
  border-radius: var(--r-lg);
  box-shadow: var(--sh-1);
  display: none;
}

.empty.is-on {
  display: block;
}

/* Komunikat pojawia sie w reakcji na filtr, wiec wchodzi jak odpowiedz, a nie
   jak przeladowana sekcja. Bez ruchu po prostu jest. */
@media (prefers-reduced-motion: no-preference) {
  .empty.is-on {
    animation: empty-in 0.34s var(--ease) both;
  }
}

@keyframes empty-in {
  from {
    opacity: 0;
    transform: translateY(10px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

.empty h3 {
  font-size: 1.4rem;
  margin-block-end: 8px;
}

.empty p {
  color: hsl(var(--muted));
  font-size: 0.94rem;
}

.crumb {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 8px;
  font-size: 0.8rem;
  color: hsl(var(--muted));
  padding-block: 20px 0;
}

.crumb a {
  /* Okruszki to nawigacja, nie zdanie z odnosnikiem, wiec obowiazuje je prog
     24 px z WCAG 2.5.8. Sam tekst przy 0.8rem daje 22 px — pole trafienia
     rosnie, odstepy w wierszu zostaja te same. */
  display: flex;
  align-items: center;
  min-height: 24px;
  font-weight: 600;
  transition: color 0.2s var(--ease);
}

.crumb a:hover {
  color: hsl(var(--brand));
}

.crumb b {
  font-weight: 650;
  color: hsl(var(--ink-2));
}

/*
 * Galeria oferty. Kształt zależy od liczby zdjęć (klasa z serwera):
 * .gal--full  — pięć i więcej: duży kadr + cztery mniejsze obok (≥ 900 px),
 * .gal--few   — dwa do czterech: jeden kadr i rząd miniatur,
 * .gal--one   — jedno zdjęcie.
 * Wysokość jest ograniczona: wcześniej kadr 3:2 na 1280 px szerokości miał
 * 853 px i nie mieścił się w oknie, a cena była pod nim.
 */
.gal {
  display: grid;
  gap: 10px;
  margin-block-start: 18px;
}

/*
 * Zdjecie wiodace w proporcji 3:2 przy szerokim ekranie mialo ponad 700 px
 * wysokosci i spychalo cene z pierwszego ekranu — trzeba bylo przewijac,
 * zeby dowiedziec sie, ile kosztuje. Ograniczenie wysokosci zostawia cene,
 * metraz i telefon w polu widzenia od razu; kadr sie nie deformuje, bo obcina
 * go object-fit, a pelne zdjecie jest o jedno klikniecie dalej w powiekszeniu.
 */
.gal__main {
  position: relative;
  display: block;
  width: 100%;
  border-radius: var(--r-lg);
  overflow: hidden;
  aspect-ratio: 3 / 2;
  background: hsl(var(--surface-3));
  box-shadow: var(--sh-2);
}

.gal__main img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.7s var(--ease);
}

.gal__main:hover img {
  transform: scale(1.03);
}

.gal__zoom {
  position: absolute;
  right: 14px;
  bottom: 14px;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 9px 14px;
  border-radius: var(--r-sm);
  background: hsl(var(--surface) / 0.94);
  backdrop-filter: blur(6px);
  font-size: 0.78rem;
  font-weight: 700;
  color: hsl(var(--ink));
  box-shadow: var(--sh-1);
  transition: background-color 0.2s var(--ease-out);
}

.gal__zoom svg {
  width: 16px;
  height: 16px;
}

.gal__main:hover .gal__zoom {
  background: hsl(var(--surface));
}

.gal__thumbs {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
}

.gal__thumb {
  position: relative;
  border-radius: var(--r);
  overflow: hidden;
  aspect-ratio: 4 / 3;
  background: hsl(var(--surface-3));
  box-shadow: var(--sh-1);
}

.gal__thumb img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.6s var(--ease);
}

.gal__thumb:hover img {
  transform: scale(1.07);
}

.gal__rest {
  position: absolute;
  inset: 0;
  display: grid;
  place-content: center;
  background: hsl(var(--ink) / 0.62);
  color: #fff;
  font-family: var(--serif);
  font-size: 1.3rem;
  font-weight: 600;
}

/*
 * Galeria pełnoekranowa. Zdjęcie jest pozycjonowane absolutnie i dopasowane
 * przez object-fit: contain — to jedyny sposób, żeby kadr o dowolnych
 * proporcjach był zawsze w środku i nigdy nie wystawał poza ekran. Wcześniej
 * `max-height: 100%` w siatce z automatycznym wierszem nie miał do czego
 * się odnieść i pionowe kadry wychodziły poza dół okna.
 */
.lightbox {
  --lb-x: clamp(64px, 7vw, 96px);
  position: fixed;
  inset: 0;
  z-index: 200;
  display: grid;
  grid-template-rows: auto minmax(0, 1fr) auto;
  /*
   * Kolumna musi byc przycieta do szerokosci okna. Bez tego domyslna kolumna
   * `auto` rosla do najwiekszej zawartosci wiersza — a tytul oferty w pasku
   * ma `white-space: nowrap`, wiec jego pelna dlugosc (a nie skrocona
   * wielokropkiem) wypychala cala galerie poza ekran: na telefonie krzyzyk
   * zamykania wychodzil za prawa krawedz, a zdjecie stalo poza srodkiem
   * i bylo przyciete z prawej.
   */
  grid-template-columns: minmax(0, 1fr);
  background: hsl(30 6% 5%);
  color: #fff;
  opacity: 0;
  visibility: hidden;
  /* visibility przełącza się natychmiast przy otwarciu (inaczej przycisk
     zamykania nie przyjmie fokusu), a przy zamknięciu dopiero po zaniku. */
  transition: opacity 0.26s var(--ease), visibility 0s linear 0.26s;
  padding-block-end: env(safe-area-inset-bottom);
}

.lightbox.is-open {
  opacity: 1;
  visibility: visible;
  transition: opacity 0.26s var(--ease), visibility 0s;
}

.lightbox__bar {
  display: flex;
  align-items: center;
  gap: 16px;
  min-height: 64px;
  padding: 10px var(--pad);
}

.lightbox__count {
  flex: none;
  font-size: 0.84rem;
  font-weight: 750;
  letter-spacing: 0.04em;
  color: hsl(var(--accent));
  font-variant-numeric: tabular-nums;
}

.lightbox__title {
  flex: 1;
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  font-size: 0.86rem;
  font-weight: 600;
  color: hsl(var(--on-dark-2));
}

.lightbox__close {
  display: grid;
  place-content: center;
  flex: none;
  width: 44px;
  height: 44px;
  border-radius: 50%;
  color: #fff;
  background: hsl(0 0% 100% / 0.08);
  box-shadow: inset 0 0 0 1px hsl(0 0% 100% / 0.14);
  transition: background-color 0.2s var(--ease-out);
}

.lightbox__close:hover {
  background: hsl(0 0% 100% / 0.18);
}

.lightbox__close svg {
  width: 20px;
  height: 20px;
}

.lightbox__body {
  position: relative;
  min-height: 0;
}

.lightbox__stage {
  position: absolute;
  inset: 0 var(--lb-x);
}

.lightbox__stage img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  display: none;
}

.lightbox__stage img.is-near {
  display: block;
  visibility: hidden;
}

.lightbox__stage img.is-on {
  display: block;
  visibility: visible;
  animation: lb-in 0.34s var(--ease);
}

@keyframes lb-in {
  from {
    opacity: 0;
    transform: scale(0.985);
  }
}

.lightbox__nav {
  position: absolute;
  top: 50%;
  translate: 0 -50%;
  display: grid;
  place-content: center;
  width: 52px;
  height: 52px;
  border-radius: 50%;
  background: hsl(0 0% 100% / 0.08);
  color: #fff;
  box-shadow: inset 0 0 0 1px hsl(0 0% 100% / 0.14);
  transition: background-color 0.2s var(--ease-out), scale 0.2s var(--ease-out);
}

.lightbox__nav:hover {
  background: hsl(0 0% 100% / 0.18);
  scale: 1.05;
}

.lightbox__nav svg {
  width: 22px;
  height: 22px;
}

/* Strzałka siedzi w środku rynny obok zdjęcia, nie na nim. */
.lightbox__nav--prev {
  left: max(10px, calc((var(--lb-x) - 52px) / 2));
}

.lightbox__nav--next {
  right: max(10px, calc((var(--lb-x) - 52px) / 2));
}

.lightbox__thumbs {
  display: flex;
  gap: 6px;
  padding: 14px var(--pad) 18px;
  overflow-x: auto;
  scrollbar-width: none;
}

.lightbox__thumbs::-webkit-scrollbar {
  display: none;
}

/* Wyśrodkowanie bez justify-content: przy przepełnieniu pierwsze miniatury
   byłyby obcięte i nie dało się do nich przewinąć. */
.lightbox__thumbs button:first-child {
  margin-inline-start: auto;
}

.lightbox__thumbs button:last-child {
  margin-inline-end: auto;
}

.lightbox__thumbs button {
  flex: none;
  width: 68px;
  height: 48px;
  padding: 0;
  overflow: hidden;
  opacity: 0.42;
  box-shadow: 0 0 0 2px transparent;
  transition: opacity 0.2s var(--ease-out), box-shadow 0.2s var(--ease-out);
}

.lightbox__thumbs button:hover {
  opacity: 0.8;
}

.lightbox__thumbs button.is-on {
  opacity: 1;
  box-shadow: 0 0 0 2px hsl(var(--accent));
}

.lightbox__thumbs img {
  display: block;
  width: 100%;
  height: 100%;
  object-fit: cover;
}

.lightbox :focus-visible {
  outline-color: hsl(var(--accent));
}

@media (max-width: 719px) {
  .lightbox {
    --lb-x: 10px;
  }

  .lightbox__bar {
    min-height: 56px;
  }

  .lightbox__thumbs {
    display: none;
  }

  .lightbox__nav {
    display: none;
  }

  .lightbox__body {
    padding-block-end: 16px;
  }
}

/*
 * Pasek z ceną i telefonem na dole ekranu telefonu. Na wąskim ekranie
 * kolumna z ceną ląduje pod formularzem, czyli sześć ekranów niżej;
 * bez tego paska ktoś czyta opis domu i nie wie, ile kosztuje.
 */
.d-bar {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 96;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px var(--pad) calc(10px + env(safe-area-inset-bottom));
  background: hsl(var(--surface) / 0.94);
  backdrop-filter: blur(14px);
  box-shadow: 0 -1px 0 hsl(var(--line)), 0 -18px 40px -24px hsl(var(--ink) / 0.35);
}

.d-bar__price {
  display: flex;
  flex-direction: column;
  min-width: 0;
}

.d-bar__price b {
  font-family: var(--serif);
  font-size: 1.45rem;
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1;
  color: hsl(var(--ink));
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.d-bar__price i {
  font-style: normal;
  font-size: 0.74rem;
  font-weight: 650;
  color: hsl(var(--muted));
  margin-block-start: 4px;
  font-variant-numeric: tabular-nums;
}

.d-bar .btn {
  flex: none;
}

.d-bar .btn svg {
  width: 17px;
  height: 17px;
}

body:has(.d-bar) main {
  padding-block-end: 72px;
}

body:has(.d-bar) .float-contact {
  display: none;
}

@media (min-width: 900px) {
  .d-bar {
    display: none;
  }

  body:has(.d-bar) main {
    padding-block-end: 0;
  }

  body:has(.d-bar) .float-contact {
    display: grid;
  }
}

.d-grid {
  display: grid;
  gap: var(--s-7);
  align-items: start;
  padding-block: var(--s-6) var(--sec);
}

.d-head {
  display: flex;
  flex-direction: column;
  gap: 12px;
  margin-block-end: 26px;
}

.d-tags {
  display: flex;
  flex-wrap: wrap;
  gap: 7px;
}

.d-tag {
  padding: 5px 12px;
  border-radius: var(--r-pill);
  background: hsl(var(--accent-soft));
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: hsl(var(--accent-ink));
}

.d-badge {
  padding: 5px 12px;
  border-radius: var(--r-pill);
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  background: hsl(var(--accent));
  color: hsl(var(--surface));
}

.d-badge--sprzedana {
  background: hsl(var(--ink));
  color: #fff;
}

.d-loc {
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: hsl(var(--muted));
}

.d-title {
  font-size: clamp(1.9rem, 3.6vw, 2.9rem);
}

.d-quick {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-block-start: 4px;
}

.d-quick li {
  padding: 7px 14px;
  border-radius: var(--r-sm);
  background: hsl(var(--surface-2));
  font-size: 0.86rem;
  font-weight: 650;
  color: hsl(var(--ink-2));
  font-variant-numeric: tabular-nums;
}

.d-block {
  margin-block-start: var(--s-7);
}

.d-block h2 {
  font-size: clamp(1.4rem, 2.4vw, 1.9rem);
  margin-block-end: 18px;
}

.d-desc {
  display: grid;
  gap: 16px;
  color: hsl(var(--ink-2));
  max-width: 68ch;
}

.params {
  /* Flex, nie grid: liczba parametrow zalezy od oferty i przy siatce ostatni
     wiersz konczyl sie pustymi komorkami, przez ktore przebijalo tlo linii —
     wygladalo to jak dziura w tabeli. We flexie ostatni wiersz sie rozciaga. */
  display: flex;
  flex-wrap: wrap;
  gap: 1px;
  background: hsl(var(--line));
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: var(--sh-1);
}

.par {
  flex: 1 1 220px;
  background: hsl(var(--surface));
  padding: 15px 20px;
  display: flex;
  flex-direction: column;
  gap: 2px;
}

.par dt {
  font-size: 0.73rem;
  font-weight: 700;
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: hsl(var(--muted));
}

.par dd {
  margin: 0;
  font-size: 0.98rem;
  font-weight: 650;
  font-variant-numeric: tabular-nums;
}

.feats {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 200px), 1fr));
  gap: 10px;
}

.feats li {
  position: relative;
  padding: 11px 16px 11px 40px;
  border-radius: var(--r);
  background: hsl(var(--surface));
  box-shadow: var(--sh-1);
  font-size: 0.88rem;
  font-weight: 600;
}

.feats li::before {
  content: '';
  position: absolute;
  left: 15px;
  top: 50%;
  translate: 0 -50%;
  width: 15px;
  height: 15px;
  background: hsl(var(--accent));
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12 5 5 9-10'/%3E%3C/svg%3E") center / contain no-repeat;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m5 12 5 5 9-10'/%3E%3C/svg%3E") center / contain no-repeat;
}

.aside {
  display: grid;
  gap: 18px;
  position: sticky;
  top: 100px;
}

.pricebox {
  background: hsl(var(--surface));
  border-radius: var(--r-xl);
  padding: var(--s-5);
  box-shadow: var(--sh-2);
  display: grid;
  gap: 16px;
}

.pricebox__price {
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 6px 12px;
}

.pricebox__price b {
  font-family: var(--serif);
  font-size: clamp(1.9rem, 3.4vw, 2.5rem);
  font-weight: 600;
  letter-spacing: -0.035em;
  line-height: 1;
  color: hsl(var(--brand));
  font-variant-numeric: tabular-nums;
}

.pricebox__price i {
  font-style: normal;
  font-size: 0.85rem;
  font-weight: 650;
  color: hsl(var(--muted));
  font-variant-numeric: tabular-nums;
}

.pricebox__id {
  font-size: 0.76rem;
  font-weight: 650;
  color: hsl(var(--muted));
  padding-block-end: 4px;
  border-block-end: 1px solid hsl(var(--line));
}

.agent {
  display: flex;
  align-items: center;
  gap: 14px;
  padding-block-start: 4px;
}

.agent__av {
  display: grid;
  place-content: center;
  width: 50px;
  height: 50px;
  flex: none;
  border-radius: var(--r-lg);
  background: hsl(var(--brand));
  color: #fff;
  font-family: var(--serif);
  font-size: 1.12rem;
  font-weight: 600;
}

.agent__txt {
  display: grid;
  gap: 1px;
  min-width: 0;
}

.agent__name {
  font-size: 0.96rem;
  font-weight: 700;
}

.agent__role {
  font-size: 0.76rem;
  color: hsl(var(--muted));
  line-height: 1.45;
}

.pricebox__actions {
  display: grid;
  gap: 9px;
}

.pricebox__date {
  margin-block-start: 12px;
  font-size: 0.76rem;
  color: hsl(var(--muted));
  text-align: center;
}

/*
 * Jedyny taki blok na stronie. W kremie z podwojna zlota obwodka czytal sie
 * jak wtret z innego projektu; na tej samej kosci sloniowej co tabela
 * kontaktowa nad nim jest po prostu jej ostatnim wierszem.
 */
.trust {
  display: grid;
  gap: var(--s-1);
  padding: var(--s-4) 22px;
  background: hsl(var(--surface));
  box-shadow: inset 3px 0 0 hsl(var(--accent)), var(--sh-1);
}

.trust h3,
.trust h2 {
  font-family: var(--sans);
  font-size: 0.88rem;
  font-weight: 750;
  letter-spacing: -0.01em;
  line-height: 1.45;
}

.trust p {
  font-size: 0.84rem;
  color: hsl(var(--ink-2));
  line-height: 1.6;
}

[data-reveal] {
  opacity: 0;
  transform: translateY(16px);
}

.is-in[data-reveal],
[data-reveal].is-in {
  opacity: 1;
  transform: none;
  transition: opacity 0.45s var(--ease), transform 0.5s var(--ease);
  /*
   * Opoznienie roslo liniowo z --i, wiec w siatce ofert dziewiata karta
   * czekala ponad pol sekundy po pierwszej — przy szybkim przewijaniu
   * widac bylo, jak dolne karty doganiaja gorne. Kaskada konczy sie na
   * czwartym elemencie, dalej wszystko wchodzi razem.
   */
  transition-delay: calc(min(var(--i, 0), 3) * 70ms);
}

@media (min-width: 640px) {
  .stats {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .form__row--2 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .grid-3 {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .svc-list {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .svc--flag {
    grid-column: 1 / -1;
  }

  .steps {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

/*
 * Rozbicie rytmu. Bez tego kazda z jedenastu sekcji ma ten sam ksztalt:
 * naglowek u gory, siatka pod spodem — i strona czyta sie jak szablon.
 * Tu naglowek schodzi do lewej kolumny i zostaje przyklejony, gdy tresc
 * przewija sie obok.
 */
/*
 * Pierwsza oferta na stronie glownej dostaje inny ksztalt niz reszta.
 * Bez tego sekcja ofert — czyli towar — ma dokladnie taka sama wage
 * wizualna jak pasek z logotypami bankow.
 */
@media (min-width: 900px) {
  /*
   * Siedem ofert w trzech kolumnach zostawialo ostatni kafelek samotnie
   * w rzedzie. :nth-child(3n+1):last-child odpala sie dokladnie w tym
   * przypadku i oddaje mu uklad poziomy sprawdzony juz na stronie glownej.
   */
  .grid-3 > .card--lead:not(.card--noimg),
  .grid-3 > .card:not(.card--noimg):nth-child(3n + 1):last-child {
    grid-column: span 2;
  }

  .card--lead:not(.card--noimg) .card__link,
  .grid-3 > .card:not(.card--noimg):nth-child(3n + 1):last-child .card__link {
    flex-direction: row;
  }

  .card--lead:not(.card--noimg) .card__media,
  .grid-3 > .card:not(.card--noimg):nth-child(3n + 1):last-child .card__media {
    flex: 0 0 52%;
    aspect-ratio: auto;
  }

  .card--lead:not(.card--noimg) .card__body,
  .grid-3 > .card:not(.card--noimg):nth-child(3n + 1):last-child .card__body {
    gap: 10px;
    padding: clamp(24px, 3vw, 42px);
  }

  .card--lead:not(.card--noimg) .card__title,
  .grid-3 > .card:not(.card--noimg):nth-child(3n + 1):last-child .card__title {
    font-size: clamp(1.35rem, 2vw, 1.85rem);
  }

  .card--lead:not(.card--noimg) .card__price b,
  .grid-3 > .card:not(.card--noimg):nth-child(3n + 1):last-child .card__price b {
    font-size: clamp(1.9rem, 2.6vw, 2.5rem);
  }
}

/*
 * Kafelek oferty bez zdjecia. Pusty kadr 3/2 oddawal 230 px pionu za nic,
 * a cena — jedyna informacja, ktora tu naprawde wazy — dostawala 1.5 rem
 * na dole. Bez zdjecia ciezar bierze cena, a kadr kurczy sie do paska
 * z typem, statusem i informacja, ze zdjecia dopiero beda. Wariant znika
 * sam, gdy w panelu pojawi sie pierwsze zdjecie.
 */
.card--noimg .card__media {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  aspect-ratio: auto;
  min-height: 0;
  padding: 10px var(--s-4);
  background: hsl(var(--surface-2));
  border-block-end: 1px solid hsl(var(--line));
}

.card--noimg .card__media::after {
  display: none;
}

.card--noimg .card__tags {
  position: static;
  order: 1;
}

.card--noimg .ph {
  order: 2;
  position: static;
  width: auto;
  height: auto;
  min-height: 0;
  flex-direction: row;
  align-items: center;
  gap: 7px;
  margin-inline-start: auto;
  background: none;
  box-shadow: none;
}

.card--noimg .ph::before {
  display: none;
}

/* W pasku obok badge'a typu i statusu ikona domu jest juz tylko szumem. */
.card--noimg .ph__mark {
  display: none;
}

.card--noimg .ph__label {
  font-size: 0.6rem;
  letter-spacing: 0.12em;
  white-space: nowrap;
}

.card--noimg .card__badge {
  position: static;
  order: 3;
}

.card--noimg .card__body {
  gap: var(--s-2);
  padding-block: var(--s-5);
}

.card--noimg .card__price b {
  font-size: clamp(1.9rem, 3vw, 2.4rem);
  line-height: 1;
}

@media (min-width: 1000px) {
  .sec--split > .wrap {
    display: grid;
    grid-template-columns: minmax(240px, 0.34fr) minmax(0, 1fr);
    gap: var(--s-8);
    align-items: start;
  }

  /*
   * Naglowek trzyma sie kolumny pierwszej i CALEJ wysokosci sekcji, a wszystko
   * inne idzie do kolumny drugiej.
   *
   * Bez tego przypisania siatka rozstawiala dzieci automatycznie: naglowek
   * ladowal w rzedzie 1 kolumnie 1, karty w rzedzie 1 kolumnie 2, a kafelek
   * "Pelny opis kazdej uslugi" spadal do rzedu 2 KOLUMNY 1 — czyli pod
   * przyklejony naglowek. Przy przewijaniu naglowek zjezdzal na niego
   * i tekst nachodzil na tekst (do 167 px nakladki).
   *
   * Pulapka przy szukaniu tego bledu: widac go WYLACZNIE przy prawdziwym
   * przewijaniu. Skokowe window.scrollTo z testu nie odtwarza go wcale.
   */
  .sec--split .sec__head {
    grid-column: 1;
    grid-row: 1 / -1;
    align-self: start;
    position: sticky;
    top: calc(var(--head-h) + var(--s-4));
    margin: 0;
    max-width: none;
  }

  .sec--split > .wrap > :not(.sec__head) {
    grid-column: 2;
  }

  /* Naglowek w waskiej kolumnie musi zejsc ze skali pelnej szerokosci,
     inaczej lamie sie na pojedyncze sylaby. */
  .sec--split .sec__head .h2 {
    font-size: clamp(1.7rem, 2.3vw, 2.4rem);
  }

  .sec--split .sec__head .lead {
    font-size: 0.95rem;
  }

  .sec--split .svc-list,
  .sec--split .steps {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }
}

@media (min-width: 900px) {
  .nav__links {
    display: flex;
  }

  .nav__tel {
    display: none;
  }

  .nav__contact {
    display: inline-flex;
  }

  .nav__burger {
    display: none;
  }

  .menu {
    display: none;
  }

  .hero__in {
    grid-template-columns: minmax(0, 1.06fr) minmax(0, 0.94fr);
    align-items: center;
    gap: clamp(48px, 6vw, 86px);
  }

  .hero__media {
    max-height: min(70vh, 640px);
  }

  .grid-3 {
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .comp__item {
    grid-template-columns: 90px 1fr;
    align-items: center;
  }

  .steps {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .svc-list {
    grid-template-columns: repeat(4, minmax(0, 1fr));
  }

  .svc--flag {
    grid-column: auto;
    display: flex;
  }

  /* Kafelek wraca do jednej kolumny, wiec numer wraca nad tytul.
     Bez tego align-self z ukladu dwukolumnowego centruje go w poprzek karty. */
  .about__grid {
    grid-template-columns: minmax(0, 0.82fr) minmax(0, 1.18fr);
  }

  /* Panel obok tekstu ma stac przy jego gorze. Wysrodkowany plywal w pustce
     tym bardziej, im krotsza byla tabela uprawnien. */
  .about__grid--rev {
    grid-template-columns: minmax(0, 1.18fr) minmax(0, 0.82fr);
    align-items: start;
  }

  /*
   * Obie karty tej samej wysokosci. Wczesniej `align-items: start` zostawialo
   * biala karte o 130 px krotsza od czarnej i dol sekcji rozjezdzal sie
   * wyraznie. Suwaki rozkladaja sie wtedy rowno na calej wysokosci, a przycisk
   * po prawej trzyma sie dolu karty.
   */
  .calc {
    grid-template-columns: minmax(0, 1.05fr) minmax(0, 0.95fr);
    align-items: stretch;
  }

  .calc__panel {
    align-content: space-between;
  }

  .calc__out .btn {
    margin-block-start: auto;
  }

  .contact__grid {
    grid-template-columns: minmax(0, 0.85fr) minmax(0, 1.15fr);
  }

  .sec__head--row {
    flex-direction: row;
    align-items: flex-end;
    justify-content: space-between;
    gap: 32px;
  }

  .sec__head--row .btn {
    align-self: auto;
    flex: none;
  }

  .d-grid {
    grid-template-columns: minmax(0, 1.5fr) minmax(0, 0.85fr);
  }

  .foot__in {
    grid-template-columns: minmax(0, 0.9fr) minmax(0, 2fr);
  }

  .foot__legal {
    grid-column: 1 / -1;
    grid-template-columns: repeat(3, minmax(0, 1fr));
    align-items: center;
  }

  .foot__legal p:last-child {
    text-align: right;
  }

  .gal--full {
    grid-template-columns: minmax(0, 2fr) minmax(0, 1fr) minmax(0, 1fr);
    grid-template-rows: repeat(2, minmax(0, 1fr));
    height: clamp(380px, 40vw, 560px);
  }

  .gal--full .gal__main {
    grid-row: 1 / 3;
    aspect-ratio: auto;
    height: 100%;
  }

  .gal--full .gal__thumbs {
    display: contents;
  }

  .gal--full .gal__thumb {
    aspect-ratio: auto;
    height: 100%;
  }

  .gal--few .gal__main,
  .gal--one .gal__main {
    aspect-ratio: auto;
    height: clamp(380px, 44vw, 600px);
  }

  /* Miniatury rozciągają się na całą szerokość — przy trzech zdjęciach
     nie zostaje pusta czwarta komórka. */
  .gal--few .gal__thumbs {
    grid-template-columns: repeat(auto-fit, minmax(0, 1fr));
  }

  .gal--few .gal__thumb {
    aspect-ratio: auto;
    height: clamp(150px, 16vw, 220px);
  }
}

@media (min-width: 1100px) {
  .quote__text {
    font-size: 1.02rem;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: 0.01ms !important;
  }

  [data-reveal] {
    opacity: 1;
    transform: none;
  }

  /*
   * Globalne `animation-duration: .01ms` nie zatrzymuje pasa bankow, tylko
   * przewija go natychmiast do konca. Pas ma po prostu stac.
   */
  .banks__track {
    animation: none;
  }
}


/* ------------------------------------------------------ zgoda na statystyki */
/* Pasek u dolu ekranu, nie modal na cala strone: nie blokuje tresci i nie
   wymusza decyzji, zeby cokolwiek przeczytac. Odrzucenie jest tak samo
   widoczne jak zgoda - przycisk obok, nie link petitem w rogu. */

.consent {
  position: fixed;
  inset-inline: 0;
  inset-block-end: 0;
  /* Nad pływającym przyciskiem kontaktu (z-index 95), inaczej „Zgadzam się"
     chowa się pod telefonem i decyzji nie da się kliknąć. */
  z-index: 96;
  padding: 14px var(--pad) calc(14px + env(safe-area-inset-bottom));
  background: hsl(var(--brand));
  color: hsl(var(--on-dark));
  box-shadow: 0 -20px 44px -34px hsl(var(--ink) / 0.9);
  transform: translateY(102%);
  transition: transform 0.42s var(--ease);
}

.consent.is-in {
  transform: none;
}

/* Dopóki pytanie o zgodę stoi na dole ekranu, pływający kontakt ustępuje mu
   miejsca — dwa paski jeden na drugim to zasłonięty przycisk decyzji. */
body:has(.consent) .float-contact,
body.ma-zgode-do-podjecia .float-contact,
body:has(.consent) .ai-launch,
body.ma-zgode-do-podjecia .ai-launch {
  display: none;
}

/*
 * Otwarte okno asystenta bylo tu wczesniej chowane razem z przyciskiem, ktory
 * je otwiera, i to bylo poprawne dopoki jedynym wejsciem byl wlasnie ten
 * przycisk — schowany przycisk nie da sie kliknac, wiec nie bylo czego chowac.
 * Odkad katalog ofert otwiera asystenta z pola nad filtrami, ta sama regula
 * kasowala okno w chwili, w ktorej mialo sie pojawic: klikniecie w „Dobierz
 * oferte" przed decyzja o cookies nie robilo widocznie nic.
 *
 * Okno wiec zostaje, tylko przenosi sie pod naglowek. Pasek zgody ma dol
 * ekranu dla siebie i nadal da sie go kliknac.
 */
body:has(.consent) .ai,
body.ma-zgode-do-podjecia .ai {
  top: calc(var(--head-h) + 14px);
  bottom: auto;
  max-height: min(560px, calc(100dvh - var(--head-h) - 160px));
}

.consent__in {
  display: flex;
  align-items: center;
  gap: 12px 28px;
  flex-wrap: wrap;
  max-width: var(--max);
  margin: 0 auto;
}

.consent__txt {
  flex: 1 1 380px;
  min-width: 0;
}

.consent__txt b {
  display: block;
  font-size: 0.9rem;
  font-weight: 750;
  letter-spacing: -0.02em;
}

.consent__txt p {
  margin: 3px 0 0;
  max-width: 78ch;
  font-size: 0.82rem;
  line-height: 1.6;
  color: hsl(var(--on-dark-2));
}

.consent__txt a {
  color: hsl(var(--accent-lt));
  text-decoration: underline;
  text-underline-offset: 2px;
}

.consent__act {
  display: flex;
  gap: 8px;
  flex-wrap: wrap;
}

.consent__act .btn {
  min-height: 44px;
}

.consent__act .btn--ghost {
  --btn-fg: hsl(var(--on-dark));
  box-shadow: inset 0 0 0 1px hsl(var(--on-dark) / 0.36);
}

.consent__act .btn--ghost:hover {
  box-shadow: inset 0 0 0 1px hsl(var(--on-dark) / 0.7);
}

@media (max-width: 640px) {
  .consent__act {
    width: 100%;
  }

  .consent__act .btn {
    flex: 1;
  }

  /* Na waskim ekranie przyciski i tak lamia sie do osobnych wierszy — przy
     wlasnych szerokosciach dawaly poszarpana krawedz. Rowna kolumna czyta sie
     jak jedna decyzja, a nie dwa przypadkowe klocki. */
  .hero__actions,
  .cta__actions {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
  }

  .hero__actions .btn,
  .cta__actions .btn {
    width: 100%;
  }
}

/* ------------------------------------------ potwierdzenie wyslania formularza */
/* Zastepuje formularz, zamiast dopisywac zdanie pod spodem: po wyslaniu nie ma
   juz czego wypelniac, a czlowiek ma wiedziec, co sie dalej wydarzy. */

.done:focus {
  outline: none;
}

.done {
  display: grid;
  gap: 14px;
  justify-items: start;
  padding: clamp(26px, 4vw, 40px);
  background: hsl(var(--surface));
  box-shadow: var(--sh-1);
}

.done__mark {
  display: grid;
  place-items: center;
  width: 52px;
  height: 52px;
  background: hsl(var(--accent) / 0.16);
  color: hsl(var(--accent-ink));
}

.done__mark svg {
  width: 26px;
  height: 26px;
}

.done h3 {
  font-family: var(--serif);
  font-size: clamp(1.3rem, 2.4vw, 1.7rem);
  font-weight: 600;
  line-height: 1.15;
  letter-spacing: -0.02em;
}

.done p {
  max-width: 54ch;
  font-size: 0.92rem;
  line-height: 1.7;
  color: hsl(var(--ink-2));
}

.done__next {
  display: grid;
  gap: 8px;
  width: 100%;
  margin-block-start: 2px;
  padding-block-start: 16px;
  border-block-start: 1px solid hsl(var(--line));
}

.done__next span {
  display: flex;
  gap: 10px;
  font-size: 0.87rem;
  color: hsl(var(--ink-2));
}

.done__next b {
  flex: none;
  width: 22px;
  font-weight: 750;
  color: hsl(var(--accent-ink));
  font-variant-numeric: tabular-nums;
}

.done__social {
  display: flex;
  align-items: center;
  gap: 10px;
  flex-wrap: wrap;
  width: 100%;
  margin-block-start: 2px;
  padding-block-start: 16px;
  border-block-start: 1px solid hsl(var(--line));
}

.done__social i {
  font-style: normal;
  font-size: 0.72rem;
  font-weight: 750;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: hsl(var(--muted));
}

.done__social a {
  display: inline-flex;
  align-items: center;
  gap: 7px;
  padding: 8px 14px;
  font-size: 0.84rem;
  font-weight: 700;
  color: hsl(var(--ink));
  box-shadow: inset 0 0 0 1px hsl(var(--line-2));
  transition: box-shadow 0.2s var(--ease), transform 0.2s var(--ease);
}

.done__social a:hover {
  transform: translateY(-2px);
  box-shadow: inset 0 0 0 1px hsl(var(--ink) / 0.55);
}

.done__social svg {
  width: 15px;
  height: 15px;
}


/* ------------------------------------------------------------ produkcja */
/* Karta ukryta filtrem: [hidden] przegrywa z każdą regułą display, a te
   w siatce ofert są. Bez tego wiersza filtry przestają cokolwiek chować,
   gdy karta dostanie własny display. */

[hidden] {
  display: none !important;
}

/* Nagłówek, który porządkuje stronę dla czytnika ekranu i wyszukiwarki,
   ale nie wchodzi w skład. Używany tam, gdzie sekcja ma jasny sens
   wizualny i nie potrzebuje podpisu — a bez niego drzewo nagłówków
   przeskakuje z h1 wprost na h3 przy kaflach. */

.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* Pułapka na automaty. Nie display:none — część botów pomija pola ukryte
   tą własnością, a wtedy pułapka nic nie łapie. Człowiek tego nie zobaczy
   i nie zatrzyma się na tym tabulatorem (tabindex="-1" w znaczniku). */

.hp {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

a.lic {
  text-decoration: none;
  transition: background-color 0.2s var(--ease);
}

a.lic:hover {
  background: hsl(var(--surface-2));
}

a.lic .lic__v {
  color: hsl(var(--muted));
  font-weight: 500;
}


/* ------------------------------------------------------- odnosnik "dalej" */
/* Strona glowna niesie calosc; podstrona jest rozwinieciem. Ten odnosnik ma
   wygladac jak zaproszenie, a nie jak wyjscie ewakuacyjne — stad pelna
   szerokosc sekcji, opis czego sie tam dowie i strzalka. */

.sec__more--link {
  margin-block-start: var(--s-5);
}

.deeper {
  display: grid;
  grid-template-columns: 1fr auto;
  align-items: center;
  gap: var(--s-4);
  width: 100%;
  padding: clamp(16px, 2vw, 22px) clamp(18px, 2.4vw, 28px);
  background: hsl(var(--surface));
  border-radius: var(--r-lg);
  box-shadow: inset 0 0 0 1px hsl(var(--line));
  text-decoration: none;
  transition: transform 0.28s var(--ease), box-shadow 0.28s var(--ease);
}

.deeper span {
  display: grid;
  gap: 3px;
}

.deeper b {
  font-size: clamp(0.98rem, 1.3vw, 1.08rem);
  font-weight: 700;
  letter-spacing: -0.02em;
  color: hsl(var(--ink));
}

.deeper i {
  font-style: normal;
  font-size: 0.82rem;
  color: hsl(var(--muted));
}

.deeper svg {
  width: 20px;
  height: 20px;
  flex: none;
  color: hsl(var(--accent-2));
  transition: transform 0.28s var(--ease);
}

.deeper:hover {
  transform: translateY(-2px);
  box-shadow: inset 0 0 0 1px hsl(var(--accent-2) / 0.5);
}

.deeper:hover svg {
  transform: translateX(4px);
}

.banks-head {
  display: grid;
  gap: 6px;
  margin-block-start: var(--s-7);
  text-align: center;
}

.banks-head p {
  color: hsl(var(--muted));
  font-size: 0.9rem;
}

/* --muted jest wyliczone pod papier; na pasie dawalo 3,1:1. */
.band .banks-head p,
.tone-navy .banks-head p {
  color: hsl(var(--on-dark-2));
}

/* ------------------------------------------------ powrot z podstrony */
/* Podstrona to slepy zaulek, jesli nie widac drogi powrotnej. Pasek siedzi
   nad naglowkiem strony i mowi wprost, dokad wraca. */

.backhome {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 8px 14px 8px 10px;
  margin-block-end: clamp(14px, 2vw, 20px);
  border-radius: var(--r-sm);
  background: hsl(var(--surface));
  box-shadow: inset 0 0 0 1px hsl(var(--line));
  font-size: 0.82rem;
  font-weight: 650;
  color: hsl(var(--ink-2));
  text-decoration: none;
  transition: transform 0.22s var(--ease), box-shadow 0.22s var(--ease);
}

.backhome svg {
  width: 16px;
  height: 16px;
  color: hsl(var(--accent-2));
}

.backhome:hover {
  transform: translateX(-2px);
  box-shadow: inset 0 0 0 1px hsl(var(--accent-2) / 0.5);
}

/* Kotwice na stronie jednostronicowej — bez tego nagłówek sekcji chowa się
   pod przyklejonym paskiem nawigacji. */

[id] {
  scroll-margin-top: calc(var(--head-h) + var(--s-3));
}


/* ------------------------------------------------------------- asystent */
/* Panel wychodzi z tego samego rogu, co przyciski szybkiego kontaktu, i na
   czas rozmowy je zastępuje — dwa pływające skupiska w jednym rogu to bałagan
   na telefonie. */

/* Asystent stoi po lewej, szybki kontakt po prawej. Dwa skupiska w jednym
   rogu zaslanialy sie nawzajem, a na telefonie przycisk asystenta ladowal
   pod paskiem zgody. */

/* Nazwa klasy MUSI byc inna niz klasa stanu na <body> ("ai-open"). Gdy byly
   takie same, po otwarciu panelu regula ponizej lapala rowniez <body> i cala
   strona stawala sie elementem position:fixed — uklad skladal sie do jednej
   kolumny, a tresc znikala. */

.ai-launch {
  position: fixed;
  left: clamp(14px, 2vw, 28px);
  bottom: clamp(14px, 2vw, 28px);
  z-index: 95;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  min-height: 44px;
  padding-inline: 16px;
  border: 0;
  border-radius: var(--r-sm);
  background: hsl(var(--surface) / 0.94);
  backdrop-filter: blur(12px);
  color: hsl(var(--ink));
  font: inherit;
  font-size: 0.85rem;
  font-weight: 750;
  cursor: pointer;
  box-shadow: 0 18px 42px -20px hsl(var(--ink) / 0.6), inset 0 0 0 1px hsl(var(--line-2));
  transition: transform 0.24s var(--ease);
}

.ai-launch svg {
  width: 17px;
  height: 17px;
  flex: none;
  color: hsl(var(--accent-2));
}

.ai-launch:hover {
  transform: translateY(-2px);
}

/* Otwarty panel zastepuje przycisk, ktory go otworzyl. */
body.ai-open .ai-launch {
  display: none;
}

/* Na waskim ekranie panel zajmuje niemal cala szerokosc — przyciski kontaktu
   z drugiego rogu i tak by pod nim zniknely, wiec chowamy je swiadomie. */
@media (max-width: 719px) {
  body.ai-open .float-contact {
    display: none;
  }
}

/*
 * Dol ekranu na telefonie.
 *
 * Byly tu trzy rzeczy naraz: przycisk asystenta z podpisem (195 px), "Napisz"
 * i numer telefonu jedno pod drugim. Razem ponad 400 px na ekranie szerokim
 * na 390 — wchodzily na siebie i asystenta praktycznie nie bylo widac.
 *
 * Asystent schodzi wiec do samej ikony, a kontakt uklada sie w jeden wiersz.
 * Podpis zostaje w kodzie dla czytnikow ekranu, bo bez niego przycisk jest
 * niemowa. Banka rozmowy w rogu to uklad, ktory kazdy zna — po podpisie
 * nikt tam nie szuka.
 */
@media (max-width: 719px) {
  .ai-launch {
    width: 52px;
    height: 52px;
    min-height: 52px;
    padding-inline: 0;
    justify-content: center;
    border-radius: var(--r-pill);
    background: hsl(var(--ink));
    box-shadow: 0 18px 42px -18px hsl(var(--ink) / 0.75), inset 0 0 0 1.5px hsl(var(--gold) / 0.55);
  }

  .ai-launch svg {
    width: 22px;
    height: 22px;
    color: hsl(var(--gold));
  }

  /* Podpis znika z oczu, nie z drzewa dostepnosci. */
  .ai-launch span {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  /* "Napisz" i telefon obok siebie zamiast jeden nad drugim. */
  .float-contact {
    grid-auto-flow: column;
    align-items: center;
  }

  .float-contact a {
    padding-inline: 14px;
  }
}

.ai {
  /* Widzet jest doklejany do stopki, a stopka ma jasny tekst na ciemnym tle.
     Bez wlasnych kolorow rozmowa dziedziczy tamte i jest nieczytelna. */
  color: hsl(var(--ink));
  position: fixed;
  left: clamp(14px, 2vw, 28px);
  bottom: clamp(14px, 2vw, 28px);
  z-index: 96;
  display: flex;
  flex-direction: column;
  width: min(380px, calc(100vw - 28px));
  max-height: min(560px, calc(100dvh - 40px));
  background: hsl(var(--surface));
  border-radius: var(--r-lg);
  overflow: hidden;
  box-shadow: 0 32px 70px -28px hsl(var(--ink) / 0.55), inset 0 0 0 1px hsl(var(--line));
}

.ai__head {
  display: flex;
  align-items: flex-start;
  gap: 12px;
  padding: 14px 14px 12px 18px;
  background: hsl(var(--ink));
  color: #fff;
}

.ai__title {
  display: grid;
  gap: 2px;
  flex: 1;
}

.ai__title b {
  font-size: 0.94rem;
  font-weight: 750;
  letter-spacing: -0.02em;
}

.ai__title i {
  font-style: normal;
  font-size: 0.74rem;
  color: hsl(var(--on-dark-2));
  line-height: 1.4;
}

.ai__x {
  flex: none;
  width: 30px;
  height: 30px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: var(--r-sm);
  background: hsl(0 0% 100% / 0.08);
  color: #fff;
  cursor: pointer;
  transition: background-color 0.2s var(--ease);
}

.ai__x svg {
  width: 15px;
  height: 15px;
}

.ai__x:hover {
  background: hsl(0 0% 100% / 0.18);
}

.ai__log {
  flex: 1;
  min-height: 120px;
  overflow-y: auto;
  display: grid;
  align-content: start;
  gap: 10px;
  padding: 16px;
  background: hsl(var(--surface-2));
}

.ai__msg {
  max-width: 88%;
  padding: 10px 13px;
  border-radius: var(--r-sm);
  font-size: 0.86rem;
  line-height: 1.6;
}

/*
 * Ruch w oknie czatu.
 *
 * Okno wjezdza od dolu z rogu, w ktorym stal przycisk — bez tego pojawia sie
 * skokiem i na chwile gubi sie, skad wzielo sie na ekranie. Wiadomosci wchodza
 * tak samo, tylko krocej. Wszystko na transform i opacity, wiec przegladarka
 * nie przelicza ukladu, a caly blok stoi pod zapytaniem o brak preferencji
 * ograniczenia ruchu.
 */
@media (prefers-reduced-motion: no-preference) {
  .ai {
    animation: ai-in 0.34s var(--ease) both;
  }

  .ai__msg {
    animation: ai-msg-in 0.28s var(--ease) both;
  }

  /* Odpowiedz podmienia tresc w tym samym elemencie, wiec bez wlasnej klasy
     nie ma czego animowac — bąbelek jest w drzewie od chwili wyslania pytania. */
  .ai__msg.is-new {
    animation: ai-msg-in 0.3s var(--ease) both;
  }

  .ai__msg.is-wait i {
    animation: ai-dot 1.1s var(--ease) infinite;
  }

  .ai__msg.is-wait i:nth-child(2) {
    animation-delay: 0.16s;
  }

  .ai__msg.is-wait i:nth-child(3) {
    animation-delay: 0.32s;
  }
}

/* Trzy kropki zamiast slowa „Sprawdzam…". Bez animacji stoja jako trzy kropki
   i nadal znacza to samo. */
.ai__msg.is-wait {
  display: flex;
  align-items: center;
  gap: 5px;
  min-height: 38px;
}

.ai__msg.is-wait i {
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: hsl(var(--muted));
}

@keyframes ai-in {
  from {
    opacity: 0;
    transform: translateY(14px) scale(0.97);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes ai-msg-in {
  from {
    opacity: 0;
    transform: translateY(8px);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

@keyframes ai-dot {
  0%,
  70%,
  100% {
    opacity: 0.28;
    transform: translateY(0);
  }
  35% {
    opacity: 1;
    transform: translateY(-3px);
  }
}

.ai__msg--bot {
  justify-self: start;
  color: hsl(var(--ink));
  background: hsl(var(--surface));
  box-shadow: inset 0 0 0 1px hsl(var(--line));
}

.ai__msg--ty {
  justify-self: end;
  background: hsl(var(--ink));
  color: #fff;
}

.ai__msg a {
  color: inherit;
  text-decoration-color: hsl(var(--accent-2));
  text-underline-offset: 3px;
}

/*
 * Odnosnik do oferty albo do katalogu z filtrem. Podpis jest krotki, wiec
 * bez wlasnego znaku wtapia sie w zdanie — strzalka mowi, ze to jest wyjscie
 * z rozmowy, a nie kolejne slowo.
 */
.ai__msg .ai__link {
  display: inline-flex;
  align-items: center;
  gap: 5px;
  font-weight: 700;
  text-decoration: none;
  box-shadow: inset 0 -1px 0 hsl(var(--accent-2) / 0.45);
  transition: box-shadow 0.18s var(--ease);
}

.ai__msg .ai__link::after {
  content: '→';
  font-size: 0.9em;
  transition: transform 0.22s var(--ease);
}

.ai__msg .ai__link:hover {
  box-shadow: inset 0 -1px 0 hsl(var(--ink));
}

@media (prefers-reduced-motion: no-preference) {
  .ai__msg .ai__link:hover::after {
    transform: translateX(3px);
  }
}

.ai__msg.is-wait {
  color: hsl(var(--muted));
  font-style: italic;
}

.ai__msg.is-err {
  color: hsl(var(--ink));
  box-shadow: inset 0 0 0 1px hsl(12 62% 52% / 0.4);
}

.ai__hints {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  padding: 0 14px 12px;
  background: hsl(var(--surface-2));
}

.ai__hints button {
  border: 0;
  border-radius: var(--r-sm);
  padding: 7px 12px;
  background: hsl(var(--surface));
  box-shadow: inset 0 0 0 1px hsl(var(--line));
  color: hsl(var(--ink-2));
  font: inherit;
  font-size: 0.76rem;
  font-weight: 600;
  cursor: pointer;
  transition: box-shadow 0.2s var(--ease);
}

.ai__hints button:hover {
  box-shadow: inset 0 0 0 1px hsl(var(--accent-2) / 0.6);
}

.ai__form {
  display: flex;
  gap: 8px;
  padding: 12px 14px;
  border-block-start: 1px solid hsl(var(--line));
}

.ai__q {
  flex: 1;
  min-width: 0;
  min-height: 42px;
  padding: 10px 14px;
  border: 0;
  border-radius: var(--r-sm);
  background: hsl(var(--surface-2));
  box-shadow: inset 0 0 0 1px hsl(var(--line));
  font: inherit;
  font-size: 0.86rem;
  color: hsl(var(--ink));
}

.ai__q::placeholder {
  color: hsl(var(--muted));
}

.ai__q:focus {
  outline: 0;
  box-shadow: inset 0 0 0 2px hsl(var(--accent-2));
}

.ai__send {
  flex: none;
  width: 42px;
  height: 42px;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: var(--r-sm);
  background: hsl(var(--ink));
  color: #fff;
  cursor: pointer;
  transition: transform 0.2s var(--ease);
}

.ai__send svg {
  width: 17px;
  height: 17px;
}

.ai__send:hover {
  transform: translateX(2px);
}

.ai__send:disabled,
.ai__q:disabled {
  opacity: 0.55;
  cursor: default;
}

.ai__note {
  padding: 0 16px 14px;
  background: hsl(var(--surface));
  font-size: 0.68rem;
  line-height: 1.5;
  color: hsl(var(--muted));
}

.ai__sr {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
}

/*
 * Dotyk nie ma kursora, ale przegladarka i tak odpala :hover po tapnieciu
 * i zostawia go przyklejonego az do nastepnego dotkniecia. Kazde uniesienie
 * kafelka i powiekszenie zdjecia zostawalo wiec na ekranie jako blad.
 * Zdejmujemy sam ruch — zmiany koloru i cienia sa na dotyku nieszkodliwe,
 * a nawet daja potwierdzenie tapniecia.
 */
@media (hover: none), (pointer: coarse) {
  .btn:hover,
  .card__link:hover,
  .card__link:hover .card__media img,
  .card__link:hover .card__more svg,
  .step:hover,
  .offers-more:hover,
  .offers-more:hover svg,
  .foot__nav a:hover,
  .float-contact a:hover,
  .gal__main:hover img,
  .gal__thumb:hover img,
  .done__social a:hover,
  .deeper:hover,
  .deeper:hover svg,
  .backhome:hover,
  .ai-launch:hover,
  .ai__send:hover {
    transform: none;
  }

  .svc:hover::before {
    transform: scaleX(0);
  }
}


/* =================================================================
   WYKONCZENIE WIDOKU
   Poprawki wygladu wychwycone na zrzutach produkcyjnych. Kazda
   dotyczy jednego, konkretnego miejsca, w ktorym uklad czytal sie
   gorzej, niz wyglada w kodzie.
   ================================================================= */

/*
 * Zlota podkreslnik w naglowku hero szedl przez 88% wysokosci linii,
 * czyli dokladnie przez ogonki liter ą, ę i ł. Na "wycenię ją i
 * załatwię kredyt." wygladalo to jak przekreslenie, nie jak akcent.
 * Kreska schodzi pod ogonki (padding + pozycja 100%), a interlinia
 * rosnie na tyle, zeby kreska nie wchodzila w nastepny wiersz.
 */
.hero__title {
  line-height: 1.2;
}

.hero__title span i {
  padding-block-end: 0.14em;
  background-image: linear-gradient(hsl(var(--gold) / 0.9), hsl(var(--gold) / 0.9));
  background-position: 0 100%;
  background-size: 100% 0.055em;
}

/*
 * Kafelek "pokaz pozostale oferty" domykal rzad, ale rozciagal sie na
 * cala jego wysokosc — na stronie glownej dawalo to szara plyte prawie
 * 450 px wysoka z trzema linijkami tresci w srodku. Teraz siedzi na
 * srodku wolnego miejsca i czyta sie jak przycisk, a nie jak pusta karta.
 */
/*
 * Uklad pionowy (liczba, podpis, strzalka jedno pod drugim) zostawial
 * w srodku kafelka ponad 180 px pustego bieli, bo trzy krotkie elementy
 * nie wypelnia dwoch kolumn siatki. W jednym wierszu ta sama tresc
 * zajmuje polowe wysokosci i czyta sie jak przycisk, a nie jak karta,
 * ktorej zabraklo zdjecia. Strzalka dostaje kolko, zeby bylo widac,
 * ze to element do klikniecia, a nie ozdobnik.
 */
.offers-toggle {
  align-self: center;
  flex-direction: row;
  flex-wrap: wrap;
  gap: 14px;
  min-height: 0;
  padding-block: var(--s-5);
  background: none;
  box-shadow: inset 0 0 0 1px hsl(var(--line-2));
  border-radius: var(--r-lg);
}

.offers-toggle b {
  font-size: clamp(1.7rem, 2.4vw, 2.1rem);
}

.offers-toggle svg {
  width: 34px;
  height: 34px;
  margin-block-start: 0;
  padding: 7px;
  border-radius: var(--r-pill);
  box-shadow: inset 0 0 0 1px hsl(var(--line-2));
}

.offers-toggle:hover svg {
  transform: translateY(2px);
  box-shadow: inset 0 0 0 1px hsl(var(--accent) / 0.55);
}

.offers-toggle:hover {
  box-shadow: 0 4px 8px hsl(var(--brand) / 0.16), 0 22px 40px -14px hsl(var(--brand) / 0.5);
}

/*
 * Pas CTA mial tresc wyrownana do lewej i przy 1440 px prawa polowa
 * zostawala pusta — widac bylo sama siatke tla. Naglowek i tekst
 * zostaja po lewej, przyciski schodza do prawej kolumny i domykaja
 * kompozycje.
 */
@media (min-width: 900px) {
  .cta {
    grid-template-columns: minmax(0, 1fr) minmax(240px, auto);
    align-items: center;
    column-gap: var(--s-8);
    row-gap: 14px;
  }

  .cta h2 {
    grid-column: 1;
    grid-row: 1;
  }

  .cta p {
    grid-column: 1;
    grid-row: 2;
  }

  .cta__actions {
    grid-column: 2;
    grid-row: 1 / 3;
    align-self: center;
    flex-direction: column;
    align-items: stretch;
    margin-block-start: 0;
  }

  .cta__actions .btn {
    justify-content: center;
  }
}

/*
 * Pionowe linie co 25% robily za teksture ciemnych pasow, ale za
 * kartami procesu ukladaly sie w widoczna krate — sekcja wygladala na
 * zle wyrenderowana. Zostaje jedna, miekka poswiata: glebia jest,
 * rysunku nie ma.
 */
.band::before {
  background-image:
    radial-gradient(1100px 620px at 82% -12%, hsl(var(--gold) / 0.09), transparent 62%),
    radial-gradient(760px 520px at 4% 108%, hsl(0 0% 100% / 0.05), transparent 60%);
  opacity: 1;
}

/*
 * Logotypy bankow na ciemnym pasie. Wczesniej kazdy siedzial w waskim
 * bialym kafelku z wloskowa ramka, wyszarzony i przygaszony do 66% —
 * czternascie identycznych prostokatow, w ktorych bardziej widac bylo
 * kafelek niz znak. Wybicie znakow na bialo odpada: czesc logotypow
 * (Alior, mBank) to pelne bloki koloru, ktore po inwersji zostaja
 * bialymi prostokatami. Zostaje wiec plytka, ale wieksza, zaokraglona
 * i bez ramki, a znak dostaje powietrze i pelna sile szarosci.
 * Kolor wraca na najechaniu.
 */
.band .banks__item {
  width: clamp(166px, 15vw, 212px);
  height: 88px;
  padding-inline: clamp(18px, 2vw, 26px);
  background: hsl(0 0% 100% / 0.94);
  border-radius: var(--r);
  box-shadow: none;
}

.band .banks__item img {
  max-height: 54px;
  filter: grayscale(1);
  opacity: 0.82;
}

.band .banks__item:hover {
  background: #fff;
  box-shadow: 0 10px 24px -14px hsl(0 0% 0% / 0.9);
}

.band .banks__item:hover img {
  filter: grayscale(0);
  opacity: 1;
}

/*
 * Pasek "Zobacz pelna baze": czarna plyta, a w niej czarny kafelek
 * logotypu — dwa czarne prostokaty jeden w drugim, z widoczna krawedzia
 * miedzy nimi. Kafelek dostaje promien i staje sie znaczkiem, plyta
 * dostaje ten sam promien co pas CTA i te sama zlota poswiate.
 */
.offers-more {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-lg);
  box-shadow: var(--sh-3);
}

.offers-more::before {
  content: '';
  position: absolute;
  inset: 0;
  background-image: radial-gradient(520px 320px at 96% 130%, hsl(var(--gold) / 0.18), transparent 62%);
}

.offers-more > * {
  position: relative;
  z-index: 2;
}

.offers-more img {
  width: clamp(64px, 7vw, 84px);
  border-radius: var(--r);
  box-shadow: 0 0 0 1px hsl(0 0% 100% / 0.1);
  opacity: 1;
}
