/* Reguli exclusiv ale portului Yii2, ținute în afara lui app.css.
 *
 * app.css și responsive.css trebuie să rămână byte-identice cu fișierele din
 * C:\Users\vadim\projects\florado\core\css\, ca resincronizările viitoare să fie
 * o simplă copiere, nu un merge manual. Tot ce adaugă portul stă aici.
 *
 * Se încarcă ULTIMUL în DesignAsset::$css, deci suprascrie app.css/responsive.css
 * la specificitate egală.
 *
 * Cele două clase de mai jos nu există în design:
 *   .is-loading   — starea butonului cât timp se așteaptă răspunsul AJAX
 *   .in-wishlist  — starea „e deja în favorite" randată de PHP la încărcarea
 *                   paginii (designul are doar ._active, pus de JS după click)
 */

/* Cât se așteaptă răspunsul de la /cart/add. Popup-ul „adăugat în coș" apare
   abia cu produsul în el, deci feedback-ul de „se lucrează" stă pe buton.
   Se animează <i>, nu ::before/::after — acelea sunt tooltip-ul .action-item. */
.action-item.is-loading,
.add-to-cart-btn.is-loading {
  pointer-events: none;
}

.action-item.is-loading i,
.add-to-cart-btn.is-loading i {
  animation: florado-pulse 0.7s ease-in-out infinite;
}

@keyframes florado-pulse {
  0%,
  100% {
    opacity: 1;
    transform: scale(1);
  }
  50% {
    opacity: 0.35;
    transform: scale(0.85);
  }
}

/* ---------------------------------------------------------------------
   Produs adăugat la favorite

   Designul colora butonul activ cu exact verdele închis pe care îl folosește
   și `:hover` — deci „e la favorite" și „mouse-ul e deasupra" arătau identic,
   iar în rândul celor trei acțiuni ieșea un bloc întunecat care trage tot
   ochiul spre el.

   Acum semnalul e inima, nu fundalul: butonul păstrează verdele deschis al
   fraților lui, iar inima devine plină și verde. Se citește ca „selectat"
   fără chenar și fără să strice echilibrul cardului.
   --------------------------------------------------------------------- */
.action-item.fav-btn._active,
.action-item.fav-btn.in-wishlist {
  background: var(--color-green-tint);
}

.action-item.fav-btn._active i,
.action-item.fav-btn.in-wishlist i {
  color: var(--primary-green);
}

/* Peste un buton deja activ, hover-ul înseamnă „scoate de la favorite": revine
   la blocul plin al designului, dar cu inima plină — se vede că e o comutare,
   nu o adăugare. */
.action-item.fav-btn._active:hover,
.action-item.fav-btn.in-wishlist:hover {
  background: var(--color-green-medium);
}

.action-item.fav-btn._active:hover i,
.action-item.fav-btn.in-wishlist:hover i {
  color: var(--color-white);
}

/* Inima de pe pagina de produs — același tratament, la scara butonului mare.
   Designul stilează acolo doar `:hover`, deci ambele stări (`._active` pus de
   JS și `.in-wishlist` randat de PHP) sunt ale portului. */
.prod-page .add-to-fav-btn._active,
.prod-page .add-to-fav-btn.in-wishlist {
  background-color: var(--color-green-tint);
}

.prod-page .add-to-fav-btn._active i,
.prod-page .add-to-fav-btn.in-wishlist i {
  color: var(--primary-green);
}

.prod-page .add-to-fav-btn._active:hover,
.prod-page .add-to-fav-btn.in-wishlist:hover {
  background-color: var(--color-green-medium);
}

.prod-page .add-to-fav-btn._active:hover i,
.prod-page .add-to-fav-btn.in-wishlist:hover i {
  color: var(--color-white);
}

/* Confirmarea la click. Clasa se pune din JS doar la ADĂUGARE și se scoate
   după animație, ca inima să nu pulseze la fiecare încărcare de pagină pentru
   produsele deja favorite. */
.fav-btn._just-added i {
  animation: florado-heart-pop 0.45s ease-out;
}

@keyframes florado-heart-pop {
  0% {
    transform: scale(1);
  }
  35% {
    transform: scale(1.45);
  }
  60% {
    transform: scale(0.92);
  }
  100% {
    transform: scale(1);
  }
}

@media (prefers-reduced-motion: reduce) {
  .fav-btn._just-added i {
    animation: none;
  }
}

/* „Șterge produsele selectate" fără nicio bifă nu are ce șterge.
   Designul doar îl colora în roșu la selecție (`._has-selection`), dar îl lăsa
   să pară apăsabil tot timpul — click-ul nu făcea nimic și arăta ca un buton
   stricat. Acum lipsa selecției se vede și blochează click-ul. */
.clear-cart:not(._has-selection) {
  opacity: 0.4;
  pointer-events: none;
  cursor: default;
}

/* Atributul `hidden` chiar ascunde.
   Reset-ul proiectului nu are regula pe care o aduce reboot-ul Bootstrap,
   iar `display: none` din foaia de stil a browserului pierde în fața
   oricărei clase de utilitate (`.d-flex`, `.d-block`). Fără asta, blocul
   „coș gol" randat ascuns se vedea peste cel plin. */
[hidden] {
  display: none !important;
}

/* ---------------------------------------------------------------------
   Loader peste o zonă care se reîncarcă prin AJAX

   Clasa se pune pe containerul care se schimbă (grila de produse, tabelul
   coșului). Conținutul vechi rămâne vizibil, estompat, ca pagina să nu
   sară — se adaugă doar un văl alb și un cerc care se rotește.

   Containerul are nevoie de `position: relative`; se pune aici, nu în
   markup, ca zona să arate identic când nu se încarcă nimic.
   --------------------------------------------------------------------- */
.is-ajax-busy {
  position: relative;
}

.is-ajax-busy > * {
  opacity: 0.45;
  transition: opacity var(--transition-base);
  pointer-events: none;
}

.is-ajax-busy::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 4;
  background-color: rgba(var(--color-white-rgb), 0.55);
}

.is-ajax-busy::after {
  content: "";
  position: absolute;
  z-index: 5;
  /* fixat pe verticală, nu centrat: la o grilă înaltă centrul poate cădea
     sub marginea ferestrei, iar loader-ul n-ar fi vizibil deloc */
  top: 80px;
  left: 50%;
  width: 38px;
  height: 38px;
  margin-left: -19px;
  border: 3px solid var(--color-green-tint);
  border-top-color: var(--primary-green);
  border-radius: var(--border-rounded);
  /* fundal propriu + halou alb: altfel inelul cade peste o fotografie de
     produs și se pierde în ea */
  background-color: var(--color-white);
  box-shadow: 0 0 0 10px var(--color-white), 0 6px 18px rgba(var(--shadow-rgb), 0.12);
  animation: florado-spin 0.7s linear infinite;
}

@keyframes florado-spin {
  to {
    transform: rotate(360deg);
  }
}

@media (prefers-reduced-motion: reduce) {
  .is-ajax-busy::after {
    animation-duration: 2.4s;
  }
}

/* ---------------------------------------------------------------------
   Paginarea: pagina curentă

   Markup-ul marchează deja pagina curentă, dar designul n-a stilizat-o
   niciodată — toate numerele arătau la fel, iar singura diferență vizibilă
   era culoarea implicită de link vizitat a browserului, care nu înseamnă
   nimic. Pagina curentă e acum verde plin.

   Se acoperă ambele convenții de clasă din proiect: `.active` (catalog,
   blog) și `._active` (paginarea din cont) — designul le folosește pe
   amândouă.
   --------------------------------------------------------------------- */
.history-pagination .pagination-item.active,
.history-pagination .pagination-item._active {
  background-color: var(--primary-green);
  border-color: var(--primary-green);
  color: var(--color-white);
  font-weight: 600;
  /* pagina curentă nu duce nicăieri — nu se comportă ca un link */
  pointer-events: none;
  cursor: default;
}

/* Restul numerelor rămân neutre indiferent de starea de „vizitat", ca
   diferența de culoare să însemne doar „aici ești". */
.history-pagination a.pagination-item:visited {
  color: var(--color-black);
}

.history-pagination a.pagination-item:hover {
  border-color: var(--primary-green);
  color: var(--primary-green);
}

/* Săgețile fără destinație sunt <span>, nu <a> — arată dezactivat. */
.history-pagination span.pagination-item {
  color: var(--gray-090);
  border-color: var(--gray-050);
}

/* Telefonul și emailul din pre-header sunt acum elemente EditMode, deci
   `<span>`-uri. În pre-header `span` e însă separatorul vertical al machetei
   (1px lățime, fundal gri), care le strivea într-o dungă. Regula temei rămâne
   pentru separatoarele goale; se resetează doar span-ul editabil, prin clasa
   proprie a portului (capcana din ghid §8). */
.pre-header .pre-header-contact {
  height: auto;
  width: auto;
  background-color: transparent;
}

/* Orarul de pe pagina de contact: în machetă doar eticheta era un <span>
   (îngroșat de tema care stilează orice `span` din bloc), iar ora era text
   simplu. Acum ambele sunt elemente EditMode, deci ambele sunt span-uri și
   ora s-ar îngroșa și ea. Regula temei rămâne neatinsă; se resetează punctual
   doar valoarea, prin clasa proprie a portului (capcana din ghid §8). */
.contact-pg .text-wrapper .contacts p .contact-hours-value {
  font-weight: 400;
}

/* ---------------------------------------------------------------------
   Carduri de produs de aceeași înălțime

   Designul a fost desenat cu carduri identice ca text; catalogul real are
   titluri pe 1–2 rânduri, preț vechi doar la reduceri și rândul de puncte
   doar peste 100 MDL, deci fiecare card ieșea cu altă înălțime. Cardul
   umple acum coloana (coloanele Bootstrap sunt oricum întinse la înălțimea
   rândului), iar `.actions-wrapper { margin-top: auto }` din app.css duce
   butoanele pe aceeași linie în toate cardurile.
   --------------------------------------------------------------------- */
#productGrid > [class*="col-"] {
  display: flex;
}

#productGrid .prod-card.single,
.wish-list-wrapper .prod-card {
  height: 100%;
}

/* Titlul e singura parte cu lungime imprevizibilă: două rânduri, apoi „…".
   Rezervă înălțimea celor două rânduri și când titlul e scurt, ca prețul și
   butoanele să înceapă la aceeași înălțime în toate cardurile. */
#productGrid .prod-card .prod-desc .title,
.wish-list-wrapper .prod-card .prod-desc .title {
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  overflow: hidden;
  min-height: calc(2 * 18px * 1.5);
}

/* Modul listă pune cardul pe orizontală, unde clamp-ul și înălțimea fixă nu
   au sens. */
#productGrid.list-view .prod-card.single {
  height: auto;
}

#productGrid.list-view .prod-card .prod-desc .title {
  display: block;
  min-height: 0;
}

/* ---------------------------------------------------------------------
   Select-urile de sortare (catalog și blog — ambele stau în `.sorting-bar`)

   Rămân <select> nativ: JS-ul de filtrare ascultă pe `.sorting-select select`
   și pe `#blogSort`. Lista deschisă e desenată de sistem, deci se poate
   influența doar prin culorile opțiunilor; restul stilizării e pe controlul
   închis — săgeata proprie (SVG inline, fără request suplimentar), aceeași
   rază și același verde ca restul interfeței.
   --------------------------------------------------------------------- */
.sorting-bar .sorting-select {
  position: relative;
}

.sorting-bar select {
  appearance: none;
  -webkit-appearance: none;
  -moz-appearance: none;
  padding: 10px 40px 10px 14px;
  border: 1px solid var(--gray-050);
  border-radius: var(--border-radius-8);
  background-color: var(--color-white);
  color: var(--color-dark-blue);
  font-size: 15px;
  font-weight: 500;
  line-height: 1.2;
  cursor: pointer;
  transition:
    border-color var(--transition-base),
    box-shadow var(--transition-base);
  /* chevron: currentColor nu funcționează în data:, deci culoarea e fixă */
  background-image: url("data:image/svg+xml;charset=UTF-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 16 16' fill='none' stroke='%23657078' stroke-width='1.8' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M4 6l4 4 4-4'/%3E%3C/svg%3E");
  background-repeat: no-repeat;
  background-position: right 14px center;
  background-size: 16px 16px;
}

.sorting-bar select:hover {
  border-color: var(--primary-green);
}

.sorting-bar select:focus-visible {
  border-color: var(--primary-green);
  box-shadow: 0 0 0 3px rgba(var(--primary-green-rgb), 0.18);
}

/* Lista deschisă e desenată de sistem: culorile de mai jos sunt tot ce
   acceptă, iar evidențierea rândului rămâne albastrul sistemului. */
.sorting-bar select option {
  padding: 8px 12px;
  background-color: var(--color-white);
  color: var(--color-dark-blue);
}

.sorting-bar select option:checked {
  background-color: var(--color-green-tint);
  color: var(--color-green-dark);
}

/* Prima opțiune e doar eticheta („Sortează"), nu o sortare — se vede ca
   text secundar, la fel ca un placeholder. */
.sorting-bar select option[value=""] {
  color: var(--text-color);
}

/* =========================================================================
   Rame fixe pentru imagini
   =========================================================================
   Designul e construit pe fotografii pătrate (cele reale sunt 2500×2500), iar
   containerele nu aveau dimensiune proprie: înălțimea o dicta imaginea. O poză
   lată (un screenshot de 1831×855, de exemplu) turtea galeria paginii de produs
   și lățea rândurile din coș, deci fiecare produs arăta altfel.

   Peste tot mai jos rama are dimensiune proprie, iar imaginea se așază în ea cu
   `object-fit`. Fotografiile pătrate arată exact ca înainte; ce nu e pătrat
   intră cu benzi în loc să strice pagina.

   `.prod-card`, `.cart-product` și `.added-to-cart-box` aveau deja rame fixe în
   app.css — aici sunt doar locurile care lipseau. */

/* ---- Galeria paginii de produs -------------------------------------- */

/* Rama principală: pătrat cât lățimea coloanei, plafonat ca pe ecrane late să
   nu împingă tabul „Descriere" sub linia de plutire. */
.product-gallery-main {
  aspect-ratio: 1 / 1;
  max-height: 520px;
  overflow: hidden;
  border-radius: var(--border-radius-12);
  background: var(--color-white);
}

.product-gallery-main .swiper-wrapper,
.product-gallery-main .swiper-slide {
  height: 100%;
}

.product-gallery-main .swiper-slide {
  display: flex;
  align-items: center;
  justify-content: center;
}

/* `contain`, nu `cover`: pe pagina de produs poza e subiectul, iar o sticlă
   tăiată la jumătate e mai rea decât două benzi albe. */
.product-gallery-main .swiper-slide img {
  width: 100%;
  height: 100%;
  object-fit: contain;
}

/* Miniaturile: pătrate egale, aceeași încadrare ca imaginea mare, ca să nu
   pară alt cadru al aceleiași fotografii. */
.product-gallery-thumbs .swiper-slide {
  aspect-ratio: 1 / 1;
  height: auto;
}

.product-gallery-thumbs img {
  /* `block`: ca <img> inline, linia de bază adăuga ~3px sub imagine, deci
     miniatura ieșea 162×165 în loc de pătrat. */
  display: block;
  width: 100%;
  height: 100%;
  object-fit: contain;
  background: var(--color-white);
  /* Miniatura activă capătă din app.css un chenar de 2px; fără box-sizing el
     s-ar adăuga peste cutie și rândul de miniaturi ar sălta la fiecare click. */
  box-sizing: border-box;
}

/* ---- Rândurile de produs din coș, checkout și detaliul comenzii ------ */

/* app.css are aici `width: 100` (fără unitate, deci ignorat) și niciun
   `object-fit`, așa că imaginea rămânea întinsă la 125px înălțime pe orice
   lățime. */
.cart-md-products-wrap .product .product-img {
  width: 125px;
  height: 125px;
  flex: 0 0 125px;
  overflow: hidden;
  border-radius: var(--border-radius-12);
  background: var(--color-white);
}

.cart-md-products-wrap .product img {
  display: block;
  width: 100%;
  max-width: none;
  height: 100%;
  /* `cover`, ca la `.cart-product` și `.added-to-cart-box` din app.css: în coș
     miniaturile umplu cutia, spre deosebire de pagina de produs unde poza e
     subiectul și n-are voie să fie tăiată. */
  object-fit: cover;
}

/* ---- Banda de parteneri ---------------------------------------------- */

/* `height: 100%` din app.css nu se rezolvă — containerul e un .swiper-slide
   fără înălțime proprie — deci fiecare logo rămânea la înălțimea lui naturală,
   plafonată la 50px: rândul ieșea zimțat, cu logouri între 34 și 50px.
   Înălțimea o primește imaginea, iar `contain` păstrează proporțiile fiecărui
   logo în interiorul slotului. */
.partner-img__container img {
  height: 50px;
  max-height: 50px;
}

/* ==========================================================================
   Notificări de checkout (erori de validare, mesaje de sistem)
   ==========================================================================

   Blocul de erori folosea `.alert.alert-danger` din Bootstrap: un dreptunghi
   roz, cu colțuri și tipografie care nu seamănă cu nimic altceva din magazin,
   în care mesajele stăteau unul sub altul fără ierarhie. Componenta de mai jos
   îi ia locul: bară de accent în culoarea stării, fundal abia colorat, iconiță,
   un titlu care spune ce trebuie făcut și lista propriu-zisă dedesubt.

   Culorile stau pe aceleași variabile ca restul magazinului, ca starea de
   succes să fie verdele Florado, nu verdele Bootstrap. */

.checkout-notice {
  display: flex;
  gap: 12px;
  padding: 14px 16px;
  border-radius: 12px;
  border: 1px solid transparent;
  border-left-width: 4px;
  font-size: 14px;
  line-height: 1.5;
  animation: checkout-notice-in 0.25s ease-out both;
}

@keyframes checkout-notice-in {
  from {
    opacity: 0;
    transform: translateY(-4px);
  }
}

/* Utilizatorii care au cerut mai puțină mișcare nu primesc animația. */
@media (prefers-reduced-motion: reduce) {
  .checkout-notice {
    animation: none;
  }
}

.checkout-notice__icon {
  flex: 0 0 auto;
  font-size: 20px;
  line-height: 1.2;
}

.checkout-notice__body {
  min-width: 0;
}

.checkout-notice__title {
  font-weight: 600;
  margin: 0 0 2px;
  color: var(--color-dark-blue);
}

.checkout-notice__text {
  margin: 0;
  color: var(--text-color);
}

/* Lista de erori: fără bulinele implicite ale browserului, cu un separator
   subțire între rânduri, ca trei mesaje să nu pară un paragraf. */
.checkout-notice__list {
  list-style: none;
  margin: 6px 0 0;
  padding: 0;
}

.checkout-notice__list li {
  position: relative;
  padding: 4px 0 4px 16px;
  color: var(--text-color);
}

.checkout-notice__list li + li {
  border-top: 1px solid rgba(0, 0, 0, 0.06);
}

.checkout-notice__list li::before {
  content: "";
  position: absolute;
  left: 2px;
  top: 12px;
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: currentColor;
  opacity: 0.45;
}

.checkout-notice--error {
  background: #fdf2f2;
  border-color: #f3d2d2;
  border-left-color: #d9534f;
}
.checkout-notice--error .checkout-notice__icon {
  color: #d9534f;
}

.checkout-notice--warning {
  background: #fff8ec;
  border-color: #f3e2c4;
  border-left-color: #e0a034;
}
.checkout-notice--warning .checkout-notice__icon {
  color: #c9821b;
}

.checkout-notice--success {
  background: #d8f3e6;
  border-color: #b9e6cf;
  border-left-color: #27925f;
}
.checkout-notice--success .checkout-notice__icon {
  color: #27925f;
}

/* Câmpul care a produs eroarea.

   Un sumar în capul formularului nu spune CARE câmp e greșit când formularul
   are zece. Marcajul de mai jos e partea care chiar economisește timp:
   chenar roșu pe câmpul vinovat și mesajul lui exact sub el. */
.checkout-form .form-control.is-invalid,
.checkout-form .form-control.is-invalid:focus {
  border-color: #d9534f;
  background: #fffafa;
}

.checkout-form .field-error {
  display: flex;
  align-items: center;
  gap: 4px;
  margin: 5px 0 0;
  font-size: 12.5px;
  font-weight: 500;
  color: #d9534f;
}

.checkout-form .field-error::before {
  content: "!";
  flex: 0 0 auto;
  width: 14px;
  height: 14px;
  border-radius: 50%;
  background: #d9534f;
  color: #fff;
  font-size: 10px;
  font-weight: 700;
  line-height: 14px;
  text-align: center;
}
