/* =========================================================
   Gotowa Strona w 3 Dni — landing page
   Dark premium. Czysty CSS3, zero zależności (poza fontem).
   Mobile-first.
   ========================================================= */

/* ---------- Fonty (hostowane lokalnie) ----------
   Pliki woff2 leżą w assets/fonts/, więc przeglądarka nie musi odpytywać
   fonts.googleapis.com o arkusz, a potem fonts.gstatic.com o same pliki.
   To oszczędza dwa połączenia z obcym hostem i jedno żądanie blokujące render.
   Pobrane są wyłącznie zakresy latin i latin-ext — latin-ext niesie ą ć ę ł ń ś ź ż.

   Metryki fallbacku niżej wyrównują zastępczy Arial do docelowego kroju, żeby
   podmiana fontu po dociągnięciu pliku nie przesuwała layoutu (CLS).
   Wyliczone z tabel OS/2 i hhea: Bricolage x-height 0,528 em, Jakarta 0,536 em,
   Arial 0,5186 em. */

@font-face {
  font-family: "Bricolage Grotesque";
  font-style: normal;
  font-weight: 700 800;
  font-stretch: 100%;
  font-display: swap;
  src: url("../fonts/bricolage-grotesque-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Bricolage Grotesque";
  font-style: normal;
  font-weight: 700 800;
  font-stretch: 100%;
  font-display: swap;
  src: url("../fonts/bricolage-grotesque-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                 U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                 U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("../fonts/plus-jakarta-sans-latin.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA,
                 U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122,
                 U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Plus Jakarta Sans";
  font-style: normal;
  font-weight: 400 800;
  font-display: swap;
  src: url("../fonts/plus-jakarta-sans-latin-ext.woff2") format("woff2");
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF,
                 U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF,
                 U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Jakarta zastepczy";
  src: local("Arial"), local("Helvetica"), local("Liberation Sans");
  size-adjust: 103.4%;
  ascent-override: 100.4%;
  descent-override: 21.5%;
  line-gap-override: 0%;
}

@font-face {
  font-family: "Bricolage zastepczy";
  src: local("Arial"), local("Helvetica"), local("Liberation Sans");
  size-adjust: 101.8%;
  ascent-override: 91.4%;
  descent-override: 26.5%;
  line-gap-override: 0%;
}

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

html {
  scroll-behavior: smooth;
  scroll-padding-top: 86px;
  -webkit-text-size-adjust: 100%;
}

body, h1, h2, h3, h4, p, ul, ol, li, figure { margin: 0; padding: 0; }
ul { list-style: none; }
img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }
button { font: inherit; color: inherit; background: none; border: none; cursor: pointer; }
summary::-webkit-details-marker { display: none; }

/* ---------- Design tokens ---------- */
:root {
  /* Tło i powierzchnie */
  --bg:            #070B14;
  --bg-2:          #0B1120;
  --bg-3:          #0E1526;
  --surface:       rgba(255, 255, 255, 0.035);
  --surface-2:     rgba(255, 255, 255, 0.06);
  --surface-3:     rgba(255, 255, 255, 0.09);
  --border:        rgba(255, 255, 255, 0.09);
  --border-strong: rgba(255, 255, 255, 0.17);

  /* Typografia */
  --text:       #EEF2F9;
  --text-muted: #9AA7BD;
  --text-dim:   #6E7D96;

  /* Marka */
  --brand:       #7C5CFF;   /* akcent dekoracyjny / tekst na ciemnym (6.7:1) */
  --brand-2:     #4F46E5;
  --brand-btn-a: #6D4AFF;   /* start gradientu CTA — biały tekst 5.1:1 */
  --brand-btn-b: #4F46E5;   /* koniec gradientu CTA — biały tekst 6.2:1 */
  --brand-soft:  rgba(124, 92, 255, 0.14);
  --cyan:        #22D3EE;
  --amber:       #FFB020;

  /* Kształt */
  --r-sm: 10px;
  --r-md: 16px;
  --r-lg: 24px;
  --r-xl: 32px;
  --r-pill: 999px;

  /* Cienie */
  --shadow-sm:    0 2px 10px rgba(0, 0, 0, 0.35);
  --shadow-md:    0 12px 32px rgba(0, 0, 0, 0.45);
  --shadow-lg:    0 30px 70px rgba(0, 0, 0, 0.55);
  --glow-brand:   0 10px 34px rgba(109, 74, 255, 0.42);
  --glow-brand-h: 0 16px 46px rgba(109, 74, 255, 0.58);

  --container: 1180px;
  --nav-h: 68px;

  /* Tekst: Plus Jakarta Sans. Nagłówki: Bricolage Grotesque — grotesk ze
     zmienną optyką i wyraźnym charakterem, z pełną polską diakrytyką. */
  --font: "Plus Jakarta Sans", "Jakarta zastepczy", ui-sans-serif, -apple-system,
          BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-display: "Bricolage Grotesque", "Bricolage zastepczy", "Plus Jakarta Sans",
          ui-sans-serif, "Segoe UI", Roboto, Arial, sans-serif;

  --ease: cubic-bezier(0.22, 1, 0.36, 1);
}

/* ---------- Baza ---------- */
body {
  font-family: var(--font);
  color: var(--text);
  background-color: var(--bg);
  line-height: 1.6;
  letter-spacing: -0.011em;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
  overflow-x: hidden;
}

/* Ziarno — zdejmuje "plastik" z płaskich, ciemnych powierzchni */
body::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 9998;
  pointer-events: none;
  opacity: 0.035;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.85' numOctaves='3'/%3E%3C/filter%3E%3Crect width='140' height='140' filter='url(%23n)'/%3E%3C/svg%3E");
}

.container {
  width: 100%;
  max-width: var(--container);
  margin: 0 auto;
  padding: 0 20px;
}

.section { padding: 72px 0; position: relative; }

/* Delikatna linia rozdzielająca sekcje zamiast zmiany koloru tła */
.section-divider {
  border-top: 1px solid var(--border);
  background: radial-gradient(60% 100% at 50% 0%, rgba(124, 92, 255, 0.07), transparent 70%);
}

.section-head {
  max-width: 680px;
  margin: 0 auto 44px;
  text-align: center;
}

/* ---------- Renderowanie poza ekranem (content-visibility) ----------
   Sekcje poniżej pierwszego ekranu pomijają layout/paint/kaskadę stylów,
   dopóki nie zbliżą się do widoku (przeglądarka sama dolicza margines
   i buduje realny layout, zanim sekcja faktycznie wjedzie w viewport, więc
   nic "nie wyskakuje").

   🔴 SEKCJE GALERII (#galeria, #galeria-lp) SĄ TU CELOWO POMINIĘTE — NIE
   DODAWAJ ICH Z POWROTEM.
   Objaw, który to spowodował: losowe kafelki galerii zostawały puste (sam
   czarny prostokąt z podpisem), za każdym wejściem inne, a w gorszym
   wariancie znikał cały blok kilkunastu kafelków naraz (prawe kolumny w
   kilku wierszach z rzędu). Powtarzalne również z file:// — czyli bez
   udziału sieci, hostingu i serwera.
   Powód: content-visibility: auto zakłada "blokadę renderowania"
   (display lock) na całym poddrzewie. Wszystkie 63 obrazki galerii mają
   loading="lazy", a natywne lazy-loading rozstrzyga "czy obrazek jest
   blisko widoku" na podstawie pozycji w layoucie — której zablokowane
   poddrzewo nie ma. Te dwa mechanizmy odraczania nałożone na siebie
   powodują, że w jednej klatce trzeba naraz odblokować, wczytać i
   zdekodować kilkadziesiąt WebP; kompozytor prezentuje klatkę zanim
   część kafelków zdąży się wyrasteryzować i zostają puste prostokąty.
   Galeria NIE traci na tym wydajnościowo: obrazki (czyli praktycznie
   cały koszt tej sekcji) i tak są odroczone przez loading="lazy",
   a content-visibility odraczał tu jedynie layout ~60 pudełek.
   Przy okazji znika nieutrzymywalna rezerwacja wysokości dopasowana
   regresją (calc(1110vw + 160px) i trzy warianty w media queries).

   Poniżej zostają WYŁĄCZNIE sekcje tekstowe, bez ani jednego <img> —
   tam content-visibility jest bezpieczne i nadal się opłaca.

   UWAGA: contain-intrinsic-size rezerwuje wysokość TREŚCI sekcji, a padding
   dochodzi na wierzchu. Wartości poniżej to zmierzona wysokość sekcji MINUS
   jej padding pionowy. Podanie pełnej wysokości sekcji sprawia, że strona
   kurczy się w trakcie przewijania i pasek przewijania skacze. */
#oferta,
#faq,
#kontakt,
.footer {
  content-visibility: auto;
}

#oferta  { contain-intrinsic-size: auto 1025px; }
#faq     { contain-intrinsic-size: auto 1180px; }
#kontakt { contain-intrinsic-size: auto 560px; }
.footer  { contain-intrinsic-size: auto 871px; }

@media (min-width: 480px) {
  #oferta  { contain-intrinsic-size: auto 915px; }
  #faq     { contain-intrinsic-size: auto 930px; }
  #kontakt { contain-intrinsic-size: auto 500px; }
  .footer  { contain-intrinsic-size: auto 850px; }
}

.section-head h2 { margin: 16px 0 14px; }

/* ---------- Typografia ---------- */
h1, h2, h3 {
  color: var(--text);
  line-height: 1.12;
  font-weight: 800;
  letter-spacing: -0.03em;
}

/* Krój display tylko tam, gdzie niesie charakter — nagłówki, cena, logo.
   Reszta interfejsu zostaje w kroju tekstowym, żeby nie przesadzić. */
h1, h2, .brand, .offer-price, .hero-stat b, .step-num, .lightbox-caption {
  font-family: var(--font-display);
  font-optical-sizing: auto;
}

h1, h2 { text-wrap: balance; }

h1 { font-size: clamp(2.1rem, 5.6vw, 3.75rem); }
h2 { font-size: clamp(1.75rem, 4.2vw, 2.75rem); }
h3 { font-size: 1.1rem; font-weight: 700; letter-spacing: -0.02em; }

p { color: var(--text-muted); }

.lead {
  font-size: clamp(1.02rem, 2.2vw, 1.18rem);
  color: var(--text-muted);
  line-height: 1.65;
}

.grad-text {
  background: linear-gradient(100deg, #A78BFA 0%, #7C5CFF 42%, #22D3EE 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  padding: 7px 15px 7px 11px;
  border-radius: var(--r-pill);
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text);
  letter-spacing: -0.005em;
}

.eyebrow .dot {
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--cyan);
  box-shadow: 0 0 0 4px rgba(34, 211, 238, 0.16);
  flex: none;
}

/* ---------- Przyciski ---------- */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  min-height: 50px;
  min-width: 44px;
  padding: 14px 28px;
  border-radius: var(--r-pill);
  font-weight: 700;
  font-size: 1rem;
  letter-spacing: -0.01em;
  text-align: center;
  position: relative;
  overflow: hidden;
  isolation: isolate;
}

.btn svg { flex: none; }

.btn-primary {
  background-image: linear-gradient(135deg, var(--brand-btn-a), var(--brand-btn-b));
  color: #FFFFFF;
  box-shadow: var(--glow-brand);
}

/* Refleks przesuwający się po przycisku przy hoverze */
.btn-primary::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: linear-gradient(115deg, transparent 30%, rgba(255, 255, 255, 0.28) 50%, transparent 70%);
  transform: translateX(-120%);
}

.btn-ghost {
  background: var(--surface-2);
  border: 1px solid var(--border-strong);
  color: var(--text);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
}

.btn-lg { min-height: 56px; padding: 16px 34px; font-size: 1.06rem; }

/* Na najwęższych telefonach 34px paddingu z każdej strony zjadało tyle
   miejsca, że "Zamów swoją stronę" łamało się na dwa wiersze i ten jeden
   przycisk był o połowę wyższy (86px) od pozostałych CTA (59px) — stąd
   wrażenie, że przyciski są nierówne. Zwężamy sam padding, wysokość
   i wielkość liter zostają. */
@media (max-width: 419px) {
  .btn-lg { padding: 16px 18px; font-size: 1rem; }
  .btn { padding: 14px 18px; }
}

.btn:focus-visible {
  outline: 3px solid var(--cyan);
  outline-offset: 3px;
}

@media (prefers-reduced-motion: no-preference) {
  .btn { transition: transform 0.25s var(--ease), box-shadow 0.25s var(--ease), background-color 0.25s var(--ease); }
  .btn-primary::before { transition: transform 0.7s var(--ease); }
  .btn-primary:hover, .btn-primary:focus-visible { transform: translateY(-2px); box-shadow: var(--glow-brand-h); }
  .btn-primary:hover::before, .btn-primary:focus-visible::before { transform: translateX(120%); }
  .btn-ghost:hover, .btn-ghost:focus-visible { background: var(--surface-3); transform: translateY(-2px); }
  .btn:active { transform: scale(0.98); }
}

/* ---------- Pasek postępu czytania ---------- */
.progress-bar {
  position: fixed;
  top: 0;
  left: 0;
  height: 2px;
  width: 100%;
  transform: scaleX(0);
  transform-origin: 0 50%;
  background: linear-gradient(90deg, var(--brand), var(--cyan));
  z-index: 1001;
  pointer-events: none;
}

/* ---------- Nawigacja ---------- */
.nav {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: var(--nav-h);
  z-index: 1000;
  display: flex;
  align-items: center;
  border-bottom: 1px solid transparent;
}

/* Bez backdrop-filter celowo: pasek jest fixed i widoczny non-stop podczas
   scrolla, więc rozmycie tła musiałoby się przeliczać co klatkę na całą
   szerokość ekranu — jeden z dwóch najdroższych przypadków blur() na
   stronie (drugi to .sticky-cta niżej). Podbite tło (0.72→0.9) daje
   niemal identyczny wizualnie efekt "przyciemnionego paska" bez tego kosztu. */
.nav.is-stuck {
  background: rgba(7, 11, 20, 0.9);
  border-bottom-color: var(--border);
}

.nav .container {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  font-weight: 800;
  letter-spacing: -0.03em;
  font-size: 1rem;
  color: var(--text);
  min-height: 44px;
}

.brand-mark {
  width: 32px;
  height: 32px;
  border-radius: 9px;
  background-image: linear-gradient(140deg, var(--brand-btn-a), var(--brand-btn-b));
  display: grid;
  place-items: center;
  box-shadow: 0 4px 14px rgba(109, 74, 255, 0.45);
  flex: none;
}

.brand-mark svg { width: 17px; height: 17px; color: #fff; }

.nav-links { display: none; align-items: center; gap: 4px; }

.nav-links a {
  padding: 9px 14px;
  border-radius: var(--r-pill);
  font-size: 0.92rem;
  font-weight: 600;
  color: var(--text-muted);
}

.nav-links a:hover,
.nav-links a:focus-visible { color: var(--text); background: var(--surface-2); }

.nav-cta {
  display: none;
  min-height: 44px;
  padding: 11px 22px;
  font-size: 0.94rem;
}

.nav a:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }

@media (prefers-reduced-motion: no-preference) {
  .nav { transition: background-color 0.3s var(--ease), border-color 0.3s var(--ease); }
  .nav-links a { transition: color 0.2s var(--ease), background-color 0.2s var(--ease); }
}

/* ---------- Hero ---------- */
.hero {
  position: relative;
  overflow: hidden;
  padding: calc(var(--nav-h) + 44px) 0 64px;
}

.hero-bg {
  position: absolute;
  inset: -30% -20% auto;
  height: 150%;
  pointer-events: none;
  z-index: 0;
  background:
    radial-gradient(46% 42% at 20% 18%, rgba(124, 92, 255, 0.34), transparent 68%),
    radial-gradient(40% 36% at 82% 12%, rgba(34, 211, 238, 0.17), transparent 66%),
    radial-gradient(52% 46% at 62% 66%, rgba(79, 70, 229, 0.22), transparent 70%);
  filter: blur(6px);
}

/* Siatka techniczna — subtelny "produktowy" podkład */
.hero-grid {
  position: absolute;
  inset: 0;
  z-index: 0;
  pointer-events: none;
  background-image:
    linear-gradient(rgba(255, 255, 255, 0.045) 1px, transparent 1px),
    linear-gradient(90deg, rgba(255, 255, 255, 0.045) 1px, transparent 1px);
  background-size: 62px 62px;
  mask-image: radial-gradient(78% 62% at 50% 34%, #000 20%, transparent 78%);
  -webkit-mask-image: radial-gradient(78% 62% at 50% 34%, #000 20%, transparent 78%);
}

.hero .container { position: relative; z-index: 1; }

.hero-layout {
  display: grid;
  grid-template-columns: 1fr;
  gap: 56px;
  align-items: center;
}

/* Elementy grida domyślnie mają min-width:auto — nie kurczą się poniżej
   szerokości własnej (nie zawijalnej) treści. Bez tego np. adres w
   mockupie przeglądarki (nowrap) rozpychał całą kolumnę poza viewport
   na wąskich ekranach. */
.hero-copy, .hero-visual { min-width: 0; }

.hero-copy { max-width: 620px; }

.hero h1 { margin: 20px 0 18px; }

.hero-sub { margin-bottom: 30px; max-width: 540px; }

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  margin-bottom: 34px;
}

/* Pasek dowodów pod CTA */
.hero-stats {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: 1px;
  background: var(--border);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
  max-width: 520px;
}

.hero-stat { background: var(--bg); padding: 16px 18px; }

.hero-stat b {
  display: block;
  white-space: nowrap;
  font-size: 1.4rem;
  font-weight: 800;
  letter-spacing: -0.035em;
  line-height: 1.1;
  color: var(--text);
}

/* tylko bezpośredni potomek — .unit siedzi w <b> i ma zostać w tej samej linii */
.hero-stat > span {
  display: block;
  font-size: 0.82rem;
  color: var(--text-dim);
  margin-top: 3px;
}

.hero-stat .unit { font-size: 0.92rem; color: var(--text-muted); font-weight: 700; }

/* ---------- Mockup przeglądarki w hero (czysty CSS, 0 KB grafiki) ---------- */
.hero-visual {
  position: relative;
  display: flex;
  justify-content: center;
  padding: 10px 8px;
}

.mock {
  position: relative;
  width: 100%;
  max-width: 520px;
  border-radius: var(--r-lg);
  border: 1px solid var(--border-strong);
  background: linear-gradient(180deg, #131C30, #0B1120);
  box-shadow: var(--shadow-lg), 0 0 0 1px rgba(124, 92, 255, 0.12);
  overflow: hidden;
}

.mock-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  padding: 11px 14px;
  background: rgba(255, 255, 255, 0.05);
  border-bottom: 1px solid var(--border);
}

.mock-dots { display: flex; gap: 6px; flex: none; }
.mock-dots i { width: 9px; height: 9px; border-radius: 50%; display: block; }
.mock-dots i:nth-child(1) { background: #FF5F57; }
.mock-dots i:nth-child(2) { background: #FEBC2E; }
.mock-dots i:nth-child(3) { background: #28C840; }

.mock-url {
  flex: 1;
  /* Bez tego flex-item nie może się skurczyć poniżej szerokości własnej
     treści (domyślne min-width:auto) — na wąskich ekranach napis URL
     (nowrap) rozpychał cały mockup poza viewport zamiast się przycinać. */
  min-width: 0;
  height: 22px;
  border-radius: var(--r-pill);
  background: rgba(255, 255, 255, 0.07);
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 0 10px;
  font-size: 0.68rem;
  /* Napis leży w makiecie oznaczonej aria-hidden, więc czytniki go pomijają,
     ale audyty automatyczne liczą kontrast wszystkiego. --text-dim dawał
     3,57:1 przy tym stopniu pisma, --text-muted daje 8,09:1. */
  color: var(--text-muted);
  letter-spacing: 0;
  overflow: hidden;
  white-space: nowrap;
}

.mock-url-text {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
  min-width: 0;
}

.mock-body { padding: 18px; display: grid; gap: 14px; }

.mock-hero {
  border-radius: var(--r-md);
  padding: 22px 18px;
  background:
    radial-gradient(80% 120% at 15% 0%, rgba(124, 92, 255, 0.42), transparent 60%),
    linear-gradient(135deg, #1A2440, #0F1729);
  border: 1px solid var(--border);
  display: grid;
  gap: 9px;
}

.sk { border-radius: 6px; background: rgba(255, 255, 255, 0.12); height: 9px; }
.sk-lg { height: 15px; background: rgba(255, 255, 255, 0.34); }
.sk-w90 { width: 90%; } .sk-w70 { width: 70%; } .sk-w55 { width: 55%; } .sk-w40 { width: 40%; }

.mock-btn {
  margin-top: 6px;
  width: 118px;
  height: 30px;
  border-radius: var(--r-pill);
  background-image: linear-gradient(135deg, var(--brand-btn-a), var(--brand-btn-b));
  box-shadow: 0 6px 18px rgba(109, 74, 255, 0.4);
}

.mock-cards { display: grid; grid-template-columns: repeat(3, 1fr); gap: 10px; }

.mock-card {
  border-radius: var(--r-sm);
  border: 1px solid var(--border);
  background: rgba(255, 255, 255, 0.04);
  padding: 12px 10px;
  display: grid;
  gap: 7px;
}

.mock-card .ic {
  width: 20px;
  height: 20px;
  border-radius: 6px;
  background: linear-gradient(140deg, rgba(124, 92, 255, 0.9), rgba(34, 211, 238, 0.75));
}

/* Odblask przesuwający się po mockupie. Pasek węższy niż .mock i
   przesuwany transformem (zamiast animowania background-position) — tamta
   wersja wymuszała paint co klatkę, ta jest w całości kompozytowana na GPU.
   .mock ma overflow:hidden, więc pasek jest przycinany przy wjeżdżaniu
   i zjeżdżaniu poza krawędzie. */
.mock-shine {
  position: absolute;
  top: 0;
  bottom: 0;
  left: -30%;
  width: 55%;
  pointer-events: none;
  background: linear-gradient(115deg, transparent 0%, rgba(255, 255, 255, 0.14) 50%, transparent 100%);
  transform: translateX(-40%);
}

/* Pływające "odznaki" wokół mockupu */
.mock-badge {
  position: absolute;
  z-index: 2;
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 15px;
  border-radius: var(--r-pill);
  background: rgba(13, 20, 36, 0.88);
  border: 1px solid var(--border-strong);
  /* Małe elementy (odznaki ~150px), więc blur jest tani niezależnie od
     promienia — zostawione, bo realnie buduje "unoszącą się szybę".
     Promień lekko przycięty (12→8px) jako drobna oszczędność, bo to
     jedyne dwa elementy z backdrop-filter animowane w nieskończoność. */
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  box-shadow: var(--shadow-md);
  font-size: 0.85rem;
  font-weight: 700;
  white-space: nowrap;
  color: var(--text);
}

.mock-badge-price { top: 8%; right: -4px; }
.mock-badge-price b { color: var(--amber); font-size: 1.05rem; }
.mock-badge-time { bottom: 4%; left: -4px; }
.mock-badge-time svg { color: var(--cyan); }

@media (prefers-reduced-motion: no-preference) {
  /* Wszystkie cztery animacje poniżej ruszają tylko transform/opacity —
     kompozytowane na GPU, bez layoutu ani paintu na wątku głównym.
     will-change tylko tutaj (nie w bazowych regułach): przy reduced-motion
     animacji nie ma, więc i rezerwowanie warstwy kompozytora byłoby
     marnowaniem pamięci bez żadnej korzyści. Elementy siedzą w hero, czyli
     w pierwszym ekranie — nie ma ryzyka trzymania will-change na czymś,
     co user może nigdy nie zobaczyć. */
  .mock { animation: mock-float 7s ease-in-out infinite; will-change: transform; }
  .mock-shine { animation: mock-shine 6s ease-in-out infinite; will-change: transform; }
  .hero-bg { animation: aurora 16s ease-in-out infinite alternate; will-change: transform; }
  .mock-badge-price { animation: mock-float 7s ease-in-out infinite 0.6s; will-change: transform; }
  .mock-badge-time { animation: mock-float 7s ease-in-out infinite 1.2s; will-change: transform; }
}

@keyframes mock-float {
  0%, 100% { transform: translateY(0); }
  50%      { transform: translateY(-10px); }
}

@keyframes mock-shine {
  0%, 100% { transform: translateX(-40%); }
  55%      { transform: translateX(260%); }
}

@keyframes aurora {
  0%   { transform: translate3d(0, 0, 0) scale(1); }
  100% { transform: translate3d(0, -3%, 0) scale(1.08); }
}

/* ---------- Scroll reveal ---------- */
.reveal { opacity: 1; transform: none; }

@media (prefers-reduced-motion: no-preference) {
  html.js .reveal {
    opacity: 0;
    transform: translateY(22px);
    transition: opacity 0.6s var(--ease), transform 0.6s var(--ease);
  }
  html.js .reveal.is-visible { opacity: 1; transform: none; }
}

/* ---------- Jak to działa ---------- */
.steps {
  display: grid;
  grid-template-columns: 1fr;
  gap: 18px;
  position: relative;
}

.step {
  position: relative;
  background: linear-gradient(180deg, var(--surface-2), var(--surface));
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 26px 24px 28px;
  overflow: hidden;
}

/* Świecąca krawędź górna — pojawia się na hoverze */
.step::after {
  content: "";
  position: absolute;
  top: 0;
  left: 12%;
  right: 12%;
  height: 1px;
  background: linear-gradient(90deg, transparent, var(--brand), transparent);
  opacity: 0;
}

.step-icon {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 46px;
  height: 46px;
  border-radius: 15px;
  background: var(--brand-soft);
  border: 1px solid rgba(124, 92, 255, 0.4);
  color: #C4B5FD;
  margin-bottom: 20px;
}

.step-icon svg { width: 23px; height: 23px; }

/* Duża, przygaszona cyfra w rogu — porządkuje kolejność bez krzyczenia */
.step-num {
  position: absolute;
  top: 16px;
  right: 20px;
  font-size: 2.6rem;
  font-weight: 800;
  line-height: 1;
  letter-spacing: -0.05em;
  color: rgba(255, 255, 255, 0.055);
}

.step-kicker {
  font-size: 0.72rem;
  font-weight: 700;
  letter-spacing: 0.09em;
  text-transform: uppercase;
  color: #8B7BD8;
  margin-bottom: 6px;
}

.step-title { margin-bottom: 8px; }
.step-desc { font-size: 0.96rem; }

@media (prefers-reduced-motion: no-preference) {
  .step { transition: transform 0.3s var(--ease), border-color 0.3s var(--ease), background-color 0.3s var(--ease); }
  .step::after { transition: opacity 0.3s var(--ease); }
  .step:hover { transform: translateY(-4px); border-color: var(--border-strong); }
  .step:hover::after { opacity: 1; }
}

/* ---------- Galeria ---------- */
/* Filtry (przebudowa 2026-09-29). Od 700 px: zwarte pigułki w 1-2 rzędach.
   Poniżej 700 px, gdy działa JS, pigułki zastępuje natywna lista wyboru
   (main.js tworzy <select> zsynchronizowany z przyciskami) - 13 pigułek
   w przewijanym pasku nie dawało sygnału, że są kolejne. Bez JS filtry
   i tak nie działają, a siatka pokazuje komplet kafelków. */
.gallery-filters {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 6px 8px;
  margin: 0 auto 32px;
  max-width: 1000px;
}

.gallery-select-wrap {
  display: none;
  margin: 0 0 24px;
}
.gallery-select-wrap label {
  display: block;
  font-size: 0.82rem;
  font-weight: 600;
  color: var(--text-muted);
  margin-bottom: 6px;
}
.gallery-select {
  width: 100%;
  min-height: 48px;
  padding: 10px 44px 10px 16px;
  border-radius: var(--r-md);
  border: 1px solid var(--border-strong);
  background-color: var(--surface-2);
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24' fill='none' stroke='%239AA7BD' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='m6 9 6 6 6-6'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 16px center;
  color: var(--text);
  font: inherit;
  font-weight: 600;
  appearance: none;
  -webkit-appearance: none;
}
.gallery-select option { background: var(--bg-2); color: var(--text); }
.gallery-select:focus-visible { outline: 3px solid var(--cyan); outline-offset: 2px; }

@media (max-width: 699px) {
  html.js .gallery-filters { display: none; }
  html.js .gallery-select-wrap { display: block; }
}

.filter-btn {
  padding: 7px 14px;
  border-radius: var(--r-pill);
  border: 1px solid var(--border);
  background: var(--surface);
  color: var(--text-muted);
  font-size: 0.84rem;
  font-weight: 600;
  /* Bez JS pigułki są widoczne także na telefonie, więc cel dotyku
     zostaje 44 px (WCAG 2.5.5); od 700 px wystarczy zwarty 36 px. */
  min-height: 44px;
}
@media (min-width: 700px) {
  .filter-btn { min-height: 36px; }
}

.filter-btn:hover { color: var(--text); border-color: var(--border-strong); }

.filter-btn[aria-pressed="true"] {
  background-image: linear-gradient(135deg, var(--brand-btn-a), var(--brand-btn-b));
  border-color: transparent;
  color: #FFFFFF;
  box-shadow: 0 6px 20px rgba(109, 74, 255, 0.35);
}

.filter-btn:focus-visible { outline: 3px solid var(--cyan); outline-offset: 2px; }

@media (prefers-reduced-motion: no-preference) {
  .filter-btn { transition: color 0.2s var(--ease), background-color 0.2s var(--ease), border-color 0.2s var(--ease), box-shadow 0.2s var(--ease); }
}

/* Siatka projektów (przebudowa 2026-09-29): czyste karty jak w portfolio
   studia. Obraz 16:10 kadrowany na górę makiety (hero), bez gradientu na
   obrazie; nazwa branży i kategoria POD obrazem. 1 kolumna do 559 px
   (miniatura czytelna na telefonie), 2 do 899 px, potem 3. */
.gallery-grid {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 18px;
}

.gallery-item {
  position: relative;
  display: flex;
  flex-direction: column;
  width: 100%;
  padding: 0;
  border-radius: var(--r-md);
  border: 1px solid var(--border);
  background: var(--bg-2);
  overflow: hidden;
  box-shadow: var(--shadow-sm);
  text-align: left;
  color: inherit;
  font: inherit;
  cursor: zoom-in;
}

.gallery-item[hidden] { display: none; }

.gallery-item img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  object-position: top center;
  background: #E9EDF3;           /* jasne tło zamiast czarnej dziury, zanim obraz dojdzie */
  border-bottom: 1px solid var(--border);
}

.gallery-meta {
  display: flex;
  flex-direction: column;
  gap: 2px;
  padding: 12px 16px 14px;
  flex: 1 1 auto;
}

.gallery-label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 700;
  color: var(--text);
  letter-spacing: -0.01em;
  line-height: 1.3;
}

.gallery-cat {
  font-size: 0.8rem;
  color: var(--text-dim);
  line-height: 1.4;
}

.gallery-label svg { opacity: 0.55; color: var(--cyan); flex: none; }

@media (prefers-reduced-motion: no-preference) {
  .gallery-item { transition: transform 0.25s var(--ease), box-shadow 0.25s var(--ease), border-color 0.25s var(--ease); }
  .gallery-item img { transition: transform 0.4s var(--ease); }
  .gallery-label svg { transition: opacity 0.2s var(--ease), transform 0.2s var(--ease); }
  .gallery-item:hover, .gallery-item:focus-visible { transform: translateY(-3px); box-shadow: var(--shadow-md); border-color: rgba(124, 92, 255, 0.45); }
  .gallery-item:hover img, .gallery-item:focus-visible img { transform: scale(1.03); }
  .gallery-item:hover .gallery-label svg, .gallery-item:focus-visible .gallery-label svg { opacity: 1; transform: translateX(2px); }
}

.gallery-item:focus-visible { outline: 3px solid var(--cyan); outline-offset: 3px; }

@media (min-width: 560px) {
  .gallery-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); }
}
@media (min-width: 900px) {
  .gallery-grid { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 22px; }
}

.gallery-empty {
  text-align: center;
  padding: 40px 0;
  color: var(--text-dim);
}

/* ---------- "Pokaż pozostałe" / "Pokaż mniej" ----------
   Siatka startuje zwinięta (data-initial na .gallery-instance), żeby
   ~75 kafelków nie odsuwało sekcji #oferta o kilka ekranów w dół.
   Kafelki poza limitem mają display:none, więc ich obrazki lazy w ogóle
   się nie pobierają, dopóki użytkownik ich nie zażąda. */
.gallery-more-wrap {
  display: flex;
  justify-content: center;
  margin-top: 28px;
}

.gallery-more {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 48px;
  padding: 13px 30px;
  border-radius: var(--r-pill);
  border: 1px solid var(--border-strong);
  background: var(--surface);
  color: var(--text);
  font-size: 0.94rem;
  font-weight: 700;
  letter-spacing: -0.01em;
}

/* Bez tego atrybut hidden przegrywa z display:inline-flex powyżej
   (tak samo jak przy .gallery-item[hidden]). */
.gallery-more[hidden] { display: none; }

.gallery-more:hover { border-color: rgba(124, 92, 255, 0.55); color: #FFFFFF; }
.gallery-more:focus-visible { outline: 3px solid var(--cyan); outline-offset: 3px; }

@media (prefers-reduced-motion: no-preference) {
  .gallery-more { transition: color 0.2s var(--ease), border-color 0.2s var(--ease); }
}

/* ---------- Oferta ---------- */
.offer-wrap { display: flex; justify-content: center; }

.offer-card {
  position: relative;
  width: 100%;
  max-width: 620px;
  border-radius: var(--r-xl);
  padding: 1px;                                   /* miejsce na gradientową ramkę */
  background: linear-gradient(150deg, rgba(124, 92, 255, 0.75), rgba(34, 211, 238, 0.35) 45%, rgba(255, 255, 255, 0.08) 75%);
  box-shadow: var(--shadow-lg), 0 0 70px rgba(109, 74, 255, 0.18);
}

.offer-inner {
  border-radius: calc(var(--r-xl) - 1px);
  background:
    radial-gradient(90% 70% at 50% 0%, rgba(124, 92, 255, 0.16), transparent 65%),
    linear-gradient(180deg, #0F1729, #0A0F1C);
  padding: 40px 26px 36px;
  text-align: center;
}

.offer-badge {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 6px 14px;
  border-radius: var(--r-pill);
  background: rgba(255, 176, 32, 0.12);
  border: 1px solid rgba(255, 176, 32, 0.35);
  color: var(--amber);
  font-size: 0.78rem;
  font-weight: 700;
  letter-spacing: 0.01em;
  text-transform: uppercase;
}

.offer-price {
  font-size: clamp(3.4rem, 13vw, 5rem);
  font-weight: 800;
  letter-spacing: -0.05em;
  line-height: 1;
  margin: 18px 0 6px;
  color: var(--text);
}

.offer-price .cur { font-size: 0.42em; font-weight: 700; color: var(--text-muted); letter-spacing: -0.02em; }

.offer-note { font-size: 0.92rem; color: var(--text-dim); margin-bottom: 28px; }

.offer-list {
  text-align: left;
  max-width: 420px;
  margin: 0 auto 26px;
  display: grid;
  gap: 12px;
}

.offer-list li {
  position: relative;
  padding-left: 34px;
  color: var(--text);
  font-size: 0.98rem;
  font-weight: 500;
}

.offer-list li::before {
  content: "";
  position: absolute;
  left: 0;
  top: 2px;
  width: 22px;
  height: 22px;
  border-radius: 50%;
  background: rgba(124, 92, 255, 0.16);
  border: 1px solid rgba(124, 92, 255, 0.45);
}

.offer-list li::after {
  content: "";
  position: absolute;
  left: 7.5px;
  top: 8px;
  width: 6px;
  height: 10px;
  border: solid #C4B5FD;
  border-width: 0 2px 2px 0;
  transform: rotate(45deg);
}

.offer-meta {
  display: grid;
  gap: 10px;
  max-width: 460px;
  margin: 0 auto 26px;
  padding-top: 22px;
  border-top: 1px solid var(--border);
}

.offer-meta p { font-size: 0.92rem; }
.offer-meta strong { color: var(--text); font-weight: 700; }

/* ---------- FAQ (accordion) ---------- */
.faq-list {
  max-width: 780px;
  margin: 0 auto;
  display: grid;
  gap: 12px;
}

.faq-item {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
}

.faq-item[open] {
  background: var(--surface-2);
  border-color: var(--border-strong);
}

.faq-q {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 16px;
  padding: 19px 22px;
  cursor: pointer;
  list-style: none;
  font-weight: 700;
  font-size: 1.02rem;
  color: var(--text);
  letter-spacing: -0.02em;
  min-height: 44px;
}

.faq-q:hover { color: #C4B5FD; }
.faq-q:focus-visible { outline: 3px solid var(--cyan); outline-offset: -3px; }

.faq-icon {
  position: relative;
  flex: none;
  width: 26px;
  height: 26px;
  border-radius: 50%;
  border: 1px solid var(--border-strong);
  background: var(--surface-2);
}

.faq-icon::before,
.faq-icon::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 50%;
  width: 11px;
  height: 2px;
  border-radius: 2px;
  background: var(--text-muted);
  transform: translate(-50%, -50%);
}

.faq-icon::after { transform: translate(-50%, -50%) rotate(90deg); }

.faq-item[open] .faq-icon { background: var(--brand-soft); border-color: rgba(124, 92, 255, 0.5); }
.faq-item[open] .faq-icon::before,
.faq-item[open] .faq-icon::after { background: #C4B5FD; }
.faq-item[open] .faq-icon::after { transform: translate(-50%, -50%) rotate(0deg); }

.faq-a { padding: 0 22px 20px; }
.faq-a p { font-size: 0.97rem; max-width: 64ch; }

@media (prefers-reduced-motion: no-preference) {
  .faq-item { transition: background-color 0.25s var(--ease), border-color 0.25s var(--ease); }
  .faq-icon::after { transition: transform 0.3s var(--ease); }
  .faq-item[open] .faq-a { animation: faq-in 0.35s var(--ease); }
}

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

/* ---------- Kontakt ---------- */
.contact-panel {
  position: relative;
  overflow: hidden;
  border-radius: var(--r-xl);
  border: 1px solid var(--border-strong);
  background:
    radial-gradient(70% 120% at 20% 0%, rgba(124, 92, 255, 0.3), transparent 62%),
    radial-gradient(60% 110% at 88% 100%, rgba(34, 211, 238, 0.18), transparent 60%),
    linear-gradient(160deg, #141D33, #0A0F1C);
  padding: 52px 24px 48px;
  text-align: center;
  box-shadow: var(--shadow-lg);
}

.contact-panel h2 { margin-bottom: 14px; }
.contact-trust { max-width: 480px; margin: 0 auto 32px; }

.contact-links {
  display: grid;
  grid-template-columns: 1fr;
  gap: 12px;
  max-width: 520px;
  margin: 0 auto 30px;
}

.contact-link {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  min-height: 60px;
  padding: 16px 12px;
  border-radius: var(--r-md);
  border: 1px solid var(--border-strong);
  background: rgba(255, 255, 255, 0.05);
  backdrop-filter: blur(10px);
  -webkit-backdrop-filter: blur(10px);
  font-weight: 700;
  font-size: 1.02rem;
  color: var(--text);
  text-align: center;
  overflow-wrap: break-word;
}

.contact-link svg { color: #C4B5FD; flex: none; }
.contact-link:focus-visible { outline: 3px solid var(--cyan); outline-offset: 3px; }

@media (prefers-reduced-motion: no-preference) {
  .contact-link { transition: transform 0.25s var(--ease), background-color 0.25s var(--ease), border-color 0.25s var(--ease); }
  .contact-link:hover, .contact-link:focus-visible {
    transform: translateY(-3px);
    background: rgba(255, 255, 255, 0.09);
    border-color: rgba(124, 92, 255, 0.5);
  }
}

/* ---------- Footer ---------- */
.footer {
  border-top: 1px solid var(--border);
  padding: 56px 0 132px;   /* zapas na przyklejony pasek zamówienia na mobile */
  font-size: 0.9rem;
}

.footer .container {
  display: flex;
  flex-direction: column;
  gap: 34px;
}

/* Górna część: marka po lewej, trzy kolumny odnośników po prawej.
   Na wąskim ekranie wszystko układa się w jedną kolumnę. */
.footer-top {
  display: grid;
  grid-template-columns: 1fr;
  gap: 32px;
}

.footer-brand .brand { margin-bottom: 12px; }

.footer-tagline {
  color: var(--text-dim);
  max-width: 34ch;
  line-height: 1.6;
  margin: 0;
}

.footer-col {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 10px;
}

.footer-head {
  font-family: var(--font-display);
  font-size: 0.78rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--text-muted);
  margin: 0 0 2px;
}

.footer-col a {
  color: var(--text-dim);
  text-decoration: none;
  transition: color 0.16s var(--ease);
}

.footer-col a:hover { color: var(--text); }
.footer-col a:focus-visible { outline: 2px solid var(--cyan); outline-offset: 3px; }

/* Jedyny odnośnik w stopce, który ma zachęcać do działania. */
.footer-cta {
  margin-top: 4px;
  color: var(--cyan) !important;
  font-weight: 600;
}

/* Dolna część: dane rejestrowe wymagane ustawą, oddzielone cienką linią. */
.footer-bottom {
  display: flex;
  flex-direction: column;
  gap: 8px;
  padding-top: 24px;
  border-top: 1px solid var(--border);
  color: var(--text-dim);
  font-size: 0.82rem;
  line-height: 1.65;
}

.footer-bottom p { margin: 0; }
.footer-firma { max-width: 70ch; }
.footer-copy { opacity: 0.75; }

@media (min-width: 700px) {
  .footer-top { grid-template-columns: 1.5fr 1fr 1fr 1fr; gap: 40px; }
}

@media (min-width: 900px) {
  .footer-bottom {
    flex-direction: row;
    align-items: baseline;
    justify-content: space-between;
    gap: 24px;
  }
  .footer-copy { white-space: nowrap; }
}

/* ---------- Sticky CTA (mobile) ---------- */
.sticky-cta {
  position: fixed;
  left: 12px;
  right: 12px;
  bottom: 12px;
  z-index: 999;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 10px 10px 18px;
  border-radius: var(--r-pill);
  background: rgba(10, 15, 28, 0.94);
  border: 1px solid var(--border-strong);
  /* Blur zmniejszony z 18px do 8px i bez saturate(): drugi element fixed
     widoczny non-stop podczas scrolla na dole ekranu, na mobile (jedyne
     miejsce gdzie się pokazuje) to najsłabsze GPU. Wyższa nieprzezroczystość
     tła (0.9→0.94) rekompensuje słabszy frost. */
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  box-shadow: var(--shadow-lg);
  transform: translateY(140%);
}

.sticky-cta.is-visible { transform: none; }
.sticky-cta .btn { min-height: 44px; padding: 11px 20px; font-size: 0.94rem; }

.sticky-cta-price {
  /* Bez flex-grow blok kurczył się do szerokości najdłuższego słowa (56px przy
     366px paska) i cena łamała się na cztery wiersze mimo wolnego miejsca. */
  flex: 1 1 auto;
  min-width: 0;
  font-size: 0.86rem;
  font-weight: 700;
  color: var(--text);
  line-height: 1.25;
}


/* Pasek na dole ekranu ma szerokość telefonu, więc cena idzie w dwóch
   wierszach: kwota główna z okresem rozliczenia, druga kwota pod spodem. */
.sticky-cta-price .pv { align-items: baseline; column-gap: 0.25em; width: 100%; }
.sticky-cta-price .pv-tag,
.sticky-cta-price .pv-tag2 { font-size: 0.8em; font-weight: 600; }
.sticky-cta-price .pv-tag2 { color: var(--text-dim); }
.sticky-cta-price .pv-alt {
  flex-basis: 100%;
  font-size: 0.8em;
  font-weight: 500;
  margin-top: 1px;
  opacity: 0.75;
}

@media (prefers-reduced-motion: no-preference) {
  .sticky-cta { transition: transform 0.4s var(--ease); }
}

/* Od tabletu w górę pasek zwęża się do własnej szerokości i staje na środku,
   zamiast ciągnąć się przez cały ekran (na 834px robił się paskiem 810px —
   za ciężki jak na dyskretne przypomnienie oferty). Pozycjonowanie przez
   left/right + margin-inline, a NIE translateX, bo transform jest zajęty
   przez animację chowania paska. */
@media (min-width: 700px) {
  .sticky-cta {
    left: 0;
    right: 0;
    bottom: 20px;
    width: max-content;
    max-width: calc(100% - 32px);
    margin-inline: auto;
    padding: 10px 10px 10px 22px;
  }

  /* Na wąskim pasku telefonu cena łamie się na dwa wiersze. Tutaj miejsca
     nie brakuje, więc obie kwoty idą w jednej linii i pasek zostaje niski. */
  .sticky-cta-price { flex: 0 0 auto; font-size: 0.95rem; }
  .sticky-cta-price .pv { width: auto; flex-wrap: nowrap; column-gap: 0.25em; }
  .sticky-cta-price .pv-alt { flex-basis: auto; margin-top: 0; }
}

/* ---------- Lightbox ---------- */
.lightbox {
  position: fixed;
  inset: 0;
  z-index: 1100;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 18px;
  padding: 24px;
  background: rgba(4, 7, 14, 0.9);
  backdrop-filter: blur(14px);
  -webkit-backdrop-filter: blur(14px);
}

.lightbox[hidden] { display: none; }

.lightbox-img {
  max-width: min(100%, 980px);
  max-height: 74vh;
  border-radius: var(--r-md);
  border: 1px solid var(--border-strong);
  box-shadow: var(--shadow-lg);
}

.lightbox-caption { color: var(--text); font-weight: 700; text-align: center; font-size: 1.05rem; }

.lightbox-close {
  position: absolute;
  top: 18px;
  right: 18px;
  width: 46px;
  height: 46px;
  border-radius: 50%;
  background: var(--surface-3);
  border: 1px solid var(--border-strong);
  color: var(--text);
  font-size: 1.5rem;
  line-height: 1;
  display: flex;
  align-items: center;
  justify-content: center;
}

.lightbox-close:focus-visible { outline: 3px solid var(--cyan); outline-offset: 3px; }

@media (prefers-reduced-motion: no-preference) {
  .lightbox { animation: fade-in 0.25s var(--ease); }
  .lightbox-img { animation: pop-in 0.35s var(--ease); }
  .lightbox-close { transition: background-color 0.2s var(--ease), transform 0.2s var(--ease); }
  .lightbox-close:hover, .lightbox-close:focus-visible { background: rgba(255, 255, 255, 0.18); }
  .lightbox-close:active { transform: scale(0.95); }
}

@keyframes fade-in { from { opacity: 0; } to { opacity: 1; } }
@keyframes pop-in { from { opacity: 0; transform: scale(0.96); } to { opacity: 1; transform: none; } }

/* Dostępne ukrycie tekstu (dla czytników ekranu) */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Ten sam schowek pod nazwą używaną przez strony dokumentowe. */
.skip-link {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
  border: 0;
}

/* Skrót do treści musi stać się widoczny, gdy dostanie fokus z klawiatury —
   inaczej pierwszy przystanek tabulatora jest niewidzialny. */
.sr-only:focus,
.sr-only:focus-visible,
.skip-link:focus,
.skip-link:focus-visible {
  position: fixed;
  top: 10px; left: 10px;
  width: auto; height: auto;
  margin: 0; padding: 11px 18px;
  overflow: visible;
  clip: auto;
  background: var(--bg-2);
  color: var(--text);
  border: 1px solid var(--border-strong);
  border-radius: var(--r-sm);
  z-index: 1200;
}

/* Strony dokumentowe nie ładują main.js, więc pasek nawigacji nigdy nie
   dostaje klasy .is-stuck i zostaje przezroczysty — tekst przewijałby się
   pod nim. Tutaj tło jest bezwarunkowe. */
.doc-page .nav {
  background: rgba(7, 11, 20, 0.9);
  border-bottom: 1px solid var(--border);
}

.doc-body ul { list-style: disc; }

/* =========================================================
   Tablet ~700px
   ========================================================= */
@media (min-width: 700px) {
  .section { padding: 96px 0; }
  .steps { grid-template-columns: repeat(2, 1fr); }
  .hero-stats { grid-template-columns: repeat(3, minmax(0, 1fr)); }
  .contact-links { grid-template-columns: repeat(2, 1fr); }
  .offer-inner { padding: 48px 44px 42px; }
  .contact-panel { padding: 68px 44px 62px; }

  /* Placeholdery content-visibility dopasowane do layoutu, który wchodzi
     dokładnie w tym progu (patrz komentarz przy definicji bazowej).
     #galeria świadomie bez content-visibility — patrz komentarz tamże. */
  #faq     { contain-intrinsic-size: auto 895px; }
  #oferta  { contain-intrinsic-size: auto 930px; }
  #kontakt { contain-intrinsic-size: auto 470px; }
  .footer  { contain-intrinsic-size: auto 372px; }
}

/* =========================================================
   Desktop ~1000px
   ========================================================= */
@media (min-width: 1000px) {
  .nav-links { display: flex; }
  .nav-cta { display: inline-flex; }
  .hero { padding: calc(var(--nav-h) + 72px) 0 96px; }
  .hero-layout { grid-template-columns: 1.05fr 0.95fr; gap: 40px; }
  .steps { grid-template-columns: repeat(4, 1fr); }
  .footer { padding: 56px 0 40px; }

  #oferta  { contain-intrinsic-size: auto 945px; }
  #faq     { contain-intrinsic-size: auto 894px; }
  #kontakt { contain-intrinsic-size: auto 506px; }
  .footer  { contain-intrinsic-size: auto 340px; }
}



/* ---------- Strony dokumentowe (polityka, regulamin) ---------- */
.doc-body { max-width: 68ch; margin: 0 auto; color: var(--text-dim); line-height: 1.75; }
.doc-body h2 {
  font-family: var(--font-display);
  color: var(--text);
  font-size: 1.35rem;
  margin: 32px 0 12px;
}
.doc-body p { margin: 0 0 16px; }
.doc-body ul { margin: 0 0 16px; padding-left: 22px; }
.doc-body li { margin-bottom: 8px; }
/* Długie adresy (URL, e-mail) w dokumentach łamią się zamiast rozpychać
   stronę na 280-320 px. */
.doc-body p,
.doc-body li { overflow-wrap: anywhere; }
.doc-body strong { color: var(--text); }

/* Odstęp nad linkiem powrotnym. Jako klasa, nie atrybut style, żeby CSP
   mogła zostać przy twardym style-src 'self'. */
.doc-powrot { margin-top: 32px; }


/* ---------- Zakres usługi ---------- */
/* Dwie listy obok siebie: co wchodzi w cenę i co nie. Sekcja istnieje po to,
   żeby klient poznał granice usługi przed zamówieniem, więc czytelność jest
   ważniejsza od ozdób. */
.zakres-grid {
  display: grid;
  gap: 18px;
  grid-template-columns: 1fr;
  /* Listy mają różną długość — bez tego krótsza karta rozciągałaby się
     do wysokości dłuższej i kończyła pustym polem. */
  align-items: start;
}

.zakres-col {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-lg);
  padding: 26px 24px;
}

.zakres-col h3 {
  font-family: var(--font-display);
  font-size: 1.15rem;
  margin: 0 0 16px;
  display: flex;
  align-items: center;
  gap: 9px;
}

.zakres-col h3::before {
  content: "";
  width: 9px; height: 9px;
  border-radius: 50%;
  flex: 0 0 auto;
}

.zakres-tak h3::before { background: var(--cyan); }
.zakres-nie h3::before { background: var(--text-dim); }

.zakres-col ul { margin: 0; padding: 0; list-style: none; }

.zakres-col li {
  position: relative;
  padding: 0 0 0 26px;
  margin-bottom: 11px;
  color: var(--text-muted);
  line-height: 1.55;
}

.zakres-col li::before {
  position: absolute;
  left: 0; top: 0;
  font-weight: 700;
}

.zakres-tak li::before { content: "+"; color: var(--cyan); }
.zakres-nie li::before { content: "−"; color: var(--text-dim); }

.zakres-stopka {
  margin: 24px auto 0;
  max-width: 62ch;
  text-align: center;
  color: var(--text-muted);
}

/* ---------- Dane rejestrowe w stopce ---------- */




@media (min-width: 800px) {
  .zakres-grid { grid-template-columns: 1fr 1fr; gap: 22px; }
}


/* Tabela w dokumencie prawnym przewija się we własnym pudełku, żeby cała
   strona nie jechała w bok na wąskim ekranie. */
.doc-tabela { overflow-x: auto; margin: 0 0 20px; }

.doc-body table {
  border-collapse: collapse;
  width: 100%;
  min-width: 460px;
  font-size: 0.92rem;
}

.doc-body th,
.doc-body td {
  border: 1px solid var(--border);
  padding: 9px 12px;
  text-align: left;
  vertical-align: top;
}

.doc-body th { color: var(--text); font-weight: 600; background: var(--surface); }

.doc-body h3 {
  font-family: var(--font-display);
  color: var(--text);
  font-size: 1.08rem;
  margin: 24px 0 10px;
}

.doc-body ol { margin: 0 0 16px; padding-left: 22px; }
.doc-body ol li { margin-bottom: 8px; }
.doc-body a { color: var(--cyan); }


/* ---------- Spis treści dokumentu prawnego ---------- */
/* Regulamin ma 22 paragrafy i trzy załączniki, więc bez spisu nie da się
   po nim poruszać. Dwie kolumny na szerszym ekranie, żeby nie wypychał
   właściwej treści poza pierwszy ekran. */
.doc-toc {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  padding: 22px 24px;
  margin: 0 0 34px;
}

.doc-toc h2 {
  font-family: var(--font-display);
  font-size: 1.05rem;
  color: var(--text);
  margin: 0 0 14px;
}

.doc-toc ol,
.doc-toc ul {
  margin: 0;
  padding: 0;
  list-style: none;
  columns: 1;
}

.doc-toc li { margin-bottom: 7px; break-inside: avoid; }

.doc-toc a {
  color: var(--text-muted);
  text-decoration: none;
  font-size: 0.92rem;
}

.doc-toc a:hover,
.doc-toc a:focus-visible { color: var(--cyan); text-decoration: underline; }

/* Nagłówek paragrafu nie może chować się pod przyklejonym paskiem nawigacji
   po skoku z odnośnika. */
.doc-body h2[id],
.doc-body section[id] { scroll-margin-top: 92px; }

@media (min-width: 760px) {
  .doc-toc ol,
  .doc-toc ul { columns: 2; column-gap: 30px; }
}


/* ---------- Cena z przełącznikiem netto/brutto ---------- */
/* Obie kwoty są zawsze w dokumencie. Przełącznik decyduje wyłącznie o tym,
   która jest główna, a która pomocnicza — dzięki temu kwota brutto nigdy nie
   jest schowana za kliknięciem (wymóg ustawy o informowaniu o cenach) i strona
   pozostaje poprawna przy wyłączonym JavaScripcie. */
.pv {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  column-gap: 0.08em;
  line-height: 1.05;
}

/* Kwota, waluta i słowo netto stoją w jednym wierszu, druga kwota schodzi
   pod spód. Sam flex-direction: column rozbijał "500 zł netto" na trzy linie. */
.pv-alt { flex-basis: 100%; }

.pv-tag {
  font-size: 0.42em;
  font-weight: 600;
  opacity: 0.7;
  letter-spacing: 0.02em;
}

.pv-alt {
  font-size: 0.34em;
  font-weight: 500;
  opacity: 0.6;
  margin-top: 0.35em;
  letter-spacing: 0.01em;
}

.pv-inline { flex-wrap: nowrap; gap: 0.4em; }
.pv-inline .pv-alt { flex-basis: auto; margin-top: 0; font-size: 0.72em; }
.pv-sm .pv-alt { font-size: 0.4em; }

/* Makieta laptopa to grafika dekoracyjna, nie prezentacja oferty. */
.pv-hide-alt .pv-alt { display: none; }

.vat-switch {
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin-top: 16px;
}

.vat-switch-end {
  display: flex;
  justify-content: center;
  width: 100%;
  margin-top: 18px;
}

.vat-switch-label {
  font-size: 0.86rem;
  font-weight: 600;
  color: var(--text-muted);
}

.vat-toggle {
  position: relative;
  width: 46px;
  height: 26px;
  flex: 0 0 46px;
  padding: 0;
  appearance: none;
  border: 1px solid var(--border-strong);
  border-radius: var(--r-pill);
  background: var(--surface-2);
  cursor: pointer;
  transition: background 0.18s var(--ease), border-color 0.18s var(--ease);
}

/* Sam przełącznik ma 46x26px — ładnie wygląda, ale to o wiele za mało
   na palec. Niewidoczna nakładka powiększa OBSZAR DOTYKU do 44px w pionie,
   nie ruszając wyglądu ani układu (position:absolute nie zajmuje miejsca). */
.vat-toggle::before {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 50%;
  min-height: 44px;
  height: 100%;
  transform: translateY(-50%);
}

.vat-toggle .vat-knob {
  position: absolute;
  top: 2px;
  left: 2px;
  width: 20px;
  height: 20px;
  border-radius: 50%;
  background: var(--text-muted);
  transition: transform 0.18s var(--ease), background 0.18s var(--ease);
}

.vat-toggle.is-on { background: var(--brand-btn-a); border-color: var(--brand-btn-a); }
.vat-toggle.is-on .vat-knob { transform: translateX(20px); background: #fff; }
.vat-toggle:focus-visible { outline: 2px solid var(--cyan); outline-offset: 3px; }

.vat-hint {
  font-size: 0.8rem;
  color: var(--text-dim);
  margin-top: 9px;
}

@media (prefers-reduced-motion: reduce) {
  .vat-toggle,
  .vat-toggle .vat-knob { transition: none; }
}

/* =========================================================
   Formularz zapytania + baner zgody na pomiar (ChatGPT Ads, 2026-09-28)
   Mobile-first od 320 px. Bez inline style (CSP style-src 'self').
   ========================================================= */
.lead-form {
  max-width: 640px;
  margin: 0 auto 28px;
  text-align: left;
}

.lead-form-title {
  font-family: var(--font-display);
  font-size: 1.2rem;
  margin: 0 0 16px;
  text-align: center;
}

.lead-form-grid {
  display: grid;
  grid-template-columns: 1fr;
  gap: 14px;
}

.lead-field { display: flex; flex-direction: column; gap: 6px; min-width: 0; }

.lead-field label { font-weight: 700; font-size: 0.95rem; color: var(--text); }
.lead-req, .lead-opt { font-weight: 500; color: var(--text-muted); }

.lead-field input,
.lead-field textarea {
  width: 100%;
  min-width: 0;
  min-height: 48px;
  padding: 12px 14px;
  border-radius: var(--r-sm);
  border: 1px solid var(--border-strong);
  background: rgba(255, 255, 255, 0.06);
  color: var(--text);
  font: inherit;
  font-size: 1rem;              /* >= 16 px: iOS nie powiększa widoku przy fokusie */
  line-height: 1.5;
}

.lead-field textarea { min-height: 112px; resize: vertical; }
.lead-field input::placeholder,
.lead-field textarea::placeholder { color: var(--text-muted); opacity: 1; }

.lead-field input:focus-visible,
.lead-field textarea:focus-visible {
  outline: 3px solid var(--cyan);
  outline-offset: 2px;
  border-color: transparent;
}

/* Pole-pułapka na boty: niewidoczne dla ludzi, poza kolejnością tabulacji. */
.lead-hp {
  position: absolute;
  left: -10000px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.lead-form-info {
  margin: 16px 0 18px;
  font-size: 0.85rem;
  line-height: 1.6;
  color: var(--text-muted);
  overflow-wrap: anywhere;
}

.lead-form-info a,
.consent-text a { color: var(--text); text-decoration: underline; text-underline-offset: 2px; }
.lead-form-info a:focus-visible,
.consent-text a:focus-visible { outline: 2px solid var(--cyan); outline-offset: 2px; }

.lead-submit { width: 100%; }

.contact-alt {
  margin: 0 0 12px;
  color: var(--text-muted);
  font-size: 0.95rem;
}

@media (min-width: 640px) {
  .lead-form-grid { grid-template-columns: 1fr 1fr; }
  .lead-field-full { grid-column: 1 / -1; }
  .lead-submit { width: auto; }
}

/* ---------- Baner prywatności (pokazywany przez oaiq-init.js) ----------
   Pływająca karta z odstępem od krawędzi ekranu (także w strefach bezpiecznych
   telefonu). Maks. 45% wysokości ekranu: dłuższy tekst przewija się wewnątrz
   karty, a przyciski zostają zawsze widoczne. Mobile-first: na <= 360 px
   przyciski jeden pod drugim na pełną szerokość, szerzej obok siebie, równe. */
.consent {
  position: fixed;
  left: max(12px, env(safe-area-inset-left));
  right: max(12px, env(safe-area-inset-right));
  bottom: max(12px, env(safe-area-inset-bottom));
  z-index: 1100;                /* nad sticky CTA (999) i nawigacją (1000) */
  max-width: 760px;
  max-height: 45vh;
  max-height: 45dvh;
  margin: 0 auto;
  padding: 16px;
  border-radius: var(--r-md);
  border: 1px solid var(--border-strong);
  background: rgba(14, 21, 38, 0.98);
  box-shadow: 0 18px 50px rgba(0, 0, 0, 0.6), 0 2px 8px rgba(0, 0, 0, 0.4);
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.consent[hidden],
.footer-privacy[hidden] { display: none; }

/* Wejście przez przenikanie (od opacity 0). Poza efektem wizualnym ma to
   znaczenie dla wydajności: element namalowany z opacity 0 nie jest brany
   jako LCP, więc elementem LCP zostaje nagłówek strony, a nie tekst banera
   (bez tego Lighthouse: LCP 2,1 s -> 2,4 s). Przy ograniczonym ruchu
   przenikanie jest natychmiastowe. */
@keyframes consent-in { from { opacity: 0; } to { opacity: 1; } }
.consent { animation: consent-in 0.3s ease-out both; }
@media (prefers-reduced-motion: reduce) {
  .consent { animation-duration: 1ms; }
}

.consent-body {
  min-height: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
}

.consent-title {
  margin: 0 0 6px;
  font-family: var(--font-display);
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1.3;
  color: var(--text);
  text-align: left;
}

.consent-text {
  margin: 0;
  font-size: 0.9375rem;         /* 15 px: czytelne na telefonie */
  line-height: 1.5;
  color: var(--text-muted);
}

.consent-actions {
  flex: none;
  display: grid;
  grid-template-columns: 1fr;
  gap: 8px;
}

.consent-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 0;
  min-height: 48px;
  padding: 10px 8px;
  border-radius: var(--r-pill);
  font-family: inherit;
  font-size: 0.9375rem;
  font-weight: 700;
  line-height: 1.2;
  white-space: nowrap;
  cursor: pointer;
}

/* Główny: pełny kolor marki. Drugorzędny: wyraźne obramowanie, ten sam rozmiar. */
.consent-btn-primary {
  border: 2px solid transparent;
  background-image: linear-gradient(135deg, var(--brand-btn-a), var(--brand-btn-b));
  color: #FFFFFF;
}

.consent-btn-secondary {
  border: 2px solid rgba(238, 242, 249, 0.6);
  background: transparent;
  color: var(--text);
}

.consent-btn-primary:hover { box-shadow: var(--glow-brand); }
.consent-btn-secondary:hover { border-color: var(--text); background: var(--surface-2); }
.consent-btn:focus-visible { outline: 3px solid var(--cyan); outline-offset: 2px; }

@media (min-width: 361px) {
  .consent-actions { grid-template-columns: 1fr 1fr; }
}

/* Gdy baner stoi przy dolnej krawędzi, sticky CTA jedzie nad nim, a dół strony
   dostaje zapas, żeby stopka nie chowała się pod kartą. --consent-lift ustawia
   oaiq-init.js (odległość górnej krawędzi banera od dołu ekranu + 8 px). */
body.consent-bottom { padding-bottom: var(--consent-lift, 0px); }
body.consent-bottom .sticky-cta { bottom: var(--consent-lift, 12px); }
body.consent-bottom .sticky-cta:not(.is-visible) {
  transform: translateY(calc(100% + var(--consent-lift, 0px) + 24px));
}

.breakable { overflow-wrap: anywhere; }

.footer-privacy {
  padding: 0;
  min-height: 44px;
  color: var(--text-dim);
  text-align: left;
  text-decoration: underline;
  text-underline-offset: 2px;
}

.footer-privacy:hover { color: var(--text); }
.footer-privacy:focus-visible { outline: 2px solid var(--cyan); outline-offset: 3px; }

.dzieki-kroki { list-style: decimal; }

/* Tablet: tekst na całą szerokość karty, przyciski w rzędzie po prawej. */
@media (min-width: 700px) {
  .consent { padding: 18px 20px; }
  .consent-actions { grid-template-columns: repeat(2, minmax(170px, auto)); justify-content: end; }
  .consent-btn { padding: 10px 24px; }
}

/* Desktop: szersza karta, tekst i przyciski obok siebie (2-3 wiersze tekstu). */
@media (min-width: 1024px) {
  .consent { max-width: 1120px; flex-direction: row; align-items: center; gap: 28px; }
  .consent-body { flex: 1 1 auto; }
}

/* =========================================================
   Poprawki UI/UX 2026-09-28 (przegląd 280-1920 px)
   ========================================================= */

/* Kontakt: numer i e-mail zawsze w jednej linii, obie karty identyczne.
   Łamanie e-maila dopuszczalne tylko na <= 360 px i wyłącznie po „@” (<wbr>). */
.contact-links { max-width: 620px; align-items: stretch; grid-auto-rows: 1fr; }
.contact-link-text {
  display: block;
  white-space: nowrap;
  overflow-wrap: normal;
  hyphens: manual;
  line-height: 1.3;
  font-size: clamp(0.95rem, 0.9rem + 0.25vw, 1.02rem);
}
@media (max-width: 360px) {
  .contact-email { white-space: normal; }
}
.contact-panel .eyebrow { margin-bottom: 18px; }
/* Ikony obu kart na tej samej wysokości także wtedy, gdy e-mail zajmuje 2 wiersze. */
.contact-link { justify-content: flex-start; }

/* Sieroty: ostatnie słowo akapitu nie zostaje samo w wierszu. */
.offer-note,
.step-desc,
.offer-list li,
.contact-alt { text-wrap: pretty; }
.lead-form-title { text-wrap: balance; }

/* Stopka: cele dotyku min. 44 px (STANDARD-WWW 1). */
.footer-col { gap: 0; }
.footer-col .footer-head { margin-bottom: 4px; }
.footer-col a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
}

/* Hero na wąskich ekranach: oba przyciski tej samej szerokości. */
@media (max-width: 399px) {
  .hero-actions .btn { flex: 1 1 100%; }
}

/* Galeria: pierwsza pigułka filtra nie przykleja się do krawędzi ekranu,
   a długie nazwy branż łamią się zamiast wychodzić poza kafelek. */
.gallery-label, .gallery-cat { overflow-wrap: anywhere; hyphens: auto; }

/* Formularz: przycisk wysyłki wyśrodkowany jak nagłówek formularza. */
@media (min-width: 640px) {
  .lead-submit { display: flex; margin-inline: auto; }
}

/* Dokumenty: linki w tekście podkreślone, nie tylko kolorem (WCAG 1.4.1). */
.doc-body p a,
.doc-body li a,
.doc-body td a { text-decoration: underline; text-underline-offset: 2px; }

/* Baner v3 (28.09, CEO: baner nie może zasłaniać CTA z hero). Na telefonach
   kompaktowo: 14 px, mniejsze odstępy, przyciski zawsze obok siebie po 50%.
   Gdy przy dolnej krawędzi zasłoniłby „Zleć darmowy projekt” na pierwszym
   ekranie, oaiq-init.js przenosi go pod nawigację (klasa consent-top). */
@media (max-width: 480px) {
  .consent { padding: 12px; gap: 10px; }
  .consent-text { font-size: 0.875rem; line-height: 1.45; }
  .consent-actions { grid-template-columns: 1fr 1fr; }
  .consent-btn { min-height: 44px; padding: 8px 4px; font-size: 0.875rem; }
}
.consent.consent-top {
  top: calc(var(--nav-h) + 8px);
  bottom: auto;
}
@media (max-width: 300px) {
  .consent-actions { grid-template-columns: 1fr; }
}

/* ---------- Wykonane strony (#realizacje) - 2026-09-29, wersja 3 ----------
   Karta = miniatura + nazwa domeny, cała karta jest linkiem. 11 stron:
   1 kolumna do 559 px; od 560 px pierwsza karta (wyróżniona) zajmuje
   2 kolumny, więc przy 2 i 3 kolumnach wypełnia się dokładnie 12 pól
   i ostatni rząd jest zawsze pełny. Przy 3 kolumnach obraz wyróżnionej
   karty rozciąga się do wysokości sąsiedniej karty (bez pustych pól).
   Sekcja ma obrazki, więc NIE dostaje content-visibility (patrz wyżej). */
.realizacje-lista {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 18px;
}
.realizacja { display: flex; min-width: 0; }
.realizacja-link {
  display: flex;
  flex-direction: column;
  width: 100%;
  min-width: 0;
  background: var(--bg-2);
  border: 1px solid var(--border);
  border-radius: var(--r-md);
  overflow: hidden;
  color: inherit;
  text-decoration: none;
  box-shadow: var(--shadow-sm);
}
.realizacja-link:focus-visible { outline: 3px solid var(--cyan); outline-offset: 3px; }
.realizacja-img {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 16 / 10;
  object-fit: cover;
  object-position: top center;
  border-bottom: 1px solid var(--border);
  background: #E9EDF3;
}
.realizacja-nazwa {
  display: block;
  padding: 12px 16px 14px;
  font-family: var(--font-display);
  font-size: 1rem;
  font-weight: 700;
  color: var(--text);
  overflow-wrap: anywhere;
}
@media (prefers-reduced-motion: no-preference) {
  .realizacja-link { transition: transform 0.25s var(--ease), box-shadow 0.25s var(--ease), border-color 0.25s var(--ease); }
  .realizacja-img { transition: transform 0.4s var(--ease); }
  .realizacja-link:hover, .realizacja-link:focus-visible { transform: translateY(-3px); box-shadow: var(--shadow-md); border-color: rgba(124, 92, 255, 0.45); }
}
@media (min-width: 560px) {
  .realizacje-lista { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .realizacja--wyrozniona { grid-column: span 2; }
}
@media (min-width: 900px) {
  .realizacje-lista { grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 22px; }
  .realizacja--wyrozniona .realizacja-img {
    flex: 1 1 0;
    min-height: 0;
    height: 0;
    aspect-ratio: auto;
  }
}

/* Dane usługodawcy w stopce (pełna nazwa prawna, NIP, REGON). */
.footer-bottom .footer-firma {
  text-align: left;
  hyphens: auto;
  -webkit-hyphens: auto;
  overflow-wrap: anywhere;
}

/* Sticky CTA chowa się, dopóki widoczny jest baner prywatności (2026-09-29).
   Wcześniej był podnoszony nad baner i na desktopie wisiał na środku ekranu
   nad treścią. Pojawia się sam po decyzji w banerze. */
body.consent-open .sticky-cta { display: none; }
