/* course_stickybar — sections/course_stickybar.php
   .m-sticky to nazwa komponentu z DESIGN-SYSTEM.md (sticky-price-bar), ale
   design-system.css wyklucza "sticky bar" z atomów wielokrotnego użytku —
   cały kształt (łącznie z .m-sticky) budowany tu, specyficznie dla kursu. */

/* Wysokość paska różni się mobile/desktop i przy złamaniu tekstu (np. inne
   ustawienia systemowe czcionki) — zmierzona w JS (course_stickybar.js,
   ResizeObserver na .m-sticky) i nadpisywana tu natychmiast po starcie.
   Wartość niżej to tylko bezpieczny fallback na czas przed pierwszym
   pomiarem, żeby #main miał zarezerwowane miejsce od razu przy renderze. */
:root {
  --csb-height: 96px;
}

/* Strona nie scrolluje się na tyle nisko, by odsłonić treść zasłoniętą przez
   position: fixed pasek — bez tego paddingu jej ostatni element jest schowany
   pod paskiem. Rezerwacja siedzi na <body>, nie na #main, bo pod #main stoi
   jeszcze stopka (sections/footer.php) i to jej pasek prawny jest teraz
   ostatni. Tło <body> i stopki to ten sam --ds-color-canvas, więc zapas pod
   stopką jest niewidoczny. */
body {
  padding-bottom: var(--csb-height);
}

.m-sticky {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  z-index: 1030;
  background-color: var(--ds-color-canvas);
  border-top: 1px solid var(--ds-color-hairline);
  border-radius: var(--ds-radius-lg) var(--ds-radius-lg) 0 0;
  box-shadow: var(--ds-shadow-sticky-bar);
  transform: translateY(100%);
  opacity: 0;
  pointer-events: none;
  transition: transform var(--ds-duration-slow) var(--ds-ease-out-soft),
              opacity var(--ds-duration-slow) var(--ds-ease-out-soft);
}
/* Zapas pod paskiem, niewidoczny w spoczynku (position: fixed + bottom: 0
   trzyma cały box na dole ekranu, więc ten kawałek renderuje się poniżej
   widocznego obszaru). Na Chrome/iOS zmierzono, że window.innerHeight i
   visualViewport.height są sobie zawsze równe w spoczynku (przetestowane na
   realnym urządzeniu: 777px z chowanym paskiem narzędzi, 669px z pokazanym —
   ale identyczne z drugą metryką w obu przypadkach), więc nie ma tu stałego
   przesunięcia do skorygowania w JS. Zgłoszony efekt ("psuje się w momencie,
   gdy pasek się chowa/pokazuje") to chwilowy artefakt malowania WebKit W
   TRAKCIE animacji toolbara, nie błędna pozycja w spoczynku — a takiego
   pojedynczego malowanego kadru nie da się poprawić przeliczaniem liczb.
   Ten pseudo-element maskuje efekt zamiast go liczyć: gdyby WebKit przez
   klatkę czy dwie źle domalował pozycję paska, odsłoni się ten sam kolor
   tła zamiast strony pod spodem. 160px z zapasem ponad zmierzoną różnicą
   777-669=108px (adres+toolbar razem), żeby starczyło z rezerwą także na
   iPhony z inną wysokością toolbara. */
.m-sticky::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: 100%;
  height: 160px;
  background-color: var(--ds-color-canvas);
  pointer-events: none;
}
.m-sticky.is-visible {
  transform: translateY(0);
  opacity: 1;
  pointer-events: auto;
}
@media (prefers-reduced-motion: reduce) {
  .m-sticky { transition: opacity var(--ds-duration-fast) linear; }
}

/* Grid, nie flex: ta sama płaska lista elementów w DOM na obu breakpointach,
   tylko grid-template-areas się zmienia (patrz media query niżej). Na
   mobile przycisk-słuchawka i CTA zajmują po jednej kolumnie rozciągniętej
   na dwa wiersze — dzięki temu oba są naturalnie wyśrodkowane na wysokości
   obu linijek po lewej, bez dodatkowego wrappera. Padding na --ds-space-3 (12px) — dokładnie wartość
   z DESIGN-SYSTEM.md → sticky-price-bar; przy dwóch krótkich linijkach
   treści pasek się od tego nie rozrasta, a wygląda spójnie z resztą strony. */
.csb-inner {
  display: grid;
  grid-template-columns: 1fr auto auto;
  grid-template-areas:
    "price call cta"
    "label call cta";
  align-items: center;
  column-gap: var(--ds-space-2);
  row-gap: var(--ds-space-1);
  padding-top: var(--ds-space-3);
  /* --safe-bottom (zamrożone przez assets/js/course_stickybar.js) zamiast
     env() na żywo — na Chrome na iOS env(safe-area-inset-bottom) zmienia
     wartość razem z chowaniem/pokazywaniem paska narzędzi, więc bez
     zamrożenia .m-sticky zmieniałby wysokość przy każdym scrollu. Fallback
     na env() zostaje na wypadek wyłączonego JS. --ds-space-5 zamiast -3 pod
     CTA (tylko mobile) — wyraźnie więcej luzu od dołu niż od góry paska. */
  padding-bottom: calc(var(--ds-space-5) + var(--safe-bottom, env(safe-area-inset-bottom)));
  /* Węższa rynna niż domyślne 16px z .container-ms (design-system.css) —
     przy 360px wiersz musi pomieścić naraz pigułkę rabatu (nie może się
     złamać na dwie linijki, bo urosłaby wysokość całego paska),
     przycisk-słuchawkę i CTA. Te 2×4px plus zwężone gapy i padding dwóch
     sąsiadów niżej to dokładnie tyle, ile trzeba, żeby wszystko zostało
     w jednej linijce. Od 1024px rynna wraca do systemowej. */
  padding-inline: var(--ds-space-3);
}

/* Nazwa przedmiotu i linijka dowodu społecznego — schowane na mobile (brak
   miejsca w dwóch linijkach), wracają od 1024px. Dowód ma na mobile własny
   pasek nad wierszem (course_last60mins_views.css), więc nic tu nie ginie.
   Kolor przedmiotu to akcent, nigdy tło całej belki (DESIGN-SYSTEM.md →
   Do's and Don'ts). */
.csb-subject { display: none; }
.csb-proof { display: none; }

/* Zielony tekst (nie pigułka/badge) — cena "przy płatności z góry".
   Kolor bierze wariant -ink (CLAUDE.md reguła 12: żywy --ds-color-success
   zostaje wypełnieniom/kropkom, litery zawsze -ink). justify-self: start,
   bo domyślnie grid rozciąga item na całą kolumnę 1fr. */
.csb-discount-label {
  grid-area: label;
  justify-self: start;
  font-family: var(--ds-font-body);
  font-weight: 600;
  font-size: 13px;
  color: var(--ds-color-success-ink);
}

.csb-price-cluster {
  grid-area: price;
  display: flex;
  align-items: center;
  gap: var(--ds-space-2);
  min-width: 0;
}

/* Ikonka info — kółeczko z hairline'a pod glifem, dokładnie to samo, co
   .cs-promo-info w course_summary.css (na życzenie: "?" ma się czytać jako
   osobny, klikalny element przy cenie, nie jako literka wolno stojąca).
   Widoczne kółko ma 27px, więc hit-area rozciąga niewidoczne ::after do
   ~39px — 44px z reguły #15 nie zmieściłoby się w tym wierszu bez rozbicia
   layoutu (świadomy wyjątek dla ikony drugorzędnej), ale 27px byłoby już za
   mało na kciuk. align-items: center na .csb-price-cluster (nie baseline)
   wyrównuje kółeczko na wysokości przekreślonej ceny, niezależnie od tego,
   jak flex/inline-flex liczyłby jego baseline. */
.csb-info {
  position: relative;
  flex: none;
  width: 15px;
  height: 15px;
  padding: 6px;
  /* Lewy margines na 0, nie na -4px: na mobile kółeczko „?" ma stać dokładnie
     pod lewą krawędzią pigułki rabatu z linijki wyżej. Ujemny margines cofał
     je o te 4px i obie linijki wyglądały na rozjechane. */
  margin: -6px -2px -6px 0;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: none;
  background-color: var(--ds-color-hairline);
  border-radius: 50%;
  color: var(--ds-color-ink-muted);
  font-family: var(--ds-font-body);
  font-size: 11px;
  font-weight: 600;
  line-height: 1;
}
.csb-info::after {
  content: "";
  position: absolute;
  inset: -6px;
}
.csb-info:hover { color: var(--ds-color-ink-muted); }
.csb-info:focus-visible { color: var(--ds-color-ink-muted); box-shadow: var(--ds-shadow-ring-focus); outline: none; }

/* Stara i nowa cena w tym samym rozmiarze (na życzenie — hierarchia i tak
   jest jasna: przekreślenie + wyciszony kolor vs. pogrubiony success). */
.csb-old-price {
  font-family: var(--ds-font-display);
  font-size: 19px;
  line-height: 1;
  color: var(--ds-color-ink-muted);
  font-variant-numeric: tabular-nums lining-nums;
}

.csb-price {
  font-family: var(--ds-font-display);
  font-weight: 600;
  font-size: 19px;
  line-height: 1;
  letter-spacing: -0.01em;
  /* Ta sama korekta, co przy .cs-promo-new w course_summary.css: pełny
     --ds-color-success-ink (#085E41) na tym stopniu i wadze wychodzi na oko
     za ciemno, bliżej czerni niż zieleni. Lżejszy ton, wciąż w rodzinie „ink"
     (żywy --ds-color-success zostaje do wypełnień — CLAUDE.md reguła 12):
     Lc ~74 na bieli, przy progu 60 dla 19px/600. */
  color: #0C8058;
  font-variant-numeric: tabular-nums lining-nums;
}
.csb-price small {
  font-family: var(--ds-font-body);
  font-weight: 400;
  font-size: 14px;
  color: inherit;
  margin-left: 2px;
}

/* Przycisk-słuchawka (tel:) na lewo od CTA — drugorzędna akcja przy CTA, więc
   baza z .btn-ghost (bez obrysu, kontur ikony w kolorze marki), ale z beżowym
   wypełnieniem: sam ghost gubił się na białym pasku obok pełnego, żółtego CTA.
   Beż to canvas-soft, czyli ten sam ton, na którym siadają „oddechowe" sekcje
   strony — pastylka czyta się jako tło, nie jako drugi przycisk do kliknięcia.
   Hover schodzi o pół tonu na hairline zamiast skakać w niebieski tint
   z .btn-ghost. Bootstrap daje .btn jako inline-block, a ikona ma być
   wyśrodkowana w kwadracie, stąd inline-flex. 44px z .btn-ghost.btn-icon
   (design-system.css) zgadza się z wysokością sąsiedniego .btn-sm.btn-solar,
   więc oba stoją w jednej linii. */
.csb-call {
  grid-area: call;
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background-color: var(--ds-color-canvas-soft);
  /* Nadpisuje primary-ink z .btn-ghost — na życzenie ikonka ma być stalowa,
     nie niebieska: niebieski ciągnął wzrok na siebie i konkurował z żółtym
     CTA obok. Ten stopień szarości to dawna wartość {colors.ink-secondary}
     (przyciemniona w v2.0 do #333B4A) — w bieżącej rampie nie ma już swojego
     tokena, więc siedzi lokalnie tutaj. Lc 78 na beżowym tle przycisku i 71
     na hairline'u pod hoverem, przy wymaganych Lc 60 dla elementów
     nietekstowych (DESIGN-SYSTEM.md → Kontrast). */
  color: #4E5768;
}
.csb-call:hover { background-color: var(--ds-color-hairline); color: #4E5768; }
.csb-call svg {
  width: 22px;
  height: 22px;
  display: block;
}

/* Kropka „online" w rogu — ten sam gest co status przy awatarze konsultanta
   w sekcji „Jak wygląda kurs?" (.cs-call-status): pełny --ds-color-success
   jako wypełnienie (nigdy jako litera, CLAUDE.md reguła 12) plus obwódka
   w kolorze paska, żeby kropka odcięła się od beżu przycisku i czytała się
   jak naklejka, a nie jak część ikony. Bez pulsowania — pasek jest na
   ekranie cały czas, więc migający punkt zabierałby uwagę CTA obok. */
.csb-call-status {
  position: absolute;
  top: -2px;
  right: -2px;
  /* 14px razem z obwódką (box-sizing: border-box z Bootstrapa), czyli 10px
     samej zieleni — ta sama proporcja do przycisku 44px, co 12px kropki do
     awatara 38px w .cs-call-status. */
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background-color: var(--ds-color-success);
  border: 2px solid var(--ds-color-canvas);
}

.csb-cta { grid-area: cta; }
/* 16px z .btn-sm ścięte do 14px na mobile — patrz komentarz o rynnie przy
   .csb-inner. Selektor z .btn-sm, żeby wygrać specyficznością z
   .btn-sm.btn-solar w design-system.css; od 1024px wraca systemowe 16px. */
.btn-sm.csb-cta {
  padding-left: 14px;
  padding-right: 14px;
}

/* Rotator trzech komunikatów w linijce dowodu społecznego (.csb-rot/
   .csb-rot-item + animacje csb-rot-in/out). Markup budowany raz w
   sections/course_last60mins_views.php ($clvRotatorHtml). Od trzeciego hosta
   (sections/zapis_form.php, pasek zapisowy) styl przeniesiony do
   assets/css/design-system.css jako współdzielony atom — patrz tam,
   sekcja „Rotator komunikatów dowodu społecznego". Stopień pisma i kolor
   zostają hostowi (.clv-text tu, .csb-proof niżej). */
.csb-rot-clock {
  font-variant-numeric: tabular-nums lining-nums;
  white-space: nowrap;
}

/* Popover Bootstrapa — pierwsze użycie w projekcie; dociąga rozmiar/szerokość
   do skali design systemu (kolor/radius/shadow dziedziczy już z mostu --bs-*
   w design-system.css). Zostaje tu, dopóki drugi konsument nie uzasadni
   przeniesienia do design-system.css (patrz CLAUDE.md → "Klasy CSS"). */
.popover {
  --bs-popover-max-width: 280px;
  --bs-popover-font-size: 13px;
}

/* Treść popovera (assets/js/course_stickybar.js buduje ją z $csbPopoverHtml
   w sections/course_stickybar.php, data-bs-html="true"). Pierwsza część
   (cena zabezpieczona + odliczanie) uwypuklona — ciemniejszy tekst, liczba
   w kolorze success. Metoda liczenia deadline'u ("do najbliższego poniedziałku
   godz. 23:59:59") była tu wcześniej w nawiasie — usunięta na życzenie, bo
   tłumaczyła mechanikę promocji zamiast ją sprzedawać. Druga część (najniższa cena z 30 dni — wymóg prawny)
   musi zostać czytelna, więc zwykły rozmiar `--bs-popover-font-size`, ale
   wyciszona kolorem i odsunięta hairline'em, żeby nie krzyczała. */
.csb-pop-primary {
  margin: 0;
  color: var(--ds-color-ink-secondary);
}
.csb-popover-countdown {
  font-weight: 600;
  color: var(--ds-color-success-ink);
  font-variant-numeric: tabular-nums lining-nums;
  white-space: nowrap;
}
.popover hr {
  margin: var(--ds-space-2) 0;
  border-top: 1px solid var(--ds-color-hairline);
  opacity: 1;
}
.csb-pop-lowest {
  margin: 0;
  color: var(--ds-color-ink-muted);
}

/* Desktop — od 1024px jeden poziomy wiersz; jedyny wyjątek od wyłączania
   sticky bara na desktopie (DESIGN-SYSTEM.md → sticky-price-bar-course).
   Kolumna "." to elastyczny odstęp bez treści — rozpycha grupę przedmiot +
   dowód społeczny (po lewej) i grupę ceny + telefon + CTA (po prawej).
   Etykieta rabatu i licznik "Koniec za…" nie wchodzą tu w ogóle: ich miejsce
   zajmuje linijka dowodu społecznego, przeniesiona z osobnego paska nad
   wierszem (sections/course_last60mins_views.php, tam ukryty od 1024px).
   Rabat wraca poniżej 1024px jako pigułka, odliczanie żyje już tylko
   w popoverze ikonki info. */
@media (min-width: 1024px) {
  .csb-inner {
    grid-template-columns: auto auto 1fr auto auto auto;
    grid-template-areas: "subject proof . price call cta";
    align-items: center;
    column-gap: var(--ds-space-4);
    row-gap: 0;
    padding-top: var(--ds-space-3);
    /* --safe-bottom (zamrożone przez assets/js/course_stickybar.js) zamiast
     env() na żywo — na Chrome na iOS env(safe-area-inset-bottom) zmienia
     wartość razem z chowaniem/pokazywaniem paska narzędzi, więc bez
     zamrożenia .m-sticky zmieniałby wysokość przy każdym scrollu. Fallback
     na env() zostaje na wypadek wyłączonego JS. */
  padding-bottom: calc(var(--ds-space-3) + var(--safe-bottom, env(safe-area-inset-bottom)));
    padding-inline: var(--ds-space-5);
  }

  .btn-sm.csb-cta {
    padding-left: 16px;
    padding-right: 16px;
  }

  .csb-subject {
    grid-area: subject;
    display: inline-flex;
    align-items: center;
    gap: var(--ds-space-2);
    padding-right: var(--ds-space-4);
    border-right: 1px solid var(--ds-color-hairline);
  }
  .csb-subject .subj-dot { width: 8px; height: 8px; flex: none; }
  .csb-subject-label {
    font-family: var(--ds-font-display);
    font-weight: 600;
    font-size: 20px;
    color: var(--subj-deep);
    white-space: nowrap;
  }

  /* Rabat wyłącznie na mobile — na desktopie jego miejsce zajmuje dowód
     społeczny (od 1280px, patrz niżej), a sam rabat i tak widać przy cenie
     (przekreślona kwota + kolor success). */
  .csb-discount-label { display: none; }

  /* Słuchawka podjeżdża do CTA: column-gap wiersza to 16px, a ta para ma
     czytać się jako jedna grupa „skontaktuj się", odsunięta od cen. 8px to
     podłoga odstępu między sąsiadującymi celami dotykowymi (CLAUDE.md
     reguła 15), więc bliżej już nie wolno. Na mobile gap wiersza wynosi
     dokładnie te 8px, więc tam nie ma czego skracać. */
  .csb-call { margin-right: calc(var(--ds-space-2) * -1); }
}

/* Zdanie dowodu społecznego wchodzi w wiersz dopiero od 1280px, czyli na
   progu „Wide" z DESIGN-SYSTEM.md → Breakpointy. Przy 1024px nie ma na nie
   miejsca: nazwa przedmiotu + zdanie + ceny + telefon + CTA potrzebują ~1030px
   samej treści, więc klaster cen dostawał ujemny zapas i łamał się na trzy
   linijki. Do 1279px zdanie zostaje więc tam, gdzie było — we własnym pasku
   nad wierszem (course_last60mins_views.css), który dopiero tutaj znika.

   Stopień i kolor te same, co w tamtym pasku (13px, ink-muted) — świadomie
   cichsze niż nazwa przedmiotu, cena i CTA, bo to tło budujące zaufanie, a nie
   element prowadzący wzrok. Wyróżniona zostaje sama liczba (waga 600 z
   <strong>) — bez podkreślenia .hl-underline, usuniętego z całego .m-sticky. */
@media (min-width: 1280px) {
  .csb-proof {
    grid-area: proof;
    display: block;
    font-family: var(--ds-font-body);
    font-size: var(--ds-text-caption);
    line-height: 1.3;
    color: var(--ds-color-ink);
    white-space: nowrap;
  }
  .csb-proof .csb-rot { justify-items: start; }
}

/* Launcher Intercomu (sections/intercom.php) na tej jednej podstronie — plik
   ładuje się WYŁĄCZNIE z kurs/kurs.php (<link>, patrz nagłówek tego pliku),
   więc reguła nigdzie indziej się nie wykona; nie trzeba żadnego dodatkowego
   selektora/warunku scope'ującego stronę.
   `!important` bije inline `bottom`, który Intercom sam sobie dopisuje z
   `vertical_padding` (patrz sections/intercom.php) — tu wartość jest na
   sztywno, bo na tej jednej podstronie ma być inna niż to, co liczy JS.
   `html.csb-visible`: podniesiony dopiero, gdy pasek faktycznie wjechał
   (po przewinięciu 200px) — bez tego warunku launcher stałby podniesiony
   przez cały czas, także zanim jest co omijać. Klasę przełącza
   course_stickybar.js razem z `.is-visible` na samym pasku (ten sam
   scroll-listener), na <html>, bo launcher Intercomu jest osobnym dzieckiem
   <body>, poza drzewem `.m-sticky`.
   DWA selektory, nie jeden: `.intercom-lightweight-app-launcher` to lekki
   placeholder pokazywany, zanim pełny widget się doładuje — Intercom
   podmienia go po pierwszym otwarciu/zamknięciu na właściwy przycisk
   `.intercom-launcher` (inny węzeł DOM, inna klasa). Bez drugiego selektora
   reguła przestawała działać dokładnie w tym momencie. */
@media (max-width: 1024px) {
  html.csb-visible .intercom-lightweight-app-launcher,
  html.csb-visible .intercom-launcher,
  html.csb-visible .intercom-amph2,
  html.csb-visible .intercom-with-namespace-4wz414 {
    bottom: 130px !important;
  }
}
