/* ============================================================
   TOM IT — arkusz instancji (szkielet fali 0)

   ZAKRES: wyłącznie WIĄZANIE tokenów marki z elementami, które renderują
   szablony silnika (.wrap, .site-header, .nav, .section, .site-footer).
   To NIE jest warstwa wizualna strony — układ sekcji, hero, karty usług
   i dekory powstają w fali 1, po akcepcie prototypu przez klienta.

   🔴 ZERO WARTOŚCI KOLORÓW I NAZW KROJÓW W TYM PLIKU.
      Wyłącznie var(--tomit-*) z brand/tokens/tomit-tokens.css.
      Egzekwuje to bramka WA04 (core/web-app/validate-web-app.py), która
      skanuje CSS instancji za #rrggbb / rgb() / hsl().

   Wpięcie: silnik linkuje ten plik warunkowo, po tokenach — konwencja
   assets/css/site.css (WAT-02, core/web-app/templates/partials/head.twig).
   Kolejność ma znaczenie: tokeny pierwsze, ten plik drugi, więc kaskada
   pozwala nadpisywać wartości bez !important.

   Dlaczego ten plik w ogóle istnieje: bez niego @font-face z tokenów jest
   zadeklarowany, ale nieużyty — przeglądarka NIE pobiera woff2, a strona
   renderuje się krojem systemowym (zmierzone: Times). Bramka PC02 łapie to
   jako „@font-face zadeklarowany ale NIE w computed (fallback?)".
   ============================================================ */

:root {
  /* Szerokość kolumny tekstu — silnik czyta ją w szablonie strony
     (`max-width:var(--prose-width,760px)`), więc ustawiamy ją tokenem,
     zamiast pozwolić na fallback spoza systemu marki. */
  --prose-width: 68ch;

  /* Kolor obrysu :focus-visible dla kontekstu JASNEGO (biel i --tomit-bg-box) —
     patrz baner przy regule :focus-visible niżej. Sekcje ciemne przestawiają go
     u siebie; wartość stoi w :root, a nie na `body`, żeby dziedziczyła też do
     elementów wyjętych z przepływu (dialog, popover — dziś ich nie ma, ale reguła
     ma przeżyć ich dołożenie). */
  --focus-obrys: var(--tomit-link);
}

body {
  margin: 0;
  background: var(--tomit-bg);
  color: var(--tomit-text);
  font-family: var(--tomit-font-body);
  font-size: var(--tomit-fs-body);
  line-height: var(--tomit-lh-body);
  -webkit-font-smoothing: antialiased;
}

/* Nagłówki niosą krój display — to jedyne miejsce, gdzie para krojów
   z decyzji B2 staje się widoczna. */
h1, h2, h3 {
  font-family: var(--tomit-font-display);
  line-height: var(--tomit-lh-tight);
  letter-spacing: var(--tomit-tracking-display);
  color: var(--tomit-text);
}

h1 { font-size: var(--tomit-fs-h1); }
h2 { font-size: var(--tomit-fs-h2); }
h3 { font-size: var(--tomit-fs-h3); }

a {
  color: var(--tomit-link);
  text-underline-offset: 0.15em;
}

a:hover { text-decoration: none; }

/* Widoczny focus — nie kosmetyka: bez niego nawigacja klawiaturą jest ślepa,
   a PC04 mierzy accessibility.

   🔴 KOLOR OBRYSU JEST ZALEŻNY OD TŁA — poprawka TIT-13 do reguły z TIT-06.
      Pierwotne uzasadnienie („cyjan dekoracyjny nadaje się, bo obrys nie jest tekstem")
      zdejmuje zakaz z palette.md, ale NIE zdejmuje progu WCAG 1.4.11: wskaźnik focusu
      to element nietekstowy z progiem 3,0 wobec sąsiadującego tła, a --tomit-accent
      (cyan-500) ma na bieli 2,41:1 — czyli obrys, którego na jasnej sekcji realnie
      nie widać. Na granacie ten sam token ma 7,22:1 i jest jedynym czytelnym.
      Zamiast dwóch reguł :focus-visible obrys bierze kontekst z --focus-obrys:
      wartość domyślna (jasne tło) niżej w :root, przestawienie dla sekcji ciemnych
      w bloku „UJEDNOLICENIA CAŁOŚCIOWE" na końcu pliku — tam, gdzie mieszka komplet
      kontekstu ciemnego. Obie wartości są w rejestrze par z progiem 3,0. */
:focus-visible {
  outline: 3px solid var(--focus-obrys);
  outline-offset: 2px;
}

/* Kontener — szerokość z tokenu, żeby wszystkie narzędzia klienta miały
   tę samą miarę. */
.wrap {
  width: min(100% - 2 * var(--tomit-space-2), var(--tomit-maxw));
  margin-inline: auto;
}

.site-header {
  background: var(--tomit-bg);
  border-bottom: 1px solid var(--tomit-border);
  padding-block: var(--tomit-space-2);
}

.header-inner,
.nav {
  display: flex;
  align-items: center;
  gap: var(--tomit-space-3);
  flex-wrap: wrap;
}

/* Logo w nawigacji. `nav.twig` emituje <img width="120" height="40"> — wartości
   zahardkodowane w szablonie SILNIKA, więc nie do zmiany po naszej stronie bez
   kopii szablonu (P14). Proporcje naszego logo to 3,47:1, a 120x40 to 3:1 —
   bez tej reguły przeglądarka wzięłaby atrybuty dosłownie i ROZCIĄGNĘŁA znak
   w pionie. `width: auto` oddaje sterowanie proporcji plikowi, `height` jest
   jedynym wymiarem, który ustawiamy świadomie.
   `display: block` zdejmuje szczelinę pod obrazem (baseline inline), przez którą
   logo siedziałoby o kilka px wyżej niż pozycje menu obok. */
.wm img {
  display: block;
  height: 52px;
  width: auto;
}

/* Na wąskich ekranach 52 px daje znak szerokości 180 px, czyli 46% z 390 px viewportu —
   logo zaczyna dominować nagłówek. 40 px schodzi do 138 px (35%). Breakpoint 720 px jest
   ten sam, co reszta arkusza (patrz nota przy pierwszym @media), żeby układ łamał się
   w JEDNYM punkcie.
   ⚠️ To dopasowanie proporcji logo, NIE naprawa rozlanego nagłówka mobilnego. Ten ma inną
   przyczynę i jest STANEM ZASTANYM: zmierzone 2026-08-07 kontrfaktem (nagłówek bez logo
   = 195 px na 390 px, z logo = 219 px, czyli logo dokłada 24 px do problemu, którego nie
   powoduje). Realna przyczyna: `nav.twig` renderuje hamburger, ale pozycje menu NIE są
   pod nim chowane i zawijają się w trzy rzędy. Naprawa siedzi poza tym arkuszem. */
@media (max-width: 720px) {
  .wm img {
    height: 40px;
  }
}

/* `nav.twig` buduje pozycje menu jako <ul><li> — bez tego resetu menu renderuje się
   jako lista punktowana z wcięciem 40 px (zmierzone). To reset struktury, nie decyzja
   wizualna. `footer.twig` NIE używa listy (płaskie <a> w <nav class="footer-links">),
   więc celowo go tu nie ma — selektor na klasę, której nikt nie emituje, byłby martwym
   kodem udającym styl.

   ⚠️ Dla fali 1: `nav.twig` ma też zagnieżdżone `.nav-dropdown ul`, dziś nierenderowane
   (usługi są w stopce, nie w menu). Gdy fala 1 rozwinie menu usług, ten selektor odziedziczy
   `display:flex` i rozłoży dropdown poziomo — będzie wymagał świadomego nadpisania.
   To nie jest wtedy nowy defekt, tylko znany skutek tego resetu. */
.nav ul {
  list-style: none;
  margin: 0;
  padding: 0;
  display: flex;
  flex-wrap: wrap;
  gap: var(--tomit-space-3);
}

.nav a {
  font-family: var(--tomit-font-display);
  color: var(--tomit-text-muted);
  text-decoration: none;
}

.nav a:hover { color: var(--tomit-link); }

/* ---------------------------------------------------------------------------
   MENU MOBILNE — hamburger był martwym przyciskiem

   Stan przed tą regułą (zmierzony, nie domniemany): `nav.twig` emituje
   <button class="hamburger" id="hamburger" aria-expanded="false"> z trzema
   <span>, ale NIKT go nie obsługiwał — silnik nie ma ani jednego pliku .js
   (`find core/web-app -name '*.js'` → pusto), a `footer.twig` linkuje
   `assets/js/app.js` tylko warunkowo, gdy instancja go dostarczy; instancja
   nie dostarczała. Do tego ani silnik, ani ten arkusz nie miały reguły dla
   `.hamburger` / `.nav-links`. Skutek: przycisk renderował się jako nagi
   prostokąt (na WSZYSTKICH szerokościach, także desktop), a cztery pozycje
   menu zawijały się na 390 px w trzy rzędy — nagłówek rósł do 195 px.

   🔴 Żadna bramka tego nie widziała: Lighthouse a11y = 100, PC03 = 0 błędów
   konsoli, `scrollWidth == clientWidth`. Defekt bez śladu w metrykach —
   złapało go dopiero oko na zrzucie mobilnym.

   Podział ról: CSS decyduje CO jest widoczne w danym stanie, `app.js` tylko
   przełącza `aria-expanded` na przycisku. Stan trzyma więc ATRYBUT ARIA, nie
   klasa — jedno źródło prawdy dla stylu i dla czytnika ekranu naraz. Menu
   bez JS (albo z błędem JS) zostaje widoczne, nie znika: awaria skryptu nie
   może odciąć nawigacji.
   --------------------------------------------------------------------------- */

/* Hamburger jest elementem WYŁĄCZNIE mobilnym — na desktopie znika. */
.hamburger { display: none; }

@media (max-width: 720px) {
  /* Logo i hamburger stoją w JEDNYM rzędzie i tak zostają — otwarte menu nie
     przesuwa ich ani o piksel, bo wychodzi z przepływu (patrz niżej).
     Kotwicą pozycjonowania jest `.site-header`, a nie `.header-inner`: ten drugi
     jest jednocześnie `.wrap` (ograniczony `max-width` + `margin-inline:auto`),
     więc panel zaczepiony o niego skończyłby się na krawędzi kolumny tekstu,
     a nie ekranu. */
  .site-header { position: relative; }

  .header-inner {
    flex-wrap: nowrap;
    justify-content: space-between;
  }

  .nav {
    flex-wrap: nowrap;
    justify-content: flex-end;
    gap: var(--tomit-space-2);
  }

  .hamburger {
    display: flex;
    flex-direction: column;
    justify-content: center;
    gap: var(--tomit-space-1);
    /* 44x44 to minimalny cel dotykowy z WCAG 2.5.5 (Target Size) — przycisk
       o rozmiarze samej ikony (ok. 24 px) trafia się kciukiem zawodnie. */
    inline-size: 44px;
    block-size: 44px;
    padding: 0;
    background: none;
    border: 0;
    cursor: pointer;
  }

  .hamburger span {
    display: block;
    block-size: 2px;
    inline-size: 24px;
    margin-inline: auto;
    background: var(--tomit-text);
    transition: transform 160ms ease, opacity 160ms ease;
  }

  /* Krzyżyk po otwarciu: skrajne kreski zbiegają się i obracają, środkowa gaśnie.
     Przesunięcie 6 px = wysokość kreski (2) + odstęp (--tomit-space-1, 4 px). */
  .hamburger[aria-expanded="true"] span:nth-child(1) { transform: translateY(6px) rotate(45deg); }
  .hamburger[aria-expanded="true"] span:nth-child(2) { opacity: 0; }
  .hamburger[aria-expanded="true"] span:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

  /* Menu schowane domyślnie. `display: none`, nie `visibility`/`opacity` —
     tylko to wyjmuje pozycje z kolejności czytania i z tabulacji naraz.
     Selektor jest sprzężony ze stanem PRZYCISKU (`:has()`), więc atrybut ARIA
     pozostaje jedynym źródłem prawdy — nie ma drugiej klasy do rozjechania. */
  .nav:has(.hamburger[aria-expanded="false"]) .nav-links { display: none; }

  /* Otwarte menu to PANEL WYSUNIĘTY Z PRZEPŁYWU, nie kolejny rząd flexa.
     Powód mierzalny: `.nav-links` jest dzieckiem `.nav`, więc `inline-size: 100%`
     w przepływie daje szerokość NAV-a (czyli tego, co zostało po logo), a nie
     nagłówka — menu rozwijało się w prawej kolumnie obok logo. Do tego hamburger
     stoi w DOM PO liście, więc lista rozpychająca się na cały wiersz spychała
     krzyżyk pod siebie. Oba objawy znikają, gdy panel przestaje zajmować miejsce
     w układzie.
     Skutek uboczny, zamierzony: wysokość nagłówka NIE ZMIENIA SIĘ przy otwarciu
     (77 px w obu stanach) — panel nakłada się na treść, więc potrzebuje własnego
     tła i `z-index`; bez tła prześwitywałaby przez niego ciemna sekcja hero. */
  .nav:has(.hamburger[aria-expanded="true"]) .nav-links {
    display: flex;
    flex-direction: column;
    align-items: stretch;
    position: absolute;
    inset-inline: 0;
    inset-block-start: 100%;
    z-index: 20;
    gap: var(--tomit-space-1);
    padding-block: var(--tomit-space-2);
    padding-inline: var(--tomit-space-2);
    background: var(--tomit-bg);
    border-block-end: 1px solid var(--tomit-border);
    box-shadow: var(--tomit-shadow);
  }

  /* Pozycja menu jako cel dotykowy pełnej szerokości, nie sam tekst. */
  .nav-links a {
    display: block;
    inline-size: 100%;
    padding-block: var(--tomit-space-1);
  }

  /* Awaryjnie: gdy `app.js` nie wystartuje, przycisk zostaje z `aria-expanded="false"`
     z szablonu i powyższa reguła schowałaby menu BEZ możliwości otwarcia. Przeglądarki
     bez `:has()` w ogóle nie zastosują obu reguł wyżej i menu zostanie widoczne — to
     zamierzony kierunek awarii. Dlatego stan zamknięty NIE jest domyślny w kaskadzie:
     wynika wyłącznie z selektora, który wymaga wsparcia `:has()`. */
}

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

.section { padding-block: var(--tomit-space-4); }

.site-footer {
  background: var(--tomit-bg-box);
  border-top: 1px solid var(--tomit-border);
  padding-block: var(--tomit-space-4);
  font-size: var(--tomit-fs-small);
  color: var(--tomit-text-muted);
}

.footer-links {
  display: flex;
  flex-wrap: wrap;
  gap: var(--tomit-space-2);
  padding-block: var(--tomit-space-2);
}

.footer-base { padding-top: var(--tomit-space-2); }

/* ============================================================================
   SEKCJA: hero  ·  partial: templates/partials/sections/hero.twig
   Tło CIEMNE (--tomit-bg-dark). 🔴 Na granacie zakazy się odwracają: --tomit-link
   oblewa AA, a --tomit-accent-on-dark (cyjan) jest czytelny. Tekst bierze wyłącznie
   tokeny *-on-dark. Pary zmierzone: tools/contrast-pairs.yaml + check-contrast-pairs.py

   KONWENCJA CAŁEJ FALI: jedna sekcja = jeden blok z takim banerem, dopisywany na
   KOŃCU pliku, ale NAD banerem „UJEDNOLICENIA CAŁOŚCIOWE", który zamyka arkusz.
   Wszystko powyżej pierwszego takiego banera to wiązanie tokenów ze strukturą szablonów silnika
   (.wrap, .section, .site-header…) — dotyczy wszystkich 10 tras, więc sekcje tam nie
   wchodzą. Wartości rytmu specyficzne dla sekcji siedzą w LOKALNYCH custom property
   (--hero-*), nie w brandzie.
   PRÓG MOBILNY 720px jest WSPÓLNY DLA CAŁEJ FALI — każda kolejna sekcja używa tej
   samej wartości w @media, żeby układ łamał się w jednym punkcie na całej stronie.
   Bez tej umowy za trzy zadania będzie 720/768/800 bez powodu i strona zacznie się
   rozjeżdżać sekcja po sekcji.
   ============================================================================ */
.section-hero {
  /* 80 px — trzeci, najwyższy stopień drabiny rytmu pionowego (40 środek /
     64 klamra / 80 otwarcie; komplet opisany w bloku „UJEDNOLICENIA CAŁOŚCIOWE"
     na końcu pliku).
     ⚠️ MNOŻNIK ZOSTAJE, BO TOKENU 80 px NIE MA — nie dlatego, że nikt nie zajrzał.
        Skala odstępów marki kończy się na --tomit-space-5 (4rem = 64 px;
        clients/tomit/brand/tokens/tomit-tokens.css:112-113), a dołożenie
        --tomit-space-6 to zmiana w BRANDZIE, czyli poza zakresem instancji
        (i poza zakresem TIT-13, którego output ogranicza się do website/strona).
        Gdy taki token powstanie, ta linia jest jedynym miejscem do podmiany. */
  --hero-pad-block: calc(var(--tomit-space-5) * 1.25);
  --hero-kolumna-tekst: 1.1fr;
  --hero-kolumna-dekor: 0.9fr;
  /* Miara kolumny tekstu — JEDNA wartość dla leadu i noty, żeby nie mogły się
     rozjechać przy późniejszej korekcie. */
  --hero-miara: 52ch;

  /* ⚠️ TŁA, KOLORU TEKSTU I KONTEKSTU PRZYCISKÓW TU NIE MA — od TIT-13 stoją raz,
     w grupowanym selektorze `.section-hero, .section-cta-band` w bloku
     „UJEDNOLICENIA CAŁOŚCIOWE" na końcu pliku. To ta sama decyzja co przy .btn:
     dwa razy ta sama wartość to dwa miejsca do rozjechania przy zmianie palety. */
  padding-block: var(--hero-pad-block);
}

/* minmax(0, …) jest konieczne, nie ozdobne: domyślne min-width kolumny gridu to
   `auto`, więc jedno długie słowo (a polskie bywają długie: „cyberbezpieczeństwo")
   rozpycha kolumnę ponad przydział `fr` i wypycha układ poza kontener. */
.hero-uklad {
  display: grid;
  grid-template-columns: minmax(0, var(--hero-kolumna-tekst)) minmax(0, var(--hero-kolumna-dekor));
  gap: var(--tomit-space-4);
  align-items: center;
}

/* Nadtytuł: cyjan jest tu LEGALNY, bo tłem jest granat (7,22:1), a nie biel. */
.hero-eyebrow {
  margin: 0 0 var(--tomit-space-2);
  color: var(--tomit-accent-on-dark);
}

/* Reguła h1 z góry pliku ustawia color:var(--tomit-text) (granat) — na granatowym tle
   dałaby tekst niewidoczny. Nadpisanie jest konieczne, nie kosmetyczne. */
.hero-tytul {
  margin: 0;
  color: var(--tomit-fg-on-dark);
  text-wrap: balance;
}

.hero-akcent { color: var(--tomit-accent-on-dark); }

.hero-lead {
  margin: var(--tomit-space-3) 0 0;
  max-width: var(--hero-miara);
  font-size: calc(var(--tomit-fs-body) * 1.08);
  color: var(--tomit-fg-on-dark);
}

.hero-cta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--tomit-space-2);
  margin: var(--tomit-space-4) 0 0;
}

.hero-nota {
  margin: var(--tomit-space-3) 0 0;
  max-width: var(--hero-miara);
  font-size: var(--tomit-fs-small);
  color: var(--tomit-fg-on-dark-muted);
}

/* ---------------------------------------------------------------------------
   KOMPONENT .btn — powstaje w bloku hero, ale NIE należy do hero.

   🔴 KONWENCJA NAZW JEST SILNIKOWA (BEM, podwójny myślnik) — zmierzone, nie umowne:
      przycisk `btn btn--primary` emitują TAKŻE szablony core/web-app
      (`templates/404.twig:20`, `templates/partials/nav.twig:46` — to drugie warunkowo,
      przy `copy.header.cta`). Ten arkusz jest linkowany na KAŻDEJ trasie, więc reguły
      poniżej malują również przyciski silnika, nie tylko sekcje instancji. Gdyby
      instancja trzymała własną konwencję (`btn-primary`), w jednym drzewie żyłyby dwie
      nazwy jednego komponentu, a przycisk silnikowego 404 zostałby nieomalowany.

   PODZIAŁ ODPOWIEDZIALNOŚCI:
      .btn           — geometria, typografia, interakcja (bez kolorów wariantu)
      .btn--primary  — wypełnienie
      .btn--ghost    — obrys
   Kolory wariantów idą przez custom property z FALLBACKIEM na kontekst JASNY; sekcja
   ustawia kontekst u siebie (patrz .section-hero), a komponent zostaje jeden.

   🔴 GRANICA PRZYCISKU NA GRANACIE — decyzja świadoma, wariant (a).
      Zmierzone: --tomit-cta (#C1121F) na --tomit-bg-dark (#101B25) = 2,80:1, czyli
      PONIŻEJ progu 3:1 dla granic elementów UI — czerwony przycisk na granacie ma
      krawędź, której nie widać, mimo że sam napis na nim przechodzi (≈6,2:1).
      Wybrano (a) — przycisk podstawowy na ciemnym jest JASNY (tło --tomit-fg-on-dark,
      napis --tomit-bg-dark): 17,42:1 zarówno dla wypełnienia wobec tła, jak i dla
      etykiety. Powód wyboru (a) zamiast (b) „czerwień + jasny obrys": obrys
      wystarczający do 3:1 i tak musiałby być biały, więc (b) daje dwa pierścienie
      i słabszy element o kontraście na granicy progu, zamiast jednego z zapasem —
      a zapas jest tu realnym zasobem (dekor i tak zjada część budżetu kontrastu).
      Czerwień zostaje sygnałem sekcji na JASNYM tle (fallback niżej).

   ⚠️ Fallbacki (kontekst JASNY) NIE są hipotetyczne: renderuje je trasa 404 silnika
      (czerwone wypełnienie na białym tle strony). Ich pary są w rejestrze
      tools/contrast-pairs.yaml z adnotacją, skąd bierze się konsument. Pierwsza
      INSTANCYJNA sekcja na białym tle (TIT-10/TIT-12) dopisze swoje własne, jeśli
      zestawi cokolwiek nowego.
   --------------------------------------------------------------------------- */

/* Sam komponent: żadnych kolorów wariantu — wyłącznie kształt i zachowanie. Dzięki
   temu nowy wariant (TIT-12) dokłada JEDNĄ regułę z trzema własnościami, zamiast
   powielać geometrię. */
.btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  padding: calc(var(--tomit-space-1) * 1.5) var(--tomit-space-3);
  border: 2px solid transparent;
  border-radius: var(--tomit-radius-pill);
  font-family: var(--tomit-font-display);
  font-size: var(--tomit-fs-body);
  font-weight: 600;
  line-height: var(--tomit-lh-tight);
  text-decoration: none;
}

/* Wariant podstawowy (wypełnienie). Kontekst JASNY = fallbacki (czerwień marki),
   kontekst CIEMNY = wartości ustawione na sekcji (patrz .section-hero). */
.btn--primary {
  border-color: var(--btn-obrys, var(--tomit-cta));
  background: var(--btn-bg, var(--tomit-cta));
  color: var(--btn-fg, var(--tomit-cta-text));
}

/* Wariant obrysowy. Tło przezroczyste, więc kontrast liczy się wobec tła SEKCJI —
   dlatego ma własną parę w rejestrze, osobno od przycisku podstawowego. */
.btn--ghost {
  background: transparent;
  border-color: var(--btn-ghost-obrys, var(--tomit-link));
  color: var(--btn-ghost-fg, var(--tomit-link));
}

/* Hover przez lekkie przygaszenie — jedyna zmiana niezależna od kontekstu (nie zna
   koloru tła sekcji). Zapas kontrastu wystarcza: biel .88 na granacie ≈ 13,9:1,
   cyjan .88 na granacie ≈ 5,8:1 — obie ponad progiem 4,5. */
.btn:hover { opacity: 0.88; }

/* Dekor: geometria z tokenów, bez pliku obrazu i bez <img> (decyzja C4).
   🔴 Stoi w OSOBNEJ kolumnie gridu — nigdy pod tekstem. Gradient pod tekstem obniża
      realny kontrast poniżej wartości z rejestru par, a rejestr mierzy tokeny, nie
      nakładki (budżet kontrastu jest wyczerpywalny). */
.hero-dekor {
  --hero-dekor-h: 300px;
  --hero-dekor-siatka: 28px;
  min-height: var(--hero-dekor-h);
  border: 1px solid var(--tomit-border-dark);
  border-radius: var(--tomit-radius);
  opacity: 0.55;
  background:
    repeating-linear-gradient(90deg, var(--tomit-border-dark) 0 1px, transparent 1px var(--hero-dekor-siatka)),
    repeating-linear-gradient(0deg, var(--tomit-border-dark) 0 1px, transparent 1px var(--hero-dekor-siatka)),
    radial-gradient(60% 60% at 72% 28%, var(--tomit-accent-on-dark), transparent 68%),
    linear-gradient(160deg, var(--tomit-bg-dark-soft), var(--tomit-bg-dark));
}

@media (max-width: 720px) {
  .section-hero { --hero-pad-block: var(--tomit-space-4); }

  .hero-uklad { grid-template-columns: 1fr; }

  .hero-dekor { --hero-dekor-h: 160px; }

  /* Na wąskim ekranie przyciski idą pełną szerokością kontenera zamiast wystawać
     poza niego — kryterium (e) Wizualnego QA: zero przewijania poziomego. */
  .hero-cta .btn {
    flex: 1 1 100%;
  }
}

/* ============================================================================
   SEKCJA: proof-stats  ·  partial: templates/partials/sections/proof-stats.twig
   Tło JASNE (--tomit-bg-box) — oddech po ciemnym hero.
   🔴 TRYB ZAPOWIEDZI (.proof-pozycja--zapowiedz) ma wyglądać na element SKOŃCZONY:
      ten sam układ i rytm co wersja z liczbą, wartość w kroju display i kolorze
      akcentu. ZAKAZ: przerywany obrys, wyszarzenie, znak zapytania, „placeholder”.

   🔴 AKCENT NA JASNYM TLE TO --tomit-link (cyan-800), NIGDY --tomit-accent
      (cyan-500, 2,41:1 na bieli — twardy zakaz pod tekstem). Zakazy odwracają się
      wyłącznie na granacie, a ta sekcja stoi na jasnym boksie. Pary zmierzone:
      tools/contrast-pairs.yaml + check-contrast-pairs.py

   CO ROBI MODYFIKATOR --zapowiedz i czego NIE robi: zmienia WYŁĄCZNIE stopień pisma
   wartości, bo zapowiedź jest zdaniem, a docelowa treść tego slotu będzie liczbą.
   Kolor, krój, obrys i rytm zostają te same — modyfikator nie sygnalizuje „stanu
   nieaktywnego", tylko dopasowuje miarę do długości tekstu. Gdy przyjdą dane
   (`zapowiedz: false`), klasa znika sama i slot wraca do stopnia liczby.
   PRÓG MOBILNY 720px — wspólny dla całej fali (patrz baner hero).
   ============================================================================ */
.section-proof {
  --proof-kolumny: repeat(3, minmax(0, 1fr));
  /* Miara tekstu biegnącego — jedna deklaracja dla wszystkich akapitów sekcji.
     ⚠️ `ch` sprzęga EDYCJĘ, nie szerokość: jednostka rozwiązuje się względem stopnia
     pisma ELEMENTU, więc to ta sama liczba znaków, a NIE ta sama liczba pikseli
     (zmierzone: .proof-intro 645 px vs .proof-nota 531 px z tej samej deklaracji —
     nota ma --tomit-fs-small). Zmiana jednej wartości nadal rusza obydwa akapity
     spójnie i po to tu jest. Konwersja miar na `rem` (te same piksele) to decyzja
     falowa, nie sekcyjna — wsad do TIT-13, patrz też --testimonial-miara niżej. */
  --proof-miara: 62ch;
  --proof-wartosc-fs: var(--tomit-fs-h3);
  /* Stopień wartości w trybie zapowiedzi: zdanie zamiast liczby, więc o krok niżej. */
  --proof-wartosc-fs-zapowiedz: calc(var(--tomit-fs-body) * 1.12);
  --proof-kreska: 3px;

  background: var(--tomit-bg-box);
  color: var(--tomit-text);
}

.proof-tytul {
  margin: 0;
  text-wrap: balance;
}

.proof-akcent { color: var(--tomit-link); }

.proof-intro {
  margin: var(--tomit-space-3) 0 0;
  max-width: var(--proof-miara);
  color: var(--tomit-text-muted);
}

/* minmax(0, 1fr) w --proof-kolumny jest konieczne, nie ozdobne: domyślne min-width
   kolumny gridu to `auto`, więc długie polskie słowo rozpycha kolumnę ponad przydział
   `fr` i wypycha układ poza kontener (ta sama pułapka co w .hero-uklad). */
.proof-lista {
  list-style: none;
  margin: var(--tomit-space-4) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: var(--proof-kolumny);
  gap: var(--tomit-space-3);
}

/* Kreska nad pozycją zastępuje ramkę karty: daje rytm i domknięcie bez obrysu,
   który przy trzech pozycjach zrobiłby z pasa tabelę. Jest CIĄGŁA i pełną mocą
   koloru — przerywana czytałaby się jako „niegotowe".

   🔴 KOLUMNA + ROZPYCHANA WARTOŚĆ = etykiety na jednej linii bazowej. W trybie
      zapowiedzi wartości są zdaniami różnej długości i łamią się na różną liczbę
      wierszy (zmierzone: 1 / 2 / 2 wiersze → etykiety na 185 / 206 / 206 px, czyli
      pierwsza wisiała 21 px wyżej). `flex: 1 1 auto` na wartości dosuwa etykietę do
      dołu komórki, więc trzy kreski u góry mają odpowiednik u dołu.
      W stanie docelowym (jednowierszowe liczby) ta reguła jest NO-OP: wszystkie
      wartości mają wtedy tę samą wysokość, więc nie ma czego wyrównywać. Zostaje
      jako zabezpieczenie na wypadek dłuższej wartości (np. „ponad 20 lat"). */
.proof-pozycja {
  border-top: var(--proof-kreska) solid var(--tomit-link);
  padding-top: var(--tomit-space-2);
  display: flex;
  flex-direction: column;
}

.proof-wartosc {
  flex: 1 1 auto;
  margin: 0;
  font-family: var(--tomit-font-display);
  font-size: var(--proof-wartosc-fs);
  line-height: var(--tomit-lh-tight);
  letter-spacing: var(--tomit-tracking-display);
  color: var(--tomit-link);
  text-wrap: balance;
}

.proof-pozycja--zapowiedz .proof-wartosc {
  font-size: var(--proof-wartosc-fs-zapowiedz);
}

.proof-etykieta {
  margin: var(--tomit-space-1) 0 0;
  color: var(--tomit-text-muted);
}

/* Nota używa TEJ SAMEJ pary kontrastu co .proof-intro (--tomit-text-muted na
   --tomit-bg-box) — w rejestrze par siedzi raz, pod pozycją „akapit wprowadzający”.
   ⚠️ Pole `note` jest w schemacie OPCJONALNE i strona główna go dziś NIE używa
   (zdjęte w rewizji TIT-10: jedyna nota, jaka tu stała, mówiła antypersonie, że telefon
   istnieje, tylko nie jest publikowany — czyli robiła to, czego brak telefonu ma uniknąć).
   Reguła zostaje, bo partial emituje tę klasę dla każdego wystąpienia typu z `note`
   (typ wraca na /o-mnie) — bez niej pierwsze użycie wyrenderowałoby się bez stylu. */
.proof-nota {
  margin: var(--tomit-space-4) 0 0;
  max-width: var(--proof-miara);
  font-size: var(--tomit-fs-small);
  color: var(--tomit-text-muted);
}

@media (max-width: 720px) {
  .section-proof { --proof-kolumny: 1fr; }
}

/* ============================================================================
   SEKCJA: testimonial  ·  partial: templates/partials/sections/testimonial.twig
   Tło BIAŁE. Cytat w kroju display, atrybucja mniejsza, w kolorze przygaszonym.
   🔴 TRYB ZAPOWIEDZI — jak wyżej: skończony blok, nie stan „nieaktywny”.
      Modyfikator .testimonial-cytat--zapowiedz zmienia WYŁĄCZNIE stopień pisma
      (opis jest dłuższy od cytatu, który tu kiedyś stanie). Bez wyszarzenia,
      bez przerywanego obrysu, bez cudzysłowu udającego wypowiedź — cudzysłów
      przy tekście, który nie jest niczyją wypowiedzią, byłby fałszem typograficznym.
      To samo rozumowanie działa piętro niżej, w ZNACZNIKU: w trybie zapowiedzi
      partial renderuje <div>/<p>, a <blockquote>/<cite> dopiero przy `zapowiedz: false`
      (znacznik też jest twierdzeniem — i to czytanym na głos przez czytnik ekranu).
      Klasy są w obu gałęziach te same, więc arkusz zna jeden blok, nie dwa.

   🔴 JEDNA PRAWA KRAWĘDŹ. Sekcja stoi między dwiema, które wypełniają całe 1140 px,
      więc krótszy blok i tak zostawia pustkę po prawej — ale pustka POSTRZĘPIONA
      (trzy różne krawędzie: pudło cytatu, tekst cytatu i szersza od nich nota)
      czyta się jako urwany render, a nie jako oddech. Miary poniżej są dobrane tak,
      żeby prawa krawędź TEKSTU cytatu i noty wypadła w tym samym punkcie —
      arytmetyka jest jawna w `max-width` noty, nie ukryta w dwóch liczbach.

   ⚠️ MIARY SĄ W `rem`, NIE W `ch` — świadomie, inaczej niż w proof-stats. Powód:
      miara musi obowiązywać tekst w kroju DISPLAY (--tomit-font-display, ~19,6 px),
      a `ch` rozwiązuje się względem stopnia pisma elementu. Deklaracja `46ch`
      postawiona na pudle (krój body 17 px) dawała realnie ~40 znaków, a po przyjściu
      danych (`zapowiedz: false` → większy stopień) miara CICHO spadłaby do ~34.
      `rem` nie zależy ani od kroju, ani od trybu. Konwersja reszty miar to TIT-13.

   Belka po lewej stronie cytatu bierze --tomit-link (7,03:1 na bieli), nie
   --tomit-accent: cyjan dekoracyjny ma tu 2,41:1, a belka jest granicą elementu UI
   z progiem 3,0. Na jasnym tle zakazy działają „normalnie” — odwracają się dopiero
   na granacie (patrz baner hero).
   ============================================================================ */
.section-testimonial {
  /* Miara TEKSTU cytatu (nie pudła) — odpowiednik --proof-miara z sekcji wyżej
     wyrażony w rem, żeby rytm obu sekcji był ten sam. */
  --testimonial-miara: 40rem;
  --testimonial-fs: calc(var(--tomit-fs-body) * 1.35);
  --testimonial-fs-zapowiedz: calc(var(--tomit-fs-body) * 1.15);
  /* Interlinia cytatu: --tomit-lh-tight (1.12) jest kalibrowana na jedno- lub
     dwuwierszowe nagłówki i przy kilku wierszach cytatu skleja wiersze. */
  --testimonial-lh: 1.34;
  --testimonial-belka: 3px;

  background: var(--tomit-bg);
  color: var(--tomit-text);
}

.testimonial-eyebrow {
  margin: 0 0 var(--tomit-space-2);
  color: var(--tomit-link);
}

.testimonial-cytat {
  margin: 0;
  padding-left: var(--tomit-space-3);
  border-left: var(--testimonial-belka) solid var(--tomit-link);
}

/* Miara siedzi TU, a nie na pudle: to ten akapit niesie krój display i to jego
   szerokość widać. Ta sama miara stoi niżej na atrybucji, więc oba akapity bloku
   kończą się w jednym punkcie niezależnie od tego, czy atrybucja renderuje się
   jako <p> (zapowiedź), czy jako <cite> (stan docelowy).
   🔴 Klasa, nie selektor typu: w trybie zapowiedzi atrybucja też jest <p>, więc
      `.testimonial-cytat p` przejąłby nad nią typografię cytatu (wyższa
      specyficzność niż jednoklasowe `.testimonial-atrybucja`). */
.testimonial-tekst {
  max-width: var(--testimonial-miara);
  margin: 0;
  font-family: var(--tomit-font-display);
  font-size: var(--testimonial-fs);
  line-height: var(--testimonial-lh);
  letter-spacing: var(--tomit-tracking-display);
  color: var(--tomit-text);
}

.testimonial-cytat--zapowiedz .testimonial-tekst {
  font-size: var(--testimonial-fs-zapowiedz);
}

/* `margin` shorthandem, nie `margin-top`: w trybie zapowiedzi atrybucja jest <p>
   i domyślne marginesy UA muszą zostać wyzerowane, a nie tylko nadpisane u góry.
   `font-style: normal` zdejmuje kursywę z <cite> w stanie docelowym — kursywa
   oznacza tytuł dzieła, nie podpis osoby, więc to decyzja semantyczna, nie kosmetyka. */
.testimonial-atrybucja {
  display: block;
  max-width: var(--testimonial-miara);
  margin: var(--tomit-space-2) 0 0;
  font-style: normal;
  font-size: var(--tomit-fs-small);
  color: var(--tomit-text-muted);
}

/* Nota dzieli parę kontrastu z atrybucją (--tomit-text-muted na --tomit-bg).
   🔴 Szerokość jest WYLICZANA z miary cytatu, nie dobierana osobno: nota stoi poza
   pudłem cytatu, więc żeby jej prawa krawędź wypadła w tym samym punkcie co krawędź
   tekstu w środku, musi być szersza dokładnie o wcięcie pudła (belka + padding).
   Arytmetyka stoi tu jawnie — dwie niezależne liczby rozjechałyby się przy pierwszej
   korekcie rytmu i wróciłaby postrzępiona krawędź. */
.testimonial-nota {
  margin: var(--tomit-space-4) 0 0;
  max-width: calc(var(--testimonial-miara) + var(--tomit-space-3) + var(--testimonial-belka));
  font-size: var(--tomit-fs-small);
  color: var(--tomit-text-muted);
}

/* ============================================================================
   SEKCJA: services-grid  ·  partial: templates/partials/sections/services-grid.twig
   Tło BIAŁE (--tomit-bg), karty na jasnym boksie (--tomit-bg-box).

   🔴 KARTA MA WYPEŁNIENIE, NIE OBRYS — decyzja wymuszona kontrastem, nie gustem.
      --tomit-border (grey-300) na bieli daje 1,47:1, czyli grubo poniżej progu 3,0
      dla granicy elementu UI: obrys byłby granicą, której nie widać, a wpisany
      do rejestru par oblałby bramkę (i słusznie). Wypełnienie --tomit-bg-box
      oddziela kartę od tła sekcji bez granicy i bez długu kontrastu.

   🔴 AKCENT NA JASNYM TLE TO --tomit-link (cyan-800), NIGDY --tomit-accent
      (cyan-500, 2,41:1 na bieli — twardy zakaz pod tekstem). Zakazy odwracają się
      wyłącznie na granacie (patrz baner hero). Pary zmierzone:
      tools/contrast-pairs.yaml + check-contrast-pairs.py

   PRÓG MOBILNY 720px — wspólny dla całej fali (patrz baner hero). Ta siatka ma
   PONADTO próg lokalny 1040px i to nie jest złamanie umowy: cztery karty przestają
   mieścić się w rzędzie wcześniej, niż strona łamie układ na jedną kolumnę. W 720px
   nadal łamie się UKŁAD STRONY, a 1040 przestawia wyłącznie liczbę kolumn tej jednej
   siatki (4 → 2 → 1). Kroku 4 → 3 celowo nie ma: przy czterech kartach zostawiałby
   ostatnią samą w rzędzie.
   ============================================================================ */
.section-services {
  --services-kolumny: repeat(4, minmax(0, 1fr));
  /* Miara akapitu wprowadzającego — ta sama liczba znaków co --proof-miara, żeby
     rytm tekstu biegnącego był na całej stronie jeden (uwaga o `ch` vs `rem`
     w banerze proof-stats obowiązuje tak samo tutaj). */
  --services-miara: 62ch;
  --services-karta-pad: var(--tomit-space-3);

  background: var(--tomit-bg);
  color: var(--tomit-text);
}

.services-tytul {
  margin: 0;
  text-wrap: balance;
}

.services-akcent { color: var(--tomit-link); }

.services-intro {
  margin: var(--tomit-space-3) 0 0;
  max-width: var(--services-miara);
  color: var(--tomit-text-muted);
}

/* minmax(0, 1fr) jest konieczne, nie ozdobne: domyślne min-width kolumny gridu to
   `auto`, więc jedno długie słowo („Cyberbezpieczeństwo" — tytuł pierwszej karty)
   rozpycha kolumnę ponad przydział `fr` i wypycha układ poza kontener. Ta sama
   pułapka co w .hero-uklad i .proof-lista. */
.services-lista {
  list-style: none;
  margin: var(--tomit-space-4) 0 0;
  padding: 0;
  display: grid;
  grid-template-columns: var(--services-kolumny);
  gap: var(--tomit-space-3);
}

/* Kolumna + rozpychany akapit = linki kart na jednej linii bazowej. Opisy obszarów
   mają różną długość i łamią się na różną liczbę wierszy; bez `flex: 1 1 auto` na
   akapicie cztery linki wisiałyby na czterech różnych wysokościach, a rząd kart
   czytałby się jako niedokończony. Ta sama mechanika co w .proof-pozycja. */
.services-karta {
  display: flex;
  flex-direction: column;
  background: var(--tomit-bg-box);
  border-radius: var(--tomit-radius);
  padding: var(--services-karta-pad);
}

.services-karta-tytul {
  margin: 0;
  font-size: var(--tomit-fs-h3);
}

.services-karta-tekst {
  flex: 1 1 auto;
  margin: var(--tomit-space-2) 0 0;
  color: var(--tomit-text-muted);
}

/* `align-self: flex-start` — link ma być celem szerokości TEKSTU, nie całej karty:
   rozciągnięty na 100% szerokości dawałby obszar kliknięcia udający kartę klikalną
   w całości, czyli dokładnie ten wariant, który partial świadomie odrzucił.
   Podkreślenie zostaje (to link w bloku tekstu, nie przycisk) i znika na hoverze,
   spójnie z regułą `a:hover` z góry pliku. */
.services-link {
  align-self: flex-start;
  margin-top: var(--tomit-space-3);
  font-family: var(--tomit-font-display);
  font-size: var(--tomit-fs-small);
  font-weight: 600;
  color: var(--tomit-link);
}

/* Strzałka jest ozdobą afordancji, nie treścią: nazwę dostępną linku ustala
   `aria-label` w partialu, więc znak z ::after niczego w niej nie zmienia.

   🔴 `display: inline-block` JEST TU MECHANIZMEM, NIE PORZĄDKOWANIEM. Dekoracja tekstu
      propaguje się z elementu na potomków i potomek NIE MOŻE jej wyłączyć (CSS Text
      Decoration L3) — `text-decoration: none` postawione na ::after jest deklaracją bez
      skutku: podkreślenie i tak biegnie pod odstępem i pod strzałką. Wyłamuje z niego
      dopiero atomowy inline-block, bo dekoracja rodzica nie obejmuje jego wnętrza.
   ⚠️ `getComputedStyle(el, '::after').textDecorationLine` zwraca w obu wariantach `none`,
      więc computed style tej klasy NIE ROZSTRZYGA — dowodem jest wyłącznie zrzut (DPR ≥ 2).
      Odstęp robi `margin-left`, nie twarda spacja w `content`: spacja jest tekstem, więc
      podlega dekoracji rodzica i wracałaby pod kreskę razem ze strzałką. */
.services-link::after {
  content: "\2192";
  display: inline-block;
  margin-left: 0.35em;
}

.services-link:hover { text-decoration: none; }

@media (max-width: 1040px) {
  .section-services { --services-kolumny: repeat(2, minmax(0, 1fr)); }
}

@media (max-width: 720px) {
  .section-services { --services-kolumny: 1fr; }
}

/* ============================================================================
   SEKCJA: feature-split  ·  partial: templates/partials/sections/feature-split.twig
   Tło BIAŁE (--tomit-bg). Lewa kolumna: tekst. Prawa: proces w panelu --tomit-bg-box.

   🔴 PRAWA KOLUMNA NIE JEST DEKOREM I NIE STOI NA MIEJSCU ZDJĘCIA. Klient nie
      dostarczył materiału zdjęciowego, a synteza AI to osobna decyzja o kluczach
      i koszcie (decyzja C4: abstrakcja tokenowa, powściągliwie). Panel renderuje
      `steps[]` — nazwy i opisy kroków — więc jest TREŚCIĄ i dlatego nie ma
      `aria-hidden` (ma go w partialu wyłącznie numer w kółku, bo kolejność niesie
      już znacznik <ol>). Kreska łącząca kroki powstaje w ::before, więc w drzewie
      dostępności nie istnieje i niczego nie wymaga.

   🔴 NA MOBILE PROCES IDZIE POD TEKSTEM, nie nad — i wynika to z KOLEJNOŚCI W ŹRÓDLE,
      nie z `order`. Kolejność wizualna sterowana `order` rozjeżdża się z kolejnością
      czytania klawiaturą i czytnikiem ekranu; tu obie są te same, bo panel stoi
      w markupie po tekście.

   AKCENT NA JASNYM TLE = --tomit-link (cyan-800), nigdy --tomit-accent (2,41:1 na
   bieli). Kółko numeru i kreska osi to granice elementów UI (próg 3,0), sam numer
   i teksty kroków — tekst (4,5). Pary: tools/contrast-pairs.yaml
   PRÓG MOBILNY 720px — wspólny dla całej fali (patrz baner hero).
   ============================================================================ */
.section-feature {
  --feature-kolumny: minmax(0, 1.05fr) minmax(0, 0.95fr);
  --feature-miara: 54ch;
  --feature-panel-pad: var(--tomit-space-4);
  /* Średnica kółka numeru. Steruje TRZEMA rzeczami naraz (wcięcie treści kroku,
     pozycja osi pionowej, wyrównanie tytułu do środka kółka) — dlatego jest jedną
     custom property, a nie trzema liczbami, które rozjadą się przy pierwszej korekcie. */
  --feature-numer-rozmiar: 2.25rem;
  --feature-os: 2px;

  background: var(--tomit-bg);
  color: var(--tomit-text);
}

/* `align-items: start` — panel procesu ma zaczynać się na wysokości nadtytułu,
   a nie rozciągać na wysokość kolumny tekstu (rozciągnięty dawałby pustkę pod
   ostatnim krokiem, czytaną jako niedokończony blok). */
.feature-uklad {
  display: grid;
  grid-template-columns: var(--feature-kolumny);
  gap: var(--tomit-space-4);
  align-items: start;
}

.feature-eyebrow {
  margin: 0 0 var(--tomit-space-2);
  color: var(--tomit-link);
}

.feature-tytul {
  margin: 0;
  text-wrap: balance;
}

.feature-akcent { color: var(--tomit-link); }

.feature-akapit {
  margin: var(--tomit-space-3) 0 0;
  max-width: var(--feature-miara);
}

.feature-cta {
  display: flex;
  flex-wrap: wrap;
  gap: var(--tomit-space-2);
  margin: var(--tomit-space-4) 0 0;
}

.feature-panel {
  background: var(--tomit-bg-box);
  border-radius: var(--tomit-radius);
  padding: var(--feature-panel-pad);
}

.feature-lista {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--tomit-space-3);
}

.feature-krok {
  position: relative;
  padding-left: calc(var(--feature-numer-rozmiar) + var(--tomit-space-2));
}

/* Oś procesu: odcinek od dołu kółka do kółka następnego kroku. Rysowana per krok
   (a nie jedną kreską przez całą listę), bo tylko wtedy kończy się dokładnie na
   ostatnim kółku — kreska ciągnąca się pod ostatnim krokiem sugerowałaby krok piąty.
   `bottom` sięga w odstęp siatki, stąd ujemna wartość równa `gap`. */
.feature-krok:not(:last-child)::before {
  content: "";
  position: absolute;
  left: calc(var(--feature-numer-rozmiar) / 2 - var(--feature-os) / 2);
  top: var(--feature-numer-rozmiar);
  bottom: calc(var(--tomit-space-3) * -1);
  width: var(--feature-os);
  background: var(--tomit-link);
}

/* Tło kółka = tło panelu, żeby oś nie przechodziła przez jego wnętrze. */
.feature-numer {
  position: absolute;
  left: 0;
  top: 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: var(--feature-numer-rozmiar);
  height: var(--feature-numer-rozmiar);
  border: var(--feature-os) solid var(--tomit-link);
  border-radius: var(--tomit-radius-pill);
  background: var(--tomit-bg-box);
  font-family: var(--tomit-font-display);
  font-size: var(--tomit-fs-small);
  font-weight: 600;
  line-height: 1;
  color: var(--tomit-link);
}

/* Wcięcie górne wyrównuje linię bazową tytułu do ŚRODKA kółka — arytmetyka jawna
   z tych samych zmiennych co kółko, więc zmiana średnicy nie wymaga dobierania
   drugiej liczby na oko. */
.feature-krok-tytul {
  margin: 0;
  padding-top: calc((var(--feature-numer-rozmiar) - var(--tomit-fs-h3) * 1.2) / 2);
  font-size: var(--tomit-fs-h3);
  line-height: 1.2;
}

.feature-krok-tekst {
  margin: var(--tomit-space-1) 0 0;
  color: var(--tomit-text-muted);
}

@media (max-width: 720px) {
  .section-feature {
    --feature-kolumny: 1fr;
    --feature-panel-pad: var(--tomit-space-3);
  }

  /* Jak w hero: na wąskim ekranie przycisk idzie pełną szerokością kontenera
     zamiast wystawać poza niego (kryterium „zero przewijania poziomego"). */
  .feature-cta .btn { flex: 1 1 100%; }
}

/* ============================================================================
   SEKCJA: tech-partnership  ·  partial: templates/partials/sections/tech-partnership.twig
   Tło JASNE (--tomit-bg-box) — rytm tła fali: ciemny hero, jasny boks, biel, biel,
   jasny boks, biel, ciemny cta-band (klamra).

   🔴 NAZWA KLASY WYPROWADZONA Z NAZWY TYPU SEKCJI, ŚWIADOMIE. Ta sama nazwa stoi już
      w CZTERECH miejscach: `type:` w content/home.md, kluczu content-schema.yaml, nazwie
      pliku partiala i atrybucie data-section (po którym szuka bramka renderu). Piąta,
      przetłumaczona nazwa znaczyłaby, że blok CSS znajdzie tylko ten, kto zna tłumaczenie.
      TIT-12 zostawił konwencję rozjechaną (services-grid → .section-uslugi, feature-split
      → .section-proces); UJEDNOLICIŁ JĄ TIT-13 — pełna reguła i jej granice w bloku
      „UJEDNOLICENIA CAŁOŚCIOWE" na końcu pliku.

   🔴 AKCENT NA JASNYM TLE TO --tomit-link (cyan-800), NIGDY --tomit-accent (cyan-500,
      2,41:1 na bieli). Zakazy odwracają się wyłącznie na granacie (patrz baner hero
      i blok cta-band niżej). Pary zmierzone: tools/contrast-pairs.yaml

   ODNOŚNIK DO ŹRÓDŁA JEST TU LEGALNY WŁAŚNIE DLATEGO, ŻE TŁO JEST JASNE: --tomit-link na
   --tomit-bg-box ma 6,39:1. Ten sam token na granacie oblewa (2,48:1) — nie kopiować tego
   odruchu do cta-band.

   PRÓG MOBILNY 720px — wspólny dla całej fali (patrz baner hero). Sekcja NIE dokłada progu
   lokalnego: ma dwie kolumny, a nie siatkę czterech kart, więc nie ma nic, co przestawałoby
   się mieścić wcześniej (inaczej niż services-grid z jego progiem 1040px).
   ============================================================================ */
.section-tech-partnership {
  --tech-kolumny: minmax(0, 1.05fr) minmax(0, 0.95fr);
  /* Miara akapitu partnerstwa — ta sama liczba znaków co --feature-miara w sekcji obok,
     żeby dwie sąsiadujące kolumny tekstu miały ten sam rytm (uwaga o `ch` vs `rem`
     z banera proof-stats obowiązuje tak samo tutaj; konwersja miar = TIT-13). */
  --tech-miara: 54ch;
  --tech-kreska: 3px;

  background: var(--tomit-bg-box);
  color: var(--tomit-text);
}

/* `align-items: start` — lista technologii zaczyna się na wysokości nadtytułu i nie
   rozciąga się na wysokość kolumny tekstu (ta sama decyzja co w .feature-uklad).
   minmax(0, …) jest konieczne, nie ozdobne: domyślne min-width kolumny gridu to `auto`,
   więc długie polskie słowo („wieloskładnikowe") rozpycha kolumnę ponad przydział `fr`. */
.tech-uklad {
  display: grid;
  grid-template-columns: var(--tech-kolumny);
  gap: var(--tomit-space-4);
  align-items: start;
}

.tech-eyebrow {
  margin: 0 0 var(--tomit-space-2);
  color: var(--tomit-link);
}

.tech-tytul {
  margin: 0;
  text-wrap: balance;
}

.tech-akcent { color: var(--tomit-link); }

.tech-partner-tekst {
  margin: var(--tomit-space-3) 0 0;
  max-width: var(--tech-miara);
}

/* Odznaka partnera — sterujemy WYŁĄCZNIE rozmiarem i odstępem.
   Znak niesie własne barwy producenta; żaden filtr, żadne `currentColor`. */
.tech-badge {
  margin: var(--tomit-space-3) 0 0;   /* 1.5rem = 24px — token, nie surowe px */
}
.tech-badge img {
  display: block;
  width: auto;
  /* 56 px — DECYZJA WŁAŚCICIELA 2026-08-09 (było 40 px). Powód: napis „PARTNER" wewnątrz
     znaku ma przy 40 px ok. 5 px wersalika i jest nieczytelny; przy 56 px rośnie o 40 %.
     Zmierzone po zmianie (`python3 tools/sonda-szerokosci.py --url http://127.0.0.1:8099/`):
     bbox znaku **130×56 px** na obu mierzonych szerokościach (1440 i 390 px), przy szerokości
     kolumny `.tech-tresc` **578 px** (1440) i **358 px** (390) — mieści się z zapasem,
     wąskim gardłem jest mobile i tam zostaje 228 px luzu. Sterujemy WYSOKOŚCIĄ w rytmie
     strony, nie szerokością (znak ma proporcję 231:100). */
  height: 56px;
  max-width: 100%;
}

/* Odnośnik do materiału producenta. Podkreślenie ZOSTAJE (to link w bloku tekstu, nie
   przycisk) i znika na hoverze, spójnie z regułą `a:hover` z góry pliku — kolor bierze
   z tej samej reguły `a`, więc nie powtarzamy go tutaj. */
.tech-zrodlo {
  margin: var(--tomit-space-2) 0 0;
  font-size: var(--tomit-fs-small);
}

/* Odnośnik w głąb serwisu (`cta[]` → /rublon-mfa). Sam przycisk NIE jest tu definiowany —
   komponent .btn/.btn--ghost mieszka w bloku hero; ta reguła daje wyłącznie odstęp, tak samo
   jak .feature-cta w sekcji obok. Wariant obrysowy, żeby nie konkurował z wezwaniem
   podstawowym w `cta-band`. Pary kontrastu (etykieta i obrys na --tomit-bg-box)
   są w tools/contrast-pairs.yaml. */
.tech-cta {
  margin: var(--tomit-space-3) 0 0;
}

/* Lista technologii. Kreska nad pozycją zamiast obrysu karty — ta sama mechanika co
   w .proof-pozycja: obrys --tomit-border na jasnym boksie miałby 1,34:1, czyli granicę,
   której nie widać (i para w rejestrze by oblała). Kreska jest CIĄGŁA i pełną mocą koloru. */
.tech-lista {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  gap: var(--tomit-space-3);
}

.tech-pozycja {
  border-top: var(--tech-kreska) solid var(--tomit-link);
  padding-top: var(--tomit-space-2);
}

.tech-nazwa {
  margin: 0;
  font-family: var(--tomit-font-display);
  font-size: var(--tomit-fs-h3);
  line-height: var(--tomit-lh-tight);
  letter-spacing: var(--tomit-tracking-display);
  color: var(--tomit-text);
}

/* Rola technologii — to jedyne miejsce tej sekcji, które mogłoby zsunąć się do poziomu
   datasheetu. Trzyma je treść (rola z brand.yaml), nie arkusz; stopień pisma tylko
   podporządkowuje ją nazwie. */
.tech-rola {
  margin: var(--tomit-space-1) 0 0;
  font-size: var(--tomit-fs-small);
  color: var(--tomit-text-muted);
}

/* Nota dzieli parę kontrastu z rolą (--tomit-text-muted na --tomit-bg-box), dlatego
   w rejestrze par siedzi jeden wiersz na obie. Stoi POD siatką, w osobnym .wrap, bo
   dotyczy całej sekcji, a nie jednej z jej kolumn. */
.tech-nota {
  margin: var(--tomit-space-4) 0 0;
  max-width: var(--tech-miara);
  font-size: var(--tomit-fs-small);
  color: var(--tomit-text-muted);
}

@media (max-width: 720px) {
  .section-tech-partnership { --tech-kolumny: 1fr; }
}

/* ============================================================================
   SEKCJA: cta-band  ·  partial: templates/partials/sections/cta-band.twig
   Tło CIEMNE (--tomit-bg-dark) — domknięcie klamrą wobec ciemnego hero.

   🔴 NA GRANACIE ZAKAZY SIĘ ODWRACAJĄ — DRUGI RAZ NA TEJ STRONIE, więc drugi raz łatwo
      o odruch „link = --tomit-link". Ten token ma tu 2,48:1 i oblewa AA; czytelny jest
      --tomit-accent-on-dark (cyjan, 7,22:1), zakazany z kolei pod tekstem na bieli.
      Tekst tej sekcji bierze WYŁĄCZNIE tokeny *-on-dark. Pary zmierzone:
      tools/contrast-pairs.yaml + check-contrast-pairs.py

   🔴 PRZYCISK NIE JEST TU DEFINIOWANY. Komponent .btn/.btn--primary/.btn--ghost mieszka
      w bloku hero (baner „KOMPONENT .btn"); ta sekcja ustawia wyłącznie KONTEKST kolorów —
      te same pięć custom property co .section-hero. Rozstrzygnięcie granicy przycisku na
      granacie pochodzi z TIT-09, wariant (a): przycisk podstawowy na ciemnym jest JASNY
      (--tomit-cta na --tomit-bg-dark to 2,80:1, poniżej progu 3,0 dla granic elementów UI).
      Gdyby kusiło dopisać tu własne reguły tła/obrysu — to znaczy, że wariant z hero nie był
      dość ogólny i trzeba UOGÓLNIĆ komponent, a nie zduplikować go w drugim bloku.

   UKŁAD LEWOSTRONNY, NIE WYŚRODKOWANY — decyzja, nie przeoczenie. Wszystkie sześć sekcji
   powyżej wyrównuje treść do lewej krawędzi kontenera; wyśrodkowany pas dokładałby na
   ostatnim ekranie drugą oś układu, czyli dokładnie ten rodzaj rozjazdu, który TIT-13 ma
   potem porządkować. Domknięcie robi tu zmiana tła, nie zmiana wyrównania.

   PRÓG MOBILNY 720px — wspólny dla całej fali (patrz baner hero).
   ============================================================================ */
.section-cta-band {
  /* Klamra zamykająca ma własną wartość pionową — środkowe sekcje 40 px (--tomit-space-4),
     klamra 64 px (--tomit-space-5), otwarcie 80 px (hero). Trzy stopnie, wszystkie nazwane;
     TIT-13 domyka drabinę, przenosząc hero z mnożnika 1.25 na wartość tokenową. */
  --cta-band-pad-block: var(--tomit-space-5);
  /* Miara tekstu — jedna wartość dla akapitu i noty, żeby nie mogły się rozjechać
     przy późniejszej korekcie (ta sama umowa co --hero-miara). */
  --cta-band-miara: 52ch;

  /* ⚠️ TŁA, KOLORU TEKSTU I KONTEKSTU PRZYCISKÓW TU NIE MA. TIT-12 powtarzał tu
     siedem deklaracji identycznych z .section-hero, świadomie („powtórzeniem byłaby
     dopiero druga definicja .btn--primary"). TIT-13 zdjął to powtórzenie do jednego
     grupowanego selektora `.section-hero, .section-cta-band` w bloku „UJEDNOLICENIA
     CAŁOŚCIOWE" na końcu pliku — grupowany selektor, a NIE wspólna klasa: klasa
     musiałaby wejść w warstwę wiązania tokenów na górze pliku, gdzie sekcje z założenia
     nie wchodzą, albo do markupu partiali, których to zadanie nie przepisuje. */
  padding-block: var(--cta-band-pad-block);
}

/* Reguła h2 z góry pliku ustawia color:var(--tomit-text) (granat) — na granatowym tle
   dałaby nagłówek niewidoczny. Nadpisanie jest konieczne, nie kosmetyczne (ta sama
   pułapka co .hero-tytul). */
.cta-band-tytul {
  margin: 0;
  max-width: var(--cta-band-miara);
  color: var(--tomit-fg-on-dark);
  text-wrap: balance;
}

/* Akcent nagłówka: cyjan jest tu LEGALNY, bo tłem jest granat. Reguła istnieje, mimo że
   treść dziś nie używa `heading_accent` — partial emituje tę klasę dla każdego wystąpienia
   typu z akcentem (a typ wraca na kolejnych trasach), więc bez niej pierwsze użycie
   wyrenderowałoby się kolorem tekstu. Para jest w rejestrze, żeby bramka pilnowała jej
   razem z resztą sekcji. */
.cta-band-akcent { color: var(--tomit-accent-on-dark); }

.cta-band-tekst {
  margin: var(--tomit-space-3) 0 0;
  max-width: var(--cta-band-miara);
  font-size: calc(var(--tomit-fs-body) * 1.08);
  color: var(--tomit-fg-on-dark);
}

.cta-band-akcje {
  display: flex;
  flex-wrap: wrap;
  gap: var(--tomit-space-2);
  margin: var(--tomit-space-4) 0 0;
}

.cta-band-nota {
  margin: var(--tomit-space-3) 0 0;
  max-width: var(--cta-band-miara);
  font-size: var(--tomit-fs-small);
  color: var(--tomit-fg-on-dark-muted);
}

@media (max-width: 720px) {
  .section-cta-band { --cta-band-pad-block: var(--tomit-space-4); }

  /* Jak w hero i feature-split: na wąskim ekranie przycisk idzie pełną szerokością
     kontenera zamiast wystawać poza niego (kryterium „zero przewijania poziomego"). */
  .cta-band-akcje .btn { flex: 1 1 100%; }
}

/* ----------------------------------------------------------------------------
   OBRAZ TREŚCIOWY W MARKDOWNIE PODSTRON (TIT-23)

   Dotyczy tras na `template: page`, gdzie treść idzie przez Parsedown do
   `page.twig` → `<article class="prose">`. Pierwszy taki obraz to diagram metod
   uwierzytelniania na /uslugi/cyberbezpieczenstwo — on JEST treścią, nie dekorem,
   więc dostaje własny rytm i nie wychodzi poza kolumnę tekstu.

   🔴 KLASA KONTENERA ODTWORZONA Z RENDERU, NIE ZGADNIĘTA. Zmierzone curl-em
      na stojącym `php -S` (/uslugi/cyberbezpieczenstwo): w dokumencie są klasy
      `prose`, `section`, `wrap`, `is-subpage`, … — klasy `page-tresc` w tej
      instancji NIE MA. Selektor napisany na zgadniętą nazwę wyrenderowałby się
      bez błędu, w domyślnym stylu przeglądarki, i ŻADNA bramka by tego nie
      złapała: obraz jest wtedy `inline`, bez ograniczenia szerokości.

   🔴 DWA AKAPITY, NIE JEDEN. Parsedown zamyka obraz we WŁASNYM `<p>`, a podpis
      w następnym (zmierzone w renderze) — bez reguły na styk tej pary podpis
      odsuwa się na pełny stopień rytmu i przestaje czytać się jako podpis TEGO
      obrazu. `:has()` jest tu jedynym sposobem trafienia w „akapit, w którym
      siedzi obraz" bez ingerencji w silnik: HTML generuje Parsedown, instancja
      nie ma gdzie dopisać klasy. Degradacja przy braku wsparcia jest łagodna
      (podpis dostaje zwykły odstęp akapitu), więc reguła nie jest warunkiem
      poprawności układu.
   ---------------------------------------------------------------------------- */

.prose img {
  display: block;
  max-width: 100%;
  height: auto;
  margin: var(--tomit-space-4) auto var(--tomit-space-1);
}

.prose p:has(> img) { margin-bottom: 0; }

/* Podpis pod obrazem: mniejszy stopień i przygaszony kolor, żeby nie czytał się
   jako kolejny akapit treści. Para --tomit-text-muted na --tomit-bg jest
   w rejestrze tools/contrast-pairs.yaml (wiersz „podstrona usługowa — podpis…").

   🔴 SELEKTOR CELUJE W PODPIS (`*kursywa*` jako CAŁY akapit), NIE w „akapit po obrazie".
      Poprawka po recenzji TIT-23: pierwotne `.prose p:has(> img) + p` ustanawiało na
      WSZYSTKICH trasach `template: page` cichą konwencję „akapit po obrazie = podpis" —
      zwykły akapit treści postawiony pod ilustracją dostawał mniejszy stopień i przygaszony
      kolor, a żadna bramka tego nie mierzy (HTTP 200, kontrast pary z rejestru nadal OK).
      `:has(> em:only-child)` zawęża to do markdownowego `*…*` w osobnej linii, czyli do
      zapisu, którym podpisy są pisane w treści.

   ⚠️ `<em>` NIE JEST TU DOCELOWY — jest jedynym nośnikiem, jaki daje dzisiejszy render.
      Parsedown (silnik `core/web-app`) zwraca dla obrazu z podpisem `<p><img></p><p><em>…</em></p>`,
      więc semantyczne `<figure>`/`<figcaption>` wymaga zmiany W SILNIKU (hook renderera treści),
      nie w tym arkuszu. To kandydat do toru B defektów silnika web-app
      (docs/prompty/2026-08-09-atomizacja-defektow-silnika-web-app.md), nie do instancji. */
.prose p:has(> img) + p:has(> em:only-child) {
  margin-top: 0;
  font-size: var(--tomit-fs-small);
  color: var(--tomit-text-muted);
}

/* ----------------------------------------------------------------------------
   ODZNAKA PARTNERSKA W TREŚCI (TIT-24, trasa /rublon-mfa)

   🔴 BEZ TEJ REGUŁY ODZNAKA ROZCIĄGA SIĘ NA CAŁĄ SZEROKOŚĆ KOLUMNY TREŚCI.
      Zmierzone sondą przed dopisaniem reguły: bbox 707×306 px przy 1440 px viewportu
      (i 358×155 przy 390 px) — czyli znak 231×100 powiększony ponad trzykrotnie.
      Powód jest w samym pliku SVG, nie w arkuszu: `Rublon Partner Badge RGB.svg` ma
      WYŁĄCZNIE `viewBox`, bez atrybutów `width`/`height`, więc jako element zastąpiony
      ma proporcję, ale nie ma wewnętrznej szerokości — a `display:block` z `width:auto`
      rozciąga się wtedy do szerokości kontenera. `max-width:100%` z reguły `.prose img`
      tego NIE ogranicza (707 < 707). Diagram metod tego problemu nie ma, bo jego SVG
      niesie `width="1373" height="1492"`. Żadna bramka tego nie łapie: HTTP 200, obraz
      doładowany, `scrollWidth == clientWidth` — wychodzi wyłącznie na zrzucie.

   Wysokość jest podana w px świadomie i jest to konwencja tej instancji (ta sama co
   `.tech-badge img` na `/`, gdzie znak ma 40 px): to WYSOKOŚĆ ZNAKU w rytmie strony,
   nie odstęp — odstępy w tym arkuszu idą przez `var(--tomit-space-*)` i tak zostaje.
   Znak jest większy niż na `/`, bo tu jest treścią sekcji, a nie stopką sekcji.

   🔴 SELEKTOR IDZIE ZA KONWENCJĄ NAZW, NIE ZA JEDNYM PLIKIEM (poprawka po recenzji TIT-24).
      Konwencja: znak partnerski leży w `assets/img/partnerzy/` i nazywa się
      `<partner>-partner-badge.svg`. Pierwotny zapis `[src$="rublon-partner-badge.svg"]`
      był zakluczowany nazwą JEDNEGO pliku, więc przy drugim partnerze defekt (rozciągnięcie
      znaku na całą kolumnę) wróciłby po cichu — bramki go nie łapią.
      Katalog w selektorze jest istotny: bez niego łapałby się każdy plik o tej końcówce
      spoza `partnerzy/`. Diagram `rublon-metody-uwierzytelniania.svg` NIE pasuje (inna
      końcówka), a odznaka na `/` idzie klasą `.tech-badge`, nie `.prose` — obie nietknięte.
   ---------------------------------------------------------------------------- */
.prose img[src*="/img/partnerzy/"][src$="-partner-badge.svg"] {
  width: auto;
  height: 64px;      /* proporcja 231:100 zachowana przez width:auto */
  max-width: 100%;
}

/* ============================================================================
   UJEDNOLICENIA CAŁOŚCIOWE (TIT-13)  ·  nie sekcja — reguły MIĘDZY sekcjami

   🔴 KOLEJNY BLOK SEKCJI DOPISUJE SIĘ NAD TYM BANEREM, NIE POD NIM.
      Ten blok musi zostać OSTATNI w arkuszu: przy równej specyficzności wygrywa nad
      blokami sekcji i na tym stoi gwarancja, że kontekst sekcji ciemnej i typografia
      nadtytułu obowiązują wszystkie sekcje. Blok sekcji wstawiony PO nim odwróciłby tę
      zależność po cichu — nowa sekcja na granacie przykryłaby grupowany selektor
      i wszystko dalej renderowałoby się poprawnie, więc żadna bramka by tego nie złapała.

   Ten blok istnieje, bo trzy rzeczy widać dopiero na komplecie siedmiu sekcji
   i żadna nie należy do żadnej z nich z osobna: rytm pionowy, styk dwóch sekcji
   o tym samym tle i kontekst „sekcja ciemna". Stoi na KOŃCU pliku (kierunek wzrostu
   arkusza wg konwencji fali), więc przy równej specyficzności wygrywa nad blokami
   sekcji — a że sekcje przestały deklarować to, co jest tutaj, kolejność i tak
   niczego nie rozstrzyga. To zabezpieczenie, nie mechanizm.

   ── 1. DRABINA RYTMU PIONOWEGO — trzy stopnie, wszystkie nazwane ──────────────
      40 px  ŚRODEK   `.section { padding-block: var(--tomit-space-4) }` (warstwa wiązania
                      tokenów na górze pliku — szukaj selektora, nie numeru linii)
                      — pięć sekcji środkowych, styk dwóch daje 80 px oddechu
      64 px  KLAMRA   `--cta-band-pad-block: var(--tomit-space-5)`
      80 px  OTWARCIE `--hero-pad-block: calc(var(--tomit-space-5) * 1.25)`
                      — mnożnik, bo tokenu 80 px w brandzie NIE MA (patrz baner hero);
                        to jedyny magiczny mnożnik rytmu, jaki został, i ma powód.
      Na progu 720 px hero i cta-band spadają do 40 px, czyli do stopnia środkowego —
      na wąskim ekranie klamra przestaje być potrzebna, bo sekcje i tak są pełnej szerokości.

   ── 2. DRABINA MIAR TEKSTU — decyzja: JEDNOSTKI ZOSTAJĄ ROZDZIELONE ───────────
      Trzy bloki sekcji (proof-stats, services-grid, tech-partnership) odsyłały
      konwersję `ch` → `rem` do tego zadania. Rozstrzygnięcie: NIE konwertujemy.
      Powód jest mierzalny, nie estetyczny: `ch` rozwiązuje się względem stopnia pisma
      ELEMENTU, więc trzyma stałą LICZBĘ ZNAKÓW (miara typograficzna) kosztem stałej
      liczby pikseli; `rem` odwrotnie. Tekst biegnący (52/54/62 ch) chce pierwszego,
      cytat w kroju display (--testimonial-miara: 40rem) drugiego, bo tam stopień pisma
      zmieni się sam przy `zapowiedz: false` i miara w `ch` CICHO by się skurczyła
      (zmierzone w TIT-10: 46ch dawało realnie ~40 znaków, po zmianie trybu ~34).
      Ujednolicona jest więc DRABINA (52 / 54 / 62 ch + 40 rem dla display), nie jednostka.
      Kto to kiedyś zmieni, zmienia OBIE strony naraz albo wraca do tego akapitu.

   ── 3. NAZWY KLAS SEKCJI — reguła domknięta w tym zadaniu ─────────────────────
      🔴 KLASA SEKCJI WYPROWADZA SIĘ Z `data-section`, NIGDY Z TŁUMACZENIA.
         Do TIT-12 dwie sekcje łamały to (`services-grid` → `.section-uslugi`,
         `feature-split` → `.section-proces`), więc blok CSS znajdował tylko ten, kto
         znał polski odpowiednik typu. TIT-13 przepisał obie w komplecie — wraz
         z prefiksami wewnętrznymi (`.uslugi-*` → `.services-*`, `.proces-*` →
         `.feature-*`) i lokalnymi custom property. Stan po: 7/7 sekcji ma klasę
         wyprowadzalną z typu (hero · proof ⊂ proof-stats · services ⊂ services-grid ·
         feature ⊂ feature-split · tech ⊂ tech-partnership · testimonial · cta-band).
         Człon jest SKRÓTEM typu, nie jego kopią co do znaku — `.proof-wartosc`
         i `.tech-nazwa` istniały tak od początku i są wyprowadzalne; polskie sufiksy
         (`-wartosc`, `-karta`, `-krok`) zostają, bo to konwencja całego arkusza.
   ============================================================================ */

/* KONTEKST SEKCJI CIEMNEJ — raz dla obu sekcji na granacie.
   Grupowany selektor, a NIE wspólna klasa: klasa musiałaby wejść albo w pierwsze
   warstwę wiązania tokenów na górze pliku (gdzie sekcje z założenia nie wchodzą), albo w markup
   partiali, których to zadanie nie przepisuje. Do TIT-12 te siedem deklaracji stało
   w dwóch miejscach, identyczne co do znaku — przy pierwszej zmianie palety rozjazd
   byłby cichy, bo obie kopie renderują się poprawnie osobno.
   Ósma deklaracja (--focus-obrys) dołącza tu z premedytacją: „sekcja ciemna" to
   JEDEN kontekst, a nie tło plus osobno wyjątek na obrys focusu. */
.section-hero,
.section-cta-band {
  --btn-bg: var(--tomit-fg-on-dark);
  --btn-fg: var(--tomit-bg-dark);
  --btn-obrys: var(--tomit-fg-on-dark);
  --btn-ghost-fg: var(--tomit-accent-on-dark);
  --btn-ghost-obrys: var(--tomit-accent-on-dark);
  --focus-obrys: var(--tomit-accent-on-dark);

  background: var(--tomit-bg-dark);
  color: var(--tomit-fg-on-dark);
}

/* NADTYTUŁ SEKCJI — jedna typografia dla pięciu konsumentów.
   `.hero-eyebrow`, `.proof-etykieta`, `.testimonial-eyebrow`, `.feature-eyebrow`,
   `.tech-eyebrow` powtarzały te same cztery deklaracje; cztery z nich były identyczne
   co do znaku poza `color`, piąta (`.proof-etykieta`) różniła się jeszcze marginesem.
   Wspólne zostaje tutaj, RÓŻNE zostaje w blokach sekcji:
     — `color`  bo zależy od tła (na granacie `--tomit-accent-on-dark`, na jasnym
                `--tomit-link`, w pasie liczb `--tomit-text-muted`: etykieta jest tam
                podpisem wartości, a nie nadtytułem sekcji),
     — `margin` bo w `proof-stats` etykieta stoi POD wartością, a nie NAD nagłówkiem.
   `TIT-10` odłożył to ujednolicenie z uzasadnieniem, że wspólna klasa wymagałaby tknięcia
   markupu `hero`. Przesłanka **padła w TIT-13**: grupowany selektor robi to samo bez
   jednej zmiany w partialach — tak samo jak kontekst sekcji ciemnej wyżej.
   🔴 SELEKTOR JEST LISTĄ, NIE WZORCEM — ósma sekcja z nadtytułem musi się tu dopisać.
      Nie ma tu magii, która obejmie ją sama; przepis „jak dodać sekcję" (README, krok 4)
      o tym mówi. */
.hero-eyebrow,
.proof-etykieta,
.testimonial-eyebrow,
.feature-eyebrow,
.tech-eyebrow {
  font-family: var(--tomit-font-display);
  font-size: var(--tomit-fs-small);
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/* STYK DWÓCH SEKCJI O TYM SAMYM TLE.
   Rytm tła fali (README backlogu §Ustalenia) daje na `/` dokładnie JEDNĄ taką parę:
   `services-grid` i `feature-split` stoją obie na --tomit-bg, więc 80 px oddechu
   między nimi nie jest granicą — dwa bloki czytają się jak jeden długi.
   ⚠️ Para jest wymieniona JAWNIE, bo CSS nie ma selektora „sąsiad o tym samym tle",
      a markup partiali nie niesie klasy rodziny tła (dołożenie jej to zmiana siedmiu
      szablonów, czyli więcej niż problem). Jeśli rytm tła się zmieni, ta reguła jest
      jednym miejscem do poprawienia — i jedynym, które o tym wie.
   Kreska jest CELOWO na progu widoczności (--tomit-border na bieli = 1,47:1): ma
   domykać kompozycję, a nie dzielić stronę na kafelki. To NIE jest granica elementu
   UI w rozumieniu WCAG 1.4.11 (nic nie otacza, niczego nie obsługuje, jej brak nie
   odbiera żadnej informacji), więc próg 3,0 jej nie dotyczy i nie ma jej w rejestrze par. */
.section-services + .section-feature {
  border-top: 1px solid var(--tomit-border);
}
