.ds-opinions-recent {
    display: none;
}
@media screen and (min-width:1024px){
    .ds-opinions-recent{
        display: block;
        background-color: #fff;
        position: fixed;
        z-index: 100;
        right: 2rem;
        bottom: 2rem;
        padding: 0.5rem 2rem;
        -webkit-box-shadow: 0 8px 10px rgba(214, 214, 214, 0.8);
        box-shadow: 0 8px 10px rgba(214, 214, 214, 0.8);
        min-width: 15rem;
    }
}

.ds-opinions-recent .visible-panel {
    background: #fff;
    border-radius: 4px;
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-orient: vertical;
    -webkit-box-direction: normal;
    -ms-flex-direction: column;
    flex-direction: column;
    height: 28.4em;
    -webkit-box-pack: end;
    -ms-flex-pack: end;
    justify-content: flex-end;
    padding: 0.8em;
    position: fixed;
    -webkit-transition: -webkit-transform .6s;
    transition: -webkit-transform .6s;
    transition: transform .6s;
    transition: transform .6s, -webkit-transform .6s;
    width: 8.2em;
    z-index: 2147483646;
    -webkit-box-shadow: 0 8px 10px rgba(214, 214, 214, 0.8);
    box-shadow: 0 8px 10px rgba(214, 214, 214, 0.8);
    right: 0;
}

@media screen and (min-width:1024px){
    .ds-opinions-recent .visible-panel{
        top: 45%;
        transform: translateY(-45%);
    }
}

.ds-opinions-recent .visible-panel .panel__top {
    -webkit-transform: rotate(-90deg) translate(-2.2em, 3.2em);
    transform: rotate(-90deg) translate(-2.2em, 3.2em);
}

.ds-opinions-recent__item {
    margin: 2rem 0;
}

.ds-opinions-recent__info {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    -webkit-box-pack: justify;
    -ms-flex-pack: justify;
    justify-content: space-between;
    margin-bottom: 0.4em;
}

.ds-opinions-recent__rate {
    margin-bottom: 0;
}

.ds-opinions-recent__date {
    font-size: 12px;
    color: #ddd;
    margin-right: 0.5rem;
    margin-bottom: 0;
}

.ds-opinions-store {
    -webkit-columns: auto 1;
    columns: auto 1;
}
@media screen and (min-width:1024px){
    .ds-opinions-store{
        columns: auto 4;
    }
}

.ds-opinions-store p {
    margin: 0;
}

.ds-opinions-store .ds-opinions__single {
    -webkit-box-shadow: 0 8px 10px rgba(214, 214, 214, 0.8);
    box-shadow: 0 8px 10px rgba(214, 214, 214, 0.8);
    margin-bottom: 1.5rem;
    padding-top: 0.4rem;

    /* Układ opinii to CSS multi-column (`columns: auto 4` wyżej), a w nim
       przeglądarka domyślnie MOŻE przełamać element w poprzek kolumn: początek
       opinii zostaje w jednej, reszta ląduje w następnej i karty wchodzą jedna
       na drugą. `break-inside: avoid` trzyma kartę w całości.
       `display: inline-block` + `width: 100%` to utrwalony sposób na to samo
       w starszych silnikach, które sam `break-inside` ignorują. */
    -webkit-column-break-inside: avoid;
    page-break-inside: avoid;
    break-inside: avoid;
    display: inline-block;
    width: 100%;
}

.ds-opinions-store .ds-opinions__header, .ds-opinions-store .ds-opinions__content, .ds-opinions-store .ds-opinions__footer {
    padding: 1rem;
}

.ds-opinions-store .ds-opinions__footer {
    text-align: center;
    padding: 2rem 0 1.5rem;
}

.ds-opinions-store .ds-opinions__header {
    -webkit-box-shadow: 0 2px 10px rgba(214, 214, 214, 0.8);
    box-shadow: 0 2px 10px rgba(214, 214, 214, 0.8);
    padding: 0.8rem 1.6rem;
}

.ds-opinions-store .ds-opinions__sectionTop {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    -webkit-box-pack: justify;
    -ms-flex-pack: justify;
    justify-content: space-between;
}

.ds-opinions-store .ds-opinions__sectionTop .opinion-date {
    display: none;
}

.ds-opinions-store .ds-opinions__sectionTop .opinion-time {
    font-size: 13px;
}

.ds-opinions-store .ds-opinions__sectionTop .icon-verified {
    padding: 10px;
}

.ds-opinions-store .ds-opinions__sectionTop .icon-verified svg {
    height: 15px;
}

.ds-opinions-store .ds-opinions__content .opinion-context {
    font-size: 20px;
}

.ds-opinions-store .ds-opinions__sectionBottom {
    display: -webkit-box;
    display: -ms-flexbox;
    display: flex;
    -webkit-box-align: center;
    -ms-flex-align: center;
    align-items: center;
    -webkit-box-pack: justify;
    -ms-flex-pack: justify;
    justify-content: space-between;
}

.ds-opinions-store .ds-opinions__sectionBottom .rate-icon svg {
    height: 20px;
    width: auto;
}

.shop-identify .rate-icon{
    height: 20px;
    width: auto;
}
/* ===== ds_opinions v2 — modal po zamówieniu, lightbox, zdjęcia opinii ===== */
.dsop-modal-overlay{position:fixed;inset:0;background:rgba(0,0,0,.55);display:flex;align-items:center;justify-content:center;z-index:99999;padding:16px}
.dsop-modal{background:#fff;border-radius:10px;max-width:460px;width:100%;padding:24px 24px 20px;position:relative;box-shadow:0 20px 60px rgba(0,0,0,.3);text-align:center}
.dsop-modal h3{margin:0 0 14px;font-size:1.15rem}
.dsop-modal-close{position:absolute;top:10px;right:14px;background:none;border:0;font-size:26px;line-height:1;cursor:pointer;color:#888}
.dsop-stars{font-size:34px;letter-spacing:4px;margin:6px 0 14px;cursor:pointer;color:#ccc}
.dsop-star{transition:color .1s}
.dsop-star.on{color:#f5a623}
.dsop-modal textarea{width:100%;border:1px solid #ddd;border-radius:6px;padding:10px;font-size:.95rem;resize:vertical}
.dsop-modal-error{color:#c0392b;font-size:.85rem;margin:8px 0 0}
.dsop-modal-actions{margin-top:16px;display:flex;gap:10px;justify-content:center;align-items:center;flex-wrap:wrap}
.dsop-modal-thanks{color:#2e7d32;font-weight:600;margin-top:10px}
.opinion-photos{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px}
.opinion-photo{display:block;width:72px;height:72px;border-radius:6px;overflow:hidden;border:1px solid #eee}
.opinion-photo img{width:100%;height:100%;object-fit:cover}
.ds-opinion-photos{margin-top:12px}
.dsop-lightbox{position:fixed;inset:0;background:rgba(0,0,0,.85);display:none;align-items:center;justify-content:center;z-index:100000;cursor:zoom-out}
.dsop-lightbox img{max-width:92vw;max-height:92vh;border-radius:6px}
.dsop-lightbox-close{position:absolute;top:16px;right:24px;color:#fff;font-size:40px;line-height:1;cursor:pointer}

/* ============================================================================
   Gwiazdki oceny — style, których modułowi brakowało.

   Szablony rysują ocenę jako <svg class="rating__star"><use href="#star">.
   Symbol ma viewBox, ale sam <svg> nie dostaje wymiarów, a SVG bez width/height
   przyjmuje domyślne 300×150 px. Do tej pory ratował to arkusz motywu classic,
   pod który moduł powstawał; hummingbird takich reguł nie ma i nie musi mieć —
   to markup modułu, więc i style należą do modułu. Bez nich sekcja opinii
   rozjeżdża się na całą stronę (gwiazdki wielkości nagłówka, opinie wchodzące
   jedna na drugą).

   Klasa `rating__star` jest specyficzna dla ds_opinions, więc stylujemy ją
   wprost; ogólniejsze `.rating` i `.rating-element` domykamy tylko wewnątrz
   kontenerów modułu, żeby nie wejść w drogę motywowi.
   ========================================================================== */

.rating__star {
  display: block;
  width: 18px;
  height: 18px;
  fill: #d8d8d8;
  transition: fill .12s ease;
}

.ds-product-opinion-mini .rating,
.ds-opinions .rating,
.ds-opinions-store .rating,
.ds-opinions-product-form .rating,
.ds-opinions-product-summary-wrapper .rating,
.product-opinions-container .rating {
  display: inline-flex;
  align-items: center;
  gap: 2px;
  line-height: 1;
}

.rating > a,
.rating__button {
  display: inline-flex;
  line-height: 0;
  text-decoration: none;
}

.rating > a.full .rating__star,
.rating__button.full .rating__star {
  fill: #fab72d;
}

/* Połowa gwiazdki: szary kształt pod spodem, a na wierzchu maska przycięta
   do lewej połowy. Maska zamiast przezroczystości, bo „wyblakła gwiazdka"
   czyta się jako inna ocena, a nie jako połowa. */
.rating > a.half,
.rating__button.half {
  position: relative;
}

.rating > a.half .rating__star,
.rating__button.half .rating__star {
  fill: #d8d8d8;
}

.rating > a.half::after,
.rating__button.half::after {
  content: "";
  position: absolute;
  top: 50%;
  left: 0;
  width: 9px;
  height: 18px;
  transform: translateY(-50%);
  background-color: #fab72d;
  -webkit-mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 98 92'><path d='M49 73.5L22.55 87.406l5.05-29.453-21.398-20.86 29.573-4.296L49 6l13.225 26.797 29.573 4.297-21.4 20.86 5.052 29.452z'/></svg>") no-repeat left center;
  mask: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 98 92'><path d='M49 73.5L22.55 87.406l5.05-29.453-21.398-20.86 29.573-4.296L49 6l13.225 26.797 29.573 4.297-21.4 20.86 5.052 29.452z'/></svg>") no-repeat left center;
  -webkit-mask-size: 18px 18px;
  mask-size: 18px 18px;
}

/* Ocena nieklikalna (podsumowanie) nie ma udawać przycisku. */
.rating.disabled > a,
.rating > a.disabled {
  pointer-events: none;
  cursor: default;
}

/* Wiersz „gwiazdki + liczba" i jego wariant pionowy z podpisem pod spodem. */
.rating-element {
  display: flex;
  align-items: center;
  gap: 8px;
}

.rating-element.vertical {
  flex-direction: column;
  align-items: center;
  gap: 2px;
}

.ds-product-opinion-mini {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 6px 0 10px;
}

.average-grade-label {
  font-weight: 600;
  line-height: 1;
}

.average-grade-amount {
  margin-left: 4px;
  font-weight: 400;
  color: #767676;
}

.average-grade-decs {
  font-size: .875rem;
  color: #767676;
}

/* Formularz oceny: gwiazdki są tu klikalne i większe, ale nadal skończonego rozmiaru. */
.ds-opinions-product-form .rating__star,
.ds-opinions-store .rating__star {
  width: 26px;
  height: 26px;
}

.ds-opinions-product-form .rating__button,
.ds-opinions-store .rating__button {
  cursor: pointer;
}

/* Karta opinii w układzie kolumnowym ma ~230 px szerokości, a w środku siedzi
   bootstrapowa siatka `.row > .col-md-6`: autor po lewej, ocena po prawej.
   Przy takiej szerokości połowa kolumny to ~115 px, podczas gdy sam blok oceny
   (5 gwiazdek + padding 1,6rem z każdej strony) potrzebuje ponad 150 px —
   dlatego ocena wychodziła poza kartę i nachodziła na dane autora.
   Wewnątrz listy opinii układamy więc kartę pionowo, zamiast walczyć
   z siatką na szerokości, której tam nie ma. */
.ds-opinions-store .ds-opinions__content .row {
    margin-left: 0;
    margin-right: 0;
}

.ds-opinions-store .ds-opinions__content [class*="col-"] {
    -ms-flex: 0 0 100%;
    flex: 0 0 100%;
    max-width: 100%;
    padding-left: 0;
    padding-right: 0;
}

.ds-opinions-store .ds-opinions__header {
    -webkit-box-shadow: none;
    box-shadow: none;
    padding: 0.4rem 0 0.2rem;
}

.ds-opinions-store .ds-opinions__sectionBottom .rating-element {
    justify-content: flex-start;
}

/* ══════════════════════════════════════════════════════════════════════
   DN-4 pkt 3-4 — lista opinii na karcie produktu i strona /opinions
   ══════════════════════════════════════════════════════════════════════

   Zgłoszenie: oba widoki „nieostylowane". Po obejrzeniu na żywo (ps9,
   hummingbird) problemy były trzy i żaden nie był problemem cache'u:

   1. Układ `columns: auto 4` (CSS multi-column) układa karty PIONOWO w kolumnach
      i wypełnia kolumnę do końca, zanim przejdzie do następnej. Przy nierównych
      opiniach (jedna długa, reszta krótkie) daje to wielką pustkę po prawej,
      a karta potrafi zacząć się w połowie wysokości sąsiedniej kolumny. Zamiast
      tego siatka — karty idą rzędami, kolejność czytania zgadza się z kolejnością
      w kodzie, a długa opinia rozpycha tylko swój rząd.
   2. Karta nie miała tła ani obrysu — sam cień. Na białym tle motywu wyglądała
      jak luźny tekst, nie jak karta.
   3. Kontener nie miał żadnego wcięcia, więc karty przyklejały się do krawędzi
      (cień był ucinany).

   Style należą do MODUŁU, nie do motywu — moduł ma wyglądać tak samo w classic
   i w hummingbird (ta sama zasada co przy Z-027).
   ---------------------------------------------------------------------- */
.ds-opinions-store {
    /* Nadpisuje `columns: auto 1` / `columns: auto 4` wyżej. `column-count: initial`
       jest konieczne — sama zmiana `display` NIE wyłącza multi-column. */
    -webkit-columns: initial;
    columns: initial;
    -webkit-column-count: initial;
    column-count: initial;

    display: grid;
    grid-template-columns: 1fr;
    gap: 1.25rem;
    align-items: start;
    padding: 2px;              /* żeby cień karty nie był ucinany przez kontener */
}

@media screen and (min-width: 768px) {
    .ds-opinions-store {
        /* auto-fill, NIE auto-fit: przy dwóch opiniach auto-fit rozciągnąłby je
           na całą szerokość i karta wyglądałaby inaczej niż przy sześciu. */
        grid-template-columns: repeat(auto-fill, minmax(260px, 1fr));
    }
}

.ds-opinions-store .ds-opinions__single {
    /* Karta w siatce: pełna wysokość rzędu nie jest potrzebna (align-items: start),
       ale karta ma wyglądać jak karta. */
    display: block;
    width: auto;
    margin-bottom: 0;
    padding: 0.9rem 1.1rem 1rem;
    background: #fff;
    border: 1px solid #e6e8eb;
    border-radius: 6px;
    box-shadow: 0 2px 6px rgba(0, 0, 0, .05);
    overflow-wrap: break-word;
    word-wrap: break-word;
}

/* Wewnętrzne bloki miały własne `padding: 1rem` z czasów układu bez karty —
   w karcie z paddingiem dublowało to wcięcia. */
.ds-opinions-store .ds-opinions__single .ds-opinions__header,
.ds-opinions-store .ds-opinions__single .ds-opinions__content {
    padding: 0;
    box-shadow: none;
}

.ds-opinions-store .ds-opinions__single .ds-opinions__content {
    margin-top: 0.5rem;
}

.ds-opinions-store .opinion-author,
.ds-opinions-store .opinion-date {
    font-size: 0.85rem;
    color: #6b7280;
    line-height: 1.5;
}

.ds-opinions-store .opinion-context {
    line-height: 1.55;
}

/* ── Zwijanie listy na karcie produktu ──────────────────────────────────
   Przycisk „Więcej opinii" był martwy: szablon renderował klasy
   `opinion-to-collapse`, `label-more` i `label-less`, ale nie istniała ani
   linia JS, ani reguła CSS dla żadnej z nich. Wszystkie opinie były widoczne
   od razu, a na przycisku stały dwie etykiety naraz („Mniej opinii Więcej
   opinii (2)"). Stan trzyma teraz klasa `ds-opinions--rozwiniete` na liście.
   ---------------------------------------------------------------------- */
.productopinions .opinion-to-collapse,
.product-opinions-container .opinion-to-collapse {
    display: none;
}

.productopinions.ds-opinions--rozwiniete .opinion-to-collapse,
.product-opinions-container.ds-opinions--rozwiniete .opinion-to-collapse {
    display: block;
}

.moreless-opinions .label-less {
    display: none;
}

.ds-opinions--rozwiniete .moreless-opinions .label-less {
    display: inline;
}

.ds-opinions--rozwiniete .moreless-opinions .label-more {
    display: none;
}

.product-opinions-footer {
    margin-top: 1.25rem;
    text-align: center;
}

/* ── Strona /module/ds_opinions/opinions ────────────────────────────────
   Nagłówek i pasek sortowania nie miały żadnych reguł: przyciski sortowania
   stały w jednej linii bez odstępów i zawijały się byle jak na wąskim ekranie.
   ---------------------------------------------------------------------- */
.opinions-heading {
    margin-bottom: 1rem;
}

.opinions-list-sort {
    display: flex;
    flex-wrap: wrap;
    gap: 0.5rem;
    align-items: center;
    margin-bottom: 1.5rem;
}

.opinions-list-sort .btn {
    flex: 0 0 auto;
}

.shop-info,
.shop-opinion {
    margin-bottom: 1.5rem;
}

/* ══════════════════════════════════════════════════════════════════════
   DN-4 runda 2, pkt 3 i 4 — „chyba jeszcze przydałoby się dopracować"
   ══════════════════════════════════════════════════════════════════════
   Runda 1 dała kartom tło, obrys i wcięcie (i testy to potwierdzają), ale punkt
   wrócił — bo zielony test sprawdzał STRUKTURĘ, a nie to, czy widok wygląda
   dobrze. Poprawki niżej dotyczą tego, co widać na zrzucie od zgłaszającego:

     • nagłówek strony: logo i dane sklepu obok surowej liczby „3.8 / 5 opinii",
       bez wspólnej ramy i bez hierarchii,
     • pasek sortowania: CZTERY pełne niebieskie przyciski naraz — każdy wygląda
       na wybrany, nie widać, które sortowanie jest aktywne,
     • treść opinii: duża czcionka i luźna interlinia, przez co jedna długa opinia
       zalewa widok.
   ---------------------------------------------------------------------- */

/* --- Nagłówek: jedna karta podsumowania ---------------------------------- */
.ds-opinions-store-header,
.shop-identify {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 24px;
    margin: 0 0 24px;
    padding: 20px 24px;
    background: #fff;
    border: 1px solid #e6e8eb;
    border-radius: 8px;
}

.shop-identify .shop-info,
.shop-identify .shop-opinion {
    flex: 1 1 260px;
    max-width: none;
    padding: 0;
}

.shop-identify .opinions-heading {
    margin: 0 0 10px;
    font-size: 1.15rem;
    font-weight: 700;
}

.shop-identify .rating-element {
    display: flex;
    align-items: center;
    gap: 14px;
    flex-wrap: wrap;
}

/* Ocena ma być pierwszą rzeczą, którą widać. */
.shop-identify .average-grade-label {
    font-size: 2.2rem;
    font-weight: 700;
    line-height: 1;
    color: #212529;
}

.shop-identify .opinions-number {
    font-size: .875rem;
    color: #6b7280;
}

.shop-identify .info-link a {
    color: #6b7280;
    font-size: .9rem;
    text-decoration: none;
}

.shop-identify .info-link a:hover {
    text-decoration: underline;
}

/* Pusty telefon/fax nie ma zostawiać dziury w nagłówku. */
.shop-identify .info-link:empty,
.shop-identify .info-link a[href="tel:"] {
    display: none;
}

/* --- Pasek sortowania: widać, które sortowanie jest włączone -------------- */
.opinions-list-sort .btn {
    background: #fff;
    border: 1px solid #d5d9dd;
    color: #495057;
    font-weight: 500;
    box-shadow: none;
}

.opinions-list-sort .btn:hover {
    border-color: #9aa3ab;
    color: #212529;
}

.opinions-list-sort .btn.active {
    background: #25b9d7;
    border-color: #25b9d7;
    color: #fff;
}

/* --- Treść opinii: spokojniejsza typografia ------------------------------- */
.ds-opinions-store .ds-opinions__single .opinion-context {
    font-size: .95rem;
    line-height: 1.5;
}

.ds-opinions-store .ds-opinions__single {
    font-size: .95rem;
}

/* ══════════════════════════════════════════════════════════════════════
   DN-4 runda 2, pkt 6 — formularz dodawania opinii bez żadnych styli
   ══════════════════════════════════════════════════════════════════════
   Ze zrzutu zgłaszającego: nagłówek przyklejony do logo, pola bez wcięć,
   domyślny niebieski przycisk „Dalej" w rozmiarze systemowym, a tuż pod nim
   — bez odstępu — baner promocyjny. Formularz wyglądał jak surowy HTML.

   Styl jest po stronie MODUŁU, nie motywu: ma wyglądać tak samo w classic
   i w hummingbird.
   ---------------------------------------------------------------------- */
.ds-opinions-store-form {
    max-width: 720px;
    margin: 2rem auto 3rem;
    padding: 24px;
    background: #fff;
    border: 1px solid #e6e8eb;
    border-radius: 8px;
    box-shadow: 0 2px 6px rgba(0, 0, 0, .05);
    box-sizing: border-box;
}

.ds-opinions-store-form .add-opinion-header {
    margin-bottom: 8px;
}

.ds-opinions-store-form .add-opinion-header h3 {
    margin: 0 0 4px;
    font-size: 1.3rem;
    font-weight: 700;
}

/* DW2-126 (2.1.5): „Produkt N z M” nad nazwą produktu w kroku 2. */
.ds-opinions-store-form .add-opinion-step {
    margin: 0 0 4px;
    color: #6b7280;
    font-size: .85rem;
    letter-spacing: .02em;
}

.ds-opinions-store-form .add-opinion-text {
    margin-bottom: 18px;
    color: #6b7280;
    font-size: .95rem;
}

.ds-opinions-store-form .amount {
    display: inline-block;
    padding: 2px 10px;
    border-radius: 999px;
    background: #eaf8fb;
    color: #12788c;
    font-weight: 600;
    font-size: .85rem;
}

.ds-opinions-store-form .form-group {
    margin-bottom: 18px;
}

.ds-opinions-store-form label {
    display: block;
    text-align: left;
    margin-bottom: 6px;
    font-weight: 600;
    font-size: .95rem;
}

.ds-opinions-store-form .form-control {
    width: 100%;
    box-sizing: border-box;
    border: 1px solid #d5d9dd;
    border-radius: 4px;
    padding: 10px 12px;
    font-size: .95rem;
}

.ds-opinions-store-form textarea.form-control {
    min-height: 120px;
    resize: vertical;
}

/* Gwiazdki oceny: 60 px to rozmiar do klikania palcem, ale bez odstępu zlewają się
   z polem poniżej. */
.ds-opinions-store-form .store-top-wrap {
    margin-bottom: 20px;
}

.ds-opinions-store-form .rating {
    display: inline-flex;
    gap: 4px;
}

/* ──────────────────────────────────────────────────────────────────────
   Z-049 (2.1.1) — wybór oceny w krokach 1 i 2 (_partials/rating-input.tpl)

   Przyciski `role="radio"`, gwiazdka inline bez koloru na ścieżce - kolor
   daje wyłącznie ten arkusz, więc `unactive` wreszcie widać. Reset przycisku
   jest tutaj, bo motyw bez Bootstrapa zostawia systemowy wygląd <button>.
   Kolory można podmienić zmiennymi --ds-opinions-gwiazdka(-obrys/-pusta).
   ────────────────────────────────────────────────────────────────────── */
.ds-opinions-rate {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 2px;
    line-height: 0;
}

.ds-opinions-rate .rating__button {
    -webkit-appearance: none;
    appearance: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    margin: 0;
    padding: 0;
    border: 0;
    border-radius: 6px;
    background: transparent;
    box-shadow: none;
    color: inherit;
    cursor: pointer;
    line-height: 0;
}

.ds-opinions-rate .rating__button .rating__star {
    display: block;
    width: 34px;
    height: 34px;
    fill: var(--ds-opinions-gwiazdka, #fab72d);
    stroke: var(--ds-opinions-gwiazdka-obrys, #f19300);
    stroke-width: 4px;
    transition: fill .12s ease, stroke .12s ease, transform .12s ease;
}

.ds-opinions-rate .rating__button.unactive .rating__star {
    fill: var(--ds-opinions-gwiazdka-pusta, #e4e7eb);
    stroke: var(--ds-opinions-gwiazdka-pusta-obrys, #c3c8ce);
}

.ds-opinions-rate .rating__button:hover .rating__star {
    transform: scale(1.08);
}

.ds-opinions-rate .rating__button:focus {
    outline: none;
}

.ds-opinions-rate .rating__button:focus-visible {
    outline: 2px solid var(--ds-opinions-fokus, #1f6feb);
    outline-offset: 1px;
}

@media (prefers-reduced-motion: reduce) {
    .ds-opinions-rate .rating__button .rating__star {
        transition: none;
    }
    .ds-opinions-rate .rating__button:hover .rating__star {
        transform: none;
    }
}

/* Błąd zapisu (formularz wraca z treścią zamiast HTTP 500). */
.ds-opinions-form__error {
    margin: 0 0 16px;
    padding: 10px 14px;
    border: 1px solid #f1b5b5;
    border-left-width: 4px;
    border-radius: 4px;
    background: #fdf2f2;
    color: #8a1f1f;
    font-size: .95rem;
}

/* Motyw bez Bootstrapa: przycisk wysyłki nie zostaje systemowy. `:where()` = zerowa
   specyficzność, więc styl `.btn` motywu bez warstw (classic, dynamite) wygrywa.
   Hummingbird trzyma Bootstrapa w `@layer`, a arkusz bez warstwy wygrywa z każdą
   warstwą niezależnie od specyficzności - dlatego kolory biorą najpierw zmienne
   przycisku Bootstrapa 5 (`--bs-btn-*` z `.btn-primary`), a dopiero potem własne. */
:where(.ds-opinions-store-form .button-wrapp) :where(button[type="submit"], a.ds-opinions-btn) {
    min-height: 44px;
    padding: 0 26px;
    border: 1px solid var(--bs-btn-border-color, transparent);
    border-radius: 4px;
    background: var(--bs-btn-bg, var(--ds-opinions-przycisk, #1f2937));
    color: var(--bs-btn-color, var(--ds-opinions-przycisk-tekst, #fff));
    font: inherit;
    font-weight: 600;
    cursor: pointer;
}

:where(.ds-opinions-store-form .button-wrapp) :where(button[type="submit"], a.ds-opinions-btn):hover {
    border-color: var(--bs-btn-hover-border-color, transparent);
    background: var(--bs-btn-hover-bg, var(--ds-opinions-przycisk-hover, #111827));
    color: var(--bs-btn-hover-color, var(--ds-opinions-przycisk-tekst, #fff));
}

:where(.ds-opinions-store-form) :where(textarea) {
    display: block;
    width: 100%;
    box-sizing: border-box;
    font: inherit;
}

.ds-opinions-store-form .button-wrapp {
    margin: 22px 0 0;
    padding-top: 18px;
    border-top: 1px solid #f0f2f4;
}

.ds-opinions-store-form .button-wrapp .btn {
    min-height: 44px;
    padding: 0 26px;
    font-weight: 600;
    border-radius: 4px;
}

/* ══════════════════════════════════════════════════════════════════════
   DN-4 pkt 5 — pływająca plakietka „Opinie Klientów"
   ══════════════════════════════════════════════════════════════════════
   Funkcja zgłaszana dwa razy (runda 1 i 2). Nie było jej ani w planie modułu,
   ani w opisie — czyli to nowa funkcja, zbudowana na prośbę z 2026-09-23.

   Dwie rzeczy przeniesione z lekcji ds_banners, żeby nie powtórzyć tych samych błędów:
     • plakietka wychodzi z serwera UKRYTA, a JS ukrycie zdejmuje (DN-7 pkt 5/6 —
       inaczej u kogoś, kto ją zamknął, mignie przy każdym wczytaniu),
     • zamknięcie ma TERMIN POWROTU (DN-2 pkt 4 — `localStorage` bez daty ważności
       kasował element na zawsze).
   ---------------------------------------------------------------------- */
.ds-opinions-plakietka {
    position: fixed;
    /* Z-041 pkt 5 (2.1.0): było 9997 i przykrywało panele off-canvas motywów (~1200-1300).
       Motyw może przestawić wartość zmienną --ds-opinions-plakietka-z. */
    z-index: 1050;
    z-index: var(--ds-opinions-plakietka-z, 1050);
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 6px;
    width: 152px;
    padding: 18px 14px 14px;
    background: #fff;
    border-radius: 10px;
    box-shadow: 0 6px 24px rgba(0, 0, 0, .18);
    font-size: .875rem;
    text-align: center;
    color: #212529;
}

.ds-opinions-plakietka--lewy-dol { left: 18px; bottom: 18px; }
.ds-opinions-plakietka--prawy-dol { right: 18px; bottom: 18px; }
.ds-opinions-plakietka--lewy-gora { left: 18px; top: 18px; }
.ds-opinions-plakietka--prawy-gora { right: 18px; top: 18px; }

/* Ukrycie startowe — patrz komentarz w plakietka.tpl. */
.ds-opinions-plakietka--czeka { visibility: hidden; }

.ds-opinions-plakietka__zamknij {
    position: absolute;
    top: 4px;
    right: 6px;
    border: 0;
    background: none;
    font-size: 20px;
    line-height: 1;
    color: #9aa3ab;
    cursor: pointer;
    padding: 4px 6px;
}

.ds-opinions-plakietka__zamknij:hover { color: #495057; }

.ds-opinions-plakietka__ikona {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 46px;
    height: 46px;
    border-radius: 50%;
    border: 1.5px solid #d5d9dd;
    color: #495057;
}

.ds-opinions-plakietka__tytul {
    font-size: .8rem;
    color: #6b7280;
    line-height: 1.2;
}

.ds-opinions-plakietka__ocena {
    font-size: 1.6rem;
    font-weight: 700;
    line-height: 1;
}

.ds-opinions-plakietka__ile {
    font-size: .8rem;
    font-weight: 400;
    color: #9aa3ab;
}

.ds-opinions-plakietka__gwiazdki {
    display: inline-flex;
    gap: 2px;
}

.ds-opinions-plakietka__gwiazdka { fill: #e3e6e9; }
.ds-opinions-plakietka__gwiazdka.is-pelna { fill: #fab72d; }

.ds-opinions-plakietka__link {
    font-size: .8rem;
    color: #6b7280;
    text-decoration: underline;
}

.ds-opinions-plakietka__link:hover { color: #212529; }

/* Na wąskim ekranie plakietka nie ma zasłaniać treści ani przycisku koszyka. */
@media (max-width: 575px) {
    .ds-opinions-plakietka {
        width: 128px;
        padding: 14px 10px 10px;
        transform: scale(.92);
        transform-origin: bottom left;
    }
    .ds-opinions-plakietka--prawy-dol,
    .ds-opinions-plakietka--prawy-gora { transform-origin: bottom right; }
}


/* ══════════════════════════════════════════════════════════════════════
   2.1.0 — Z-041 / Z-044
   ══════════════════════════════════════════════════════════════════════ */

/* Plakietka: odsetek polecających (Z-041 pkt 2). */
.ds-opinions-plakietka__poleca {
    font-size: .75rem;
    color: #495057;
}

/* Karta produktu: sortowanie opinii (Z-041 pkt 3). */
.ds-opinions-sort {
    display: flex;
    align-items: center;
    justify-content: flex-end;
    gap: 8px;
    margin: 0 0 12px;
}
.ds-opinions-sort label {
    margin: 0;
    font-size: .875rem;
    color: #6b7280;
}
.ds-opinions-sort select {
    width: auto;
    max-width: 220px;
}

/* Strona opinii o sklepie: rozkład ocen (Z-044 pkt 1). */
.ds-opinions-rozklad {
    display: grid;
    gap: 4px;
    max-width: 320px;
    margin-top: 12px;
}
.ds-opinions-rozklad__wiersz {
    display: grid;
    grid-template-columns: 2.5em 1fr 2.5em;
    align-items: center;
    gap: 8px;
    color: inherit;
    font-size: .85rem;
    text-decoration: none;
}
.ds-opinions-rozklad__wiersz:hover,
.ds-opinions-rozklad__wiersz.is-active {
    font-weight: 600;
    text-decoration: none;
}
.ds-opinions-rozklad__tor {
    display: block;
    height: 8px;
    border-radius: 4px;
    background: #eef0f2;
    overflow: hidden;
}
.ds-opinions-rozklad__tor > span {
    display: block;
    height: 100%;
    background: #fab72d;
}
.ds-opinions-rozklad__liczba {
    text-align: right;
    color: #6b7280;
}

/* Filtr po ocenie (Z-044 pkt 2) i plakietka zakupu (pkt 4). */
.ds-opinions-filtry {
    margin-top: -0.75rem;
}
.ds-opinions-zakup {
    display: inline-block;
    margin-left: 6px;
    padding: 1px 8px;
    border-radius: 999px;
    background: #e8f5e9;
    color: #2e7d32;
    font-size: .75rem;
    font-weight: 600;
}
.ds-opinions-pusto {
    margin: 1rem 0;
    color: #6b7280;
}

/* Krok 2 formularza — opinia o produkcie (Z-044 pkt 9): ta sama karta co krok 1
   (klasa .ds-opinions-store-form na kontenerze), tu tylko elementy, których krok 1 nie ma. */
.ds-opinions-product-form .opinion-image {
    margin: 0 0 16px;
}
.ds-opinions-product-form .opinion-image img {
    display: block;
    width: 160px;
    max-width: 100%;
    height: auto;
    border: 1px solid #e6e8eb;
    border-radius: 6px;
}
.ds-opinions-product-form .rating.store-top-wrap {
    margin-bottom: 20px;
}
.ds-opinions-store-form .ds-opinion-photos input[type="file"] {
    display: block;
    width: 100%;
    box-sizing: border-box;
    padding: 10px 12px;
    border: 1px dashed #c9ced3;
    border-radius: 4px;
    background: #fafbfc;
    font-size: .9rem;
    cursor: pointer;
}
.ds-opinions-store-form .ds-opinion-photos small {
    display: block;
    margin-top: 6px;
    color: #6b7280;
}
.ds-opinions-store-form .hints-wrapper span {
    display: inline-block;
    margin: 0 6px 6px 0;
    padding: 4px 10px;
    border: 1px solid #d5d9dd;
    border-radius: 999px;
    font-size: .85rem;
    cursor: pointer;
}
.ds-opinions-store-form .hints-wrapper span:hover {
    border-color: #6b7280;
}

/* ══════════════════════════════════════════════════════════════════════
   DN-12 / Z-057 — strony końcowe: podziękowanie (end.tpl) i „opinia już dodana"
   (opinion-already-exist.tpl). Ta sama karta co kroki formularza (.ds-opinions-store-form),
   te same kolory i przycisk; ikona stanu to inline SVG w kolorze `currentColor`.
   ---------------------------------------------------------------------- */
.ds-opinions-end {
    text-align: center;
}
/* 2.1.3: limit wysokości logo także w krokach formularza (create-store, create-product) - logo sklepu
   w naturalnym rozmiarze (np. 520 px) zajmowało pół karty. */
.ds-opinions-store-form .opinion-store-logo {
    margin: 0 0 12px;
}
.ds-opinions-store-form .opinion-store-logo img {
    display: inline-block;
    max-width: 100%;
    max-height: 64px;
    width: auto;
    height: auto;
}
.ds-opinions-end__icon {
    display: flex;
    justify-content: center;
    margin: 4px 0 12px;
}
.ds-opinions-end__icon svg {
    display: block;
    width: 48px;
    height: 48px;
}
.ds-opinions-end--success .ds-opinions-end__icon {
    color: var(--ds-opinions-sukces, #1b8a4b);
}
.ds-opinions-end--info .ds-opinions-end__icon {
    color: var(--ds-opinions-info, #12788c);
}
.ds-opinions-end .add-opinion-header {
    margin-bottom: 0;
}
.ds-opinions-end .add-opinion-text {
    margin-bottom: 0;
}
.ds-opinions-end .add-opinion-text p {
    margin: 0 0 10px;
}
.ds-opinions-end .zoozone-amount {
    margin-top: 4px;
}
.ds-opinions-end .button-wrapp {
    margin-top: 22px;
}
.ds-opinions-end .button-wrapp a.ds-opinions-btn {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    box-sizing: border-box;
    text-decoration: none;
    /* Link, nie <button>: reguły motywu `a`/`a:hover` mają wyższą specyficzność niż
       `:where()` wyżej, więc kolory przycisku podajemy tu wprost (te same zmienne). */
    border: 1px solid var(--bs-btn-border-color, transparent);
    background: var(--bs-btn-bg, var(--ds-opinions-przycisk, #1f2937));
    color: var(--bs-btn-color, var(--ds-opinions-przycisk-tekst, #fff));
}
.ds-opinions-end .button-wrapp a.ds-opinions-btn:hover,
.ds-opinions-end .button-wrapp a.ds-opinions-btn:focus {
    border-color: var(--bs-btn-hover-border-color, transparent);
    background: var(--bs-btn-hover-bg, var(--ds-opinions-przycisk-hover, #111827));
    color: var(--bs-btn-hover-color, var(--ds-opinions-przycisk-tekst, #fff));
    text-decoration: none;
}
@media (max-width: 480px) {
    .ds-opinions-end {
        padding: 20px 16px;
    }
    .ds-opinions-end .button-wrapp a.ds-opinions-btn {
        width: 100%;
    }
}
