/*! PageForYou site-runtime.css — audyt 30.09.2026 (S1). Wspólny CSS 12 szablonów (enhancery: scroll-progress,
 *  active-nav, ripple, back-to-top, gradient hero, testimonial progress, team initials, card tilt, gallery masonry/filters,
 *  lightbox caption, hero-anim orb). Wyodrębniony przez scripts/extract-runtime.cjs; <link> stoi w miejscu dawnego </style>,
 *  więc kaskada jest taka sama. Zmienne CSS (--color-*, --heading-color…) definiuje szablon. */
/* ── Rytm sekcji na telefonie (21.10.2026, Piotr: „puste przestrzenie między sekcjami”, zrzut: 192 px między „O nas” a „Galerią”) ──
   Odstęp sekcji z komputera (py-20 = 80 px, py-24 = 96 px) sumował się na styku dwóch sekcji do 160–221 px pustki na ekranie 390 px.
   Na telefonie 56 / 64 px (styk 112–128 px); od 640 px bez zmian (sm:py-28). Tylko sekcje z odstępem Tailwinda, bez pierwszego ekranu. */
@media (max-width:639.98px){
  main>section[data-section]:not([data-section="hero"]).py-20{padding-top:3.5rem;padding-bottom:3.5rem}
  main>section[data-section]:not([data-section="hero"]).py-24{padding-top:4rem;padding-bottom:4rem}
  /* 23.10.2026 (visual-qa: 161–190 px między sekcjami na 320–430 px — 2 dni po zgłoszeniu Piotra): reguła wyżej brała tylko klasy
     Tailwinda na korzeniu. + układy z odstępem w CSS wariantu (ta sama lista co niski ekran niżej: aside 4/6rem, offset 5/6rem,
     sequence 96 px…) i odstęp na WEWNĘTRZNYM bloku sekcji (tailblocks: div.pt-20 = 80 px) */
  main>section[data-section]:not([data-section="hero"]):is([data-variant="aside"],[data-variant="offset"],[data-variant="frames"],[data-variant="sequence"],[data-variant="folio"],[data-variant="reel"],[data-variant="spread"],[data-variant="edge-note"]){padding-top:3.5rem;padding-bottom:3.5rem}
  main>section[data-section]:not([data-section="hero"])>div:is(.py-20,.py-24,.pt-20,.pt-24){padding-top:3.5rem}
  main>section[data-section]:not([data-section="hero"])>div:is(.py-20,.py-24,.pb-20,.pb-24){padding-bottom:3.5rem}
}
/* ── Scroll progress bar ── */
#scroll-progress{position:fixed;top:0;left:0;height:3px;background:linear-gradient(90deg,var(--color-primary),var(--color-accent));z-index:9999;width:100%;transform:scaleX(0);transform-origin:0 0;transition:none;pointer-events:none}
/* ── Active nav link ── */
#nav-links a.nav-active,#mobile-menu a.nav-active{color:var(--heading-color)}
#nav-links a.nav-active{box-shadow:inset 0 -2px 0 var(--color-primary)}
/* ── Ripple effect ── */
.btn-primary{position:relative;overflow:hidden}
.ripple-effect{position:absolute;border-radius:50%;background:rgba(255,255,255,.35);transform:scale(0);animation:ripple-anim .6s ease-out;pointer-events:none}
@keyframes ripple-anim{to{transform:scale(4);opacity:0}}
/* ── Back to top ── */
#back-to-top{position:fixed;bottom:24px;right:24px;z-index:90;width:44px;height:44px;border-radius:50%;background:var(--color-primary);color:var(--btn-text,#111);border:none;cursor:pointer;display:flex;align-items:center;justify-content:center;opacity:0;transform:translateY(20px);transition:opacity .3s,transform .3s;pointer-events:none;box-shadow:0 4px 16px rgba(0,0,0,.3)}
#back-to-top.visible{opacity:1;transform:translateY(0);pointer-events:auto}
/* 21.10.2026 (zrzut Piotra: przycisk „na górę” zasłaniał „Dostępność”): pod ostatnim blokiem stopki miejsce na przycisk (44 px + 24 px
   od dołu) — przewinięta do końca strona kończy się nad przyciskiem w każdym wariancie stopki; tło bloku zostaje to samo */
body:has(#back-to-top) footer>:nth-last-child(1 of :not(script,style,template)){padding-bottom:max(5rem,calc(4.5rem + env(safe-area-inset-bottom)))}
#back-to-top:hover{transform:translateY(-3px);box-shadow:0 8px 24px rgba(0,0,0,.4)}
/* ── Gradient text on hero title ── */
.hero-gradient-text{background:linear-gradient(135deg,var(--heading-color) 0%,var(--primary-text,var(--color-primary)) 50%,var(--accent-text,var(--color-accent)) 100%);-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text}
/* ── Testimonial progress ── */
.testimonial-progress{height:2px;background:color-mix(in srgb,var(--color-primary) 20%,transparent);border-radius:2px;overflow:hidden;margin-top:16px}
.testimonial-progress-bar{height:100%;background:var(--color-primary);width:100%;transform:scaleX(0);transform-origin:left center;border-radius:2px}
.testimonial-progress-bar.animating{animation:testim-progress 5s linear forwards}
@keyframes testim-progress{from{transform:scaleX(0)}to{transform:scaleX(1)}}
/* ── Team initials avatar ── */
.team-initials{width:80px;height:80px;border-radius:50%;display:flex;align-items:center;justify-content:center;font-family:var(--font-display,inherit);font-weight:700;font-size:1.5rem;color:var(--heading-color);background:linear-gradient(135deg,color-mix(in srgb,var(--color-primary) 25%,transparent),color-mix(in srgb,var(--color-accent) 20%,transparent));border:2px solid color-mix(in srgb,var(--color-primary) 30%,transparent);margin:0 auto 16px}
/* ── Enhanced card hover (3D tilt) ── */
.card-tilt{transition:transform .4s ease,box-shadow .4s ease}
.card-tilt:hover{box-shadow:0 24px 48px var(--shadow-card)}
/* ── Number highlight in stats ── */
/* przegląd 2.10.2026 (noc): gradient tylko w hero (skill §3) — cyfry statystyk jednolitym kolorem marki bezpiecznym jako tekst */
:where(.counter-value){color:var(--primary-text,var(--color-primary))} /* :where — warianty (pas liczb na zdjęciu) ustawiają własny kolor */
/* ── Gallery filter tabs ── */
.gallery-filters{display:flex;flex-wrap:wrap;justify-content:center;gap:8px;margin-bottom:24px}
.gallery-filter-btn{padding:6px 16px;border-radius:9999px;font-size:.75rem;font-weight:600;border:1px solid var(--card-border);background:transparent;color:var(--text-muted);cursor:pointer;transition:all .3s}
.gallery-filter-btn:hover,.gallery-filter-btn.active{background:var(--color-primary);color:var(--btn-text,#111);border-color:var(--color-primary)}
.gallery-card.filtering-out{opacity:0;transform:scale(.8);pointer-events:none;position:absolute}
.gallery-card{transition:transform .4s ease,box-shadow .4s ease,opacity .4s ease}
/* ── Smooth section divider ── */
.section-divider{height:1px;background:linear-gradient(90deg,transparent,var(--card-border),transparent);margin:0 auto;max-width:80%}
/* ── Contact click links ── */
.contact-link{transition:color .3s}
.contact-link:hover{color:var(--primary-text,var(--color-primary))}
@media(prefers-reduced-motion:reduce){.ripple-effect,.testimonial-progress-bar.animating,#scroll-progress{animation:none;transition:none}#back-to-top{transition:none}}

/* ── Masonry gallery layout ── */
@media(min-width:640px){.gallery-masonry{column-count:2;column-gap:20px}}
@media(min-width:1024px){.gallery-masonry{column-count:3;column-gap:24px}}
.gallery-masonry .gallery-card{break-inside:avoid;margin-bottom:20px;display:inline-block;width:100%}
.gallery-masonry .gallery-card .aspect-\[4\/3\]{aspect-ratio:auto}
/* ── Lightbox caption ── */
.lb-caption{position:absolute;bottom:60px;left:50%;transform:translateX(-50%);max-width:80vw;text-align:center;color:rgba(255,255,255,.8);font-size:.85rem;line-height:1.5;padding:8px 20px;background:rgba(0,0,0,.5);border-radius:8px;opacity:0;transition:opacity .3s}
.lightbox.open .lb-caption{opacity:1}
/* ── Gallery card image number ── */
.gallery-number{position:absolute;top:12px;right:12px;width:28px;height:28px;border-radius:50%;background:rgba(0,0,0,.5);color:rgba(255,255,255,.7);font-size:.65rem;font-weight:600;display:flex;align-items:center;justify-content:center;z-index:3;opacity:0;transition:opacity .3s}
.gallery-card:hover .gallery-number{opacity:1}

/* ── Hero animation orb ─────────────────────────────────────── */
.hero-anim-orb{position:absolute;border-radius:50%;overflow:hidden;z-index:15;box-shadow:0 8px 32px rgba(0,0,0,.18)}
.hero-anim-orb video{width:100%;height:100%;object-fit:cover;filter:grayscale(.65) contrast(1.1)}
.hero-anim-orb::after{content:'';position:absolute;inset:0;background:var(--color-primary);mix-blend-mode:multiply;opacity:.55;border-radius:50%;pointer-events:none}
.hero-anim-float{position:absolute;border-radius:50%;overflow:hidden;z-index:5;box-shadow:0 4px 24px rgba(0,0,0,.15);animation:anim-float 6s ease-in-out infinite}
.hero-anim-float video{width:100%;height:100%;object-fit:cover;filter:grayscale(.7) contrast(1.1)}
.hero-anim-float::after{content:'';position:absolute;inset:0;background:var(--color-primary);mix-blend-mode:multiply;opacity:.5;border-radius:50%;pointer-events:none}
@keyframes anim-float{0%,100%{transform:translateY(0) scale(1)}50%{transform:translateY(-8px) scale(1.02)}}

/* ── Tokenowe klasy kolorów (2.10.2026, dług INFO walidatora L2) ──
 *  Warianty sprzed S2b miały klasy palety Tailwind (text-white, text-gray-400, bg-white/5…), które _base/tw-remap,
 *  _base/modern i custom.css szablonów przemapowywały na tokeny. Teraz warianty używają tych klas wprost — jedno źródło
 *  znaczenia. Specyficzność „body .x” = jak w tw-remap (wygląd bez zmian).
 *  Biel i czerń na zdjęciach i pasach w kolorze marki: tokeny KANAŁÓW --on-media-rgb / --scrim-rgb (domyślne niżej, szablon
 *  może nadpisać w template.json); kolor = rgb(var(--on-media-rgb) / .8). Celowo rgb(), nie color-mix(): gradient z kolorem
 *  spoza składni legacy jest interpolowany w oklab (inny przebieg niż dawne rgba() — widoczne pasy na overlayach hero). */
:where(:root){--on-media-rgb:255 255 255;--scrim-rgb:0 0 0}
body .tk-heading{color:var(--heading-color)}
body .tk-muted{color:var(--text-muted)}
body .hover\:tk-heading:hover{color:var(--heading-color)}
body .tk-bg-card{background-color:var(--card-bg)}
body .tk-bg-heading{background-color:var(--heading-color)}
.tk-on-media{color:rgb(var(--on-media-rgb))}
.tk-on-media-60{color:rgb(var(--on-media-rgb) / .6)}
.tk-on-media-80{color:rgb(var(--on-media-rgb) / .8)}
.tk-on-media-90{color:rgb(var(--on-media-rgb) / .9)}
.tk-scrim{color:rgb(var(--scrim-rgb))}
.tk-bg-on-media{background-color:rgb(var(--on-media-rgb))}
.tk-bg-on-media-5{background-color:rgb(var(--on-media-rgb) / .05)}
.hover\:tk-bg-on-media-5:hover{background-color:rgb(var(--on-media-rgb) / .05)}
.hover\:tk-bg-on-media-10:hover{background-color:rgb(var(--on-media-rgb) / .1)}
.hover\:tk-bg-on-media-90:hover{background-color:rgb(var(--on-media-rgb) / .9)}
.tk-border-on-media-10{border-color:rgb(var(--on-media-rgb) / .1)}
.tk-border-on-media-30{border-color:rgb(var(--on-media-rgb) / .3)}
.tk-border-on-media-40{border-color:rgb(var(--on-media-rgb) / .4)}
.hover\:tk-border-on-media:hover{border-color:rgb(var(--on-media-rgb))}
.tk-from-scrim-60{--tw-gradient-from:rgb(var(--scrim-rgb) / .6) var(--tw-gradient-from-position);--tw-gradient-to:transparent var(--tw-gradient-to-position);--tw-gradient-stops:var(--tw-gradient-from),var(--tw-gradient-to)}
.tk-placeholder-muted::placeholder{color:var(--text-muted)}
.focus\:tk-bg-on-media:focus{background-color:rgb(var(--on-media-rgb))}
.focus\:tk-scrim:focus{color:rgb(var(--scrim-rgb))}
/* hover/focus wariantów sprzed S2b (dawniej inline onmouseenter/onfocus ustawiające style) — !important jak inline style */
.tk-hover-border-primary:hover,.tk-focus-border-primary:focus{border-color:var(--color-primary)!important}
.tk-hover-lift:hover{transform:translateY(-4px)!important}

/* ── Przegląd wizualny 2.10.2026 (noc) — kontrast i spójność (src/services/template-builder/merge-contrast.ts) ── */
/* Akcent jako tekst: --accent-text liczy silnik (≥ 4.5:1 dla schematu i motywu); tu tylko zapas dla starych dokumentów */
:where(:root){--accent-text:color-mix(in srgb,var(--color-accent) 55%,var(--heading-color))}
.tk-accent{color:var(--accent-text)}
/* Przycisk główny: jeden kolor tekstu na stronie (--btn-text, strażnik kontrastu) — bez wpływu klas wariantu
   (tk-heading, nav-active, text-white), które dawały ciemny tekst na kolorze marki w jednym miejscu i biały w innym */
body .btn-primary,body .btn-primary:hover,#nav-links a.btn-primary.nav-active{color:var(--btn-text,#fff)!important;-webkit-text-fill-color:currentColor}
#nav-links a.btn-primary.nav-active{box-shadow:none}
/* Tytuł hero na zdjęciu (tk-on-media): jednolity kolor zamiast gradientu z --heading-color (ginie na kadrze w jasnym motywie) */
.hero-gradient-text.tk-on-media{background:none;-webkit-text-fill-color:currentColor}
/* Nawigacja nad pełnoekranowym zdjęciem hero (hero/fullscreen-media): tło z tokenu od pierwszego malowania, jak w mm-hero */
body:has(#hero[data-hero-fullbleed]) #navbar{background:var(--nav-bg);-webkit-backdrop-filter:saturate(1.4) blur(12px);backdrop-filter:saturate(1.4) blur(12px);box-shadow:0 1px 0 var(--card-border)}
/* Przycisk na dole karty (cennik: karty o różnej liczbie punktów — przyciski w jednej linii); karta = flex-col */
.pfy-push-end{margin-top:auto}
/* Siatki kart wg liczby kart (merge-quality.ts finalizeGrids): silnik zastępuje klasy grid-cols-* wariantu kompletem
   pfy-cN dla wszystkich progów (bez konfliktu z Tailwind), a gdy liczba kart nie dzieli się bez sieroty — ostatnia karta
   na całą szerokość rzędu (pfy-last-full) */
.pfy-c1{grid-template-columns:repeat(1,minmax(0,1fr))}.pfy-c2{grid-template-columns:repeat(2,minmax(0,1fr))}.pfy-c3{grid-template-columns:repeat(3,minmax(0,1fr))}.pfy-c4{grid-template-columns:repeat(4,minmax(0,1fr))}.pfy-last-full>:last-child{grid-column:1/-1}.pfy-last-auto>:last-child{grid-column:auto}
@media(min-width:640px){.sm\:pfy-c1{grid-template-columns:repeat(1,minmax(0,1fr))}.sm\:pfy-c2{grid-template-columns:repeat(2,minmax(0,1fr))}.sm\:pfy-c3{grid-template-columns:repeat(3,minmax(0,1fr))}.sm\:pfy-c4{grid-template-columns:repeat(4,minmax(0,1fr))}.sm\:pfy-last-full>:last-child{grid-column:1/-1}.sm\:pfy-last-auto>:last-child{grid-column:auto}}
@media(min-width:768px){.md\:pfy-c1{grid-template-columns:repeat(1,minmax(0,1fr))}.md\:pfy-c2{grid-template-columns:repeat(2,minmax(0,1fr))}.md\:pfy-c3{grid-template-columns:repeat(3,minmax(0,1fr))}.md\:pfy-c4{grid-template-columns:repeat(4,minmax(0,1fr))}.md\:pfy-last-full>:last-child{grid-column:1/-1}.md\:pfy-last-auto>:last-child{grid-column:auto}}
@media(min-width:1024px){.lg\:pfy-c1{grid-template-columns:repeat(1,minmax(0,1fr))}.lg\:pfy-c2{grid-template-columns:repeat(2,minmax(0,1fr))}.lg\:pfy-c3{grid-template-columns:repeat(3,minmax(0,1fr))}.lg\:pfy-c4{grid-template-columns:repeat(4,minmax(0,1fr))}.lg\:pfy-last-full>:last-child{grid-column:1/-1}.lg\:pfy-last-auto>:last-child{grid-column:auto}}
@media(min-width:1280px){.xl\:pfy-c1{grid-template-columns:repeat(1,minmax(0,1fr))}.xl\:pfy-c2{grid-template-columns:repeat(2,minmax(0,1fr))}.xl\:pfy-c3{grid-template-columns:repeat(3,minmax(0,1fr))}.xl\:pfy-c4{grid-template-columns:repeat(4,minmax(0,1fr))}.xl\:pfy-last-full>:last-child{grid-column:1/-1}.xl\:pfy-last-auto>:last-child{grid-column:auto}}
/* Siatki z CSS wariantu (merge-quality.ts finalizeGrids → data-pfy-grid="md:c3 lg:full", audyt 8.10.2026): kolumny wg liczby kart
   i ostatnia karta na cały rząd zamiast sieroty; [data-pfy-grid][data-pfy-grid~=…] = specyficzność 0,2,0 (ponad klasę wariantu) */
[data-pfy-grid][data-pfy-grid~="base:c1"]{grid-template-columns:repeat(1,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="base:c2"]{grid-template-columns:repeat(2,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="base:c3"]{grid-template-columns:repeat(3,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="base:c4"]{grid-template-columns:repeat(4,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="base:full"]>:last-child{grid-column:1/-1}[data-pfy-grid][data-pfy-grid~="base:auto"]>:last-child{grid-column:auto}
@media(min-width:640px){[data-pfy-grid][data-pfy-grid~="sm:c1"]{grid-template-columns:repeat(1,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="sm:c2"]{grid-template-columns:repeat(2,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="sm:c3"]{grid-template-columns:repeat(3,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="sm:c4"]{grid-template-columns:repeat(4,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="sm:full"]>:last-child{grid-column:1/-1}[data-pfy-grid][data-pfy-grid~="sm:auto"]>:last-child{grid-column:auto}}
@media(min-width:768px){[data-pfy-grid][data-pfy-grid~="md:c1"]{grid-template-columns:repeat(1,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="md:c2"]{grid-template-columns:repeat(2,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="md:c3"]{grid-template-columns:repeat(3,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="md:c4"]{grid-template-columns:repeat(4,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="md:full"]>:last-child{grid-column:1/-1}[data-pfy-grid][data-pfy-grid~="md:auto"]>:last-child{grid-column:auto}}
@media(min-width:1024px){[data-pfy-grid][data-pfy-grid~="lg:c1"]{grid-template-columns:repeat(1,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="lg:c2"]{grid-template-columns:repeat(2,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="lg:c3"]{grid-template-columns:repeat(3,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="lg:c4"]{grid-template-columns:repeat(4,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="lg:full"]>:last-child{grid-column:1/-1}[data-pfy-grid][data-pfy-grid~="lg:auto"]>:last-child{grid-column:auto}}
@media(min-width:1280px){[data-pfy-grid][data-pfy-grid~="xl:c1"]{grid-template-columns:repeat(1,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="xl:c2"]{grid-template-columns:repeat(2,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="xl:c3"]{grid-template-columns:repeat(3,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="xl:c4"]{grid-template-columns:repeat(4,minmax(0,1fr))}[data-pfy-grid][data-pfy-grid~="xl:full"]>:last-child{grid-column:1/-1}[data-pfy-grid][data-pfy-grid~="xl:auto"]>:last-child{grid-column:auto}}
/* ── Logo klienta w obu motywach (3.10.2026, LogoService + merge-slots.applyLogo) ──
 *  wysokość z tokenu --logo-height (compose.ts); szerokie logo (ratio > 4) niższe; plakietka tylko w motywie z kontrastem < 3:1;
 *  dwa warianty przełączane data-theme (motyw domyślny = data-default-theme, gdy brak data-theme) — bez JS */
/* 21.10.2026 (skill css-architecture-repair, „adaptacyjny system logo”): bez !important — img.pfy-logo (0,1,1) i tak bije klasy wysokości
   wariantów menu (h-8 / sm:h-10 Tailwinda, 0,1,0), a filtry zdjęć wykluczają logo u źródła (:not([data-slot-img="logo"])).
   Wysokość = token × kształt (merge-slots: pfy-logo--panoramic|horizontal|square|vertical|tower z proporcji WIDOCZNEJ treści, LogoService),
   ale nie więcej, niż pozwala szerokość: przy braku miejsca maleje wysokość, proporcje zostają (--logo-ar z merge). Nigdy object-fit:fill
   (szerokość ucinana przez max-width przy stałej wysokości spłaszczała logo panoramiczne na telefonie). */
img.pfy-logo{--logo-k:1;--logo-m:1;--logo-maxw:min(60vw,22rem);height:min(calc(var(--logo-height,2.5rem) * var(--logo-k) * var(--logo-m)),calc(var(--logo-maxw) / var(--logo-ar,1)));width:auto;max-width:var(--logo-maxw);object-fit:contain}
img:is(.pfy-logo--wide,.pfy-logo--panoramic){--logo-k:.72}
img.pfy-logo--square{--logo-k:1.15}img.pfy-logo--vertical{--logo-k:1.3}img.pfy-logo--tower{--logo-k:1.4}
/* telefon: miejsce na logo = ekran − marginesy paska − grupa przycisków (motyw + ☰ ≈ 9,75rem); logo-fit-check: 9:1 na 320 px nachodziło na przełącznik */
@media (max-width:639px){img.pfy-logo{--logo-m:.8;--logo-maxw:min(55vw,16rem,100vw - 9.75rem)}img:is(.pfy-logo--wide,.pfy-logo--panoramic){--logo-m:.84}}
img.pfy-logo-plate{background:var(--pfy-plate,#fff);padding:4px 8px;border-radius:8px;box-sizing:content-box}
:root[data-theme="dark"] img.pfy-logo--l,:root:not([data-theme]):not([data-default-theme="light"]) img.pfy-logo--l{display:none}
:root[data-theme="light"] img.pfy-logo--d,:root:not([data-theme])[data-default-theme="light"] img.pfy-logo--d{display:none}
.pfy-sr{position:absolute!important;width:1px!important;height:1px!important;padding:0!important;margin:-1px!important;overflow:hidden!important;clip:rect(0,0,0,0)!important;white-space:nowrap!important;border:0!important}

/* 3.10.2026 (Piotr: „drżenie przy przewijaniu”): 100vh w hero zmienia się, gdy telefon chowa pasek adresu → cała strona
   podskakuje przy scrollu. svh = stabilna wysokość małego viewportu; przeglądarki bez svh zostają przy 100vh z klasy. */
#hero.min-h-screen,.mm-hero.min-h-screen{min-height:100svh}

/* ══ Sygnatury archetypów i warstwa powierzchni (3.10.2026, docs/template-design.md §15) ══════════════════════════════
 *  compose.ts wystawia na <body> data-signature="<archetyp>" + data-surface-hero / data-texture / data-card-style /
 *  data-accent-decoration / data-bg-motion / data-button-style (wartości: contract.ts SURFACE_VALUES, domyślne:
 *  archetypes.ts → signature.surface, nadpisanie: template.json → tokens.surface). Strona bez archetypu nie ma tych
 *  atrybutów — nic poniżej jej nie dotyczy. Hero statyczny w 1. malowaniu; ruch tylko pod html.pfy-loaded (site-runtime.js
 *  po `load`) i nigdy przy prefers-reduced-motion. */
/* odręczny akcent warm-local: Caveat (SIL OFL 1.1, data/sections/LICENSES.md) — plik pobierany dopiero, gdy font jest użyty */
@font-face{font-family:'PFY Hand';font-style:normal;font-weight:500 700;font-display:swap;src:url(fonts/caveat-sig-cyrillic.woff2) format('woff2');unicode-range:U+0301,U+0400-045F,U+0490-0491,U+04B0-04B1,U+2116}
@font-face{font-family:'PFY Hand';font-style:normal;font-weight:500 700;font-display:swap;src:url(fonts/caveat-sig-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:'PFY Hand';font-style:normal;font-weight:500 700;font-display:swap;src:url(fonts/caveat-sig-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}
/* ── faktura (--texture, krycie --texture-opacity ≤ .08): nakładka nad całą stroną, bez zdarzeń myszy ── */
body[data-texture]:not([data-texture="none"])::after{content:"";position:fixed;inset:0;z-index:2147483000;pointer-events:none;opacity:var(--texture-opacity,.05);background-repeat:repeat}
body[data-texture="grain"]::after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='180' height='180'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.85' numOctaves='3' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E")}
body[data-texture="paper"]::after{background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='320' height='320'%3E%3Cfilter id='p'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.018 .6' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23p)'/%3E%3C/svg%3E")}
body[data-texture="grid"]::after{background-image:linear-gradient(var(--heading-color) 1px,transparent 1px),linear-gradient(90deg,var(--heading-color) 1px,transparent 1px);background-size:56px 56px}
/* ── karty (--card-style): flat/outline bez cienia (obrys z --card-border zostaje), glass półprzezroczyste; soft-shadow = cień szablonu ── */
body[data-card-style="flat"],body[data-card-style="outline"]{--shadow-card:transparent}
body[data-card-style="glass"]{--card-bg:color-mix(in srgb,var(--bg) 62%,transparent);--card-border:color-mix(in srgb,var(--heading-color) 14%,transparent)}
/* ── dekoracja nagłówków sekcji (--accent-decoration) ── */
body[data-accent-decoration="underline"] main section[data-section]:not(#hero) h2[data-slot$="Title"]::after{content:"";display:block;width:2.75rem;height:3px;border-radius:3px;margin-top:.85rem;background:var(--color-primary)}
body[data-accent-decoration="underline"] main :is(.text-center,[class*="--center"])>h2[data-slot$="Title"]::after,body[data-accent-decoration="underline"] main h2.text-center[data-slot$="Title"]::after{margin-inline:auto}
body[data-accent-decoration="bar"] main section[data-section]:not(#hero) p[data-slot$="Kicker"]::before{content:"";display:inline-block;width:1.75rem;height:2px;margin-right:.7rem;vertical-align:middle;background:currentColor}
/* ── tło hero (--surface-hero): gradient z palety pod treścią; image-overlay/video/flat = media daje wariant ── */
body[data-surface-hero="gradient-linear"] #hero{background-image:linear-gradient(155deg,color-mix(in srgb,var(--color-primary) 14%,transparent) 0%,transparent 55%,color-mix(in srgb,var(--color-accent) 10%,transparent) 100%)!important;background-size:180% 180%}
body[data-surface-hero="gradient-radial"] #hero{background-image:radial-gradient(60% 70% at 88% 12%,color-mix(in srgb,var(--color-primary) 16%,transparent),transparent 70%),radial-gradient(50% 60% at 8% 92%,color-mix(in srgb,var(--color-accent) 12%,transparent),transparent 70%)!important;background-size:180% 180%}
@keyframes pfy-drift{from{background-position:0% 0%}to{background-position:100% 100%}}
html.pfy-loaded body[data-bg-motion="drift"] #hero{animation:pfy-drift 20s ease-in-out infinite alternate}
/* ── plamy (--bg-motion: blobs): statyczne w 1. malowaniu, powolny dryf po load ── */
body[data-signature] #hero:has(>.pfy-sig-blobs){position:relative;isolation:isolate}
.pfy-sig-blobs{display:none}
body[data-bg-motion="blobs"] .pfy-sig-blobs{display:block;position:absolute;inset:0;z-index:-1;overflow:hidden;pointer-events:none}
body[data-bg-motion="blobs"] .mm-hero>.pfy-sig-blobs{z-index:0} /* hero na zdjęciu: nad przyciemnieniem (z -1), pod treścią (później w DOM) */
.pfy-sig-blobs i{position:absolute;border-radius:50%;filter:blur(56px);opacity:.6}
.pfy-sig-blobs i:nth-child(1){width:44vmax;height:44vmax;top:-18vmax;right:-14vmax;background:color-mix(in srgb,var(--color-primary) 60%,transparent)}
.pfy-sig-blobs i:nth-child(2){width:36vmax;height:36vmax;bottom:-20vmax;left:-14vmax;background:color-mix(in srgb,var(--color-accent) 55%,transparent)}
.pfy-sig-blobs i:nth-child(3){width:16vmax;height:16vmax;bottom:8%;right:12%;opacity:.4;background:color-mix(in srgb,var(--color-accent) 50%,var(--color-primary))}
@keyframes pfy-blob{0%{transform:translate(0,0) scale(1)}50%{transform:translate(3vmax,2vmax) scale(1.08)}100%{transform:translate(-2vmax,3vmax) scale(.95)}}
html.pfy-loaded .pfy-sig-blobs i{animation:pfy-blob 24s ease-in-out infinite alternate}
html.pfy-loaded .pfy-sig-blobs i:nth-child(2){animation-duration:29s;animation-direction:alternate-reverse}
html.pfy-loaded .pfy-sig-blobs i:nth-child(3){animation-duration:19s}
/* ── przycisk główny (--button-style) ── */
body[data-button-style="hard-offset"]{--pfy-offset:var(--heading-color)}
body[data-button-style="hard-offset"] .mm-hero{--pfy-offset:rgb(var(--on-media-rgb))}
body[data-button-style="hard-offset"] .btn-primary{box-shadow:4px 4px 0 0 var(--pfy-offset);transition:transform .15s ease,box-shadow .15s ease}
body[data-button-style="hard-offset"] .btn-primary:hover{transform:translate(-2px,-2px);box-shadow:6px 6px 0 0 var(--pfy-offset)}
body[data-button-style="hard-offset"] .btn-primary:active{transform:translate(2px,2px);box-shadow:1px 1px 0 0 var(--pfy-offset)}
body[data-button-style="soft"] .btn-primary{box-shadow:0 10px 24px -12px color-mix(in srgb,var(--color-primary) 75%,transparent);transition:transform .3s ease,box-shadow .3s ease}
body[data-button-style="soft"] .btn-primary:hover{transform:translateY(-2px);box-shadow:0 16px 30px -12px color-mix(in srgb,var(--color-primary) 75%,transparent)}
body[data-button-style="springy"] :is(.btn-primary,.btn-ghost,.btn-outline){transition:transform .4s cubic-bezier(.34,1.56,.64,1),background-color .3s,color .3s,border-color .3s}
body[data-button-style="springy"] :is(.btn-primary,.btn-ghost,.btn-outline):hover{transform:scale(1.03)}
body[data-button-style="springy"] :is(.btn-primary,.btn-ghost,.btn-outline):active{transform:scale(.97)}

/* ── editorial: okładka magazynu ── */
body[data-signature="editorial"] #hero h1[data-sig-folio]{font-size:clamp(2.75rem,9vw,8.5rem);line-height:.94;letter-spacing:-.025em;font-weight:500;overflow-wrap:break-word;hyphens:auto}
body[data-signature="editorial"] #hero h1[data-sig-folio]::before{content:attr(data-sig-folio);content:attr(data-sig-folio) / "";display:block;width:min(100%,20rem);margin-bottom:1.4rem;padding-right:1rem;font:600 .75rem/1 system-ui,sans-serif;letter-spacing:.32em;opacity:.85;background:linear-gradient(currentColor,currentColor) 3.4em 50%/calc(100% - 3.4em) 1px no-repeat}
body[data-signature="editorial"] #hero :is(.text-center)>h1[data-sig-folio]::before,body[data-signature="editorial"] #hero h1.text-center[data-sig-folio]::before{margin-inline:auto}
/* 3.10.2026 (fala v2, recenzja): bez numeracji sekcji „01/02” jako ozdoby — zostaje światło między sekcjami */
/* 21.10.2026: na telefonie min. 4rem (było 6rem = 96 px góra i dół → 192 px pustki między sekcjami na 390 px; Piotr: „puste przestrzenie”) */
body[data-signature="editorial"] main>section[data-section]:not(#hero){padding-block:clamp(4rem,11vw,9.5rem)}
body[data-signature="editorial"] [data-section="stats"] .counter-value{font-size:clamp(3rem,7vw,6rem);line-height:1;font-weight:500;letter-spacing:-.02em}
body[data-signature="editorial"] [data-section="gallery"] [data-slot-item="caption"]{font-style:italic;letter-spacing:.01em}

/* ── bold-video: kinetyczny nagłówek (słowa po load, ≤ 600 ms, transform/opacity — bez przesuwania layoutu) ── */
h1[data-sig-kinetic] .pfy-kw{display:inline-block}
@keyframes pfy-kw{from{opacity:0;transform:translateY(.55em)}}
html.pfy-kinetic h1[data-sig-kinetic] .pfy-kw{animation:pfy-kw var(--kw-d,.32s) cubic-bezier(.2,.75,.25,1) both;animation-delay:var(--kw-t,0s)}

/* ── minimal-portfolio: powietrze i odsłanianie ── */
.pfy-sig-word{color:var(--accent-text)}
body[data-signature="minimal-portfolio"] #hero.mm-hero .pfy-sig-word{color:inherit;text-decoration:underline;text-decoration-color:var(--color-primary);text-decoration-thickness:.07em;text-underline-offset:.14em}
body[data-signature="minimal-portfolio"] [data-gallery-item].pfy-rv{clip-path:inset(0 0 100% 0);transition:clip-path 1s cubic-bezier(.2,.7,.2,1)}
body[data-signature="minimal-portfolio"] [data-gallery-item].pfy-rv.is-in{clip-path:inset(0 0 0 0)}
@media (hover:hover) and (pointer:fine){
  body[data-signature="minimal-portfolio"].pfy-cursor-on [data-section="gallery"] [data-gallery-item]{cursor:none}
  body[data-signature="minimal-portfolio"].pfy-cursor-on [data-section="gallery"] [data-gallery-item] [data-slot-item="caption"]{opacity:0;transition:opacity .3s}
  body[data-signature="minimal-portfolio"].pfy-cursor-on [data-section="gallery"] [data-gallery-item]:focus-visible [data-slot-item="caption"]{opacity:1}
}
.pfy-sig-cursor{position:fixed;left:0;top:0;z-index:9990;pointer-events:none;display:flex;align-items:center;justify-content:center;min-width:5.5rem;min-height:5.5rem;max-width:15rem;padding:.75rem 1.25rem;border-radius:2.75rem;background:var(--color-primary);color:var(--btn-text,#fff);font-size:.8rem;font-weight:600;line-height:1.25;text-align:center;opacity:0;transform:translate3d(var(--x,0),var(--y,0),0) translate(-50%,-50%) scale(var(--s,.2));transition:opacity .2s,transform .25s cubic-bezier(.2,.8,.2,1)}
.pfy-sig-cursor.is-on{opacity:1;--s:1}
.pfy-sig-cursor svg{width:1.5rem;height:1.5rem}

/* ── warm-local: 3.10.2026 (recenzja zewnętrzna) polaroidy i odręczne kickery WYCOFANE z poziomu archetypu („AI template dla kwiaciarni”);
 *  gest archetypu = przerwanie krawędzi (niżej, „Gramatyka kompozycji”, tylko szablony v2). Zostaje spokojny kicker. ── */
:where(:root){--pfy-polaroid:#fbf8f1;--pfy-polaroid-ink:#3b342c}
body[data-signature="warm-local"] main section[data-section] p[data-slot$="Kicker"]{letter-spacing:.2em}

/* ── corporate-trust: pas zaufania pod hero, cienka rama zdjęcia, karty w obrysie ── */
body[data-signature="corporate-trust"] section[data-sig-band]{padding-block:1.5rem;border-block:1px solid var(--card-border)}
body[data-signature="corporate-trust"] section[data-sig-band] #stats-section{display:flex!important;flex-flow:row wrap!important;justify-content:center;gap:1rem 0!important;max-width:64rem;margin-inline:auto;padding:0!important;background:none!important;border:0!important;border-radius:0!important;box-shadow:none!important}
body[data-signature="corporate-trust"] section[data-sig-band] #stats-section>*{flex:1 1 40%;padding:.25rem 1rem!important;margin:0!important;background:none!important;border:0!important;box-shadow:none!important;text-align:center}
body[data-signature="corporate-trust"] section[data-sig-band] .counter-value{font-size:clamp(1.6rem,3vw,2.25rem)!important;line-height:1.1!important;color:var(--primary-text)!important}
@media(min-width:640px){
  body[data-signature="corporate-trust"] section[data-sig-band]{padding-block:1.75rem}
  body[data-signature="corporate-trust"] section[data-sig-band] #stats-section>*{flex:1 1 0;border-left:1px solid var(--card-border)!important}
  body[data-signature="corporate-trust"] section[data-sig-band] #stats-section>:first-child{border-left:0!important}
}
body[data-signature="corporate-trust"] #hero:not(.mm-hero) :is(img[data-slot-img="heroImage"],video){outline:1px solid rgb(var(--on-media-rgb) / .75);outline-offset:-12px}
/* pas zaufania widoczny w pierwszym ekranie: hero niższe o wysokość pasa */
body[data-signature="corporate-trust"] #hero:has(+ section[data-sig-band]){min-height:calc(100svh - 6.5rem)}

/* ── playful: duże ikony branżowe w pełnych kołach (plamy i sprężyste przyciski — warstwa powierzchni wyżej) ── */
body[data-signature="playful"] [data-section="services"] .flex.items-center.justify-center:has(>svg:only-child){width:4.5rem;height:4.5rem;border-radius:9999px}
body[data-signature="playful"] [data-section="services"] .flex.items-center.justify-center:has(>svg:only-child)>svg{width:2.25rem;height:2.25rem}

/* ── operational: rzeczowa typografia, etykiety nad H2 bez ozdobników, CTA bez efektów (decyzja, nie dekoracja) ── */
body[data-signature="operational"] main section[data-section] p[data-slot$="Kicker"]{letter-spacing:.14em}
body[data-signature="operational"] .btn-primary:hover{transform:none}

/* ── retreat (11.10.2026, Tafla): spokój — kicker szeroko, szeryfowa kursywa w cytatach i cenach, przyciski bez podskoku (sygnatura = hero/water) ── */
body[data-signature="retreat"] main section[data-section] p[data-slot$="Kicker"]{letter-spacing:.22em}
body[data-signature="retreat"] .btn-primary:hover{transform:none}

/* ── layered (11.10.2026, Wycinanki): produkt jest bohaterem — kicker zwarty, przycisk główny bez podskoku (ruch mają warstwy, layers.js) ── */
body[data-signature="layered"] main section[data-section] p[data-slot$="Kicker"]{letter-spacing:.16em}
body[data-signature="layered"] .btn-primary:hover{transform:none}

/* ── ruch sygnatur: zawsze stop przy prefers-reduced-motion ── */
@media (prefers-reduced-motion:reduce){
  .pfy-sig-blobs i,html.pfy-loaded body[data-bg-motion="drift"] #hero,html.pfy-kinetic h1[data-sig-kinetic] .pfy-kw{animation:none!important}
  body[data-button-style] :is(.btn-primary,.btn-ghost,.btn-outline),body[data-signature] [data-gallery-item],.pfy-sig-cursor{transition:none!important}
  body[data-button-style] :is(.btn-primary,.btn-ghost,.btn-outline):is(:hover,:active){transform:none!important}
  body[data-signature="minimal-portfolio"] [data-gallery-item].pfy-rv{clip-path:none!important}
}
/* bold-video: tytuł na wideo jednolitym kolorem (gradient tekstu nie przeżywa animacji słów) */
body[data-signature="bold-video"] #hero h1[data-sig-kinetic].hero-gradient-text{background:none;-webkit-text-fill-color:currentColor}
/* minimal-portfolio: słowo w kolorze marki także w tytule z gradientem tekstu */
.pfy-sig-word{-webkit-text-fill-color:currentColor}

/* ══ Traktowanie zdjęć i chrome per archetyp (3.10.2026, kierunek artystyczny — docs/template-design.md §16) ══════════════════
 *  compose: <body data-photo / data-photo-mask / data-photo-frame / data-photo-cutout> (contract.ts PHOTO_VALUES, domyślne archetypu
 *  archetypes.ts → signature.photo, nadpisanie template.json → tokens.photo). Filtry SVG #pfy-duotone / #pfy-film wstawia merge-photo.ts
 *  z kolorów schematu strony. Filtr nie zmienia wymiarów ani kolejności ładowania — LCP bez zmian. Wyjątek od traktowania: logo
 *  i wszystko w [data-photo-raw] (np. przed/po, gdzie liczy się prawdziwy kolor).
 *  19.10.2026 (Piotr: „zdjęcia mają takie same kolory”): czerń i biel (mono / mono-accent) NIE na pierwszym ekranie z motywem
 *  ([data-hero-motif]) — 6 z 24 szablonów miało szare hero obok siebie w galerii; szarość zostaje dla zdjęć niżej („materiał dokumentacyjny”). */
body[data-photo="duotone"] main section[data-section] img:not([data-slot-img="logo"]):not([data-photo-raw] img){filter:url(#pfy-duotone)}
body[data-photo="film"] main section[data-section] img:not([data-slot-img="logo"]):not([data-photo-raw] img){filter:url(#pfy-film)}
body[data-photo="mono"] main section[data-section] img:not([data-slot-img="logo"]):not([data-photo-raw] img):not([data-hero-motif] img){filter:grayscale(1) contrast(1.08)}
body[data-photo="mono-accent"] main section[data-section] img:not([data-slot-img="logo"]):not([data-photo-raw] img):not([data-hero-motif] img){filter:grayscale(1) contrast(1.14) brightness(1.03);transition:filter .8s ease}
/* kolor wraca pod kursorem — „podejdź bliżej” (duotone i czarno-białe z kolorem; film zostaje ciepły) */
body:is([data-photo="duotone"],[data-photo="mono-accent"]) main :is(a,figure,[data-gallery-item],[data-slot-repeat]>*):is(:hover,:focus-visible) img:not([data-slot-img="logo"]){filter:none}
body[data-photo="duotone"] main section[data-section] img:not([data-slot-img="logo"]){transition:filter .8s ease}
/* maska i rama — tylko kadr „portretowy”, który wariant oznaczył [data-photo-portrait] (hero split, „o nas”) */
body[data-photo-mask="arch"] [data-photo-portrait] img,body[data-photo-mask="arch"] [data-photo-portrait]>.pfy-ph{border-radius:9999px 9999px 0 0}
body[data-photo-mask="circle"] [data-photo-portrait] img{clip-path:circle(closest-side)}
body[data-photo-mask="slant"] [data-photo-portrait] img{clip-path:polygon(0 0,100% 0,100% 86%,0 100%)}
body[data-photo-frame="hairline"] [data-photo-portrait]:not([data-cut="1"]) img{outline:1px solid color-mix(in srgb,var(--heading-color) 60%,transparent);outline-offset:10px}
body[data-photo-frame="offset"] [data-photo-portrait]:not([data-cut="1"]) img{box-shadow:1.25rem 1.25rem 0 0 color-mix(in srgb,var(--color-accent) 30%,var(--bg))}
body[data-photo-frame="polaroid"] [data-photo-portrait]:not([data-cut="1"]) img{padding:.65rem .65rem 2.6rem;background:var(--pfy-polaroid,#fbf8f1);box-shadow:0 18px 36px -18px rgba(0,0,0,.5),0 2px 6px rgba(0,0,0,.08)}
/* wycinanka bez tła: nigdy rama ani maska na samej postaci (kompozycję daje wariant), cień pod postacią */
[data-photo-cut][data-cut="1"] img[data-cutout]{border-radius:0!important;clip-path:none!important;outline:0!important;padding:0!important;background:none!important}
/* ── Geny klienta (12.10.2026, taśma szablonów — merge-client.ts): gradacja zdjęć z ziarna nazwy firmy, tylko szablony z tokens.client
 *  i bez własnej obróbki (data-photo). Filtr statyczny (bez ruchu i przejść) — raz rastrowany, przewijanie bez kosztu (e2e 68). */
body[data-photo-grade="warm"] main section[data-section] img:not([data-slot-img="logo"]):not([data-photo-raw] img):not([src$=".svg"]){filter:sepia(.16) saturate(1.08) brightness(1.02)}
body[data-photo-grade="cool"] main section[data-section] img:not([data-slot-img="logo"]):not([data-photo-raw] img):not([src$=".svg"]){filter:saturate(.9) hue-rotate(-8deg) brightness(1.03)}
body[data-photo-grade="vivid"] main section[data-section] img:not([data-slot-img="logo"]):not([data-photo-raw] img):not([src$=".svg"]){filter:saturate(1.2) contrast(1.05)}
body[data-photo-grade="soft"] main section[data-section] img:not([data-slot-img="logo"]):not([data-photo-raw] img):not([src$=".svg"]){filter:saturate(.82) contrast(.94) brightness(1.05)}

/* ── przyciski: hand (warm-local — miękki, drugorzędny z odręcznym zawijasem) / ink (corporate — prostokąt, drugorzędny = podkreślenie) ── */
body[data-button-style="hand"] .btn-primary{box-shadow:0 10px 24px -12px color-mix(in srgb,var(--color-primary) 75%,transparent);transition:transform .3s ease,box-shadow .3s ease}
body[data-button-style="hand"] .btn-primary:hover{transform:translateY(-2px) rotate(-1deg)}
body[data-button-style="hand"] main :is(.btn-ghost,.btn-outline){border-color:transparent!important;background:none!important;position:relative;padding-inline:.25rem!important}
body[data-button-style="hand"] main :is(.btn-ghost,.btn-outline)::after{content:"";position:absolute;left:0;right:0;bottom:.3rem;height:.6rem;opacity:.7;background:var(--primary-text);-webkit-mask:no-repeat center/100% 100% url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 12' preserveAspectRatio='none'%3E%3Cpath d='M2 8c18-5 38-6 58-3s40 2 58-3' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round'/%3E%3C/svg%3E");mask:no-repeat center/100% 100% url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 120 12' preserveAspectRatio='none'%3E%3Cpath d='M2 8c18-5 38-6 58-3s40 2 58-3' fill='none' stroke='%23000' stroke-width='2.4' stroke-linecap='round'/%3E%3C/svg%3E");transform-origin:left;transition:transform .4s ease}
body[data-button-style="hand"] main :is(.btn-ghost,.btn-outline):hover::after{transform:scaleX(1.08)}
body[data-button-style="ink"] :is(.btn-primary,.btn-ghost,.btn-outline){border-radius:0!important;letter-spacing:.04em}
body[data-button-style="ink"] .btn-primary:hover{transform:none;box-shadow:inset 0 -3px 0 0 var(--color-accent)}
body[data-button-style="ink"] main :is(.btn-ghost,.btn-outline){border:0!important;background:none!important;padding-inline:0!important;margin-inline:.75rem;box-shadow:inset 0 -1px 0 0 currentColor;transition:box-shadow .3s ease}
body[data-button-style="ink"] main :is(.btn-ghost,.btn-outline):hover{box-shadow:inset 0 -3px 0 0 var(--color-accent)}

/* ── karty: note (warm-local — karteczka z taśmą) / rule (corporate — bez pudełka, linia nad pozycją, podkreślenie jak w akcie) ── */
body[data-card-style="note"] main [data-slot-repeat]:is([data-slot-repeat="services"],[data-slot-repeat="pricingPlans"],[data-slot-repeat="testimonials"])>*{position:relative;background:var(--pfy-polaroid,#fbf8f1)!important;color:var(--pfy-polaroid-ink,#3b342c);border:0!important;border-radius:3px!important;box-shadow:0 16px 30px -18px rgba(0,0,0,.45),0 1px 3px rgba(0,0,0,.08)!important;transform:rotate(-.8deg);transition:transform .35s ease,box-shadow .35s ease}
body[data-card-style="note"] main [data-slot-repeat]:is([data-slot-repeat="services"],[data-slot-repeat="pricingPlans"],[data-slot-repeat="testimonials"])>:nth-child(2n){transform:rotate(.9deg)}
body[data-card-style="note"] main [data-slot-repeat]:is([data-slot-repeat="services"],[data-slot-repeat="pricingPlans"],[data-slot-repeat="testimonials"])>:nth-child(3n){transform:rotate(-.3deg)}
body[data-card-style="note"] main [data-slot-repeat]:is([data-slot-repeat="services"],[data-slot-repeat="pricingPlans"],[data-slot-repeat="testimonials"])>::before{content:"";position:absolute;z-index:2;top:-.7rem;left:50%;width:5.5rem;height:1.4rem;margin-left:-2.75rem;transform:rotate(-3deg);background:color-mix(in srgb,var(--color-accent) 22%,rgba(255,255,255,.55));box-shadow:0 1px 2px rgba(0,0,0,.08);pointer-events:none}
body[data-card-style="note"] main [data-slot-repeat]:is([data-slot-repeat="services"],[data-slot-repeat="pricingPlans"],[data-slot-repeat="testimonials"])>:is(:hover,:focus-within){transform:rotate(0) translateY(-4px)}
body[data-card-style="note"] main [data-slot-repeat]:is([data-slot-repeat="services"],[data-slot-repeat="pricingPlans"],[data-slot-repeat="testimonials"])>* :is(h3,h4,p,li,span:not(.sr-only)){color:inherit}
body[data-card-style="rule"]{--shadow-card:transparent}
/* 23.10.2026 (Piotr, szkłaż na telefonie: „litery przykleiły się do boxów” — cennik tailblocks-rows): styl „linia” spłaszcza KARTY, ale
   wiersze w liście z własną ramką (pojemnik z border w style) zostawały bez marginesu przy tej ramce — taka lista zostaje jak w układzie */
body[data-card-style="rule"] main [data-slot-repeat]:is([data-slot-repeat="services"],[data-slot-repeat="pricingPlans"]):not([style*="border"])>*{background:none!important;border:0!important;border-top:1px solid var(--heading-color)!important;border-radius:0!important;box-shadow:none!important;padding-inline:0!important;position:relative}
body[data-card-style="rule"] main [data-slot-repeat]:is([data-slot-repeat="services"],[data-slot-repeat="pricingPlans"])>* h3{background:linear-gradient(var(--color-accent),var(--color-accent)) 0 100%/0 2px no-repeat;transition:background-size .5s cubic-bezier(.2,.7,.2,1);display:inline;padding-bottom:.15em}
body[data-card-style="rule"] main [data-slot-repeat]:is([data-slot-repeat="services"],[data-slot-repeat="pricingPlans"])>:is(:hover,:focus-within) h3{background-size:100% 2px}

/* font faktów (corporate-trust): IBM Plex Mono (SIL OFL 1.1, static/fonts/LICENSES.md) — pobierany dopiero, gdy użyty */
@font-face{font-family:'PFY Mono';font-style:normal;font-weight:400;font-display:swap;src:url(fonts/plexmono-sig-400-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:'PFY Mono';font-style:normal;font-weight:400;font-display:swap;src:url(fonts/plexmono-sig-400-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:'PFY Mono';font-style:normal;font-weight:500;font-display:swap;src:url(fonts/plexmono-sig-500-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:'PFY Mono';font-style:normal;font-weight:500;font-display:swap;src:url(fonts/plexmono-sig-500-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}

@media (prefers-reduced-motion:reduce){
  body[data-photo] main section[data-section] img,body[data-card-style] main [data-slot-repeat]>*,body[data-card-style] main [data-slot-repeat]>* h3,body[data-button-style] main :is(.btn-ghost,.btn-outline)::after{transition:none!important}
  body[data-card-style="note"] main [data-slot-repeat]>:is(:hover,:focus-within){transform:none!important}
}

/* ══ Gramatyka kompozycji (3.10.2026, recenzja zewnętrzna rund 1–2 — docs/template-design.md §17) ═══════════════════════════════
 *  compose.ts (tylko szablon "composition": "v2"): <body data-composition="<archetyp>" data-grid data-gesture data-intensity
 *  [data-doc-frame]> + --intensity (subtle .6 / standard 1 / bold 1.4 — suwak CHARAKTER). Gest archetypu jest TU, raz — każdy nowy
 *  szablon v2 archetypu go dziedziczy; wariant tylko oznacza miejsce ([data-edge-break], [data-doc-grid], [data-work-media]). */
/* kadr bezpieczny (tokens.photo.crop = safe): kształt pudełka wariantu, środek kadru, BEZ powiększenia (agresywny kadr = crop_confidence ≥ 0,7) */
body[data-photo-crop="safe"] [data-photo-crop]{overflow:hidden}
body[data-photo-crop="safe"] [data-photo-crop] img{object-fit:cover;object-position:50% 50%}
/* warm-local — przerwanie krawędzi. 11.10.2026 (Piotr: „wychodzenie zdjęć poza obręb ekranu nie wygląda estetycznie — ma sens tylko
   w PNG bez tła, SVG i podobnych”): wystawanie poza siatkę/ekran i schodzenie na następną sekcję TYLKO dla grafiki z przezroczystym tłem —
   merge oznacza ją [data-edge-media="alpha"] (merge.ts markEdgeMedia: SVG, wycinanka, PNG/WebP z alfą). FOTOGRAFIA (domyślnie, także strony
   sprzed republish bez znacznika) zostaje w marginesach treści: lekkie przesunięcie w pudełku, nieregularna maska, plama za nią — w ekranie.
   Pilnuje visual-audit M18. */
body[data-gesture="edge-break"]{--edge-break:10%;--edge-overlap:clamp(4rem,13vw,11rem);--edge-tilt:-1.5deg}
body[data-gesture="edge-break"][data-intensity="subtle"]{--edge-break:8%;--edge-overlap:clamp(2.5rem,7vw,6rem);--edge-tilt:-.8deg}
body[data-gesture="edge-break"][data-intensity="bold"]{--edge-break:12%;--edge-overlap:clamp(5rem,16vw,14rem);--edge-tilt:-2.2deg}
body[data-gesture="edge-break"] main{overflow-x:clip}
body[data-gesture="edge-break"] [data-edge-break] img{border-radius:44% 56% 47% 53% / 37% 41% 59% 63%}
/* fotografia: pudełko wariantu bez zmian, zdjęcie 93 % przesunięte w głąb pudełka, plama wypełnia odsłonięty róg — wszystko w pudełku */
body[data-gesture="edge-break"] [data-edge-break]:not([data-edge-media="alpha"]){position:relative;z-index:1}
body[data-gesture="edge-break"] [data-edge-break]:not([data-edge-media="alpha"])::before{content:"";position:absolute;z-index:-1;inset:9% 0 0 11%;background:color-mix(in srgb,var(--color-primary) 16%,var(--bg));border-radius:58% 42% 61% 39% / 47% 55% 45% 53%}
body[data-gesture="edge-break"] [data-edge-break]:not([data-edge-media="alpha"]) img{transform:translate(-3%,-3%) scale(.93)}
body[data-gesture="edge-break"] [data-edge-break="left"]:not([data-edge-media="alpha"])::before{inset:9% 11% 0 0}
body[data-gesture="edge-break"] [data-edge-break="left"]:not([data-edge-media="alpha"]) img{transform:translate(3%,-3%) scale(.93)}
/* sekcja z fotografią w przerwaniu kończy się zdjęciem (warianty mają padding-bottom 0 pod wystawanie) — oddech jak każda sekcja,
   odstęp zdjęć różnych sekcji ≥ 96 px (390) / 160 px (1440) — rytm zdjęć 11.10, pkt 5 */
body[data-gesture="edge-break"] main>section:has([data-edge-break]:not([data-edge-media="alpha"])){padding-bottom:clamp(2.5rem,5vw,4.5rem)}
/* grafika z alfą: dotychczasowy gest — wystaje 8/10/12 % poza siatkę, schodzi na następną sekcję, plama za nią */
body[data-gesture="edge-break"] main>section:has([data-edge-media="alpha"]){position:relative;z-index:3;overflow:visible}
body[data-gesture="edge-break"] main>section#hero:has([data-edge-media="alpha"]){z-index:5}
body[data-gesture="edge-break"] [data-edge-break][data-edge-media="alpha"]{position:relative;z-index:4;margin-right:calc(-1 * var(--edge-break));margin-bottom:calc(-1 * var(--edge-overlap));transform:translateX(1.5%) rotate(var(--edge-tilt))}
body[data-gesture="edge-break"] [data-edge-break][data-edge-media="alpha"]::before{content:"";position:absolute;z-index:-1;inset:8% -6% -7% 10%;background:color-mix(in srgb,var(--color-primary) 16%,var(--bg));border-radius:58% 42% 61% 39% / 47% 55% 45% 53%;transform:rotate(5deg)}
body[data-gesture="edge-break"] [data-edge-break="left"][data-edge-media="alpha"]{margin-right:0;margin-left:calc(-1 * var(--edge-break));transform:translateX(-1.5%) rotate(calc(-1 * var(--edge-tilt)))}
body[data-gesture="edge-break"] [data-edge-break="left"][data-edge-media="alpha"]::before{inset:8% 10% -7% -6%;transform:rotate(-5deg)}
body[data-gesture="edge-break"] main>section:not(#hero):has([data-edge-media="alpha"]) + section{padding-top:calc(var(--edge-overlap) + 4rem)!important}
body[data-gesture="edge-break"] #hero:has([data-edge-media="alpha"]) + section{padding-top:calc(var(--edge-overlap) + 3rem)!important}
@media(max-width:1023px){
  /* telefon/tablet: grafika z alfą wychodzi za PRAWĄ krawędź, plama po wewnętrznej stronie (Piotr 11.10, eco-green edge-root) */
  body[data-gesture="edge-break"] [data-edge-break="left"][data-edge-media="alpha"]{margin-left:0;margin-right:calc(-1 * var(--edge-break));justify-self:end;transform:translateX(1.5%) rotate(var(--edge-tilt))}
  body[data-gesture="edge-break"] [data-edge-break][data-edge-media="alpha"]::before{inset:8% 10% -7% -6%;transform:rotate(-5deg)}
}
/* corporate-trust — rama dokumentu: numer strony w stopce każdej sekcji, linia marginesu (2/12) w sekcjach z siatką dokumentu,
   kickery krojem faktów; natężenie: subtelny = bez linii, wyrazisty = linia w kolorze nagłówków */
body[data-doc-frame]{--doc-rule:var(--card-border)}
body[data-doc-frame][data-intensity="bold"]{--doc-rule:var(--heading-color)}
body[data-doc-frame] main>section[data-section][data-doc-page]{position:relative}
/* 23.10.2026 (Piotr, szkłaż na telefonie — drugi raz po 21.10 kwiaciarni: „STRONA 02 / 11” przekreślone linią): numer strony leży w dolnym
   marginesie sekcji (bottom .9rem, ~1rem wysokości), a pas zaufania (section[data-sig-band], padding-block 1.5rem) zostawiał mu 24 px — numer
   trafiał na linię kończącą pas. Sekcja z numerem ma pod treścią co najmniej 2.75rem. Strażnik: nav-fit NF-g (numer nie nachodzi na tekst
   ani linię — każdy szablon, każdy układ do wyboru, 7 szerokości). */
body[data-doc-frame] main>section[data-section][data-doc-page][data-sig-band]{padding-block-end:2.75rem}
body[data-doc-frame] main>section[data-section][data-doc-page]::after{content:attr(data-doc-page);position:absolute;right:max(1rem,calc((100% - 80rem) / 2 + 1.5rem));bottom:.9rem;font-family:'PFY Mono',ui-monospace,monospace;font-size:.62rem;letter-spacing:.18em;text-transform:uppercase;color:var(--text-muted);pointer-events:none}
body[data-doc-frame] main section[data-section] p[data-slot$="Kicker"]{font-family:'PFY Mono',ui-monospace,monospace;letter-spacing:.18em}
@media(min-width:1024px){
  body[data-doc-frame]:not([data-intensity="subtle"]) main>section[data-doc-grid]::before{content:"";position:absolute;top:0;bottom:0;left:calc(max(0px,(100% - 80rem) / 2) + 4.5rem + (min(100%,80rem) - 25rem) / 6);width:1px;background:var(--doc-rule);pointer-events:none}
}
body[data-doc-frame][data-intensity="subtle"] [data-doc-seal]{display:none}
/* minimal-portfolio — praca jest layoutem: udział pierwszego ekranu dla zdjęcia (subtelny 70 % / standard 80 % / wyrazisty 88 %) */
body[data-gesture="work-is-layout"]{--work-share:.8}
body[data-gesture="work-is-layout"][data-intensity="subtle"]{--work-share:.7}
body[data-gesture="work-is-layout"][data-intensity="bold"]{--work-share:.88}


/* playful — żywy element (fala v2): 1–2 elementy mają fizykę (obrót, sprężyste wejście po `load`, reakcja na kursor), reszta strony cicha.
   [data-living="1"] = pierwszy element (naklejka / obrócone zdjęcie hero), [data-living="2"] i lista [data-living-list] (druga karta) = drugi;
   subtelny = tylko pierwszy, standard = dwa, wyrazisty = dwa + mocniejsze wejście. Wejście tylko transform (bez opacity — hero statyczny
   w 1. malowaniu), reduced-motion = stan końcowy bez ruchu. */
body[data-gesture="living-element"]{--live-in:1}
body[data-gesture="living-element"][data-intensity="bold"]{--live-in:1.8}
body[data-gesture="living-element"] [data-living]{transform:rotate(var(--live-rot,-4deg));transition:transform .55s cubic-bezier(.34,1.56,.64,1)}
body[data-gesture="living-element"] [data-living]:hover{transform:rotate(0deg) scale(1.04)}
body[data-gesture="living-element"] [data-living-list]>:nth-child(2){transform:rotate(1.6deg) translateY(-.5rem);box-shadow:0 22px 40px -24px rgb(var(--scrim-rgb) / .45);transition:transform .55s cubic-bezier(.34,1.56,.64,1)}
body[data-gesture="living-element"] [data-living-list]>:nth-child(2):hover{transform:rotate(0deg) translateY(-.75rem)}
body[data-gesture="living-element"][data-intensity="subtle"] [data-living="2"],body[data-gesture="living-element"][data-intensity="subtle"] [data-living-list]>:nth-child(2){transform:none;box-shadow:none}
@keyframes pfy-live-in{0%{transform:translateY(calc(1.25rem * var(--live-in))) rotate(calc(var(--live-rot,-4deg) * 2.5)) scale(.92)}60%{transform:translateY(-.2rem) rotate(calc(var(--live-rot,-4deg) * .6)) scale(1.02)}100%{transform:rotate(var(--live-rot,-4deg))}}
html.pfy-loaded body[data-gesture="living-element"] [data-living="1"]{animation:pfy-live-in calc(.8s * var(--live-in)) cubic-bezier(.34,1.56,.64,1) .15s both}
@media (prefers-reduced-motion:reduce){
  body[data-gesture="living-element"] [data-living],body[data-gesture="living-element"] [data-living-list]>*,html.pfy-loaded body[data-gesture="living-element"] [data-living="1"]{animation:none!important;transition:none!important}
}
/* operational („Operacyjny”, docs/archetype-operacyjny-spec.md) — WCIĘTY DOWÓD: zdjęcie ~1/3 sekcji, górna krawędź 12/15/18 % (subtelny /
   standard / wyrazisty) poniżej górnej krawędzi sąsiedniej treści. Kolumna dowodu = flex w komórce siatki rozciągniętej do wysokości
   treści; odstęp to procent tej wysokości (nie stała w px) — działa przy każdej długości tekstu. Telefon: zwykła kolejność, bez wcięcia. */
body[data-gesture="indented-proof"]{--indent:15%}
body[data-gesture="indented-proof"][data-intensity="subtle"]{--indent:12%}
body[data-gesture="indented-proof"][data-intensity="bold"]{--indent:18%}
@media(min-width:1024px){
  body[data-gesture="indented-proof"] [data-indent-row]{align-items:stretch}
  body[data-gesture="indented-proof"] [data-indent-proof]{display:flex;flex-direction:column;align-self:stretch}
  body[data-gesture="indented-proof"] [data-indent-proof]::before{content:"";flex:0 0 var(--indent)}
  body[data-gesture="indented-proof"] [data-indent-proof]>*{flex:1 1 auto;min-height:0}
}
/* 3.10.2026 (Piotr: „drżenie przy przewijaniu w każdym szablonie”). Dwie przyczyny wspólne dla wszystkich stron:
   1) .section-fade wjeżdżał translateY(24px→0) przez 0,6 s DOKŁADNIE wtedy, gdy użytkownik przewija — treść porusza się
      względem scrolla i wygląda jak drganie; zostaje samo wygaszenie opacity, bez przesunięcia, krócej;
   2) html{scroll-behavior:smooth} na całej stronie podwaja wygładzanie kółka/gestu w części przeglądarek (Firefox, Chrome na
      Windows) i daje „gumowe” dociąganie; płynne przewijanie zostaje tylko dla kliknięć w kotwice (site-runtime.js). */
.section-fade,.slide-up,.slide-left,.slide-right{transform:none!important;transition:opacity .35s ease!important}
.section-fade.visible,.slide-up.visible,.slide-left.visible,.slide-right.visible{transform:none!important}
html{scroll-behavior:auto!important}
/* ── zasoby marki branży (3.10.2026, merge-brand.ts): znak = dwie maski kolorowane tokenami; wzór = kafelek tła body (bez nakładki) ── */
body[data-texture="brand"]::after,body[data-texture-tile]::after{content:none!important}
.pfy-mark{position:relative;display:inline-block;flex:none;width:var(--logo-height,2.5rem);height:var(--logo-height,2.5rem);vertical-align:middle;margin-right:.6rem}
.pfy-mark i{position:absolute;inset:0;display:block;-webkit-mask:var(--m) center/contain no-repeat;mask:var(--m) center/contain no-repeat}
.pfy-mark__ink{--m:var(--pfy-mark-ink);background:var(--heading-color)}
.pfy-mark__tint{--m:var(--pfy-mark-tint);background:var(--color-primary)}
.pfy-mark[data-mono] .pfy-mark__ink{background:var(--color-primary)}
footer .pfy-mark{margin-right:.5rem}
/* 4.10.2026 (brand-v2) logo: znak w nawigacji i stopce — jeden rozmiar i odstęp w obu motywach (raster 2 maski / Lucide 1 maska) */
nav .pfy-mark{width:clamp(2rem,var(--logo-height,2.5rem),3rem);height:clamp(2rem,var(--logo-height,2.5rem),3rem)}
footer .pfy-mark{width:2.25rem;height:2.25rem}
/* warstwa marki w hero (merge-brand.applyBrandHeroLayer): pod treścią wariantu (z-index −1 w izolowanym kontekście), statyczna,
   bez fixed i mix-blend-mode (incydent 6). Wzór = maska luminancji z pattern-dark w kolorze marki + mgła radialna; znak wodny = maski logo. */
:where([data-brand-hero]){position:relative}
[data-brand-hero]{isolation:isolate}
.pfy-hero-brand{position:absolute;inset:0;z-index:-1;pointer-events:none;overflow:hidden;contain:paint}
.pfy-hero-brand__tile{position:absolute;inset:0;background:var(--color-primary);opacity:.9;mask:var(--pfy-hero-tile) 0 0/480px repeat luminance,radial-gradient(ellipse 70% 80% at 72% 45%,#000 0%,transparent 75%) alpha;mask-composite:intersect}
/* 11.10.2026 (przycinanie przewijania na telefonie): kafelek wypieczony w kolorze marki z kryciem = luminancja (merge-brand + tile-bake.ts) —
   zostaje JEDNA maska (mgła radialna), bez maski luminancji i mask-composite; wygląd ten sam. Strony sprzed republish: reguła wyżej. */
.pfy-hero-brand__tile--baked{background:var(--pfy-hero-tile-baked) 0 0/480px repeat;mask:radial-gradient(ellipse 70% 80% at 72% 45%,#000 0%,transparent 75%);mask-composite:add}
.pfy-hero-brand .pfy-hero-brand__mark{position:absolute;margin:0;right:3%;top:12%;width:clamp(200px,30vw,440px);height:auto;aspect-ratio:1;opacity:.08}
html[data-theme="dark"] .pfy-hero-brand .pfy-hero-brand__mark{opacity:.1}
/* 11.10.2026 (kids-playful 390 px: dokument 421 px) — znak wodny na telefonie w CAŁOŚCI w pudełku hero: bez ujemnego right,
   które w części przeglądarek poszerzało stronę mimo overflow:hidden warstwy; pfy-mark ma margin-right z logo — zerujemy */
@media (max-width:640px){.pfy-hero-brand .pfy-hero-brand__mark{right:0;left:auto;top:9%;width:min(62vw,100%);max-width:100%;margin:0;opacity:.07}}
/* nawigacja na tapecie (kafelek body) przed przewinięciem: mgła z --bg pod linkami — wzór nie wchodzi pod tekst menu
   (pomiar 4.10: linki 4,25–4,49:1 nad wzorem), dół mgły przezroczysty, więc bez pasa; hero pełnoekranowe ma własne tło nawigacji.
   21.10.2026: bez mgły nad pełnym zdjęciem/filmem ([data-over-media], motyw hm-m-full) — tam menu jest białe na przyciemnieniu
   kadru, a jasna mgła dawała białe na jasnym (~1,1:1; nazwa, linki, ☰ niewidoczne — kreslarnia: tapeta + pełne zdjęcie) */
body[data-texture-tile] #navbar:not(.nav-scrolled):not([data-over-media]){background-image:linear-gradient(180deg,var(--bg) 0,var(--bg) 62%,color-mix(in srgb,var(--bg) 0%,transparent) 100%)}
/* ikony według branży (merge-icons.ts): glif w linii tytułu karty, kolor tekstu marki; corporate-trust — wyciszony (akcent tylko na liczbach i CTA) */
/* 23.10.2026 (NF-e): tytuł obok ikony ma co najmniej 7rem — w ciaśniejszej karcie (bold-landing, 3 usługi na 768 px: ~95 px obok ikony,
   „OKOLICZNOŚCIOWE”/„Hochzeitsdekorationen” wypychały stronę o 199 px) schodzi pod ikonę i dostaje całą szerokość karty */
.pfy-ititle{display:flex;flex-wrap:wrap;align-items:center;gap:.6rem}
.pfy-ititle>h3{min-width:0;flex:1 1 7rem}
.pfy-ico{display:inline-flex;flex:none;align-items:center;justify-content:center;color:var(--primary-text)}
.pfy-ico svg{display:block}
.pfy-ico--lead{margin-bottom:.75rem}
body[data-signature="corporate-trust"] .pfy-ico{color:var(--text-muted)}
/* faktura brand: sekcje na tle --bg przezroczyste (widać kafelek body); sekcje alt zostają PEŁNE — czyste przejścia rytmu zamiast
   półprzezroczystych szwów (Piotr 3.10: „niepokoją przejścia między sekcjami”) */
body[data-texture-tile] [data-section][style*="var(--bg)"]{background-color:transparent!important}
/* sekcje alt na tapecie: zamiast pasa koloru — miękka mgła z rozmytymi krawędziami (Piotr 3.10: „przejścia powinny być niewidoczne”);
   wzór prześwituje przez całą stronę, rytm zostaje jako delikatne pociemnienie środka sekcji */
body[data-texture-tile] [data-section][style*="var(--section-alt)"]{background-color:transparent!important;background-image:linear-gradient(180deg,transparent 0%,color-mix(in srgb,var(--section-alt) 78%,transparent) 22%,color-mix(in srgb,var(--section-alt) 78%,transparent) 78%,transparent 100%)!important}
/* 20.10.2026 (reżyser strony, art-direction.ts): sekcja-kontrapunkt w drugim motywie ma WŁASNE pełne tło — na kafelku materiału
   (paper/linen/kraft) reguły wyżej robiły ją przezroczystą i jasny tekst ciemnego motywu leżał na jasnym papierze */
/* materiały (3.10 noc): właściwy wygląd daje kafelek z merge-brand (data-texture-tile); poniżej AWARYJNA nakładka, gdy kafelka brak (walidator S-e) */
body[data-texture="linen"]::after,body[data-texture="kraft"]::after,body[data-texture="plaster"]::after,body[data-texture="concrete"]::after,body[data-texture="slate"]::after{background-image:linear-gradient(0deg,transparent 0 50%,color-mix(in srgb,var(--heading-color) 5%,transparent) 50%);background-size:3px 3px}
body[data-texture="drafting"]::after{background-image:linear-gradient(color-mix(in srgb,var(--heading-color) 6%,transparent) 1px,transparent 1px),linear-gradient(90deg,color-mix(in srgb,var(--heading-color) 6%,transparent) 1px,transparent 1px);background-size:8px 8px} /* 12.10.2026 kalka (taśma, kreslarnia) — awaryjnie, gdy brak kafelka */

/* 5.10.2026 generator logo: układ pionowy / znak + nazwa w stopce — wyższe logo (nav ma stałą wysokość, tam układ poziomy) */
footer img.pfy-logo--tall{--logo-k:1.8;--logo-maxw:min(80vw,18rem)} /* układ pionowy w stopce (plik footer) — przez zmienne, bez !important */

/* 7.10.2026 (opinia „obszar dotyku przycisku menu”, WCAG 2.5.5): przycisk menu i przełącznik motywu w nawigacji KAŻDEGO szablonu
   ≥ 44×44 px (pomiar przed: 36–44 × 31–34). Tylko rozmiar i wyśrodkowanie — display zostaje z wariantu (md:hidden / lg:hidden). */
/* Ujemny margines pionowy = pasek nawigacji nie rośnie (przycisk był 34–36 px wysokości), rośnie tylko pole dotyku. */
#menu-btn,#theme-toggle{min-width:44px;min-height:44px;margin-block:-4px}
#menu-btn{justify-content:center;align-items:center;margin-block:-5px}

/* 21.10.2026 (recenzja zewnętrzna: „przerywana ramka jak z innego systemu”): cienka ciągła linia i krój strony zamiast systemowego.
   8.10.2026 (opinia kolegi pkt 5): podgląd/demo — przykładowe opinie i ceny podpisane przy treści (sample-content.ts
   labelSamplesInPreview). Kolor dziedziczony z karty/nagłówka (kontrast jak tekst obok, także na zdjęciu), bez opacity. */
.pfy-sample-tag{display:inline-flex;align-items:center;width:max-content;max-width:100%;margin-top:.625rem;padding:.125rem .625rem;border:1px solid color-mix(in srgb,currentColor 38%,transparent);border-radius:999px;font-family:inherit;font-size:.6875rem;font-weight:600;line-height:1.5;letter-spacing:.06em;text-transform:uppercase;color:inherit}
.pfy-sample-note{display:block;margin:.75rem 0 0}
.pfy-sample-note .pfy-sample-tag{margin-top:0}
/* ── Dostępność (10.10.2026, WCAG 2.1 AA): widoczny fokus na każdym elemencie interaktywnym, obrys pól ≥ 3:1 w obu motywach,
   link w tekście odróżnialny nie tylko kolorem (stopka), tekst tylko dla czytnika, cel „przejdź do treści” bez ramki. ── */
/* dwukolorowy wskaźnik fokusu (WCAG 1.4.11, technika C40): pierścień w kolorze tła strony + pierścień w kolorze fokusu — widoczny na jasnym,
   ciemnym i odwróconym tle (stopka ledger); outline przezroczysty zostaje dla trybu wysokiego kontrastu Windows */
a:focus-visible,button:focus-visible,input:focus-visible,select:focus-visible,textarea:focus-visible,summary:focus-visible,[tabindex]:focus-visible{outline:2px solid transparent;outline-offset:2px;box-shadow:0 0 0 2px var(--bg,#fff),0 0 0 4px var(--focus-color,#2563eb)}
/* 12.10.2026: wskaźnik fokusu od razu, bez przejścia — szablony z `transition:all` (np. .btn-primary medical-trust) animowały pierścień
   przez 0,3 s z białego obrysu (1:1 na białej karcie formularza); przejścia przycisku wracają po zdjęciu fokusu. Pilnuje a11y-audit K2 (render z przejściami na fokusie). */
:is(a,button,input,select,textarea,summary,[tabindex]):focus-visible{transition-property:none!important}
#main-content:focus,#main-content:focus-visible{outline:none}
.pfy-sr{position:absolute!important;left:0;top:0;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border:0}
/* 11.10.2026: left/top 0 — bez nich tekst dla czytnika stał w miejscu statycznym; w pasie przewijanym w poziomie (opinie marquee przy
   reduced-motion: overflow-x:auto) wychodził poza ekran i poszerzał całą stronę (qqw: 796 px przy oknie 412) */
/* !important: warianty mają inline border:1px solid var(--input-border), a token bywa za słaby w ciemnym motywie (1,3:1) */
form[data-contact-form] :is(input:not([type=checkbox]):not([type=hidden]),textarea,select){border-color:color-mix(in srgb,var(--text) 80%,var(--bg))!important}
footer p a:not(.btn-primary){text-decoration:underline;text-underline-offset:.15em}
#back-to-top:not(.visible){visibility:hidden}
.pfy-vid-toggle{position:absolute;right:1rem;bottom:1rem;z-index:3;display:inline-flex;align-items:center;justify-content:center;width:44px;height:44px;border-radius:9999px;border:1px solid rgba(255,255,255,.6);background:rgba(0,0,0,.55);color:#fff;cursor:pointer}
.pfy-vid-toggle:hover{background:rgba(0,0,0,.75)}
/* pola formularza: pierścień fokusu z Tailwinda (focus:ring-2 … /50) ma 2,4:1 — ten sam dwukolorowy wskaźnik co wyżej (specyficzność > .focus\:ring-2:focus) */
form[data-contact-form] :is(input,textarea,select):focus-visible{box-shadow:0 0 0 2px var(--bg,#fff),0 0 0 4px var(--focus-color,#2563eb)}
/* przyciski zgody cookies: tło primary bywa za jasne dla bieli i za ciemne dla grafitu (medical-trust 4,1:1, kids-playful 4,2:1) —
   para nagłówek/tło strony jest zawsze ≥ 4,5:1 w obu motywach (walidator), więc przycisk główny banera = ta para */
#cookie-banner button[onclick="cookieAccept('all')"],#cookie-modal button[onclick="cookieSavePrefs()"]{background:var(--heading-color)!important;color:var(--bg)!important}
/* 11.10.2026 (Piotr: „dopóki widać baner cookies, strona przewija się mniej płynnie”): baner miał backdrop-filter:blur(10px) na
   półprzezroczystym --card-bg (ciemne motywy: 3–4,5% bieli) — filtr tła na stałym elemencie = w każdej klatce przewijania przeglądarka
   od nowa czyta i rozmywa to, co pod banerem (ślad Chromium: rysowanie klatki 10,2 ms zamiast 3,3 ms). Teraz pełne tło: --card-bg na --bg
   (wygląd karty na stronie, kontrast liczony na pełnym tle). Źródło: data/sections/_layout/document.html; ta reguła = zapas dla stron
   opublikowanych przed zmianą (inline style). Pilnuje: tests/cookie-banner-perf.test.ts + e2e panelu 68 (_scroll-smoothness.mjs). */
#cookie-banner>div{-webkit-backdrop-filter:none!important;backdrop-filter:none!important;background:linear-gradient(var(--card-bg),var(--card-bg)),var(--bg)!important}
#cookie-modal{-webkit-backdrop-filter:none!important;backdrop-filter:none!important;background:rgba(0,0,0,.75)!important}
/* 20.10.2026 (badanie wzrokowe: baner zajmował ~40 % pierwszego ekranu telefonu i zasłaniał nagłówek i przycisk na 24/24 stronach;
   badanie wydajności: cień 50 px na stałym elemencie): na telefonie przyciski w jednym rzędzie, mniejsze odstępy, cień ≤ 24 px.
   Wszystkie trzy wybory zostają równie dostępne (zgoda tak samo łatwa jak odmowa). */
#cookie-banner>div{box-shadow:0 10px 24px -10px rgb(0 0 0 / .35)!important}
@media (max-width:639px){
  #cookie-banner{padding:.5rem!important}
  #cookie-banner>div{padding:.75rem .85rem!important}
  #cookie-banner>div>div{gap:.6rem!important}
  #cookie-banner p.text-sm{font-size:.8rem;margin-bottom:.15rem}
  #cookie-banner p.text-xs{font-size:.7rem;line-height:1.4}
  #cookie-banner>div>div>div:last-child{flex-direction:row!important;flex-wrap:wrap;gap:.4rem!important}
  #cookie-banner>div>div>div:last-child>button{flex:1 1 auto;padding:.55rem .6rem!important;min-height:2.5rem;font-size:.72rem}
}

/* 20.10.2026 (badanie wzrokowe: „duży pastelowy prostokąt z KZ/MZ/MJ jako zdjęcie — wygląda jak niedokończony wireframe”): kafel inicjałów
   (osoba bez własnego zdjęcia, merge-quality finalizeTeam) = mały monogram w kole przy nazwisku, nie prostokąt na miejscu zdjęcia */
[data-team-tile]{width:4.5rem!important;height:4.5rem!important;min-height:0!important;max-width:4.5rem;aspect-ratio:1!important;border-radius:50%!important;flex:none;background:color-mix(in srgb,var(--color-primary) 10%,var(--card-bg))!important;box-shadow:inset 0 0 0 1px color-mix(in srgb,var(--color-primary) 22%,transparent)}
[data-team-tile]>span{font-size:1.35rem!important}

/* ── Rytm zdjęć (11.10.2026, Piotr: „kolejne zdjęcie po drugiej stronie”) — merge-rhythm.ts liczy stronę zdjęcia z kolejności WŁĄCZONYCH sekcji
   i stawia [data-split-flip] na sekcji, której domyślna strona (data-split wariantu) jest niewłaściwa. Odbicie raz dla wszystkich wariantów:
   direction:rtl odwraca linie siatki grid i kolejność flex-row; dzieci wracają do ltr (tekst, wcięcia). Tylko od 1024 px — na telefonie jedna
   kolumna, kolejność stała (body[data-mobile-order], archetypes.ts photoRhythmFor). Wariant, któremu odbicie psuje element na całą szerokość,
   dopisuje własną regułę [data-split-flip] … w swoim .css. Wcięcia asymetryczne w splitach tylko właściwościami logicznymi (walidator RY-b). */
@media(min-width:1024px){
  [data-split-flip] [data-split],[data-split-flip][data-split]{direction:rtl}
  [data-split-flip] [data-split]>*,[data-split-flip][data-split]>*{direction:ltr}
}
/* telefon: zdjęcie pierwsze w archetypie „praca jest layoutem” (minimal-portfolio); reszta = tekst nad zdjęciem (kolejność DOM wariantów) */
@media(max-width:1023px){body[data-mobile-order="media-first"] [data-split]:not([data-split="exhibit"])>[data-split-media]{order:-1}}
/* Galerie 11.10.2026 — przyciski filtrów realizacji (runtime [data-gal-filter], np. gallery/worklog): ≥ 44 px, stan aria-pressed, fokus widoczny */
.pfy-gal-chip{min-height:44px;padding:.55rem 1.1rem;border-radius:9999px;border:1px solid var(--card-border);background:var(--card-bg);color:var(--heading-color);font-size:.9rem;font-weight:600;cursor:pointer;transition:background-color .2s,border-color .2s,color .2s}
.pfy-gal-chip:hover{border-color:var(--color-primary)}
.pfy-gal-chip[aria-pressed="true"]{background:var(--color-primary);border-color:var(--color-primary);color:var(--btn-text)}
/* ── Warstwy (11.10.2026, archetyp layered — szablon „Wycinanki”, docs §19). Grafiki z alfą wychodzą poza ekran i na sąsiednie sekcje;
   fotografie nie (zasada 11.10, walidator LY + visual-audit M18). Bez poziomego przewijania: main/stopka overflow-x:clip.
   Ruch: _global/scripts/layers.js (tylko transform/opacity, jeden rAF); wejście warstw = klasa .ly-pre zdejmowana przy pojawieniu się. */
body[data-gesture="layer-break"] main,body[data-gesture="layer-break"] footer{overflow-x:clip}
body[data-gesture="layer-break"] main>section{position:relative}
[data-layer-motion] [data-ly-depth],[data-layer-motion] [data-ly-float]{will-change:transform}
[data-ly-sat],[data-ly-img],[data-ly-shape],.ly-doodle{pointer-events:none}
[data-ly-sat]>*,[data-ly-img]>*,.ly-sh__media.ly-pre>*,.ly-sh__media>*{transition:opacity var(--ly-enter-ms,700ms) ease,transform var(--ly-enter-ms,700ms) var(--ly-ease,ease)}
.ly-pre>*{opacity:0;transform:translate3d(0,var(--ly-enter-y,24px),0) scale(var(--ly-enter-scale,1))}
.ly-stamp{display:flex;align-items:center;justify-content:center;aspect-ratio:1;width:100%;border-radius:9999px;background:var(--ly-dot,var(--color-accent));color:var(--btn-text);box-shadow:0 6px 14px -8px rgb(var(--scrim-rgb) / .45)}
.ly-stamp img,.ly-stamp__ico{width:52%;height:52%}
.ly-stamp__ico{stroke:currentColor}
@media(prefers-reduced-motion:reduce){[data-ly-sat]>*,[data-ly-img]>*,.ly-sh__media>*{transition:none}.ly-pre>*{opacity:1;transform:none}}

/* 12.10.2026: menu poziome, które się nie mieści (site-runtime.js „menu zwijane od progu”), zamienia się w przycisk ☰ na każdej
   szerokości; #mobile-menu otwarty przyciskiem pokazuje się mimo md:hidden/lg:hidden wariantu. */
html.pfy-nav-collapsed #nav-links:not(:has(> .pv-navc__brand)){display:none} /* logo w środku menu (centered-split) zostaje — wariant chowa same grupy linków */
html.pfy-nav-collapsed #menu-btn{display:flex!important}
html.pfy-nav-collapsed #mobile-menu:not(.hidden){display:block!important}
/* 12.10.2026 (reguła NF-b, 320 px): długa nazwa firmy w pasku (np. „Zakład Mechaniki Precyzyjnej” + telefon + motyw + ☰) wypychała
   przycisk menu poza ekran — na wąskim ekranie nazwa się zwęża i łamie, przyciski zostają w całości. */
@media (max-width:479px){
  #navbar :is(a,div,span):has(> [data-slot="companyName"]){min-width:0;flex-shrink:1}
  #navbar [data-slot="companyName"]{min-width:0;overflow-wrap:anywhere;font-size:min(1em,5.2vw)}
}
/* 12.10.2026 (NF-b): cena w karcie nigdy szersza niż karta — opisowa („wycena indywidualna”, merge → .pfy-price-text) mniejszym krojem,
   każda łamie się zamiast wypychać stronę w bok (strony sprzed republish: samo łamanie). */
[data-slot-item="price"]{overflow-wrap:break-word;min-width:0;max-width:100%}
/* 23.10.2026 (NF-e, przykład DE strony głównej: „Kundenbewertungen” w H2 na 344 px = przewijanie w bok): słowo dłuższe niż CAŁY nagłówek
   łamie się zamiast wypychać stronę; krótkie słowa bez zmian. break-word, nie anywhere: anywhere zmniejsza min-content w wierszach flex
   i łamało zwykłe „USŁUGA” w ciasnej karcie. Wiersze flex (nazwa + cena, ikona + tytuł) zawijają się same — featured-split, .pfy-ititle. */
:where(h1,h2,h3,h4,h5,h6,[data-slot-item="name"],[data-slot-item="title"],[data-slot-item="caption"]){overflow-wrap:break-word}
.pfy-price-text{font-size:clamp(1.125rem,1rem + .6vw,1.5rem)!important;line-height:1.25!important;white-space:normal!important;letter-spacing:0!important}
/* menu zwinięte na szerokim ekranie: panel przy przycisku ☰, nie lista na całą szerokość */
@media (min-width:768px){html.pfy-nav-collapsed #mobile-menu{max-width:24rem;margin-left:auto}}
/* 16.10.2026: tryb „Więcej” (site-runtime.js) — pozycje, które się nie mieszczą, tylko w panelu przycisku; przycisk z napisem „Więcej” */
html.pfy-nav-priority #nav-links .pfy-nav-overflow{display:none}
/* nazwa firmy ściska się, by zmieścić menu — stały odstęp, żeby nigdy nie stykała się z pierwszą pozycją (salon: „FRYZJERSKIO NASZYM”) */
#navbar #nav-links{margin-left:1rem}
html.pfy-nav-priority #menu-btn{display:inline-flex!important;flex-direction:row;align-items:center;gap:.35rem;font-size:.875rem;font-weight:500;color:inherit;white-space:nowrap}
html.pfy-nav-priority #menu-btn .hamburger-line{display:none}
html.pfy-nav-priority #menu-btn .pfy-more-label::after{content:"";display:inline-block;width:.45em;height:.45em;margin-left:.4em;border-right:2px solid currentColor;border-bottom:2px solid currentColor;transform:translateY(-.15em) rotate(45deg)}
html.pfy-nav-priority #menu-btn[aria-expanded="true"] .pfy-more-label::after{transform:translateY(.1em) rotate(-135deg)}
.pfy-more-label{display:none}
html.pfy-nav-priority .pfy-more-label{display:inline}
html.pfy-nav-priority #mobile-menu:not(.hidden){display:block!important}
html.pfy-nav-priority #mobile-menu .pfy-in-row{display:none!important}
@media (min-width:768px){html.pfy-nav-priority #mobile-menu{max-width:24rem;margin-left:auto}}
/* ── Napisy z okruszków (20.10.2026, site-runtime.js, body[data-text-fx="crumbs"]): tekst czeka niewidoczny (układ bez zmian), okruszki
   spadają na płótnie nad nim (miękka krawędź u góry rysowana w płótnie — bez maski CSS), potem tekst wraca, a płótno gaśnie ── */
body[data-text-fx] .pfy-crumb-wait{opacity:0}
body[data-text-fx] .pfy-crumb-done{transition:opacity .9s ease}
.pfy-crumbs{position:absolute;z-index:5;pointer-events:none;transition:opacity .9s ease}
.pfy-crumbs--out{opacity:0}
@media print{body[data-text-fx] .pfy-crumb-wait{opacity:1}}
/* ── Efekt-sygnatura „Pył” (21.10.2026, site-runtime.js, body[data-fx="dust"]): płótno drobinek w pierwszym ekranie, pod tekstem ── */
.pfy-fx-dust{position:absolute;inset:0;width:100%;height:100%;z-index:2;pointer-events:none}
@media print{.pfy-fx-dust{display:none}}
/* ── Efekty-sygnatury rodzin szablonu (21.10.2026, merge-effects.ts; DeepSeek 20.10) — warstwa ozdobna, reduced-motion = stan końcowy ── */
/* Linia: gałązka / ornament rysowany raz w pustym rogu pierwszego ekranu, kolor marki */
.pfy-fx-line{position:absolute;right:clamp(1rem,5vw,4rem);bottom:clamp(1rem,6vh,3.5rem);width:clamp(120px,22vw,320px);height:auto;z-index:2;pointer-events:none;fill:none;stroke:var(--primary-text);stroke-width:1.25;stroke-linecap:round;stroke-linejoin:round;opacity:.9}
.pfy-fx-line path{stroke-dasharray:1;stroke-dashoffset:1}
.pfy-fx-line--on path{animation:pfy-fx-draw 1.4s cubic-bezier(.33,0,.2,1) forwards}
@keyframes pfy-fx-draw{to{stroke-dashoffset:0}}
@media(max-width:479px){.pfy-fx-line{width:120px;opacity:.35;top:calc(var(--hm-nav,5rem) + .5rem);bottom:auto}}
@media(prefers-reduced-motion:reduce){.pfy-fx-line path{stroke-dashoffset:0;animation:none}}
/* Głębia: powolny najazd kamery na zdjęcie/film pierwszego ekranu + przyciemnienie pod paskiem menu (napisy menu czytelne na zdjęciu) */
@media(prefers-reduced-motion:no-preference){body[data-fx="depth"] [data-section="hero"] :is(.hm-media>.hm-tile,.hm-media>video,.hero-media){animation:pfy-fx-depth 24s ease-in-out 1.8s infinite alternate}}
@keyframes pfy-fx-depth{from{transform:scale(1)}to{transform:scale(1.06)}}
/* Album: kolejne zdjęcia z galerii przenikają w kadrze pierwszego ekranu */
.pfy-fx-album{position:absolute;inset:0;width:100%;height:100%;object-fit:cover;opacity:0;transition:opacity .9s ease}
.pfy-fx-album--on{opacity:1}
/* Reguła: kreska pod tytułem + numer i linia nad nagłówkiem sekcji (dokument) */
body[data-fx="rule"] main{counter-reset:pfy-sec}
body[data-fx="rule"] main section h2::before{counter-increment:pfy-sec;content:counter(pfy-sec,decimal-leading-zero);display:block;width:max-content;min-width:3rem;padding-top:.8rem;margin-bottom:.9rem;
  font:600 .75rem/1 system-ui,sans-serif;letter-spacing:.16em;color:var(--primary-text);opacity:0;transition:opacity .3s ease .25s,background-size .6s cubic-bezier(.33,0,.2,1);
  background:linear-gradient(var(--primary-text),var(--primary-text)) 0 0/0 1px no-repeat}
body[data-fx="rule"] main section h2.pfy-fx-rule--on::before{opacity:1;background-size:100% 1px}
body[data-fx="rule"] [data-section="hero"] h1::after{content:"";display:block;height:1px;width:0;margin-top:.45em;background:var(--primary-text)}
@media(prefers-reduced-motion:no-preference){body[data-fx="rule"] [data-section="hero"] h1::after{animation:pfy-fx-rule .5s cubic-bezier(.33,0,.2,1) .6s forwards}}
@media(prefers-reduced-motion:reduce){body[data-fx="rule"] [data-section="hero"] h1::after{width:6rem}}
@keyframes pfy-fx-rule{to{width:6rem}}
/* kreska pod tytułem po tej stronie, po której stoi tytuł (motyw: tekst do prawej / na środku) */
body[data-fx="rule"] [data-section="hero"]:is(.hm-ta-tr,.hm-ta-mr,.hm-ta-br) h1::after{margin-left:auto}
body[data-fx="rule"] [data-section="hero"]:is(.hm-ta-tc,.hm-ta-mc,.hm-ta-bc) h1::after{margin-left:auto;margin-right:auto}
/* Oddech: kształt zdjęcia pierwszego ekranu powoli się zmienia (tylko komputer — przemalowanie dużego obrazu) */
@media(min-width:1024px) and (prefers-reduced-motion:no-preference){body[data-fx="breath"] [data-section="hero"] .hm-media>.hm-tile{animation:pfy-fx-breath 18s ease-in-out infinite alternate}}
@keyframes pfy-fx-breath{from{border-radius:50% 50% 46% 54% / 46% 52% 48% 54%}to{border-radius:46% 54% 52% 48% / 54% 46% 52% 48%}}
@media(prefers-reduced-motion:reduce){
  .pfy-fx-line--on path{animation:none;stroke-dashoffset:0}
  body[data-fx="depth"] [data-section="hero"] :is(.hm-media>.hm-tile,.hm-media>video,.hero-media){animation:none}
  body[data-fx="rule"] [data-section="hero"] h1::after{animation:none;width:6rem}
  body[data-fx="breath"] [data-section="hero"] .hm-media>.hm-tile{animation:none}
}

/* ── Niski ekran (21.10.2026, telefon POZIOMO 873×340 — zrzut Piotra i recenzja zewnętrzna „ogromna pusta przestrzeń”): sekcje miały
   po 96 px odstępu u góry i u dołu (192 px między sekcjami = ponad połowa ekranu) i nagłówki 48 px. Odstęp z wysokości ekranu,
   nagłówek sekcji w skali ekranu; pierwszy ekran ma własny układ poziomy (hero/motif, hero/scene). ── */
@media (orientation:landscape) and (max-height:560px),(orientation:landscape) and (max-width:1023.98px){ /* + tablet poziomo (visual-qa 820×600: 240–264 px) */
  /* tylko sekcje z odstępem NA KORZENIU (klasa py-/pt-): 4 układy trzymają go na wewnętrznym divie i dostawały +44 px (audyt 21.10, 2-P1) */
  /* + układy z odstępem w CSS wariantu na korzeniu (audyt 2: aside, offset, frames, sequence, folio, reel, spread, edge-note) */
  main [data-section]:not([data-section="hero"]):is([class*="py-"],[class*="pt-"],[data-variant="aside"],[data-variant="offset"],[data-variant="frames"],[data-variant="sequence"],[data-variant="folio"],[data-variant="reel"],[data-variant="spread"],[data-variant="edge-note"]){padding-top:clamp(1.75rem,9svh,4.5rem);padding-bottom:clamp(1.75rem,9svh,4.5rem)}
  /* 23.10.2026 (visual-qa telefon poziomo 873×393: 141–196 px między sekcjami = 36–50 % ekranu): 13svh → 9svh, minimum 1.75rem */
  /* + odstęp na wewnętrznym bloku sekcji (tailblocks: div.pt-20/py-24) — jak na telefonie pionowo */
  main>section[data-section]:not([data-section="hero"])>div:is(.py-20,.py-24,.py-28,.pt-20,.pt-24,.pt-28){padding-top:clamp(1.75rem,9svh,4.5rem)}
  main>section[data-section]:not([data-section="hero"])>div:is(.py-20,.py-24,.py-28,.pb-20,.pb-24,.pb-28){padding-bottom:clamp(1.75rem,9svh,4.5rem)}
  main [data-section]:not([data-section="hero"]) h2{font-size:clamp(1.75rem,4vw,2.25rem);line-height:1.15}
  /* editorial ma własny „oddech” (wyższa specyficzność, wyżej w pliku) — na niskim ekranie skalowany tak samo z wysokości (audyt 2-P2) */
  body[data-signature="editorial"] main>section[data-section]:not(#hero){padding-block:clamp(2.75rem,13svh,4.5rem)}
  /* nagłówek sekcji → treść: mb-16 (64 px) z sm: = wartość komputerowa na telefonie poziomo (audyt 2-P5) */
  main [data-section]:not([data-section="hero"]) :is(div,header):has(>h2){margin-bottom:clamp(1.25rem,6svh,2.25rem)}
}

