/* =============================================================================
   chat-patch2.css — patch 2 pentru chat. Se încarcă DUPĂ `chat-v7.css`.
   -----------------------------------------------------------------------------
   Nu înlocuiește nimic: doar suprascrie punctual. Dacă îl scoți, revii exact la
   comportamentul de acum. Fiecare bloc spune ce repară și cum a fost măsurat.

   Reproducerea defectelor: `masuratori/` (randează ruta reală de chat cu twig-ul
   și CSS-ul din repo, fără bază de date).
   ============================================================================= */


/* =========================================================================
   1. GRANULAȚIA — „texturile ciudate" și „cutia de sub Andu AI"
   -------------------------------------------------------------------------
   Sunt același defect. `body::after` (chat-v7.css:146) desenează o granulație
   de zgomot fractal cu `background-size: 140px` la `opacity: .04`.

   Pe landing, peste imagini și carduri, dala de 140px se pierde. Pe chat, peste
   suprafețe mari și foarte întunecate, se întâmplă invers: dala se repetă de
   ~2,8 ori pe un ecran de 390px, iar structura ei la scară mare devine
   VIZIBILĂ — se citește ca dreptunghiuri cu cusătură între ele, nu ca textură.
   Fiind `position: fixed`, nu derulează, deci pare lipită de ecran: exact
   „cutia" care rămâne și după ce dai „Sunt de acord".

   Reparația păstrează intenția (textură premium) și scoate artefactul: dală mult
   mai mică și zgomot mai fin, deci nu se mai poate organiza în blocuri.
   `baseFrequency` urcă de la .8 la 1.6 — zgomot de două ori mai fin.
   ====================================================================== */
body::after {
  background-size: 64px;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='64' height='64'%3E%3Cfilter id='n2'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='1.6' numOctaves='3' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='64' height='64' filter='url(%23n2)' opacity='1'/%3E%3C/svg%3E");
}
/* Pe ecrane mici suprafețele plate sunt proporțional mai mari, deci și cel mai
   mic zgomot se vede mai bine. 3% în loc de 4%. */
@media (max-width: 719.98px) {
  body::after { opacity: .03; }
}
/* Ecranele cu densitate mare afișează dala la jumătate de dimensiune fizică;
   fără asta granulația devine aproape invizibilă și nu mai face nimic. */
@media (min-resolution: 2dppx) {
  body::after { background-size: 48px; }
}


/* =========================================================================
   2. DISCLAIMERUL — REVENIT LA MECANISMUL v7 (1:1 cu replica)
   -------------------------------------------------------------------------
   Aici stătea rescrierea din patch2 (derulare pe CARD, înălțime `--dz-h` scrisă
   din JS de la capul listei până la buton, bară de scroll vizibilă). MĂSURAT pe
   1920×900, ea producea trei devieri față de replică:
     · caseta 664px înaltă, în loc de 504px;
     · pagina primea 57px de scroll inutil, deși totul încape pe ecran;
     · bara de scroll era vizibilă, iar v7 nu are niciuna.

   v7 (replica-noua/assets/css/chat-v6.css:383-392) face altfel, și e ce se
   restaurează aici: derulează CONTAINERUL, plafonat la `min(56vh, 560px)`
   (`min(48vh, 420px)` sub 720px), FĂRĂ bară de scroll — afordanța e o mască de
   estompare de 22px jos, iar padding-ul de sub text (34px) o depășește, deci
   ultimul rând nu e niciodată voalat.

   Din înălțimea mai mică dispare și scrollul de pagină: e o consecință, nu o
   reparație separată.

   `--dz-h` rămâne scris de `chat-patch2.js`, dar nimeni nu-l mai citește — inert.
   ====================================================================== */
/* -------------------------------------------------------------------------
   CORECȚIE (raportat pe telefon): caseta „se termina brusc", iar rama se vedea
   doar la capătul de sus sau la cel de jos al derulării.

   CAUZA, una singură pentru amândouă: rama, fundalul ȘI derularea stăteau pe
   elemente greșite.
     · Fundalul + rama în gradient erau pe CARD (`.message-assistant-disclaimer`),
       iar cardul e conținutul din interiorul zonei care derulează. Rama fiind
       desenată cu `::before { position:absolute; inset:0 }`, se întindea pe toată
       ÎNĂLȚIMEA DE CONȚINUT și derula odată cu textul: latura de sus se vedea doar
       la scroll 0, cea de jos doar la capăt. Exact ce se raportează.
     · Masca de estompare era pe ACELAȘI element care purta fundalul, deci nu
       estompa doar textul — stingea și fundalul, și rama. De aici senzația de
       tăiat brusc: jos nu mai exista nicio muchie, textul se pierdea în pagină.

   REPARAȚIA inversează responsabilitățile:
     · CONTAINERUL devine rama — nu derulează, deci fundalul, colțurile și chenarul
       în gradient stau pe loc, mereu vizibile, ca un cadru.
     · CARDUL dinăuntru devine zona care derulează și poartă el masca. Estomparea
       cade acum peste fundalul cadrului, nu peste pagină, deci textul se stinge
       ÎN interiorul casetei, iar muchia de jos rămâne desenată.
   Plafoanele de înălțime și absența barei de scroll rămân cele din v7.
   ---------------------------------------------------------------------- */
.up5-chat .message-container:has(.message-assistant-disclaimer) {
  position: relative;
  max-width: 100%;
  display: block;
  height: auto;
  /* plafonul v7 era pe container, când el era zona care derula; acum îl poartă
     cardul, iar cadrul se strânge pe el */
  max-height: none;
  margin: 2px;
  overflow: hidden; /* colțurile rotunjite taie conținutul derulat */
  background: var(--card-solid);
  border-radius: var(--r-xl);
  box-shadow: var(--inset-hi), var(--sh-1);
}
/* chenarul în gradient, mutat aici de pe card (aceleași valori) */
.up5-chat .message-container:has(.message-assistant-disclaimer)::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 2;
  border-radius: inherit;
  padding: 1px;
  pointer-events: none;
  opacity: 0.5;
  background: linear-gradient(150deg, rgba(0, 194, 255, 0.5), rgba(124, 92, 252, 0.22) 42%, rgba(181, 33, 233, 0.45) 92%);
  -webkit-mask:
    linear-gradient(#000 0 0) content-box,
    linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask-composite: exclude;
}

/* Cardul: zona care derulează. Fără fundal și fără ramă proprie — le poartă cadrul. */
.up5-chat .message.message-assistant-disclaimer {
  flex: none;
  width: auto;
  display: block;
  margin: 0;
  background: none;
  border: 0;
  border-radius: 0;
  box-shadow: none;
  overflow-y: auto;
  scrollbar-width: none;
  max-height: min(56svh, 560px);
  /* estomparea de 22px, acum pe zona care derulează; padding-ul de jos (34px) o
     depășește, deci ultimul rând nu e niciodată voalat */
  -webkit-mask-image: linear-gradient(180deg, #000 calc(100% - 22px), transparent);
  mask-image: linear-gradient(180deg, #000 calc(100% - 22px), transparent);
}
/* rama s-a mutat pe container; pseudo-elementul vechi al cardului ar dubla-o */
.up5-chat .message.message-assistant-disclaimer::before {
  content: none;
}
.up5-chat .message.message-assistant-disclaimer::-webkit-scrollbar {
  display: none;
}
/* PE DESKTOP, la fel ca pe telefon: caseta coboară până la bara de acord.
   `--dz-h` se măsoară pe orice lățime (`potriveste()` nu are prag), dar o consumam
   doar sub 720px — de aceea pe ecrane late rămânea plafonul fix `min(56vh, 560px)`
   și, pe monitoare înalte, aceeași bandă goală sub casetă ca pe telefon.
   Rezerva rămâne valoarea v7, dacă măsurătoarea nu se face. */
@media (min-width: 720px) {
  .up5-chat .message.message-assistant-disclaimer {
    max-height: var(--dz-h, min(56svh, 560px));
  }
}
@media (max-width: 719.98px) {
  /* PE TELEFON caseta coboară până la bara de acord, nu până la o fracțiune fixă.
     `min(48vh, 420px)` e o valoare arbitrară: nu știe cât loc chiar există între
     antet și bara de jos, iar pe ecranele înalte lăsa o bandă goală de câteva sute
     de pixeli sub casetă — spațiu în care textul chiar ar fi încăput.

     `--dz-h` e distanța MĂSURATĂ de la capul cardului până la bara de acord, minus
     un respiro (`chat-patch2.js`, `potriveste()`). Era deja calculată și ținută la zi
     la fiecare `resize` — inclusiv când iOS retrage bara de adrese — dar rămăsese
     nefolosită după revenirea la mecanismul v7. O consumăm acum: variabila stă pe
     `.message-container`, deci se moștenește în card.

     Rezerva rămâne valoarea v7, pentru cazul în care măsurătoarea nu apucă să se
     facă (JS oprit, geometrie absurdă — `potriveste()` refuză sub 200px).

     DESKTOP rămâne neatins: acolo plafonul v7 e cel validat, iar spațiul liber sub
     casetă e mult mai mic. */
  .up5-chat .message.message-assistant-disclaimer {
    max-height: var(--dz-h, min(48svh, 420px));
  }
}

/* HERO-UL DE „CHAT GOL" — reparat dupa acelasi tipar ca regula de mai sus.
   v7 decide starea de chat gol prin PREZENTA in DOM a unui `.message-container`:
     chat-v7.css:1469  [data-empty]:not(:has(.message-container))  → centrarea verticala
     chat-v7.css:1478  :has(.message-container) .acx-welcome        → ascunde hero-ul
   Cardul de disclaimer randat de server E un `.message-container`, iar `:has()` se
   uita la DOM, nu la vizibilitate. Deci si dupa acord, cand cardul e `display: none`,
   v7 credea in continuare ca exista un mesaj: hero-ul disparea si centrarea nu se
   aplica — ecran gol cu sugestiile lipite jos, exact ce s-a raportat.

   Reparatia scoate cardul static din numaratoare, dar NUMAI in starea de dupa acord
   (`html.chat-pre-composer`). Cat timp disclaimerul e pe ecran (`chat-pre-disclaimer`),
   comportamentul v7 ramane neatins: hero ascuns, fara centrare — ca in replica. */
html.chat-pre-composer .up5-chat .js-messages-container[data-empty]:not(:has(.message-container:not([data-disclaimer-static]))) {
  display: flex;
  flex-direction: column;
  justify-content: center;
  min-height: calc(var(--screen-height) - 400px);
}
html.chat-pre-composer .up5-chat .js-messages-container[data-empty]:not(:has(.message-container:not([data-disclaimer-static]))) .acx-welcome {
  display: block;
}

/* Lista de mesaje nu mai are ce afișa cât timp disclaimerul e pe ecran (e singurul
   mesaj), dar îi scoatem înălțimea ca să nu rămână o zonă derulabilă goală în
   spatele casetei fixe. */
.up5-chat .js-messages-container:has(.message-assistant-disclaimer) { min-height: 0; }


/* =========================================================================
   3. LĂȚIMEA BULELOR pe mobil
   -------------------------------------------------------------------------
   MĂSURAT la 390px: bula lui Andu avea 342px, adică 48px nefolosiți — 12% din
   ecran, pe un conținut care e aproape numai text. Pe mobil marginea de tip
   „conversație" (bula nu atinge marginea, ca să se vadă că e o bulă) costă mai
   mult decât aduce: planul, listele și cardurile de produs sunt deja delimitate
   de propriul lor chenar.

   Bulele UTILIZATORULUI rămân retrase — ele trebuie să se distingă de cele ale
   asistentului, iar mesajele scurte oricum nu ating limita.
   ====================================================================== */
@media (max-width: 719.98px) {
  /* Inset-ul real vine dintr-un singur loc, măsurat: `.grid-container` din chat are
     `padding: 0 14px`. NU adăugăm padding nou (s-ar aduna la el și bula ar ieși mai
     îngustă) — îl reducem la 8px. Câștig net: 12px pe fiecare parte. */
  .up5-chat .grid-container.messages,
  .up5-chat .messages.grid-container { padding-left: 8px; padding-right: 8px; }

  .up5-chat .message-container > .message.message--assistant,
  .up5-chat .message-container > .message--pending {
    max-width: 100%;
    width: auto;
  }
  /* padding interior mai strâns: pe 390px fiecare pixel de text contează */
  .up5-chat .message-container > .message.message--assistant { padding: 12px 14px; }

  /* Bula utilizatorului rămâne vizibil mai îngustă — contrastul de lățime e ceea
     ce face conversația citibilă dintr-o privire. */
  /* CORECTAT: era `max-width: 86%` pe BULĂ. Părintele (`.message-container`) e
     shrink-to-fit — se dimensionează după copil — iar copilul era limitat la 86%
     din părinte: constrângere circulară, pe care browserul o rezolvă strângând la
     min-content. Cu `overflow-wrap` activ, min-content e lățimea unui caracter,
     deci „sigur" ieșea „sig / ur" deși mai era loc berechet pe rând.
     Îngustarea o face oricum containerul, care are `max-width: 86%` raportat la
     COLOANA conversației (chat-v7.css:1197) — acolo procentul are reper fix. */
  .up5-chat .message-container > .message.message--user {
    max-width: 100%;
    width: auto;
  }
}

/* =========================================================================
   4. ȚINTA MORPH-ULUI din landing, decisă ÎNAINTE de primul desen
   -------------------------------------------------------------------------
   Aici era defectul de fond al animației. `chat-v7.css` dă numele de tranziție
   `composer` la două elemente, prin stări pe care le pune MOTORUL:
       .search-bar-container:not([data-hidden]) .input-bar   → cel implicit
       .disclaimer-actions[data-active]                      → când e disclaimer
   Dar motorul rulează în `pse.addToDOMLoad`, adică DUPĂ primul desen. În clipa
   în care browserul face instantaneul paginii noi, bara de input NU are încă
   `data-hidden` (deci ea poartă numele) și bara de disclaimer NU are `data-active`
   (deci nu-l poartă). Rezultat pentru un utilizator nou: pastila din landing se
   morfează în bara de input, care imediat după e ascunsă și înlocuită de bara de
   disclaimer. Morph-ul aterizează pe un element care dispare.

   Tot de aici venea și o clipire pe care nu o ceruse nimeni: bara de input se
   vedea o fracțiune de secundă, apoi era schimbată.

   Reparația: decizia se ia înainte de desen, într-un script inline din twig
   (vezi `twig/chat-v5.diff.md`), care pune pe `<html>` una din două clase.
   CSS-ul de mai jos face restul — determinist, fără să aștepte motorul.
   ====================================================================== */

/* utilizator nou → ținta e butonul de acord; bara de input nici nu apare */
html.chat-pre-disclaimer .up5-chat .search-bar-container .input-bar { view-transition-name: none; }
html.chat-pre-disclaimer .disclaimer-actions { view-transition-name: composer; }
html.chat-pre-disclaimer .up5-chat .search-bar-container { visibility: hidden; }
/* bara de disclaimer e vizibilă din primul cadru: fără ea, instantaneul ar
   surprinde un element cu `opacity: 0` și morph-ul ar ateriza în gol */
html.chat-pre-disclaimer .disclaimer-actions {
  transform: none; opacity: 1; pointer-events: auto;
}

/* utilizator care a acceptat deja → ținta e bara de scriere */
html.chat-pre-composer .disclaimer-actions { view-transition-name: none; }

/* Cardul de disclaimer randat de server (chat.html.twig, `[data-disclaimer-static]`) e în
   HTML din prima cadră, ca textul consimțământului să nu mai aștepte motorul de chat.
   Serverul nu poate ști dacă a fost deja acceptat în sesiunea asta — `sessionStorage` e
   doar al clientului — deci decizia o ia aceeași clasă pusă înainte de primul desen:
   `chat-pre-composer` = a acceptat deja, deci cardul nu are ce căuta pe ecran.
   `display: none` (nu `visibility`) ca să nu lase nici spațiu gol în lista de mesaje. */
/* SPECIFICITATE — aici a fost un bug raportat: disclaimerul reapărea, fără bara de
   acord, lângă input și sugestii, dacă îl acceptaseși fără să scrii nimic.
   Regula de ascundere avea (0,2,1), dar §2 de mai sus pune `display: block` pe
   `.up5-chat .message-container:has(.message-assistant-disclaimer)` = (0,3,0), care
   câștigă. Selectorul lung de mai jos urcă la (0,4,1) și trece înaintea ei.
   Al doilea selector rămâne ca plasă, dacă markup-ul se schimbă. */
html.chat-pre-composer .up5-chat .message-container[data-disclaimer-static],
html.chat-pre-composer [data-disclaimer-static] { display: none; }


/* =========================================================================
   5. FLIP-ul de sosire (rezerva care funcționează în ORICE browser)
   -------------------------------------------------------------------------
   View Transitions între documente merg doar în Chrome/Edge/Safari 18+, și doar
   dacă niciun header nu le taie (Dennis a găsit corect că `Cache-Control:
   no-store`, pus implicit de `session.cache_limiter`, le dezactivează — reparat
   în HomeRouteController și ChatRouteController). În Firefox și pe Safari mai
   vechi nu există deloc.

   `chat-patch2.js` măsoară unde era pastila pe landing și animează ținta din
   acea poziție. Clasele de mai jos sunt doar suportul: JS-ul scrie variabilele.
   ====================================================================== */
.acx-flip-target {
  will-change: transform, opacity;
  animation: acxFlipIn var(--flip-dur, .58s) cubic-bezier(.22, .61, .36, 1) both;
  transform-origin: 50% 50%;
}
/* CONFLICT DE ANIMATII, masurat pe ruta reala: FLIP-ul nu-si juca niciodata
   animatia exact cand conta — la sosirea din landing.

   `.acx-flip-target` are specificitate (0,1,0). Coregrafia de intrare v7 pune
   `animation` pe ACELEASI elemente, cu selectori mult mai puternici:
     · chat-v7.css:3811  body[data-anim-handoff] .disclaimer-actions[data-active]
                         .button-disclaimer-accept        → (0,4,1), acxAttention 1.4s
     · chat-v7.css:3754  body[data-anim-entrance] .up5-chat .search-bar-container
                         :not([data-hidden]) / .disclaimer-actions[data-active]
                                                          → (0,4,1), acxUp .6s
   `animation` e o singura proprietate: cine invinge ia tot. MASURAT inainte de
   reparatie: durata 1.4s si curba cubic-bezier(.4,0,.2,1) pe butonul de acord —
   adica pulsul de atentie, nu morph-ul.

   Nu scoatem coregrafia: o INLANTUIM. Ordinea conteaza — animatia listata ultima
   invinge cat timp e activa. FLIP-ul se termina la .58s, `acxAttention` incepe la
   1.1s si `acxUp` la .16s cu durata .6s, deci suprapunerea reala e minima, iar
   `both` de pe acxFlipIn tine starea finala (`transform: none`) intre ele.
   Selectorii de mai jos adauga `.acx-flip-target`, deci urca la (0,5,1) si trec
   inaintea celor din chat-v7.css. Demo-ul nu prinde conflictul: el reconstruieste
   ecranul de chat si nu ruleaza coregrafia de intrare. */
body[data-anim-handoff] .disclaimer-actions[data-active] .button-disclaimer-accept.acx-flip-target {
  animation:
    acxFlipIn var(--flip-dur, .58s) cubic-bezier(.22, .61, .36, 1) both,
    acxAttention 1.4s var(--ease-inout) 1.1s 2;
}
body[data-anim-entrance] .up5-chat .search-bar-container:not([data-hidden]).acx-flip-target,
body[data-anim-entrance] .disclaimer-actions[data-active].acx-flip-target {
  animation:
    acxFlipIn var(--flip-dur, .58s) cubic-bezier(.22, .61, .36, 1) both,
    acxUp .6s var(--ease-emph) .16s both;
}

@keyframes acxFlipIn {
  from {
    transform: translate(var(--flip-dx, 0px), var(--flip-dy, 0px))
               scale(var(--flip-sx, 1), var(--flip-sy, 1));
    opacity: var(--flip-op, .85);
  }
  to { transform: none; opacity: 1; }
}
/* restul paginii intră în urma ei, ca mișcarea să aibă un singur centru */
body[data-acx-flip] .up5-chat .messages,
body[data-acx-flip] .chatroom-top { animation: acxFlipRest .5s var(--ease-out, ease-out) .08s both; }
@keyframes acxFlipRest { from { opacity: 0; } to { opacity: 1; } }

/* Pe desktop mișcarea e mai scurtă: distanța dintre pastilă și bară e mică, iar
   un morph lung pe un ecran lat devine ostentativ. Andu a cerut explicit
   „pe desktop poate fi ceva mai simplu". */
@media (min-width: 1024px) {
  .acx-flip-target { --flip-dur: .4s; }
  body[data-acx-flip] .up5-chat .messages,
  body[data-acx-flip] .chatroom-top { animation-duration: .34s; }
}

@media (prefers-reduced-motion: reduce) {
  /* Regulile inlantuite de mai sus urca la (0,5,1), iar un `@media` NU adauga
     specificitate — deci fara selectorii repetati aici, `animation: none` ar fi
     pierdut si morph-ul ar rula tocmai pentru cine a cerut mai putina miscare.
     (JS-ul iese oricum din start pe reduced-motion, deci asta e plasa a doua.) */
  .acx-flip-target,
  body[data-anim-handoff] .disclaimer-actions[data-active] .button-disclaimer-accept.acx-flip-target,
  body[data-anim-entrance] .up5-chat .search-bar-container:not([data-hidden]).acx-flip-target,
  body[data-anim-entrance] .disclaimer-actions[data-active].acx-flip-target { animation: none; }
  body[data-acx-flip] .up5-chat .messages,
  body[data-acx-flip] .chatroom-top { animation: none; opacity: 1; }
}


/* =========================================================================
   6. GLOW-UL BAREI DE SCRIERE — un singur strat, un singur timp
   -------------------------------------------------------------------------
   MĂSURAT pe beta14, la 1920×1080: `.input-bar` are DOUĂ pseudo-elemente cu
   același gradient — `::before` la `opacity: .13` (inelul permanent) și `::after`
   la `opacity: 0` (glow-ul de focus). Iar `::before` are `transition: all`.

   De aici „se stinge în frame-uri diferite": două straturi care își schimbă
   opacitatea pe timpi diferiți, plus `all`, care încearcă să interpoleze și
   proprietăți neinterpolabile (`background-image`) — acelea sar, nu tranzitează.

   `transition: all` pe un pseudo-element cu gradient e o capcană dublă: nu poți
   ști ce animă, și animă și ce n-ar trebui. Reparația nu schimbă aspectul, doar
   sincronizează: aceeași proprietate, aceeași durată, același easing, zero delay
   pe ambele straturi. Dacă amândouă se mișcă, se mișcă împreună.
   ====================================================================== */
.up5-chat .search-bar-container .input-bar::before,
.up5-chat .search-bar-container .input-bar::after {
  transition-property: opacity;
  transition-duration: .24s;
  transition-timing-function: cubic-bezier(.22, .61, .36, 1);
  transition-delay: 0s;
}
/* Straturile de glow sunt pur decorative: le scoatem din calea compozitorului
   ca schimbarea de opacitate să nu declanșeze repaint pe tot ce e dedesubt. */
.up5-chat .search-bar-container .input-bar::after { will-change: opacity; }

@media (prefers-reduced-motion: reduce) {
  .up5-chat .search-bar-container .input-bar::before,
  .up5-chat .search-bar-container .input-bar::after { transition: none; }
}


/* =========================================================================
   7. TRANSPARENȚA BAREI ÎN FULLSCREEN — „îmi văd desktopul prin ea"
   -------------------------------------------------------------------------
   MĂSURAT: `.js-search-bar-container` e `position: fixed`, cu
   `background: rgba(8, 11, 18, .82)` și `backdrop-filter: blur(14px) saturate(1.2)`.
   Deci 18% din ea e transparent, iar ce se vede prin ea depinde de ce alege
   compozitorul ca „fundal" de estompat.

   În Safari, un `backdrop-filter` pe un element `fixed` creează o rădăcină de
   backdrop. În fullscreen, compozitorul poate ajunge să eșantioneze fundalul
   FERESTREI în loc de al paginii — și atunci prin cele 18% se vede literal
   desktopul. Nu e o eroare de CSS, e o cale de compunere; nu poate fi „reparată”
   din interior, doar evitată.

   Principiu: un element care ACOPERĂ conținut nu trebuie să depindă de ce e
   dedesubt ca să fie opac. Deci:
     · în ferestruire normală urcăm opacitatea la 94% — încă se citește ca sticlă
       peste gradientul paginii, dar nu mai lasă să treacă nimic real;
     · în fullscreen renunțăm complet la transparență și la blur. Nu se pierde
       nimic: în fullscreen nu există chrome de browser peste care să „plutească”.

   Aceeași corecție pe `.chatroom-top`, care are exact aceeași construcție. Nu a
   fost raportată — headerul e lipit de bara de adrese, deci se observă mai greu —
   dar e același defect și ar apărea în aceleași condiții.
   ====================================================================== */
.up5-chat .search-bar-container,
.up5-chat .chatroom-top {
  background-color: rgba(8, 11, 18, .94);
}

/* `:fullscreen` prinde fullscreen-ul din API (F cu Safari/Chrome pe video sau
   pe document). Pentru fullscreen-ul de FEREASTRĂ al macOS nu există selector,
   deci acoperim și cazul „foarte lat și foarte înalt”, care în practică e el. */
:fullscreen .up5-chat .search-bar-container,
:fullscreen .up5-chat .chatroom-top,
:-webkit-full-screen .up5-chat .search-bar-container,
:-webkit-full-screen .up5-chat .chatroom-top {
  background-color: var(--bg, #080B12);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
}
@media (min-width: 1600px) and (min-height: 1000px) {
  .up5-chat .search-bar-container,
  .up5-chat .chatroom-top {
    background-color: var(--bg, #080B12);
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
}


/* =========================================================================
   8. ECRANE LATE — chat-ul nu mai e „o bară pe mijloc"
   -------------------------------------------------------------------------
   MĂSURAT la 1920×1080: sidebar 300px, zona de conținut 1620px, coloana de
   citire 760px, bulele 620px. Adică **62% din zona de conținut e goală**.

   PRIMELE PRINCIPII, ca să nu reparăm în direcția greșită. Limita de citit e
   reală: peste ~75 de caractere pe rând, ochiul pierde începutul rândului
   următor. La 15px/1.6, asta e ~620-700px. **Deci bulele de 620px NU sunt
   defectul** — lățirea lor la 1200px ar strica lizibilitatea, nu ar repara-o.

   Defectul e că spațiul rămas nu are nicio intenție. Trei lucruri, împreună:

     a. Coloana crește ÎN TREPTE, nu proporțional: 760 → 880 (≥1440) → 980
        (≥1800). Bulele urcă la 680 și 720 — capătul de sus al intervalului
        confortabil, nu peste el.
     b. CARDURILE primesc toată coloana. Planul, cardul de produs, formularele și
        cardul de conversie nu sunt proză: sunt tabele, imagini și grile, care
        câștigă din lățime. Ele erau strânse la 620px degeaba.
     c. Coloana capătă un cadru discret, ca să se citească drept „foaie
        deliberată”, nu bandă rămasă. O umbră foarte moale pe verticală, plus
        marginile zonei de conținut ușor mai închise.

   Pragurile: 1024 (desktop), 1440 (desktop mare), 1800 (foarte lat). Jumătatea
   de ecran pe un 1920 cade la ~960px, adică sub 1024 — deci rămâne pe chrome-ul
   mobil, care e deja optimizat. Verificat în ambele screenshot-uri ale lui Andu.
   ====================================================================== */

/* ---- a. coloana în trepte ----
   `!important` pe celulă nu e neglijență: grila framework-ului îi pune lățimea
   cu `!important` (verificat pe beta14 — o regulă cu specificitate 0,5,0 și
   selector pe atribut NU câștigă, doar `!important` o face). Restul regulilor de
   aici sunt fără, pentru că acolo nu e nevoie. */
/* @media (min-width: 1440px) — SCOS pentru 1:1 cu v7.
   Lățea coloana (cell 880/980px) și bulele (assistant 680/720px) pe ecrane mari.
   Replica ține `.cell` la 760px și bula lui Andu la 620px pe ORICE lățime
   (chat-v6.css:44 și :323) — de aici „caseta de chat este mai lată". */
/* @media (min-width: 1800px) — SCOS pentru 1:1 cu v7.
   Lățea coloana (cell 880/980px) și bulele (assistant 680/720px) pe ecrane mari.
   Replica ține `.cell` la 760px și bula lui Andu la 620px pe ORICE lățime
   (chat-v6.css:44 și :323) — de aici „caseta de chat este mai lată". */

/* ---- b. cardurile iau toată coloana: nu sunt proză ---- */
@media (min-width: 1024px) {
  .up5-chat .message-container > .message.message--assistant:has(.chat-meal-plan),
  .up5-chat .message-container > .message.message--assistant:has(.chat-shopping),
  .up5-chat .message-container > .message.message--assistant:has(.event-user-form),
  .up5-chat .message-container > .message--assistant:has(.message__link),
  .up5-chat .message-container > .event-purchase-plan,
  .up5-chat .message-container > .message__link,
  .up5-chat .message-container > .event-user-form,
  .up5-chat .message-container > .event-purchase-plan .plan-switch { max-width: 100%; }
}

/* ---- c. SCOS: „coloana citește ca foaie, nu ca bandă" ----
   Aici stăteau două efecte care se aplicau doar peste 1440px, deci nu se vedeau pe
   ecrane obișnuite — și exact ele făceau zona de mesaje să pară că are alt fundal:

     1. `.up5acc-content` primea două gradiente negre pe margini
        (`rgba(0,0,0,.22)` până la 22% din lățime, stânga și dreapta, cu
        `background-attachment: fixed`). Efectul: toată zona de conținut era
        vizibil mai închisă la margini decât restul paginii.
     2. `.up5-chat .messages .grid-x > .cell` primea
        `box-shadow: 0 0 90px 40px rgba(0,0,0,.18)` — un halou negru de 130px în
        jurul coloanei de mesaje. MĂSURAT pe 1613×830: la 15px sub caseta de
        disclaimer fundalul cobora de la rgb(8,11,18) la rgb(6,9,15) și revenea
        treptat abia după ~50px. Asta era „încadrarea ciudată": un chenar difuz
        în jurul cutiei de mesaje.

   Intenția era să conducă ochiul spre centru pe monitoare late, dar pe o casetă
   care ocupă aproape tot ecranul (disclaimerul) rezultatul e o cutie într-o cutie.
   Fundalul rămâne acum uniform: doar `body` pictează, ca la lățimile mici.
   Limitele de lățime din blocurile a. și b. rămân — acelea sunt layout, nu culoare. */


/* =========================================================================
   9. MENIUL MOBIL NU DERULEAZĂ — cardul de cont rămâne tăiat
   -------------------------------------------------------------------------
   CAUZA, o singură declarație: `.acx-shell` (chat-v7.css:430-433) e
   `position: fixed; inset: 0` cu **`overflow: hidden`**. Pe desktop e corect —
   sidebarul are exact înălțimea ecranului și nimic nu depășește. Pe mobil,
   același element devine meniul pe tot ecranul, iar conținutul lui (logo + 5
   intrări + 2 pastile + cardul „Creează un cont") e mai înalt decât un telefon.
   `overflow: hidden` nu ascunde surplusul politicos: îl taie și îl face
   inaccesibil, fiindcă nu există nicio altă zonă derulabilă.

   Se vede exact ce a raportat Andu: „Am deja cont — autentificare" tăiat la
   jumătate, fără scroll.

   Reparația nu e doar `overflow: auto`. Trei lucruri împreună, altfel apar
   defecte noi:
     · `overscroll-behavior: contain` — fără el, derularea la capătul meniului
       „trece" în pagina de dedesubt (chat-ul se mișcă sub meniul deschis);
     · padding jos cu `safe-area-inset-bottom` — pe iPhone cu bară de gesturi,
       ultimul element ar sta sub ea și tot n-ar fi atingibil;
     · `-webkit-overflow-scrolling: touch` — derulare cu inerție pe iOS vechi.
   ====================================================================== */
@media (max-width: 1023.98px) {
  /* `.acx-nav` e containerul care trebuie să deruleze. E `flex: 1 1 0%` într-o
     coloană flex, deci are nevoie de `min-height: 0` — fără el, un element flex
     refuză să devină mai scurt decât conținutul lui, `scrollHeight` rămâne egal
     cu `clientHeight` și `overflow-y: auto` nu are ce derula. Capcană clasică de
     flexbox, și motivul pentru care prima variantă a acestei reparații (pusă pe
     `.acx-shell`) nu a schimbat nimic: măsurat, `scrollHeight === clientHeight`. */
  .acx-nav {
    min-height: 0;
    overflow-y: auto;
    overscroll-behavior: contain;      /* derularea nu „trece" în chat-ul de dedesubt */
    -webkit-overflow-scrolling: touch;
    padding-bottom: calc(20px + env(safe-area-inset-bottom, 0px));
    scrollbar-width: thin;
    scrollbar-color: rgba(255, 255, 255, .22) transparent;
  }
  .acx-nav::-webkit-scrollbar { width: 6px; }
  .acx-nav::-webkit-scrollbar-track { background: transparent; }
  .acx-nav::-webkit-scrollbar-thumb { background: rgba(255, 255, 255, .22); border-radius: 99px; }

  /* Cauza reală a tăierii. `.acx-guest` e flex-item fără `flex-shrink: 0`, deci
     când spațiul se termină flexbox îl STRIVEȘTE, iar `overflow: hidden` taie
     restul. MĂSURAT la 390×660: conținut 181px, comprimat la 66px — de aceea
     „Am deja cont — autentificare" apărea la jumătate.
     Cardul de conversie e exact motivul pentru care meniul există la un musafir;
     el nu se comprimă niciodată. Se comprimă spațiul, sau se derulează. */
  .acx-guest { flex: 0 0 auto; overflow: visible; }
  .acx-card, .acx-pills { flex: 0 0 auto; }

  /* Shell-ul rămâne cu `overflow: hidden` — el e rama ecranului, nu zona de
     conținut. Dacă i-am da și lui scroll, am avea două bare suprapuse. */
  .acx-shell { overflow: hidden; }
  .acx .acx-mbtns { z-index: 98; }     /* butonul de închidere, peste conținutul derulat */
}


/* =========================================================================
   10. CORTINA SPRE ONBOARDING — gradientul care „nu mai aparține"
   -------------------------------------------------------------------------
   CAUZA: `body[data-transitioning-to-onboarding]::before` (chat-v7.css:1146)
   desenează un dreptunghi pe tot ecranul, **complet opac și complet saturat**
   (`#00C2FF → #7C5CFC → #B521E9`), care mătură de jos în sus timp de 0,5s.

   În designul vechi, deschis, gradientul continua paleta paginii. În v7 ambele
   pagini — chat/magazin și onboarding — sunt aproape negre (`#080B12`). Deci
   între două ecrane întunecate apare o jumătate de secundă de cyan-magenta la
   saturație maximă. Nu e o tranziție, e un blitz. Exact „un gradient care nu mai
   e disponibil": culoarea nu mai aparține nicăieri în jurul ei.

   PRIMELE PRINCIPII. O cortină de navigare are un singur rol: să acopere
   schimbarea de pagină fără să atragă atenția asupra ei. Dacă o observi, a
   eșuat. Iar produsul are DEJA un limbaj de tranziție care face asta corect —
   vălul din landing → chat (`body.lp-leaving::before`): bază întunecată, cu o
   urmă de brand doar pe muchia care intră. Două limbaje diferite pentru același
   gest e o inconsecvență în sine.

   Deci nu inventăm nimic: aducem cortina spre onboarding în același limbaj.
   Bază `--bg`, brandul rămâne, dar ca lumină pe muchia de atac, nu ca perete.
   Plus o umbră care o face să pară că vine „peste", nu că apare din senin.
   ====================================================================== */
body[data-transitioning-to-onboarding]::before {
  background:
    /* muchia de atac: brandul, dar ca strălucire, nu ca suprafață */
    radial-gradient(120% 42% at 50% 100%, rgba(124, 92, 252, .38), transparent 62%),
    radial-gradient(90% 30% at 18% 100%, rgba(0, 194, 255, .22), transparent 58%),
    radial-gradient(90% 30% at 82% 100%, rgba(181, 33, 233, .22), transparent 58%),
    var(--bg, #080B12);
  box-shadow: 0 -24px 60px -12px rgba(124, 92, 252, .35);
  animation-duration: .42s;
}
/* Muchia de sus capătă o linie fină de brand — dă direcție mișcării, la costul
   unui singur pseudo-element în plus, și face ca „mătura" să se citească drept
   gest, nu drept dreptunghi. */
body[data-transitioning-to-onboarding]::after {
  content: ""; position: fixed; left: 0; right: 0; top: 0; height: 2px;
  z-index: 1000000; pointer-events: none;
  background: linear-gradient(90deg, #00C2FF, #7C5CFC 50%, #B521E9);
  transform-origin: 50% 0;
  animation: acxCurtainEdge .42s var(--ease-emph) both;
}
@keyframes acxCurtainEdge {
  from { transform: translateY(-100vh) scaleX(.2); opacity: 0; }
  60%  { opacity: 1; }
  to   { transform: none; opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
  body[data-transitioning-to-onboarding]::before { animation: none; }
  body[data-transitioning-to-onboarding]::after { display: none; }
}


/* =========================================================================
   11. CERCUL LUI ANDU ȘI BARA DE SCRIERE, puțin mai mari
   -------------------------------------------------------------------------
   Cerere directă: cercul cu 10-20% mai mare, bara „o idee" mai mare. Am ales
   +18% pe cerc (44 → 52px) și +2px pe înălțimea barei, cu textul la 15,5px.

   De ce +18% și nu +10%: la 44px, avatarul era mai mic decât butonul de meniu
   din colț (44px) — adică Andu cântărea vizual cât un buton de sistem. La 52px
   devine cel mai mare element din header, ceea ce e corect: el e subiectul.
   Peste ~56px ar începe să împingă titlul, care are nevoie de două rânduri.

   Bara: +2px înălțime și text de la 15 la 15,5px. Nu mai mult — bara e `fixed`
   și fiecare pixel al ei e luat din zona de conversație, care e mai valoroasă.
   ====================================================================== */
/* SCOS pentru 1:1 cu v7 (cerut explicit: „poza cu Andu este mai mare").
   Regula de aici avea și un defect de construcție, independent de mărime: dădea
   dimensiunea AMBELOR — wrapperului ȘI imaginii — deși wrapperul are `padding: 2px`.
   La 52px pe wrapper, cutia de conținut rămâne 48px, deci imaginea forțată la 52px
   ieșea din ea. MĂSURAT: wrapper 52×52, dar `<img>` 48×52 — fotografie întinsă pe
   verticală într-un decupaj rotund de 48px, iar inelul (`::before`, `inset: -3px`)
   fiind centrat pe wrapper, aura părea deplasată față de poză. Exact ce s-a raportat.

   v7 dimensionează DOAR imaginea (40×40) și lasă wrapperul să rezulte din
   `inline-flex` + padding → 44×44, perfect concentric (chat-v6.css:258-265).
   Dacă mărimea se dorește iar mai mare, se schimbă NUMAI `img`, niciodată wrapperul.

.up5-chat .chatroom-top-image,
.up5-chat .chatroom-top-image img {
  width: 52px; height: 52px;
}
.up5-chat .chatroom-top-image::before { inset: -3px; }
*/

/* Punctul verde „online" de pe avatar — 1:1 cu v7.
   CAUZA, sistemica: framework.bundle.css declara `*, ::before, ::after
   { box-sizing: border-box }`, adica INCLUDE pseudo-elementele. base-v6.css din
   replica il pune doar pe `*`, iar `*` NU prinde pseudo-elemente. Punctul are
   `width/height: 11px` + `border: 2.5px`, deci:
     · in replica (content-box): 11 + 2×2,5 = 16px vizual, la 28-29px de colt;
     · la noi (border-box):      11px vizual, la 33px de colt — mai mic si mai infundat.
   MASURAT: `inset` 29px vs 33px. Il readucem la constructia din replica.
   ATENTIE: aceeasi diferenta poate atinge orice pseudo-element din chat-v7.css
   dimensionat cu width/height + border. Asta e singurul gasit pana acum. */
.up5-chat .chatroom-top-image::after { box-sizing: content-box; }

/* SCOS pentru 1:1 cu v7 (raportat: „inputul e nejustificat de mare").
   MASURAT pe 1440x900: bara ajungea la 88px in loc de 60px — cu 28px mai inalta —
   fiindca `padding: 20px` uniform inlocuia padding-ul asimetric al v7
   (`6px 6px 6px 18px`, chat-v6.css:1047): +14px sus si +14px jos. Containerul
   crestea de la 85 la 113px, iar fontul scadea de la 16 la 15,5px.
   v7 are o singura definitie, fara suprascriere pe mobil, deci scotand-o revenim
   la valorile lui pe toate latimile.

.up5-chat .search-bar-container .input-bar { padding: 20px; }
.up5-chat .search-bar-container textarea,
.up5-chat .search-bar-container .input-bar textarea { font-size: 15.5px; }
*/

@media (max-width: 719.98px) {
  /* avatarul pe mobil: scos la fel, vezi nota de mai sus */
  /* padding-ul barei pe mobil: scos la fel, v7 nu are suprascriere aici */
}


/* =========================================================================
   12. URMA FORMULARULUI COMPLETAT (vezi `chat-patch2.js` F)
   -------------------------------------------------------------------------
   Chitanța trebuie să arate a ISTORIC, nu a card activ: fără inel gradient,
   fără umbră, fundal mai stins decât al mesajelor. Dacă ar arăta ca un card
   viu, utilizatorul ar încerca să o editeze.
   ====================================================================== */
.up5-chat .acx-form-receipt {
  margin-top: 10px;
  padding: 12px 14px;
  border: 1px dashed var(--card-bd);
  border-radius: var(--r-lg, 14px);
  background: rgba(255, 255, 255, .022);
  animation: acxRise .4s var(--ease-emph) both;
}
.up5-chat .acx-form-receipt-h {
  display: flex; align-items: center; gap: 7px;
  font-size: 12.5px; font-weight: 700; color: var(--fg-2, #B9BDC9);
}
.up5-chat .acx-form-receipt-h::before {
  content: "✓";
  display: inline-flex; align-items: center; justify-content: center;
  width: 16px; height: 16px; border-radius: 50%;
  background: rgba(52, 199, 132, .18); color: #4ADE9B;
  font-size: 10px; font-weight: 800; flex: 0 0 auto;
}
.up5-chat .acx-form-receipt-l {
  display: flex; flex-wrap: wrap; gap: 6px 8px; margin-top: 9px;
}
.up5-chat .acx-form-receipt-i {
  font-size: 12px; color: var(--muted);
  padding: 3px 9px; border-radius: 99px;
  background: rgba(255, 255, 255, .04);
  border: 1px solid var(--hairline, rgba(255, 255, 255, .06));
}
.up5-chat .acx-form-receipt-i b { color: var(--fg-2, #B9BDC9); font-weight: 600; }

@media (prefers-reduced-motion: reduce) {
  .up5-chat .acx-form-receipt { animation: none; }
}

/* =========================================================================
   13. MODALUL „ÎȚI TREBUIE CONT" (pisica) — încape pe un ecran de telefon
   -------------------------------------------------------------------------
   MĂSURAT la 390×844: containerul avea 767px, adică tot ecranul minus 77.
   Pe telefoane reale, mai scunde (375×667, 360×640), depășea și devenea
   derulabil — un modal de conversie nu are voie să-și ascundă butoanele.

   Ce consuma înălțimea, în ordine: imaginea 180×240 (cea mai mare bucată
   dintre toate), padding-ul de 34/28px al cardului, titlul de 24px.
   Reducerile de mai jos sunt DOAR pe mobil; pe desktop rămâne cum era.
   ====================================================================== */
@media (max-width: 719.98px) {
  /* imaginea: 180 → 120px lățime, deci ~240 → ~160px înălțime (raport 3:4).
     Cel mai mare câștig dintr-o singură valoare, fără să atingem conținutul. */
  #modal.modal-pop-up--create-account .modal__content img.asteptam,
  .popup-custom img.asteptam {
    max-width: 120px;
  }
  /* cardul: padding mai strâns, dar nu lipit de text */
  #modal .modal__wrapper {
    padding: 22px 18px 20px;
  }
  /* titlul: 24 → 21px; rămâne cel mai mare element de text */
  #modal .modal__content .font-bold.small-font-24 {
    font-size: 21px;
  }
  /* ritmul vertical dintre blocuri, o idee mai strâns */
  #modal .modal__content .small-margin-children-10 > * + * {
    margin-top: 7px;
  }
}

/* Ecrane SCUNDE (iPhone SE 375×667, Android 360×640): dupa reducerile de mai sus mai
   rămâneau 17-20px de derulare. Pragul e pe ÎNĂLȚIME, nu pe lățime — problema e
   verticală, iar pe telefoanele înalte imaginea nu are motiv să scadă mai mult. */
@media (max-width: 719.98px) and (max-height: 700px) {
  #modal.modal-pop-up--create-account .modal__content img.asteptam,
  .popup-custom img.asteptam {
    max-width: 96px;
  }
  #modal .modal__wrapper {
    padding: 18px 16px 16px;
  }
}

/* Sub 660px de înălțime (Android 360×640) mai rămâneau 12px. Nu le luăm din blocul de
   beneficii — acela e deja la 13,5px cu line-height 1,55, iar el poartă argumentele de
   conversie. Le luăm iar din imagine, singurul element decorativ. */
@media (max-width: 719.98px) and (max-height: 660px) {
  #modal.modal-pop-up--create-account .modal__content img.asteptam,
  .popup-custom img.asteptam {
    max-width: 84px;
  }
}

/* ---------------------------------------------------------------------------
   ȚINTA MORPH-ULUI, ASCUNSĂ PÂNĂ PORNEȘTE FLIP-UL
   `chat-patch2.js` (§B) rulează `defer`, deci abia DUPĂ ce browserul a desenat
   pagina o dată. Ținta apărea așezată la locul ei, apoi sărea la punctul de
   plecare al animației și abia apoi se mișca — „așezat, animat, așezat".
   Clasa e pusă înainte de primul desen de scriptul inline din `chat-v5.html.twig`,
   doar când chiar există un dreptunghi de predare din landing, și e scoasă de
   `elibereazaTinta()` pe ORICE drum (animație pornită, sărită, sau plasa de 2,5s).
   `visibility`, nu `display`: geometria rămâne calculabilă, iar FLIP-ul are nevoie
   de ea ca să măsoare unde trebuie să ajungă.
   ------------------------------------------------------------------------ */
html.acx-flip-pending .up5-chat .search-bar-container .input-bar,
html.acx-flip-pending .disclaimer-actions .button-disclaimer-accept {
  visibility: hidden;
}

/* ---------------------------------------------------------------------------
   POARTA COREGRAFIEI — îngheț la cadra ZERO până când pagina e gata.
   `data-anim-hold` e pus înainte de primul desen (scriptul inline din
   `chat-v5.html.twig`) și scos o singură dată, când `load` + `document.fonts.ready`
   s-au încheiat (sau la plafonul de 1500ms).

   DE CE MERGE: toate coregrafiile din §12 au `animation-fill-mode: both`. O animație
   în pauză la timpul 0, cu `both`, randează exact PRIMA cadră — deci elementele se
   încarcă în starea lor de început de animație (translate + opacity 0), nu în cea
   finală. Ceasul nu avansează cât e pauză, deci la eliberare toate pleacă de la 0
   real și în același timp. Fără asta, ceasul pornea la primul calcul de stil și mergea
   în timp ce fonturile și imaginile încă soseau — de unde „animația continuă dintr-o
   poziție aleatoare".

   Selectorii îi oglindesc pe cei din `chat-v7.css` §12; `animation-play-state` nu se
   moștenește, deci trebuie numite elementele animate, nu un strămoș.
   ------------------------------------------------------------------------ */
body[data-anim-hold] .chatroom-top,
body[data-anim-hold] .up5-chat .search-bar-container:not([data-hidden]),
body[data-anim-hold] .disclaimer-actions[data-active],
body[data-anim-hold] .acx-welcome,
body[data-anim-hold] .acx-shell,
body[data-anim-hold] .acx-card,
body[data-anim-hold] .acx-pills,
body[data-anim-hold] .acx-guest,
body[data-anim-hold] .up5-chat .input-bar::before,
body[data-anim-hold] .disclaimer-actions[data-active] .button-disclaimer-accept,
/* și cele două adăugate mai jos, pentru sosirea din landing — altfel ar porni
   singure la primul desen, cât restul stă în pauză, adică exact desincronizarea
   pe care poarta o elimină */
body[data-anim-hold] .up5-chat .js-messages-container,
body[data-anim-hold] .acx-mbtns,
/* suprafața barei de jos, mutată pe `::before` (vezi blocul de la finalul fișierului) */
body[data-anim-hold] .up5-chat .chat-suggestions,
body[data-anim-hold] .disclaimer-actions::before,
body[data-anim-hold] .up5-chat .search-bar-container:not([data-hidden])::before,
body[data-anim-hold] .disclaimer-actions .button-disclaimer-decline {
  animation-play-state: paused !important;
}
/* Sub „mișcare redusă" poarta nici nu se armează (vezi `chat-v5.html.twig`), deci
   `data-anim-hold` nu ajunge niciodată pe pagină acolo — nu e nevoie de contra-regulă. */

/* ---------------------------------------------------------------------------
   SOSIREA DIN LANDING: ÎNTÂI DOAR ELEMENTUL CARE SE MORFEAZĂ, APOI PAGINA.
   -----------------------------------------------------------------------------
   CE ERA. Coregrafia de intrare pornea odată cu morph-ul: bara de sus la 0,05s,
   meniul la 0s, hero-ul la 0,3s — iar cardul de disclaimer, fiind randat de server,
   nu era animat deloc, deci se vedea din prima cadră. Rezultatul: pagina apărea
   întreagă, și abia peste ea răsărea butonul zburând. Citit ca „s-a încărcat pagina,
   apoi a apărut ceva din senin", nu ca o continuare a landing-ului.

   CE FACEM. Pe sosirea din landing (`data-anim-handoff`) singurul element care se
   mișcă la început e ținta morph-ului — pastila de căutare devine butonul de acord
   sau bara de scriere. Tot restul intră DUPĂ ce ea aterizează (FLIP = 0,58s).

   Nu rescriem coregrafia, doar îi mutăm plecarea: `animation-delay` e proprietate
   separată, deci schimbarea ei păstrează animația, curba și durata din chat-v7.css.
   Ordinea dintre elemente se păstrează, doar decalată în bloc.

   TOATE plecările sunt DUPĂ 0,58s — durata FLIP-ului (`--flip-dur`). Prima versiune
   le punea la 0,5s, adică peste ultimii 80ms ai morph-ului: se vedea cum restul
   paginii începe să apară în timp ce butonul încă zboară. Acum ținta chiar aterizează
   întâi, și abia apoi începe restul.
   ------------------------------------------------------------------------ */
body[data-anim-handoff] .chatroom-top { animation-delay: .6s; }
body[data-anim-handoff] .acx-shell    { animation-delay: .6s; }
body[data-anim-handoff] .acx-card     { animation-delay: .72s; }
body[data-anim-handoff] .acx-pills    { animation-delay: .8s; }
body[data-anim-handoff] .acx-guest    { animation-delay: .88s; }
body[data-anim-handoff] .acx-welcome  { animation-delay: .9s; }

/* Suprafața conversației (inclusiv cardul de disclaimer randat de server) nu avea
   nicio animație de intrare — de aceea se vedea din prima cadră. Îi dăm una, doar
   pe opacitate: `.js-messages-container` e zona care derulează, iar un `transform`
   pe ea ar muta și poziția de scroll în timpul animației. */
body[data-anim-handoff] .up5-chat .js-messages-container {
  animation: acxApareDupaMorph .45s var(--ease-out) .88s both;
}
/* Burgerul mobil stă în afara `.acx-shell`, deci scăpase de coregrafie și rămânea
   vizibil singur în colț cât timp restul era ascuns. */
body[data-anim-handoff] .acx-mbtns {
  animation: acxApareDupaMorph .4s var(--ease-out) .6s both;
}
@keyframes acxApareDupaMorph {
  from { opacity: 0; }
  to   { opacity: 1; }
}

/* ---------------------------------------------------------------------------
   BARA CARE ȚINE BUTONUL — apare ODATĂ CU mișcarea lui, nu înaintea ei.
   -----------------------------------------------------------------------------
   DE CE scăpase de poartă: bara nu intră printr-o ANIMAȚIE, ci printr-o TRANZIȚIE
   declanșată de motor când îi pune `data-active` (chat-v7.css:3203 / 2811).
   `animation-play-state: paused` nu atinge tranzițiile, deci bara aluneca în sus și
   era complet vizibilă cu mult înainte ca poarta să se deschidă. Pe ecran se vedea
   bara plină, cu butonul zburând prin ea — exact invers față de ce trebuie.

   DE CE nu putem pur și simplu să stingem bara: butonul care se morfează e COPILUL
   ei. `opacity: 0` pe bară l-ar stinge și pe el, adică tocmai singurul lucru care
   trebuie văzut.

   SOLUȚIA: îi mutăm suprafața (fundal, blur, linia de sus) pe un `::before` și
   stingem doar pseudo-elementul. Butonul, fiind copil normal, rămâne neatins.
   `z-index: -1` îl ține sub conținut; bara are `z-index` propriu, deci creează
   context de stivuire și pseudo-elementul nu poate coborî sub ea.

   Pornește la 0,12s — după ce butonul s-a urnit, cum trebuie — și se termină la
   0,52s, cu puțin înainte de aterizare (0,58s), ca bara să fie deja acolo când
   butonul se așază în ea.
   ------------------------------------------------------------------------ */
/* FĂRĂ `[data-active]`, deliberat. Atributul e pus de MOTOR, deci abia după primul
   desen — dar bara e forțată vizibilă din prima cadră mai sus în fișier
   (`html.chat-pre-disclaimer .disclaimer-actions { opacity: 1 }`, ca instantaneul
   morph-ului să nu prindă un element transparent). Legând regulile de `[data-active]`,
   ele începeau să se aplice abia când sosea motorul — deci bara apărea întreagă, apoi
   se stingea, apoi revenea odată cu butonul. Exact clipirea raportată. */
body[data-anim-handoff] .disclaimer-actions,
body[data-anim-handoff] .up5-chat .search-bar-container:not([data-hidden]) {
  background: transparent;
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border-top-color: transparent;
}
body[data-anim-handoff] .disclaimer-actions::before,
body[data-anim-handoff] .up5-chat .search-bar-container:not([data-hidden])::before {
  content: "";
  position: absolute;
  inset: -1px 0 0;
  z-index: -1;
  pointer-events: none;
  background: rgba(8, 11, 18, 0.82);
  -webkit-backdrop-filter: blur(14px) saturate(1.2);
  backdrop-filter: blur(14px) saturate(1.2);
  border-top: 1px solid var(--hairline);
  animation: acxApareDupaMorph .32s var(--ease-out) .26s both;
}
/* Butonul X („refuz") e COPIL al barei, deci suprafața mutată pe `::before` nu-l
   acoperea — rămânea vizibil din prima cadră și trăda conturul barei chiar dacă
   fundalul ei era stins. Intră odată cu suprafața.
   Perechea din bara de scriere nu are nevoie de asta: acolo ținta morph-ului
   (`.input-bar`) e îngropată în grila barei, deci n-are frați vizibili la același
   nivel pe care să-i putem stinge fără s-o stingem și pe ea. */
body[data-anim-handoff] .disclaimer-actions .button-disclaimer-decline {
  animation: acxApareDupaMorph .32s var(--ease-out) .26s both;
}
/* ═══════════════════════════════════════════════════════════════════════════
   PATCH 3 — se adaugă la SFÂRȘITUL lui public/assets/css/routes/chat-patch2.css
   (obligatoriu DUPĂ blocul „POARTA COREGRAFIEI", altfel pierde la ordine)
   ═══════════════════════════════════════════════════════════════════════════ */

/* ---------------------------------------------------------------------------
   EXCEPȚIE LA POARTĂ — obiectul urmărit de ochi nu are voie să fie înghețat.

   `data-anim-hold` pune `animation-play-state: paused !important` pe lista de
   elemente din coregrafie, iar butonul de acord și bara de scriere sunt în acea
   listă. Cât timp poarta e închisă, morph-ul pornit inline (vezi patch-ul din
   `chat-v5.html.twig`) era pus în pauză odată cu restul — adică exact ce nu
   trebuie: el e singurul lucru care are voie să se miște în intervalul ăla.

   Regula asta îl lasă să meargă. Restul paginii rămâne înghețat până la poartă,
   ceea ce e chiar intenția scrisă la blocul „SOSIREA DIN LANDING" de mai sus:
   „întâi doar elementul care se morfează, apoi pagina".

   DE CE TREI SELECTORI. Blocul de pauză urcă până la specificitate (0,4,1)
   (`body[data-anim-hold] .disclaimer-actions[data-active] .button-disclaimer-accept`).
   Cu `!important` de ambele părți, la specificități diferite câștigă tot cea mai
   specifică — deci un singur selector scurt ar putea pierde în clipa în care
   motorul pune `data-active`. Primii doi urcă la (0,5,1) și acoperă exact cele
   două ținte posibile ale morph-ului; al treilea rămâne pentru orice altceva.
   E același tipar folosit la blocul de specificitate de mai sus în fișier.
   ------------------------------------------------------------------------ */
body[data-anim-hold] .disclaimer-actions[data-active] .button-disclaimer-accept.acx-flip-target,
body[data-anim-hold] .up5-chat .search-bar-container:not([data-hidden]) .input-bar.acx-flip-target,
body[data-anim-hold] .acx-flip-target {
  animation-play-state: running !important;
}

/* ---------------------------------------------------------------------------
   1. SUGESTIILE DE CHAT — intră cu pagina, nu în timpul morph-ului.
   -----------------------------------------------------------------------------
   Pe sosirea din landing a unui utilizator care a acceptat deja disclaimerul, ținta
   morph-ului e bara de scriere. MĂSURAT pe ruta reală: la 221ms de la pornirea
   morph-ului, sugestiile erau deja pe ecran, iar bara zbura peste ele.

   DE CE scăpaseră: ele nu apar printr-o ANIMAȚIE, ci printr-o TRANZIȚIE pe
   `opacity`/`transform`, declanșată când motorul pune `data-active`
   (chat-v7.css:3007-3013). Poarta oprește `animation-play-state`, care nu atinge
   tranzițiile — aceeași scăpare ca la suprafața barei de jos.
   Le dăm o animație proprie, pornită după aterizare, ca restul paginii.
   ------------------------------------------------------------------------ */
body[data-anim-handoff] .up5-chat .chat-suggestions {
  animation: acxApareDupaMorph .4s var(--ease-out) .88s both;
}

/* ---------------------------------------------------------------------------
   2. GLOW-UL BUTONULUI DE ACORD — încadrat, ca să nu mai fie retezat.
   -----------------------------------------------------------------------------
   `.cta--background-gradient` are `box-shadow: 0 12px 28px -6px` — un halou împins
   12px în JOS. MĂSURAT: butonul se termină la y=679, glow-ul ajunge la y=713, iar
   ecranul are 693 — deci **20px din el cad sub marginea de jos**. Sub buton există
   doar 14px de bară, fiindcă bara e `position: fixed; bottom: 0`.
   Efectul e exact cel raportat: haloul pare urcat (i se vede doar jumătatea de sus)
   și se termină într-o linie dreaptă, ca o cutie.

   Reparația îl centrează și îl strânge, ca să încapă în cei 14px. Umbra închisă
   (`0 2px 8px`) rămâne — ea oricum se încadra. Regula e scopată DOAR pe butonul
   ăsta: `.cta--background-gradient` e folosit și pe landing și în magazin, unde are
   loc sub el și arată corect.
   ------------------------------------------------------------------------ */
.disclaimer-actions .button-disclaimer-accept.cta--background-gradient,
.disclaimer-actions .button-disclaimer-accept.cta--background-gradient:hover {
  box-shadow:
    0 2px 8px rgba(0, 0, 0, 0.3),
    0 0 20px -4px rgba(124, 92, 252, 0.55);
}

/* Textul butonului de acord, tăiat jos pe iOS. `.font-gradient` pune
   `-webkit-background-clip: text`, iar regula care îl anulează pe buton
   (chat-v7.css:3247) schimbă doar culoarea și `text-fill-color`, nu și decuparea.
   Cu `background: none` + decupare pe text, WebKit poate reteza coborâtoarele.
   Anulăm și decuparea. */
.button-disclaimer-accept .font-gradient {
  -webkit-background-clip: border-box;
  background-clip: border-box;
}

/* ---------------------------------------------------------------------------
   SPAȚIEREA CONVERSAȚIEI — mai strânsă, cerut.
   Valorile v7 (gap 18px între bule, `line-height: 1.6` în ele) sunt identice cu
   replica, deci nu erau o abatere — dar pe ecran citesc aerisit. Strângem ambele
   pârghii, fiindcă distanța percepută între „liniile de chat" vine din amândouă:
   spațiul dintre bule ȘI înălțimea rândului dinăuntru.
   Bula de disclaimer NU se atinge: are propriul ritm de lectură, iar textul e lung.
   ------------------------------------------------------------------------ */
.up5-chat .js-messages-container {
  gap: 13px;
}
.up5-chat .message:not(.message-assistant-disclaimer) {
  line-height: 1.5;
}
.up5-chat .message:not(.message-assistant-disclaimer) p + p,
.up5-chat .message:not(.message-assistant-disclaimer) p + ul,
.up5-chat .message:not(.message-assistant-disclaimer) ul + p {
  margin-top: 7px;
}

/* ---------------------------------------------------------------------------
   BULELE SCURTE SE RUPEAU LA MIJLOCUL CUVÂNTULUI („sal / ut", raportat).
   `chat-v7.css:1234` pune `word-break: break-word` pe bulă. Proprietatea NU e
   sinonimă cu `overflow-wrap: break-word`: prin definiție se comportă ca
   `word-break: normal` + `overflow-wrap: anywhere`, iar `anywhere` **intră în
   calculul dimensiunii intrinseci** — min-content devine lățimea celui mai lat
   CARACTER. Bula e dimensionată shrink-to-fit (containerul are `align-self`,
   deci nu se întinde), așa că motorul are voie s-o strângă până la un caracter,
   deși pe rând mai era loc berechet.
   `overflow-wrap: break-word` rupe la fel cuvintele care chiar nu încap (URL-uri
   lungi), dar NU afectează dimensiunea intrinsecă — deci bula se întinde cât
   textul, iar ruperea rămâne doar ca plasă.
   ------------------------------------------------------------------------ */
.up5-chat .message {
  word-break: normal;
  overflow-wrap: break-word;
}

/* ---------------------------------------------------------------------------
   CAPUL CONVERSAȚIEI — trei reglaje cerute.
   MĂSURAT înainte: bară 57px, avatar 40px, nume 15,5px, status 12,5px, buton de
   meniu 44px cu centrul la 31px față de centrul barei la 28 (3px mai jos) și la
   12px de marginea dreaptă, față de 14px cât are avatarul în stânga.
   ------------------------------------------------------------------------ */

/* 1. Bara „Andu AI / scrie", o idee mai mare — DOAR prin conținut, nu prin padding.
      Prima încercare mărea și `padding` pe `.grid-x`: bara sărea de la 57 la 85px,
      adică +50%, mult peste „o idee". Cu avatarul și textul mărite, bara crește
      singură cât trebuie. */
/* Avatarul se mărește prin IMAGINE, nu prin cutie. Inelul colorat E chiar
   `padding: 2px` peste `background: var(--grad)` de pe container, iar imaginea are
   la rândul ei `border: 2px solid var(--bg)`. Fixând lățimea containerului la 44px
   forțam un conținut de 48px într-o cutie de 44 — inelul se strivea inegal, exact
   „border-ul nu e uniform/centrat". Lăsăm containerul să se dimensioneze singur. */
.up5-chat .chatroom-top-image img {
  width: 44px;
  height: 44px;
}
@media (max-width: 719.98px) {
  .up5-chat .chatroom-top-image img {
    width: 40px;
    height: 40px;
  }
}
.up5-chat .chatroom-top .font-bold.large-font-18 {
  font-size: 16.5px;
}
.up5-chat .chatroom-top [data-js="chatroom-top-message"] {
  font-size: 13px;
  height: 16px !important;
}

/* 2. Butonul de meniu, încadrat: centrat pe bară și la aceeași distanță de
      margine ca avatarul în partea cealaltă. Bara devine 65px cu punctul 1,
      deci (65 − 44) / 2 ≈ 10px. */
@media (max-width: 1023.98px) {
  .acx-mbtns {
    /* bara are 71px sub 720px si 79px peste (dupa respiroul dat aurei) — butonul are
       44px, deci centrul cere top 8, respectiv 12 */
    top: calc(13px + env(safe-area-inset-top, 0px));
    right: 14px;
  }
}
@media (min-width: 720px) and (max-width: 1023.98px) {
  .acx-mbtns {
    top: calc(17px + env(safe-area-inset-top, 0px));
  }
}

/* 3. Aura de scriere se stinge lin, nu dintr-o dată.
      Era `transition: opacity .6s` — dar inelul se rotește continuu, așa că la
      stingere se vedea mai degrabă o tăietură decât o așezare. Adăugăm și o
      relaxare de scară: cercul „se retrage", nu dispare. */
.up5-chat .chatroom-top-image::before {
  transition:
    opacity 0.9s var(--ease-out),
    transform 0.9s var(--ease-out);
  transform: scale(0.94);
}
.up5-chat .chatroom-top-image[data-active]::before {
  transition:
    opacity 0.3s var(--ease-out),
    transform 0.45s var(--ease-emph);
  transform: scale(1);
}

/* ---------------------------------------------------------------------------
   MENIUL DIN CHAT, DESCHIS PE MOBIL — conținutul urcă, logo-ul la fel ca pe LP.
   MĂSURAT: `.acx-shell` are `padding-top: calc(64px + safe-area)`, rezervat
   pentru burgerul fixat sus. Dar burgerul stă sus-DREAPTA (8→52px), iar logo-ul
   sus-STÂNGA — nu se ating pe orizontală, deci cei 64px erau spațiu gol. Logo-ul
   începea la 77px, primul element de meniu la 141px.
   Cu 14px, capul meniului se aliniază pe aceeași linie cu burgerul, ca pe LP.
   Logo-ul: 124px aici, 120px pe LP după micșorare — le facem identice.
   ------------------------------------------------------------------------ */
@media (max-width: 1023.98px) {
  .acx-shell {
    /* 3px, nu 14: X-ul e fix, cu centrul la 30px (8 + 44/2). Logo-ul are 29px, deci
       trebuie sa inceapa la ~15,5px ca centrele sa coincida. MASURAT: marginea de sus
       a logo-ului = padding-ul asta + 13px. */
    padding-top: calc(8px + env(safe-area-inset-top, 0px));
  }
  .acx-brand svg {
    width: 120px;
    height: auto;
  }
}

/* ---------------------------------------------------------------------------
   X-ul ȘI LOGO-UL, PE ACEEAȘI LINIE CÂND MENIUL E DESCHIS.
   Butonul e `position: fixed`, deci are o singură poziție — dar are DOUĂ contexte:
     · meniu închis → plutește peste capul conversației (61px), centru la 30px;
     · meniu deschis → capul conversației e acoperit, iar reperul devine logo-ul
       din meniu, al cărui centru e la 42px (14px padding pe shell + 13px până la
       logo + 29/2).
   MĂSURAT: 12px diferență, exact cât se vede în captură. Îl coborâm doar în
   starea deschisă: 42 − 44/2 = 20px.
   ------------------------------------------------------------------------ */
/* CORECTAT: nu X-ul se mută, ci logo-ul urcă la el (vezi padding-ul de pe
   `.acx-shell` de mai sus). Un buton care sare la deschiderea meniului se citește
   ca o eroare, chiar dacă ajunge într-un loc corect. */

/* ---------------------------------------------------------------------------
   Ultimul reglaj de aliniere, pus la FINAL intentionat: blocul `max-width: 1023.98px`
   de mai sus fixeaza `padding-top: 3px` pe shell, iar o regula cu acelasi rang pusa
   inainte pierde la ordine. Aici castiga.
   Intre 720 si 1024px bara e 69px (avatar 48), deci X-ul sta cu 4px mai jos; logo-ul
   il urmeaza cu aceiasi 4px, ca centrele sa coincida ca pe telefon.
   ------------------------------------------------------------------------ */
@media (min-width: 720px) and (max-width: 1023.98px) {
  .acx-shell {
    padding-top: calc(12px + env(safe-area-inset-top, 0px));
  }
}

/* ---------------------------------------------------------------------------
   AURA AVATARULUI din capul conversației era lipită de marginea de sus.
   MĂSURAT: avatarul 8→52 într-o bară de 61px; aura are `inset: -3px` plus
   `blur(4px)`, deci ajunge la y=1 pe o bară care începe la y=0 — un singur pixel
   de joc. Vizual se citește ca tăiată, și ca descentrată, fiindcă sub avatar
   rămâne mai mult loc decât deasupra.
   Adăugăm 5px de respiro simetric pe rândul din bară: aura capătă ~6px deasupra,
   iar avatarul redevine centrat pe verticală. Bara crește de la 61 la 71px.
   ------------------------------------------------------------------------ */
.up5-chat .chatroom-top .grid-x {
  padding: 5px 0;
}

/* ---------------------------------------------------------------------------
   HERO-UL DE CHAT GOL, CENTRAT CU ADEVĂRAT.
   Regula v7 centrează cu `justify-content: center` într-o cutie de
   `calc(--screen-height - 400px)`. MĂSURAT pe 844px: cutia iese 444px, dar zona
   liberă dintre capul conversației (jos la 71) și sugestii (sus la 587) e de
   516px — deci hero-ul se centra într-o cutie mai mică decât spațiul real și
   ieșea cu 28px mai sus decât mijlocul.
   Rezerva corectă e suma a ce ocupă marginile: bara 71 + sugestiile 169 + bara de
   scriere 85 = 325px, plus 18px de ajustare fina masurata pe ecran (343). Se aplică pe amândouă regulile de centrare — cea din v7 și
   cea pentru starea de după acceptarea disclaimerului.
   ------------------------------------------------------------------------ */
.up5-chat .js-messages-container[data-empty]:not(:has(.message-container)),
html.chat-pre-composer .up5-chat .js-messages-container[data-empty]:not(:has(.message-container:not([data-disclaimer-static]))) {
  min-height: calc(var(--screen-height) - 343px);
}

/* ---------------------------------------------------------------------------
   BARA DE SCRIS, PREA SUS DEASUPRA TASTATURII (iOS).
   Bara e `position: fixed; bottom: 0` cu
   `padding-bottom: calc(12px + env(safe-area-inset-bottom))`. iOS urcă singur
   elementele fixate deasupra tastaturii — dar continuă să raporteze inset-ul de
   jos (bara de gesturi, ~34px), deși cu tastatura deschisă acolo nu mai e nicio
   bară de gesturi. Rezultatul e un spațiu gol între casetă și tastatură.
   Cât timp se scrie, renunțăm la rezerva aceea; revine la pierderea focusului.
   ------------------------------------------------------------------------ */
.up5-chat .search-bar-container:has(textarea:focus),
.up5-chat .search-bar-container:has(input:focus) {
  padding-bottom: 12px;
}

/* ---------------------------------------------------------------------------
   ÎNĂLȚIMEA DE ECRAN: `svh`, nu `vh`.
   -----------------------------------------------------------------------------
   `framework.bundle.js:1585` scrie `--screen-height = window.innerHeight + 'px'`
   ca stil INLINE pe `<html>`. Pe telefon asta e înălțimea cu bara de adrese
   retrasă — adică viewportul MARE. Containerele dimensionate cu ea ies mai înalte
   decât zona vizibilă, deci ultimele mesaje cad sub margine și par tăiate; ca să
   le vezi trebuie să derulezi tu, deși n-ai făcut nimic care să ceară asta.
   Exact ce se raportează la primul mesaj trimis.

   `svh` e viewportul MIC (cu bara de adrese pe ecran) — cel garantat vizibil.
   Am ales `svh`, nu `dvh`, tocmai ca să NU se redimensioneze sub degete în timp
   ce derulezi: valoarea rămâne fixă, layoutul nu tresare.

   `!important` e necesar și suficient: o declarație importantă dintr-o foaie bate
   un stil inline neimportant, deci nu trebuie atins framework-ul, care e folosit
   de tot site-ul. Prima linie e rezerva pentru browserele fără `svh` — acolo a
   doua declarație e ignorată și rămâne comportamentul de azi.
   ------------------------------------------------------------------------ */
:root {
  --screen-height: 100vh !important;
  --screen-height: 100svh !important;
}

/* ---------------------------------------------------------------------------
   AVATARUL DIN HERO — halou tăiat pe iOS/Safari.
   `chat-v7.css:1481` folosește `filter: drop-shadow(0 10px 30px …)`. `filter` cere
   o suprafață proprie de randare, iar WebKit îi calculează marginile din cutia
   elementului: haloul coboară 40px (10 offset + 30 blur) sub un element de 73px,
   iar pe `display: inline-flex`, într-un context de linie, partea de jos e tăiată.
   Pe Blink nu se vede, fiindcă acolo regiunea filtrului e extinsă altfel.

   `drop-shadow` are sens când umbra trebuie să urmeze transparența conținutului.
   Aici nu e cazul: elementul e un CERC OPAC — fundal în gradient, `border-radius:
   50%`, cu o imagine care îl umple. `box-shadow` urmează raza de colț și dă exact
   același rezultat vizual, fără suprafață de filtru și fără nimic de tăiat.
   ------------------------------------------------------------------------ */
.acx-welcome .acx-w-av {
  filter: none;
  box-shadow: 0 10px 30px rgba(124, 92, 252, 0.35);
}

/* ---------------------------------------------------------------------------
   BARA DE JOS ȘI TASTATURA — NU COMPENSĂM.
   -----------------------------------------------------------------------------
   Aici a existat o compensare proprie: măsuram din `visualViewport` cât acoperă
   tastatura și ridicam bara cu `bottom: var(--kb-offset)`. A fost o greșeală și
   e scoasă de tot, împreună cu partea de JS care scria variabila.

   Motivul: și iOS, și Android ancorează SINGURE elementele `position: fixed` la
   marginea de jos a visual viewportului cât timp tastatura e deschisă. `bottom: 0`
   e deja corect. Compensarea noastră se adăuga peste a lor, așa că bara urca de
   două ori și rămânea la mijlocul ecranului, cu o bandă goală sub ea — iar la
   derulare `offsetTop` se schimba, noi rescriam variabila, browserul își rescria
   ancorarea, și bara rămânea desprinsă de tastatură.

   Dar nici `bottom: 0` nu e de ajuns, și de aceea urmează secțiunea de mai jos.
   ------------------------------------------------------------------------ */


/* ---------------------------------------------------------------------------
   FEREASTRA APLICAȚIEI URMEAZĂ VISUAL VIEWPORTUL (mobil).
   -----------------------------------------------------------------------------
   De ce se putea „derula în gol": pe iOS tastatura NU micșorează layout
   viewportul — rămâne 844px — se micșorează doar zona vizibilă, la ~508px. iOS
   te lasă apoi să PLIMBI fereastra de 508 peste suprafața de 844. Deci chiar cu
   zero derulare de document ai ~336px de suprafață pe care gliseZI, și e goală
   pentru că acolo nu mai există conținut. Iar `bottom: 0` pune bara la baza
   celor 844, nu la baza celor 508 vizibili — de aici banda goală.

   Ce facem: pagina devine EXACT fereastra vizibilă și o urmează oriunde o
   plimbă Safari.
     · `height: var(--app-h)`  = `visualViewport.height` → cât e vizibil;
     · `translateY(var(--vv-top))` = `visualViewport.offsetTop` → unde e vizibil.

   A DOUA parte e cea care lipsea la încercarea trecută. Fără ea, body-ul rămânea
   ancorat la layout viewport, Safari plimba fereastra, iar aplicația ieșea de tot
   din ecran — ecran negru. Cu ea, bara ajunge fix pe tastatură și rămâne acolo
   orice ai trage, pentru că nu mai există suprafață în plus peste care să
   gliseze: pagina e cât fereastra.

   Derularea coboară în listă. ATENȚIE la structură: bara de scris NU e soră cu
   `.messages`, ci ultimul lui COPIL — deci `.messages` devine coloana, iar
   derularea intră în `.grid-x`. Dacă ar derula `.messages`, bara ar pleca în sus
   odată cu mesajele.

   Totul e condiționat de clasa `kb-fix`, pusă din `chat-patch2.js` DOAR dacă
   `visualViewport` există. Fără ea nu se schimbă absolut nimic — browserele
   vechi rămân pe comportamentul de acum.

   `transform` pe `body` face din el bloc de referință pentru descendenții
   `position: fixed` (`.acx-shell`, `.disclaimer-actions`). Aici e în avantajul
   nostru: se raportează la fereastra vizibilă, nu la layout.

   Compromis asumat: pe un ecran care nu derulează, Safari nu-și mai retrage bara
   de adrese — rămâne vizibilă, ca într-o aplicație instalată.
   ------------------------------------------------------------------------ */
@media (max-width: 1023px) {
  html.kb-fix {
    height: 100%;
    overflow: hidden;
    overscroll-behavior: none;
  }
  html.kb-fix body.acx-page {
    position: fixed;
    top: 0;
    left: 0;
    right: 0;
    bottom: auto;                /* `height` decide, nu `bottom` */
    width: 100%;
    height: var(--app-h, 100%);
    transform: translateY(var(--vv-top, 0px));   /* urmează fereastra vizibilă */
    overflow: hidden;
    overscroll-behavior: none;
  }

  /* MĂSURAT: între `body` și coloana de chat stă un `div.up5acc` cu înălțime din
     conținut. Fără `height: 100%` aici, procentele de mai jos se raportează la
     `auto`, coloana rămâne cât conținutul și bara nu urcă deloc. */
  html.kb-fix body.acx-page > .up5acc {
    height: 100%;
  }
  /* `min-height` venea din `calc(var(--screen-height) - 0px)`, adică ecranul
     ÎNTREG — ar fi împins bara sub tastatură oricât am strânge `--app-h` */
  html.kb-fix body.acx-page .up5acc-content {
    height: 100%;
    min-height: 0;
  }
  html.kb-fix body.acx-page .up5-chat {
    min-height: 0;
  }

  html.kb-fix body.acx-page .up5-chat > .messages {
    display: flex;
    flex-direction: column;
    flex: 1 1 auto;
    min-height: 0;
    padding-left: 0;             /* mutat pe zona derulabilă, ca bara să rămână */
    padding-right: 0;            /* pe toată lățimea, ca înainte */
    padding-bottom: 0;           /* cei 148px țineau loc barei fixe; nu mai e cazul */
  }
  html.kb-fix body.acx-page .up5-chat > .messages > .grid-x {
    flex: 1 1 auto;
    min-height: 0;
    height: auto;                /* `.full-height` ar cere toată coloana, fără bară */
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;
    padding: 0 20px 12px;
  }

  /* din element fix, în ultimul element al coloanei — nu are cum să se miște */
  html.kb-fix body.acx-page .up5-chat .search-bar-container {
    position: relative;
    left: auto;
    right: auto;
    bottom: auto;
    flex: 0 0 auto;
  }
}
