/* ============================================================================
   plon/multipage — sections.css (WWW-01)

   Klasy komponentów przeniesione z design-hub/assets/styleguide.css (sekcja
   KOMPONENTY) + chrome witryny (nav/footer). WYŁĄCZNIE var(--token) z _tokens.css
   (brand single-source). ZERO hardkodu kolorów/fontów — bramka WA04 blokuje
   #hex / rgb() / hsl(). Subtelne półprzezroczyste tła = --border-soft/--divider
   (tokeny), placeholdery zdjęć = --plon-gray-850.

   Bazowa typografia (h1/h2/p/.lead/.eyebrow/.haslo/blockquote) żyje w _tokens.css
   (ELEMENT DEFAULTS) — tu tylko warstwa komponentów i layout.
   ============================================================================ */

/* === A11Y: kontrast tekstu pomocniczego (WWW-09) =========================
   Brandowe --fg-3 = --plon-gray-500 (#6B6B6B) daje na czerni tylko 3.71:1 —
   poniżej WCAG AA 4.5:1 dla drobnego tekstu (podpisy, noty, etykiety stopki,
   opisy dropdownu). Podnosimy tercjarny tekst do --plon-gray-400 (#9A9A9A ≈7:1)
   WYŁĄCZNIE w tej instancji (override :root; brand-token bez zmian → zero blast-radius
   na inne instancje/goldeny). Hierarchia zachowana: fg-1 > fg-2(#C4C4C4) > fg-3(#9A9A9A). */
:root { --fg-3: var(--plon-gray-400); }

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

.container {
  width: 100%;
  max-width: var(--max-w-content);
  margin: 0 auto;
  padding: 0 var(--space-6);
}

.section { padding: var(--space-9) 0; }
.section + .section { padding-top: 0; }

img { max-width: 100%; height: auto; display: block; }
a { color: inherit; text-decoration: none; }

/* === REVEAL-ON-SCROLL + count-up (WWW-13) =================================
   Wzorzec: onepager.css:1372-1379 (1:1 loci). Utility generyczna: `[data-reveal]`
   + `.reveal`/`.reveal-stagger` na dowolnym kontenerze, `assets/js/reveal.js`
   dodaje `.is-in` przez IntersectionObserver (threshold .25) i odpala count-up
   na `.counter` (data-count/data-prefix/data-suffix) wewnątrz.
   A11y/SEO: bez JS `<noscript>` w layout.twig ujawnia oba warianty (opacity:1) —
   treść nigdy nie zostaje ukryta (opacity:0) dla botów/no-JS. =================== */
.reveal { opacity: 0; transform: translateY(20px); transition: opacity var(--dur-slow) var(--ease-out-quart), transform var(--dur-slow) var(--ease-out-quart); }
.reveal.is-in { opacity: 1; transform: none; }
.reveal-stagger > * { opacity: 0; transform: translateY(20px); transition: opacity var(--dur-slow) var(--ease-out-quart), transform var(--dur-slow) var(--ease-out-quart); }
.reveal-stagger.is-in > * { opacity: 1; transform: none; }
.reveal-stagger.is-in > *:nth-child(1) { transition-delay: 0ms; }
.reveal-stagger.is-in > *:nth-child(2) { transition-delay: 80ms; }
.reveal-stagger.is-in > *:nth-child(3) { transition-delay: 160ms; }
.reveal-stagger.is-in > *:nth-child(4) { transition-delay: 240ms; }

/* === AKCENT SUBBRANDU ====================================================
   Na stronach inicjatyw layout ustawia [data-sb] na <body> (front.subbrand:
   camp/mlody/festiwal/air). Wtedy akcent całej strony = kolor subbrandu
   (--sb-color/--sb-on z _tokens.css), zamiast domyślnego mintu — jednym
   remapem obejmuje WSZYSTKIE sekcje (hero, value-cards, cta, event-list…).
   Strony bez data-sb (subbrand:null — O nas / Współpraca / Kontakt) zostają
   na mincie (--accent z tokenów). Zero hardkodu HEX — wyłącznie tokeny (WA04). */
[data-sb] {
  --accent:       var(--sb-color);
  --accent-hover: var(--sb-color);
  --accent-fg:    var(--sb-on);
  --kv-color:     var(--sb-color); /* recolor warstwy dekoracyjnej KV (WWW-12) */
}

/* === PRYMITYWY: przyciski / linki ======================================= */
.btn {
  display: inline-flex; align-items: center; gap: 10px;
  padding: 14px 22px; border: 0;
  background: var(--accent); color: var(--accent-fg);
  font-family: var(--font-sans); font-weight: 700; font-size: 14px;
  letter-spacing: .02em; cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out-quart);
}
.btn:hover { background: var(--accent-hover); }
.btn.ghost { background: transparent; color: var(--fg-1); border: 1px solid var(--fg-1); }
.btn.ghost:hover { background: var(--border-soft); }
.btn.dark { background: var(--plon-black); color: var(--fg-1); border: 1px solid var(--border); }
.btn.dark:hover { background: var(--plon-graphite); }
.btn.block { justify-content: center; width: 100%; }
.btn .arrow { width: 14px; height: 10px; flex: none; }

.tlink {
  display: inline-flex; align-items: center; gap: 8px;
  color: var(--fg-1); font-weight: 600; font-size: 13px;
  border-bottom: 1px solid transparent; padding-bottom: 2px;
  transition: color var(--dur-fast) var(--ease-out-quart), border-color var(--dur-fast) var(--ease-out-quart);
}
.tlink:hover { color: var(--accent-text); border-bottom-color: var(--accent); }
.tlink .arrow { width: 14px; height: 10px; }

.cta-row, .actions { display: flex; gap: 14px; flex-wrap: wrap; }

/* eyebrow (augmentuje bazę z _tokens.css: inline-flex + kropka akcentu) */
.eyebrow { display: inline-flex; align-items: center; }
.eyebrow .dot { display: inline-block; width: 6px; height: 6px; background: var(--accent); margin-right: 10px; flex: none; }

.badge {
  font-size: 10px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
  color: var(--accent-text); border: 1px solid var(--accent); padding: 2px 6px;
}
.badge.soon { color: var(--fg-3); border-color: var(--fg-3); }

/* logo — biała płytka (marka: kontrast na czerni) */
.plate { background: var(--plon-white); display: inline-flex; align-items: center; padding: 7px 12px; }
.plate img { height: 22px; width: auto; }
.plate.lg img { height: 32px; }

/* nagłówek sekcji (eyebrow + h2) — używany przez value-cards / two-cols */
.section-heading { margin-bottom: var(--space-6); display: flex; flex-direction: column; gap: 12px; }
.section-heading h2 { font-size: clamp(28px, 3vw, 44px); letter-spacing: -.025em; line-height: 1.05; }
.section-heading .accent { font-family: var(--font-serif); font-style: italic; color: var(--accent-text); }

/* =========================================================================
   NAWIGACJA (desktop + mobilny overlay)
   Wzorzec: design-hub navbar.html / nav-mobile.html + _ref/index-prototype.html
   ========================================================================= */
.nav {
  position: sticky; top: 0; z-index: 50;
  background: color-mix(in srgb, var(--bg) 85%, transparent);
  backdrop-filter: blur(8px) saturate(140%);
  -webkit-backdrop-filter: blur(8px) saturate(140%);
  border-bottom: 1px solid var(--border);
}
.nav-inner { display: flex; align-items: center; gap: 28px; height: 68px; }
.nav-logo { display: inline-flex; align-items: center; }
.nav-logo .plate img { height: 29px; } /* +30% logo w nagłówku (22px × 1.3 ≈ 29px), scope: tylko nav — parytet onepager (WWW-44) */
.nav-logo .wordmark { font-size: 20px; color: var(--fg-1); }
.nav-menu { display: flex; align-items: center; gap: 4px; margin-right: auto; }
.nav-link {
  padding: 8px 12px; font-size: 14px; color: var(--fg-1);
  display: inline-flex; gap: 6px; align-items: center;
  background: transparent; border: 0; font-family: var(--font-sans); cursor: pointer;
}
.nav-link:hover, .nav-link.active { color: var(--accent-text); }
.nav-link .chev { width: 10px; height: 10px; transition: transform var(--dur-fast) var(--ease-out-quart); }

.nav-item { position: relative; }
.nav-item[data-open="true"] .chev { transform: rotate(180deg); }

/* WWW-85→WWW-91 (fix, 2026-07-30): .nav jest position:sticky;top:0 — zasłania GÓRĘ viewportu
   niezależnie od wysokości sekcji, więc skok do KAŻDEJ kotwicy sekcji ląduje pod navem, nie tylko
   #sponsoring/#partnerstwo. WWW-85 dodało scroll-margin-top TYLKO dla tych dwóch zahardkodowanych
   ID (content/wspolpraca.md) — każda kolejna kotwica (o-mlodym, o-podcascie, o-plon, inicjatywy,
   kalendarium, wartosci, wartosci-onas, prelegenci, bilety, patronat, formularz) cicho wracała do
   scroll-margin-top:0. Zmierzony objaw (WWW-91, kontrola kliknięcia „Czym jest Młody PL:ON" na
   /mlody): scrollY 0→710, getComputedStyle('#o-mlodym').scrollMarginTop === "0px", .nav height 69
   sticky → nagłówek sekcji manifesto lądował ucięty za paskiem nawigacji.
   Reguła generalizowana na `section[id]` — obejmuje KAŻDĄ sekcję renderującą `anchor:` jako `id`
   na tagu <section> (patrz templates/partials/sections/*.twig, `id="{{ section.anchor }}"`),
   niezależnie od klasy (idea.twig renderuje `section-idea` BEZ bazowej `.section`, więc selektor
   celuje w TAG, nie w klasę). Wartość i wyliczenie BEZ ZMIAN: wysokość .nav-inner (68px) +
   border-bottom (1px) + oddech var(--space-4).
   Wyjątek :not() — .section-event-list/.section-schedule/.section-location mają WŁASNY, starszy
   hardcoded scroll-margin-top:80px (linie ~1067/1235/1258, INNE wyliczenie/powód) — bez wyjątku
   [id] (specificity 0,1,1) cicho nadpisałby ich 80px, mimo że te sekcje nie mają dziś aktywnego
   `anchor` (schedule/location ukryte WWW-42/89, event-list „najbliższe" bez id na obu stronach). */
section[id]:not(.section-event-list):not(.section-schedule):not(.section-location) {
  scroll-margin-top: calc(68px + 1px + var(--space-4));
}

/* mega-dropdown „Inicjatywy" */
/* WWW-85 (OG-01): opisy w .dd-list łamały się na 3 wiersze (potwierdzone wzrokowo —
   „Cykliczny barcamp — biznes, samorząd, studenci" w kolumnie ~186px). Panel
   440px→560px + kolumny 1fr 1fr→minmax(0,1fr) minmax(0,1.3fr) (dd-list dostaje
   więcej — .dd-intro ma tylko eyebrow/h4/1 akapit, mieści się i węziej) razem
   dają kolumnie opisu ~224px tekstu (560-padding44-gap24, split 1:1.3, minus
   padding pozycji 28 + strzałka 14 + gap 12) → przy ~6px/znak (12px sans) to
   ~37 znaków/wiersz, najdłuższy wpis (44 znaki) mieści się w 2 wierszach. */
.dropdown {
  position: absolute; top: calc(100% + 10px); left: 0;
  min-width: 560px; background: var(--bg-elevated);
  border: 1px solid var(--border); padding: 22px;
  display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1.3fr); gap: 24px;
  opacity: 0; visibility: hidden; transform: translateY(-6px);
  transition: opacity var(--dur-fast) var(--ease-out-quart), transform var(--dur-fast) var(--ease-out-quart), visibility var(--dur-fast);
  z-index: 60;
}
.nav-item:hover .dropdown,
.nav-item:focus-within .dropdown,
.nav-item[data-open="true"] .dropdown { opacity: 1; visibility: visible; transform: translateY(0); }
.dd-intro h4 { font-size: 18px; margin: 10px 0 8px; }
.dd-intro p { font-size: 13px; color: var(--fg-3); line-height: 1.5; margin-bottom: 12px; }
/* WWW-85 (OG-01): gap 2px→6px (oddech między pozycjami), padding pozycji 12/14→14/16
   (więcej miejsca na 2-wierszowy opis bez ściśnięcia), interlinia .desc 1.4→1.5. */
.dd-list { display: flex; flex-direction: column; gap: 6px; }
.dd-item {
  display: flex; align-items: center; gap: 12px; padding: 14px 16px;
  border: 1px solid transparent;
  transition: border-color var(--dur-fast) var(--ease-out-quart), background var(--dur-fast) var(--ease-out-quart);
}
.dd-item:hover { border-color: var(--border); background: var(--plon-black); }
.dd-item .dd-name { font-size: 15px; font-weight: 700; color: var(--fg-1); }
.dd-item .meta { display: flex; flex-direction: column; gap: 4px; min-width: 0; margin-right: auto; }
.dd-item .meta .desc { font-size: 12px; color: var(--fg-3); line-height: 1.5; }
.dd-item .arrow { width: 14px; height: 10px; color: var(--fg-3); flex: none; transition: transform var(--dur-fast) var(--ease-out-quart), color var(--dur-fast); }
.dd-item:hover .arrow { transform: translateX(4px); color: var(--accent-text); }

/* WWW-85 (OG-03): .nav-cta zostaje bez zmian po usunięciu reguły przełącznika
   języka (markup skasowany w WWW-86) — kontener już był flex/gap (nie
   space-between), więc odjęcie jednego dziecka nie rozjeżdża pozostałych
   (przycisk CTA), tylko usuwa martwą przestrzeń po przełączniku. */
.nav-cta { display: flex; align-items: center; gap: 16px; }

/* hamburger + overlay (<1080px) */
.nav-toggle { display: none; width: 44px; height: 44px; align-items: center; justify-content: center; background: transparent; border: 0; cursor: pointer; }
.nav-toggle .bars { position: relative; display: block; width: 22px; height: 2px; background: var(--fg-1); transition: background var(--dur-instant); }
.nav-toggle .bars::before, .nav-toggle .bars::after { content: ""; position: absolute; left: 0; width: 22px; height: 2px; background: var(--fg-1); transition: transform var(--dur-fast) var(--ease-out-quart); }
.nav-toggle .bars::before { top: -7px; } .nav-toggle .bars::after { top: 7px; }
body.menu-open .nav-toggle .bars { background: transparent; }
body.menu-open .nav-toggle .bars::before { transform: translateY(7px) rotate(45deg); }
body.menu-open .nav-toggle .bars::after { transform: translateY(-7px) rotate(-45deg); }

.mobile-overlay {
  position: fixed; inset: 0; z-index: 55; background: var(--plon-black);
  display: flex; flex-direction: column; padding: 92px 32px 40px;
  transform: translateY(-100%); opacity: 0; pointer-events: none;
  transition: transform var(--dur-base) var(--ease-out-expo), opacity var(--dur-base);
  overflow-y: auto;
}
body.menu-open .mobile-overlay { transform: translateY(0); opacity: 1; pointer-events: auto; }
.mobile-overlay .mob-link { font-size: 26px; font-weight: 700; letter-spacing: -.02em; color: var(--fg-1); padding: 14px 0; border-bottom: 1px solid var(--border-soft); display: flex; justify-content: space-between; align-items: center; }
.mobile-overlay .mob-link:hover { color: var(--accent-text); }
.mobile-overlay .mob-sub { display: grid; gap: 2px; padding: 6px 0 14px; }
.mobile-overlay .mob-sub a { font-size: 15px; color: var(--fg-2); padding: 9px 0 9px 16px; border-left: 1px solid var(--border); }
.mobile-overlay .mob-sub a:hover { color: var(--accent-text); border-color: var(--accent); }
/* WWW-85 (OG-03): .mob-foot zostaje bez zmian po usunięciu reguły przełącznika
   języka mobile (markup skasowany w WWW-86) — kontener już był column/gap
   (nie space-between), więc odjęcie jednego dziecka nie rozjeżdża pozostałych
   (przycisk CTA mobile), tylko usuwa martwą przestrzeń. */
.mobile-overlay .mob-foot { margin-top: auto; padding-top: 28px; display: flex; flex-direction: column; gap: 16px; }
.mobile-overlay .mob-foot .btn { justify-content: center; }

/* =========================================================================
   SEKCJA: hero (eyebrow · h1 + serif accent · lead · cta · meta-row)
   Wzorzec: hero-main.html
   ========================================================================= */
.section-hero { position: relative; overflow: hidden; }
.section-hero h1 { font-size: clamp(44px, 5.6vw, 80px); font-weight: 800; line-height: .98; letter-spacing: -.03em; margin: 18px 0 0; }
.section-hero h1 .accent { font-family: var(--font-serif); font-style: italic; font-weight: 700; color: var(--accent-text); }
.section-hero .lead { margin-top: 24px; max-width: 560px; }
.section-hero .cta-row { margin-top: 28px; }
.meta-row { margin-top: 36px; display: flex; gap: 40px; flex-wrap: wrap; }
.meta-row .item { display: flex; flex-direction: column; }
.meta-row .v { font-weight: 800; font-size: 30px; letter-spacing: -.02em; }
.meta-row .v .accent { color: var(--accent-text); }
.meta-row .l { font-size: 12px; color: var(--fg-3); letter-spacing: var(--tracking-caps); text-transform: uppercase; margin-top: 8px; }

/* =========================================================================
   SEKCJA: hero — prawa kolumna (foto dokumentalne 4:5 + karta hero-festival, WWW-33)
   Wzorzec: onepager.css:297-432 (.hero-inner/.hero-right/.photo/.hero-festival).
   `.hero-copy` = istniejąca lewa treść (eyebrow/h1/lead/cta/meta-row) bez zmian
   wizualnych — grid tylko rozstawia dwie kolumny; mobile (≤1080px) składa w 1.
   ========================================================================= */
.hero-inner {
  display: grid;
  grid-template-columns: 1.15fr 0.85fr;
  gap: var(--space-7, 40px);
  /* Wyrównanie do GÓRY (korekta wizualna właściciela 2026-07-30): treść hero ma zaczynać się
     na wysokości górnej krawędzi zdjęcia w prawej kolumnie. Wcześniej `end` dociskało
     eyebrow/h1/lead do dołu boksa, zostawiając pustkę nad tekstem. */
  align-items: start;
}
.hero-copy { max-width: 720px; }

.hero-right {
  position: relative;
  align-self: stretch;
  display: flex;
  flex-direction: column;
  gap: 16px;
}
.hero-right .photo {
  background: var(--plon-gray-800, var(--plon-graphite));
  position: relative;
  overflow: hidden;
  border: 1px solid var(--border);
  aspect-ratio: 4 / 5;
  min-height: 280px;
}
.hero-right .photo img { width: 100%; height: 100%; object-fit: cover; display: block; }

.hero-festival {
  background: var(--plon-graphite);
  border: 1px solid var(--border);
  padding: 24px;
  display: flex;
  flex-direction: column;
  gap: 14px;
}
.hero-festival .top { display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; }
.hero-festival .label { font-size: 11px; letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--sb-color, var(--accent-text)); }
.hero-festival h3 { font-size: 22px; font-weight: 700; letter-spacing: -.015em; margin-top: 6px; }
.hero-festival .when { display: flex; gap: 24px; font-size: 13px; color: var(--fg-2); }
.hero-festival .when span:nth-child(2) { border-left: 1px solid var(--border); padding-left: 18px; }
.hero-festival .when strong { color: var(--fg-1); font-weight: 600; }
.hero-festival .price-row { display: flex; justify-content: space-between; align-items: center; margin-top: 4px; padding-top: 16px; border-top: 1px solid var(--border); }
.hero-festival .price-row .is-soon { font-size: 12px; color: var(--fg-3); }

/* Sub-brand sig — plate + kolorowy kartusz z nazwą (onepager.css:58-79,661-671) */
.sig { display: inline-flex; align-items: center; }
.sig .name { font-family: var(--font-serif); font-style: italic; font-weight: 700; color: var(--accent-text); margin-left: -10px; letter-spacing: -.01em; line-height: 1; font-size: 28px; }
.sig .plate img { height: 22px; }
.sig.kartusz { align-items: stretch; }
.sig.kartusz .plate { align-items: center; }
.sig.kartusz .name {
  display: inline-flex; align-items: center;
  background: var(--sb-color, var(--accent)); color: var(--sb-on, var(--accent-fg));
  margin-left: 0; padding: 0 12px; line-height: 1; font-style: normal;
}
.sig.kartusz[data-sb="festiwal"] .name { font-family: var(--font-serif); font-style: italic; font-weight: 700; }
/* Warianty .lg (kartusz nagłówka karty, WWW-34) i .reversed (Młody — plate po
   prawej, by nie dublować wordmarku PL:ON, wzorem onepager.css:78-81,681). */
.sig.lg .plate img { height: 32px; }
.sig.lg .name { font-size: 36px; }
/* Wariant .xl — samodzielny lockup w prawej kolumnie hero (hero.twig `right.lockup`).
   Prawa kolumna hero ma na desktopie 462 px, a na podstronach bez zdjęcia stała pusta
   (zmierzone 2026-07-30: 542 px niewykorzystanej szerokości na /festiwal). Kartusz w tej
   skali wypełnia ją jako sygnatura wydarzenia. Skala rośnie płynnie z viewportem, żeby przy
   1080 px (złożenie do jednej kolumny) nie przeskakiwała skokowo. */
.sig.xl .plate img { height: clamp(38px, 3.4vw, 52px); }
.sig.xl .name { font-size: clamp(42px, 3.9vw, 60px); padding: 0 16px; }
/* Lockup na PEŁNĄ szerokość kolumny — równa krawędź ze zdjęciem pod spodem (korekta
   właściciela 2026-07-30: „logo na taką samą szerokość jak zdjęcie"). Kartusz jest domyślnie
   `inline-flex`, więc szerokość dyktowała mu długość słowa (zmierzone: 380 px przy zdjęciu
   460 px). Tutaj rozciąga go plakietka o stałej szerokości + pole nazwy przejmujące resztę
   (`flex: 1`), dzięki czemu obie krawędzie — lockupu i zdjęcia — schodzą się na każdej
   szerokości, bez wpisywania sztywnych pikseli. Nazwa zostaje wyśrodkowana w swoim polu. */
.hero-lockup { padding: 8px 0; }
.hero-lockup .sig.xl { display: flex; width: 100%; }
.hero-lockup .sig.xl .name { flex: 1 1 auto; justify-content: center; }
.sig.kartusz.reversed { flex-direction: row-reverse; }
.sig.kartusz.reversed .name { margin: 0; }

@media (max-width: 1080px) {
  .hero-inner { grid-template-columns: 1fr; }
  .hero-right { margin-top: 40px; }
}

/* =========================================================================
   DEKORY: hero-kv (bogaty KV-99 supporting, powolny obrót) + sig-lines (fale)
   Wzorzec: onepager.css (.hero-kv kv-spin-wrap > .kv/.kv__art) + design-system kv-99.
   Heksagon = <img> kv-99-supporting.svg (wielokolorowy komponent DS, kolory w SVG —
   poza skanem WA04). --kv-color (bazowo --plon-mint, na [data-sb] → --sb-color)
   obsługuje pozostałe recolorable prymitywy KV (stroke-inline / kv-accent).
   sig-lines = bespoke line-art (inline w hero.twig).

   ROZDZIAŁ transformów (WWW-33 fix, regresja QA): `.hero-kv` = WRAPPER —
   kv-motion.js ustawia na nim `transform: translate3d(...)` (parallax, case
   specjalny dla klasy `.hero-kv`). Gdyby ten sam element niósł też CSS
   `animation: kv-spin` (rotate), inline transform z JS nadpisywałby/gubił obrót
   (jeden property `transform` na element — animacja "zjada" translację lub
   odwrotnie w zależności od kolejności recalculacji). Dlatego obrót żyje na
   WEWNĘTRZNYM `.hero-kv-art` (sam obraz) — dwa elementy, dwa niezależne
   transformy, oba widoczne jednocześnie (wzorzec onepagera: kv-spin-wrap
   [data-parallax] > svg.kv[animation]). ========================================================================= */
:root { --kv-color: var(--plon-mint); }

.hero-kv {
  position: absolute; top: -120px; right: -200px;
  width: 880px; height: 880px; z-index: 0;
  display: block; pointer-events: none; opacity: .22;
}
.hero-kv-art {
  display: block; width: 100%; height: 100%;
  transform-origin: 50% 50%;
  animation: kv-spin var(--kv-motion-spin, 40s) linear infinite;
}
@keyframes kv-spin { to { transform: rotate(360deg); } }
/* Recolor per subbrand (WWW-68 przeróbka, wytyczne.md §3.2 — CSS-maska SCOPED
   wyłącznie do [data-sb="camp"]/[data-sb="mlody"]): PIERWSZA iteracja WWW-68
   maskowała `.hero-kv-art` GLOBALNIE (wszystkie strony), co spłaszczyło
   świadomie wielobarwny kv-99-supporting.svg na home/festiwal do flat mint —
   REGRESJA, cofnięta. Domyślnie (home/festiwal/air/pozostałe) `.hero-kv-art`
   (<img>) renderuje się bez zmian, jak wyżej. Tylko camp/mlody: <img> chowa
   się, a zawsze-obecny sibling `.hero-kv-art-sb` (pusty <div>, hero.twig)
   dostaje background=--sb-color maskowany konturem TEGO SAMEGO pliku (zero
   nowych assetów) — camp=orange, mlody=purple. */
[data-sb="camp"] img.hero-kv-art,
[data-sb="mlody"] img.hero-kv-art { display: none; }
[data-sb="camp"] .hero-kv-art-sb,
[data-sb="mlody"] .hero-kv-art-sb {
  display: block; width: 100%; height: 100%;
  transform-origin: 50% 50%;
  animation: kv-spin var(--kv-motion-spin, 40s) linear infinite;
  background: var(--sb-color);
  -webkit-mask: url(../key-visuals/kv-99-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-99-supporting.svg) center/contain no-repeat;
}
@media (max-width: 1080px) {
  .hero-kv { top: -80px; right: -260px; width: 620px; height: 620px; opacity: .14; }
}
/* Wariant LEWO (WWW-53, opt-in `section.kv_side`) — defensywny: hero=PRAWO na home i festiwalu
   dziś (kv_side niezdefiniowany/„right"), wariant gotowy pod przyszłą podstronę z hero od lewej. */
.hero-kv--left { left: -200px; right: auto; }
@media (max-width: 1080px) {
  .hero-kv--left { left: -260px; right: auto; }
}
.section-hero .container { position: relative; z-index: 1; }
.section-hero .sig-lines { z-index: 1; }
/* Glow miękki hero (WWW-53, §3.4): krawędź prawa (kv_side domyślne), za treścią (z-index:0),
   NIE łapany przez `.section-hero .container`/`.sig-lines` z-index:1. */
.section-hero::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: radial-gradient(640px 440px at 100% 30%, color-mix(in srgb, var(--kv-color) 16%, transparent), transparent 60%);
}

.sig-lines {
  position: absolute; left: 0; right: 0; bottom: 0;
  width: 100%; height: 120px;
  pointer-events: none;
}
.sig-lines svg { width: 100%; height: 100%; display: block; }
@keyframes drift {
  0%   { transform: translateX(0); }
  100% { transform: translateX(-100px); }
}
.sig-lines .drift-a { animation: drift 22s linear infinite; }
.sig-lines .drift-b { animation: drift 32s linear infinite reverse; }

/* =========================================================================
   SEKCJA: factbar (infografika liczbowa — serif mint)
   Wzorzec: stats.html (.stats/.stat)
   ========================================================================= */
/* WWW-88 (ONA-02): kotwica pozycjonowania dla `.sig-lines` (opt-in `factbar.sig_lines`,
   templates/partials/sections/factbar.twig) — `.sig-lines` jest `position: absolute; bottom: 0`
   (wyżej w tym pliku) i bez pozycjonowanego przodka (position != static) kotwiczy się do
   initial containing block, NIE do tej sekcji. Zmierzony objaw (kontroler, Chrome @1440,
   getBoundingClientRect po `.is-in`): `.section-factbar` bez tej reguły miała `position: static`,
   zakres y 820–1076; `.stats` kończyła się na y=980; `.sig-lines` renderowała się na y 780–900 —
   czyli NAD sekcją i PRZEZ liczby, zamiast pod nimi (insideSection: false). Nie kasuj tej reguły
   jako „zbędnej" — bez niej fala wraca do złego miejsca. Wzorzec identyczny jak przy innych
   sekcjach z overlayem absolutnym (`.section-hero`, `.manifesto.has-kv`, `.two-cols.has-kv`…). */
.section-factbar { position: relative; }
/* auto-fit: factbar dopasowuje się do liczby statów (4 na /o-nas, 3 na /wspolpraca)
   bez pustej komórki; puste tory auto-fit kolapsują (WWW-03). */
.stats { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: 1px; background: var(--border); border: 1px solid var(--border); }
.stat { background: var(--plon-black); padding: 28px 22px; }
.stat .n { font-family: var(--font-serif); font-style: italic; font-weight: 700; font-size: 48px; color: var(--accent-text); line-height: 1; }
/* WWW-85 (ONA-03): factbar.twig NIE nadaje `.counter` wartościom nienumerycznym
   (factbar.twig:19 — regex `/^\d+\+?$/`, np. „poza metropoliami" na /o-nas) —
   ten brak jest haczykiem do selekcji: `.n:not(:has(.counter))` łapie WYŁĄCZNIE
   nienumeryczne wartości, liczby (.counter) zostają przy 48px. clamp(24px,2.4vw,34px)
   dobrane tak, by najdłuższa fraza z ewidencji mieściła się w komórce siatki
   auto-fit(160px,1fr) bez wyjścia poza ramkę; overflow-wrap:anywhere = zabezpieczenie
   na wypadek jeszcze dłuższej frazy w treści (fala 3). */
.stat .n:not(:has(.counter)) { font-size: clamp(24px, 2.4vw, 34px); line-height: 1.1; overflow-wrap: anywhere; }
.stat .l { font-size: 12px; color: var(--fg-3); margin-top: 10px; line-height: 1.4; }

/* =========================================================================
   SEKCJA: manifesto (pull statement serif italic + body prozy)
   Wzorzec: pullquote.html (.pull)
   ========================================================================= */
.manifesto .pull { font-family: var(--font-serif); font-style: italic; font-weight: 700; font-size: clamp(28px, 3.4vw, 48px); line-height: 1.12; letter-spacing: -.015em; margin: 0; max-width: 820px; }
.manifesto .pull .accent, .manifesto .pull em { color: var(--accent-text); font-style: italic; }
.manifesto .manifesto-body { margin-top: 24px; max-width: 720px; color: var(--fg-2); }
.manifesto .manifesto-body p { margin: 0 0 14px; line-height: 1.6; }
.manifesto .manifesto-body p:last-child { margin-bottom: 0; }
/* Zdjęcie pod prozą manifestu (`foto`, opt-in — patrz manifesto.twig). Kadr POZIOMY 16:9 na pełną
   szerokość kontenera; `object-fit: cover` na wypadek pliku o innej proporcji (nie rozciągamy).
   Ramka jak przy pozostałych zdjęciach instancji (.hero-right .photo, .idea-foto). */
/* Wariant z ilustracją: proza po lewej, zdjęcie po prawej. Siatka włącza się TYLKO przy
   `.manifesto--foto` (klasa wychodzi z partiala wyłącznie gdy sekcja ma `foto`), więc manifest
   bez zdjęcia (/wspolpraca, /mlody, /festiwal) renderuje się bez zmiany. Kolumny 1.15/0.85 jak
   w hero — tekst zostaje wiodący. `.pull` traci wtedy własne `max-width`, bo szerokość dyktuje
   już kolumna siatki. */
/* `grid-template-rows: auto 1fr` jest tu KONIECZNE: zdjęcie rozpina się na oba wiersze
   (`grid-row: 1 / -1`), więc bez jawnej definicji przeglądarka rozdziela jego wysokość
   między wiersze i rozpycha pierwszy — między hasłem a prozą powstawała luka ~185 px
   (zmierzone). Pierwszy wiersz ma być wysokości hasła, reszta idzie do drugiego. */
.manifesto--foto { display: grid; grid-template-columns: 1.15fr 0.85fr; grid-template-rows: auto 1fr; column-gap: var(--space-7, 48px); align-items: start; }
.manifesto--foto .pull { grid-column: 1; max-width: none; }
.manifesto--foto .manifesto-body { grid-column: 1; max-width: none; }
/* Proporcja slotu = proporcja PLIKU (16:9, kadr poziomy przygotowany pod tę sekcję). Slot
   pionowy przycinałby boki zdjęcia, a właściciel prosił wprost o kadr poziomy. */
.manifesto-foto { grid-column: 2; grid-row: 1 / -1; align-self: start; margin: 0; aspect-ratio: 16 / 9; overflow: hidden; border: 1px solid var(--border); background: var(--plon-gray-800, var(--plon-graphite)); }
.manifesto-foto img { width: 100%; height: 100%; object-fit: cover; display: block; }
@media (max-width: 900px) {
  /* Jedna kolumna — zdjęcie wraca pod tekst (kolejność z DOM), proporcja na poziomą, bo pionowy
     kadr na wąskim ekranie zajmowałby cały ekran. */
  .manifesto--foto { grid-template-columns: 1fr; }
  .manifesto--foto .pull, .manifesto--foto .manifesto-body, .manifesto-foto { grid-column: 1; grid-row: auto; }
  .manifesto-foto { margin-top: 28px; aspect-ratio: 16 / 9; }
}

/* DEKORY: manifesto (WWW-65, opt-in `section.kv_side` — patrz templates/partials/sections/
   manifesto.twig). Klasa gatująca `.has-kv`: `.kv-bg` za treścią, subtelny (jeden blok prozy,
   nie może konkurować z pull statement). `.kv-bg--{left,right}` = strona (generyczne, wyżej),
   tu tylko rozmiar/pozycja/opacity. */
.manifesto.has-kv { position: relative; overflow: hidden; }
.manifesto.has-kv > .container { position: relative; z-index: 1; }
.manifesto .kv-bg {
  top: 10%; width: 30%; aspect-ratio: 1;
  opacity: var(--kv-bg-op, .11);
  background: var(--sb-color, var(--accent));
  -webkit-mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
}
@media (max-width: 860px) { .manifesto .kv-bg { opacity: calc(var(--kv-bg-op, .11) * .6); } }

/* =========================================================================
   DEKORY: prymitywy KV — kv-bg / kv-accent / idea-mask / wartosc-glyph
   Wzorzec: onepager.css:1381–1562 (+ design-hub/assets/kv.css, referencyjnie).
   Recolor wyłącznie --kv-color (= --sb-color na [data-sb]) — zero HEX (WA04).
   Generyczne warstwy tła/akcentu KV; kv-bg/kv-accent/wartosc-glyph NIE wpięte
   w żaden partial jeszcze — gotowe pod kolejne zadania. idea-mask wpięty
   przez partials/sections/idea.twig (WWW-32, patrz SEKCJA: idea niżej).
   ========================================================================= */
.kv-bg { position: absolute; z-index: 0; pointer-events: none; opacity: var(--kv-bg-op, .12); mix-blend-mode: screen; }
.kv-bg img, .kv-bg svg { display: block; width: 100%; height: 100%; }
.kv-bg.breathe svg, .kv-bg.breathe img { transform-box: fill-box; transform-origin: 50% 50%; animation: kvBreathe 9s ease-in-out infinite; }
.kv-bg.spin svg, .kv-bg.spin img { animation: kv-spin 120s linear infinite; }
@keyframes kvBreathe { 0%, 100% { transform: scale(1); opacity: .8; } 50% { transform: scale(1.05); opacity: 1; } }
/* Recolor per subbrand value-cards (WWW-68 przeróbka, wytyczne.md §3.2 — CSS-maska
   SCOPED wyłącznie do [data-sb="camp"]/[data-sb="mlody"] I do `.value-cards` —
   `initiatives-tiles.twig` też wpina <img> w `.kv-bg.spin` i musi zostać poza
   zakresem tego zadania). PIERWSZA iteracja WWW-68 maskowała `.kv-bg` GLOBALNIE
   (wszystkie strony), spłaszczając wielobarwny kv-100-supporting.svg na home —
   REGRESJA, cofnięta. Domyślnie (home/o-nas i pozostałe) `.value-cards .kv-bg`
   niesie oryginalny <img>, bez zmian. Tylko camp/mlody: <img> chowa się, a
   zawsze-obecny sibling `.kv-bg-art-sb` (pusty <div>, value-cards.twig) dostaje
   background=--sb-color maskowany konturem TEGO SAMEGO pliku (zero nowych
   assetów) — camp=orange, mlody=purple. */
[data-sb="camp"] .value-cards .kv-bg img,
[data-sb="mlody"] .value-cards .kv-bg img { display: none; }
[data-sb="camp"] .value-cards .kv-bg-art-sb,
[data-sb="mlody"] .value-cards .kv-bg-art-sb {
  display: block; width: 100%; height: 100%;
  transform-box: fill-box; transform-origin: 50% 50%;
  animation: kvBreathe 9s ease-in-out infinite;
  background: var(--sb-color);
  -webkit-mask: url(../key-visuals/kv-100-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-100-supporting.svg) center/contain no-repeat;
}

/* Modyfikatory strony (WWW-53, wzorzec opt-in `section.kv_side` — wytyczne.md §3.5): generyczne
   left/right; rozmiar/top/opacity nadpisywane per sekcja (wzorzec `.kal-festival .kv-bg`, poniżej). */
.kv-bg--left { left: -6%; }
.kv-bg--right { right: -6%; }

/* Rotacja heksagonów (WWW-52): idea = LEWO (naprzemienność stron, hero=P/idea=L/…).
   Lustro dawnego prawego układu: left:0 + maska solid-lewo→fade-prawo + obraz do lewej. */
.idea-mask {
  position: absolute; z-index: 0; pointer-events: none;
  top: 0; left: 0; bottom: 0; width: 68%; opacity: .16;
  /* CSS-structural: czerń (keyword, nie hex) = pełna maska (nie kolor marki, WA04-manual) */
  -webkit-mask-image: linear-gradient(90deg, black 45%, transparent 100%);
  mask-image: linear-gradient(90deg, black 45%, transparent 100%);
}
.idea-mask img { height: 100%; width: auto; margin-right: auto; display: block; }

.kv-accent {
  position: absolute; pointer-events: none; z-index: 0;
  --kv-par: 0px;
  transform: translate3d(0, var(--kv-par), 0);
  will-change: transform;
  transition: transform 120ms linear;
}
.kv-accent img, .kv-accent svg { display: block; width: 100%; height: 100%; }
.kv-accent svg .kv__art { stroke: var(--kv-color); }
.kv-accent.float img, .kv-accent.float svg { animation: kvFloat 9s ease-in-out infinite; }
@keyframes kvFloat {
  0%, 100% { transform: translateY(0) rotate(0deg); }
  50%      { transform: translateY(-14px) rotate(4deg); }
}
.kv-accent.spin img, .kv-accent.spin svg { animation: kv-spin 90s linear infinite; }
.kv-accent.kv-enter { opacity: 0; }
.kv-accent.kv-enter img, .kv-accent.kv-enter svg { transform: scale(.82); }
.kv-accent.kv-enter.is-in { opacity: var(--kv-target-op, .4); transition: opacity 900ms var(--ease-out-quart); }
.kv-accent.kv-enter.is-in img, .kv-accent.kv-enter.is-in svg { transform: scale(1); transition: transform 1100ms var(--ease-out-expo); }
/* Recolor per subbrand cta (WWW-68 przeróbka, wytyczne.md §3.2 — CSS-maska SCOPED
   wyłącznie do [data-sb="camp"]/[data-sb="mlody"]): PIERWSZA iteracja WWW-68
   maskowała `.kv-accent-art` GLOBALNIE (wszystkie strony), spłaszczając wielobarwny
   kv-101-original.svg na home/festiwal — REGRESJA, cofnięta. Domyślnie (home/
   festiwal/pozostałe) `.kv-accent` niesie oryginalny <img>, bez zmian. Tylko
   camp/mlody: <img> chowa się, a zawsze-obecny sibling `.kv-accent-art-sb` (pusty
   <div>, cta.twig) dostaje background=--sb-color maskowany konturem TEGO SAMEGO
   pliku (zero nowych assetów) — camp=orange, mlody=purple. Animacje (float/spin/
   kv-enter) replikowane 1:1 z generycznych reguł img/svg wyżej, celowana wyłącznie
   na `.kv-accent-art-sb`. */
[data-sb="camp"] .kv-accent img,
[data-sb="mlody"] .kv-accent img { display: none; }
[data-sb="camp"] .kv-accent-art-sb,
[data-sb="mlody"] .kv-accent-art-sb {
  display: block; width: 100%; height: 100%;
  background: var(--sb-color);
  -webkit-mask: url(../key-visuals/kv-101-original.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-101-original.svg) center/contain no-repeat;
}
[data-sb="camp"] .kv-accent.float .kv-accent-art-sb,
[data-sb="mlody"] .kv-accent.float .kv-accent-art-sb { animation: kvFloat 9s ease-in-out infinite; }
[data-sb="camp"] .kv-accent.spin .kv-accent-art-sb,
[data-sb="mlody"] .kv-accent.spin .kv-accent-art-sb { animation: kv-spin 90s linear infinite; }
[data-sb="camp"] .kv-accent.kv-enter .kv-accent-art-sb,
[data-sb="mlody"] .kv-accent.kv-enter .kv-accent-art-sb { transform: scale(.82); }
[data-sb="camp"] .kv-accent.kv-enter.is-in .kv-accent-art-sb,
[data-sb="mlody"] .kv-accent.kv-enter.is-in .kv-accent-art-sb { transform: scale(1); transition: transform 1100ms var(--ease-out-expo); }

/* CTA (WWW-36): pierwszy render .kv-accent — rozmiar instancji (pozycja/opacity/animacja
   już generyczne wyżej, L379-397); .section-cta musi kontenerować absolute+overflow. */
.section-cta { position: relative; overflow: hidden; }
.section-cta .kv-accent { width: 520px; height: 520px; }
.section-cta > .container { position: relative; z-index: 1; }

.wartosc-glyph {
  position: absolute; top: 28px; right: 24px;
  width: 40px; height: 40px;
  color: var(--plon-mint); opacity: .28;
  pointer-events: none;
  transition: opacity 180ms, transform 320ms cubic-bezier(.2,.7,.2,1);
}
.wartosc-glyph svg { width: 100%; height: 100%; display: block; }
.theme-card:hover .wartosc-glyph { opacity: .55; transform: rotate(30deg); }

@media (max-width: 860px) {
  .kv-bg { opacity: calc(var(--kv-bg-op, .12) * .6) !important; }
  .idea-mask { opacity: .10; }
}

/* =========================================================================
   SEKCJA: value-cards (numerowane karty 01–04)
   Wzorzec: card-value.html (.theme-card + serif .tnum)
   Dekor (WWW-35, 1:1 onepager.css:866-917,1513-1514): sekcja jako positioning
   context dla `.kv-bg.breathe` (tło pulsujące, z-index:0) — `.container` podniesiony
   do z-index:1 (wzorzec .section-hero/.section-initiatives-tiles), by dekor nie
   malował się nad treścią. Pozycja/rozmiar kv-bg override — baza (opacity/animation/
   pointer-events) już w klasie `.kv-bg`/`.kv-bg.breathe` (DEKORY: prymitywy KV, wyżej).
   `.theme-card{position:relative}` = kotwica dla `.wartosc-glyph` (position:absolute).
   ========================================================================= */
.section.value-cards { position: relative; overflow: hidden; }
.section.value-cards .container { position: relative; z-index: 1; }
.value-cards .kv-bg.breathe { top: -60px; right: -60px; width: 620px; height: 620px; }
.value-cards .cards { display: grid; grid-template-columns: repeat(auto-fit, minmax(240px, 1fr)); gap: 16px; }
/* MT-DIVERGENCE (WWW-66): rotacja §3.5 wymaga by drugi `value-cards` na /o-nas (sekcja
   Wartości) renderował dekor po PRZECIWNEJ stronie niż pierwszy (Strategia) — partial
   value-cards.twig ma `.kv-bg.breathe` hardcoded PRAWO dla WSZYSTKICH stron (WWW-35, dzielony
   z home / camp / mlody, NIE zmieniamy wspólnej reguły wyżej). Page-specific override przez
   id z content (anchor: wartosci-onas, UNIKALNY — nie koliduje z anchorem „wartosci" home.md,
   inny dokument = inny zasięg id). Overload TYLKO right/left, reszta dekoru (top/rozmiar/
   animacja) dziedziczy z bazowej reguły wyżej. */
#wartosci-onas.value-cards .kv-bg.breathe { right: auto; left: -60px; }
.theme-card { position: relative; border: 1px solid var(--border); padding: 24px; display: flex; flex-direction: column; gap: 8px; background: var(--plon-black); }
.theme-card .tnum { font-family: var(--font-serif); font-style: italic; color: var(--accent-text); font-size: 28px; line-height: 1; }
.theme-card h3 { margin: 4px 0; font-size: 18px; }
.theme-card p { margin: 0; color: var(--fg-2); font-size: 14px; line-height: 1.55; }

/* =========================================================================
   SEKCJA: two-cols (filary 2×2)
   Wzorzec: pillars.html (.pillars/.pill)
   ========================================================================= */
.two-cols .pillars { display: grid; grid-template-columns: repeat(2, 1fr); gap: 1px; background: var(--border); border: 1px solid var(--border); }
.pillars .pill { background: var(--plon-black); padding: 22px 20px; }
.pillars .pill .h { display: flex; align-items: center; gap: 10px; margin-bottom: 8px; }
.pillars .pill .num { width: 24px; height: 24px; border: 1px solid var(--accent); color: var(--accent-text); font-size: 11px; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; flex: none; }
.pillars .pill .t { font-weight: 700; font-size: 16px; }
.pillars .pill p { font-size: 13px; line-height: 1.55; color: var(--fg-3); margin: 0; }

/* DEKORY: two-cols (WWW-65, opt-in `section.kv_side` — patrz templates/partials/sections/
   two-cols.twig). Klasa gatująca `.has-kv`: `.kv-bg` za treścią. `.kv-bg--{left,right}` = strona
   (generyczne, wyżej), tu tylko rozmiar/pozycja/opacity. */
.two-cols.has-kv { position: relative; overflow: hidden; }
.two-cols.has-kv > .container { position: relative; z-index: 1; }
.two-cols .kv-bg {
  top: 8%; width: 28%; aspect-ratio: 1;
  opacity: var(--kv-bg-op, .13);
  background: var(--sb-color, var(--accent));
  -webkit-mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
}
@media (max-width: 860px) { .two-cols .kv-bg { opacity: calc(var(--kv-bg-op, .13) * .6); } }

/* =========================================================================
   SEKCJA: timeline (kamienie milowe)
   Wzorzec: timeline.html (.timeline/.tl-cell)
   ========================================================================= */
.timeline { display: grid; grid-auto-flow: column; grid-auto-columns: 1fr; border-top: 2px solid var(--accent); }
.tl-cell { padding: 24px 16px 16px; border-right: 1px solid var(--border); position: relative; min-height: 180px; display: flex; flex-direction: column; gap: 8px; }
.tl-cell:last-child { border-right: 0; }
.tl-cell .marker { width: 12px; height: 12px; border-radius: 50%; border: 2px solid var(--accent); background: var(--plon-black); position: absolute; top: -7px; left: 16px; }
.tl-cell.future .marker { border-color: var(--fg-3); }
.tl-cell .when { font-size: 11px; letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--accent-text); }
.tl-cell.future .when { color: var(--fg-3); }
.tl-cell .year { font-size: 28px; font-weight: 800; letter-spacing: -.02em; }
.tl-cell .tl-title { font-weight: 600; }
.tl-cell .desc { font-size: 12px; color: var(--fg-3); margin-top: auto; }

/* DEKORY: timeline (WWW-65, opt-in `section.kv_side` — patrz templates/partials/sections/
   timeline.twig). Klasa gatująca `.has-kv`: `.kv-bg` za treścią, nisko-osadzony (oś czasu jest
   poziomym pasem). `.kv-bg--{left,right}` = strona (generyczne, wyżej), tu tylko rozmiar/pozycja/
   opacity. */
.section-timeline.has-kv { position: relative; overflow: hidden; }
.section-timeline.has-kv > .container { position: relative; z-index: 1; }
.section-timeline .kv-bg {
  top: 4%; width: 24%; aspect-ratio: 1;
  opacity: var(--kv-bg-op, .12);
  background: var(--sb-color, var(--accent));
  -webkit-mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
}
@media (max-width: 860px) { .section-timeline .kv-bg { opacity: calc(var(--kv-bg-op, .12) * .6); } }

/* =========================================================================
   SEKCJA: founder (karta założyciela)
   Wzorzec: founder.html (.founder-card)
   ========================================================================= */
.founder-card { background: var(--plon-graphite); border: 1px solid var(--border); display: grid; grid-template-columns: 260px 1fr; gap: 32px; padding: 32px; align-items: start; }
.founder-card .portrait { aspect-ratio: 4/5; background: var(--plon-gray-850); overflow: hidden; }
.founder-card .portrait img { width: 100%; height: 100%; object-fit: cover; }
.founder-card .name { font-size: 30px; font-weight: 800; letter-spacing: -.02em; }
.founder-card .frole { font-size: 11px; letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--accent-text); margin-top: 4px; }
.founder-card .bio { color: var(--fg-2); font-size: 15px; line-height: 1.6; margin-top: 16px; }
.founder-card .bio p { margin: 0 0 12px; } .founder-card .bio p:last-child { margin-bottom: 0; }
.founder-card .creds { list-style: none; padding: 0; margin: 16px 0 0; display: flex; flex-direction: column; gap: 8px; font-size: 13px; color: var(--fg-2); }
.founder-card .creds li::before { content: "→ "; color: var(--accent-text); }
.founder-card .fquote { border-left: 2px solid var(--accent); padding-left: 16px; font-family: var(--font-serif); font-style: italic; font-size: 16px; margin-top: 18px; color: var(--fg-1); }

/* DEKORY: founder (WWW-65, opt-in `section.kv_side` — patrz templates/partials/sections/
   founder.twig). Klasa gatująca `.has-kv`: `.kv-bg` za treścią, portret zajmuje lewą kolumnę
   karty więc dekor osadzony wyżej/mniejszy, by nie kolidować wizualnie z kadrem 4:5.
   `.kv-bg--{left,right}` = strona (generyczne, wyżej), tu tylko rozmiar/pozycja/opacity. */
.section-founder.has-kv { position: relative; overflow: hidden; }
.section-founder.has-kv > .container { position: relative; z-index: 1; }
.section-founder .kv-bg {
  top: 6%; width: 26%; aspect-ratio: 1;
  opacity: var(--kv-bg-op, .12);
  background: var(--sb-color, var(--accent));
  -webkit-mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
}
@media (max-width: 860px) { .section-founder .kv-bg { opacity: calc(var(--kv-bg-op, .12) * .6); } }

/* =========================================================================
   SEKCJA: cta (wielkie serif hasło + przycisk)
   Wzorzec: cta.html (.cta-festival). Dekoracyjne linie sygnaturalne (.lines)
   stokenizowane — recolor --sb-color/--accent, zero HEX (WA04, WWW-12).
   ========================================================================= */
.cta-festival { position: relative; overflow: hidden; border: 1px solid var(--border-soft); padding: 64px 40px; }
.cta-festival > *:not(.lines) { position: relative; z-index: 1; }
.cta-festival h2 { font-family: var(--font-serif); font-style: italic; font-weight: 700; font-size: clamp(40px, 6vw, 96px); line-height: .96; letter-spacing: -.025em; margin: 14px 0 0; }
.cta-festival h2 .accent { color: var(--accent-text); }
.cta-festival .sub { margin-top: 24px; color: var(--fg-2); font-size: 17px; max-width: 600px; line-height: 1.55; }
.cta-festival .actions { margin-top: 28px; }
/* CTA „bilety wkrótce" (WWW-43): nieaktywny przycisk — spójny z .kal-festival .actions .btn.is-soon;
   generyczny partial cta.twig renderuje <a class="btn is-soon">, więc reguła scope'owana do .section-cta. */
.section-cta .btn.is-soon { background: var(--border-soft, var(--border)); color: var(--fg-3); cursor: not-allowed; pointer-events: none; }

/* CTA hero „bilety wkrótce" (WWW-43 follow-up): hero.twig renderuje ten sam wzorzec
   <span class="btn is-soon"> w .cta-row — spójne z .section-cta/.tiers/.kal-festival. */
.hero-copy .cta-row .btn.is-soon { background: var(--border-soft, var(--border)); color: var(--fg-3); cursor: not-allowed; pointer-events: none; }

/* DEKORY: cta-festival — linie sygnaturalne (wave-drift, przeciwfaza) */
/* WWW-85 (E1): SVG ma viewBox 0 0 1600 700 z preserveAspectRatio="none" — najwyższy
   tusz (`getBBox()` ścieżek, nie sam kontener `.lines`) startuje na y≈520, czyli
   0,257 × wysokości warstwy NAD jej dolną krawędzią (bramka geometryczna
   `tools/check-cta-waves.py`, mierzy dokładnie to, mapowanie liniowe bo
   preserveAspectRatio="none"). Warstwa jest przypięta do dołu (top:auto;bottom:0),
   ale sam cap `min(45%, 220px)` z pierwszej iteracji był za wysoki na OBU
   viewportach z gate'u (1440/390): przy odległości przycisków od dołu sekcji
   ≈58px (desktop, padding 64px) i ≈34px (mobile ≤560px, padding 40px) potrzeba
   0,257×layerH ≤ (odległość − 8px min-gap) → desktop layerH ≤ ~194px, mobile
   layerH ≤ ~101px — JEDNA wartość nie starcza na oba (194 na mobile zjadłby
   cały prześwit). Rozwiązanie (opcja A z recenzji): cap ODMIENNY per breakpoint,
   ten sam próg co zmiana paddingu `.cta-festival` (max-width:560px) — 190px na
   desktopie (clearance ~9–14px wg trasy) + 78px na mobile (clearance ~10–16px)
   w `@media (max-width:560px)` niżej. Zmierzone GATE'EM: 14/14 OK, min-gap 8px —
   patrz „Wynik" w zadaniu za realnym outputem. Dekor zostaje na WSZYSTKICH
   7 sekcjach CTA (decyzja E1: geometria, nie usunięcie), tylko cieńszy na mobile. */
.cta-festival .lines { position: absolute; inset: auto 0 0 0; height: min(38%, 190px); z-index: 0; pointer-events: none; opacity: .55; }
.cta-festival .lines .wave-drift { animation: ctaWaveDrift 26s linear infinite alternate; }
.cta-festival .lines .wave-drift.slow { animation-duration: 38s; animation-direction: alternate-reverse; }
@keyframes ctaWaveDrift { from { transform: translateX(0); } to { transform: translateX(-120px); } }

/* =========================================================================
   SEKCJA: prose (surowy markdown → HTML w kolumnie prozy)
   ========================================================================= */
.prose { max-width: var(--max-w-prose); color: var(--fg-2); }
.prose h2 { font-size: clamp(24px, 2.6vw, 34px); margin: 32px 0 12px; color: var(--fg-1); }
.prose h3 { font-size: 20px; margin: 24px 0 10px; color: var(--fg-1); }
.prose p { margin: 0 0 16px; line-height: 1.65; }
.prose a { color: var(--accent-text); border-bottom: 1px solid transparent; }
.prose a:hover { border-bottom-color: var(--accent); }
.prose ul, .prose ol { margin: 0 0 16px; padding-left: 22px; display: flex; flex-direction: column; gap: 6px; }
.prose li { line-height: 1.55; }
.prose blockquote { border-left: 2px solid var(--accent); padding-left: 18px; font-family: var(--font-serif); font-style: italic; color: var(--fg-1); margin: 0 0 16px; }
.prose strong { color: var(--fg-1); }

/* DEKORY: section-prose (WWW-53, opt-in `section.kv_side` — patrz templates/partials/sections/
   prose.twig). DECYZJA WWW-53: prose Festiwalu (archiwum) dostaje KV, nie reveal-only, by utrzymać
   kadencję rotacji P/L/P (§3.5); dekor SUBTELNY (opacity dolny zakres §3.1, by nie konkurować z
   prozą). `.kv-bg--{left,right}` = strona (generyczne, wyżej); tu tylko rozmiar/pozycja/opacity. */
.section-prose { position: relative; overflow: hidden; }
.section-prose > .container { position: relative; z-index: 1; }
.section-prose .kv-bg {
  top: 12%; width: 32%; aspect-ratio: 1;
  opacity: var(--kv-bg-op, .11);
  background: var(--sb-color, var(--accent));
  -webkit-mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
}
@media (max-width: 860px) { .section-prose .kv-bg { opacity: calc(var(--kv-bg-op, .11) * .6); } }

/* =========================================================================
   STOPKA
   Wzorzec: footer.html (.site-footer)
   ========================================================================= */
.site-footer { position: relative; overflow: hidden; background: var(--plon-black); border-top: 1px solid var(--border); padding: 48px 0 28px; margin-top: var(--space-9); }
/* Pas newslettera wyłączony (footer.twig, `newsletter_enabled: false`) — margines istniał wyłącznie
   po to, by odsunąć stopkę od KARTY newslettera. Bez pasa sumował się z padding-bottom sekcji CTA
   w ~240 px pustki. Zerujemy sam margines; padding stopki bez zmian. */
.site-footer--no-nl { margin-top: 0; }
/* DEKORY: subtelna tekstura heksagonu (mask glyph-hex, WWW-12) — CSS-only, bez SVG w DOM */
.site-footer::before {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: var(--plon-mint); opacity: .04;
  -webkit-mask-image: url('../glyphs/glyph-hex.svg');
  -webkit-mask-size: 84px 84px; -webkit-mask-repeat: repeat;
  mask-image: url('../glyphs/glyph-hex.svg');
  mask-size: 84px 84px; mask-repeat: repeat;
}
.site-footer::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: linear-gradient(180deg, transparent 0%, var(--plon-black) 78%);
}
.site-footer > .container { position: relative; z-index: 1; }
.foot-grid { display: grid; grid-template-columns: 1.3fr 1fr 1fr 1fr; gap: 40px; }
.foot-haslo { font-family: var(--font-serif); font-style: italic; font-weight: 700; font-size: 22px; line-height: 1.15; margin: 16px 0; max-width: 280px; }
.foot-haslo em { color: var(--accent-text); }
.foot-col .foot-col-title { font-size: 12px; font-weight: 700; letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--fg-3); margin: 0 0 14px; }
.foot-col ul { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 10px; }
.foot-col a { color: var(--fg-2); font-size: 14px; } .foot-col a:hover { color: var(--accent-text); }
.foot-bottom { margin-top: 40px; padding-top: 20px; border-top: 1px solid var(--border-soft); display: flex; justify-content: space-between; flex-wrap: wrap; gap: 12px; color: var(--fg-3); font-size: 12px; }
.foot-bottom .legal { display: flex; gap: 20px; flex-wrap: wrap; }
.foot-bottom a:hover { color: var(--accent-text); }
.foot-bottom .footer-cookie-btn { background: transparent; border: 0; color: var(--fg-3); font: inherit; cursor: pointer; padding: 0; }
.foot-bottom .footer-cookie-btn:hover { color: var(--accent-text); }
.social { display: flex; gap: 8px; margin-top: 6px; }
.social a { width: 36px; height: 36px; border: 1px solid var(--border); display: inline-flex; align-items: center; justify-content: center; color: var(--fg-2); }
.social a:hover { border-color: var(--accent); color: var(--accent-text); }
.social svg { width: 16px; height: 16px; }
.foot-addr { color: var(--fg-3); font-size: 12px; line-height: 1.5; margin-top: 20px; }

/* =========================================================================
   SEKCJA: tiers (poziomy zaangażowania / cennik — GENERYCZNY, reuse Festiwal)
   Wzorzec: tickets.html (.ticket/.featured)
   ========================================================================= */
/* DEKORY: tiers (WWW-54, opt-in `section.kv_side` — patrz templates/partials/sections/
   tiers.twig). Klasa gatująca `.has-kv` (jak person-grid, WWW-53): `.kv-bg` za treścią +
   poświata §3.4 za kartą `.featured` — ODBLOKOWANA TYLKO gdy sekcja ma kv_side.
   ERRATA WWW-79 (2026-07-27): pierwotna treść tego komentarza twierdziła, że /wspolpraca
   „renderuje się bez zmiany, bo tiers bez kv_side" — to NIEPRAWDA. Pomiar DOM na żywo:
   /wspolpraca ma `kv_side: left` na sekcji tiers (content/wspolpraca.md:46), więc renderuje
   `.section-tiers.has-kv` i poświatę DOSTAJE. Nie opieraj na `.has-kv` żadnego scopingu
   „tylko festiwal" — patrz l. 745 niżej. */
.section-tiers.has-kv { position: relative; overflow: hidden; }
.section-tiers.has-kv > .container { position: relative; z-index: 1; }
.section-tiers .kv-bg {
  top: 8%; width: 34%; aspect-ratio: 1;
  opacity: var(--kv-bg-op, .14);
  background: var(--sb-color, var(--accent));
  -webkit-mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
}
@media (max-width: 860px) { .section-tiers .kv-bg { opacity: calc(var(--kv-bg-op, .14) * .6); } }
.section-intro { margin-top: 14px; max-width: 560px; color: var(--fg-3); font-size: 15px; line-height: 1.55; }
.tiers { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; align-items: stretch; }
/* WWW-79: /festiwal ma DWA bilety, a `.tiers` (regułą wyżej) jest siatką 3-kolumnową zaprojektowaną
   pod trzy — bez korekty dwa kafle zajmują 2/3 kontenera, zostawiając pusty pas po prawej.
   UWAGA — `.has-kv` NIE nadaje się do scopingu (wbrew komentarzowi l. 731 i tiers.twig): pomiar
   na żywo (2026-07-27) pokazał, że sekcja tiers na /wspolpraca TEŻ ma `kv_side: left`
   (content/wspolpraca.md:46) → renderuje `.section-tiers.has-kv` identycznie jak /festiwal; selektor
   `.section-tiers.has-kv .tiers` złapałby OBIE strony. Scoping realny = `id="bilety"`, który
   `tiers.twig` renderuje TYLKO gdy `section.anchor` jest ustawiony — festiwal ma `anchor: bilety`
   (content/festiwal.md:137), wspolpraca ma `anchor: partnerstwo` na INNEJ sekcji (partner-cards,
   nie tiers) i BRAK anchora na swojej sekcji tiers → `#bilety .tiers` trafia wyłącznie /festiwal. */
#bilety .tiers { grid-template-columns: repeat(2, 1fr); }
.tier { position: relative; background: var(--plon-black); border: 1px solid var(--border); padding: 28px; display: flex; flex-direction: column; gap: 12px; min-height: 360px; }
.tier.featured { background: var(--plon-graphite); border-color: var(--accent); }
/* Poświata za kartą featured (§3.4, at 80% 110% = róg poza kartą) — gated `.has-kv` (wyżej).
   ERRATA WWW-79: gate `.has-kv` NIE wyłącza tego efektu na /wspolpraca — ta strona też ma
   `kv_side` na tiers, więc jej karta „Mecenas" (featured) poświatę ma. Zmieniając ten efekt,
   sprawdzaj OBIE podstrony. Treść karty
   podniesiona do z-index:1 (badge osobno, już absolute, dostaje z-index:2 dla pewności). */
.section-tiers.has-kv .tier.featured { overflow: hidden; }
.section-tiers.has-kv .tier.featured::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: radial-gradient(420px 320px at 80% 110%, color-mix(in srgb, var(--sb-color, var(--accent)) 18%, transparent), transparent 60%);
}
.section-tiers.has-kv .tier.featured > *:not(.tier-badge) { position: relative; z-index: 1; }
.section-tiers.has-kv .tier.featured .tier-badge { z-index: 2; }
.tier-badge { position: absolute; top: 0; right: 0; background: var(--accent); color: var(--accent-fg); font-size: 10px; font-weight: 700; letter-spacing: var(--tracking-caps); text-transform: uppercase; padding: 4px 10px; }
.tier-eyebrow { font-size: 11px; letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--accent-text); }
.tier-name { font-size: 26px; font-weight: 800; letter-spacing: -.02em; line-height: 1.05; }
.tier-name .accent { font-family: var(--font-serif); font-style: italic; font-weight: 700; color: var(--accent-text); }
.tier-desc { font-size: 13px; line-height: 1.55; color: var(--fg-2); margin: 0; }
/* gotcha P1: linia sygnaturowa/cena — wrapuje się; długa etykieta tekstowa NIE rozjeżdża karty */
.tier-price { font-family: var(--font-serif); font-style: italic; font-weight: 700; font-size: 24px; line-height: 1.15; color: var(--accent-text); overflow-wrap: anywhere; }
.tier-meta { font-size: 12px; letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--fg-2); }
.tier-features { list-style: none; padding: 0; margin: 6px 0 0; display: flex; flex-direction: column; gap: 10px; font-size: 13px; color: var(--fg-2); line-height: 1.45; }
.tier-features li { padding-left: 20px; position: relative; }
.tier-features li::before { content: "\2713"; position: absolute; left: 0; color: var(--accent-text); }
.tier .tier-link, .tier .btn { margin-top: auto; }
.tier-link { align-self: flex-start; }
/* CTA „wkrótce" (WWW-43 follow-up, decyzja właściciela 2026-07-22): nieinteraktywny
   <span class="btn is-soon"> — spójne z .section-cta .btn.is-soon / .kal-festival .actions .btn.is-soon. */
.tiers .btn.is-soon { background: var(--border-soft, var(--border)); color: var(--fg-3); cursor: not-allowed; pointer-events: none; }

/* =========================================================================
   SEKCJA: comparison-table (tabela porównawcza — overflow-x na mobile)
   Wzorzec: table.html (.data-table)
   ========================================================================= */
.table-scroll { overflow-x: auto; -webkit-overflow-scrolling: touch; }
.compare-table { width: 100%; border-collapse: collapse; min-width: 680px; }
.compare-table caption { text-align: left; font-size: 11px; letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--fg-3); margin-bottom: 10px; }
.compare-table thead th { background: var(--accent); color: var(--accent-fg); text-align: left; padding: 12px 14px; font-size: 13px; font-weight: 700; vertical-align: top; }
.compare-table thead th.corner { background: var(--plon-black); }
.compare-table .col-sub { display: block; font-size: 11px; font-weight: 400; letter-spacing: 0; text-transform: none; margin-top: 4px; opacity: .85; }
.compare-table tbody th { text-align: left; padding: 12px 14px; font-size: 12px; letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--fg-2); font-weight: 600; white-space: nowrap; border-bottom: 1px solid var(--border); background: var(--plon-black); vertical-align: top; }
.compare-table tbody td { padding: 12px 14px; border-bottom: 1px solid var(--border); font-size: 13px; color: var(--fg-2); line-height: 1.5; vertical-align: top; }
.compare-table tbody tr:hover td { background: var(--plon-graphite); }

/* DEKORY: comparison-table (WWW-65, opt-in `section.kv_side` — patrz templates/partials/sections/
   comparison-table.twig). Klasa gatująca `.has-kv`: `.kv-bg` za treścią, subtelny (tabela jest
   gęsta wizualnie — dekor niskiej opacity). `.kv-bg--{left,right}` = strona (generyczne, wyżej),
   tu tylko rozmiar/pozycja/opacity. */
.section-comparison.has-kv { position: relative; overflow: hidden; }
.section-comparison.has-kv > .container { position: relative; z-index: 1; }
.section-comparison .kv-bg {
  top: 6%; width: 24%; aspect-ratio: 1;
  opacity: var(--kv-bg-op, .10);
  background: var(--sb-color, var(--accent));
  -webkit-mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
}
@media (max-width: 860px) { .section-comparison .kv-bg { opacity: calc(var(--kv-bg-op, .10) * .6); } }

/* =========================================================================
   SEKCJA: partner-cards (karty form partnerstwa)
   Wzorzec: card-initiative.html (.ini-card)
   ========================================================================= */
.partner-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.partner-card { background: var(--plon-graphite); border: 1px solid var(--border); padding: 28px; display: flex; flex-direction: column; gap: 14px; min-height: 240px; transition: border-color var(--dur-fast) var(--ease-out-quart); }
.partner-card:hover { border-color: var(--accent); }
.partner-card .pc-head { display: flex; align-items: flex-start; gap: 14px; }
.partner-card .pc-num { font-family: var(--font-serif); font-style: italic; color: var(--accent-text); font-size: 26px; line-height: 1; flex: none; }
.partner-card .pc-titles { display: flex; flex-direction: column; gap: 6px; }
.partner-card h3 { font-size: 20px; margin: 0; }
.partner-card .pc-role { font-size: 10px; letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--accent-text); border: 1px solid var(--accent); padding: 2px 7px; align-self: flex-start; }
.partner-card p { font-size: 14px; line-height: 1.55; color: var(--fg-2); margin: 0; }
.partner-card .pc-foot { margin-top: auto; padding-top: 16px; border-top: 1px solid var(--border); font-size: 12px; color: var(--fg-3); }

/* DEKORY: partner-cards (WWW-65, opt-in `section.kv_side` — patrz templates/partials/sections/
   partner-cards.twig). Klasa gatująca `.has-kv`: `.kv-bg` za treścią. `.kv-bg--{left,right}` =
   strona (generyczne, wyżej), tu tylko rozmiar/pozycja/opacity. */
.section-partner-cards.has-kv { position: relative; overflow: hidden; }
.section-partner-cards.has-kv > .container { position: relative; z-index: 1; }
.section-partner-cards .kv-bg {
  top: 8%; width: 28%; aspect-ratio: 1;
  opacity: var(--kv-bg-op, .12);
  background: var(--sb-color, var(--accent));
  -webkit-mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
}
@media (max-width: 860px) { .section-partner-cards .kv-bg { opacity: calc(var(--kv-bg-op, .12) * .6); } }

/* =========================================================================
   SEKCJA: initiatives-tiles (kafle 4 inicjatyw/subbrandów — Festiwal/Camp/Młody/AIR)
   Wzorzec: onepager index.html:197-328 (.ini-card) + onepager.css:569-720,1515-1532.
   Recolor WYŁĄCZNIE przez data-sb → var(--sb-color) (fallback var(--accent)) —
   --accent-text NIE jest remapowany generycznie (tylko mlody, tokens.css) więc
   tekst/border kolorowy czyta jawnie var(--sb-color, var(--accent)), wzorem
   event-list/speaker-grid (WWW-12). Zero HEX (WA04).
   Poświata karty (WWW-45, MT-DIVERGENCE od ZASADY KV z WWW-14/34): kv-99-supporting.svg
   jako CSS-maska (background + mask:url(...)) recolorowana przez var(--sb-color) —
   NIE już statyczny wielokolorowy <img> — poświata świeci w kolorze inicjatywy.
   Tło sekcji (WWW-34): `.kv-bg.spin` (prymityw KV, WWW-12) wpięty przez partial,
   analogicznie do `.section-hero .kv-bg`/onepager `.inicjatywy .kv-bg` (kv-bg
   base class w sekcji "DEKORY: prymitywy KV" niżej) — `.container` podniesiony
   do z-index:1, by dekor (z-index:0) nie malował się nad treścią.
   ========================================================================= */
.section-initiatives-tiles { position: relative; overflow: hidden; }
.section-initiatives-tiles .container { position: relative; z-index: 1; }
.section-initiatives-tiles .kv-bg.spin { top: -80px; right: -80px; width: 620px; height: 620px; }
/* MT-DIVERGENCE (WWW-45): 2 duże boksy/rząd na desktop (parytet onepager
   .ini-grid 12-kol + span-6) zamiast dawnych 4 wąskich kart w rzędzie. */
.ini-grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 20px; }
.ini-card {
  position: relative; overflow: hidden;
  /* Ramka WIDOCZNA (WWW-48): --border = gray-700 = tło graphite karty → niewidoczna;
     gray-600 daje subtelną, ale realnie widoczną cienką ramkę dookoła boksu. */
  background: var(--plon-graphite); border: 1px solid var(--plon-gray-600);
  padding: 28px; display: flex; flex-direction: column; gap: 14px;
  min-height: 320px;
  transition: border-color var(--dur-fast) var(--ease-out-quart);
}
.ini-card > * { position: relative; z-index: 1; }
.ini-card[data-sb]::before {
  content: ""; position: absolute; top: 0; left: 0; right: 0; height: 3px;
  background: var(--sb-color); z-index: 1; pointer-events: none;
}
.ini-card:hover { border-color: var(--sb-color, var(--accent)); }
.ini-card:hover .ini-cta .arrow { transform: translateX(6px); }

/* Poświata (WWW-48, MT-DIVERGENCE od onepager.css:649-655 `.ini-card.featured::after`
   — tu na KAŻDEJ karcie inicjatywy): miękki gradient-glow wychodzący z prawego-
   dolnego rogu w kolorze inicjatywy (`at 80% 110%` = poza rogiem karty). Zastępuje
   dawną heksagonową CSS-maskę (.ini-glow/.ini-glow-sharp) — właściciel chce miękki
   wash koloru, nie pierścienie heksagonu. WA04: kolor wyłącznie z tokenu --sb-color. */
.ini-card[data-sb]::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: radial-gradient(760px 340px at 82% 112%, color-mix(in srgb, var(--sb-color) 22%, transparent), transparent 62%);
}

.ini-head { display: flex; justify-content: space-between; align-items: flex-start; gap: 10px; }
.ini-tag {
  font-size: 11px; font-weight: 700; letter-spacing: var(--tracking-caps); text-transform: uppercase;
  color: var(--sb-color, var(--accent));
}
.ini-meta { display: flex; align-items: center; gap: 8px; font-size: 11px; letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--fg-3); white-space: nowrap; }
.ini-status { font-weight: 700; padding: 2px 7px; border: 1px solid var(--border); color: var(--fg-3); }
.ini-status.live { color: var(--sb-color, var(--accent)); border-color: var(--sb-color, var(--accent)); }
.ini-status.soon { color: var(--fg-2); border-color: var(--border); }

.ini-photo { width: 100%; aspect-ratio: 5 / 2; background: var(--plon-gray-800); overflow: hidden; border: 1px solid var(--border); }
.ini-photo img { width: 100%; height: 100%; object-fit: cover; display: block; }

.ini-body h3 { font-size: 20px; font-weight: 700; letter-spacing: -.015em; line-height: 1.15; margin: 0 0 8px; }
.ini-body p { font-size: 13px; line-height: 1.55; color: var(--fg-2); margin: 0; }

.ini-footer { margin-top: auto; padding-top: 16px; border-top: 1px solid var(--border); }
.ini-cta { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 700; color: var(--sb-color, var(--accent-text)); }
.ini-cta .arrow { width: 14px; height: 10px; flex: none; transition: transform var(--dur-fast) var(--ease-out-quart); }

/* =========================================================================
   SEKCJA: festival-feature (wyróżnienie Festiwalu / kalendarium, big-date)
   Wzorzec: onepager index.html:333-371 (.kal-festival) + onepager.css:795-861,1534-1538.
   Recolor karty WYŁĄCZNIE przez data-sb → var(--sb-color) (fallback var(--accent)),
   wzorem initiatives-tiles (WWW-14). Poświata (ZASADA KV): bogaty
   kv-99-supporting.svg jako <img> w .ini-glow (reużyta klasa, poza skanem WA04)
   — pozycja/rozmiar nadpisane niżej pod szeroki układ karty. Zero HEX (WA04).
   ========================================================================= */
.kal-festival {
  position: relative; overflow: hidden;
  margin-top: 0;
  background: var(--plon-graphite); border: 1px solid var(--border);
  padding: 40px 44px;
  display: grid; grid-template-columns: auto 1fr auto; gap: 48px;
  align-items: center;
}
.kal-festival > *:not(.kv-bg) { position: relative; z-index: 1; }
/* JEDEN heksagon MINT po prawej (WWW-49): dawniej DWA nałożone (.kv-bg <img> +
   .ini-glow <img>, oba wielokolorowe) → zostaje sam `.kv-bg` recolorowany na mint
   CSS-maską (background: var(--sb-color)=mint przy data-sb="festiwal"), wzorem
   recoloru inicjatyw. Zero <img>, zero HEX (WA04). */
.kal-festival .kv-bg {
  position: absolute; top: 50%; left: -6%; transform: translateY(-50%);
  width: 46%; aspect-ratio: 1; z-index: 0;
  opacity: var(--kv-op-bg, .18); pointer-events: none;
  background: var(--sb-color, var(--plon-mint));
  -webkit-mask: url(../key-visuals/kv-100-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-100-supporting.svg) center/contain no-repeat;
}
/* Mint glow z LEWEJ (WWW-49 glow + WWW-52 rotacja na LEWO): miękki gradient od lewej
   krawędzi karty w kolorze inicjatywy (mint dla festiwal). Za treścią (z-index:0). */
.kal-festival::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: radial-gradient(600px 400px at 0% 50%, color-mix(in srgb, var(--sb-color) 14%, transparent), transparent 60%);
}

.kal-festival .big-date { display: flex; flex-direction: column; line-height: 1; }
.kal-festival .big-date .d {
  font-family: var(--font-sans); font-weight: 800;
  font-size: 96px; letter-spacing: -0.04em; line-height: .9;
}
.kal-festival .big-date .d .sm {
  font-size: 32px; color: var(--sb-color, var(--accent)); margin-left: 4px; vertical-align: top;
}
.kal-festival .big-date .y {
  font-family: var(--font-sans); font-weight: 700; color: var(--sb-color, var(--accent));
  font-size: 18px; letter-spacing: .02em; margin-top: 14px;
}

.kal-festival h3 { font-size: 36px; font-weight: 700; letter-spacing: -0.02em; line-height: 1.05; margin: 0 0 12px; }
.kal-festival .where { display: flex; gap: 24px; color: var(--fg-2); font-size: 14px; align-items: center; flex-wrap: wrap; }
.kal-festival .where .dot { width: 4px; height: 4px; background: var(--fg-3); border-radius: 50%; display: inline-block; }
.kal-festival .blurb { margin-top: 16px; color: var(--fg-2); font-size: 15px; line-height: 1.55; max-width: 480px; }

.kal-festival .actions { flex-direction: column; align-items: stretch; min-width: 180px; }
.kal-festival .actions .btn.is-soon { background: var(--border-soft); color: var(--fg-3); cursor: not-allowed; }
.kal-festival .actions .btn.is-soon:hover { background: var(--border-soft); }
.kal-festival .actions .pill {
  display: flex; justify-content: space-between;
  background: rgba(255,255,255,0.04); border: 1px solid var(--border);
  padding: 8px 12px; font-size: 11px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
}
.kal-festival .actions .pill b { color: var(--sb-color, var(--accent)); }

/* =========================================================================
   SEKCJA: benefits-grid (siatka korzyści/wartości)
   Wzorzec: pillars.html (.cards4/.wartosc)
   ========================================================================= */
.benefits { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--border); border: 1px solid var(--border); }
.benefit { background: var(--plon-black); padding: 28px 22px; min-height: 200px; display: flex; flex-direction: column; gap: 10px; transition: background var(--dur-fast) var(--ease-out-quart); }
.benefit:hover { background: var(--plon-graphite); }
.benefit .b-eyebrow { font-size: 12px; font-weight: 700; letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--accent-text); }
.benefit .b-icon { font-size: 22px; line-height: 1; }
.benefit h3 { font-size: 20px; margin: 0; }
.benefit p { color: var(--fg-2); font-size: 13px; line-height: 1.55; margin: auto 0 0; }

/* DEKORY: benefits-grid (WWW-65, opt-in `section.kv_side` — patrz templates/partials/sections/
   benefits-grid.twig). Klasa gatująca `.has-kv`: `.kv-bg` za treścią. `.kv-bg--{left,right}` =
   strona (generyczne, wyżej), tu tylko rozmiar/pozycja/opacity. */
.section-benefits.has-kv { position: relative; overflow: hidden; }
.section-benefits.has-kv > .container { position: relative; z-index: 1; }
.section-benefits .kv-bg {
  top: 6%; width: 26%; aspect-ratio: 1;
  opacity: var(--kv-bg-op, .12);
  background: var(--sb-color, var(--accent));
  -webkit-mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
}
@media (max-width: 860px) { .section-benefits .kv-bg { opacity: calc(var(--kv-bg-op, .12) * .6); } }

/* =========================================================================
   SEKCJA: event-list (lista wydarzeń — GENERYCZNA: Camp/Młody/Festiwal)
   Wzorzec: list-rows.html (.lrow — data · treść · status · strzałka)
   Akcent = --sb-color (fallback --accent) — kolor subbrandu na [data-sb].
   ========================================================================= */
.section-event-list { scroll-margin-top: 80px; }
.event-list { border-top: 1px solid var(--border); }
.event-row {
  display: grid; grid-template-columns: 132px 1fr auto; gap: 28px; align-items: center;
  padding: 24px 4px; border-bottom: 1px solid var(--border);
}
.ev-date { display: flex; flex-direction: column; gap: 4px; }
.ev-day { font-size: 30px; font-weight: 800; letter-spacing: -.02em; line-height: 1; }
.ev-sub { font-size: 12px; color: var(--fg-3); letter-spacing: var(--tracking-wide); text-transform: uppercase; }
.ev-main { display: flex; flex-direction: column; gap: 8px; min-width: 0; }
.ev-title { font-size: 22px; font-weight: 700; letter-spacing: -.015em; margin: 0; line-height: 1.15; }
.ev-title .ev-sep { color: var(--fg-3); font-weight: 400; }
.ev-title .ev-city { color: var(--accent-text); }
.ev-topic { font-size: 14px; color: var(--fg-2); margin: 0; line-height: 1.5; }
.ev-tags { display: flex; gap: 8px; flex-wrap: wrap; margin-top: 2px; }
.ev-tag { font-size: 11px; letter-spacing: var(--tracking-wide); color: var(--fg-2); border: 1px solid var(--border); padding: 4px 9px; }
.ev-aside { display: flex; flex-direction: column; align-items: flex-end; gap: 10px; text-align: right; }
.ev-status { font-size: 11px; font-weight: 700; letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--fg-3); border: 1px solid var(--border); padding: 4px 10px; white-space: nowrap; }
.ev-status.open { color: var(--accent-text); border-color: var(--sb-color, var(--accent)); }
.ev-cta { display: inline-flex; align-items: center; gap: 8px; font-size: 13px; font-weight: 700; color: var(--accent-text); white-space: nowrap; border-bottom: 1px solid transparent; padding-bottom: 2px; transition: border-color var(--dur-fast) var(--ease-out-quart); }
.ev-cta:hover { border-bottom-color: var(--sb-color, var(--accent)); }
.ev-cta .arrow { width: 14px; height: 10px; flex: none; }
.ev-intro { margin-top: 4px; max-width: 620px; color: var(--fg-2); font-size: 15px; line-height: 1.55; }
.ev-note { margin-top: 20px; color: var(--fg-3); font-size: 13px; line-height: 1.5; }

/* DEKORY: event-list (WWW-65, opt-in `section.kv_side` — patrz templates/partials/sections/
   event-list.twig). Klasa gatująca `.has-kv`: `.kv-bg` za treścią. `.kv-bg--{left,right}` =
   strona (generyczne, wyżej), tu tylko rozmiar/pozycja/opacity. */
.section-event-list.has-kv { position: relative; overflow: hidden; }
.section-event-list.has-kv > .container { position: relative; z-index: 1; }
.section-event-list .kv-bg {
  top: 10%; width: 28%; aspect-ratio: 1;
  opacity: var(--kv-bg-op, .13);
  background: var(--sb-color, var(--accent));
  -webkit-mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
}
@media (max-width: 860px) { .section-event-list .kv-bg { opacity: calc(var(--kv-bg-op, .13) * .6); } }

/* =========================================================================
   SEKCJA: speaker-grid (siatka prelegentów — GENERYCZNA: Camp/Młody/Festiwal)
   Wzorzec: person-card.html (.sp-card — inicjały/foto · nazwisko · bio · edycja)
   ========================================================================= */
.speaker-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); gap: 16px; }
.sp-card { background: var(--plon-graphite); border: 1px solid var(--border); display: flex; flex-direction: column; transition: border-color var(--dur-fast) var(--ease-out-quart); }
.sp-card:hover { border-color: var(--sb-color, var(--accent)); }
.sp-photo { aspect-ratio: 4/5; background: var(--plon-gray-850); display: flex; align-items: center; justify-content: center; overflow: hidden; }
.sp-photo img { width: 100%; height: 100%; object-fit: cover; }
.sp-photo .initials { font-family: var(--font-serif); font-style: italic; font-weight: 700; font-size: 44px; color: var(--accent-text); }
.sp-body { padding: 18px; display: flex; flex-direction: column; gap: 8px; }
.sp-body .nm { font-size: 16px; font-weight: 700; line-height: 1.2; }
.sp-body .sp-bio { font-size: 13px; color: var(--fg-2); line-height: 1.5; }
.sp-body .sp-edition { margin-top: 4px; font-size: 10px; letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--fg-3); }
.sp-intro { margin-top: 4px; max-width: 620px; color: var(--fg-2); font-size: 15px; line-height: 1.55; }

/* DEKORY: speaker-grid (WWW-65, opt-in `section.kv_side` — patrz templates/partials/sections/
   speaker-grid.twig). Klasa gatująca `.has-kv`: `.kv-bg` za treścią, wzorem person-grid (namespace
   .sp- — zero kolizji z .pg-). `.kv-bg--{left,right}` = strona (generyczne, wyżej), tu tylko
   rozmiar/pozycja/opacity. */
.section-speaker-grid.has-kv { position: relative; overflow: hidden; }
.section-speaker-grid.has-kv > .container { position: relative; z-index: 1; }
.section-speaker-grid .kv-bg {
  top: 8%; width: 34%; aspect-ratio: 1;
  opacity: var(--kv-bg-op, .14);
  background: var(--sb-color, var(--accent));
  -webkit-mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
}
@media (max-width: 860px) { .section-speaker-grid .kv-bg { opacity: calc(var(--kv-bg-op, .14) * .6); } }

/* =========================================================================
   SEKCJA: person-grid (siatka osób z portretem — Zespół/O nas) — WWW-17
   RÓŻNI SIĘ od speaker-grid (initials-first/prelegenci, powyżej — NIETKNIĘTA):
   person-grid to portret jako pierwszy wybór; fallback (brak/404 foto) = kadr
   4:5 + inicjały z `name`. Namespace .pg-* — zero kolizji z .sp-* / .partner-*.
   ========================================================================= */
/* Siatka osób. `--pg-cols` (opt-in, ustawiane przez modyfikator `.pg-grid--6`) pozwala sekcji
   zażądać konkretnej liczby kolumn na desktopie; domyślnie zostaje elastyczne auto-fill. */
.pg-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); gap: 16px; }
.pg-grid--6 { grid-template-columns: repeat(6, minmax(0, 1fr)); }
/* Przycisk w wąskiej (6-kolumnowej) karcie: pełna szerokość, tekst wyśrodkowany, STAŁA wysokość.
   Powód zmierzony, nie estetyczny: przy kolumnie ~176 px etykiety różnią się liczbą linii
   („Poznaj Piotra" mieści się w jednej, „Poznaj Mateusza" łamie się na dwie). Dolne krawędzie
   były równe dzięki `margin-top: auto`, ale GÓRNE skakały o 20 px — a właściciel prosił o
   przycisk „na tej samej wysokości w każdym boksie". `min-height` w miejsce naturalnej wysokości
   zrównuje obie krawędzie niezależnie od długości imienia. */
.pg-grid--6 .pg-cta {
  width: 100%; justify-content: center; text-align: center; align-self: stretch;
  /* JEDNA linia dla każdej etykiety — inaczej wysokość przycisku zależy od długości imienia
     (zmierzone: „Poznaj Piotra" 56 px w jednej linii vs „Poznaj Mateusza" 65 px w dwóch, czyli
     górne krawędzie rozjeżdżały się o 9–20 px mimo równych kart). Węższy padding i o stopień
     mniejszy krój kupują miejsce w kolumnie ~176 px; `nowrap` gwarantuje jedną linię, a
     `min-height` trzyma wysokość, gdyby krój kiedyś urósł. */
  padding-left: 10px; padding-right: 10px;
  font-size: 13px; white-space: nowrap; min-height: 56px;
}
@media (max-width: 1240px) { .pg-grid--6 { grid-template-columns: repeat(3, minmax(0, 1fr)); } }
@media (max-width: 760px)  { .pg-grid--6 { grid-template-columns: repeat(2, minmax(0, 1fr)); } }
@media (max-width: 460px)  { .pg-grid--6 { grid-template-columns: minmax(0, 1fr); } }
.pg-card { position: relative; background: var(--plon-graphite); border: 1px solid var(--border); display: flex; flex-direction: column; transition: border-color var(--dur-fast) var(--ease-out-quart); }
.pg-card:hover { border-color: var(--sb-color, var(--accent)); }
.pg-photo { aspect-ratio: 4/5; background: var(--plon-gray-850); display: flex; align-items: center; justify-content: center; overflow: hidden; }
.pg-photo img { width: 100%; height: 100%; object-fit: cover; }
.pg-photo .initials { font-family: var(--font-serif); font-style: italic; font-weight: 700; font-size: 40px; color: var(--accent-text); }
.pg-body { padding: 18px; display: flex; flex-direction: column; gap: 6px; flex: 1 1 auto; }
.pg-body .nm { font-size: 16px; font-weight: 700; line-height: 1.2; }
.pg-role { font-size: 11px; letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--accent-text); }
.pg-bio { font-size: 13px; color: var(--fg-2); line-height: 1.5; margin: 4px 0 0; }
/* WWW-78: `position/z-index` podnoszą `.pg-links` NAD overlay `.pg-cta::after` (z-index: 1).
   Bez tego link zewnętrzny (np. LinkedIn) renderowałby się i wyglądał klikalnie, ale kliknięcie
   trafiałoby w stretched link karty i prowadziło do `/profil/<slug>` — cichy regres bez sygnału
   z walidatora. Kombinacji `profil` + `links` nie ma dziś w treści, ale pole `links` jest nadal
   udokumentowane w `person-grid.twig` i chronił ją jawnie kod WWW-61. */
.pg-links { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 8px; position: relative; z-index: 2; }
.pg-links a { font-size: 12px; font-weight: 600; color: var(--accent-text); border-bottom: 1px solid transparent; }
.pg-links a:hover, .pg-links a:focus-visible { border-bottom-color: var(--accent); }
.pg-links a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.pg-intro { margin-top: 4px; max-width: 620px; color: var(--fg-2); font-size: 15px; line-height: 1.55; }
/* WWW-78: cała karta klikalna wzorcem „stretched link" — ZASTĘPUJE dwa osobne linki WWW-61
   (`.pg-photo a` / `.pg-body a.nm`, usunięte z twiga razem z tym CSS). `.pg-cta` jest JEDYNYM
   `<a>` w karcie; jego `::after` rozciąga cel kliknięcia na cały `.pg-card` (position: relative,
   patrz reguła wyżej), dzięki czemu nie ma zagnieżdżonych linków ani wielokrotnych celów dla
   czytnika ekranu. Fokus klawiaturą pokazuje obwódkę na CAŁEJ karcie, nie tylko na przycisku —
   `:has()` (Chrome/Safari/Firefox aktualne wersje wspierają); brak wsparcia dla `:has()` = brak
   obwódki karty, ale sam link `.pg-cta` nadal dostaje DOMYŚLNY fokus przeglądarki (nie usuwamy
   `outline` nigdzie w regule) — bez regresji „znika fokus całkiem". */
/* Przycisk DOCISKANY DO DOŁU karty (korekta właściciela 2026-07-30: „przycisk zawsze wyrównany
   do dołu — cel: przycisk na tej samej wysokości w każdym boksie"). `margin-top: auto` w kolumnie
   flex zjada całą wolną przestrzeń nad przyciskiem, więc różnej długości bio nie przesuwa go już
   w pionie; `.pg-body` musi przy tym rosnąć na całą wysokość karty (`flex: 1`), inaczej „dół"
   znaczyłby dół tekstu, a nie dół kafla. */
.pg-cta { margin-top: auto; padding-top: 10px; align-self: flex-start; text-decoration: none; }
.pg-cta::after { content: ""; position: absolute; inset: 0; z-index: 1; }
.pg-card:has(.pg-cta:focus-visible) { outline: 2px solid var(--accent); outline-offset: 4px; }

/* DEKORY: person-grid (WWW-53, opt-in `section.kv_side` — patrz templates/partials/sections/
   person-grid.twig). Sekcja jako positioning context (wzorzec .section-hero); `.kv-bg--{left,right}`
   ustawia stronę (generyczne, wyżej), tu tylko rozmiar/pozycja pionowa/opacity/recolor CSS-maska
   (§3.2 flat-mint) + poświata §3.4. Kanon Festiwal: kv_side=left (naprzemienność P/L/P, WWW-53). */
.section-person-grid { position: relative; overflow: hidden; }
.section-person-grid > .container { position: relative; z-index: 1; }
.section-person-grid .kv-bg {
  top: 8%; width: 40%; aspect-ratio: 1;
  opacity: var(--kv-bg-op, .16);
  background: var(--sb-color, var(--accent));
  -webkit-mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
}
.section-person-grid.has-kv::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: radial-gradient(560px 380px at 0% 30%, color-mix(in srgb, var(--sb-color, var(--accent)) 16%, transparent), transparent 60%);
}
@media (max-width: 860px) { .section-person-grid .kv-bg { opacity: calc(var(--kv-bg-op, .16) * .6); } }

/* =========================================================================
   SEKCJA: partner-grid (siatka logotypów — mono→hover kolor) — WWW-17
   RÓŻNI SIĘ od partner-cards (karty FORM partnerstwa, .partner-grid/.partner-card
   powyżej — NIETKNIĘTE): partner-grid to wyłącznie logotypy. Namespace .plg-* —
   zero kolizji z .partner-grid. Fallback (brak/404 logo) = tekst (nazwa partnera).
   ========================================================================= */
/* DEKORY: partner-grid (WWW-54, opt-in `section.kv_side` — patrz templates/partials/sections/
   partner-grid.twig). Partial renderuje się DWUKROTNIE na Festiwalu (Partnerzy=left/
   Patronat=right) — `.kv-bg--{left,right}` (generyczne, wyżej) ustawia stronę per-instancja;
   tu tylko rozmiar/pozycja/opacity. */
.section-partner-grid.has-kv { position: relative; overflow: hidden; }
.section-partner-grid.has-kv > .container { position: relative; z-index: 1; }
.section-partner-grid .kv-bg {
  top: 6%; width: 28%; aspect-ratio: 1;
  opacity: var(--kv-bg-op, .12);
  background: var(--sb-color, var(--accent));
  -webkit-mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
}
@media (max-width: 860px) { .section-partner-grid .kv-bg { opacity: calc(var(--kv-bg-op, .12) * .6); } }
/* WWW-79: siatka partnerów/patronatu na 4 kolumny (było auto-fill@160px → 7 kolumn przy
   kontenerze 1136px). Przy 4 realnych podmiotach siedmiokolumnowy rytm zostawiał pusty pas
   po prawej. `partner-grid` występuje wyłącznie na /festiwal (grep 2026-07-27:
   content/*.md — `- type: partner-grid` = 2 w festiwal.md, 0 gdzie indziej) — zmiana bazowej
   reguły nie dotyka innych podstron, scoping niepotrzebny. */
.plg-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--border); border: 1px solid var(--border); }
.plg-tile { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 8px; min-height: 96px; padding: 16px; background: var(--bg); }
.plg-mark { display: flex; align-items: center; justify-content: center; width: 100%; height: 48px; }
.plg-mark img { max-width: 100%; max-height: 100%; object-fit: contain; filter: grayscale(1); opacity: .72; transition: filter var(--dur-fast) var(--ease-out-quart), opacity var(--dur-fast) var(--ease-out-quart); }
.plg-name { font-size: 13px; font-weight: 700; letter-spacing: .01em; text-align: center; color: var(--fg-2); line-height: 1.3; transition: color var(--dur-fast) var(--ease-out-quart); }
/* Kafel na jasnym tle (`plate: true` w content, partner-grid.twig — korekta właściciela 2026-07-30).
   Powód: logotyp ANS istnieje tylko z czarną typografią; na `--bg` (#0A0A0A) kontrast ≈1,05:1,
   czyli znak znika, a przemalowanie cudzego logo jest niedopuszczalne. Jasne tło dostaje więc CAŁY
   kafel, nie sam obraz. Zdejmujemy `grayscale`/`opacity` — na białym przygaszanie dawałoby szary
   napis zamiast czarnego. Etykieta `plg-tier` musi zmienić kolor, bo jasnoszary tekst na białym
   spada poniżej progu czytelności. */
.plg-tile--plate { background: var(--bg-inverse); }
.plg-tile--plate .plg-mark img { filter: none; opacity: 1; }
.plg-tile--plate .plg-name { color: var(--plon-black); }
.plg-tile--plate .plg-tier { color: var(--plon-black); opacity: .64; }
.plg-tile:hover .plg-mark img, .plg-tile:focus-within .plg-mark img { filter: grayscale(0); opacity: 1; }
.plg-tile:hover .plg-name, .plg-tile:focus-within .plg-name { color: var(--accent-text); }
a.plg-mark:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.plg-tier { font-size: 9px; letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--fg-3); }
/* Podpis pod znakiem (`show_name: true`) — kto stoi za patronatem/partnerstwem, gdy sam logotyp
   tego nie mówi (np. ogólny znak województwa przy patronacie Marszałka). Jaśniejszy i większy od
   `.plg-tier`, bo to nazwa własna, a nie etykieta rangi; kafel ma `min-height: 96px` i układ
   kolumnowy, więc dodatkowy wiersz rośnie w dół bez rozpychania sąsiadów w rzędzie. */
.plg-caption { font-size: 12px; line-height: 1.35; text-align: center; color: var(--fg-2); max-width: 22ch; }
.plg-tile--plate .plg-caption { color: var(--plon-black); }
.plg-intro { margin-top: 4px; max-width: 620px; color: var(--fg-2); font-size: 15px; line-height: 1.55; }

/* =========================================================================
   SEKCJA: schedule (program dni — GENERYCZNA: Festiwal/Camp)
   Wzorzec: schedule.html (.schedule__tab / .schedule__row). Render bez JS —
   dni jako bloki (nagłówek-dnia + wiersze), wszystkie widoczne.
   ========================================================================= */
.section-schedule { scroll-margin-top: 80px; }
.schedule { display: flex; flex-direction: column; gap: 36px; }
.sch-daytab { display: flex; align-items: baseline; gap: 14px; flex-wrap: wrap; padding: 16px 20px; background: var(--plon-graphite); border: 1px solid var(--border); border-top: 2px solid var(--accent); }
.sch-daytab .d { font-family: var(--font-serif); font-style: italic; font-weight: 700; font-size: 26px; color: var(--accent-text); line-height: 1; }
.sch-daytab .day { font-weight: 700; font-size: 15px; text-transform: capitalize; }
.sch-daytab .topic { font-size: 11px; letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--fg-3); }
.sch-rows { border-top: 0; }
.sch-row { display: grid; grid-template-columns: 110px 1fr; gap: 24px; padding: 18px 4px; border-bottom: 1px solid var(--border); align-items: start; }
.sch-row .time { font-family: var(--font-serif); font-style: italic; font-weight: 700; font-size: 20px; color: var(--accent-text); line-height: 1.3; }
.sch-main { min-width: 0; }
.sch-main .title { font-size: 17px; font-weight: 600; line-height: 1.35; display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.sch-main .who { font-size: 13px; color: var(--fg-3); margin-top: 6px; }
/* chip programu (Keynote / Scena A …) — reuse: schedule + inne sekcje */
.tag { font-size: 10px; letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--accent-text); border: 1px solid var(--accent); padding: 2px 7px; display: inline-block; line-height: 1.5; }

/* =========================================================================
   SEKCJA: location (miejsce — GENERYCZNA: Festiwal/Camp)
   Wzorzec: location.html (.location / .map / .pin / .locrow). Mapa = placeholder
   (pin + puls „ping"); realny widget przez map_embed (raw).
   ========================================================================= */
/* DEKORY: location (WWW-54, opt-in `section.kv_side` — patrz templates/partials/sections/
   location.twig). Sekcja jako positioning context (wzorzec .section-hero); `.kv-bg--{left,right}`
   ustawia stronę (generyczne, wyżej), tu tylko rozmiar/pozycja/opacity. */
.section-location { scroll-margin-top: 80px; position: relative; overflow: hidden; }
.section-location > .container { position: relative; z-index: 1; }
.section-location .kv-bg {
  top: 10%; width: 30%; aspect-ratio: 1;
  opacity: var(--kv-bg-op, .13);
  background: var(--sb-color, var(--accent));
  -webkit-mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
}
@media (max-width: 860px) { .section-location .kv-bg { opacity: calc(var(--kv-bg-op, .13) * .6); } }
.location { display: grid; grid-template-columns: 1.2fr 1fr; gap: 28px; align-items: start; }
.loc-map { position: relative; aspect-ratio: 4/3; background: var(--plon-graphite); border: 1px solid var(--border); overflow: hidden; display: flex; align-items: center; justify-content: center; }
.loc-map iframe, .loc-map img { width: 100%; height: 100%; border: 0; object-fit: cover; }
.loc-pin { position: absolute; left: 46%; top: 50%; width: 14px; height: 14px; border-radius: 50%; background: var(--accent); }
.loc-pin::after { content: ""; position: absolute; inset: -8px; border-radius: 50%; border: 1px solid var(--accent); animation: ping 1.8s infinite; }
.loc-coord { position: absolute; bottom: 12px; left: 14px; font-size: 11px; letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--fg-3); }
.loc-venue { display: flex; flex-direction: column; gap: 4px; margin-bottom: 18px; }
.loc-name { font-size: 20px; font-weight: 700; line-height: 1.2; }
.loc-addr { font-size: 13px; color: var(--fg-3); line-height: 1.45; }
.loc-date { font-size: 12px; letter-spacing: var(--tracking-wide); text-transform: uppercase; color: var(--accent-text); margin-top: 4px; }
.loc-rows { border-top: 1px solid var(--border); }
.loc-row { display: flex; justify-content: space-between; align-items: flex-start; gap: 14px; padding: 14px 0; border-bottom: 1px solid var(--border); }
.loc-rmain { display: flex; flex-direction: column; gap: 3px; min-width: 0; }
.loc-rlabel { font-size: 11px; letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--fg-3); }
.loc-rname { font-size: 15px; font-weight: 600; line-height: 1.3; }
.loc-rnote { font-size: 12px; color: var(--fg-3); line-height: 1.45; }
.loc-marker { width: 24px; height: 24px; flex: none; border: 1px solid var(--accent); color: var(--accent-text); font-size: 12px; font-weight: 700; display: inline-flex; align-items: center; justify-content: center; }
.loc-note { margin-top: 16px; color: var(--fg-3); font-size: 13px; line-height: 1.55; }
@keyframes ping { 0% { transform: scale(.6); opacity: 1; } 100% { transform: scale(1.8); opacity: 0; } }

/* =========================================================================
   RESPONSYWNOŚĆ
   ========================================================================= */
@media (max-width: 1080px) {
  .nav-menu { display: none; }
  .nav-toggle { display: inline-flex; }
  .nav-cta .btn { display: none; }
}
@media (max-width: 860px) {
  .founder-card, .foot-grid { grid-template-columns: 1fr; }
  .stats, .two-cols .pillars { grid-template-columns: repeat(2, 1fr); }
  .tiers, .partner-grid { grid-template-columns: 1fr; }
  /* WWW-79: `#bilety .tiers` (l. ~754, specificity id+class = 1,1,0) jest MOCNIEJSZY niż `.tiers`
     powyżej (0,1,0) — bez tej linii dwa bilety zostałyby wymuszone na 2 kolumny NAWET pod 860px,
     psując stack mobilny, który reguła wyżej ustawia dla wszystkich innych `.tiers` (w tym
     /wspolpraca). Powtórzenie tej samej wartości `1fr` z wyższą specyficznością przywraca stack. */
  #bilety .tiers { grid-template-columns: 1fr; }
  .benefits { grid-template-columns: repeat(2, 1fr); }
  .ini-grid { grid-template-columns: repeat(2, 1fr); }
  .kal-festival { grid-template-columns: 1fr; }
  .timeline { grid-auto-flow: row; }
  .tl-cell { border-right: 0; border-bottom: 1px solid var(--border); }
  .foot-grid { grid-template-columns: 1fr 1fr; }
  /* event-row: data u góry, treść, aside na dole (wyrównane do lewej) */
  .event-row { grid-template-columns: 96px 1fr; gap: 16px 20px; }
  .ev-aside { grid-column: 1 / -1; flex-direction: row; align-items: center; justify-content: flex-start; text-align: left; }
  .location { grid-template-columns: 1fr; }
  .sch-row { grid-template-columns: 84px 1fr; gap: 16px; }
  .idea-grid { grid-template-columns: 1fr; gap: 40px; }
  .section-head { grid-template-columns: 1fr; }
}
@media (max-width: 560px) {
  .stats, .two-cols .pillars, .value-cards .cards, .foot-grid { grid-template-columns: 1fr; }
  .benefits { grid-template-columns: 1fr; }
  .ini-grid { grid-template-columns: 1fr; }
  .speaker-grid, .pg-grid { grid-template-columns: repeat(2, 1fr); }
  .plg-grid { grid-template-columns: repeat(2, 1fr); }
  .cta-festival { padding: 40px 22px; }
  /* WWW-85 (E1): pod tym samym breakpointem co skok paddingu (odległość przycisków
     od dołu sekcji spada z ~58px do ~34px) — cap warstwy fal musi się skurczyć
     razem z nią, inaczej 0,257×layerH zjada cały prześwit (był FAIL na 390px,
     `tools/check-cta-waves.py`). 78px dobrane tak, by zostało ≥8px prześwitu
     na najciaśniejszej trasie z gate'u. */
  .cta-festival .lines { height: min(38%, 78px); }
  .meta-row { gap: 24px; }
  .sch-row { grid-template-columns: 1fr; gap: 6px; }
  .kal-festival { padding: 28px 24px; gap: 28px; }
  .kal-festival .big-date .d { font-size: 64px; }
}

/* prefers-reduced-motion — wyłącz przejścia dekoracyjne */
@media (prefers-reduced-motion: reduce) {
  *, *::before, *::after { transition-duration: .01ms !important; animation-duration: .01ms !important; }
  /* REVEAL-ON-SCROLL + count-up (WWW-13) — treść od razu widoczna, bez czekania na scroll/IO;
     reveal.js sam pilnuje count-up (matchMedia w JS ustawia wartość docelową bez animacji). */
  .reveal, .reveal-stagger > * { opacity: 1 !important; transform: none !important; }
  /* DEKORY KV/sig-lines/glify (WWW-12) — twardy stop ruchu (nie tylko skrócenie) */
  .sig-lines .drift-a, .sig-lines .drift-b,
  .hero-kv-art, .hero-kv-art-sb,
  .cta-festival .lines .wave-drift,
  .kv-bg.breathe svg, .kv-bg.breathe img, .kv-bg.breathe .kv-bg-art-sb,
  .kv-bg.spin svg, .kv-bg.spin img,
  .kv-accent.float, .kv-accent.spin,
  .kv-accent.float img, .kv-accent.float svg, .kv-accent.float .kv-accent-art-sb,
  .kv-accent.spin img, .kv-accent.spin svg, .kv-accent.spin .kv-accent-art-sb,
  .wartosc-glyph { animation: none !important; }
  .kv-accent { transform: none !important; }
  .kv-accent.kv-enter { opacity: var(--kv-target-op, .4) !important; }
  .kv-accent.kv-enter img, .kv-accent.kv-enter svg, .kv-accent.kv-enter .kv-accent-art-sb { transform: none !important; }
}

/* === KONTAKT: formularz / dane rejestrowe / social (WWW-06) ==============
   Wzorce: design-hub form-contact.html (.topic-pills/.field) + card-social.html
   (.social-card/.org-card). Wyłącznie var(--token) — zero HEX (WA04). */
.container-narrow { max-width: var(--max-w-prose); }

/* --- contact-form --- */
.contact-form .lbl {
  font-size: 11px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
  color: var(--fg-3); margin: 0 0 12px;
}
.topic-pills { display: flex; flex-wrap: wrap; gap: 10px; margin-bottom: var(--space-5); }
.topic-pills .pill {
  display: inline-flex; align-items: center; gap: 8px;
  padding: 9px 16px; background: var(--bg-elevated); border: 1px solid var(--border);
  color: var(--fg-2); font-family: var(--font-sans); font-size: 13px; font-weight: 600;
  cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out-quart), border-color var(--dur-fast) var(--ease-out-quart), background var(--dur-fast) var(--ease-out-quart);
}
.topic-pills .pill .dot { width: 6px; height: 6px; background: var(--fg-3); flex: none; transition: background var(--dur-fast) var(--ease-out-quart); }
.topic-pills .pill:hover { color: var(--fg-1); border-color: var(--fg-2); }
.topic-pills .pill.active { color: var(--accent-fg); background: var(--accent); border-color: var(--accent); }
.topic-pills .pill.active .dot { background: var(--accent-fg); }
.topic-pills .pill:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.cf-form { display: flex; flex-direction: column; gap: var(--space-4); }
.cf-form .form-row { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-4); }
.cf-form .field { display: flex; flex-direction: column; gap: 6px; }
.cf-form .field > label { font-size: 13px; font-weight: 600; color: var(--fg-2); }
.cf-form .req { color: var(--accent-text); }
.cf-form input, .cf-form textarea {
  width: 100%; padding: 12px 14px; font-family: var(--font-sans); font-size: 15px;
  color: var(--fg-1); background: var(--bg-elevated); border: 1px solid var(--border);
  transition: border-color var(--dur-fast) var(--ease-out-quart);
}
.cf-form input::placeholder, .cf-form textarea::placeholder { color: var(--fg-3); }
.cf-form textarea { resize: vertical; min-height: 120px; }
.cf-form input:focus-visible, .cf-form textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-color: var(--accent); }
.cf-form .field.has-error input, .cf-form .field.has-error textarea { border-color: var(--plon-red); }
.field-err { color: var(--plon-red); font-size: 12px; line-height: 1.4; }
.field-err:empty { display: none; }

.cf-form .field-check { flex-direction: column; }
.checkbox-row { display: flex; align-items: flex-start; gap: 10px; font-size: 13px; line-height: 1.5; color: var(--fg-2); font-weight: 400; cursor: pointer; }
.checkbox-row input[type="checkbox"] { margin-top: 1px; width: 18px; height: 18px; flex: none; accent-color: var(--accent); }
.checkbox-row input[type="checkbox"]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.form-actions { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; margin-top: var(--space-2); }
.form-actions .micro { font-size: 12px; color: var(--fg-3); }

.cf-status { margin: var(--space-3) 0 0; padding: 12px 14px; font-size: 14px; line-height: 1.5; color: var(--fg-1); background: var(--bg-elevated); border-left: 2px solid var(--accent); }
.cf-status a { color: var(--accent-text); border-bottom: 1px solid var(--accent); }

/* --- social-cards --- */
.social-grid { display: grid; grid-template-columns: repeat(4, 1fr); gap: 1px; background: var(--border); border: 1px solid var(--border); }
.social-card { display: flex; flex-direction: column; gap: 10px; padding: 24px 20px; background: var(--bg); transition: background var(--dur-fast) var(--ease-out-quart); }
.social-card:hover { background: var(--bg-elevated); }
.social-card:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.social-card .icon { width: 28px; height: 28px; color: var(--accent-text); }
.social-card .icon svg { width: 100%; height: 100%; display: block; }
.social-card .platform { font-size: 11px; letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--fg-3); }
.social-card h3 { font-size: 16px; font-weight: 700; color: var(--fg-1); line-height: 1.3; }
.social-card .handle { margin-top: auto; font-size: 13px; font-weight: 600; color: var(--accent-text); }

/* --- contact-details (org-card) --- */
.org-card { background: var(--bg-elevated); border: 1px solid var(--border); padding: var(--space-6); max-width: var(--max-w-prose); }
.org-card h3 { font-size: 18px; font-weight: 700; color: var(--fg-1); margin-bottom: var(--space-4); }
.org-rows { display: flex; flex-direction: column; }
.org-rows .row { display: grid; grid-template-columns: 96px 1fr; gap: 16px; padding: 12px 0; border-top: 1px solid var(--border); }
.org-rows .row:first-child { border-top: 0; padding-top: 0; }
.org-rows .k { font-size: 12px; letter-spacing: var(--tracking-caps); text-transform: uppercase; color: var(--fg-2); }
.org-rows .v { font-size: 15px; color: var(--fg-1); }
.org-rows .v.mono { font-family: var(--font-mono); letter-spacing: .02em; }
.org-rows .v a { color: var(--accent-text); border-bottom: 1px solid transparent; }
.org-rows .v a:hover { border-bottom-color: var(--accent); }

/* DEKORY: contact-form (WWW-70, opt-in `section.kv_side` — patrz templates/partials/sections/
   contact-form.twig). Sekcja jako positioning context (wzorzec .section-hero); `.kv-bg--{left,right}`
   ustawia stronę (generyczne, wyżej), tu tylko rozmiar/pozycja/opacity/recolor CSS-maska (§3.2
   flat-mint). Rotacja §3.5: kontakt = contact-form LEWO. */
.section-contact-form { position: relative; overflow: hidden; }
.section-contact-form > .container { position: relative; z-index: 1; }
.section-contact-form .kv-bg {
  top: 6%; width: 34%; aspect-ratio: 1;
  opacity: var(--kv-bg-op, .13);
  background: var(--sb-color, var(--accent));
  -webkit-mask: url(../key-visuals/kv-100-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-100-supporting.svg) center/contain no-repeat;
}
@media (max-width: 860px) { .section-contact-form .kv-bg { opacity: calc(var(--kv-bg-op, .13) * .6); } }

/* DEKORY: contact-details (WWW-70, opt-in `section.kv_side` — patrz templates/partials/sections/
   contact-details.twig). Sekcja jako positioning context; `.kv-bg--{left,right}` = strona
   (generyczne, wyżej), tu tylko rozmiar/pozycja/opacity. Rotacja §3.5: kontakt = contact-details
   PRAWO (naprzemienność w dół strony: hero P / contact-form L / social-cards — / contact-details P). */
.section-contact-details { position: relative; overflow: hidden; }
.section-contact-details > .container { position: relative; z-index: 1; }
.section-contact-details .kv-bg {
  top: 10%; width: 30%; aspect-ratio: 1;
  opacity: var(--kv-bg-op, .12);
  background: var(--sb-color, var(--accent));
  -webkit-mask: url(../key-visuals/kv-100-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-100-supporting.svg) center/contain no-repeat;
}
@media (max-width: 860px) { .section-contact-details .kv-bg { opacity: calc(var(--kv-bg-op, .12) * .6); } }

/* WWW-85 (KON-01 + KON-05): układ „newsletter-like" (wzorzec .nl-card/.nl-panel/.nl-main,
   templates/partials/newsletter.twig:30-44) dla obie sekcje na /kontakt — treść z lewej
   (~60%), dekor z prawej (~40%) — ≥861px (spójne z progiem 860px używanym już przez
   .kv-bg wyżej). BEZ zmiany markupu: `.kv-bg` <span> istnieje już w DOM (WWW-70, opt-in
   `section.kv_side`) jako rodzeństwo `.container` — tu tylko przenosimy go z warstwy
   tła (position:absolute) do realnej komórki grid (`grid-column:2`), niezależnie od
   `kv_side` (left/right = rotacja pływającego blobu na INNYCH stronach/sekcjach —
   tu ujednolicona na PRAWO wg decyzji KON-01/05). Padding przeniesiony z `.container`
   na sekcję (ta sama wartość var(--space-6)), by nie dublować go w komórce grid.

   POPRAWKA PO RECENZJI: pierwsza iteracja tylko przenosiła `.kv-bg` do kolumny 2 —
   sam element zostawał półprzezroczystą (opacity .12/.13) plamą blend-mode:screen,
   niewidoczną na czarnym tle sekcji (kolumna wyglądała na pustą, gorzej niż
   wyśrodkowany blok sprzed zmiany). `.nl-panel` maluje tło PRZEZ osobny box
   (background:var(--bg)) i dopiero WEWNĄTRZ niego osadza świecącą ikonę
   (.nl-hex-glow + .nl-hex-art) — `.kv-bg` nie ma takich dzieci w markupie (jeden
   goły <span>), a `mask` na elemencie obcina RAZEM z nim całą jego zawartość
   (więc `background` + `mask` na TYM SAMYM elemencie nie mogą jednocześnie dać
   „box tła" + „ikona w kształcie"). Rozwiązanie bez dotykania twiga: tło+ramka
   idą na SAM `.kv-bg` (jak `.nl-panel`), maskowana ikona i poświata schodzą na
   `::before`/`::after` (odpowiedniki `.nl-hex-glow`/`.nl-hex-art`, generowane
   przez CSS — zero nowych węzłów DOM). `opacity:1`/`mix-blend-mode:normal`
   neutralizują bazową regułę `.kv-bg` (L442, myślaną pod SUBTELNY blob w tle
   treści, nie pod samodzielny panel).
   Mobile (<861px) BEZ ZMIAN: dekor wraca do pływającego blobu za treścią — ten sam
   wzorzec co pozostałe ~15 sekcji z `.kv-bg` w tym pliku (spójność, zero specjalnego
   przypadku tylko dla /kontakt na małym ekranie). */
@media (min-width: 861px) {
  .section-contact-form,
  .section-contact-details {
    max-width: var(--max-w-content); margin: 0 auto;
    padding-left: var(--space-6); padding-right: var(--space-6);
    display: grid; grid-template-columns: minmax(0, 3fr) minmax(220px, 2fr);
    align-items: stretch; gap: var(--space-7);
  }
  /* WWW-85 (KON-01/05, poprawka po recenzji): `.kv-bg` żyje w DOM PRZED `.container`
     (WWW-70 — span dekoru renderuje się jako pierwsze dziecko sekcji). Auto-placement
     grida w trybie "sparse" (domyślnym) idzie po kolejności DOM i NIE cofa kursora:
     `.kv-bg` (bez jawnego `grid-row`) zająłby rząd 1/kolumnę 2 jako pierwszy
     napotkany element, a `.container` z samym `grid-column:1` (bez `grid-row`)
     dostałby wtedy rząd 2 (bo rząd 1/kolumna 1 była "przed" kursorem) — efekt:
     DWA rzędy zamiast jednego, treść pod dekorem zamiast obok. Fix: `grid-area`
     przypina OBA elementy do rzędu 1 jawnie (rząd/kolumna w jednym miejscu). */
  .section-contact-form > .container,
  .section-contact-details > .container {
    grid-area: 1 / 1; max-width: none; margin: 0; padding: 0;
  }
  .section-contact-form > .kv-bg,
  .section-contact-details > .kv-bg {
    grid-area: 1 / 2; position: relative;
    /* align-self:stretch (decyzja, nie domyślne dziedziczenie): panel dekoru
       rozciąga się na PEŁNĄ wysokość treści (formularz 680px / dane 498px),
       tak jak .nl-panel wypełnia całą wysokość .nl-card — "start" zostawiłby
       niski prostokąt 280px przyklejony do góry z pustką pod spodem, gorzej niż
       jednolita kolumna dekoru na całą wysokość bloku. */
    align-self: stretch;
    top: auto; left: auto; right: auto; bottom: auto;
    width: 100%; height: 100%; aspect-ratio: auto; min-height: 280px;
    display: grid; place-items: center; overflow: hidden;
    opacity: 1; mix-blend-mode: normal;
    background: var(--bg-elevated); border: 1px solid var(--border);
    mask: none; -webkit-mask: none;
  }
  /* poświata (odpowiednik .nl-hex-glow): plama koloru marki za ikoną, żeby panel
     nie był płaskim szarym prostokątem — ten sam trik co newsletter (radial-gradient
     + color-mix + blur), skalowany do węższej kolumny kontaktu. */
  .section-contact-form > .kv-bg::before,
  .section-contact-details > .kv-bg::before {
    content: ""; position: absolute; inset: -20%; z-index: 0; pointer-events: none;
    background: radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--sb-color, var(--accent)) 40%, transparent), transparent 66%);
    filter: blur(6px);
  }
  /* ikona KV (odpowiednik .nl-hex-art): maska na PSEUDO-elemencie, nie na `.kv-bg`
     samym — inaczej `mask` obcięłaby też tło/ramkę panelu (patrz notatka wyżej). */
  .section-contact-form > .kv-bg::after,
  .section-contact-details > .kv-bg::after {
    content: ""; position: relative; z-index: 1;
    width: min(58%, 220px); aspect-ratio: 1;
    background: var(--sb-color, var(--accent));
    -webkit-mask: url(../key-visuals/kv-100-supporting.svg) center/contain no-repeat;
    mask: url(../key-visuals/kv-100-supporting.svg) center/contain no-repeat;
  }
}

/* DEKOR: social-cards (WWW-70, §3.4 glow miękki — bez KV opt-in, audyt kontakt.md: kandydat
   zostaje bez heksagonu, kontakt ma już rotację P/L na contact-form/contact-details). Glow subtelny
   w rogu siatki, wzór §3.4 (radial-gradient color-mix, N ~18 procent). */
.section-social-cards { position: relative; overflow: hidden; }
.section-social-cards > .container { position: relative; z-index: 1; }
.section-social-cards::after {
  content: ""; position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background: radial-gradient(560px 380px at 100% 0%, color-mix(in srgb, var(--sb-color, var(--accent)) 18%, transparent), transparent 60%);
}

@media (max-width: 720px) {
  .cf-form .form-row { grid-template-columns: 1fr; }
  .social-grid { grid-template-columns: repeat(2, 1fr); }
}
@media (max-width: 460px) {
  .social-grid { grid-template-columns: 1fr; }
  .org-rows .row { grid-template-columns: 1fr; gap: 4px; }
}

/* === NEWSLETTER (WWW-B1 → WWW-47 → WWW-50 iteracja 2) =====================
   Wzorzec: design-hub newsletter.html + inspiracje docs/newsletter-inspiracje/
   (insp-1 mozaika geometryczna | insp-2 inline-form). Band nad stopką (footer.twig).
   Wyłącznie var(--token) — zero HEX (WA04). Submit = stub (newsletter.js).
   WWW-50 (rewizja F1 runda 2, „jeszcze jedna iteracja boksu"): układ 2-panel —
   LEWA `.nl-panel/.nl-mosaic` = gęsta mozaika kafli glifów/heksagonów (CSS-maski
   assets/key-visuals/glyphs/*, recolor kolorami marki mint+subbrandy przez
   data-sb → --sb-color; odpowiednik mozaiki z insp-1 zamiast pustej przestrzeni);
   PRAWA `.nl-main` = copy(serif <em>)+bullets + inline `.nl-row` (input + OKRĄGŁY
   przycisk-ikona `.nl-send` paper-plane, mint — jak insp-1). Mobile ≤820px = 1-kol
   (mozaika-pas nad treścią). Formularz/js/aria bez zmian logiki. */
.nl-band { padding: var(--space-9) 0 0; }
.nl-card {
  position: relative; overflow: hidden;
  background: var(--bg-elevated); border: 1px solid var(--border); border-top: 3px solid var(--accent);
  display: grid; grid-template-columns: minmax(240px, 340px) minmax(0, 1fr);
  align-items: stretch;
}

/* LEWA: rozbudowany heksagon MINT z animacją (spin) + mint glow (WWW-51) */
.nl-panel {
  position: relative; overflow: hidden;
  background: var(--bg); border-right: 1px solid var(--border);
  display: grid; place-items: center; padding: var(--space-6); min-height: 300px;
}
.nl-hex { position: relative; width: min(78%, 300px); aspect-ratio: 1; display: grid; place-items: center; }
.nl-hex-glow {
  position: absolute; inset: -24%; z-index: 0; pointer-events: none;
  background: radial-gradient(circle at 50% 50%, color-mix(in srgb, var(--accent) 42%, transparent), transparent 66%);
  filter: blur(6px);
  animation: nlHexGlow 6s ease-in-out infinite;
}
.nl-hex-art {
  position: relative; z-index: 1; width: 100%; height: auto; display: block;
  transform-origin: 50% 50%;
  animation: kv-spin 90s linear infinite;
}
@keyframes nlHexGlow { 0%, 100% { opacity: .5; transform: scale(1); } 50% { opacity: .9; transform: scale(1.06); } }

/* PRAWA: copy + form */
.nl-main { display: flex; flex-direction: column; gap: var(--space-5); justify-content: center; padding: var(--space-7) var(--space-7); min-width: 0; }
.nl-copy { display: flex; flex-direction: column; min-width: 0; }

.nl-card h3 {
  margin-top: 14px; font-size: clamp(24px, 3.2vw, 32px); font-weight: 700;
  line-height: 1.15; letter-spacing: -.02em; color: var(--fg-1);
}
.nl-card h3 em { color: var(--accent-text); font-style: italic; }
.nl-intro { margin-top: 12px; color: var(--fg-2); font-size: 15px; line-height: 1.55; max-width: 46ch; }
.nl-list { list-style: none; margin: var(--space-4) 0 0; padding: 0; display: flex; flex-direction: column; gap: 8px; }
.nl-list li { position: relative; padding-left: 20px; font-size: 14px; line-height: 1.5; color: var(--fg-2); }
.nl-list li::before { content: ""; position: absolute; left: 0; top: 8px; width: 6px; height: 6px; background: var(--accent); }

.nl-form {
  display: flex; flex-direction: column; gap: var(--space-3);
}
.nl-row { display: flex; gap: 10px; align-items: flex-start; }
.nl-field { display: flex; flex-direction: column; gap: 6px; flex: 1 1 auto; min-width: 0; }
.nl-field input[type="email"] {
  width: 100%; padding: 14px 16px; font-family: var(--font-sans); font-size: 15px;
  color: var(--fg-1); background: var(--bg); border: 1px solid var(--border);
  transition: border-color var(--dur-fast) var(--ease-out-quart);
}
.nl-field input[type="email"]::placeholder { color: var(--fg-3); }
.nl-field input[type="email"]:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; border-color: var(--accent); }
.nl-field.has-error input[type="email"] { border-color: var(--plon-red); }

/* OKRĄGŁY przycisk-ikona (paper-plane), mint — insp-1. Ikona czarna = wysoki kontrast na mint. */
.nl-send {
  flex: none; width: 52px; height: 52px; border-radius: 50%;
  display: inline-flex; align-items: center; justify-content: center;
  background: var(--accent); color: var(--plon-black); border: none; cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out-quart);
}
.nl-send:hover { background: var(--accent-hover); }
.nl-send:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
.nl-send .icon { display: block; transition: transform var(--dur-fast) var(--ease-out-quart); }
.nl-send:hover .icon { transform: translate(2px, -2px); }

.nl-check { flex-direction: column; }
.nl-card .micro { font-size: 12px; color: var(--fg-2); line-height: 1.5; }  /* fg-2 (nie fg-3): nota niesie kontekst RODO → AA */

.nl-status { margin: 0; padding: 12px 14px; font-size: 14px; line-height: 1.5; color: var(--fg-1); background: var(--bg-elevated); border-left: 2px solid var(--accent); }
.nl-status[hidden] { display: none; }

@media (max-width: 820px) {
  .nl-card { grid-template-columns: 1fr; }
  .nl-panel { border-right: none; border-bottom: 1px solid var(--border); padding: var(--space-5); min-height: 200px; }
  .nl-hex { width: min(46%, 180px); }
  .nl-main { padding: var(--space-6); }
}
@media (prefers-reduced-motion: reduce) {
  .nl-hex-art, .nl-hex-glow { animation: none; }
}

/* ======================================================================
   MODAL ZAKUPU BILETU (WWW-B2) — UI + submit-STUB (PayU później)
   Wzorzec: design-hub/components/ticket-modal.html. Wyłącznie var(--token).
   ====================================================================== */
.ticket-modal { position: fixed; inset: 0; z-index: 200; display: flex; align-items: center; justify-content: center; padding: var(--space-4); }
.ticket-modal[hidden] { display: none; }
body.ticket-modal-open { overflow: hidden; }

.ticket-modal__overlay { position: absolute; inset: 0; background: color-mix(in srgb, var(--plon-black) 78%, transparent); backdrop-filter: blur(2px); }

.ticket-modal__dialog {
  position: relative; width: 100%; max-width: 460px; max-height: calc(100vh - 2 * var(--space-4));
  overflow-y: auto; background: var(--bg-elevated); border: 1px solid var(--border);
  padding: var(--space-6); display: flex; flex-direction: column; gap: 14px;
  box-shadow: var(--shadow-2);
}
.ticket-modal__dialog:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.ticket-modal__close {
  position: absolute; top: 14px; right: 14px; width: 34px; height: 34px;
  display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 1px solid var(--border); color: var(--fg-2); cursor: pointer;
  transition: color var(--dur-fast) var(--ease-out-quart), border-color var(--dur-fast) var(--ease-out-quart);
}
.ticket-modal__close:hover { color: var(--fg-1); border-color: var(--fg-1); }
.ticket-modal__close:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }

.ticket-modal__title { font-size: 22px; font-weight: 800; letter-spacing: -.02em; line-height: 1.1; margin: 4px 0 0; }
.ticket-modal__desc { font-size: 13px; line-height: 1.55; color: var(--fg-2); margin: 0; }

.ticket-modal__row { display: flex; align-items: center; justify-content: space-between; gap: 14px; flex-wrap: wrap; }
.ticket-modal__qty-label { font-size: 13px; font-weight: 600; color: var(--fg-2); }
.ticket-qty { display: inline-flex; align-items: stretch; border: 1px solid var(--border); background: var(--bg); }
.ticket-qty__btn {
  width: 40px; display: inline-flex; align-items: center; justify-content: center;
  background: transparent; border: 0; color: var(--fg-1); cursor: pointer;
  transition: background var(--dur-fast) var(--ease-out-quart), color var(--dur-fast) var(--ease-out-quart);
}
.ticket-qty__btn:hover { background: var(--border-soft); color: var(--accent-text); }
.ticket-qty__btn:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }
.ticket-qty__input {
  width: 56px; text-align: center; padding: 10px 6px; font-family: var(--font-mono); font-size: 15px;
  color: var(--fg-1); background: transparent; border: 0; border-left: 1px solid var(--border); border-right: 1px solid var(--border);
  -moz-appearance: textfield;
}
.ticket-qty__input::-webkit-outer-spin-button,
.ticket-qty__input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; }
.ticket-qty__input:focus-visible { outline: 2px solid var(--accent); outline-offset: -2px; }

.ticket-modal__total { display: flex; align-items: baseline; justify-content: space-between; gap: 12px; padding: 14px 0; border-top: 1px solid var(--border); border-bottom: 1px solid var(--border); }
.ticket-modal__muted { font-size: 13px; color: var(--fg-2); }
.ticket-modal__amount { font-family: var(--font-serif); font-style: italic; font-weight: 700; font-size: 22px; color: var(--accent-text); }

.ticket-modal__submit { margin-top: 2px; }
.ticket-modal__status { margin: 0; padding: 12px 14px; font-size: 13px; line-height: 1.5; color: var(--fg-1); background: var(--bg); border-left: 2px solid var(--accent); }
.ticket-modal__status[hidden] { display: none; }
.ticket-modal__status:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.ticket-modal__note { font-size: 12px; color: var(--fg-2); line-height: 1.5; margin: 0; }
.ticket-modal__note a { color: var(--accent-text); border-bottom: 1px solid transparent; }
.ticket-modal__note a:hover { border-bottom-color: var(--accent); }

@media (prefers-reduced-motion: reduce) {
  .ticket-modal__overlay { backdrop-filter: none; }
}
@media (max-width: 460px) {
  .ticket-modal__dialog { padding: var(--space-5); }
  .ticket-modal__row { align-items: flex-start; }
}

/* =========================================================================
   A11Y — skip-link + sr-only (WWW-09)
   ========================================================================= */
.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;
}
.skip-link {
  position: absolute; left: 12px; top: -60px; z-index: 200;
  background: var(--accent); color: var(--accent-fg);
  padding: 10px 16px; font-weight: 700; font-size: 14px;
  transition: top var(--dur-fast) var(--ease-out-quart);
}
.skip-link:focus { top: 12px; outline: 2px solid var(--fg-1); outline-offset: 2px; }

/* =========================================================================
   CONSENT BANNER — Consent Mode v2, 4 kategorie RODO (WWW-09 → WWW-20)
   Widoczny tylko gdy skonfigurowano GA4/GTM; slide-up przy pierwszej wizycie.
   Kolory/box WYŁĄCZNIE var(--token) — zero hardkodu (WA04).
   ========================================================================= */
.consent-banner {
  position: fixed; left: 0; right: 0; bottom: 0; z-index: 150;
  background: var(--bg-elevated); border-top: 1px solid var(--border);
  box-shadow: var(--shadow-2);
  transform: translateY(100%); opacity: 0;
  transition: transform var(--dur-base) var(--ease-out-quart), opacity var(--dur-base) var(--ease-out-quart);
}
.consent-banner.hidden { display: none; }
.consent-banner.is-visible { transform: translateY(0); opacity: 1; }
.consent-inner {
  display: flex; align-items: center; gap: var(--space-6);
  padding-top: var(--space-5); padding-bottom: var(--space-5);
  flex-wrap: wrap;
}
.consent-copy { flex: 1 1 340px; min-width: 0; }
.consent-title { font-weight: 700; font-size: 15px; color: var(--fg-1); margin: 0 0 4px; }
.consent-text { font-size: 13px; color: var(--fg-2); line-height: 1.5; margin: 0; }
.consent-text a { color: var(--accent-text); border-bottom: 1px solid transparent; }
.consent-text a:hover { border-bottom-color: var(--accent-text); }

/* Panel kategorii (4 kat. RODO) — rozwijany przez „Dostosuj ustawienia cookies" (WWW-20) */
.consent-cats {
  display: grid;
  gap: 10px;
  margin: var(--space-4) 0 0;
  padding-top: var(--space-4);
  border-top: 1px solid var(--border);
}
.consent-cats.hidden { display: none; }
.consent-cat { display: flex; align-items: flex-start; gap: 12px; cursor: pointer; }
.consent-cat-body { flex: 1 1 auto; min-width: 0; }
.consent-cat-name { display: block; font-weight: 600; font-size: 13px; color: var(--fg-1); }
.consent-cat-tag { font-weight: 400; font-size: 12px; color: var(--fg-3); margin-left: 4px; }
.consent-cat-desc { display: block; font-size: 12px; color: var(--fg-3); line-height: 1.5; margin-top: 2px; }

/* Custom checkbox kategorii — akcent tokenu marki (nie hardkod — WA04) */
.consent-checkbox {
  appearance: none; -webkit-appearance: none;
  width: 18px; height: 18px; margin: 2px 0 0;
  border: 1.5px solid var(--border); border-radius: 4px;
  background: transparent; cursor: pointer; flex: 0 0 auto;
  position: relative;
  transition: background var(--dur-fast) var(--ease-out-quart), border-color var(--dur-fast) var(--ease-out-quart);
}
.consent-checkbox:checked { background: var(--accent); border-color: var(--accent); }
.consent-checkbox:checked::after {
  content: ''; position: absolute; left: 5px; top: 1px; width: 5px; height: 10px;
  border: solid var(--accent-fg); border-width: 0 2px 2px 0; transform: rotate(45deg);
}
.consent-checkbox:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.consent-checkbox:disabled { cursor: not-allowed; opacity: .6; }

.consent-toggle {
  display: inline-block; margin-top: var(--space-4);
  font-size: 12px; font-weight: 600; color: var(--accent-text);
  background: transparent; border: none; padding: 0; cursor: pointer;
  text-decoration: underline;
}
.consent-toggle:hover { color: var(--accent); }

.consent-actions { display: flex; gap: 12px; flex: none; flex-wrap: wrap; }
@media (max-width: 560px) {
  .consent-actions { width: 100%; }
  .consent-actions .btn { flex: 1 1 auto; justify-content: center; }
}
@media (prefers-reduced-motion: reduce) {
  .consent-banner { transition: none !important; transform: none !important; }
}

/* =========================================================================
   PERF — content-visibility dla długich stron (np. Festiwal) (WWW-09)
   Sekcje poza pierwszym ekranem pomijają layout/paint do zbliżenia się do viewportu.
   contain-intrinsic-size rezerwuje przybliżoną wysokość → brak skoków scrolla/CLS.
   ========================================================================= */
.cv-defer,
body.is-long main > section:nth-of-type(n+5) {
  content-visibility: auto;
  contain-intrinsic-size: auto 640px;
}

/* =========================================================================
   SEKCJA: idea (O PL:ON) — blockquote serif + copy + idea-mask KV — WWW-32
   Wzorzec: onepager.css:456-486 (.section-head/.lab, port 1:1 — nazwa różna od
   .section-heading już istniejącej, bo treść jest port verbatim) + :491-563
   (.idea→.section-idea/.idea-grid/blockquote/.copy). .idea-mask NIE portowany
   tu ponownie — już istnieje wyżej (prymityw KV, WWW-12), tylko wpięty w DOM
   przez partial. Kolory przez tokeny: mint→--accent/--accent-text,
   tło/tekst→--border-soft/--fg-*. Padding var(--space-9) 0 dopełnia brak klasy
   generycznej „.section" w markupie partiala (onepager stosował ją przez goły
   selektor elementu `section{}`, tu jest to klasa — bez tego rytm pionowy
   względem sąsiednich sekcji by się rozjechał). */
.section-idea {
  position: relative; overflow: hidden;
  padding: var(--space-9) 0;
  border-top: 1px solid var(--border-soft);
  border-bottom: 1px solid var(--border-soft);
}

.section-head {
  display: grid; grid-template-columns: 220px 1fr auto; gap: 48px; align-items: end;
  margin-bottom: 56px;
}
.section-head .lab {
  font-size: 12px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
  color: var(--fg-3); border-left: 2px solid var(--accent); padding-left: 14px; line-height: 1.5;
}
.section-head h2 {
  font-size: clamp(36px, 4vw, 56px); font-weight: 800; letter-spacing: -0.025em;
  line-height: 1.05; margin: 0; max-width: 720px;
}
.section-head h2 .accent { font-family: var(--font-serif); font-style: italic; font-weight: 700; color: var(--accent-text); }

.idea-grid { display: grid; grid-template-columns: 1.1fr 1fr; gap: 80px; align-items: start; }
.section-idea blockquote {
  font-weight: 700; font-size: clamp(32px, 3.4vw, 48px); line-height: 1.12;
  letter-spacing: -0.015em; max-width: 620px;
}
.section-idea blockquote em { color: var(--accent-text); font-style: italic; }
.section-idea .copy p { color: var(--fg-2); font-size: 17px; line-height: 1.6; }
.section-idea .copy p + p { margin-top: 16px; }
.section-idea .copy .key { color: var(--fg-1); font-weight: 500; }

/* ── idea + zdjęcie ilustracyjne (FEST-1b) ────────────────────────────────────
   OPT-IN: cały blok jest scoped do `.has-foto` / `.idea-grid--foto`, klas które
   idea.twig wypuszcza WYŁĄCZNIE gdy sekcja ma pole `foto`. Sekcja idea bez pola
   (home.md „PL:ON to nie jedno wydarzenie.") nie łapie ani jednej z tych reguł —
   warunek twardy zadania (parytet `/` przed/po).

   Kolizja z dekorem KV — ZMIERZONA, nie założona. `.idea-mask` to warstwa
   `position:absolute; z-index:0` przyklejona do LEWEJ krawędzi (left:0, width:68%,
   maska gradientu 45%→100%), a jej `<img>` ma `height:100%` przy kwadratowym
   kv-100-mint.svg, więc ROŚNIE WSZERZ RAZEM Z WYSOKOŚCIĄ SEKCJI. Zdjęcie podnosi tę
   wysokość z 672px do 871px (1440px viewportu), przez co obraz dekoru sięga x≈879
   przy lewej krawędzi zdjęcia x=785 → realne nałożenie ~94px. Do tego `.container`
   był statyczny, a element pozycjonowany z `z-index:0` maluje się PO treści inline
   (CSS painting order) — mint kalka (16%) ległaby NA zdjęciu. Rozstrzygnięcie:
   dekor zostaje po lewej i zostaje TŁEM — kontener treści dostaje własny
   `z-index:1` (wzorzec `.section-hero .container` / `.section-cta > .container`),
   więc zdjęcie (nieprzezroczyste) przykrywa ogon dekoru zamiast być przez niego
   podbarwiane. Bez zmiany strony dekoru: `kv_side: right` w content/festiwal.md
   dotyczy sekcji z `.kv-bg`, `idea.twig` tego pola nie czyta (rotacja WWW-52
   przypisała `idea` na stałe LEWO) — zdjęcie idzie po PRAWEJ, dekor po LEWEJ.  */
.section-idea.has-foto > .container { position: relative; z-index: 1; }

/* Tekst zawsze w kolumnie 1, zdjęcie w kolumnie 2 na pełną wysokość rzędu — jawne
   przypisanie zamiast auto-placementu, żeby wariant z `quote` + `copy` + `foto`
   (3 dzieci w 2-kolumnowej siatce) nie zepchnął zdjęcia do drugiego rzędu. */
.idea-grid--foto { grid-template-columns: minmax(0, 1.1fr) minmax(0, 1fr); }
.idea-grid--foto > blockquote,
.idea-grid--foto > .copy { grid-column: 1; }
.idea-foto {
  grid-column: 2; grid-row: 1 / -1; align-self: start;
  margin: 0;
  aspect-ratio: 1 / 1;              /* plik 1000×1000 — slot 1:1, bez rozciągania */
  overflow: hidden;
  border: 1px solid var(--border);
  background: var(--plon-gray-800, var(--plon-graphite));
}
.idea-foto img { width: 100%; height: 100%; object-fit: cover; display: block; }

/* Mobile: jedna kolumna, zdjęcie POD tekstem (kolejność DOM = kolejność czytania,
   bez `order` — zdjęcie jest ilustracją domykającą narrację archiwum, a wstawione
   nad tekstem zepchnęłoby 3 akapity poniżej ekranu na 390px).
   UWAGA na źródło prawdy: `@media (max-width:860px){ .idea-grid{1fr} }` z ~l.1347
   jest CICHO NADPISANY przez `.idea-grid{1.1fr 1fr}` z l.1894 (ta sama specyficzność,
   późniejsza kolejność w pliku) — na 390px siatka idea nadal liczy 2 kolumny (pomiar:
   `grid-template-columns: 120.469px 109.531px`). Ta reguła musi więc stać PO l.1894 i
   celować we własną klasę. Defekt dotyczy też `/` (poza zakresem FEST-1b) — zgłoszony
   osobno, świadomie NIE naprawiany globalnie, bo zmieniłby sekcję idea na home. */
@media (max-width: 860px) {
  .idea-grid--foto { grid-template-columns: minmax(0, 1fr); gap: 40px; }
  .idea-grid--foto > blockquote,
  .idea-grid--foto > .copy,
  .idea-grid--foto > .idea-foto { grid-column: 1; grid-row: auto; }
  .section-idea.has-foto .section-head { grid-template-columns: minmax(0, 1fr); gap: 20px; }
}

/* ── page-template „profil" (prelegent | partner | patron) — WWW-59 ──────────
   Namespace .profil-* (zero kolizji z .pg- / .plg- / .sp- / .founder-). Kolory
   przez var(--sb-color, var(--accent)) — recolor dziedziczy z <body data-sb>
   (layout.twig). Zero HEX (WA04). Wzorce kadru/inicjałów = person-grid/founder. */
/* Hero profilu: TREŚĆ po lewej, ZDJĘCIE po prawej (korekta właściciela 2026-07-30 — wcześniej
   odwrotnie). Kolejność w DOM zostaje bez zmian (media → head), bo dla czytnika ekranu i przy
   złożeniu do jednej kolumny sensowniej jest zacząć od portretu; przestawiamy WYŁĄCZNIE kolumny
   siatki, jawnym `grid-column`, a nie `order` — dzięki temu przy jednej kolumnie (≤900 px)
   wszystko wraca do kolejności dokumentu bez dodatkowych reguł. */
.section-profil .profil-hero {
  display: grid; grid-template-columns: 1fr 300px;
  /* Odstęp PIONOWY osobno: między nagłówkiem a opisem ma być blisko („bezpośrednio pod
     imieniem i funkcją"), więc wspólny `gap: 48px` rozsuwałby je za mocno. Poziomy zostaje. */
  column-gap: var(--space-7, 48px); row-gap: 0;
  align-items: start;
}
.section-profil .profil-hero > .profil-media { grid-column: 2; grid-row: 1 / span 2; }
.section-profil .profil-hero > .profil-head  { grid-column: 1; grid-row: 1; }
/* Opis w tej samej kolumnie co nagłówek, w drugim wierszu — czyli bezpośrednio pod funkcją,
   a nie pod całym portretem (patrz komentarz w profil.twig). `align-self: start` trzyma go przy
   nagłówku, gdy portret jest wyższy od tekstu. */
.section-profil .profil-hero > .profil-bio { grid-column: 1; grid-row: 2; align-self: start; margin-top: 24px; }
/* Dekor KV za treścią (`.has-kv` + `.kv-bg--right` w profil.twig). Rozmiar/opacity jak w
   manifesto — profil to strona tekstowa, dekor nie może konkurować z portretem ani nagłówkiem. */
.section-profil.has-kv { position: relative; overflow: hidden; }
.section-profil.has-kv > .container { position: relative; z-index: 1; }
.section-profil .kv-bg {
  top: 6%; width: 32%; aspect-ratio: 1;
  opacity: var(--kv-bg-op, .10);
  background: var(--sb-color, var(--accent));
  -webkit-mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
  mask: url(../key-visuals/kv-101-supporting.svg) center/contain no-repeat;
}
.profil-media {
  aspect-ratio: 4 / 5; background: var(--plon-gray-850);
  border: 1px solid var(--border); overflow: hidden;
  display: flex; align-items: center; justify-content: center;
}
.profil-media--mark { aspect-ratio: 3 / 2; background: var(--plon-graphite); }
.profil-photo, .profil-logo { width: 100%; height: 100%; object-fit: cover; }
.profil-media--mark .profil-logo { object-fit: contain; padding: 8%; }
.profil-initials {
  font-family: var(--font-serif); font-style: italic; font-weight: 700;
  font-size: 56px; color: var(--sb-color, var(--accent-text));
}
.profil-mark-name {
  font-size: 18px; font-weight: 700; color: var(--fg-1);
  text-align: center; padding: 0 12px; line-height: 1.25;
}
.profil-head { display: flex; flex-direction: column; gap: 8px; padding-top: 4px; }
.profil-eyebrow {
  font-size: 12px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
  color: var(--sb-color, var(--accent-text)); font-weight: 600;
}
.profil-name {
  font-size: clamp(30px, 3.4vw, 48px); font-weight: 800; letter-spacing: -0.025em;
  line-height: 1.06; margin: 0; color: var(--fg-1);
}
.profil-role { font-size: 16px; color: var(--fg-2); margin: 2px 0 0; line-height: 1.4; }
.profil-tier {
  font-size: 12px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
  color: var(--sb-color, var(--accent-text)); font-weight: 600; margin: 2px 0 0;
}
.profil-links { display: flex; flex-wrap: wrap; gap: 12px; margin-top: 10px; }
.profil-links a {
  font-size: 13px; font-weight: 600; color: var(--accent-text);
  border-bottom: 1px solid transparent;
}
.profil-links a:hover, .profil-links a:focus-visible { border-bottom-color: var(--accent); }
.profil-links a:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
.profil-bio { margin-top: var(--space-7, 48px); }
.profil-powiazania {
  display: flex; flex-wrap: wrap; gap: 10px;
  margin-top: var(--space-6, 32px); padding-top: 20px;
  border-top: 1px solid var(--border-soft);
}
.profil-rel {
  font-size: 13px; font-weight: 600; color: var(--accent-text);
  border: 1px solid var(--border); padding: 6px 14px; border-radius: 999px;
  transition: border-color var(--dur-fast) var(--ease-out-quart);
}
.profil-rel:hover, .profil-rel:focus-visible { border-color: var(--sb-color, var(--accent)); }
.profil-rel:focus-visible { outline: 2px solid var(--accent); outline-offset: 2px; }
@media (max-width: 860px) {
  .section-profil .profil-hero { grid-template-columns: 1fr; gap: var(--space-6, 32px); }
  /* Jedna kolumna — zdejmujemy jawne przypisania, wraca kolejność z DOM (portret, potem treść). */
  .section-profil .profil-hero > .profil-media,
  .section-profil .profil-hero > .profil-head,
  .section-profil .profil-hero > .profil-bio { grid-column: 1; grid-row: auto; }
  .profil-media { max-width: 240px; }
}
@media (max-width: 560px) {
  .profil-media { max-width: 200px; }
}

/* ── page-template „profil" — Festiwal CTA + editorial + cross-nav — WWW-63.
   Reuse: .section-heading / .actions / .btn / .profil-links / .profil-rel (bez
   duplikacji stylu linków). Kolory przez var(--sb-color, var(--accent-text)) —
   zero HEX (WA04). Uwaga §8.5: bez sekwencji gwiazdka-slash w komentarzach. */
.profil-festiwal-cta {
  margin-top: var(--space-7, 48px); padding-top: var(--space-6, 32px);
  border-top: 1px solid var(--border-soft);
}
.profil-festiwal-cta .section-heading { margin-bottom: var(--space-5, 24px); }
.profil-festiwal-cta .section-heading p { color: var(--fg-2); font-size: 16px; max-width: 560px; }

.profil-editorial {
  margin-top: var(--space-6, 32px); padding-top: var(--space-6, 32px);
  border-top: 1px solid var(--border-soft);
}
.profil-editorial-heading {
  font-size: 13px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
  color: var(--fg-3); font-weight: 600; margin: 0 0 12px;
}

.profil-crossnav {
  margin-top: var(--space-8, 64px); padding-top: var(--space-6, 32px);
  border-top: 1px solid var(--border-soft);
}
.profil-crossnav-heading {
  font-size: 13px; letter-spacing: var(--tracking-caps); text-transform: uppercase;
  color: var(--fg-3); font-weight: 600; margin: 0 0 20px;
}
/* PROF-A (życzenie właściciela 2026-07-30): gęstsza siatka — 6 kolumn na desktopie zamiast 4,
   mniejsze koło (88 → 72 px) i druga linijka z rolą. Pomiar szerokości kolumny (nie założenie):
   .container = max-width 1200 − 2 x var(--space-6, 32px) padding = 1136 px treści; przy 6 kolumnach
   i column-gap var(--space-4, 16px) → (1136 − 5 x 16) / 6 = 176 px na kolumnę; render potwierdza
   176 px @1440 i 157 px @1100. 72-px koło + nazwisko 13px + rola 11px mieszczą się z zapasem;
   najdłuższe pozycje („Joanna Jabłońska-Białowąs", „Kardiochirurg · CMO Yoshi Innovations") łamią
   się MAKS na 2 wiersze — zmierzone w Chromium na wszystkich progach, nie oszacowane. Zejście:
   6 (>1080) → 4 (<=1080) → 3 (<=860) → 2 (<=560); przy 390 px kolumna ma 147 px i miniatura
   zostaje 72-px (mieści się), więc nie ma osobnej reguły rozmiaru koła. */
.profil-crossnav-grid {
  display: grid;
  /* `auto-fit` + stała górna granica ścieżki zamiast `repeat(6, 1fr)`: obie grupy (prelegenci,
     zespół) mają po 5 osób, a bieżący profil się wyklucza, więc kafli jest ZAWSZE 4 — przy
     sześciu sztywnych kolumnach prawa 1/3 rzędu zostawała pusta (zmierzone: 6×176 px ścieżek
     na 4 elementy). `auto-fit` zwija puste ścieżki, `justify-content: center` centruje niepełny
     rząd, a `minmax(0, 176px)` trzyma tę samą szerokość kafla co przy pełnych sześciu — dzięki
     temu miniatura nie rozjeżdża się między profilami. Liczba kolumn schodzi sama wraz
     z szerokością, więc progi niżej pilnują już tylko dolnej granicy czytelności. */
  grid-template-columns: repeat(auto-fit, minmax(0, 176px));
  justify-content: center;
  gap: var(--space-5, 24px) var(--space-4, 16px);
}
/* Miniatura = KAFEL w formie analogicznej do siatki prelegentów na /festiwal (uwaga właściciela
   2026-07-30: „miniaturki w formie analogicznej jak w Festiwal … tylko imię, nazwisko i funkcje").
   Poprzednia wersja była okrągłym awatarem 72 px — czytelna, ale wizualnie obca wobec kafli
   `.pg-card`, do których właściciel się odwołał. Teraz: prostokątny portret 4:5 (ten sam kadr co
   w person-grid), ramka i tło kafla, podpis pod spodem. Bez bio — to zostaje różnicą wobec
   `.pg-card`, zgodnie z „bez krótkiego opisu". */
.profil-mini {
  display: flex; flex-direction: column; gap: 0;
  color: var(--fg-1); background: var(--plon-graphite);
  border: 1px solid var(--border);
  transition: border-color var(--dur-fast) var(--ease-out-quart);
}
.profil-mini:hover { border-color: var(--sb-color, var(--accent)); }
.profil-mini-photo {
  width: 100%; aspect-ratio: 4 / 5; overflow: hidden;
  background: var(--plon-gray-850);
  display: flex; align-items: center; justify-content: center;
}
/* WWW-63: miniatura to KOŁO 88 px, a źródłem jest grafika `person-portrait-www` 4:5 (SG-11).
   Kadr środkowy (domyślne 50% 50%) wcina się w tors i wciąga do koła dekor `lines` z dolnej
   krawędzi grafiki — w tej skali fale są szumem, nie dekorem. Przesunięcie kadru w górę
   (22%) łapie twarz i wypycha fale poza koło. Zmierzone na renderze 86x86, nie założone. */
/* Kadr wraca do środka: przesunięcie w górę (22%) było korektą pod KOŁO 88 px, gdzie dolna
   krawędź grafiki wciągała dekor fal do kadru. W prostokącie 4:5 grafika `person-portrait-www`
   pokazuje się tak, jak została zaprojektowana — z dekorem włącznie. */
.profil-mini-photo img { width: 100%; height: 100%; object-fit: cover; }
.profil-mini-photo .initials {
  font-family: var(--font-serif); font-style: italic; font-weight: 700;
  font-size: 28px; color: var(--sb-color, var(--accent-text));
}
.profil-mini-name {
  font-size: 13px; font-weight: 700; line-height: 1.3;
  padding: 12px 12px 0; /* podpis w kaflu, nie pod nim */
  transition: color var(--dur-fast) var(--ease-out-quart);
}
/* PROF-A: rola/funkcja pod nazwiskiem. Świadomie BEZ `text-transform: uppercase` + `--tracking-caps`
   (styl .pg-role z kart person-grid): wersaliki z trackingiem poszerzają najdłuższą rolę o ~40%, co
   przy 176-px kolumnie wpychało ją w 3. wiersz. Bez opisu/bio — samo imię, nazwisko i funkcja. */
.profil-mini-role {
  font-size: 11px; line-height: 1.35; color: var(--fg-3);
  padding: 2px 12px 12px;
}
.profil-mini:hover .profil-mini-name,
.profil-mini:focus-visible .profil-mini-name { color: var(--sb-color, var(--accent-text)); }
.profil-mini:focus-visible { outline: 2px solid var(--accent); outline-offset: 4px; }
/* Progi 1080/860 z `repeat(4|3, 1fr)` ZDJĘTE — `auto-fit` schodzi z liczbą kolumn sam, a sztywne
   3 kolumny przy czterech kaflach dawały sierotę w drugim rzędzie (grid nie centruje ostatniego
   rzędu, więc lądowała przy lewej krawędzi). Zostaje jeden próg: poniżej 900 px wracamy do dwóch
   PEŁNYCH kolumn — cztery kafle układają się wtedy 2×2, bez sieroty na żadnej z tych szerokości. */
@media (max-width: 900px) {
  .profil-crossnav-grid { grid-template-columns: repeat(2, 1fr); }
}
