/* css/review-card.css
 * ============================================================
 * KARTA OPINII — wygląd wspólny dla dwóch miejsc w serwisie:
 *   • strona /opinie          (opinie.html + css/opinie.css)
 *   • krok 2, checkout        (kadr_step2.html, sekcja „Co mówią nasi klienci")
 * Odpowiednik js/opinie/review-card.js po stronie stylów: ten plik opisuje
 * DOKŁADNIE to, co produkuje renderCard() — nagłówek, ocena, treść, odpowiedź
 * kadr.ai, blok materiałów (zakładki Przed/Renowacja/Animacja) i lightbox zdjęć.
 * Wyniesione z css/opinie.css, gdy karta stała się wspólna — jedno źródło wyglądu,
 * żeby checkout i strona opinii nie rozjechały się przy pierwszej zmianie.
 *
 * CZEGO TU NIE MA (świadomie):
 *   • podsumowanie, sort, filtry, formularz, CTA — to widok listy → css/opinie.css
 *   • blok głosowania „pomocna" — renderuje go WYŁĄCZNIE reviews-list.js → opinie.css
 *   • układ dwukolumnowy karty na checkoucie — to layout strony → kadr_step2.html
 *
 * TOKENY: definiowane na `.op-scope` (klasa opakowania — <main class="op op-scope">
 * na /opinie, sekcja opinii na step2). Strona-host może je nadpisać lokalnie, żeby
 * karta wtopiła się w swoją paletę (tak robi checkout z --op-stroke). To jest API
 * tego komponentu — zmiana koloru NIE wymaga dublowania reguł.
 * ============================================================ */

.op-scope {
  --op-green: var(--color-main-green, #1E5336);
  --op-green-hover: #164428;
  --op-stroke: var(--color-stroke, #DBD1D1);
  --op-white: var(--color-white, #FFFFFF);
  --op-ink: var(--color-black, #111111);
  --op-muted: var(--color-text-secondary, #4A4A4A);
  --op-star-green: #2E7D46; /* zielone kafelki gwiazdek (ocena) — jaśniejsze niż primary */
  --op-badge-bg: #E8F1E8;   /* miękkie zielone tło plakietek (zweryfikowany zakup, % pozytywnych) */
  --op-shadow: 0 1px 3px rgba(17, 17, 17, 0.06), 0 8px 24px rgba(17, 17, 17, 0.05);
  --op-radius: var(--border-radius-lg, 16px);
  --op-press-scale: 0.97; /* skala „wciśnięcia" kontrolek (mikro-interakcja) — jedno źródło, DRY */
}

/* ===== KARTA ===== */
.op-rev { background: var(--op-white); border: 1px solid var(--op-stroke); border-radius: 14px; padding: 18px 20px; }

/* Opakowanie treści (nagłówek + ocena + tekst + ewentualna plakietka). CELOWO bez
   własnych stylów: na stronie /opinie to zwykły blok, więc karta wygląda jak przed
   wydzieleniem. Sens ma dopiero tam, gdzie treść i materiały stoją obok siebie
   (checkout): wtedy to JEDEN element gridu zamiast trzech, więc nie ma czego
   rozpychać do wysokości materiałów, a plakietkę da się docisnąć do dołu kolumny. */


/* Nagłówek karty: nazwa po lewej, data w prawym górnym rogu (space-between). Nazwa
   skraca się wielokropkiem, gdyby była długa — data zawsze zostaje widoczna. Plakietka
   „zweryfikowany zakup" NIE jest w nagłówku (zeszła do rzędu oceny, pod datę).
   Data bywa nieobecna (renderCard({showDate:false}) na checkoucie) — wtedy nazwa
   zostaje sama po lewej, bez pustego miejsca do wypełnienia. */
.op-rev__head { display: flex; align-items: baseline; justify-content: space-between; gap: 10px; margin-bottom: 6px; }
.op-rev__name {
  font-weight: 600; color: #333; min-width: 0;   /* lżejszy bold + jaśniejsza czerń — spokojniejszy nagłówek karty */
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}

/* Plakietka „zweryfikowany zakup" — sam ptaszek + tekst (mniejsza czcionka), w zieleni
   marki. Żyje w rzędzie oceny (.op-rev__sub), dosunięta do prawej (margin-left:auto) →
   wizualnie pod datą z nagłówka. Gdy zabraknie miejsca obok gwiazdek, ŁAMIE SIĘ TEKST na
   dwie linie (flex:0 1 auto + min-width:0), a nie cała plakietka do nowej linii (rząd ma
   flex-wrap:nowrap). text-align:right → treść trzyma się prawej krawędzi (pod datą).
   Ptaszek jest INLINE w potoku tekstu (NIE osobny element flex) — dzięki temu przy
   zawijaniu skleja się z pierwszym słowem („✓ Zweryfikowany" / „zakup") i nie osamotnia
   się z boku (osobny element flex + text-align:right dosuwał tekst do prawej, a ikonę
   zostawiał samą po lewej). W HTML nie ma spacji między <svg> a tekstem, więc łamanie nie
   wypada po ikonie; overflow-wrap:anywhere to bezpiecznik dopiero na skrajnie wąskich ekranach. */
.op-vbadge {
  flex: 0 1 auto; min-width: 0; margin-left: auto;
  color: var(--op-green); text-align: right; overflow-wrap: anywhere;
  font-size: 0.72rem; font-weight: 600; line-height: 1.3;
}
/* Ptaszek inline: lekko obniżony (vertical-align), by optycznie leżał na wysokości tekstu;
   margines robi odstęp ikona→tekst (dawniej gap flexa). */
.op-vbadge svg { vertical-align: -0.2em; margin-right: 3px; }

/* PO regule bazowej, nie przed — modyfikator ma tę samą specyficzność (jedna klasa),
   więc o wyniku decyduje KOLEJNOŚĆ. Odwrotnie ustawiony przegrywał z .op-vbadge
   i plakietka na checkoucie trzymała się prawej (text-align:right z bazy) zamiast
   lewej. Bazowe reguły zawsze wyżej, warianty niżej.
/* Plakietka POD treścią opinii, do lewej (wariant checkoutu) — zdejmuje dosunięcie
   do prawej z reguły bazowej. Wariant mówi TYLKO o miejscu w karcie; rozłożeniem
   kolumny w pionie steruje strona-host (checkout centruje treść względem
   materiałów), więc świadomie nie ma tu margin-top:auto — dociskanie do dołu
   zjadłoby to centrowanie. */
.op-vbadge--bottom {
  /* display:block, bo plakietka bazowa jest inline (<span>), a na elemencie inline
     padding-top nie odsuwa treści — dopiero blok respektuje odstęp. */
  display: block;
  margin-left: 0;
  padding-top: 12px;
  text-align: left;
}

/* Sub-rząd: gwiazdki + liczbowa ocena z lewej, plakietka „zweryfikowany zakup" z prawej
   (pod datą). flex-wrap → na bardzo wąskiej karcie plakietka spada pod gwiazdki (dalej
   do prawej), zamiast ściskać ocenę. */
.op-rev__sub { display: flex; align-items: center; flex-wrap: nowrap; gap: 8px; row-gap: 6px; margin-top: 0; }
.op-rev__stars { display: inline-flex; gap: 3px; flex: 0 0 auto; }
/* Numer oceny obok gwiazdek (jak na wzorcu) — ten sam zielony co primary. */
.op-rev__num { font-weight: 700; color: var(--op-green); font-size: 0.95rem; }
/* Data w prawym górnym rogu nagłówka (nie zawija się). */
.op-rev__date { color: var(--op-muted); font-size: 0.88rem; white-space: nowrap; flex: 0 0 auto; }

/* Kafelek pojedynczej gwiazdki (.op-star-box, .is-empty, .is-partial + nakładka
   .op-star-box__fill) — css/stars.css. Wyniesiony stąd, gdy ocena wyszła poza kartę
   opinii: pokazuje ją też widget na landingu (index.html), a ten nie ma po co ładować
   całego CSS karty. KAŻDA strona z oceną musi linkować css/stars.css PRZED tym plikiem.
   Token --op-star-green nadal definiuje `.op-scope` niżej — stars.css tylko go czyta
   (z fallbackiem na tę samą wartość, żeby działał także bez `.op-scope`). */

.op-rev__text { margin: 6px 0 0; line-height: 1.55; color: var(--op-ink); white-space: pre-wrap; font-size: 0.95rem; }

/* Odpowiedź kadr.ai pod opinią (publiczna). Subtelne zielone tło + akcent po
   lewej, mała „plakietka" nadawcy — spójne z wzorcem mobile/desktop. */
.op-rev__reply { margin-top: 12px; padding: 12px 14px; background: #F1F5EC; border-left: 3px solid var(--op-green); border-radius: 0 8px 8px 0; }
.op-rev__reply-head { display: flex; align-items: center; gap: 8px; margin-bottom: 5px; }
/* Znaczek nadawcy odpowiedzi — favicon kadr.ai w białym ZAOKRĄGLONYM KWADRACIE (nie
   kole). Powód: znak „k." wypełnia ~99% szer. swojego canvasu, więc w KOLE jego rogi
   wypadały poza obwód i były przycinane, a duży padding potrzebny do ich schowania robił
   znak malutki („przykryty marginesem"). Zaokrąglony kwadrat (border-radius 8px) nie
   przycina rogów → znak może być większy (padding tylko 4px, znak ~18px) i w całości
   widoczny. Przezroczyste tło favicona pozwala prześwitywać białemu tłu kafelka. */
.op-rev__reply-mark {
  width: 28px; height: 28px; box-sizing: border-box; flex: 0 0 auto;
  padding: 4px; border: 1px solid var(--op-stroke); border-radius: 8px;
  background: var(--op-white); object-fit: contain; display: block;
}
.op-rev__reply-name { font-weight: 700; color: var(--op-green); font-size: 0.9rem; }
.op-rev__reply-date { color: var(--op-muted); font-size: 0.8rem; margin-left: auto; white-space: nowrap; }
.op-rev__reply-text { margin: 0; line-height: 1.55; color: var(--op-ink); white-space: pre-wrap; font-size: 0.95rem; }

/* ---- Podgląd materiałów przy opinii (Przed / Renowacja / Animacja) ----
   Renderowany WYŁĄCZNIE z pól, które poda serwer (zgoda + istnienie plików
   decydują po stronie backendu — patrz review_service._serialize_public). Frontend
   nic nie zmyśla: brak URL-i = brak zakładki, brak wszystkich = brak bloku.
   Zdjęcia otwierają lightbox (klik), animacja gra inline (wyciszona, jedna na
   raz) i rozwija się na pełny ekran z dźwiękiem.
   KLUCZOWE: `.op-rev__stage` ma STAŁY kadr poziomy (aspect-ratio 16/9, spójnie
   z podglądem w step1 i pickerze animacji) — dzięki temu przełączanie zakładek
   NIE skacze po wysokości. Materiał jest w nim pokazany ZAWSZE W CAŁOŚCI
   (object-fit: contain), a wolne miejsce po bokach (lub nad/pod) wypełnia ROZMYTA
   kopia tego samego materiału — wzorzec YouTube Shorts.
   Dlaczego nigdy `cover`: kadrowanie przycinało zdjęcia inne niż 16:9 — przy
   fotografii 4:3 znikała jedna czwarta wysokości, a to są zdjęcia rodzinne, gdzie
   ucięta głowa albo brzeg pamiątki to realna strata. Pełny kadr kosztem rozmytych
   pasów jest zawsze właściwym kompromisem dla TEJ treści. */
/* Przełącznik (zakładki) + kadr podglądu to JEDEN element o wspólnej szerokości:
   oba żyją w .op-rev__media (zakładki nad kadrem 16:9), więc cap szerokości na tym
   kontenerze obejmuje jedno i drugie. Desktop: ~1/2 szerokości karty, dobite do
   lewej (blok bez auto-marginesów). Na mobile cap znika (media query niżej,
   .op-rev__media → max-width:none) i element schodzi do 100%.
   UWAGA: układ dwukolumnowy na checkoucie zdejmuje ten cap własną regułą — media
   wypełnia tam swoją kolumnę gridu (patrz kadr_step2.html). */
.op-rev__media { margin-top: 12px; max-width: 50%; }

/* Pasek zakładek — segmentowany przełącznik (jak na wzorcu): zaokrąglony tor,
   aktywna zakładka to wypełniony zielony pill. Odklejony od kadru (margines pod
   spodem), więc kadr ma własne, pełne zaokrąglenia. */
.op-rev__tabs {
  display: flex; gap: 4px; padding: 4px; margin-bottom: 10px;
  background: #EFEDE8; border-radius: 999px;
}
.op-rev__tab {
  flex: 1; min-width: 0;   /* min-width:0 — pozwól flex-itemowi zejść poniżej treści, żeby
                              pasek zakładek nie narzucał karcie szerokiego min-content */
  padding: 8px 10px; border: 0; background: transparent; cursor: pointer;
  font-family: inherit; font-size: 0.86rem; font-weight: 600; color: var(--op-muted);
  border-radius: 999px; white-space: nowrap;   /* etykieta w jednej linii (segment się nie zawija) */
  /* BEZPIECZNIK: `flex:1` + `min-width:0` pozwalają segmentowi zejść PONIŻEJ szerokości
     własnej etykiety — bez tej pary etykiety nie zawijały się (nowrap), tylko wylewały
     poza segment i NACHODZIŁY na sąsiada (widoczne w wąskiej kolumnie materiałów na
     checkoucie). Przycięcie z wielokropkiem zamienia kolizję w czytelne „Renowac…".
     Na szerokich kadrach nie robi nic — nie ma czego przycinać. */
  overflow: hidden; text-overflow: ellipsis;
  display: inline-flex; align-items: center; justify-content: center;
  transition: color .15s ease, background-color .15s ease;
}
.op-rev__tab:hover { color: var(--op-ink); }
.op-rev__tab.is-active { background: var(--op-green); color: #fff; }
.op-rev__tab:focus-visible { outline: 3px solid var(--op-green); outline-offset: 2px; }

/* Scena — jeden stały kadr poziomy 16:9. Ciemne tło to fallback zanim materiał
   (lub rozmyte tło) się doładuje. */
.op-rev__stage {
  position: relative; width: 100%; aspect-ratio: 16 / 9; overflow: hidden;
  background: #141414; border: 1px solid var(--op-stroke); border-radius: 10px;
}

/* Zakładki-plansze: tylko aktywna widoczna, wszystkie w tym samym kadrze. */
.op-rev__pane { position: absolute; inset: 0; display: none; }
.op-rev__pane.is-active { display: block; }

/* Rozmyte tło kadru — rozmyta kopia TEGO SAMEGO materiału (zdjęcie: miniatura,
   animacja: poster). Wypełnia paski po bokach, gdy materiał jest pionowy/kwadratowy.
   Widoczna ZAWSZE: materiał jest skalowany w całości (contain), więc przy każdych
   proporcjach innych niż dokładnie 16:9 zostaje wolne miejsce do wypełnienia.
   (Przy dokładnie 16:9 materiał zakrywa tło w 100% i bluru i tak nie widać —
   dlatego nie ma po co wyliczać proporcji i przełączać klas.)
   inset ujemny + brightness < 1: przykrywa rozmyciem krawędź i lekko ściemnia,
   żeby materiał na wierzchu był czytelny (wzorzec ze step1/step3). */
.op-rev__blur {
  position: absolute; inset: 0; z-index: 0; pointer-events: none;
  background-size: cover; background-position: center;
  /* PRZYCZYNA starego problemu z „twardymi pasami": przy blur(20px) miękki falloff
     filtra ma ~20px, a inset:-12px dawał tylko 12px zapasu → ~8px ciemnej/przezroczystej
     krawędzi wychodziło w kadr (widoczne jako pasy). scale(1.18) skaluje pokryte
     (cover) tło ~18% poza każdą krawędź, więc cały falloff dzieje się POZA ramką
     (stage ma overflow:hidden → przycina). Efekt: rozmyte tło wypełnia całą ramkę. */
  transform: scale(1.18);
  filter: blur(24px) brightness(0.72);
}

/* Materiał ZAWSZE w całości — nic nie jest przycinane, niezależnie od proporcji
   i szerokości ekranu. Puste miejsce zakrywa rozmyta warstwa wyżej. */
.op-rev__img, .op-rev__video {
  position: absolute; inset: 0; z-index: 1;
  display: block; width: 100%; height: 100%; object-fit: contain; background: transparent;
}
.op-rev__img { cursor: zoom-in; }
.op-rev__img:focus-visible { outline: 3px solid var(--op-green); outline-offset: -3px; }

/* Etykieta rogu przy pojedynczym materiale (bez paska zakładek). */
.op-rev__solo-label {
  position: absolute; top: 8px; left: 8px; z-index: 2; pointer-events: none;
  padding: 3px 9px; border-radius: 999px; font-size: 0.72rem; font-weight: 600;
  color: #fff; background: rgba(0, 0, 0, 0.55);
}

/* Animacja: wrapper NAD rozmytym tłem (z-index 1) + nałożone przyciski
   (play na środku, pełny ekran w rogu — te mają wyższy z-index niżej). */
.op-rev__vidwrap { position: absolute; inset: 0; z-index: 1; width: 100%; height: 100%; }
.op-rev__video { cursor: pointer; }
.op-rev__play {
  position: absolute; top: 50%; left: 50%; transform: translate(-50%, -50%); z-index: 2;
  width: 56px; height: 56px; border: 0; border-radius: 999px; cursor: pointer;
  display: grid; place-items: center; color: var(--op-green); background: rgba(255, 255, 255, 0.92);
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.35); padding-left: 3px; /* optyczne wyśrodkowanie trójkąta */
  transition: opacity .15s ease, transform .12s ease;
}
.op-rev__play:hover { transform: translate(-50%, -50%) scale(1.05); }
.op-rev__play:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }
/* Gdy animacja gra — chowamy „play" (wraca, gdy autoplay zablokowany / reduced-motion). */
.op-rev__media.is-playing .op-rev__play { opacity: 0; pointer-events: none; }
.op-rev__expand {
  position: absolute; top: 8px; right: 8px; z-index: 2;
  width: 36px; height: 36px; border: 0; border-radius: 8px; cursor: pointer;
  display: grid; place-items: center; color: #fff; background: rgba(0, 0, 0, 0.55);
  transition: background .12s ease;
}
.op-rev__expand:hover { background: rgba(0, 0, 0, 0.78); }
.op-rev__expand:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }

/* Linia zgody pod kadrem. */
.op-rev__media-consent { display: inline-flex; align-items: center; gap: 6px; margin: 8px 0 0; font-size: 0.8rem; color: var(--op-green); }
.op-rev__media-consent svg { flex: 0 0 auto; }

/* ---- Lightbox zdjęć przed/po (js/opinie/lightbox_review.js) ----
   Pełnoekranowy podgląd z nawigacją przed↔po. Przyciski nałożone na krawędzie
   sceny (nie w flow) — nie rozpychają layoutu na wąskich ekranach.
   Overlay jest doklejany do <body> (poza .op-scope), więc CELOWO nie używa
   tokenów --op-* — kolory ma zaszyte (czerń/biel), niezależnie od palety hosta. */
.op-lb { position: fixed; inset: 0; z-index: 1000; display: flex; }
.op-lb[hidden] { display: none; }
.op-lb__backdrop { position: absolute; inset: 0; background: rgba(17, 17, 17, 0.86); }
.op-lb__stage { position: relative; margin: auto; display: flex; max-width: 96vw; max-height: 92vh; }
.op-lb__figure { margin: auto; display: flex; flex-direction: column; align-items: center; max-width: 92vw; max-height: 90vh; }
.op-lb__img {
  max-width: 92vw; max-height: 82vh; object-fit: contain; border-radius: 8px;
  background: #111; box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
}
.op-lb__cap { color: #fff; font-weight: 600; margin-top: 10px; font-size: 0.95rem; }
.op-lb__btn {
  position: absolute; border: 0; cursor: pointer; color: #fff; background: rgba(255, 255, 255, 0.16);
  width: 44px; height: 44px; border-radius: 999px; font-size: 1.6rem; line-height: 1;
  display: grid; place-items: center;
}
.op-lb__btn:hover { background: rgba(255, 255, 255, 0.28); }
.op-lb__btn:focus-visible { outline: 3px solid #fff; outline-offset: 2px; }
.op-lb__prev { left: 6px; top: 50%; transform: translateY(-50%); }
.op-lb__next { right: 6px; top: 50%; transform: translateY(-50%); }
.op-lb__close { top: 4px; right: 4px; width: 40px; height: 40px; font-size: 1.2rem; }

/* ===== MOBILE (≤640px) — reguły dotyczące SAMEJ karty ===== */
@media (max-width: 640px) {
  /* Nagłówek karty na wąskim ekranie: nick + data (align-items:flex-start → data obok
     pierwszego wiersza nicku). Nick może się ZAWINĄĆ (white-space:normal) zamiast znikać
     przez ellipsis. Plakietka „zweryfikowany zakup" jest w rzędzie oceny (.op-rev__sub),
     więc nie ściska już nicku w nagłówku (naprawiony bug znikającego nicku). */
  .op-rev__head { align-items: flex-start; }
  .op-rev__name { white-space: normal; overflow: visible; overflow-wrap: anywhere; }
  /* Gdy plakietka „zweryfikowany zakup" łamie się na 2 linie (wąska karta), wyrównaj
     rząd oceny do góry — gwiazdki równo z pierwszą linią plakietki (nie zawieszone w pół). */
  .op-rev__sub { align-items: flex-start; }
  /* Materiały: cap ~1/2 szerokości znika — przełącznik + kadr schodzą do 100% karty. */
  .op-rev__media { max-width: none; }
  /* Pasek zakładek na wąskim ekranie: trzy segmenty (Przed/Renowacja/Animacja — same
     etykiety, bez ikon) muszą zmieścić się w ~250px karty. Zmniejszamy font/padding,
     żeby najdłuższa etykieta („Renowacja") mieściła się w segmencie bez ucinania na
     typowych telefonach (≥360px). Etykieta zostaje w jednej linii (white-space:nowrap
     z reguły bazowej). */
  .op-rev__tab { padding: 7px 4px; font-size: 0.76rem; }
  /* Lightbox — mniejsze przyciski, obraz szerzej. */
  .op-lb__btn { width: 40px; height: 40px; }
  .op-lb__img { max-width: 94vw; }
}
