/* ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ TEMA „CARBON-GRAFIT" — SINGURA FOAIE DE STIL A PRODUSULUI.                            ║
   ║                                                                                       ║
   ║ ⭐ CERUTĂ DE NELU (01.09.2026, aleasă din machete): bară #161616, fila activă          ║
   ║ subliniată albastru, conținut pe alb-cald, pastile de stare, cifre tabulare aliniate  ║
   ║ la dreapta. Plus MOD ÎNTUNECAT, cu comutator per utilizator.                           ║
   ╠══════════════════════════════════════════════════════════════════════════════════════╣
   ║ ⛔⛔ AICI E SINGURUL LOC DIN PRODUS ÎN CARE SE SCRIE O CULOARE.                        ║
   ║                                                                                       ║
   ║ Măsurat înainte de runda asta: 1 397 de culori scrise de mână, în 36 de foi de ecran, ║
   ║ pentru aceleași ~20 de roluri. Griul textului secundar avea patru valori, fondul      ║
   ║ paginii trei, verdele de „e bine" cinci. Nu erau alegeri — erau cifre copiate dintr-un║
   ║ ecran vecin și modificate cu un pas, fiecare la ea acasă.                              ║
   ║                                                                                       ║
   ║ Simptomul unei a doua liste de culori nu e că arată urât: e că un ecran arată ALTFEL  ║
   ║ decât vecinii lui, iar nimeni nu mai poate spune de ce. De aceea garda                 ║
   ║ `TestNicioCuloareInSabloane` refuză orice `#hex`, `rgb(` sau nume de culoare într-un   ║
   ║ `<style>` din Go. Un ecran NOU intră în temă fără să scrie o linie de culoare.          ║
   ╠══════════════════════════════════════════════════════════════════════════════════════╣
   ║ ⛔ ȘI E UN SISTEM, NU O LISTĂ DE CULORI (întărirea lui Nelu, 03.09.2026).              ║
   ║                                                                                       ║
   ║ Butoanele, cardurile, formularele, tabelele, pastilele, insignele, alertele, modalele ║
   ║ și filele se definesc AICI, o dată. Șabloanele le FOLOSESC, nu le redesenează: garda   ║
   ║ `TestNiciunSablonNuIsiDeseneazaComponentele` refuză un `.btn{…}`, un `table{…}` sau un ║
   ║ `input{…}` scris local. Consecința căutată: un ecran nou iese în temă din prima, fără  ║
   ║ CSS propriu — iar produsul are o identitate, nu doar culori schimbate.                  ║
   ╠══════════════════════════════════════════════════════════════════════════════════════╣
   ║ ⚠️ FONTURI DE SISTEM, DELIBERAT. IBM Plex / Inter erau permise (OFL), dar ar fi        ║
   ║ însemnat ~400 KB de binar în repo și o a doua descărcare pe fiecare pagină, într-un    ║
   ║ produs care trebuie să pornească într-o rețea fără internet — chiar motivul pentru     ║
   ║ care Leaflet e vendorat și nu luat de pe un CDN (vezi caseta din `harta_ecran.go`).    ║
   ║ Identitatea o dau spațierea, culorile și formele, nu numele fontului. Cifrele sunt     ║
   ║ TABULARE peste tot unde se compară pe verticală — asta se obține din                   ║
   ║ `font-variant-numeric`, care merge pe orice font de sistem.                             ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */

/* ══════════════════════════════════════════════════════════════════════════════════════
   1. VARIABILE — SETUL LUMINOS (implicit)
   ══════════════════════════════════════════════════════════════════════════════════════ */
:root {
  /* ---------- GRILA DE 8 px ----------
     Toate spațierile ies de aici. Cele două jumătăți de pas (4 și 12) există fiindcă
     spațiul dintre o etichetă și câmpul ei, sau dintre două pastile, e mai mic decât un
     pas întreg — iar alternativa (a le scrie de mână) e chiar felul în care s-au adunat
     cei 16 / 18 / 20 / 22 px de margine interioară de pe cardurile de dinainte. */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 48px;

  /* ---------- COLȚURI ----------
     Trei, nu opt: mic (semne, insigne), obișnuit (butoane, câmpuri, carduri) și pastilă. */
  --rot-mic: 4px;
  --rot: 8px;
  --rot-mare: 12px;
  --rot-pastila: 999px;

  /* ---------- ȚINTA DEGETULUI ----------
     ╔══════════════════════════════════════════════════════════════════════════════════╗
     ║ ⭐ 44 px, sub pragul de telefon — cerința lui Nelu (08.09.2026). Măsurat înainte:  ║
     ║ cel mai mic lucru apăsabil din produs avea **14 px** (butoanele Leaflet), iar ale ║
     ║ noastre 15–19 px. Pe un mouse asta merge; pe un deget, nu.                         ║
     ║ ⛔ NUMAI sub prag, dinadins: pe birou, 44 px pe fiecare legătură dintr-un tabel ar ║
     ║ fi umflat rândul de la 40 la 44+ și ar fi stricat chiar densitatea cerută la       ║
     ║ 30.08 („rânduri ~40 px, dens dar citibil"). Degetul e o problemă de ATINGERE, nu   ║
     ║ de mărime în absolut.                                                              ║
     ╚══════════════════════════════════════════════════════════════════════════════════╝ */
  --tinta: 44px;
  /* Sublinierea legăturii: subțire și puțin coborâtă, ca să nu taie codițele literelor. */
  --legatura-grosime: 1px;
  --legatura-departare: 0.2em;

  /* ---------- FÂȘIA DIN DREAPTA ----------
     ╔══════════════════════════════════════════════════════════════════════════════════╗
     ║ ⭐⭐ CÂT ȚINE PRODUSUL LIBER ÎN DREAPTA, SUB BARĂ (runda 20, 12.09.2026).          ║
     ║                                                                                   ║
     ║ De azi, căsuța de căutat de pe hartă stă în colțul DIN DREAPTA SUS — cerința lui  ║
     ║ Nelu, cu poză: în stânga sus se ciocnea cu butoanele de zoom, care sunt tot acolo.║
     ║ Dar pe dreapta se deschidea deja fereastra „Calc", lipită sub butonul ei din bară:║
     ║ măsurat la 12.09, ele se suprapuneau pe 56 px, și la 1024, și la 1400.            ║
     ║                                                                                   ║
     ║ ⛔ CIFRA ASTA E SINGURUL LOC ÎN CARE SE HOTĂRĂȘTE ÎMPĂRȚEALA. O citesc AMÂNDOUĂ:  ║
     ║   · foaia — căsuța de pe hartă își ia lățimea din ea (`.harta-cauta`);            ║
     ║   · `static/calc.js` — fereastra nu se mai deschide niciodată în fâșia asta.      ║
     ║ Scrise separat, cele două s-ar fi despărțit la prima lărgire a căsuței, iar       ║
     ║ despărțirea s-ar fi văzut doar cu calculatorul deschis — adică rar, și târziu.    ║
     ║                                                                                   ║
     ║ ⚠️ Cifra ține ÎNTREAGA fâșie: marginea de 10 px a controalelor Leaflet, căsuța, și ║
     ║ aerul dintre ea și fereastră. De aceea căsuța ia `fâșia − un pas mare`, nu toată  ║
     ║ fâșia. Că nu se suprapun se MĂSOARĂ, în `_dev-probe-cauta-harta.js`.               ║
     ╚══════════════════════════════════════════════════════════════════════════════════╝ */
  --fasia-dreapta: 344px;

  /* ---------- PRAGUL DE TELEFON ----------
     ⛔ Cifra e scrisă în interogările de media de mai jos (CSS n-o poate lua dintr-o
     variabilă acolo), dar STĂ ȘI AICI fiindcă JavaScript-ul are nevoie de ea: cardul de
     curs al hărții își hotărăște locul după ea. Până la 08.09.2026 el avea o cifră a lui,
     640 — iar pe o tabletă de 768 px cele două nu erau de acord, deci cardul plutea peste
     hartă pe un ecran care era deja în forma lui strâmtă. Un prag, un loc.
     ⚠️ Garda `TestPragulDeTelefonEUnulSingur` cere ca fiecare `@media (max-width: …)` din
     foaie să folosească exact cifra asta. */
  --prag-telefon: 820px;

  /* ---------- TELEFONUL ȚINUT PE LAT ----------
     ╔══════════════════════════════════════════════════════════════════════════════════╗
     ║ ⛔⛔ MĂSURAT LA 08.09.2026, SEARA: la 844×390 (iPhone 14 pe lat) pragul de LĂȚIME  ║
     ║ nu se aprinde — 844 > 820 — deci telefonul primea așezarea de BIROU pe un ecran   ║
     ║ de 390 px înălțime. Urmarea, văzută în probă: bara plus filtrele luau 156 px din  ║
     ║ 390, panoul de 452 px plutea peste hartă, iar legenda și cardul de curs rămâneau  ║
     ║ controale Leaflet, adică exact peste hartă. Poza lui Nelu arăta chiar asta.       ║
     ║                                                                                   ║
     ║ ⭐ „Mic" are DOUĂ măsuri, nu una: puțină lățime SAU puțină înălțime. A doua vine  ║
     ║ cu o limită de lățime, ca o fereastră de birou trasă scundă (1400×500) să NU      ║
     ║ primească așezarea de telefon: un telefon pe lat e mic pe amândouă laturile.      ║
     ║ ⚠️ Cele două cifre se citesc împreună; garda `TestPragurileSuntCeleDouaStiute` le ║
     ║ cere pe toate interogările foii.                                                  ║
     ╚══════════════════════════════════════════════════════════════════════════════════╝ */
  --prag-scund: 560px;
  --prag-scund-lat: 1024px;

  /* ---------- ÎNĂLȚIMEA UNUI ECRAN „CÂT FEREASTRA" ----------
     ╔══════════════════════════════════════════════════════════════════════════════════╗
     ║ ⛔ CE A TĂIAT CARDUL DE CURS LA MARGINEA DE JOS (08.09.2026, poza lui Nelu).      ║
     ║ Harta e singurul ecran „cât fereastra": `html, body { height: 100% }` plus o      ║
     ║ coloană flex. Pe birou e chiar ce trebuie — nimic nu derulează, harta ia restul.  ║
     ║ Pe telefon însă coloana primește, sub hartă, panoul punctului, legenda și cardul  ║
     ║ de curs; suma lor trece de fereastră, iar pagina **nu are voie să deruleze**,     ║
     ║ fiindcă `height` e fix. Ce nu încape se taie, tăcut.                               ║
     ║ ⭐ Sub prag înălțimea devine `auto`: pagina redevine o pagină și derulează. Ecranul║
     ║ nu-și scrie asta singur — cere `height: var(--inaltime-ecran)` și atât.           ║
     ╚══════════════════════════════════════════════════════════════════════════════════╝ */
  --inaltime-ecran: 100%;

  /* ---------- TIPOGRAFIE: O SINGURĂ FAMILIE ----------
     ⚠️ `--font-cod` NU e a doua familie de text: e pentru serii, id-uri publice și
     coduri, adică pentru șiruri care se citesc CARACTER cu caracter și în care „l" și
     „1" trebuie să se deosebească. */
  --font: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --font-cod: ui-monospace, SFMono-Regular, "Cascadia Mono", Consolas, monospace;

  --t-xs: 11px;    /* eticheta de deasupra unui câmp, capul de tabel */
  --t-mic: 12px;   /* adaosuri mărunte: seria de lângă model */
  --t-mic2: 13px;  /* explicații, note, filtre */
  --t-baza: 14px;  /* textul obișnuit, rândurile de tabel */
  --t-mare: 16px;  /* titlul unui card */
  /* ---------- TITLUL PAGINII: 21px → 28px (Nelu, 04.09.2026) ----------
     ⭐ Cerința, literal: „titluri de pagină uniformizate ȘI MĂRITE… mari, lizibile".
     UNIFORME erau deja — toate ecranele trec prin `banda`, deci prin acest singur token
     (măsurat pe zece pagini: 21px peste tot, inclusiv pe fișa aparatului). Ce lipsea era
     MĂRIMEA: la 21px, un titlu scurt („Mesaje") se citește ca titlu, dar unul lung
     („Xerox WorkCentre 5325 · 3526466216") se pierde în densitatea paginii — de-aia se
     vedeau ca fiind „mai mici" ecrane care aveau, la măsurătoare, exact aceeași cifră.
     ⛔ E UN SINGUR NIVEL, și trebuie să rămână unul: garda `TestTitlulPaginiiEUnulSingur`
     refuză un `<h1>` scris în afara benzii și orice `font-size` pus pe el într-un ecran. */
  --t-h1: 28px;    /* titlul paginii, în bandă — singurul nivel de titlu de pagină */
  --t-h2: 19px;    /* titlul unei ferestre din pagină (discuția cu clientul) */
  --t-cifra: 20px; /* o cifră care se citește de la doi metri */
  --t-cifra-mare: 24px; /* cifra care E pagina: contorul, restanța, luna facturată */

  --ritm: 1.5;     /* înălțimea rândului de text */

  /* --schema — în ce mod suntem, spus BROWSERULUI. Vezi regula de la `body`. */
  --schema: light;

  /* ---------- SUPRAFEȚE ----------
     „alb-cald" e chiar cerința: un alb pur pe toată pagina obosește, iar cardurile albe
     de deasupra lui nu s-ar mai deosebi de fond. */
  --fond: #f6f5f3;
  --fond-card: #ffffff;
  --fond-slab: #f0efec;   /* capul de tabel, zebra, butonul secundar */
  --fond-apasat: #e4e2de; /* butonul secundar sub deget */

  /* ---------- TEXT ---------- */
  --text: #161616;
  --text-slab: #525252;   /* explicații, etichete, capul de tabel */
  --text-stins: #767676;  /* adaosuri mărunte, text dezactivat */
  --text-pe-inchis: #f4f4f4;

  /* ---------- LINII ----------
     „borduri fine" (cerința): o linie de 1 px care se vede, nu o umbră care plutește. */
  --linie: #d8d5d0;
  --linie-slaba: #ebe9e5; /* între rândurile aceluiași tabel */

  /* ---------- ACCENT ----------
     ⚠️ `--accent` (legături, subliniere de filă, inel de focalizare) și `--buton-fond`
     sunt DOUĂ roluri, nu unul: în modul întunecat albastrul de legătură trebuie să se
     lumineze ca să rămână lizibil pe grafit, pe când butonul plin rămâne albastrul tare
     cu text alb. Un singur token le-ar fi legat, iar unul dintre cele două ar fi ieșit
     prost exact în modul pentru care nu a fost ales. */
  --accent: #0f62fe;
  --accent-tare: #0043ce;
  --accent-slab: #edf3ff;  /* fondul rândului selectat, al filei active */

  --buton-fond: #0f62fe;
  --buton-fond-hover: #0043ce;
  --buton-text: #ffffff;

  /* ---------- STĂRI: UN SINGUR SET DE FORME, CULOARE DOAR PE STARE ----------
     Cerința lui Nelu, literal. Fiecare stare are TREI valori și atât:
       -semn  = punctul, bara, marginea — culoarea „tare"
       -fond  = fondul pastilei / al alertei
       -text  = textul pe acel fond
     Formele (pastilă, punct, alertă) sunt aceleași pentru toate cinci; ce se schimbă de
     la o stare la alta e strict tripleta de mai jos. */
  --ok-semn: #198038;    --ok-fond: #dcf3e4;    --ok-text: #0e6027;
  --avert-semn: #b28600; --avert-fond: #fcf3d6; --avert-text: #6d5100;
  --rau-semn: #da1e28;   --rau-fond: #fde7e7;   --rau-text: #a2191f;
  --neutru-semn: #8d8d8d; --neutru-fond: #eceae6; --neutru-text: #525252;
  --info-semn: #0f62fe;  --info-fond: #edf3ff;  --info-text: #0043ce;
  /* ⚠️ MOV NU E O STARE, E O CATEGORIE. Pe ecranul de mapare a contoarelor două insigne
     trebuie să se deosebească între ele — „standard" (albastru) și „coloană de contoare"
     — iar amândouă sunt informative: niciuna nu spune că e bine sau rău. De aceea are un
     token propriu și nu se împrumută din cele cinci stări. E singurul; un al doilea ar
     însemna că vocabularul stărilor nu mai ajunge, și atunci se schimbă vocabularul. */
  --mov-fond: #f3e8fd; --mov-text: #6929c4;

  /* ---------- BARA DE SUS ----------
     #161616 e chiar cifra din machetă. Bara e ÎNTOTDEAUNA închisă, în amândouă modurile:
     e coaja produsului, nu o parte a paginii.
     ⛔ HOTĂRÂREA S-A REPUS ÎN DISCUȚIE ȘI S-A CONFIRMAT (Nelu, 14.09.2026): „bara rămâne
     coajă". Ce NU e coajă — comutatorul de vederi, care stă în pagină, sub bară, și balonul
     de pe hartă, care e conținut peste hartă — nu are voie să împrumute jetoanele de mai jos;
     vezi secțiunea comutatorului, după `.nr`, și pe a balonului, după `.probleme-rand`.
     ⛔ Cine le poate cere în afara barei e o listă ÎNCHISĂ, în `TestBalonulUrmeazaTemaNuBara`. */
  --bara-fond: #161616;
  --bara-text: #e8e8e8;
  --bara-text-tare: #ffffff;
  --bara-text-slab: #a8a8a8;
  --bara-hover: #2a2a2a;
  --bara-linie: #393939;
  --bara-panou: #262626;   /* submeniul care coboară */
  --bara-nr: #da1e28;      /* cifra „ai ceva de făcut" */
  --bara-nr-text: #ffffff; /* cifra de pe pastila roșie — aceeași pe zi și pe noapte */

  /* ---------- HÂRTIA ----------
     ⛔ NU SE SCHIMBĂ ÎN MODUL ÎNTUNECAT, și e chiar rostul tokenului: e albul pe care
     ajunge sigla dealerului când documentul lui se tipărește sau se deschide în portal.
     Previzualizarea din Setări → Firma îl folosește ca să arate sigla pe FUNDAL DESCHIS,
     lângă cea pe fundal închis (`--bara-fond`). Cu `--fond-card` — care se întunecă odată
     cu tema — dealerul care lucrează pe întuneric ar fi văzut două casete închise și ar
     fi crezut că sigla lui se citește pe hârtie fără s-o fi văzut niciodată acolo. */
  --hartie: #ffffff;

  /* ---------- BANDA DE TITLU ----------
     ⭐⭐ AICI SE REPARĂ „BANDA CONTOPITĂ CU MENIUL" (cerința 3 a rundei).
     Până azi banda era #1c2733 sub o bară #1c2733: două dreptunghiuri închise, lipite,
     din care ochiul nu putea citi unde se termină navigația și unde începe pagina.
     Acum banda e o SUPRAFAȚĂ DE PAGINĂ — deschisă, cu titlul în negru și o linie de
     bază — deci se desparte de coaja închisă de deasupra ei prin CONTRAST, nu printr-o
     nuanță cu doi pași diferență pe care n-o vede nimeni. */
  --banda-fond: #ffffff;
  --banda-text: #161616;
  --banda-text-slab: #525252;
  --banda-linie: #d8d5d0;

  /* ---------- UMBRE ----------
     Una singură, și doar pentru ce PLUTEȘTE (submeniu, modal). Cardurile se despart de
     fond printr-o linie, nu printr-o umbră: nouă umbre diferite pe nouă ecrane erau
     jumătate din diferența pe care o vedea omul între două pagini vecine. */
  --umbra-plutire: 0 12px 28px rgba(0, 0, 0, .18);
  /* A doua, și ultima: marginea coloanei de acțiuni LIPITE dintr-un tabel care derulează
     (§11). Nu e decor — e singurul semn că sub coloana aia mai e tabel. */
  --umbra-lipita: -8px 0 8px -8px rgba(0, 0, 0, .18);

  /* ---------- SCARA DE GRAVITATE A HĂRȚII ----------
     ⛔ CINCI TREPTE, ÎN ORDINE: roșu → portocaliu → galben → gri → verde. E scara din
     `nivelPunct` (harta.go), iar pinii, bulinele din balon, legenda și rândurile din
     vederea Listă o folosesc pe TOATE — două vocabulare de culoare în același produs ar
     face ca „galben" să însemne altceva pe două ecrane vecine.

     ⚠️ NU SE SCHIMBĂ ÎNTRE MODURI, și e o alegere: pinii stau pe DALE, iar dalele rămân
     deschise oricare ar fi modul. O scară care s-ar lumina în modul întunecat ar fi
     luminat exact pinii care stau pe fundalul care nu s-a schimbat.

     ⛔ PERECHILE `-clar` AU PLECAT (runda balonului, 14.09.2026), în afară de cea gri. Erau
     pentru balonul de hover, care stătea închis în amândouă modurile; de azi balonul urmează
     tema, iar bulinele lui sunt chiar cele din `.probleme-rand` — aceeași listă, aceleași
     vopsele. `--nivel-gri-clar` rămâne: e fondul de sub dale (hărțile care încă se încarcă). */
  --nivel-rosu: #b42318;
  --nivel-portocaliu: #d97706;
  --nivel-galben: #b58900;
  --nivel-gri: #6b7d8f;        --nivel-gri-clar: #9fb3c8;
  --nivel-verde: #1a7f37;
  /* Bulina clientului fără monitorizare: albastru, DINADINS în afara scării de gravitate
     — vezi caseta de la `.pin-client`. */
  --nivel-client: #1c66d6;

  /* ---------- CE STĂ PESTE DALE ----------
     ⛔ NU URMEAZĂ MODUL, și e o regulă, nu o scăpare: dalele hărții rămân deschise în
     amândouă modurile (nu le desenăm noi). Un card care s-ar întuneca peste ele ar fi o
     pată neagră pe o hartă albă, iar un text deschis ar deveni ilizibil.
     De aceea legenda, cardul de curs și pinii își iau culorile de aici — un set mic,
     constant, care spune limpede „asta stă peste hartă".
     ⛔ BALONUL NU MAI E ÎN GRUPA ASTA (runda balonului, 14.09.2026): el e o casetă de CITIT,
     deschisă de om, nu un semn pe hartă — deci urmează tema, ca orice card. Vezi secțiunea
     lui, după `.probleme-rand`. */
  --pe-pin: #ffffff;
  --umbra-pin: 0 1px 4px rgba(0, 0, 0, .4);
  --dale-carte: rgba(255, 255, 255, .94);
  --dale-text: #161616;
  --dale-text-slab: #525252;
  --dale-text-stins: #767676;
  --dale-camp: #ffffff;
  --dale-buton: #eef2f6;
  /* ⭐⭐ PINUL DE CĂUTARE (runda 18, 12.09.2026) — cel care cade pe o ADRESĂ găsită, nu pe
     un punct de lucru. ⛔ DINADINS ÎN AFARA SCĂRII DE GRAVITATE ȘI DEPARTE DE ALBASTRUL
     LOCULUI: roșul ar fi spus „cere intervenție", verdele „e în regulă", iar albastrul „un
     punct fără colector" — pinul ăsta nu e nicio stare, e răspunsul la ce a scris omul
     acum o clipă și dispare la golirea căsuței. ⛔ NU `--accent`: accentul se alege pe cont
     (cinci variante, una verde), deci pinul ar fi putut ieși exact în culoarea unei stări.
     ⚠️ Nu se schimbă între moduri, ca toată grupa asta: stă pe dale, iar dalele nu se
     întunecă. */
  --pin-cautat: #7c3aed;
  /* ⛔⛔ CELE DOUĂ CULORI DE VESTE ALE CĂUTĂRII DE PE HARTĂ — ȘI DE CE NU `--ok-text` /
     `--avert-text`. Acelea se SCHIMBĂ între moduri (verde închis → verde deschis, ca să
     rămână lizibile pe fondul paginii). Peste dale, care rămân albe în amândouă modurile, un
     text deschis ar fi devenit invizibil — chiar regula scrisă în capul grupei ăsteia. */
  --dale-ok: #0e6027;
  --dale-avert: #8a5a00;

  /* ---------- GRAFICE (cerința 4) ----------
     ⛔ PALETĂ FIXĂ, cerută pe cifre: albastru #2a78d6, portocaliu #eb6834, plus stările.
     ⚠️ NU sunt aceleași cu `--accent`: accentul e al interfeței (legături, butoane) și
     se schimbă între moduri ca să rămână lizibil, pe când seria unui grafic trebuie să
     fie ACEEAȘI culoare în amândouă modurile — altfel două capturi ale aceluiași grafic
     nu se pot compara. */
  --grafic-1: #2a78d6;
  --grafic-2: #eb6834;
  --grafic-grila: #e4e2de;
  --grafic-ax: #767676;
  --grafic-fond: #ffffff;

  /* ---------- CULORILE CONSUMABILELOR (08.09.2026; redenumite 3b, 09.09.2026) ----------
     ⭐ ERAU `--toner-*`. Redenumite la runda 3b, hotărârea lui Nelu: în tot produsul,
     „toner" numea o PIESĂ ANUME și ajunsese să numească toate piesele care se consumă.
     Jetoanele astea colorează bare care poartă azi și cilindri, și developer, și cuptor —
     deci numele lor spunea mai puțin decât aperă.
     ⛔ CLASELE `.toner`, `.toner-k`, `.toner-umplut` NU s-au atins: ele sunt scrise în
     șabloane (`kpi_aparat.go`, `card_aparat.go`) și sunt COD, nu text citit de nimeni —
     „nume noi, coduri vechi". Redenumirea cerută era a JETOANELOR.
     ⛔ NU sunt stări și n-au voie să intre în scara de gravitate: un toner cyan e cyan
     și plin, și gol. Sunt culoarea PIESEI, exact ca seriile unui grafic — de aceea stau
     aici, lângă ele, și nu lângă `--ok-*` / `--rau-*`.
     ⚠️ `--consumabil-k` e SINGURA care se schimbă în modul întunecat: negrul curat pe fond
     grafit nu se vede deloc, iar o bară invizibilă se citește ca „n-are toner". Restul
     rămân identice în ambele moduri, ca două capturi ale aceluiași aparat să se poată
     compara — aceeași regulă ca la paleta de grafice de mai sus.
     ⚠️ `--consumabil-alt` e pentru un toner al cărui nume nu spune ce culoare e (un aparat
     alb-negru care raportează doar „Toner Cartridge"): gri neutru, nu o culoare ghicită. */
  --consumabil-k: #2b2b2b;
  --consumabil-c: #0f9bc4;
  --consumabil-m: #d02670;
  --consumabil-y: #e8b300;
  --consumabil-alt: #8d8d8d;

  /* ---------- CELE ZECE NUANȚE ALE SEMNULUI OMULUI (06.09.2026) ----------
     Amprenta unui nume, nu o stare: vezi caseta de la `.semn-om`, mai jos în foaie.
     ⛔ Nu se amestecă în vocabularul stărilor și nu se poate alege din „Setări → Temă":
     un cerc pe care omul îl citește ca „e bine" ar fi mai rău decât unul gri.
     Contrastul fiecărei perechi se SOCOTEȘTE, în amândouă modurile:
     `TestSemneleOamenilorRamanCitibile`. */
  --semn1-fond: #f3d2cd;  --semn1-text: #6d2317;
  --semn2-fond: #f3e9cd;  --semn2-text: #6d5617;
  --semn3-fond: #e7f3cd;  --semn3-text: #516d17;
  --semn4-fond: #d0f3cd;  --semn4-text: #1d6d17;
  --semn5-fond: #cdf3e2;  --semn5-text: #176d45;
  --semn6-fond: #cdeef3;  --semn6-text: #17626d;
  --semn7-fond: #cdd8f3;  --semn7-text: #172e6d;
  --semn8-fond: #dacdf3;  --semn8-text: #34176d;
  --semn9-fond: #f1cdf3;  --semn9-text: #68176d;
  --semn10-fond: #f3cddf; --semn10-text: #6d173f;
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   2. VARIABILE — SETUL ÎNTUNECAT
   ══════════════════════════════════════════════════════════════════════════════════════
   ⛔ AICI SE REDEFINESC DOAR VALORILE, NICIODATĂ REGULILE. Niciun selector de componentă
   nu are voie să apară sub `.tema-intunecat`: dacă o componentă are nevoie de altă REGULĂ
   în întuneric, regula e greșită și în lumină. Garda `TestModulIntunecatDoarValori` o cere,
   iar motivul e chiar cel din caseta de sus — două seturi de reguli se despart la prima
   corectură, și se despart tăcut, fiindcă nimeni nu ține două moduri deschise deodată.

   ⚠️ Clasa stă pe `<body>`, nu pe `<html>`: `background` de pe body se propagă la pânza
   ferestrei (CSS 2.1 §14.2), deci fondul acoperă și zona de peste marginea paginii, iar
   cele ~49 de etichete `<body class="lat-…">` erau oricum singurul loc din fiecare pagină
   unde se scrie o clasă de cadru.
   ══════════════════════════════════════════════════════════════════════════════════════
   ⭐⭐ „NEGRU E PREA NEGRU" (Nelu, 04.09.2026) — și avea dreptate pe cifre, nu pe gust.

   Setul de mai jos pornise din **#161616 și rudele lui**: #262626, #333333, #3f3f3f,
   #393939 și un #000000 pe bară. Toate au R = G = B, adică sunt gri PUR — singura familie
   de culori pe care ochiul n-o citește ca pe o suprafață, fiindcă nicio suprafață din
   lume nu e neutră. Rezultatul arăta stins, nu închis; iar bara neagră lipită de un
   #161616 punea a doua gaură lângă prima.

   Acum baza e un **grafit-albastru**: aceeași luminozitate mică (deci aceeași odihnă
   pentru ochi seara), dar cu o nuanță în ea. Contrastele nu s-au muiat — au CRESCUT
   ușor, fiindcă baza e cu un pas mai închisă decât #161616:

     text pe fond     15,2 : 1     text pe card     13,9 : 1
     text-slab/card   10,1 : 1     text-stins/card   6,4 : 1     accent/card  6,5 : 1

   ⛔⛔ ȘI SUNT INGREDIENTE, NU CULORI PUSE DIRECT PE ROLURI. Tot ce e suprafață, linie
   sau coajă iese din cele ȘAPTE `--g-*` de mai jos; rolurile doar le cer. Asta e chiar
   ce face treptele din „Setări → Temă" posibile: o treaptă rescrie șapte valori, iar tot
   restul întunericului o urmează singur. Scrise direct pe roluri, o treaptă ar fi
   însemnat cincisprezece rânduri copiate — iar a doua treaptă ar fi divergit de prima,
   tăcut, exact ca cele 1 397 de culori de dinaintea temei.

   ⚠️ Ce NU s-a atins, deliberat: culorile de STARE (`--ok-*`, `--rau-*`, `--info-*`,
   `--mov-*`) și accentul. Ele n-au fost niciodată „rudele lui #161616" — sunt nuanțe cu
   înțeles, iar înțelesul nu se schimbă fiindcă fondul s-a încălzit. Singura excepție e
   `--neutru-fond`, care ERA #333333, adică chiar o treaptă a rampei de grafit. */
body.tema-intunecat {
  /* ---------- INGREDIENTELE GRAFITULUI, de la cel mai închis la cel mai deschis ----------
   * De ce ingrediente și nu roluri: caseta de sus. Treptele omului peste ele: §2b. */
  --g-coaja: #101319;
  --g-baza: #1a1d23;
  --g-sus: #21252e;
  --g-slab: #2b303a;
  --g-apasat: #363c47;
  --g-linie: #3a404c;
  --g-linie-slaba: #2b303a;

  --fond: var(--g-baza);
  --fond-card: var(--g-sus);   /* „carduri mai deschise" — chiar cerința machetei */
  --fond-slab: var(--g-slab);
  --fond-apasat: var(--g-apasat);

  --text: #f4f4f4;
  --text-slab: #c6c6c6;
  --text-stins: #a8a8a8;
  --text-pe-inchis: #f4f4f4;
  --schema: dark;

  --linie: var(--g-linie);
  --linie-slaba: var(--g-linie-slaba);

  --accent: #78a9ff;
  --accent-tare: #a6c8ff;
  --accent-slab: #1c2a44;

  --buton-fond: #0f62fe;
  --buton-fond-hover: #4589ff;
  --buton-text: #ffffff;

  --ok-semn: #42be65;    --ok-fond: #1d3326;    --ok-text: #a7f0ba;
  --avert-semn: #d2a106; --avert-fond: #332a12; --avert-text: #fddc69;
  --rau-semn: #fa4d56;   --rau-fond: #3b1f22;   --rau-text: #ffb3b8;
  --neutru-semn: #8d8d8d; --neutru-fond: var(--g-slab); --neutru-text: #c6c6c6;
  --info-semn: #78a9ff;  --info-fond: #1c2a44;  --info-text: #a6c8ff;
  --mov-fond: #2f1f45; --mov-text: #d4bbff;

  /* Bara rămâne COAJA, dar nu mai e negru pur: cu o pagină grafit sub ea, despărțirea o
     face nuanța, iar negrul curat era chiar jumătatea de „prea negru". */
  --bara-fond: var(--g-coaja);
  --bara-text: #e8e8e8;
  --bara-text-tare: #ffffff;
  --bara-text-slab: #a8a8a8;
  --bara-hover: var(--g-sus);
  --bara-linie: var(--g-linie);
  --bara-panou: var(--g-sus);
  --bara-nr: #fa4d56;

  --banda-fond: var(--g-sus);
  --banda-text: #f4f4f4;
  --banda-text-slab: #c6c6c6;
  --banda-linie: var(--g-linie);

  --umbra-plutire: 0 12px 28px rgba(0, 0, 0, .5);
  --umbra-lipita: -8px 0 8px -8px rgba(0, 0, 0, .55);

  --grafic-grila: var(--g-linie);
  --grafic-ax: #a8a8a8;
  --grafic-fond: var(--g-sus);

  /* Vezi caseta din setul luminos: doar NEGRUL se schimbă, fiindcă pe fond grafit o
     bară #2b2b2b nu se vede deloc — iar o bară invizibilă se citește ca „fără toner". */
  --consumabil-k: #9e9e9e;

  /* Semnele oamenilor, întoarse: fond închis, litere deschise. ACELEAȘI zece nuanțe, deci
     același om are aceeași culoare în amândouă modurile — culoarea e o amprentă, iar o
     amprentă care se schimbă la comutatorul de temă n-ar mai fi una. */
  --semn1-fond: #58332d;  --semn1-text: #ebb6ad;
  --semn2-fond: #584c2d;  --semn2-text: #ebdaad;
  --semn3-fond: #49582d;  --semn3-text: #d6ebad;
  --semn4-fond: #30582d;  --semn4-text: #b1ebad;
  --semn5-fond: #2d5844;  --semn5-text: #adebce;
  --semn6-fond: #2d5258;  --semn6-text: #ade2eb;
  --semn7-fond: #2d3858;  --semn7-text: #adbeeb;
  --semn8-fond: #3b2d58;  --semn8-text: #c2adeb;
  --semn9-fond: #552d58;  --semn9-text: #e7adeb;
  --semn10-fond: #582d41; --semn10-text: #ebadca;
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   2b. PALETA OMULUI — CE POATE SCHIMBA UN CONT, ȘI DE CE NU MAI MULT
   ══════════════════════════════════════════════════════════════════════════════════════
   ⭐ CERUT DE NELU (04.09.2026): „utilizatorul ajustează câteva culori-cheie, nu toată
   paleta — cel puțin accentul și intensitatea fondului întunecat, de la cald la sever.
   Fiecare alegere suprascrie DOAR variabila ei, peste temă; restul sistemului
   (componente, stări, grafice) moștenește automat."

   ⚠️ E numerotată „2b", nu „3": ține de VARIABILE, deci îi e locul lângă cele două seturi
   de sus. Numerele 3–20 de mai jos sunt secțiuni de reguli și n-au fost renumerotate
   pentru o secțiune de valori — o renumerotare de șaptesprezece titluri e exact felul de
   diferență care înghite adevărata schimbare într-o citire de commit.
   ══════════════════════════════════════════════════════════════════════════════════════
   ⛔⛔ GARDA, ȘI E STRUCTURALĂ, NU O VERIFICARE.

   Omul NU alege o culoare. Alege o CHEIE dintr-un set închis (`store/tema_culori.go`),
   iar cheia se traduce într-una din clasele de mai jos PRIN CATALOG. O cheie
   necunoscută — venită dintr-un formular măsluit, dintr-un `UPDATE` de mână în bază,
   dintr-o migrare viitoare scrisă neatent — nu produce NICIO clasă; nu produce o clasă
   compusă din ce era scris acolo.

   Deci nu există niciun drum prin care un `#ffffff` ales de cineva să ajungă text pe fond
   alb: mulțimea culorilor posibile e EXACT ce e scris mai jos, iar contrastul FIECĂREI
   combinații (2 moduri × 5 accente × 4 fonduri × 2 contraste) e socotit de o gardă —
   `TestOriceAlegereRamaneCitibila` — nu promis într-un comentariu.

   ⚠️ De ce nu un selector de culoare liber: exact fiindcă ar fi putut da text alb pe fond
   alb. Iar un selector „cu validare de contrast" mută problema, nu o rezolvă — validarea
   ar trebui să știe pe CE fond ajunge culoarea, adică toate combinațiile de mai sus, în
   browser, la fiecare mișcare de cursor.
   ══════════════════════════════════════════════════════════════════════════════════════
   ⚠️ FIECARE ACCENT ARE DOUĂ RÂNDURI, ȘI AL DOILEA NU E OPȚIONAL. `.acc-x` e (0,1,0) în
   specificitate, iar `body.tema-intunecat` e (0,1,1) — deci în întuneric setul de mai sus
   ar CÂȘTIGA în fața alegerii omului, iar accentul ales ar dispărea exact în modul pentru
   care omul l-a ales. Perechea `body.tema-intunecat.acc-x` e (0,2,1) și câștigă.
   Garda `TestFiecareAlegereAreAmandouaModurile` cere perechea, ca lipsa ei să nu se afle
   de la un om care spune „la mine nu se schimbă nimic". */

/* ---------- ACCENTUL: legături, filă activă, inel de focalizare, buton primar ----------
   ⛔ Cele CINCI stări (`--ok-*`, `--avert-*`, `--rau-*`, `--neutru-*`, `--info-*`) NU se
   ating: „e bine" rămâne verde și pe accentul verde, fiindcă altfel două lucruri diferite
   ar avea aceeași culoare pe ecranul aceluiași om. Accentul e vocea produsului; stările
   sunt vocabularul lui. Albastrul e implicitul, deci n-are clasă: implicitul e absența. */
.acc-verde     { --accent: #0e6027; --accent-tare: #044317; --accent-slab: #e4f5ea; --buton-fond: #0e6027; --buton-fond-hover: #044317; }
.acc-turcoaz   { --accent: #005d5d; --accent-tare: #004144; --accent-slab: #d9f2f0; --buton-fond: #007d79; --buton-fond-hover: #005d5d; }
.acc-mov       { --accent: #6929c4; --accent-tare: #491d96; --accent-slab: #f0e6ff; --buton-fond: #6929c4; --buton-fond-hover: #491d96; }
.acc-chihlimbar{ --accent: #8a3800; --accent-tare: #6b2a00; --accent-slab: #fdeade; --buton-fond: #8a3800; --buton-fond-hover: #6b2a00; }

/* Perechile de întuneric. Legătura se LUMINEAZĂ (altfel se stinge în grafit), butonul
   plin rămâne culoarea tare cu text alb — chiar despărțirea de roluri explicată la
   `--accent` în setul luminos. */
body.tema-intunecat.acc-verde     { --accent: #6fdc8c; --accent-tare: #a7f0ba; --accent-slab: #12291c; --buton-fond: #0e6027; --buton-fond-hover: #198038; }
body.tema-intunecat.acc-turcoaz   { --accent: #3ddbd9; --accent-tare: #9ef0f0; --accent-slab: #10292b; --buton-fond: #007d79; --buton-fond-hover: #009d9a; }
body.tema-intunecat.acc-mov       { --accent: #be95ff; --accent-tare: #d4bbff; --accent-slab: #251a3a; --buton-fond: #6929c4; --buton-fond-hover: #8a3ffc; }
body.tema-intunecat.acc-chihlimbar{ --accent: #ff832b; --accent-tare: #ffb784; --accent-slab: #2b1a10; --buton-fond: #8a3800; --buton-fond-hover: #a04200; }

/* ---------- INTENSITATEA FONDULUI ÎNTUNECAT: patru trepte, de la cald la sever ----------
   ⛔ NUMAI ÎN MODUL ÎNTUNECAT, și nu e o scăpare: în lumină n-ar avea ce încălzi, iar o
   treaptă care ar schimba și pagina albă ar fi însemnat că alegerea face două lucruri.
   Fiecare treaptă rescrie EXACT cele șapte ingrediente; nimic altceva. */
body.tema-intunecat.fond-cald {
  --g-coaja: #15181f; --g-baza: #1e2128; --g-sus: #272b34; --g-slab: #31363f;
  --g-apasat: #3c424d; --g-linie: #414753; --g-linie-slaba: #31363f;
}
body.tema-intunecat.fond-neutru {
  --g-coaja: #0d0d0d; --g-baza: #1c1c1c; --g-sus: #262626; --g-slab: #333333;
  --g-apasat: #3f3f3f; --g-linie: #3f3f3f; --g-linie-slaba: #333333;
}
body.tema-intunecat.fond-sever {
  --g-coaja: #000000; --g-baza: #101216; --g-sus: #191c22; --g-slab: #24272e;
  --g-apasat: #2e323a; --g-linie: #33373f; --g-linie-slaba: #24272e;
}

/* ---------- CONTRAST RIDICAT ----------
   Pentru cine citește greu textul secundar — sau lucrează în lumină puternică, cazul
   tehnicianului cu telefonul în mână, afară. Ridică DOAR textul stins și liniile; nu
   atinge nici fondul, nici accentul, deci se combină cu oricare dintre ele. */
.contrast-ridicat { --text-slab: #3f3f3f; --text-stins: #525252; --linie: #a8a8a8; --linie-slaba: #cfccc7; }
body.tema-intunecat.contrast-ridicat { --text-slab: #f4f4f4; --text-stins: #dedede; --linie: #5a616e; --linie-slaba: #414855; }

/* ---------- DENSITATEA: „compact", a patra axă (0091, runda 15) ----------
   ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⭐ CERUTĂ DE PLANUL DE INTERFEȚĂ: „densitate (compact sau confortabil)". E singura     ║
   ║ dintre cele patru alegeri ale omului care nu schimbă nicio culoare — schimbă CÂTE     ║
   ║ RÂNDURI încap pe un ecran, adică singurul lucru pe care îl simte cineva care se uită  ║
   ║ la o listă de două sute de echipamente.                                                ║
   ╠══════════════════════════════════════════════════════════════════════════════════════╣
   ║ ⛔⛔ SE REDEFINESC CHIAR JETOANELE DE SPAȚIERE, NU SE RESCRIU COMPONENTELE.            ║
   ║                                                                                       ║
   ║ Toate spațierile produsului ies din grila de 8 px de sus (vezi caseta ei) — 316       ║
   ║ selectori o citesc, niciunul n-are cifra lui. Deci „compact" se face coborând         ║
   ║ jetoanele cu o treaptă, într-un singur bloc: cardurile, tabelele, formularele,        ║
   ║ filele și bara se strâng toate deodată, fără nicio regulă nouă scrisă pentru vreuna   ║
   ║ dintre ele. Scris pe componente, ar fi fost 316 locuri în care se poate uita unul.    ║
   ║                                                                                       ║
   ║ ⛔ `--sp-1` ȘI `--sp-2` (4 și 8 px) RĂMÂN NEATINSE. Sunt jumătățile de pas — spațiul  ║
   ║ dintre o etichetă și câmpul ei, dintre două pastile. Sub 4 px ele nu mai despart       ║
   ║ nimic, iar ce se câștigă pe înălțime se pierde din citit.                              ║
   ║                                                                                       ║
   ║ ⛔⛔ `--tinta` (44 px, ținta degetului) NU E O SPAȚIERE ȘI NU SE ATINGE. „Compact"     ║
   ║ înseamnă mai puțin aer, nu butoane la care nu nimerești; hotărârea de la 08.09.2026   ║
   ║ e a ATINGERII, nu a densității, iar pe telefon ea bate densitatea. Ținut de            ║
   ║ `TestDensitateaScrieDoarSpatieri`, care cere ca blocul ăsta să nu scrie altceva.       ║
   ║                                                                                       ║
   ║ ⚠️ FĂRĂ PERECHE DE ÎNTUNERIC, dinadins: aerul dintre două rânduri e același pe alb și ║
   ║ pe negru. O a doua scriere ar fi fost două locuri în care se poate pune altă cifră     ║
   ║ pentru același lucru. De aceea densitatea NU intră în                                  ║
   ║ `TestFiecareAlegereAreAmandouaModurile`, iar motivul e scris și acolo.                 ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
.dens-compact {
  --sp-3: 8px;
  --sp-4: 12px;
  --sp-5: 16px;
  --sp-6: 24px;
  --sp-7: 32px;
}

/* ---------- MOSTRA: pătratul de lângă fiecare opțiune, pe ecranul „Setări → Temă" ----------
   ⚠️ Culorile ei sunt SCRISE, nu luate din variabile, și trebuie să fie: pătratul arată
   cum ARATĂ o alegere pe care omul NU a făcut-o încă, deci nu poate cere variabila —
   variabila spune ce e acum. Garda `TestMostrelePotrivescPaleta` compară fiecare pătrat
   cu valoarea pe care o anunță, ca ele să nu poată minți după prima corectură de nuanță. */
.mostra {
  display: inline-block; width: 16px; height: 16px; vertical-align: -3px;
  margin-right: var(--sp-2); border: 1px solid var(--linie); border-radius: var(--rot-mic);
}
.mostra-albastru    { background: #0f62fe; }
.mostra-verde       { background: #0e6027; }
.mostra-turcoaz     { background: #005d5d; }
.mostra-mov         { background: #6929c4; }
.mostra-chihlimbar  { background: #8a3800; }
.mostra-g-implicit  { background: #1a1d23; }
.mostra-g-cald      { background: #1e2128; }
.mostra-g-neutru    { background: #1c1c1c; }
.mostra-g-sever     { background: #101216; }

/* ══════════════════════════════════════════════════════════════════════════════════════
   3. BAZA
   ══════════════════════════════════════════════════════════════════════════════════════ */
*, *::before, *::after { box-sizing: border-box; }

body {
  margin: 0;
  font-family: var(--font);
  font-size: var(--t-baza);
  line-height: var(--ritm);
  background: var(--fond);
  color: var(--text);
  /* Fondul de pe body se propagă la pânză, deci nu mai trebuie pictat și pe `html`. */
  -webkit-text-size-adjust: 100%;
  /* ⛔ `color-scheme` SPUNE BROWSERULUI ÎN CE MOD SUNTEM, și fără el jumătate din modul
     întunecat nu se întâmplă: controalele NATIVE — lista deschisă a unui dropdown,
     calendarul, câmpul de fișier, bara de derulare — rămân albe pe o pagină grafit.
     Nu e o culoare de-a noastră; e singura cale prin care se cere unui browser să-și
     deseneze singur piesele în mod închis. */
  color-scheme: var(--schema);
}
/* ⚠️ ȘI PE <html>, fiindcă bara de derulare A PAGINII e a lui, iar variabilele nu urcă de
   la `body` în sus. `:has()` e singura formă care citește o clasă de pe copil. */
html:has(body.tema-intunecat) { color-scheme: dark; }

h1, h2, h3, h4 { margin: 0 0 var(--sp-2); line-height: 1.25; font-weight: 700; color: var(--text); }
h1 { font-size: var(--t-h1); }
h2 { font-size: var(--t-mare); }
h3 { font-size: var(--t-baza); }
h4 { font-size: var(--t-mic2); }
p { margin: 0 0 var(--sp-3); }

/* ⭐ LEGĂTURA E SUBLINIATĂ (runda uniformizării butoanelor, 14.09.2026): e a treia formă,
   „te duce în altă parte și nu schimbă nimic". Sublinierea o deosebește de un text colorat
   fără să ceară încă o culoare. ⚠️ Componentele care folosesc `<a>` ca altceva — filele,
   filtrele-pastilă, bara, butoanele — își scot sublinierea în regula lor. */
a {
  color: var(--accent); text-decoration: underline;
  text-decoration-thickness: var(--legatura-grosime); text-underline-offset: var(--legatura-departare);
}
a:hover { color: var(--accent-tare); text-decoration: underline; }

code, .cod, .idpub {
  font-family: var(--font-cod);
  font-size: var(--t-mic);
}
/* ⛔ Un cod în proză se rupe unde trebuie (18.09.2026, proba din Chrome la 390 px): calea
   dosarului de copii, scrisă ca un singur „cuvânt", împingea /setari/copii 247 px lateral. */
:where(p, li) code { overflow-wrap: anywhere; }
.idpub {
  background: var(--fond-slab);
  color: var(--text-slab);
  padding: 2px var(--sp-1);
  border-radius: var(--rot-mic);
}

hr { border: 0; border-top: 1px solid var(--linie); margin: var(--sp-4) 0; }

/* ---------- FOCALIZAREA SE VEDE, PESTE TOT ----------
   ⛔ Un `outline:none` scris ca să „curețe" un buton scoate produsul din uzul de la
   tastatură fără ca cineva să observe: cine navighează cu mouse-ul nu vede niciodată
   ce a stricat. Aici e o singură regulă, pe `:focus-visible`, deci nu apare la clic. */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  border-radius: var(--rot-mic);
}

/* ---------- CIFRELE ----------
   ⭐ „cifre la dreapta cu font tabular" (cerința 3). `.nr` e clasa pe care o poartă o
   celulă sau un câmp de cifre; capul ei de coloană o poartă și el, ca titlul să stea
   deasupra cifrelor, nu deasupra spațiului gol din stânga lor. */
td.num, th.num, td.nrc, th.nrc, .cifra .v, .contor {
  font-variant-numeric: tabular-nums;
  text-align: right;
}

/* `.nr` — CIFRA CARE SPUNE „ai ceva de făcut": necititele unei file, alertele deschise.
   ⛔ E o pastilă, nu o coloană de cifre. Numele e scurt și vechi în produs; alinierea la
   dreapta se cere cu `.num` pe celulă. Aceeași formă și aceeași culoare ca semnul din
   bară (`.bs-nr`) — e același lucru văzut în două locuri. */
.nr {
  background: var(--bara-nr); color: var(--bara-nr-text); border-radius: var(--rot-pastila);
  padding: 1px var(--sp-2); font-size: var(--t-xs); font-weight: 700;
  margin-left: var(--sp-1); font-variant-numeric: tabular-nums;
}

/* ---------- COMUTATORUL DE VEDERI (Listă · Hartă · Descoperite · …) ----------
   ⛔⛔ E O BUCATĂ A PAGINII, NU A BAREI (14.09.2026). Stă în rândul de filtre, sub coajă,
   dar își lua fundalul din panoul barei — iar pe tema de zi ieșea o fâșie neagră lipită
   peste o pagină luminoasă (Nelu, cu poză). De aici încolo ia jetoanele PAGINII și
   urmează modul zi/noapte, ca filtrele de lângă el. Bara rămâne coajă: aia e hotărâre.
   ⚠️ Așezarea (rupere, spațieri) stă în ecran; culorile stau AICI, o singură dată.
   Păzit de `TestBandaDeVederiUrmeazaModul` și `TestZonaDeSusNuScrieCuloriDeMana`. */
.comutator { background: var(--fond-slab); border: 1px solid var(--linie); }
.comutator a { color: var(--text-slab); text-decoration: none; }
.comutator a:hover { background: var(--fond-apasat); color: var(--text); text-decoration: none; }
.comutator .aici { background: var(--buton-fond); color: var(--buton-text); }

/* ══════════════════════════════════════════════════════════════════════════════════════
   4. CADRUL PAGINII: O LĂȚIME DE PAGINĂ, O LĂȚIME DE CITIT, DEFINITE O SINGURĂ DATĂ
   ══════════════════════════════════════════════════════════════════════════════════════
   ⭐ Cerut de Nelu (30.08). Măsurate înainte, pe ecrane vecine: Clienți ~630 px, Praguri
   ~490, Presete ~710, Consumabile ~910, Mesaje ~560 — iar pe fișa clientului formularul
   era îngust și „Puncte de lucru" lat, în aceeași pagină.

   ⭐⭐ 08.09.2026 — PLAFONUL URCĂ DE LA 1100 LA 1600 px (hotărârea lui Nelu).
   Măsurat înainte: tabelul de contacte cerea 1312 px într-o cutie de 1018, deci tăia
   294 px de acțiuni pe ORICE monitor; `/utilizatori?tab=clienti` ascundea 163 px cu ZERO
   rânduri. Nu era o problemă de ferestre mici — era plafonul.

   ⛔ ȘI DE CE NU SE SCOATE CU TOTUL. Pe un monitor de 2560 px un tabel întins pe toată
   lățimea nu se mai poate citi: ochiul pierde rândul între prima coloană și ultima, iar
   „ce scrie pe rândul ăsta" cere o riglă. Un plafon nu e o limitare de ecran, e o limită
   de CITIRE — de aceea rămâne, doar că mai sus.

   DOUĂ CIFRE, ȘI RĂSPUND LA ÎNTREBĂRI DIFERITE:
     PAGINA (--lat-pagina, 1600 px) — cât se întinde cadrul: tabele, tablouri, liste.
     CITITUL (--lat-citit, 720 px)  — cât se întinde o COLOANĂ DE CITIT SAU DE COMPLETAT.
                                      Peste atât, un rând de text și un câmp de formular
                                      devin greu de urmărit — iar un formular pe 1600 px
                                      e chiar exemplul.
     AERUL (--lat-aer, 24 px)       — marginea care nu se atinge niciodată de fereastră.

   ⛔ Lățimea de citit se aplică PRIN COMPONENTĂ, nu prin pagină, și e ALINIATĂ LA STÂNGA:
   cadrul rămâne al paginii (banda de titlu ține toată lățimea), iar înăuntrul lui coloana
   de completat începe de la stânga. O pagină îngustată toată ar fi mutat și titlul, și
   tabelele care stau lângă formular.

   ⛔ Pagina alege UNA SINGURĂ dintre cele trei clase, pe <body>, iar banda de titlu și
   conținutul o primesc amândouă din aceeași variabilă. Garda
   `TestNiciunSablonNuAreLatimeaLui` o cere. */
:root {
  --lat-pagina: 1600px;
  --lat-citit: 720px;
  --lat-aer: var(--sp-5);
  --lat: var(--lat-pagina);
  /* Numele vechi, păstrate ca sinonime: `--lat-formular` era citat în ecrane vechi, iar o
     variabilă dispărută tace, nu cade. */
  --lat-formular: var(--lat-citit);
  --lat-lista: var(--lat-pagina);
}
/* ⚠️ `lat-formular` NU mai îngustează PAGINA, ci CARDURILE ei (vezi `.ingust` mai jos).
   Îngustată toată, pagina muta și banda de titlu — adică numele clientului, care de la
   11.09 e chiar lucrul care trebuie să se vadă primul. */
body.lat-formular { --lat: var(--lat-pagina); }
body.lat-lista    { --lat: var(--lat-pagina); }
/* ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⭐⭐ HARTA TRECE DE PLAFON, ȘI E O HOTĂRÂRE (Nelu, 08.09.2026, văzută pe producție). ║
   ║                                                                                       ║
   ║ `lat-plin` înseamnă TOATĂ lățimea ferestrei, dincolo de cei 1600 px — pe un monitor  ║
   ║ de 2560 harta chiar folosește tot. ⛔ Nu se bate cu plafonul, îi arată rostul: un    ║
   ║ TABEL pe 2560 px nu se mai poate citi, fiindcă ochiul pierde rândul între prima       ║
   ║ coloană și ultima; o HARTĂ câștigă din fiecare pixel, fiindcă acolo nu urmărești un   ║
   ║ rând, ci o suprafață. Plafonul e o limită de CITIRE, iar harta nu se citește pe       ║
   ║ rânduri.                                                                              ║
   ║ ⚠️ Singurul ecran care o folosește azi e `/dashboard`. Un al doilea care ar cere-o    ║
   ║ trebuie să răspundă la aceeași întrebare: se citește pe rânduri sau pe suprafață?     ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
body.lat-plin     { --lat: none; }

/* ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⭐⭐ LOCUL BAREI DE DERULARE SE REZERVĂ MEREU (17.09.2026, cerut de Nelu).             ║
   ║                                                                                       ║
   ║ MĂSURAT PE PRODUCȚIE, la 1400 px lățime de fereastră, lățimea lui `main`:             ║
   ║   1400 px — /clienti, /utilizatori, /mesaje                                           ║
   ║   1385 px — /dispecerat, /colectoare, /productie, /contracte, /diagnostic, /setari/tema║
   ║ Diferența de 15 px e chiar bara de derulare: paginile SCURTE n-o au, cele lungi o au. ║
   ║ Deci trecând de la Clienți la Contracte, TOT conținutul sărea lateral cu 15 px.       ║
   ║                                                                                       ║
   ║ ⛔ ȘI NU E O ÎMPĂRȚIRE STABILĂ A ECRANELOR, CI O ÎNTÂMPLARE A DATELOR: /clienti cu    ║
   ║ unsprezece firme nu derulează, cu patruzeci derulează — deci cadrul aceluiași ecran   ║
   ║ se strânge cu 15 px de la o firmă la alta. Un cadru care atârnă de câte rânduri a     ║
   ║ nimerit înăuntru nu e un cadru.                                                        ║
   ║                                                                                       ║
   ║ ⛔ DE CE NU `overflow-y: scroll`, care ar fi rezolvat-o și el: acela DESENEAZĂ o bară ║
   ║ moartă, cu săgeți și tot, pe fiecare pagină scurtă din produs. `scrollbar-gutter`     ║
   ║ rezervă locul fără s-o deseneze.                                                       ║
   ║ Garda: TestBaraDeDerulareNuMutaPagina.                                                 ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
html { scrollbar-gutter: stable; }

main {
  max-width: var(--lat);
  margin: 0 auto;
  padding: var(--sp-5) var(--lat-aer) var(--sp-7);
}
body.lat-plin main { max-width: none; margin: 0; padding: 0; }

/* ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⭐ ȘI FÂȘIA DE FILTRE A PARCULUI SE OPREȘTE LA PLAFON (17.09.2026).                    ║
   ║                                                                                       ║
   ║ Parcul n-are bandă de titlu: comutatorul „Hartă · Listă · Mutări…" îi ține locul, și   ║
   ║ stă în fâșia de filtre de deasupra conținutului (vezi `TestPaginileSERVITEPoartaCadrul║
   ║ Intreg`). Odată ce conținutul a intrat în `main`, fâșia rămăsese singura piesă fără    ║
   ║ plafon: măsurat la 1900 px, comutatorul începea la 24 px, iar tabelul de sub el la    ║
   ║ 143 — adică exact defectul cu care a pornit runda, „titlul mai la stânga decât         ║
   ║ tabelul", mutat cu o fâșie mai sus.                                                    ║
   ║                                                                                       ║
   ║ ⛔ SE PLAFONEAZĂ FÂȘIA ÎNTREAGĂ, NU DOAR CONȚINUTUL EI, și e o deosebire de banda de  ║
   ║ titlu: `.pg-banda` are fond pe toată fereastra și doar `.pg-banda-in` se oprește la    ║
   ║ plafon. Acolo merge, fiindcă banda e chenarul paginii. Aici fâșia e o piesă A         ║
   ║ PAGINII — poartă comutatorul de vederi și filtrele ei — deci se aliniază cu pagina.    ║
   ║ ⚠️ O umplutură centrată ar fi mers și ea, dar ar fi bătut regula de telefon a temei    ║
   ║ (`.filtre { padding: … }`, §19b) prin specificitate, la ORICE lățime: plafonul de aici ║
   ║ nu atinge nimic sub 1600 px.                                                           ║
   ║                                                                                       ║
   ║ ⛔ Numai pe `lat-lista`: pe vederea HARTĂ fâșia rămâne lipită de margini, ca dalele de ║
   ║ sub ea. Vezi hotărârea #21.                                                            ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
body.lat-lista .zona-filtre { max-width: var(--lat); margin-inline: auto; }


/* ---------- COLOANA DE CITIT / DE COMPLETAT ----------
   ⭐ Se pune pe CARD (`.card.ingust`), iar pe paginile declarate „formular" o primesc
   singure toate cardurile de la primul nivel — altfel fiecare ecran de formular ar fi
   trebuit să-și amintească o clasă, iar cel scris mâine ar fi uitat-o.
   ⛔ `margin-right: auto`, nu `margin: 0 auto`: ALINIAT LA STÂNGA. Centrată, coloana s-ar
   fi mutat sub titlu la fiecare schimbare de lățime a ferestrei. */
.ingust,
body.lat-formular main > .card,
body.lat-formular main > form > .card { max-width: var(--lat-citit); margin-right: auto; }

/* ⛔ ȘI CÂMPURILE, ORIUNDE AR STA. Un card lat care ține un formular (setările, fișa
   firmei) n-are voie să întindă un `<input>` la 1600 px doar fiindcă `input{width:100%}`.
   Regula asta prinde cazul FĂRĂ ca ecranul să declare ceva — deci și pe cel scris mâine.
   ⚠️ Nu atinge câmpurile din rând (tabel, filtre, bară): acelea au deja `width:auto`. */
main input, main select, main textarea, main label { max-width: var(--lat-citit); }
main input[type="checkbox"], main input[type="radio"] { max-width: none; }

/* .sx — împachetarea care lasă un tabel să deruleze pe orizontală.
   Marginea negativă anulează margine interioară pusă doar ca inelul de focalizare al
   ultimului rând să nu fie tăiat de containerul de derulare.
   ⚠️ `position: relative` e pentru coloana de acțiuni LIPITĂ (vezi §11): un element
   `sticky` se leagă de cel mai apropiat strămoș care derulează, iar ăsta e. */
.sx { overflow-x: auto; position: relative; padding-bottom: var(--sp-1); margin-bottom: calc(-1 * var(--sp-1)); }

/* ══════════════════════════════════════════════════════════════════════════════════════
   5. BARA DE SUS
   ══════════════════════════════════════════════════════════════════════════════════════
   ⚠️ Clasele sunt prefixate `bs-`, ca să nu se lovească de `.user` / `.bara` care există,
   diferit, în ecranele vechi. Stilul stătea până azi într-un `<style>` din chiar șablonul
   barei, repetat pe fiecare pagină randată; acum e aici, o dată, servit și ținut în cache. */
.bs {
  background: var(--bara-fond);
  color: var(--bara-text);
  padding: 0 var(--lat-aer);
  display: flex;
  align-items: center;
  align-content: center;
  gap: var(--sp-3);
  /* ⭐⭐ BARA SE ÎNDOAIE, NU ÎMPINGE PAGINA (08.09.2026).
     ⛔ CAUZA, MĂSURATĂ ÎNAINTE: bara cerea 1236 px și nu putea să se strângă — meniul are
     `white-space: nowrap`, căsuța de căutare avea `width: 190px` fix, iar un element flex
     are implicit `min-width: auto`, adică refuză să scadă sub conținutul lui. Sub 1255 px
     lățime de fereastră, DOCUMENTUL ÎNTREG căpăta derulare orizontală — și cu el pleca
     lateral chiar bara, adică navigația. Un laptop de 1366 px cu fereastra pe două treimi
     cădea exact acolo. (Probat pe cinci ecrane: `document.scrollWidth = 1236` peste tot.)
     ⛔ NU s-a reparat cu `overflow: hidden` pe pagină: aia ascunde defectul și taie tăcut
     butonul „Ieși". Se repară CAUZA — bara capătă voie să curgă pe un al doilea rând, iar
     piesele ei capătă voie să se strângă. Nimic nu dispare, nimic nu se taie.
     ⚠️ `height` a devenit `min-height`: cu wrap, o înălțime fixă ar fi strivit al doilea
     rând peste primul. Ancorele își iau cifra din `--bs-inaltime`, pe care scriptul barei
     o măsoară deja la fiecare `resize`. */
  flex-wrap: wrap;
  min-height: 46px;
  font-size: var(--t-mic2);
  /* ⭐ BARA RĂMÂNE LA VEDERE LA DERULARE (30.08.2026, cerut de Nelu).
     position:sticky, nu fixed: fixed ar scoate bara din flux, iar fiecare set de șabloane
     ar fi avut nevoie de propriul padding-top potrivit de mână la înălțimea ei.
     ⚠️ flex:0 0 auto e pentru HARTĂ, unde body e o coloană flex pe tot ecranul și bara —
     cu înălțime fixă, dar flex-shrink implicit 1 — putea fi strivită pe ferestre mici. */
  position: sticky;
  top: 0;
  flex: 0 0 auto;
  /* ⛔ BARA E UN SINGUR STRAT, DEASUPRA PAGINII (28.08.2026). Găsită pe hartă: cu panoul
     lateral deschis, submeniul îi trecea PE DEDESUBT (panoul la 900, panoul barei la 60).
     Se ridică bara ÎNTREAGĂ, ca să se declare o dată că navigația stă peste conținut. */
  z-index: 1000;
}
/* ⛔ ANCORELE. Cu bara lipită, un href="#ceva" duce ținta EXACT sub ea. Cifra vine din
   înălțimea REALĂ a bării, pusă de scriptul din bara_sablon.go; valoarea de aici e rezerva
   pentru cazul fără JS. */
:root { --bs-inaltime: 46px; }
html { scroll-padding-top: calc(var(--bs-inaltime) + var(--sp-2)); }

/* ⭐ ORDINEA ÎN CARE SE STRÂNGE BARA, ca nimic să nu dispară până nu trebuie:
   (1) numele firmei și numele omului se scurtează cu „…"; (2) căsuța de căutare scade de
   la 190 la 110 px; (3) abia dacă tot nu încape, cluster-ul din dreapta trece pe rândul
   al doilea. ⛔ `min-width: 0` peste tot: fără el, un element flex refuză să scadă sub
   conținutul lui, iar toate regulile de mai jos ar fi fost decor. */
.bs > * { min-width: 0; }
.bs .bs-marca {
  font-weight: 700; color: var(--bara-text-tare); letter-spacing: .02em;
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 0 1 auto;
}
.bs a { color: var(--bara-text); text-decoration: none; padding: var(--sp-1) var(--sp-2); border-radius: var(--rot-mic); }
.bs a:hover { background: var(--bara-hover); color: var(--bara-text-tare); text-decoration: none; }
/* ⚠️ `bs-spatiu` e ȘI locul de rupere: cu `flex-wrap`, el umple rândul întâi, iar ce vine
   după el trece pe al doilea — deci meniul rămâne întreg pe primul rând, iar identitatea
   coboară ca un bloc. Ruperea se întâmplă unde trebuie fără niciun element nou. */
.bs .bs-spatiu { flex: 1 1 0; }
.bs .bs-nume {
  font-weight: 600; color: var(--bara-text-tare);
  overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 0 1 auto;
}
.bs .bs-rol {
  background: var(--bara-hover); color: var(--bara-text); padding: 2px var(--sp-2);
  border-radius: var(--rot-pastila); font-size: var(--t-xs); text-transform: uppercase;
}
.bs .bs-brand { color: var(--bara-text-slab); font-size: var(--t-mic); margin-left: calc(-1 * var(--sp-2)); }
/* ⭐ SIGLA — inițialele firmei, într-un pătrat. Pe BIROU nu se vede: acolo încape numele
   întreg, iar o siglă lângă el ar fi spus același lucru de două ori. Sub prag ea ia locul
   numelui — vezi caseta „TELEFON" de mai jos.
   ⚠️ Culorile sunt ale BĂRII, nu nuanța din nume: în banda de titlu semnul unei firme e
   colorat ca s-o deosebească de vecinele ei dintr-o listă, dar în bară nu e nicio listă —
   e o singură firmă, a ta, iar o pată colorată ar fi concurat cu semnul de mesaje. */
.bs .bs-sigla {
  display: none; flex: 0 0 auto; align-items: center; justify-content: center;
  width: 30px; height: 30px; border-radius: var(--rot-mic);
  background: var(--bara-hover); color: var(--bara-text-tare);
  font-weight: 700; font-size: var(--t-mic); letter-spacing: 0;
}
/* ⭐⭐ SIGLA ÎNCĂRCATĂ DE DEALER (11.09.2026, migrarea 0084) — perechea de mai sus, pentru
   dealerul care ȘI-A PUS marca lui. Aceeași împărțire: una pentru birou, una pentru
   telefon, iar TEMA alege care se vede. Amândouă se randează (vezi caseta din bara_sablon).

   ⛔⛔ CELE PATRU RÂNDURI DE MAI JOS SUNT CHIAR REGULA „NU SE ÎNTINDE ȘI NU SE TAIE":
     · `width: auto; height: auto` — browserul păstrează raportul propriu al imaginii;
     · `max-height` — pe ce se încadrează sigla, adică ÎNĂLȚIMEA, iar lățimea urmează;
     · `max-width` — plasa pentru siglele foarte late (una de 7:1 la 28 px cere 196 px);
       atunci mărginește ea, iar înălțimea scade — tot fără nicio tăiere;
     · `object-fit: contain` — chiar dacă o zi cineva pune o lățime ȘI o înălțime fixe,
       imaginea rămâne întreagă înăuntru. ⛔ `cover` ar TĂIA, și de aceea nu apare nicăieri.

   ⚠️ Cifrele sunt jumătatea celor din `internal/sigla` (variantele se taie la dublu, pentru
   ecranele dese). Perechea e ținută de garda TestCutiileSiglaSePotrivescCuFoaia. */
.bs .bs-sigla-birou, .bs .bs-sigla-telefon {
  display: none; flex: 0 0 auto;
  width: auto; height: auto; object-fit: contain;
}
.bs .bs-sigla-birou { display: inline-block; max-height: 28px; max-width: 240px; }
.bs .bs-iesi {
  background: transparent; color: var(--bara-text); border: 1px solid var(--bara-linie);
  border-radius: var(--rot-mic); padding: var(--sp-1) var(--sp-3);
  font: inherit; font-size: var(--t-mic); cursor: pointer;
}
.bs .bs-iesi:hover { background: var(--bara-hover); color: var(--bara-text-tare); }
.bs .bs-mesaje { display: inline-flex; align-items: center; gap: var(--sp-1); }
/* Căutarea e prima care cedează spațiu: 190 px când încape, 110 px când nu.
   ⚠️ Lățimea stă pe FORMULAR, iar câmpul o umple — pe câmp, `width` fix ar fi bătut
   `flex-basis` și forma s-ar fi strâns doar pe hârtie. */
.bs .bs-cauta { margin: 0; flex: 0 1 190px; min-width: 110px; margin-left: auto; }
.bs .bs-cauta input {
  background: var(--bara-hover); border: 1px solid var(--bara-linie); color: var(--bara-text-tare);
  border-radius: var(--rot-mic); padding: var(--sp-1) var(--sp-2);
  font: inherit; font-size: var(--t-mic2); width: 100%; min-width: 0;
}
.bs .bs-cauta input::placeholder { color: var(--bara-text-slab); }
.bs .bs-cauta input:focus { outline: none; border-color: var(--accent); }
.bs .bs-nr {
  background: var(--bara-nr); color: var(--bara-nr-text); border-radius: var(--rot-pastila);
  padding: 1px var(--sp-2); font-size: var(--t-mic); font-weight: 700;
  font-variant-numeric: tabular-nums;
}

/* ---------- PLICUL CU MESAJE NECITITE (runda 20, 12.09.2026) ----------
   ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⭐ Forma e CHIAR a butonului „Calc" de lângă el — același chenar, același colț,        ║
   ║ aceeași margine interioară. Două semne vecine cu două forme s-ar fi citit ca două      ║
   ║ feluri de lucruri; ele sunt același fel: unelte mereu la îndemână.                     ║
   ╠══════════════════════════════════════════════════════════════════════════════════════╣
   ║ ⛔⛔ CIFRA STĂ PE COLȚUL PLICULUI, NU LÂNGĂ EL — și nu e o alegere de gust.            ║
   ║                                                                                       ║
   ║ Lângă, plicul ar fi fost cu ~22 px mai lat când ai un mesaj decât când n-ai, și cu    ║
   ║ încă ~10 la trei cifre. Bara de telefon n-are atâta: măsurat la 390 px, cu sigla lată ║
   ║ a unui dealer, ea era DEJA plină înainte de runda asta (vezi bugetul de mai jos).     ║
   ║ Pe colț, plicul e lat la fel cu cifră și fără — deci bugetul se poate socoti o dată   ║
   ║ și rămâne adevărat. ⚠️ Insigna din MENIU rămâne lângă cuvânt: acolo e o listă pe      ║
   ║ verticală, care are loc, iar cifra se citește în rândul ei.                            ║
   ║ ⛔ Aceeași pastilă (`.bs-nr`), aceeași culoare: se schimbă locul, nu semnul.           ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
.bs .bs-plic {
  position: relative; display: inline-flex; align-items: center; flex: 0 0 auto;
  color: var(--bara-text); border: 1px solid var(--bara-linie);
  border-radius: var(--rot-mic); padding: var(--sp-1) var(--sp-2); line-height: 1;
}
.bs .bs-plic:hover { background: var(--bara-hover); color: var(--bara-text-tare); }
.bs .bs-plic-pict { width: 14px; height: 14px; flex: 0 0 auto; }
/* ⛔⛔ PASTILA STĂ ÎNTREAGĂ ÎNĂUNTRU, fără să iasă cu niciun pixel — două măsurători din
   12.09.2026 au cerut-o, una după alta: cu −7 px ea ajungea la −3, adică DEASUPRA barei
   (plicul are 44 px într-o bară de 52); cu −2 px lateral, piesa raporta conținut mai lat
   decât cutia ei, iar garda de „nimic tăiat" de la 390 px o citea drept o tăietură. Ce iese
   dintr-o bară nu se poate deosebi de ce e tăiat de ea. */
.bs .bs-plic .bs-nr {
  position: absolute; top: 0; right: 0;
  padding: 0 var(--sp-1); font-size: var(--t-xs);
}

/* ---------- MENIUL CU SUBMENIURI ----------
   ⭐ details/summary native, nu div plus JS: clicul care deschide, Tab-ul care ajunge pe
   titlu și Enter/Space vin de la browser. Fără JS meniul TOT se deschide. */
/* ⚠️ `flex-wrap` ȘI PE MENIU, nu doar pe bară: intrările au `white-space: nowrap`, deci
   dacă meniul singur ar depăși fereastra (un dealer cu numele lung, o traducere mai lungă,
   un grup nou), el ar fi împins pagina lateral chiar cu bara îndoită. Aici e ultima plasă. */
.bs .bs-meniu { display: flex; align-items: center; gap: 1px; flex-wrap: wrap; min-width: 0; }
.bs .bs-m { position: relative; }
.bs .bs-m > summary {
  list-style: none; cursor: pointer; padding: var(--sp-1) var(--sp-2);
  border-radius: var(--rot-mic); white-space: nowrap; user-select: none;
}
.bs .bs-m > summary::-webkit-details-marker { display: none; }
.bs .bs-m > summary::after { content: "▾"; margin-left: var(--sp-1); font-size: 10px; opacity: .65; }
.bs .bs-m > summary:hover, .bs .bs-m[open] > summary { background: var(--bara-hover); color: var(--bara-text-tare); }
/* ⭐ GRUPUL PAGINII CURENTE E SUBLINIAT ALBASTRU — chiar macheta aleasă. De la 08.09.2026
   toate intrările stau în panouri, deci semnul e unul singur: pe titlul grupului. */
.bs .bs-m.aici > summary { color: var(--bara-text-tare); box-shadow: inset 0 -2px 0 var(--accent); }
.bs .bs-sub {
  position: absolute; top: calc(100% + var(--sp-1)); left: 0; min-width: 210px; z-index: 60;
  background: var(--bara-panou); border: 1px solid var(--bara-linie); border-radius: var(--rot);
  padding: var(--sp-1); box-shadow: var(--umbra-plutire);
  display: flex; flex-direction: column; gap: 1px;
}
.bs .bs-sub a { display: block; padding: var(--sp-1) var(--sp-2); white-space: nowrap; }
.bs .bs-sub a.aici { background: var(--bara-hover); color: var(--bara-text-tare); font-weight: 600; }
.bs .bs-sub .bs-nr { margin-left: var(--sp-1); }
/* ---------- AL DOILEA NIVEL DIN PANOU (08.09.2026, meniul pe trei grupuri) ----------
   ⭐ „Colectoare" și „Setări" sunt FAMILII, nu pagini: numele lor e un titlu (.bs-eticheta),
   iar vecinii stau retrași sub el (.bs-sub2). „Parc", „Clienți", „Facturare" și
   „Consumabile" sunt amândouă — legătură ȘI titlu peste vecinii lor.
   ⛔ Retragerea e SINGURUL semn de ierarhie, dinadins: un al doilea `details` înăuntru ar
   fi cerut încă o apăsare ca să vezi trei rânduri, iar panoul se deschide oricum întreg. */
.bs .bs-sub .bs-eticheta {
  display: block; padding: var(--sp-1) var(--sp-2); white-space: nowrap;
  font-size: var(--t-mic2); text-transform: uppercase; letter-spacing: .04em; opacity: .7;
}
.bs .bs-sub .bs-sub2 { display: block; }
.bs .bs-sub .bs-sub2 a { padding-left: var(--sp-4); }

/* ---------- COMUTATORUL LUMINOS / ÎNTUNECAT ----------
   ⭐ Cerința 2: stă ÎN BARĂ, e per utilizator și se ține pe cont, nu în browser.
   E un buton de formular (POST), nu un link: schimbă o preferință, iar un GET care
   schimbă ceva se poate declanșa dintr-o previzualizare de link sau dintr-un prefetch. */
.bs .bs-tema { margin: 0; display: inline-flex; }
.bs .bs-tema button {
  background: transparent; color: var(--bara-text); border: 1px solid var(--bara-linie);
  border-radius: var(--rot-mic); padding: var(--sp-1) var(--sp-2);
  font: inherit; font-size: var(--t-mic2); cursor: pointer; line-height: 1;
}
.bs .bs-tema button:hover { background: var(--bara-hover); color: var(--bara-text-tare); }

/* ---------- CELE DOUĂ BUTOANE DE PE TELEFON ----------
   ⭐ `bs-mob` — comutatoarele care există DOAR sub pragul de telefon: unul deschide meniul,
   celălalt căutarea. Sunt `<details>`/`<summary>` goale, fără conținut: ce se deschide e
   `.bs-meniu`, respectiv `.bs-cauta`, care rămân unde erau în markup.
   ⛔ De ce așa și nu un `<details>` care le ÎNVELEȘTE: învelite, ele n-ar mai fi putut fi
   arătate pe birou fără JS (un `<details>` închis nu-și randează conținutul, iar „deschis
   mereu peste 820 px" nu se poate cere din CSS). Cu `:has()` pe bară, aceeași bucată de
   markup e inline pe birou și panou pe telefon — fără nicio a doua scriere a meniului. */
/* Butonul de filtre: nu există pe birou, unde filtrele stau la vedere. */
.filtre-buton { display: none; }
.bs .bs-mob { display: none; }
.bs .bs-mob > summary {
  list-style: none; cursor: pointer; user-select: none;
  display: inline-flex; align-items: center; justify-content: center;
  min-width: var(--tinta); min-height: var(--tinta);
  border-radius: var(--rot-mic); font-size: var(--t-mare); line-height: 1;
}
.bs .bs-mob > summary::-webkit-details-marker { display: none; }
.bs .bs-mob > summary:hover, .bs .bs-mob[open] > summary { background: var(--bara-hover); color: var(--bara-text-tare); }

/* ---------- TELEFON ----------
   ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⛔⛔ MĂSURAT DE NELU PE TELEFONUL LUI, ȘI APOI DE MINE (08.09.2026): forma de dinainte║
   ║ desfășura cele opt intrări de meniu una sub alta, urmate de căutare, de nume, de      ║
   ║ insigna de rol, de comutatorul de temă și de „Ieși" — **408 px de meniu**, plus 126 px║
   ║ de filtre, ÎNAINTE de orice conținut. Pe un iPhone 14 (390×844) harta rămânea cu      ║
   ║ **102 px, adică 12 % din ecran**. Verdictul lui: „nu se poate folosi pe telefon."     ║
   ║                                                                                       ║
   ║ Nu era o lipsă de reguli — pragul de 820 exista și se aprindea. Era o regulă GREȘITĂ: ║
   ║ „bara curge pe mai multe rânduri" e bună la 1000 px și catastrofală la 390.           ║
   ╠══════════════════════════════════════════════════════════════════════════════════════╣
   ║ ⭐ FORMA DE ACUM, sub prag: **marca · ☰ · ⌕ · omul**, pe UN SINGUR RÂND. Meniul și    ║
   ║ căutarea se deschid ca panou PESTE pagină (`position: absolute`), nu împing conținutul║
   ║ în jos — altfel butonul ar fi mutat doar problema cu un clic mai încolo.              ║
   ║ ⛔ GRUPURILE RĂMÂN GRUPURI: în panou, `<details class="bs-m">` e tot acolo, deschis   ║
   ║ în flux. Aplatizate într-o listă de paisprezece legături, s-ar fi pierdut chiar       ║
   ║ hotărârea din 28.08 („cinci grupuri, nu paisprezece legături la același nivel").      ║
   ╠══════════════════════════════════════════════════════════════════════════════════════╣
   ║ ⛔⛔ NIMIC NU SE TAIE ȘI NIMIC NU SE SCURTEAZĂ CU TREI PUNCTE (Nelu, 08.09 seara, pe   ║
   ║ telefonul lui). Forma de dimineață păstra sub prag numele ÎNTREG al firmei și numele  ║
   ║ omului, amândouă cu „…". Măsurat: la 390 px marca cerea 107 px într-o cutie de 105 —  ║
   ║ deci scria „XEGORA (de…", iar pe PEISAJ (844×390) bara nici măcar nu intra în forma   ║
   ║ de telefon și se rupea pe două rânduri, 69 px din 390.                                ║
   ║                                                                                       ║
   ║ ⭐ DE AZI, sub prag bara poartă **SIGLA** — inițialele firmei, în pătratul cu care     ║
   ║ produsul marchează deja orice firmă (`semn_om.go`) —, apoi ☰ · ⌕ · ☾ · Ieși. O siglă  ║
   ║ de două litere nu are ce tăia; un nume are, oricât l-ai scurta.                       ║
   ║ ⚠️ Ce DISPARE sub prag, și e o hotărâre a lui Nelu: insigna de ROL, brandul dealerului║
   ║ și **numele omului** — „omul știe cine e". Sunt context, nu acțiune. Comutatorul de   ║
   ║ temă și „Ieși" rămân: alea sunt fapte, iar o faptă nu se citește o dată.               ║
   ║ ⛔ Numele firmei rămâne în pagină, pe sigla: `title` și `aria-label` îl poartă întreg, ║
   ║ deci cine chiar vrea să afle firma îl are — fără să-l plătească toată lumea în pixeli.║
   ╠══════════════════════════════════════════════════════════════════════════════════════╣
   ║ ⛔⛔ INTEROGAREA E CEA CU DOUĂ MĂSURI, nu doar lățimea — și ăsta e defectul reparat.   ║
   ║ Un telefon ținut pe lat are **844 px lățime**: pragul de 820 nu-l prindea, deci bara  ║
   ║ primea forma de birou (meniu inline, căutare, rol, nume) și se rupea pe două rânduri. ║
   ║ „Mic" are două măsuri — vezi caseta lui `--prag-scund` din §19c. Aceeași întrebare,   ║
   ║ același răspuns, în amândouă locurile.                                                ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
@media (max-width: 820px), (max-height: 560px) and (max-width: 1024px) {
  .bs {
    flex-wrap: nowrap; align-items: center; min-height: var(--tinta);
    padding: var(--sp-1) var(--sp-3); gap: var(--sp-1);
  }
  .bs .bs-mob { display: inline-flex; flex: 0 0 auto; position: static; }
  /* ⛔ Cele TREI care pleacă: brandul, insigna de rol și numele omului. Vezi caseta. */
  .bs .bs-brand, .bs .bs-rol, .bs .bs-nume { display: none; }
  /* ⭐ SIGLA ia locul numelui de firmă. `overflow: visible` și `text-overflow: clip` nu
     sunt decor: fără ele, regula de birou („se scurtează cu …") ar fi rămas pe marca, iar
     cerința e că NIMIC nu se taie. Cu inițiale nici n-ar avea ce tăia — dar o regulă care
     mai poate tăia se reaprinde singură la primul nume lung. */
  .bs .bs-sigla { display: inline-flex; }
  .bs .bs-marca-lung { display: none; }
  /* ⭐⭐ SIGLA ÎNCĂRCATĂ, PE TELEFON: se schimbă desenul, nu se taie cel de birou.
     ╔════════════════════════════════════════════════════════════════════════════════════╗
     ║ ⛔⛔ BUGETUL BAREI DE TELEFON, RESOCOTIT LA 12.09.2026 — ȘI ERA DEJA DEPĂȘIT.        ║
     ║                                                                                     ║
     ║ Bugetul de la 08.09 socotea 24 (margini) + 20 (spații) + 44 (☰) + 44 (⌕) + ~34 (☾)  ║
     ║ + ~52 („Ieși") = ~218 px, deci sigla putea lua 132 și mai rămâneau ~40 de aer.       ║
     ║ ⛔ La 11.09, „Calc" a intrat în bară (runda 15) și n-a intrat nimeni în socoteală.   ║
     ║ MĂSURAT în Chrome la 390×844, cu o siglă lată de 7:1, ÎNAINTE de runda asta:         ║
     ║ spațiul liber al barei era ZERO, iar ☾ scăzuse de la 25 la 23 px și „Ieși" de la 43 ║
     ║ la 39 — adică bara chiar strângea butoane, tăcut. Un buget nescris e un buget rupt. ║
     ╠════════════════════════════════════════════════════════════════════════════════════╣
     ║ ⭐ SOCOTEALA DE AZI, cu plicul de mesaje adăugat, din cifre MĂSURATE la 390 px:     ║
     ║   24 (margini) + 28 (7 spații de 4) + 44 (☰) + 44 (⌕) + 44 (✉) + 60 („Calc")        ║
     ║   + 25 (☾) + 43 („Ieși") = 312 px. Rămân 78, deci sigla ia cel mult 72 și mai rămân  ║
     ║   6 px de aer. ⛔ Cifra plicului NU intră în socoteală, fiindcă stă pe COLȚUL lui —  ║
     ║   vezi caseta lui din §9.                                                            ║
     ╚════════════════════════════════════════════════════════════════════════════════════╝
     ⚠️ Când dealerul a încărcat și o formă SCURTĂ, aici se desenează EA (adresa vine din
     `semnulFirmei`); altfel e sigla întreagă, micșorată de max-width până încape. Nimic
     nu se taie și nimic nu se scurtează cu trei puncte — vezi hotărârea din 08.09.
     ⭐ Tocmai de aceea scăderea cerută de bugetul nou nu strică nimic pentru dealerul care
     și-a desenat forma scurtă: o siglă aproape pătrată încape în 72 px la 28 înălțime.
     Cel care n-a desenat una primește, ca și până azi, sigla lui întreagă micșorată. */
  .bs .bs-sigla-birou { display: none; }
  .bs .bs-sigla-telefon { display: inline-block; max-height: 28px; max-width: 72px; }
  /* ⛔ Plicul capătă ȚINTA DEGETULUI, ca ☰ și ⌕ de lângă el: pe birou e un semn mic într-o
     bară de 46 px, pe telefon e ceva ce se apasă. Cifra rămâne pe colț, deci lățimea nu se
     mișcă — vezi bugetul de mai sus. */
  .bs .bs-plic {
    min-width: var(--tinta); min-height: var(--tinta); justify-content: center;
  }
  .bs .bs-plic-pict { width: 18px; height: 18px; }
  .bs .bs-marca {
    flex: 0 0 auto; overflow: visible; text-overflow: clip;
    display: inline-flex; align-items: center; min-height: var(--tinta); padding: 0;
  }
  .bs .bs-spatiu { flex: 1 1 0; display: block; }

  /* Meniul și căutarea: ascunse până se apasă, apoi PANOU peste pagină. */
  .bs .bs-meniu, .bs .bs-cauta { display: none; }
  .bs:has(#bs-mob-meniu[open]) .bs-meniu,
  .bs:has(#bs-mob-cauta[open]) .bs-cauta {
    display: flex; position: absolute; left: 0; right: 0; top: 100%;
    background: var(--bara-panou); border-top: 1px solid var(--bara-linie);
    box-shadow: var(--umbra-plutire); padding: var(--sp-2) var(--sp-3);
    max-height: 70vh; overflow-y: auto; z-index: 20;
  }
  .bs:has(#bs-mob-meniu[open]) .bs-meniu { flex-direction: column; align-items: stretch; gap: 2px; }
  .bs .bs-cauta input { width: 100%; }

  /* Grupurile, în panou: submeniul se deschide ÎN flux, sub titlul lui. */
  .bs .bs-m > summary { padding: var(--sp-2); min-height: var(--tinta); display: flex; align-items: center; }
  /* ⭐ Eticheta unei familii („Colectoare", „Setări") NU capătă ținta de 44 px: nu se
     apasă. Ce se apasă sunt legăturile de sub ea, iar acelea o au din regula de mai jos. */
  .bs .bs-sub .bs-eticheta { padding: var(--sp-2) var(--sp-2) 2px; }
  .bs .bs-sub {
    position: static; background: transparent; border: 0; box-shadow: none;
    padding: 2px 0 var(--sp-1) var(--sp-4); min-width: 0;
  }
  .bs .bs-sub a { min-height: var(--tinta); display: flex; align-items: center; }
  /* ⛔⛔ REGULILE DE TELEFON ALE CĂUTĂRII NU MAI STAU AICI (08.09.2026) — s-au mutat lângă
     componenta lor, în §9b, imediat DUPĂ regulile ei de birou.
     MOTIVUL, măsurat: la specificitate egală câștigă regula scrisă mai jos în fișier, iar
     §19b stă ÎNAINTEA componentelor. Deci `.cauta-cutie input[type=search] { flex: 1 1 100% }`
     scrisă aici era ANULATĂ de regula de birou de mai jos — o regulă moartă, pe care o gardă
     o citea și o găsea în regulă. Ce ținea perechea pe două rânduri era doar `width: 100%`
     al butonului; în ziua în care cutia a primit `flex-wrap: nowrap`, telefonul s-a rupt.
     ⚠️ O interogare de media NU bate cascada. Vezi caseta din §9b. */
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   6. BANDA DE TITLU
   ══════════════════════════════════════════════════════════════════════════════════════
   Aceeași bandă pe toate ecranele: titlul în stânga, acțiunea principală în dreapta, iar
   dedesubt — pe ecranele care schimbă ceva — DESPRE CINE E VORBA.

   ⚠️ padding:0 EXPLICIT pe bandă. Banda E un <header>, iar câteva foi de ecran mai au încă
   regula veche „header{padding:16px 24px}" de pe vremea antetelor proprii. Măsurat pe dev:
   pe telefon banda ieșea 342 px într-un ecran de 390, adică începea cu 24 px mai înăuntru
   decât tabelul de sub ea. O regulă moștenită tăcut e tot o regulă. */
.pg-banda {
  background: var(--banda-fond);
  color: var(--banda-text);
  padding: 0;
  /* ⭐ LINIA E CHIAR DESPĂRȚIREA DE MENIU. Vezi caseta de la `--banda-fond`. */
  border-bottom: 1px solid var(--banda-linie);
}
.pg-banda-in {
  max-width: var(--lat); margin: 0 auto; padding: var(--sp-4) var(--lat-aer);
  display: flex; align-items: flex-end; justify-content: space-between;
  gap: var(--sp-4); flex-wrap: wrap;
}
body.lat-plin .pg-banda-in { max-width: none; }
.pg-banda h1 { margin: 0; font-size: var(--t-h1); font-weight: 700; line-height: 1.25; }
/* Titlul și „i"-ul pe același rând; cutia desfăcută trece pe toată lățimea. */
.pg-titlu { display: flex; flex-wrap: wrap; align-items: baseline; }
.pg-titlu .dece-pliat[open] { flex-basis: 100%; }
.pg-banda .pg-inapoi {
  display: inline-block; color: var(--accent); font-size: var(--t-mic2);
  text-decoration: none; margin-bottom: var(--sp-1);
}
.pg-banda .pg-inapoi:hover { text-decoration: underline; }
/* FIRIMITURILE — strămoșii paginii, pe un rând, deasupra titlului. Ultimul e „← părinte"
   și își păstrează culoarea de accent (regula de mai sus); ceilalți sunt mai stinși, ca
   ochiul să cadă pe cel de care are nevoie de nouă ori din zece.
   ⚠️ Se ÎNFĂȘOARĂ: pe telefon, patru niveluri cu nume de firmă nu încap pe un rând, iar
   un `nowrap` ar fi împins banda în afara ecranului — chiar lucrul reparat la padding. */
.pg-banda .pg-fir {
  display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 var(--sp-1);
  font-size: var(--t-mic2); margin-bottom: var(--sp-1);
}
.pg-banda .pg-fir a { color: var(--banda-text-slab); text-decoration: none; }
.pg-banda .pg-fir a:hover { text-decoration: underline; }
.pg-banda .pg-fir .pg-inapoi { margin-bottom: 0; }
.pg-banda .pg-fir-sep { color: var(--text-stins); }
/* Coloana din dreapta benzii: vecinii deasupra, acțiunea principală dedesubt. */
.pg-dreapta { display: flex; flex-direction: column; align-items: flex-end; gap: var(--sp-2); }
/* PRECEDENT / URMĂTOR — plimbarea prin parc, fără întoarcere la listă. Cifra din mijloc
   spune cât a mai rămas; capetele rămân scrise, dar stinse (vezi caseta din șablon). */
.pg-vecini {
  display: flex; align-items: baseline; gap: var(--sp-2);
  font-size: var(--t-mic2); white-space: nowrap;
}
.pg-vecini a { color: var(--accent); text-decoration: none; }
.pg-vecini a:hover { text-decoration: underline; }
.pg-vecini .pg-vecin-gol { color: var(--text-stins); }
.pg-vecini .pg-vecini-cifra { color: var(--banda-text-slab); font-variant-numeric: tabular-nums; }
/* ⭐⭐ BANDA „AL CUI E" — cercul firmei și numele ei, DEASUPRA titlului (11.09.2026).
   Vezi caseta lui `cineBanda`: pe ecranele al căror h1 e altceva („Contract 4/19.08.2026"),
   firma nu poate fi titlul — dar tot ea e lucrul pe care omul îl caută primul.
   ⛔ NU e un al doilea nivel de titlu: numele e la `--t-mare`, sub h1 ca mărime, iar ce-l
   face să se vadă e ANTURAJUL — cercul de lângă el —, exact soluția de pe fișa clientului.
   ⚠️ Punctul de lucru e mai stins decât firma: e unde, nu cine. */
.pg-banda .pg-cine {
  display: flex; align-items: center; flex-wrap: wrap; gap: var(--sp-2);
  margin-bottom: var(--sp-1);
}
.pg-banda .pg-cine-nume { font-size: var(--t-mare); font-weight: 700; line-height: 1.2; }
.pg-banda .pg-cine-nume a { color: inherit; text-decoration: none; }
.pg-banda .pg-cine-nume a:hover { text-decoration: underline; }
.pg-banda .pg-cine-loc { font-size: var(--t-mic2); color: var(--banda-text-slab); }
.pg-banda .pg-cine-loc::before { content: "·"; margin-right: var(--sp-2); color: var(--text-stins); }

/* „Al cui e" — sub titlu, dar tot în bandă și tot mare: e informația pentru care omul s-a
   uitat în sus. Punctele mediane se pun din CSS, ca o bucată goală să nu lase un separator
   orfan. */
.pg-banda .pg-cui {
  margin-top: var(--sp-1); font-size: var(--t-baza); color: var(--banda-text-slab);
  display: flex; flex-wrap: wrap; gap: 0 var(--sp-2);
}
.pg-banda .pg-cui span + span::before { content: "·"; margin-right: var(--sp-2); color: var(--text-stins); }
.pg-banda .pg-nota { margin-top: var(--sp-1); font-size: var(--t-mic2); color: var(--banda-text-slab); }
/* Acțiunea benzii: „+ Client nou", „+ Contract nou" — un pas care se DESCHIDE, nu o faptă.
   ⛔ Până la runda uniformizării butoanelor era butonul plin, iar pe o listă cu un buton de
   filtrare ieșeau două pline pe ecran. E butonul GOL al temei (§9), cu aceleași jetoane.
   Ce doar duce în altă parte nu stă aici: se scrie `Inapoia` ori ca legătură în pagină. */
.pg-banda .pg-act {
  background: var(--fond-card); color: var(--accent); border: 1px solid var(--accent);
  border-radius: var(--rot-mic); padding: var(--sp-2) var(--sp-3);
  font-size: var(--t-baza); font-weight: 600; text-decoration: none; white-space: nowrap;
}
.pg-banda .pg-act:hover { background: var(--accent-slab); color: var(--accent-tare); border-color: var(--accent-tare); text-decoration: none; }

@media (max-width: 820px) {
  /* Specificitatea trebuie s-o bată pe body.lat-lista de mai sus — un body gol (0,0,1)
     ar fi pierdut tăcut, iar telefonul ar fi rămas cu lățimea de birou. */
  body.lat-formular, body.lat-lista, body.lat-plin { --lat: 100%; }
  main { padding: var(--sp-4) var(--sp-3) var(--sp-6); }
  .pg-banda-in { padding: var(--sp-3); }
  /* Pe telefon titlul coboară un pas — dar rămâne CEL MAI MARE lucru de pe ecran, iar
     cifra iese tot din scară, nu scrisă de mână (a fost 19px, de la un --t-h1 de 21). */
  .pg-banda h1 { font-size: var(--t-cifra-mare); }
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   6b. POARTA — login, alegerea firmei, resetarea de parolă
   ══════════════════════════════════════════════════════════════════════════════════════
   Trei ecrane care se arată ÎNAINTE să existe cineva: aceeași casetă albă, centrată, pe
   fondul închis al produsului. Erau scrise de trei ori, cu aceleași cifre copiate.

   ⛔ POARTA RĂMÂNE LUMINOASĂ, în amândouă modurile, și nu e o scăpare: modul e o
   preferință a CONTULUI, iar aici nu se știe încă al cui e contul. Fondul închis vine din
   `--bara-fond`, adică din coaja produsului — deci ecranul de login arată la fel cu bara
   pe care omul o va vedea o secundă mai târziu. */
body.poarta {
  display: flex; min-height: 100vh; align-items: center; justify-content: center;
  background: var(--bara-fond); padding: var(--sp-4);
}
.poarta .box {
  background: var(--fond-card); color: var(--text);
  border-radius: var(--rot-mare); box-shadow: var(--umbra-plutire);
  padding: var(--sp-6); width: 380px; max-width: 100%;
}
/* Într-o poartă butonul e SINGURA faptă, deci ocupă toată lățimea casetei. */
.poarta button { width: 100%; margin-top: var(--sp-5); padding: var(--sp-3); font-size: var(--t-mare); }
.poarta .inapoi, .poarta .uitat {
  display: block; margin-top: var(--sp-4); text-align: center; font-size: var(--t-mic2);
}
/* ⭐⭐ SIGLA DEALERULUI PE UȘĂ (11.09.2026, migrarea 0084). Ea stă ÎN h1 — e chiar titlul
   paginii —, deci `h1`-ul își pierde aici mărimea de literă și devine doar locul ei.
   ⛔ Aceleași patru rânduri ca în bară, și din același motiv: nu se întinde, nu se taie.
   Cutia e mai mare (320 × 48 px CSS) fiindcă aici sigla n-are cu ce concura: e singurul
   lucru din capul casetei.
   ⚠️ Caseta e ALBĂ în amândouă modurile (vezi caseta de sus), deci o siglă care se citește
   pe hârtie se citește și aici — și de-asta previzualizarea din Setări arată AMÂNDOUĂ
   fundalurile, nu doar pe cel închis. */
.poarta h1:has(.poarta-sigla) { line-height: 1; }
/* ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⛔⛔ `min(320px, 100%)`, NU `320px` — DEFECTUL VĂZUT DE NELU PE PRODUCȚIE (08.09.2026).║
   ║                                                                                       ║
   ║ Sigla lui are raportul 7:1. Măsurat în Chrome, ÎNAINTE de reparație:                  ║
   ║                                                                                       ║
   ║   la 1400 px — sigla desenată 320 px, caseta 316 px  ⇒ IEȘEA CU 4 px                  ║
   ║   la  390 px — sigla desenată 320 px, caseta 294 px  ⇒ IEȘEA CU 26 px                 ║
   ║                                                                                       ║
   ║ ⛔ CAUZA NU ERA „se încadrează după înălțime". Lățimea CHIAR mărginea (imaginea are    ║
   ║ 640 px intrinseci, iar `max-width` o oprea la 320) — dar o mărginea la o cifră        ║
   ║ ABSOLUTĂ, care nu știe cât de lată e caseta. Caseta are 380 px cu `--sp-6` de o parte ║
   ║ și de alta, deci 316 px de conținut pe birou; la 390 px ea se strânge la 294. Cifra   ║
   ║ 320 era mai mare decât amândouă — de la prima zi, pentru ORICE siglă lată. O siglă    ║
   ║ pătrată încăpea (48×48), și de aceea defectul a stat ascuns până a încărcat Nelu una. ║
   ║                                                                                       ║
   ║ ⭐ REGULA, SCRISĂ ÎNTREAGĂ: sigla încape în cutia dată, ORICARE i-ar fi raportul.     ║
   ║ `320px` rămâne fiindcă face o treabă adevărată — imaginea e tăiată la DUBLU (640 px), ║
   ║ deci fără el s-ar desena la mărimea ei brută. `100%` e cealaltă jumătate: caseta.     ║
   ║ Cine dă de perete primul oprește, iar înălțimea urmează. Nu se taie, nu se întinde.   ║
   ║ ⚠️ `100%` se socotește pe `h1`, care e bloc, deci chiar pe lățimea de conținut a      ║
   ║ casetei — de aceea sigla stă în `h1` și nu într-un `span` care s-ar strânge.          ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
.poarta .poarta-sigla {
  display: inline-block; width: auto; height: auto; object-fit: contain;
  max-height: 48px; max-width: min(320px, 100%);
}

/* ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⭐⭐ POARTA URMEAZĂ MODUL SISTEMULUI (Nelu, 08.09.2026) — RĂSTOARNĂ nota de mai sus.   ║
   ║                                                                                       ║
   ║ Până azi caseta rămânea LUMINOASĂ în amândouă modurile, cu motivul scris: „modul e o  ║
   ║ preferință a CONTULUI, iar aici nu se știe încă al cui e contul". Adevărat — dar      ║
   ║ rezultatul măsurat era o casetă `#ffffff` pe o pagină `#161616`, la orice oră și pe   ║
   ║ orice mașină. Nelu: „ia culorile temei, ca restul produsului."                        ║
   ║                                                                                       ║
   ║ ⛔ CONTUL NU SE ȘTIE, DAR SISTEMUL SE ȘTIE. `prefers-color-scheme` e singurul lucru    ║
   ║ care se poate afla despre un om înainte ca el să spună cine e — și e chiar întrebarea ║
   ║ pe care produsul i-o pune o secundă mai târziu, din contul lui.                        ║
   ║                                                                                       ║
   ║ ⛔⛔ VALORILE SUNT COPIA SETULUI ÎNTUNECAT, ȘI NU SE POT DESPĂRȚI DE EL: garda         ║
   ║ `TestPoartaAreExactCulorileIntunericului` compară rând cu rând blocul ăsta cu         ║
   ║ `body.tema-intunecat` și cade dacă vreo valoare diferă ori dacă una nouă apare doar   ║
   ║ într-unul din ele. E singura formă în care CSS-ul curat poate avea două porți de      ║
   ║ intrare spre același set — un preprocesor n-avem, iar `matchMedia` ar fi fost un al   ║
   ║ doilea prag în JavaScript (hotărârea din 08.09).                                       ║
   ║ ⚠️ Aici se redefinesc DOAR valori, ca în §2. Nicio regulă de componentă.               ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
@media (prefers-color-scheme: dark) {
  html:has(body.poarta) { color-scheme: dark; }
  body.poarta {
    --g-coaja: #101319;
    --g-baza: #1a1d23;
    --g-sus: #21252e;
    --g-slab: #2b303a;
    --g-apasat: #363c47;
    --g-linie: #3a404c;
    --g-linie-slaba: #2b303a;

    --fond: var(--g-baza);
    --fond-card: var(--g-sus);
    --fond-slab: var(--g-slab);
    --fond-apasat: var(--g-apasat);

    --text: #f4f4f4;
    --text-slab: #c6c6c6;
    --text-stins: #a8a8a8;
    --text-pe-inchis: #f4f4f4;
    --schema: dark;

    --linie: var(--g-linie);
    --linie-slaba: var(--g-linie-slaba);

    --accent: #78a9ff;
    --accent-tare: #a6c8ff;
    --accent-slab: #1c2a44;

    --buton-fond: #0f62fe;
    --buton-fond-hover: #4589ff;
    --buton-text: #ffffff;

    --rau-semn: #fa4d56;   --rau-fond: #3b1f22;   --rau-text: #ffb3b8;

    --bara-fond: var(--g-coaja);

    --umbra-plutire: 0 12px 28px rgba(0, 0, 0, .5);
  }
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   6c. PREVIZUALIZAREA SIGLEI — pe fundal închis ȘI pe fundal deschis
   ══════════════════════════════════════════════════════════════════════════════════════
   ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⛔⛔ CELE DOUĂ CASETE NU URMEAZĂ TEMA OMULUI, ȘI ĂSTA E TOT ROSTUL LOR.               ║
   ║                                                                                       ║
   ║ Sigla dealerului ajunge în DOUĂ locuri cu fundaluri opuse: bara neagră a produsului  ║
   ║ și hârtia albă a borderoului. Cerința lui Nelu e ca el să vadă amândouă ÎNAINTE de a ║
   ║ salva. Dacă previzualizarea s-ar fi desenat în tema lui, dealerul care lucrează pe   ║
   ║ întuneric ar fi văzut de două ori același fundal — adică exact jumătatea de răspuns  ║
   ║ pe care caseta trebuia s-o dea întreagă.                                              ║
   ║                                                                                       ║
   ║ ⛔ ȘI NICIO PĂRERE DESPRE CONTRAST. Aici nu se calculează niciun raport și nu se      ║
   ║ aprinde niciun avertisment: se ARATĂ. Ochiul dealerului hotărăște dacă marca lui se  ║
   ║ citește pe amândouă — e marca lui.                                                    ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝
   ⚠️ Fondul în tablă de șah, sub siglă: fără el, o siglă cu fundal transparent și una cu
   fundal alb arată IDENTIC pe caseta deschisă — iar deosebirea dintre ele se vede abia în
   bara neagră, adică prea târziu. */
.sigla-probe { display: flex; flex-wrap: wrap; gap: var(--sp-3); margin: var(--sp-3) 0; }
.sigla-probe > * { flex: 1 1 220px; min-width: 0; }
.sigla-proba {
  display: flex; align-items: center; justify-content: center;
  min-height: 84px; padding: var(--sp-3); border-radius: var(--rot);
  border: 1px solid var(--linie);
  background-image:
    linear-gradient(45deg, rgba(128,128,128,.22) 25%, transparent 25%),
    linear-gradient(-45deg, rgba(128,128,128,.22) 25%, transparent 25%),
    linear-gradient(45deg, transparent 75%, rgba(128,128,128,.22) 75%),
    linear-gradient(-45deg, transparent 75%, rgba(128,128,128,.22) 75%);
  background-size: 12px 12px;
  background-position: 0 0, 0 6px, 6px -6px, -6px 0;
}
.sigla-proba.inchis { background-color: var(--bara-fond); }
.sigla-proba.deschis { background-color: var(--hartie); }
/* ⛔ Aceleași patru rânduri ca peste tot unde apare sigla: nu se întinde, nu se taie. */
.sigla-proba img {
  width: auto; height: auto; object-fit: contain;
  max-height: 60px; max-width: 100%;
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   7. CARDUL
   ══════════════════════════════════════════════════════════════════════════════════════
   ⛔ O SINGURĂ DEFINIȚIE. Măsurat înainte: 25 de definiții ale lui `.card` (margine
   interioară 16 / 16×20 / 18×22 / 20 / 20×24 / 22, unele cu chenar, altele cu umbră, rază
   8 / 10 / 12). Un ecran nou N-ARE VOIE să-și scrie propriul `.card`; garda o cere. */
.card {
  background: var(--fond-card);
  border: 1px solid var(--linie);
  border-radius: var(--rot-mare);
  padding: var(--sp-4);
  margin-bottom: var(--sp-3);
}
/* ⛔⛔ ȘI PRIN SECȚIUNEA PLIABILĂ (06.09.2026). `static/sectiuni.js` bagă un `<details>`
   ÎNTRE card și conținutul lui, iar cele trei reguli `.card > …` din foaia asta sunt
   COMBINATORI DE COPIL DIRECT: fără rândul în plus, ele nu mai prind nimic pe cele ~85 de
   secțiuni. Ce s-ar fi văzut: un al DOILEA chenar în jurul fiecărui tabel dintr-un card
   (`.card > .sx > table` nu mai ajungea), exact ce zice comentariul de mai jos că se
   citește ca o greșeală de randare. Prins înainte să ajungă pe ecran, citind foaia.
   ⚠️ Selectorul nou e ADĂUGAT, nu pus în locul celui vechi: specificitatea fiecărui
   selector dintr-o listă e a lui, deci cel vechi rămâne exact cât era. */
.card > :last-child,
.card > details.sectiune > :last-child { margin-bottom: 0; }
/* Titlul unui card: mărunt, majuscule, gri — e o etichetă de secțiune, nu un al doilea h1. */
.card h3, .card-titlu {
  margin: 0 0 var(--sp-1); font-size: var(--t-mic);
  text-transform: uppercase; letter-spacing: .04em;
  color: var(--text-slab); font-weight: 700;
}
/* Un card care nu are nimic de arătat. */
.gol {
  padding: var(--sp-5) var(--sp-4); color: var(--text-stins); font-style: italic;
  background: var(--fond-card); border: 1px solid var(--linie); border-radius: var(--rot-mare);
  text-align: center;
}
/* ...iar când e DEJA într-un card, e doar propoziția: două chenaruri la 1 px distanță se
   citesc ca o greșeală de randare, nu ca o intenție. Aceeași regulă ca la tabel. */
.card > .gol, .card > .sx > .gol,
.card > details.sectiune > .gol,
.card > details.sectiune > .sx > .gol { border: 0; background: none; border-radius: 0; }

/* ---------- TEXTELE DE LÂNGĂ LUCRU ---------- */
/* .expl — propoziția care explică un câmp sau un rând. */
.expl { color: var(--text-slab); font-size: var(--t-mic2); line-height: var(--ritm); margin: var(--sp-1) 0 0; }
/* .marunt — adaosul de lângă lucrul principal: hostname-ul de lângă punctul de lucru,
   seria de lângă model. ⚠️ Pentru explicația unui câmp e `.expl`. */
.marunt { font-size: var(--t-mic); color: var(--text-stins); font-weight: 400; }
.mic { font-size: var(--t-mic2); color: var(--text-slab); }

/* ══════════════════════════════════════════════════════════════════════════════════════
   8. „i" — DE CE-UL, DISCRET
   ══════════════════════════════════════════════════════════════════════════════════════
   ⭐ REGULA DIN 22 AUGUST: FAPTUL SCURT, DE CE-UL DISCRET. Paginile începeau cu două-trei
   paragrafe care JUSTIFICĂ ecranul; ele se citesc o dată, iar ecranul se deschide de o mie
   de ori. Deci: un „i" lângă titlu, care le desface. Textul nu dispare din produs — un
   motiv scos cu totul e un motiv pe care îl reinventează altcineva peste un an. */
.dece {
  display: inline-block; width: 15px; height: 15px; line-height: 15px; text-align: center;
  border-radius: 50%; background: var(--fond-apasat); color: var(--text-slab);
  font-size: 10px; font-weight: 700; cursor: help; vertical-align: middle;
}
.dece-pliat { display: inline-block; vertical-align: middle; margin-left: var(--sp-2); }
.dece-pliat > summary {
  list-style: none; cursor: pointer; display: inline-flex; align-items: center;
  justify-content: center; width: 19px; height: 19px; border-radius: 50%;
  border: 1px solid var(--linie); color: var(--text-slab); background: var(--fond-card);
  font-size: var(--t-mic); font-weight: 700; font-style: italic; line-height: 1;
  font-family: Georgia, "Times New Roman", serif;
}
.dece-pliat > summary::-webkit-details-marker { display: none; }
.dece-pliat > summary:hover { border-color: var(--accent); color: var(--accent); }
/* Cutia se desface SUB titlu, pe toată lățimea, nu lângă semn: o notă de patru rânduri
   înghesuită într-o coloană de 19 px ar fi mai greu de citit decât paragraful de dinainte. */
.dece-pliat[open] { display: block; margin: var(--sp-2) 0 0; }
.dece-cutie {
  margin-top: var(--sp-2); padding: var(--sp-3); background: var(--fond-slab);
  border: 1px solid var(--linie); border-radius: var(--rot);
  color: var(--text-slab); font-size: var(--t-mic2); line-height: 1.55; max-width: 80ch;
}
.dece-cutie p { margin: 0 0 var(--sp-2); }
.dece-cutie p:last-child { margin-bottom: 0; }
.dece-cutie ul { margin: var(--sp-1) 0 0; padding-left: var(--sp-5); }
.dece-cutie strong { color: var(--text); }

/* ⭐ MODELUL SCURTAT, CU ÎNTREGUL LA HOVER (06.09.2026).
   Aparatele își spun numele cum vor: un RICOH raportează patru denumiri despărțite cu „/",
   un Lexmark își pune versiunea de kernel în el. Pe ecran se vede denumirea de bază; restul
   stă în `title`, la trecerea mouse-ului.
   ⚠️ SEMNUL E DISCRET, ȘI DELIBERAT — o subliniere punctată, aceeași convenție ca la „i".
   Un semn mai apăsat ar fi strigat pe un rând în care nu se ascunde nimic important; unul
   absent n-ar fi lăsat pe nimeni să bănuiască că mai e ceva de văzut.
   ⛔ Elementul apare NUMAI când chiar s-a tăiat ceva (vezi `cuIntregulLaHover`), deci
   regula asta nu atinge numele întregi. */
.ap-taiat { border-bottom: 1px dotted var(--linie); cursor: help; }

/* Răspunsul BRUT al aparatului, așa cum a venit: monospațiat, într-o cutie stinsă.
   ⛔ ERA ÎN STILUL UNUI SINGUR ECRAN (mutată aici 06.09.2026). De când sysDescr-ul se
   pliază și pe fișă, și pe clasificare, cutia asta se cere pe trei ecrane — iar o regulă
   ținută în <style>-ul unuia lăsa celelalte două cu textul brut atârnând în pagină. */
.brut { background: var(--fond-slab); border: 1px solid var(--linie);
        border-radius: var(--rot); padding: var(--sp-2); margin-top: var(--sp-1); }
.brut code { word-break: break-all; }

/* ══════════════════════════════════════════════════════════════════════════════════════
   9. BUTOANE
   ══════════════════════════════════════════════════════════════════════════════════════
   ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⭐⭐ TREI FORME, UNA PENTRU FIECARE ÎNȚELES — hotărâte de Nelu și de arhitect la      ║
   ║ runda uniformizării butoanelor (14.09.2026):                                          ║
   ║                                                                                       ║
   ║  · PLIN — `.btn-principal`: fapta PRINCIPALĂ a ecranului, care schimbă ceva greu de   ║
   ║    întors. ⛔ UNUL SINGUR pe ecran. Acțiunea benzii (`.pg-act`, §6) NU e el: deschide  ║
   ║    un pas, deci e gol.                                                                ║
   ║    Un ecran de citit n-are niciunul.                                                  ║
   ║  · GOL — `button` și `.btn`: o faptă reversibilă, sau una care deschide un pas.      ║
   ║    `.btn-pericol` e tot gol, în culoarea stării rele; `.btn-mic` e doar mai mic.      ║
   ║  · LEGĂTURĂ SUBLINIATĂ — un `<a>` fără clasă de buton (§2): te duce în altă parte și  ║
   ║    nu schimbă nimic.                                                                  ║
   ╠══════════════════════════════════════════════════════════════════════════════════════╣
   ║ ⛔ MĂSURAT ÎNAINTE, pe cele 89 de pagini randate ale gărzilor: 25 de ecrane cu mai    ║
   ║ multe butoane pline (9 pe Setări → Firmă), 31 de fapte scrise ca legătură, 45 de      ║
   ║ legături desenate ca buton. Cauza e scrisă chiar în caseta care stătea aici: „`.btn`  ║
   ║ singur e primarul" și „`button` gol e tot butonul primar" — deci ORICE buton ieșea    ║
   ║ plin, iar „unul singur pe ecran" nu-l ținea nimic.                                     ║
   ║ ⭐ De aceea implicitul s-a întors: un buton fără clasă e GOL, iar plinul se CERE pe     ║
   ║ nume. Un buton uitat iese discret, nu strigă.                                         ║
   ╠══════════════════════════════════════════════════════════════════════════════════════╣
   ║ ⛔ Un al patrulea fel se adaugă AICI sau deloc — și nicio culoare ori mărime de buton  ║
   ║ în stilul unui ecran (garda `TestNiciunEcranNuDeseneazaButoaneleInAfaraTemei`, pe     ║
   ║ pagina randată). Au plecat din temă `.gri`, `.btn-secundar`, `.rosu`, `.btn.mic` (nume ║
   ║ vechi ale acelorași forme) și `.ca-link`, `.link-rosu`, `.link-dezactiv`,              ║
   ║ `.link-reactiv` — butoane fără chenar și fără fond, adică fapte cu chip de legătură.  ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
button, .btn {
  display: inline-block; box-sizing: border-box;
  background: var(--fond-card); color: var(--accent);
  border: 1px solid var(--accent); border-radius: var(--rot-mic);
  padding: var(--sp-2) var(--sp-3);
  font: inherit; font-size: var(--t-baza); font-weight: 600; line-height: 1.4;
  cursor: pointer; text-decoration: none; text-align: center; white-space: nowrap;
}
button:hover, .btn:hover { background: var(--accent-slab); color: var(--accent-tare); border-color: var(--accent-tare); text-decoration: none; }
button:active, .btn:active { background: var(--accent-slab); }

/* PLIN — fapta principală. ⚠️ `:hover` și `:active` au clasa lor: fără ele, `button:hover`
   (0,1,1) ar fi bătut `.btn-principal` (0,1,0) și butonul plin s-ar fi golit sub mouse. */
.btn-principal {
  background: var(--buton-fond); color: var(--buton-text); border-color: transparent;
}
.btn-principal:hover { background: var(--buton-fond-hover); color: var(--buton-text); border-color: transparent; }
.btn-principal:active { background: var(--accent-tare); }

/* PERICOL — ștergerea, dezactivarea, retragerea. Contur, nu plin: un buton roșu plin
   într-un rând de acțiuni atrage ochiul înaintea faptei obișnuite, adică exact invers. */
.btn-pericol {
  background: var(--fond-card); color: var(--rau-text); border-color: var(--rau-semn);
}
.btn-pericol:hover { background: var(--rau-fond); color: var(--rau-text); border-color: var(--rau-semn); }
.btn-pericol:active { background: var(--rau-fond); }

/* ⛔⛔ PESTE HARTĂ, LEAFLET ÎȘI COLOREAZĂ LEGĂTURILE (runda balonului, 14.09.2026, măsurat în
   Chrome, nu presupus). `leaflet.css` scrie `.leaflet-container a { color: #0078A8 }` — (0,1,1),
   mai tare decât `.btn` (0,1,0). Deci „Navighează ↗", singurul buton-legătură din balon, ieșea
   TEAL lângă „Copiază locația" albastru, iar noaptea teal închis pe grafit, abia lizibil.
   ⭐ `:where()` ține specificitatea la (0,1,1): egală cu a lui Leaflet, câștigă prin ordine
   (tema se încarcă DUPĂ `leaflet.css`), dar pierde în fața `.btn:hover` (0,2,0) — deci
   trecerea mouse-ului rămâne a butonului. Plinul și pericolul își repun culoarea lor, altfel
   regula de sus le-ar fi bătut (0,1,0). Proba: `_dev-probe-balon.js`, „aceeași formă". */
:where(.leaflet-container) a.btn { color: var(--accent); }
:where(.leaflet-container) a.btn-principal { color: var(--buton-text); }
:where(.leaflet-container) a.btn-pericol { color: var(--rau-text); }

/* DEZACTIVAT — o singură înfățișare pentru toate trei, și pentru `<a>` care ține locul
   unui buton (`aria-disabled`), fiindcă un link nu poate fi `:disabled`. */
button:disabled, .btn:disabled, .btn[aria-disabled="true"], .btn.dezactivat {
  background: var(--fond-slab); color: var(--text-stins); border-color: var(--linie);
  cursor: not-allowed; opacity: 1;
}
button:disabled:hover, .btn:disabled:hover, .btn[aria-disabled="true"]:hover, .btn.dezactivat:hover {
  background: var(--fond-slab); color: var(--text-stins);
}
/* ⛔⛔ AICI ERAU PATRU BUTOANE CU CHIP DE LEGĂTURĂ (`.ca-link`, `.link-rosu`, `.link-dezactiv`,
   `.link-reactiv`): fără chenar, fără fond, text colorat. Motivul lor era bun pe jumătate —
   o faptă POST trebuie să fie un `<button>`, nu un `<a href>` —, iar cealaltă jumătate era
   greșită: „în rândul lor citesc ca o legătură". Pe ecran „Retrage accesul" arăta EXACT ca
   „Modifică" de lângă el, deși unul îi închide omului sesiunile și celălalt doar deschide o
   pagină. De azi fapta dintr-un rând e `.btn-mic` (gol), iar cea care scoate ceva din uz e
   `.btn-mic.btn-pericol`. Garda: `TestNicioFaptaNuEScrisaCaLegatura`. */

/* Butonul mărunt — din capătul unui rând de tabel, ori din rândul de sub un card. Aceeași
   formă, doar mai mică. */
.btn-mic { padding: var(--sp-1) var(--sp-2); font-size: var(--t-mic2); font-weight: 600; }
/* Rândul de acțiuni de sub un formular. */
.actiuni-form { margin-top: var(--sp-5); display: flex; gap: var(--sp-2); align-items: center; flex-wrap: wrap; }

/* ══════════════════════════════════════════════════════════════════════════════════════
   10. FORMULARE
   ══════════════════════════════════════════════════════════════════════════════════════ */
label {
  display: block; font-size: var(--t-mic2); color: var(--text-slab);
  margin: var(--sp-3) 0 var(--sp-1);
}
input, select, textarea {
  width: 100%; box-sizing: border-box;
  padding: var(--sp-2) var(--sp-3);
  border: 1px solid var(--linie); border-radius: var(--rot-mic);
  background: var(--fond-card); color: var(--text);
  font: inherit; font-size: var(--t-baza);
}
textarea { line-height: var(--ritm); resize: vertical; }
/* Un câmp în care se lipește TEXT DE MAȘINĂ — CSV, o listă de OID-uri, valori de contor.
   Familia monospațiată face coloanele vizibile ÎNAINTE de a apăsa ceva, adică exact
   când omul mai poate repara lipitura. */
textarea.cod { font-family: var(--font-cod); font-size: var(--t-mic2); }
/* ⚠️ `width:100%` de mai sus e regula formularului STIVUIT — eticheta deasupra, câmpul
   sub ea — adică forma a nouăsprezece din cele douăzeci de ecrane cu câmpuri. Un câmp
   care stă ÎN RÂND cu altceva (o celulă de tabel, rândul de filtre, căutarea din bară) se
   întinde după conținut; scris invers, fiecare formular ar fi avut de cerut lățimea, iar
   cel care uita ieșea cu câmpuri de mărimi diferite în aceeași coloană. */
table input, table select, table textarea,
.fl input, .fl select, .bs input,
.camp-auto { width: auto; }
input[type="checkbox"], input[type="radio"] { width: auto; accent-color: var(--accent); }
input::placeholder, textarea::placeholder { color: var(--text-stins); }
input:focus-visible, select:focus-visible, textarea:focus-visible {
  outline: 2px solid var(--accent); outline-offset: 0; border-color: var(--accent);
}
input:disabled, select:disabled, textarea:disabled {
  background: var(--fond-slab); color: var(--text-stins); cursor: not-allowed;
}
/* Un câmp care a fost refuzat de server. `aria-invalid` e ȘI marcajul pe care îl citește
   cititorul de ecran, deci starea are un singur purtător, nu o clasă plus un atribut. */
input[aria-invalid="true"], select[aria-invalid="true"], textarea[aria-invalid="true"] {
  border-color: var(--rau-semn); background: var(--rau-fond);
}
.camp-eroare { color: var(--rau-text); font-size: var(--t-mic2); margin-top: var(--sp-1); }

/* ---------- GRILA DE CÂMPURI ----------
   Patru ecrane (feeduri, presete, cele două importuri) desenau aceeași grilă de câmpuri,
   fiecare cu propriile cifre. Sunt câmpuri care stau UNUL LÂNGĂ ALTUL fiindcă se citesc
   împreună; lățimea de bază se dă în `ch`, adică în caractere — o măsură de conținut, nu
   de pagină (de aceea nici nu se lovește de regula celor trei lățimi). */
.grila { display: flex; flex-wrap: wrap; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.camp { flex: 1 1 20ch; min-width: 13ch; }
.campLat { flex: 1 1 44ch; min-width: 20ch; }
/* ---------- DOUĂ COLOANE ----------
   Conținutul principal, și lucrurile de lângă el (previzualizarea, ajutorul, istoricul).
   Trei ecrane (tarife, șabloane de tarif, fișa aparatului) o desenau cu aceleași trei
   clase și trei seturi de cifre. Se strânge singură pe telefon: `flex-wrap`, nu o
   interogare de media — coloanele se pun una sub alta când nu mai încap, oricare ar fi
   lățimea ferestrei. */
.doua { display: flex; gap: var(--sp-5); align-items: flex-start; flex-wrap: wrap; }
.stanga { flex: 1 1 540px; min-width: 0; }
.dreapta { flex: 1 1 330px; min-width: 0; }
/* Titlul mărunt al unei secțiuni dintr-o coloană. */
.sec-titlu {
  font-size: var(--t-mic); text-transform: uppercase; letter-spacing: .03em;
  color: var(--text-stins); margin: var(--sp-5) 0 var(--sp-2);
}
.sec-titlu:first-child { margin-top: 0; }
/* Rândul „titlu de secțiune la stânga, acțiunea ei la dreapta". ⚠️ `.bara` e o secțiune
   DIN pagină; bara de sus a produsului e `.bs`. */
.bara { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--sp-4); flex-wrap: wrap; gap: var(--sp-2); }
.bara h2 { font-size: var(--t-baza); text-transform: uppercase; letter-spacing: .04em; color: var(--text-slab); margin: 0; }

/* Rândul de butoane al unui card — același lucru ca `.actiuni-form`, alt nume moștenit. */
.butoane { margin-top: var(--sp-2); display: flex; gap: var(--sp-1); flex-wrap: wrap; align-items: center; }
/* `.lk` — legătura mărunte de lângă un rând. Culoarea e a legăturilor, mărimea e a notelor. */
a.lk, .lk { font-size: var(--t-mic2); }
/* `.eticheta` — pastila mică de lângă un titlu de card. */
.eticheta {
  font-size: var(--t-xs); text-transform: uppercase; letter-spacing: .04em;
  background: var(--neutru-fond); color: var(--neutru-text);
  border-radius: var(--rot-pastila); padding: 2px var(--sp-2);
  margin-left: var(--sp-1); vertical-align: middle;
}
.eticheta.asteapta { background: var(--avert-fond); color: var(--avert-text); }
/* Secțiunea de ajutor pliată dintr-un card. */
details.ajutor > summary { cursor: pointer; color: var(--text-slab); font-size: var(--t-mic); }
details.ajutor p { font-size: var(--t-mic2); color: var(--text-slab); margin: var(--sp-1) 0 0; }
/* Un formular care e doar un gest într-un rând, nu o secțiune. */
form.inline { display: inline; }

/* Câmpul de dată: textul în formatul dealerului, calendarul nativ mic lângă el. */
.camp-data { display: flex; align-items: center; gap: var(--sp-1); width: 100%; }
.camp-data input[type=text] { flex: 1 1 auto; min-width: 0; }
/* ⛔⛔ DOAR PICTOGRAMA CALENDARULUI, NU ȘI ZIUA (18.09.2026, /audit pe producție): cu
   `width: auto`, câmpul nativ își scria și el ziua, în formatul BROWSERULUI („mm/dd/yyyy"),
   lângă câmpul nostru („zz.ll.aaaa") — două date pe același rând, în două convenții. Ziua
   o scrie numai câmpul de text; cel nativ rămâne butonul care deschide calendarul. */
.camp-data .camp-data-cal {
  flex: 0 0 auto; width: 2.4em; min-width: 0; padding: var(--sp-1);
  color: transparent; font-size: var(--t-mic2); overflow: hidden; cursor: pointer;
}
.camp-data .camp-data-cal::-webkit-datetime-edit { display: none; }
.camp-data .camp-data-cal::-webkit-calendar-picker-indicator { margin: 0; cursor: pointer; }

/* ══════════════════════════════════════════════════════════════════════════════════════
   10b. BIFELE UNUI TARIF, PREVIZUALIZAREA LUI, LISTA DE LIPSURI
   ══════════════════════════════════════════════════════════════════════════════════════
   ⛔⛔ AICI STĂTEAU ÎN <style>-URILE A DOUĂ ECRANE (runda „contractul: așezare", 15.09.2026).
   Nelu, uitându-se la contract: „nu respectă tema". Măsurat pe pagina contractului: 17 atribute
   `style=` și 101 declarații în două blocuri <style>, dintre care 26 cu o cifră scrisă de mână.
   Iar bifele de pe rândul echipamentului nu primeau NICIUNA dintre regulile de mai jos: stilul
   lor era într-un fragment pe care setul contractelor nu-l chema. De azi sunt ale temei, deci
   ajung oriunde se desenează bifele — șablonul de tarif, istoricul, echipamentul contractat.
   ⚠️ Selectorii poartă containerul (`.grupuri > .grup`): `.grup` scris singur ar fi prins și
   grupurile panoului de alerte de pe lista de contracte, care își au forma lor. */
.grupuri { display: flex; flex-direction: column; gap: var(--sp-3); }
.grupuri > .grup { border: 1px solid var(--linie); border-radius: var(--rot-mare);
                   padding: var(--sp-3); background: var(--fond-card); }
.grupuri > .grup > h4 { margin: 0 0 var(--sp-1); font-size: var(--t-mic); text-transform: uppercase;
                        letter-spacing: .04em; color: var(--text-stins); }
.grupuri > .grup > .expl-grup { margin: 0 0 var(--sp-2); font-size: var(--t-mic); color: var(--text-stins); }
.bifa { border-top: 1px solid var(--linie-slaba); padding: var(--sp-2) 0 var(--sp-1); }
.grupuri > .grup .bifa:first-of-type { border-top: 0; padding-top: var(--sp-1); }
.bifa > label.cap { display: flex; align-items: center; gap: var(--sp-2); font-size: var(--t-baza);
                    margin: 0; cursor: pointer; font-weight: 600; color: var(--text); }
.bifa > label.cap input { width: auto; margin: 0; }
.campuri { display: flex; gap: var(--sp-3); flex-wrap: wrap; margin: var(--sp-2) 0 var(--sp-1) var(--sp-5); }
.campuri > div { flex: 0 1 20ch; min-width: 13ch; }
.campuri label { margin: 0 0 var(--sp-1); font-size: var(--t-mic); }
/* Previzualizarea rămâne la vedere cât timp bifezi: se lipește sub bară, nu sub marginea
   ferestrei — de aceea cifra vine din înălțimea bării. */
.prev { position: sticky; top: calc(var(--bs-inaltime) + var(--sp-2)); }
.prev table { width: 100%; }
.prev td, .prev th { padding: var(--sp-1) var(--sp-2); font-size: var(--t-mic2); }
.prev .total td { border-top: 2px solid var(--text); font-weight: 700; font-size: var(--t-mare); }
.prev .nota-rand { color: var(--text-stins); font-size: var(--t-xs); }
/* Propoziția care spune, în cuvinte, ce a ieșit din bife: o casetă de informare. */
.propozitie { background: var(--info-fond); color: var(--info-text);
              border-left: 3px solid var(--info-semn); border-radius: var(--rot);
              padding: var(--sp-2) var(--sp-3); font-size: var(--t-mic2); margin-bottom: var(--sp-3); }
.prev-eroare { background: var(--rau-fond); color: var(--rau-text);
               border-radius: var(--rot); padding: var(--sp-2) var(--sp-3); font-size: var(--t-mic2); }
.note-bife { margin: var(--sp-2) 0 0; padding-left: var(--sp-4); font-size: var(--t-mic2); color: var(--text-slab); }
/* Caseta dezactivată — gri, dar NU ștearsă: tot ea îl învață pe om că opțiunea există. */
.bifa.blocat > label.cap { color: var(--text-stins); cursor: not-allowed; }
.bifa.blocat .campuri label { color: var(--text-stins); }
.bifa.blocat .hint-blocat { margin-left: var(--sp-5); }
/* Lista de lipsuri a unui contract: ce oprește facturarea, ce e de completat. */
.lipsuri { list-style: none; margin: var(--sp-2) 0 0; padding: 0; }
.lipsuri li { padding: var(--sp-2) 0; border-bottom: 1px solid var(--linie); }
.lipsuri li:last-child { border-bottom: 0; }
.lipsuri .aparat { color: var(--text-slab); }
.lipsuri .lip { color: var(--rau-text); font-weight: 600; }
.lipsuri a { margin-left: var(--sp-1); }

/* ══════════════════════════════════════════════════════════════════════════════════════
   11. TABELE — DENSE, CU CIFRELE LA DREAPTA
   ══════════════════════════════════════════════════════════════════════════════════════
   Cerința 3: rânduri ~40 px, cifre tabulare la dreapta, dens dar citibil.
   10 px sus/jos + 14 px la 1,4 = 39,6 px pe rând. */
table {
  width: 100%; border-collapse: collapse; background: var(--fond-card); font-size: var(--t-baza);
  /* Chenarul e AL TABELULUI, ca să nu plutească pe fondul paginii. */
  border: 1px solid var(--linie); border-radius: var(--rot-mare); overflow: hidden;
}
/* ⛔⛔ ÎNTR-O CUTIE CARE DERULEAZĂ, TABELUL NU MAI E EL CLIPPERUL (08.09.2026).
   `overflow: hidden` de mai sus e acolo doar ca să taie colțurile rotunjite — dar el face
   din tabel „cel mai apropiat strămoș care decupează", iar `position: sticky` se leagă
   TOCMAI de ăla. Cu el pus, coloana de acțiuni avea `position: sticky` în stil și zero
   efect pe ecran: măsurat pe fișa unui client la 1024 px, celula stătea la x=1082 într-o
   cutie care se termina la 964. ⚠️ Găsit ÎN BROWSER, nu citind foaia — regula din 27.08:
   proba finală e ecranul. Colțurile le taie acum cutia, care oricum decupează. */
.sx { border-radius: var(--rot-mare); }
.sx > table { overflow: visible; border-radius: 0; }
/* ...iar într-un card îl are deja cardul: două chenaruri la 1 px distanță se citesc ca o
   greșeală de randare, nu ca o intenție. */
.card > table, .card > .sx > table,
.card > details.sectiune > table,
.card > details.sectiune > .sx > table { border: 0; border-radius: 0; }
th {
  text-align: left; padding: var(--sp-2) var(--sp-4);
  background: var(--fond-slab); color: var(--text-slab);
  font-size: var(--t-xs); font-weight: 700; text-transform: uppercase; letter-spacing: .04em;
  border-bottom: 1px solid var(--linie); white-space: nowrap;
}
td {
  padding: 10px var(--sp-4); border-bottom: 1px solid var(--linie-slaba);
  vertical-align: top; color: var(--text);
}
tbody tr:last-child td { border-bottom: 0; }
/* ZEBRA — pe rândul par, o singură nuanță. ⚠️ `:nth-child`, nu o clasă pusă din Go: o
   listă filtrată ar fi păstrat clasele rândurilor scoase și zebra ar fi sărit. */
tbody tr:nth-child(even) td { background: var(--fond-slab); }
tbody tr:hover td { background: var(--accent-slab); }
/* Rândul unui lucru scos din uz. */
tr.inactiv td, tr.stins td { color: var(--text-stins); }
td.actiuni, th.actiuni { text-align: right; white-space: nowrap; }
/* ⛔⛔ `nowrap` ȘI `right` SUNT ALE RÂNDULUI DE ACȚIUNI, NU ALE CE CREȘTE ÎNĂUNTRUL LUI
   (12.09.2026, măsurat pe /colectoare).

   Regula de deasupra a fost scrisă pentru o ÎNȘIRUIRE DE CUVINTE SCURTE — „Modifică ·
   Parolă nouă · Retrage" —, care n-are voie să se rupă în două rânduri. De când coloana
   de acțiuni poartă și CARDURI (cele trei fapte ale mașinii, `fapte-colector`), în ea
   intră PROZĂ: mesajul scris de colector despre ce a adus, plus ceasul. Un text
   care nu se rupe cere lățimea celei mai lungi propoziții, iar coloana e lipită la
   dreapta (`position: sticky`) — deci surplusul pleacă pe dincolo de marginea cardului și
   se taie exact la capăt, adică peste DATĂ.

   ⛔ MĂSURAT ÎNAINTE, pe pagina randată: mesajul real al unei aduceri de jurnal („94 KB de
   jurnal (6 KB comprimat), din mpsconnector.log · 10.09.2026 18:21") ieșea cu **37 px**
   din cutia lui la 1400 px și la 1024 px — chiar data retezată. Cu un jurnal luat din
   toate cele șase fișiere rotite, mesajul ieșea cu **1239 px**, iar la 768 și 390 px
   împingea PAGINA cu 1032, respectiv 1410 px lateral.

   ⭐ SE REPARĂ CAUZA, NU CELE DOUĂ TEXTE DE AZI: orice BLOC din celulă își rupe singur
   rândurile, oricât de lung ar fi textul lui. Pastilele și butoanele NU se ating — ele au
   `white-space: nowrap` al lor, mai specific decât moștenirea, deci un cuvânt de pe buton
   rămâne întreg.
   ⚠️ `overflow-wrap: anywhere`, nu `break-word`: numai `anywhere` scade și lățimea
   MINIMĂ cerută de conținut, deci o cale Windows fără niciun spațiu
   (`C:\ProgramData\XEGORA\MPSConnector\…`) lasă celula să se strângă în loc s-o umfle.
   ⛔ `form` NU e în listă: un formular pus la stânga și-ar muta butonul de sub degetul
   omului, iar butoanele coloanei chiar stau la dreapta. */
td.actiuni :where(div, p, ul, ol, li, dl, dt, dd, blockquote, figure, details, summary) {
  white-space: normal; overflow-wrap: anywhere; text-align: left;
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   ACȚIUNILE NU IES NICIODATĂ DIN ECRAN (08.09.2026, hotărârea lui Nelu)
   ══════════════════════════════════════════════════════════════════════════════════════
   ⛔ MĂSURAT ÎNAINTE: tabelul de contacte cerea 1312 px într-o cutie de 1018, deci ultima
   coloană — chiar cea cu „Modifică · Parolă nouă · Retrage" — stătea dincolo de marginea
   cardului. Omul o găsea doar dacă ghicea că trebuie să deruleze lateral ÎN card. Un buton
   pe care trebuie să-l cauți nu e un buton, e o ascunzătoare.

   ⭐ SOLUȚIA E `position: sticky`, nu o strângere într-un meniu: lipită de marginea din
   dreapta, coloana rămâne pe ecran ORICÂT ar derula tabelul, iar acțiunile se apasă
   DIRECT — un meniu care se deschide ar fi costat un clic în plus la fiecare rând, pe
   toate cele 71 de tabele, ca să repare o problemă pe care lipirea o rezolvă cu zero.

   ⛔ CARE E COLOANA DE ACȚIUNI. Convenția casei, veche și respectată în toate cele 36 de
   tabele care au butoane pe rând: **ultima coloană, cu antetul GOL** (`<th></th>`) — cea
   pe care sortare.js o sare deja, fiindcă „o coloană fără nume n-are după ce se sorta".
   Se recunoaște din FORMĂ, nu dintr-o listă de ecrane: o listă s-ar fi erodat la primul
   tabel scris mâine. `.actiuni` rămâne marcajul explicit, pentru cine vrea să-l spună.

   ⚠️ FONDUL TREBUIE SĂ FIE OPAC, altfel rândul curge pe dedesubtul coloanei lipite. De
   aceea cele trei stări (obișnuit, zebră, sub cursor) se repetă aici: sunt aceleași
   culori, doar că puse pe celulă în loc de rând. */
.sx table:has(tr > th:last-child:empty) > * > tr > :last-child,
.sx table th.actiuni, .sx table td.actiuni {
  position: sticky; right: 0; z-index: 2;
  background: var(--fond-card);
  /* Umbra spune că dedesubt mai e tabel — fără ea, coloana lipită arată ca marginea lui. */
  box-shadow: var(--umbra-lipita);
}
.sx table:has(tr > th:last-child:empty) > thead > tr > :last-child,
.sx table thead th.actiuni { background: var(--fond-slab); z-index: 3; }
.sx table:has(tr > th:last-child:empty) > tbody > tr:nth-child(even) > :last-child,
.sx table tbody tr:nth-child(even) td.actiuni { background: var(--fond-slab); }
.sx table:has(tr > th:last-child:empty) > tbody > tr:hover > :last-child,
.sx table tbody tr:hover td.actiuni { background: var(--accent-slab); }
.sx table:has(tr > th:last-child:empty) > tfoot > tr > :last-child,
.sx table tfoot td.actiuni { background: var(--fond-slab); }

/* ---------- COLOANELE DE CONTEXT ----------
   ⭐ `class="ctx"` pe `<th>` ȘI pe `<td>`: coloana care spune CINE/UNDE, nu CE STARE și
   nu CÂT. ID public, telefon, funcție, locație — lucruri pe care le citești când te uiți
   la un rând anume, nu când cauți printre rânduri.
   ⛔ REGULA, și e o hotărâre, nu o optimizare: se ascund DOAR coloanele de context.
   Starea și cifra rămân întotdeauna — ele sunt chiar motivul pentru care omul se uită la
   listă, iar o listă din care lipsește starea arată ca o listă în care totul e în regulă.
   ⚠️ Pragul e cel al benzii de sus (820 px): sub el produsul e deja în forma lui strâmtă,
   deci nu s-a inventat un al doilea prag pentru un al doilea lucru. */
@media (max-width: 820px) {
  th.ctx, td.ctx { display: none; }
}
/* Aliniere pe cifre: vezi `.nr` de la baza foii. `td.nrc`/`th.nrc` e numele vechi din
   portal, păstrat ca să nu se atingă markup-ul lui. */
td.nrc, th.nrc, td.num, th.num { text-align: right; font-variant-numeric: tabular-nums; }
caption { text-align: left; color: var(--text-slab); font-size: var(--t-mic2); padding: 0 0 var(--sp-2); }

/* PICIORUL TABELULUI — concluzia, nu încă un rând de date.
   ⭐ A apărut odată cu sortarea (07.09.2026): două tabele își țineau totalul ca rând
   obișnuit în `<tbody>`, iar o reașezare l-ar fi împrăștiat în mijlocul listei. Mutat în
   `<tfoot>`, unde îi era locul, el nu se mai sortează prin CHIAR structura tabelului — nu
   printr-o excepție pe care trebuie s-o țină minte cineva. */
tfoot td { background: var(--fond-slab); border-bottom: 0; }
tfoot tr:first-child td { border-top: 1px solid var(--linie); }

/* ══════════════════════════════════════════════════════════════════════════════════════
   SORTAREA PE CAPUL DE TABEL — mânerul și săgeata. Vezi static/sortare.js.
   ══════════════════════════════════════════════════════════════════════════════════════
   ⭐ Mânerul e un `<button>` (sortare în browser) ori un `<a>` (listele cu paginare, care
   se sortează pe server). Amândouă poartă `.cap-sort` și arată la fel: coloana nu are voie
   să se citească altfel după cum e sortată dedesubt.

   ⚠️ `font: inherit` și tot ce urmează după el NU sunt zgomot: un buton adus în tabel își
   aduce fontul, chenarul, fondul și alinierea browserului — adică antetul ar fi devenit
   un buton gri cu literă de sistem, pe fiecare coloană a produsului. */
th > .cap-sort {
  display: inline-flex; align-items: center; gap: var(--sp-1); width: 100%;
  border: 0; background: none; padding: 0; margin: 0;
  font: inherit; color: inherit; letter-spacing: inherit; text-transform: inherit;
  text-align: inherit; cursor: pointer; text-decoration: none;
}
/* Cifrele stau la dreapta, deci și mânerul lor: săgeata are ce căuta lângă coloana pe care
   o descrie, nu la capătul opus al celulei. */
th.num > .cap-sort, th.nrc > .cap-sort, th.actiuni > .cap-sort { justify-content: flex-end; }
th > .cap-sort:hover, th > .cap-sort:focus-visible { color: var(--accent); }
/* „↕" stins pe coloanele nesortate — așa se vede că antetul e de apăsat, fără să pară că
   lista e sortată după fiecare coloană deodată. */
.sageata { font-size: 9px; line-height: 1; opacity: .35; }
th[aria-sort="ascending"] .sageata,
th[aria-sort="descending"] .sageata { opacity: 1; color: var(--accent); }

/* ══════════════════════════════════════════════════════════════════════════════════════
   12. STĂRI: PASTILE ȘI PUNCTE — UN SINGUR SET DE FORME
   ══════════════════════════════════════════════════════════════════════════════════════
   ⭐ Cerința lui Nelu, literal: „stările ca pastile moi sau puncte — un singur set de
   forme, culoare doar pe stare."

   Numele canonice sunt `.pastila` (+ `.ok` / `.avert` / `.rau` / `.neutru` / `.info`) și
   `.punct-stare` (⚠️ NU `.punct`: în portalul clientului acela e un PUNCT DE LUCRU). `.badge` și numele de culoare din portal (`.verde`, `.galben`, `.rosu`, `.gri`)
   rămân ca ALIAS pe aceleași reguli — nu ca a doua definiție — fiindcă markup-ul nu se
   atinge în runda asta. ⚠️ Un ecran nou scrie `.pastila`, nu numele unei culori: „verde"
   spune cum arată, „ok" spune ce înseamnă, iar în modul întunecat verdele e altul. */
.pastila, .badge {
  display: inline-block; border-radius: var(--rot-pastila);
  padding: 2px var(--sp-2); font-size: var(--t-mic); font-weight: 600;
  white-space: nowrap; line-height: 1.5;
  background: var(--neutru-fond); color: var(--neutru-text);
}
.pastila.ok, .badge.ok, .badge.activ, .badge.verde, .badge.bine { background: var(--ok-fond); color: var(--ok-text); }
.pastila.avert, .badge.avert, .badge.astept, .badge.galben, .badge.atentie { background: var(--avert-fond); color: var(--avert-text); }
.pastila.rau, .badge.rau, .badge.stins, .badge.rosu, .badge.grav { background: var(--rau-fond); color: var(--rau-text); }
.pastila.neutru, .badge.neutru, .badge.gri { background: var(--neutru-fond); color: var(--neutru-text); }
.pastila.info, .badge.info, .badge.albastru { background: var(--info-fond); color: var(--info-text); }
/* ⭐ STĂRILE „CU NUME" — codul de activare și accesul unei persoane în portal.
   ⛔ MUTATE AICI din foaia ecranului de clienți (11.09.2026): de când pastila accesului e
   o componentă („stare-acces", acces_actiuni.go) ea se desenează în TREI seturi de
   șabloane, iar o regulă scrisă în foaia unuia i-ar fi lăsat pe ceilalți doi cu o pastilă
   albă. Aceeași lecție ca la `.brut` (06.09). */
.badge.stare-activ, .stare-activ { background: var(--ok-fond); color: var(--ok-text); }
.badge.stare-folosit, .stare-folosit { background: var(--info-fond); color: var(--info-text); }
.badge.stare-expirat, .stare-expirat { background: var(--avert-fond); color: var(--avert-text); }
.badge.stare-retras, .stare-retras, .stare-revocat, .stare-client-dezactivat { background: var(--rau-fond); color: var(--rau-text); }

/* PUNCTUL — aceeași stare, în locurile unde nu încape o pastilă (capul unui rând dens,
   o legendă de hartă). Aceeași triplete de culori, altă formă. */
.punct-stare {
  display: inline-block; width: 9px; height: 9px; border-radius: 50%;
  background: var(--neutru-semn); vertical-align: baseline; margin-right: var(--sp-1);
}
/* ══════════════════════════════════════════════════════════════════════════════════════
   SEMNUL OMULUI (ȘI AL FIRMEI): un cerc cu INIȚIALELE lui
   ══════════════════════════════════════════════════════════════════════════════════════
   ⭐ CERUT DE NELU (04.09.2026): „avataruri cu inițiale (ex. «RD» Radu Diana, «EC» Ecart)
   în loc de cercuri goale — în chat, mesaje, liste de clienți."

   ⛔ INIȚIALELE, NU O POZĂ, și nu e o etapă intermediară: produsul n-are unde ține poze,
   n-are cine să le urce, iar un cerc gol nu spune nimic. Două litere se recunosc dintr-o
   privire pe un rând de listă și rămân lizibile la 24 px — ceea ce o poză mică nu e.

   ⭐⭐ CULOAREA IESE DIN NUME (06.09.2026, cerut de Nelu: „culoare derivată din nume,
   contrast garantat"). Aici scria, până azi, exact pe dos — „o singură pereche de culori,
   ca să nu apară un al doilea vocabular de culoare lângă cel al stărilor". Grija era
   bună, răspunsul nu: pe o listă de douăzeci de clienți, douăzeci de cercuri identice
   nu ajută pe nimeni să găsească rândul pe care-l caută.

   ⛔ CE RĂMÂNE ÎNTREG DIN GRIJA VECHE: culoarea semnului NU ÎNSEAMNĂ NIMIC. Nu e o stare,
   nu e o categorie, nu se poate alege. E o amprentă a numelui — la fel de arbitrară ca
   inițialele, și la fel de stabilă. De aceea cele zece nuanțe sunt scrise AICI, nu în
   vocabularul stărilor, și niciuna nu e verdele lui `--ok-semn` sau roșul lui
   `--rau-semn`: un cerc pe care omul îl citește ca „e bine" ar fi mai rău decât unul gri.

   ⚠️ CONTRAST GARANTAT NU SE SCRIE ÎNTR-UN COMENTARIU, SE SOCOTEȘTE. Perechile de mai
   jos se măsoară în `TestSemneleOamenilorRamanCitibile`, în amândouă modurile, la fel ca
   paletele omului. Nicio nuanță nu se poate schimba fără ca cifrele să se refacă singure.

   Regula care compune literele — și de ce „Ecart SRL" dă „E", nu „ES" — stă în
   `store.Initiale`, lângă `NumeIntreg`; cea care alege nuanța, în `semn_om.go`. */
.semn-om {
  display: inline-flex; align-items: center; justify-content: center; flex: none;
  width: 26px; height: 26px; border-radius: 50%;
  background: var(--fond-apasat); color: var(--text-slab);
  font-size: var(--t-xs); font-weight: 700; letter-spacing: .02em;
  text-transform: uppercase; user-select: none;
}
.semn-om.mic { width: 20px; height: 20px; font-size: 9px; }
/* ⭐ MĂRIMEA DE ANTET (09.09.2026), cerută pe macheta fișei de client: „logo cu inițiale"
   lângă numele firmei. Cifra NU e aleasă: e chiar 54 px, cât pătratul de marcă al fișei de
   aparat (`.pg-marca`), ca cele două capuri de fișă să aibă aceeași siluetă. */
.semn-om.mare { width: 54px; height: 54px; font-size: var(--t-h2); }
/* CELE ZECE NUANȚE. Numele clasei e un NUMĂR, nu o culoare: „c7" nu promite albastru, iar
   ziua în care nuanțele se rearanjează nu lasă în cod nume care mint.
   ⛔ REGULA E SCRISĂ O SINGURĂ DATĂ, pe variabile. Prima formă avea zece reguli pe lumină
   și încă zece sub `body.tema-intunecat` — iar garda `TestModulIntunecatDoarValori` a
   prins-o pe loc, cu propoziția ei: în blocul întunecat se redefinesc DOAR valori. Avea
   dreptate și dincolo de formă: două seturi de reguli se despart la prima nuanță
   adăugată, pe când două seturi de VALORI nu au cum. */
.semn-om.c1  { background: var(--semn1-fond);  color: var(--semn1-text); }
.semn-om.c2  { background: var(--semn2-fond);  color: var(--semn2-text); }
.semn-om.c3  { background: var(--semn3-fond);  color: var(--semn3-text); }
.semn-om.c4  { background: var(--semn4-fond);  color: var(--semn4-text); }
.semn-om.c5  { background: var(--semn5-fond);  color: var(--semn5-text); }
.semn-om.c6  { background: var(--semn6-fond);  color: var(--semn6-text); }
.semn-om.c7  { background: var(--semn7-fond);  color: var(--semn7-text); }
.semn-om.c8  { background: var(--semn8-fond);  color: var(--semn8-text); }
.semn-om.c9  { background: var(--semn9-fond);  color: var(--semn9-text); }
.semn-om.c10 { background: var(--semn10-fond); color: var(--semn10-text); }
/* Numele lipit de semnul lui: aceeași distanță peste tot unde apar împreună. */
.cu-semn { display: inline-flex; align-items: center; gap: var(--sp-2); min-width: 0; }
.cu-semn > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; }

.punct-stare.ok { background: var(--ok-semn); }
.punct-stare.avert { background: var(--avert-semn); }
.punct-stare.rau { background: var(--rau-semn); }
.punct-stare.neutru { background: var(--neutru-semn); }
.punct-stare.info { background: var(--info-semn); }

/* ---------- BARA DE NIVEL A UNUI CONSUMABIL ----------
   Un jgheab și o umplutură colorată după prag. Se construiește în Go (`bara_consumabil.go`),
   fiindcă pragurile sunt ale DEALERULUI și nu se pot scrie în CSS — dar ÎNFĂȚIȘAREA e aici,
   iar Go trimite doar clasa de nivel. Până azi cele patru culori și cele două mărimi erau
   scrise în șirul de format din Go, adică într-un al doilea loc unde se aleg vopsele. */
.bara-cons { display: inline-flex; align-items: center; gap: var(--sp-1); white-space: nowrap; }
.bara-cons .jgheab {
  display: inline-block; width: 74px; height: 9px; border-radius: 5px;
  background: var(--fond-apasat); overflow: hidden; flex: 0 0 auto;
}
.bara-cons .umplut { display: block; height: 100%; background: var(--nivel-gri); }
.bara-cons .umplut.rosu { background: var(--nivel-rosu); }
.bara-cons .umplut.galben { background: var(--nivel-galben); }
.bara-cons .umplut.verde { background: var(--nivel-verde); }
/* ⛔ „text-transform" ȘI „letter-spacing" SE DECLARĂ, DEȘI PAR DE PRISOS — găsit pe dev,
   cu ochii, la 08.09.2026: în portal, aceeași bară scria „80% RĂMAS" cu majuscule, iar la
   dispecer „80% rămas". Cauza: portalul are un `.et` al lui (eticheta lui de rând), cu
   MAJUSCULE — iar regula de aici nu spunea nimic despre litere, deci n-avea ce înlocui.
   ⚠️ E chiar defectul pe care bara scrisă O SINGURĂ DATĂ există să-l împiedice: clientul
   și dispecerul se uitau la același toner și citeau altceva. Componenta își apără acum
   propria înfățișare, în locul în care e definită. */
.bara-cons .et {
  font-variant-numeric: tabular-nums; font-size: var(--t-mic); color: var(--text-slab);
  text-transform: none; letter-spacing: normal;
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   13. ALERTE ȘI MESAJE DE REZULTAT
   ══════════════════════════════════════════════════════════════════════════════════════
   Aceleași cinci stări, a treia formă: o casetă lată, cu o bară colorată în stânga.
   `.eroare` și `.reusit` sunt numele folosite azi pe ~20 de ecrane; rămân, ca alias. */
.alerta, .eroare, .reusit {
  border-radius: var(--rot); border: 1px solid transparent;
  border-left: 3px solid var(--neutru-semn);
  background: var(--neutru-fond); color: var(--neutru-text);
  padding: var(--sp-2) var(--sp-3); font-size: var(--t-mic2);
  margin-bottom: var(--sp-4); line-height: var(--ritm);
}
.alerta.rau, .eroare { background: var(--rau-fond); color: var(--rau-text); border-left-color: var(--rau-semn); }
.alerta.ok, .reusit { background: var(--ok-fond); color: var(--ok-text); border-left-color: var(--ok-semn); }
.alerta.avert { background: var(--avert-fond); color: var(--avert-text); border-left-color: var(--avert-semn); }
.alerta.info { background: var(--info-fond); color: var(--info-text); border-left-color: var(--info-semn); }
.alerta a, .eroare a, .reusit a { color: inherit; text-decoration: underline; }

/* ---------- HINTUL DE LÂNGĂ UN CÂMP DEZACTIVAT ----------
   ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⭐⭐ „RĂMÂN MEREU VIZIBILE, DOAR ACTIVE SAU INACTIVE, CU HINT CARE SPUNE CUM SE        ║
   ║ ACTIVEAZĂ." (Nelu, 06.09.2026)                                                        ║
   ║                                                                                       ║
   ║ Un câmp gri fără o vorbă lângă el se citește ca un defect. Hintul e o INSTRUCȚIUNE,   ║
   ║ nu o notă de subsol — de aceea are forma casetei de informare, nu pe cea a lui        ║
   ║ `.expl` (mărunt și stins, adică exact ce arată deja câmpul dezactivat).               ║
   ║                                                                                       ║
   ║ ⚠️ STĂ AICI, nu în foaia unui ecran: îl folosesc amândouă capetele aceluiași          ║
   ║ comutator — clauzele contractului și fragmentul de bife al tarifului. Scris în două   ║
   ║ locuri, cele două jumătăți ale aceleiași reguli ar fi arătat diferit.                  ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝
   Marginea de sus e mică și cea de jos aproape zero: hintul aparține câmpului de deasupra,
   nu paragrafului de dedesubt. */
.hint-blocat {
  border-radius: var(--rot); border-left: 3px solid var(--info-semn);
  background: var(--info-fond); color: var(--info-text);
  padding: var(--sp-2) var(--sp-3); font-size: var(--t-mic2);
  line-height: var(--ritm); margin: var(--sp-2) 0 2px;
}
.hint-blocat a { color: inherit; text-decoration: underline; }

/* ⭐ `.ce-face` / `.pilda` — ce se întâmplă cu BANII sub alegerea de deasupra (0087).
   ⛔ NU sunt `.expl`: aceea e lămurirea unui câmp, se citește o dată și se sare. Astea se
   schimbă ODATĂ CU ALEGEREA și sunt chiar răspunsul la „ce fac dacă apăs asta" — de aceea
   stau lipite de control, nu la subsolul cardului, unde se citesc după ce ai greșit deja.
   ⚠️ Aceleași jetoane ca restul foii; nicio culoare nouă. */
.ce-face { color: var(--text-slab); font-size: var(--t-mic2); line-height: var(--ritm);
           margin: var(--sp-1) 0 0; }
.pilda { border-left: 3px solid var(--linie); background: var(--fond-slab);
         border-radius: var(--rot); padding: var(--sp-2) var(--sp-3);
         font-size: var(--t-mic2); line-height: var(--ritm); margin: var(--sp-2) 0 0;
         font-variant-numeric: tabular-nums; }

/* ---------- VOCABULARUL CARE EXISTA DEJA, ADUS AICI ----------
   ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⭐ NU SUNT ALIASURI DE POLITEȚE, E CHIAR VOCABULARUL PRODUSULUI.                       ║
   ║                                                                                       ║
   ║ Numărate în cele 36 de foi de ecran, înainte de rundă: `.grav` de 12 ori, `.ok` de 10,║
   ║ `.bine` de 8, `.nota` de 7, `.avert`/`.atentie` de 10 — aceleași patru înțelesuri, cu ║
   ║ patru nume și cu 21 de perechi de culori ușor diferite. Oamenii care au scris          ║
   ║ ecranele foloseau deja un vocabular comun; ce lipsea era un singur loc în care el să   ║
   ║ fie DEFINIT.                                                                           ║
   ║                                                                                       ║
   ║ ⚠️ Un ecran NOU scrie numele canonice — `.alerta.ok`, `.pastila.rau` —, nu numele unei ║
   ║ culori: „verde" spune cum arată, „ok" spune ce înseamnă, iar în modul întunecat        ║
   ║ verdele e altul. Numele vechi rămân fiindcă runda asta e strict înfățișare și nu       ║
   ║ atinge markup-ul; se sting singure, pe măsură ce ecranele se rescriu.                  ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
.ok, .bine { background: var(--ok-fond); color: var(--ok-text); border-left-color: var(--ok-semn); }
.grav { background: var(--rau-fond); color: var(--rau-text); border-left-color: var(--rau-semn); }
.avert, .atentie { background: var(--avert-fond); color: var(--avert-text); border-left-color: var(--avert-semn); }
.nota { background: var(--info-fond); color: var(--info-text); border-left-color: var(--info-semn); }
/* Forma lor e a alertei — aceeași cutie, aceeași margine colorată în stânga.
   ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⛔⛔ …DAR NUMAI CÂND LUCRUL CHIAR E O CASETĂ. Reparație, 04.09.2026.                   ║
   ║                                                                                       ║
   ║ Rândul ăsta era, până azi, `.ok, .bine, .grav, .avert, .atentie, .nota { … }` — adică ║
   ║ se lipea de ORICE element care poartă unul dintre numele alea, inclusiv de o PASTILĂ  ║
   ║ sau de un PUNCT de stare. Iar `.pastila` și `.punct-stare` au aceeași specificitate   ║
   ║ (0,1,0) și sunt scrise MAI SUS în foaie, deci pierdeau: forma casetei le suprascria    ║
   ║ colțul, marginea interioară, chenarul și litera.                                       ║
   ║                                                                                       ║
   ║ Măsurat pe viu, în browser, pe ecranul „Setări → Temă" (04.09):                        ║
   ║                                                                                       ║
   ║   .pastila.rau    22 px înălțime, colț 999px, fără chenar   ← pastilă, corect         ║
   ║   .pastila.ok     38 px înălțime, colț 8px, chenar 2,5 px   ← CASETĂ DE ALERTĂ        ║
   ║   .punct-stare.ok 28 × 18 px, colț 8px, cu padding          ← nici punct, nici pastilă║
   ║                                                                                       ║
   ║ ⚠️ De ce n-a picat nimic și de ce nu s-a văzut o zi întreagă pe producție: se lovesc   ║
   ║ EXACT numele care sunt și stare, și alertă — `ok`, `bine`, `avert`, `atentie`, `grav`, ║
   ║ `nota`. `rau`, `neutru` și `info` n-au pereche de alertă, deci arătau perfect — iar    ║
   ║ pe majoritatea ecranelor pastila e roșie sau gri, adică tocmai cele care mergeau.      ║
   ║                                                                                       ║
   ║ ⛔ Reparația NU rescrie forma pastilei aici (aia ar fi fost a doua definiție a         ║
   ║ aceluiași lucru, chiar ce refuză toată runda de temă). Scoate din selector lucrurile   ║
   ║ care au deja o formă, iar pastila și punctul rămân cu regula lor, singura.             ║
   ╠══════════════════════════════════════════════════════════════════════════════════════╣
   ║ ⛔⛔ ȘI DE CE `:where(:not(…))` ȘI NU `:not(…)` DIRECT — a doua capcană, prinsă        ║
   ║ verificând ce ALTCEVA se mai mișcă.                                                    ║
   ║                                                                                       ║
   ║ `:not(.pastila, …)` ÎȘI ADAUGĂ specificitatea argumentului: selectorul ar fi urcat de ║
   ║ la (0,1,0) la (0,2,0). Sună inofensiv, dar foaia temei se încarcă ÎNAINTEA stilului    ║
   ║ fiecărui ecran, deci regulile de așezare ale ecranelor câștigă azi doar pentru că sunt ║
   ║ mai TÂRZII, la specificitate egală. Urcat cu un pas, rândul ăsta le-ar fi bătut:       ║
   ║                                                                                       ║
   ║   `.restanta.ok` (banda de restanțe de pe hartă) — margine interioară de 24 px devenea ║
   ║   12, iar linia ei de jos devenea un chenar întreg pe toate patru laturile;            ║
   ║   `.anunt.ok` (anunțul de sub filtre) — căpăta o bară de 3 px în stânga.                ║
   ║                                                                                       ║
   ║ Adică o reparație de pastilă ar fi stricat două ecrane care n-aveau nimic. `:where()`  ║
   ║ are specificitate ZERO, deci `:is(…):where(:not(…))` rămâne exact (0,1,0) — cât era.   ║
   ║ Se schimbă CE se potrivește, nu CINE câștigă.                                          ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
:is(.ok, .bine, .grav, .avert, .atentie, .nota):where(:not(.pastila, .badge, .punct-stare, .semn, .sursa, .eticheta)) {
  border-radius: var(--rot); border: 1px solid transparent; border-left-width: 3px; border-left-style: solid;
  padding: var(--sp-2) var(--sp-3); font-size: var(--t-mic2);
  margin: 0 0 var(--sp-3); line-height: var(--ritm);
}
.ok a, .bine a, .grav a, .avert a, .atentie a, .nota a { color: inherit; text-decoration: underline; }

/* Pastilele cu numele vechi. FORMA e a pastilei, culoarea e a stării.
   ⚠️ `.gri` e ȘI numele butonului secundar (`.btn.gri`): acolo câștigă regula butonului,
   care are un selector mai specific. Perechea e ținută de `TestBtnGriRamaneButon`. */
.semn, .sursa {
  display: inline-block; border-radius: var(--rot-pastila);
  padding: 2px var(--sp-2); font-size: var(--t-mic); font-weight: 600;
  white-space: nowrap; line-height: 1.5;
  background: var(--neutru-fond); color: var(--neutru-text);
}
.verde, .semn.al, .s-meu, .s-lui { background: var(--ok-fond); color: var(--ok-text); }
.galben, .portocaliu, .s-inst, .s-firma { background: var(--avert-fond); color: var(--avert-text); }
.rosu, .s-fara { background: var(--rau-fond); color: var(--rau-text); }
.gri, .gri2 { background: var(--neutru-fond); color: var(--neutru-text); }
/* Cuvinte de stare care stau ÎN RÂND (o coloană de tabel), deci poartă doar culoarea,
   fără forma pastilei. */
.anulat { color: var(--rau-text); }
.asteapta { color: var(--avert-text); }
.albastru, .insig { background: var(--info-fond); color: var(--info-text); }
.mov { background: var(--mov-fond); color: var(--mov-text); }
.insig {
  display: inline-block; border-radius: var(--rot-pastila);
  padding: 1px var(--sp-2); font-size: var(--t-xs); font-weight: 600; white-space: nowrap;
}

/* ---------- PAȘII UNUI FLUX ----------
   Trei ecrane (restaurarea, importul de oferte, importul de lucrări) desenau același rând
   de pași cu trei perechi de culori. E o CALE, nu o stare: pasul de acum e plin, cei
   făcuți poartă verdele de „gata", restul stau neutri. */
.pasi { display: flex; gap: var(--sp-1); flex-wrap: wrap; margin: 0 0 var(--sp-3); font-size: var(--t-mic2); }
.pasi span {
  padding: var(--sp-1) var(--sp-3); border-radius: var(--rot-pastila);
  background: var(--neutru-fond); color: var(--neutru-text);
}
.pasi span.acum { background: var(--buton-fond); color: var(--buton-text); font-weight: 600; }
.pasi span.gata { background: var(--ok-fond); color: var(--ok-text); }

/* ---------- CIFRA MARE, cu eticheta ei ----------
   „câte rânduri s-au citit", „câte aparate are firma". Cifra e ce se vede de la doi metri;
   eticheta stă sub ea, mărunt. ⛔ Tabulară, ca două cifre alăturate să se poată compara. */
.cifre { display: flex; gap: var(--sp-5); flex-wrap: wrap; margin: var(--sp-1) 0 var(--sp-3); }
.cifra { font-size: var(--t-cifra); font-weight: 700; font-variant-numeric: tabular-nums; }
.cifra small, .cifra .e { display: block; font-size: var(--t-xs); font-weight: 400; color: var(--text-stins); }
.cifra .v { font-size: var(--t-cifra); font-weight: 700; }

/* ---------- TEXTELE DE STRUCTURĂ, tot din vocabularul existent ---------- */
/* .sub — propoziția de sub titlul unei secțiuni. */
.sub { color: var(--text-slab); font-size: var(--t-mic2); margin: 0 0 var(--sp-4); }
/* .cap — capul unei secțiuni dintr-un card: mai greu decât textul, mai ușor decât un titlu. */
.cap { font-weight: 600; font-size: var(--t-mare); margin: 0 0 var(--sp-1); color: var(--text); }
/* .unit — unitatea de lângă un număr („zile", „%"). */
.unit { font-size: var(--t-mic2); color: var(--text-slab); margin-left: var(--sp-1); }
/* .optiune — un rând de radio/bifă dintr-o listă de alegeri. */
.optiune { display: block; margin: var(--sp-2) 0 0; font-size: var(--t-baza); }
.optiune input { margin-right: var(--sp-1); }
/* .pierzi / .urmare — „ce se întâmplă dacă apeși": o notă de avertisment, mică, lipită de
   controlul care o provoacă. Aceeași stare ca `.avert`, altă greutate. */
.pierzi, .urmare {
  background: var(--avert-fond); color: var(--avert-text);
  border-radius: var(--rot-mic); padding: var(--sp-1) var(--sp-2);
  margin-top: var(--sp-2); font-size: var(--t-mic2); line-height: var(--ritm);
}

/* ---------- FILTRELE-PASTILĂ ----------
   Aceleași pe hartă și pe Mesaje, ca să se citească la fel pe amândouă. Sunt LEGĂTURI
   (starea e adresa paginii, deci o listă filtrată se poate da mai departe), nu butoane. */
.filtru {
  font-size: var(--t-mic2); text-decoration: none; border-radius: var(--rot-pastila);
  padding: var(--sp-1) var(--sp-3); border: 1px solid var(--linie);
  background: var(--fond-card); color: var(--text-slab);
}
.filtru:hover { border-color: var(--accent); color: var(--accent); text-decoration: none; }
.filtru.aici { background: var(--text); border-color: var(--text); color: var(--fond-card); font-weight: 600; }

/* ---------- RÂNDUL-CARD ----------
   Un rând de listă care e ÎN ÎNTREGIME o legătură: discuția din Mesaje, aparatul din
   portalul clientului. Card, nu rând de tabel, fiindcă are două-trei rânduri de text și
   se apasă pe toată suprafața. */
a.rand, .rand-a {
  display: flex; align-items: flex-start; gap: var(--sp-3);
  background: var(--fond-card); border: 1px solid var(--linie); border-radius: var(--rot-mare);
  padding: var(--sp-3) var(--sp-4); margin-bottom: var(--sp-2);
  text-decoration: none; color: var(--text);
}
a.rand:hover { border-color: var(--accent); text-decoration: none; }

/* ══════════════════════════════════════════════════════════════════════════════════════
   14. FILE (TABURI)
   ══════════════════════════════════════════════════════════════════════════════════════
   ⭐ Fila activă e SUBLINIATĂ ALBASTRU — chiar macheta aleasă, aceeași formă ca marcajul
   paginii curente din bară. Un singur fel de „aici sunt", în tot produsul. */
.taburi {
  display: flex; gap: var(--sp-1); flex-wrap: wrap;
  border-bottom: 1px solid var(--linie); margin-bottom: var(--sp-4);
}
.taburi a, .taburi .tab {
  padding: var(--sp-2) var(--sp-3); color: var(--text-slab);
  text-decoration: none; font-size: var(--t-mic2); font-weight: 600;
  border-bottom: 2px solid transparent; margin-bottom: -1px;
}
.taburi a:hover { color: var(--text); text-decoration: none; }
.taburi a.aici, .taburi a.ales, .taburi .tab.aici { color: var(--text); border-bottom-color: var(--accent); }

/* ---------- FILE LIPITE DE CAPUL PAGINII (08.09.2026) ----------
   ⭐ CERUT DE NELU: „taburi lipicioase sus — la schimbare de tab NU trebuie scroll".
   Bara produsului (.bs) e deja lipită la 0 și are 46 px, deci filele se opresc SUB ea,
   la `--bs-inaltime`. Cifra e aceeași variabilă pe care o pune scriptul barei la
   înălțimea REALĂ măsurată — scrisă din nou aici, s-ar fi despărțit de bară la prima
   schimbare de înălțime, iar simptomul e o bandă de filă tăiată pe jumătate.
   ⛔ `z-index` sub cel al barei (1000) și peste conținut: filele trec PESTE tabelele
   care se derulează pe sub ele, dar niciodată peste bară și peste meniul ei.
   ⚠️ Fondul e OBLIGATORIU. Fără el, un rând de tabel s-ar fi văzut prin filele lipite —
   nimic nu pică, dar pagina arată ca și cum s-ar fi randat de două ori. */
.taburi.lipite {
  position: sticky; top: var(--bs-inaltime); z-index: 900;
  background: var(--fond); padding-top: var(--sp-2);
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   14b. CAPUL DE APARAT — CELE PATRU CARDURI KPI
   ══════════════════════════════════════════════════════════════════════════════════════
   ⭐⭐ CERUT DE NELU (08.09.2026), pe machetele fișei: „SUS, dintr-o privire, patru
   carduri KPI grafice — Stare · Nivel tonere · Contoare · Contract". Sunt AICI, nu în
   foaia fișei, fiindcă aceeași componentă se desenează pe DOUĂ ecrane cu seturi de
   șabloane diferite (fișa dealerului și fișa din portalul clientului); scrisă în unul
   dintre ele, celălalt ar fi rămas fără ea sau ar fi primit o copie care diverge.

   ⛔ Cardul rămâne `.card` din secțiunea 8 — aici e doar AȘEZAREA lor în grilă și
   piesele care nu există nicăieri altundeva (bara verticală de toner). */
/* ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⛔⛔ PATRU COLOANE FIXE, NU `auto-fit` — REPARAT PE MĂSURĂTOARE (10.09.2026).         ║
   ║                                                                                       ║
   ║ `repeat(auto-fit, minmax(250px, 1fr))` umple cât încape, deci numărul de coloane      ║
   ║ trece prin TOATE valorile: 4 · 3 · 2 · 1. Iar 3 e chiar cea care strică o grilă de    ║
   ║ PATRU carduri — trei sus, al patrulea singur dedesubt.                                 ║
   ║                                                                                       ║
   ║ Măsurat în Chrome adevărat, pe Dispecerat, ÎNAINTE de reparație:                      ║
   ║   1400×900  → 4 pe rând   (bine)                                                      ║
   ║   1024×768  → 3 + 1       ⛔ TABLETA PE LAT, chiar fâșia pe care n-o probase nimeni   ║
   ║    768×1024 → 2 + 2       (bine)                                                      ║
   ║    390×844  → 1 pe rând   (bine)                                                      ║
   ║                                                                                       ║
   ║ ⚠️ Tableta cade ÎNTRE cele două praguri ale temei (820 lățime · 560 înălțime): la     ║
   ║ 1024×768 nicio interogare nu se aprinde, deci așezarea e cea de birou pe un ecran     ║
   ║ care n-are lățimea unui birou. „E bine la 390 și la 1400" nu spune nimic despre ea.   ║
   ║                                                                                       ║
   ║ ⛔ NICIUN PRAG NOU: cifra 4 e adevărul componentei (toate cele trei grile `.kpi` din  ║
   ║ produs au exact patru carduri — capul de aparat, capul de fișă de client, cifrele     ║
   ║ Dispeceratului), iar sub pragul de telefon regula se întoarce la `auto-fit`, unde     ║
   ║ el chiar are ce alege: 2 la 768, 1 la 390. Un al treilea prag ar fi fost o fâșie de   ║
   ║ ecrane în care produsul se poartă altfel fără ca cineva să fi hotărât-o.               ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
.kpi {
  display: grid; gap: var(--sp-3); margin-bottom: var(--sp-4);
  grid-template-columns: repeat(4, minmax(0, 1fr));
}
/* ⚠️ Cardurile KPI nu-și pun titlu <h3>: un titlu copil direct l-ar face pe
   static/sectiuni.js să le prefacă în secțiuni pliabile, iar un KPI care se poate
   strânge nu mai e „dintr-o privire". Eticheta e `.kpi-et`, deasupra, mărunt. */
.kpi > .card { margin: 0; padding: var(--sp-3) var(--sp-4); display: flex; flex-direction: column; gap: var(--sp-2); }
.kpi-et {
  font-size: var(--t-xs); text-transform: uppercase; letter-spacing: .05em;
  color: var(--text-stins); font-weight: 600;
}
.kpi-mare { font-size: var(--t-cifra); font-weight: 700; font-variant-numeric: tabular-nums; }
.kpi-rand { display: flex; align-items: baseline; justify-content: space-between; gap: var(--sp-3); font-size: var(--t-mic2); }
.kpi-rand .kpi-v { font-variant-numeric: tabular-nums; font-weight: 600; }
/* ⭐ Linia dinaintea TOTALULUI, cerută pe machetă: totalul nu e încă un rând, e suma
   rândurilor de deasupra, iar despărțitura o spune fără niciun cuvânt. */
.kpi-rand.kpi-total { border-top: 1px solid var(--linie); padding-top: var(--sp-2); margin-top: 2px; font-size: var(--t-baza); }
.kpi-rand.kpi-total .kpi-v { font-weight: 700; }
.kpi-nota { font-size: var(--t-mic); color: var(--text-stins); }
/* ⭐ PASTILA DE ACȚIUNE A UNUI CARD KPI (09.09.2026, capul fișei de client): pastila e
   îmbrăcată într-o legătură, ca tot dreptunghiul să fie de apăsat, nu doar cuvintele.
   ⛔ Fără subliniere și fără culoare proprie: insigna dinăuntru poartă deja culoarea
   stării, iar o legătură albastră peste ea ar fi fost al doilea semnal pe același obiect. */
.kpi-drum { display: inline-block; text-decoration: none; }
.kpi-drum:hover { text-decoration: none; filter: brightness(0.96); }
/* ⭐⭐ BUTONUL LA BAZA CARDULUI (Nelu, 10.09.2026): „toate patru au aceeași formă —
   eticheta sus, cifra cu contextul ei pe același rând, butonul la bază."
   ⛔ `margin-top: auto` ÎN COLOANA FLEX A CARDULUI, nu o înălțime scrisă: grila întinde
   deja cardurile unui rând la aceeași înălțime, iar marginea automată înghite tot ce
   rămâne deasupra. Fără ea, butonul atârna de cât text avea cardul lui — măsurat la
   1400×900: bazele erau 259 · 259 · 259 · 287, adică al patrulea cu 28 px mai jos.
   ⚠️ Se apără cu ochiul browserului, nu de aici: `_dev-probe-dispecerat.js` cere ca
   butoanele cardurilor de pe ACELAȘI rând să aibă aceeași linie de bază, pe pagina
   randată. O regulă citită dintr-un fișier .css n-ar fi văzut niciodată 3+1. */
.kpi-baza { margin-top: auto; }

/* ---------- BARELE VERTICALE DE TONER ----------
   ⛔ CULOAREA E A TONERULUI, NU O STARE. Un cartuș cyan e cyan și când e plin, și când e
   pe sfârșite — de aceea culorile stau lângă paleta de grafice (fixe în ambele moduri),
   nu în scara de gravitate.
   ⭐⭐ ȘI SUB PRAG RĂMÂNE A PIESEI (Nelu, 11.09.2026). Până azi umplutura se făcea roșie sub
   pragul urgent, iar culoarea declarată se dădea la o parte. Pe VersaLink C7125 cyanul a
   coborât de la 15 % la 14 % și a apărut ca o bară ROȘIE între K, M și Y — citită, pe bună
   dreptate, drept o culoare greșită. Gravitatea o poartă acum CIFRA (`.toner-pr`, roșie) și
   RAMA jgheabului; umplutura nu se atinge. Garda: C5 din garda_consumabile_declarate_test. */
/* ⚠️ LĂȚIMEA ȘI SPAȚIUL SUNT MĂSURATE, nu alese: patru bare de 42 px cu 8 px între ele
   încap în cel mai îngust card al grilei (250 px minus paddingul cardului). Cu 46 și
   `--sp-3`, a patra bară — galbenul — cădea pe rândul al doilea; prins pe dev, cu ochii. */
.tonere { display: flex; gap: var(--sp-2); flex-wrap: wrap; align-items: flex-end; }
/* ⚠️ COLOANĂ, NU SPAN-URI INLINE. Prima formă lăsa `.toner` inline, iar procentul și
   litera ieșeau UNA LÂNGĂ ALTA, la înălțimi diferite de la o bară la alta („100%" e mai
   lat decât „60%"). Prins pe dev, cu ochii, la prima randare. */
/* ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⛔⛔ BARA SE STRÂNGE, NU CADE PE RÂNDUL DOI (10.09.2026) — și e reparația a chiar     ║
   ║ COSTULUI grilei de patru coloane de mai sus.                                          ║
   ║                                                                                       ║
   ║ Cardul cel mai îngust nu mai are 250 px: cu patru coloane fixe, la 830 px lățime de   ║
   ║ fereastră el ajunge la 183 (147 pe dinăuntru). Măsurat în Chrome, cu chiar marcajul   ║
   ║ temei injectat într-un card al grilei:                                                ║
   ║      821→147px  3+1 ⛔ · 900→166px  3+1 ⛔ · 1000→191px  3+1 ⛔ · 1024→197px  4 ok    ║
   ║ Adică fâșia 821–1010 px arăta galbenul singur pe rândul al doilea — chiar defectul pe ║
   ║ care caseta de deasupra spune că l-a prins cineva pe dev, cu ochii.                    ║
   ║                                                                                       ║
   ║ ⭐ `flex: 1 1 0` cu `max-width: 42px`: când e loc, bara e exact cât era (42 px, nici  ║
   ║ un pixel altfel); când nu e, cele patru se strâng împreună până la 26 px și rămân pe  ║
   ║ un rând. Patru bare de 26 cu trei spații de 8 cer 128 px — încap și în cel mai îngust ║
   ║ card măsurat. ⚠️ `flex-wrap` RĂMÂNE: e plasa pentru ziua în care apar mai mult de     ║
   ║ patru culori, nu o regulă moartă.                                                      ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
.toner {
  flex: 1 1 0; max-width: 42px; min-width: 26px;
  display: flex; flex-direction: column; align-items: center;
}
.toner-jgheab {
  height: 76px; width: 100%; display: flex; align-items: flex-end; overflow: hidden;
  background: var(--fond-slab); border: 1px solid var(--linie); border-radius: var(--rot-mic);
}
.toner-umplut { width: 100%; background: var(--neutru-semn); }
.toner-k .toner-umplut { background: var(--consumabil-k); }
.toner-c .toner-umplut { background: var(--consumabil-c); }
.toner-m .toner-umplut { background: var(--consumabil-m); }
.toner-y .toner-umplut { background: var(--consumabil-y); }
.toner.subprag .toner-jgheab { border-color: var(--rau-semn); }
.toner-pr { font-size: var(--t-mic2); font-weight: 600; font-variant-numeric: tabular-nums; margin-top: 3px; }
.toner.subprag .toner-pr { color: var(--rau-text); }
.toner-lit { font-size: var(--t-xs); color: var(--text-stins); }
/* Consumabilele care NU sunt tonere (cilindru, recipient de rezidual, cuptor) rămân sub
   bare, cu bara orizontală obișnuită: nivelul lor nu se pierde de pe ecran, dar nu fură
   locul culorilor pe care omul le caută dintr-o privire. */
.kpi-alte { display: flex; flex-direction: column; gap: var(--sp-1); font-size: var(--t-mic); }
.kpi-alte > span { display: flex; align-items: center; gap: var(--sp-2); justify-content: space-between; }

/* ---------- UN PUNCT DE LUCRU ÎNTR-O LISTĂ, ȘI PROBLEMELE UNUI ECHIPAMENT ----------
   ⭐⭐ VENITE AICI DIN FOAIA HĂRȚII LA RUNDA 6 (09.09.2026), din chiar motivul scris la
   §14b: aceeași componentă se desenează pe DOUĂ ecrane cu seturi de șabloane diferite —
   Parcul (vederea Listă) și Dispeceratul (lista de drumuri). Scrise în foaia unuia dintre
   ele, celălalt ar fi rămas fără ele sau ar fi primit o copie care diverge.
   ⛔ Nicio valoare schimbată la mutare: sunt exact regulile de dinainte. */
.punct-titlu { font-weight: 700; }
.punct-sub { color: var(--text-stins); font-size: var(--t-mic); }
/* Problemele unui echipament, una sub alta: ACELEAȘI vopsele ca în panoul hărții și în
   balon — e aceeași listă (`randAparat.Probleme`), deci ar fi o minciună de culoare să
   difere la un clic distanță. */
.probleme-rand { margin-top: 3px; display: flex; flex-direction: column; gap: 2px; }
.probleme-rand .pb { display: flex; align-items: baseline; gap: var(--sp-1);
                     font-size: var(--t-mic2); color: var(--text-slab); }
/* ⭐ SEMNALAREA E STARE, NU DRUM (runda contractelor pe secțiuni, 14.09.2026, Nelu).
   „cere service", „hârtie puțină", „tavă goală" rămân de apăsat, dar sublinierea e semnul
   NAVIGĂRII — iar un rând de stare subliniat citea ca o listă de legături.
   ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⭐⭐ ȘI CULOAREA E A STĂRII, PESTE TOT UNDE STĂ LISTA (runda balonului, 14.09.2026).   ║
   ║ Regula de dinainte era scrisă numai sub `.probleme-rand`: în balon și în panoul hărții ║
   ║ semnalările ieșeau tot subliniate albastru, iar pe Listă și pe Dispecerat gri.         ║
   ║ Pe ecranul unde omul caută ce e stricat, albastrul spune „se poate apăsa" peste ceva  ║
   ║ ce spune „aici e o problemă" — două înțelesuri pe aceeași culoare, și câștiga cel     ║
   ║ greșit. De azi textul ia culoarea STĂRII, după bulina din fața lui (aceeași potrivire ║
   ║ nivel → stare ca la `.badge`), iar drumul se arată la trecerea mouse-ului.            ║
   ║ ⛔ Pe `a.pb`, nu sub un părinte: e ACEEAȘI listă (`randAparat.Probleme`) în balon, în  ║
   ║ panou, pe Listă și pe Dispecerat; un al cincilea loc o primește fără să se scrie nimic.║
   ║ ⚠️ `:has()` pe bulină, nu o clasă nouă pe legătură: numele stării e deja pe bulină,   ║
   ║ iar `.rosu` ori `.galben` puse pe legătură i-ar fi dat și fondul pastilei.            ║
   ║ Garda: `TestSemnalarileNuSuntSubliniateSiPoartaStarea`.                                 ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
a.pb { text-decoration: none; }
a.pb:hover { text-decoration: underline; }
a.pb:has(.bul-n.rosu) { color: var(--rau-text); }
a.pb:has(.bul-n.portocaliu), a.pb:has(.bul-n.galben) { color: var(--avert-text); }
a.pb:has(.bul-n.gri) { color: var(--neutru-text); }
a.pb:has(.bul-n.verde) { color: var(--ok-text); }
.probleme-rand .bul-n { width: 8px; height: 8px; border-radius: 50%; flex: 0 0 auto;
                        transform: translateY(1px); }
.probleme-rand .bul-n.rosu { background: var(--nivel-rosu); }
.probleme-rand .bul-n.portocaliu { background: var(--nivel-portocaliu); }
.probleme-rand .bul-n.galben { background: var(--nivel-galben); }
.probleme-rand .bul-n.gri { background: var(--nivel-gri); }
.probleme-rand .bul-n.verde { background: var(--nivel-verde); }
/* ⚠️ Balonul unui punct poartă aceleași buline, în reguli SEPARATE: gărzile legendei cer ca
   fiecare culoare a legendei să fie o regulă proprie a `.probleme-rand` (L5, L6). */
.balon-in .bul-n.rosu { background: var(--nivel-rosu); }
.balon-in .bul-n.portocaliu { background: var(--nivel-portocaliu); }
.balon-in .bul-n.galben { background: var(--nivel-galben); }
.balon-in .bul-n.gri { background: var(--nivel-gri); }
.balon-in .bul-n.verde { background: var(--nivel-verde); }
/* ⭐ Bulina punctului fără colector, ÎN LEGENDĂ (runda 16, 11.09.2026): forma celorlalte,
   doar fondul e al ei. Până azi legenda desena chiar pinul hărții (`.pin-client`, 17 px cu
   contur alb), vizibil mai mare decât bulinele de 8 px de lângă el. ⛔ Pe HARTĂ pinul își
   păstrează mărimea: acolo ea e chiar mesajul. ⛔ Regula dă DOAR fondul — garda L6. */
.probleme-rand .bul-n.client { background: var(--nivel-client); }

/* ---------- BALONUL DE PE HARTĂ — URMEAZĂ TEMA (runda balonului, 14.09.2026) ----------
   ⛔⛔ PÂNĂ AZI ÎȘI LUA CULORILE DIN BARĂ (panoul, textul, linia și fundalul de trecere ale
   barei), scrise în stilul hărții. Pe tema de zi ieșea un balon NEGRU peste o hartă
   luminoasă — punctul #12 din registru, văzut de Nelu cu poză. Motivul vechi („stă peste
   dale, iar dalele nu se întunecă") e bun pentru pini, nu pentru o casetă de citit: balonul
   NU e coajă, e CONȚINUT peste hartă, deci are culorile paginii — luminos pe zi, grafit pe
   noapte. Aceeași greșeală ca banda de vederi de la runda zonei de sus.
   ⚠️ CHENARELE STAU AICI ÎNTREGI, nu doar culoarea lor: foaia hărții se încarcă DUPĂ temă,
   iar un `border-top: 1px solid` rămas acolo ar fi pus culoarea la loc pe `currentColor`.
   Chenarul casetei e nou și nu e decor: pe zi, un card alb peste dale deschise se desparte
   de ele doar prin umbră, iar pe un colț de hartă aproape alb umbra nu ajunge.
   Gărzile: `TestBalonulUrmeazaTemaNuBara` (Go) și `_dev-probe-balon.js` (Chrome). */
.balon-in { background: var(--fond-card); color: var(--text); border: 1px solid var(--linie); }
.balon-in .d, .balon-in .t .nrap, .balon-in .ap-cap .ser, .balon-in .maimult { color: var(--text-slab); }
.balon-in .motive, .balon-in .cifre { border-top: 1px solid var(--linie); }
.balon-in .subsol { border-top: 1px solid var(--linie); color: var(--text-slab); }
.balon-in .cifre span { background: var(--fond-slab); }
/* ⭐ NUMELE ECHIPAMENTULUI DIN BALON E LEGĂTURA OBIȘNUITĂ (15.09.2026): culoarea și sublinierea
   ale oricărei legături. ⛔ Regula există fiindcă `leaflet.css` scrie `.leaflet-container a`
   (0,1,1) — fără ea numele ar ieși teal. (0,2,1) și nu `.balon-in a`: aceea ar fi bătut, prin
   ordine, și butoanele din balon. Seria rămâne ștearsă, sub aceeași subliniere. */
.balon-in .ap-cap a { color: var(--accent); }
.balon-in .ap-cap a:hover { color: var(--accent-tare); }

/* ---------- PĂTRATUL DE MARCĂ DIN ANTET ----------
   ⭐ CERUT DE NELU: marca aparatului stă într-un pătrat, în antet, SCRISĂ — nu o
   iconiță. ⛔ Nicio siglă și niciun logo: n-avem drepturi pe ele, iar un pătrat cu
   litere se citește la fel de repede și nu îmbătrânește când producătorul își schimbă
   sigla. Textul îl dă aparatul (`echipament.brand`), deci nicio marcă nu e scrisă în cod. */
.pg-banda .pg-marca {
  flex: 0 0 auto; align-self: center;
  display: flex; align-items: center; justify-content: center;
  width: 54px; height: 54px; border-radius: var(--rot); margin-right: var(--sp-3);
  background: var(--banda-linie); color: var(--banda-text);
  font-size: var(--t-mic); font-weight: 700; letter-spacing: .04em;
  text-align: center; line-height: 1.1; overflow: hidden; word-break: break-word;
}
/* ⚠️ Banda e un `space-between` cu două coloane. Strecurat un al treilea copil la stânga,
   titlul ar fi plutit în MIJLOC, la distanță de pătratul care îl însoțește. Coloana de
   după pătrat crește, deci pătratul rămâne lipit de titlu, iar dreapta rămâne la dreapta.
   ⛔ Regula atârnă de existența pătratului (selector compus), deci ecranele fără marcă
   n-o văd deloc. */
.pg-banda .pg-marca + div { flex: 1 1 auto; }

/* ---------- SEMNUL FIRMEI ÎN ANTET (09.09.2026) ----------
   Aceeași așezare ca pătratul de marcă, din același motiv scris mai sus: banda e un
   `space-between` cu două coloane, iar coloana de după semn trebuie să crească, altfel
   titlul ar pluti în mijloc, departe de cercul care îl însoțește.
   ⛔ Regulile atârnă de existența semnului (selector compus), deci ecranele fără el
   n-o văd deloc. */
.pg-banda .semn-om { flex: 0 0 auto; align-self: center; margin-right: var(--sp-3); }
.pg-banda .semn-om + div { flex: 1 1 auto; }


/* ══════════════════════════════════════════════════════════════════════════════════════
   14c. PARCUL: CARDUL VIU AL UNUI APARAT, ȘI RUBRICILE LUI
   ══════════════════════════════════════════════════════════════════════════════════════
   ⭐⭐ CERUT DE NELU (08.09.2026), pe macheta „parc-colector": „fiecare aparat = CARD VIU
   — pătrat de marcă, nume + serie + pastilă de stare, barele de toner cu procent sub
   fiecare, și cele 4 contoare + Total. Clic pe card → fișa aparatului."

   AICI, nu în foaia unui ecran, fiindcă ACEEAȘI componentă se desenează pe DOUĂ ecrane cu
   seturi de șabloane diferite: fila Parc a fișei clientului (dispecer) și lista din
   portalul clientului. Scrisă în unul dintre ele, celălalt ar fi rămas fără ea sau ar fi
   primit o copie care diverge — chiar defectul reparat la barele de toner (08.09).

   ⛔ Barele de toner NU se redefinesc aici: sunt cele din 14b (`.tonere`, `.toner*`),
   aceleași pe card și pe capul fișei. Un al doilea set de reguli ar fi însemnat că un
   toner arată altfel în listă decât pe fișa lui, la un clic distanță. */

/* ---------- RUBRICA: „În contract (3)" ---------- */
.rubrica + .rubrica { margin-top: var(--sp-4); }
.rubrica-titlu {
  font-size: var(--t-mic2); font-weight: 600; color: var(--text-slab);
  margin: 0 0 var(--sp-2); text-transform: none;
}
.rubrica-expl { margin: -4px 0 var(--sp-2); }

/* ---------- LISTA DE CARDURI ----------
   ⚠️ GRILĂ, nu coloană: pe un ecran lat intră două-trei carduri pe rând, pe telefon unul.
   `minmax(320px, 1fr)` e măsurat, nu ales: sub 320 px, coloana contoarelor („A4 alb-negru
   … 114.000") se rupe pe două rânduri și cifrele nu se mai pot compara pe verticală. */
.ap-lista {
  display: grid; gap: var(--sp-3);
  /* ⭐⭐ GRILA INTELIGENTĂ (10.09.2026, cerută de Nelu): „max 3 pe rând; 4 = 2+2
     (echilibrat, nu 3+1); 5 = 3+2; 6 = 3+3."

     CÂTE coloane se cer vine din GO (`coloaneGrila`), pe `data-coloane` — o socoteală pe
     numărul de carduri, care în CSS nu se poate face: foaia numără cât LOC are, nu câte
     carduri sunt, deci n-ar fi putut niciodată deosebi 4 de 5.

     ⛔ CIFRA E O LIMITĂ DE SUS, nu o promisiune. `minmax` cere fiecărei coloane ori a
     n-a parte din rând, ori cei 320 px măsurați la 08.09 — care e mai mare. Pe un ecran
     îngust câștigă 320 px, `auto-fill` scade singur coloanele, iar telefonul primește una
     — fără ca ecranul să știe ceva despre telefoane.

     ⚠️ Scăderea gapurilor din 100% e obligatorie: fără ea, trei coloane de exact o treime
     plus două spații depășesc rândul, iar ultima cade dedesubt — adică exact 3+3+1 în
     locul lui 3+3+3, tăcut. */
  --n: 3;
  grid-template-columns: repeat(auto-fill,
      minmax(max(320px, calc((100% - (var(--n) - 1) * var(--sp-3)) / var(--n))), 1fr));
}
.ap-lista[data-coloane="1"] { --n: 1; }
.ap-lista[data-coloane="2"] { --n: 2; }
.ap-lista[data-coloane="3"] { --n: 3; }

/* ---------- CARDUL ----------
   `position: relative` e OBLIGATORIU: pe el se sprijină legătura întinsă de mai jos. */
.ap-card {
  position: relative;
  background: var(--fond-card); border: 1px solid var(--linie);
  border-radius: var(--rot-mare); padding: var(--sp-3) var(--sp-4);
  display: flex; flex-direction: column; gap: var(--sp-2);
}
.ap-card:hover { border-color: var(--accent); }

/* ---------- CAPUL: pătrat · nume/serie · pastilă ---------- */
.ap-cap { display: flex; align-items: flex-start; gap: var(--sp-3); }
.ap-ident { flex: 1 1 auto; min-width: 0; }
.ap-stare { flex: 0 0 auto; text-align: right; max-width: 45%; }

/* ⭐ PĂTRATUL DE MARCĂ, fratele mai mic al celui din bandă (14b).
   ⛔ Nicio siglă: n-avem drepturi pe ele, se schimbă fără să ne întrebe nimeni, iar o marcă
   nouă ar fi apărut ca un pătrat gol. Textul îl dă aparatul (`echipament.brand`), deci
   nicio marcă nu e scrisă în cod. Gol ⇒ pătratul nu se desenează deloc (în șablon). */
/* ⛔⛔ MARCA NU SE MAI RUPE ÎN DOUĂ (runda 17, 16.09.2026).
   Pătratul avea `word-break: break-word` într-o cutie de 40 px: „Lexmark" ieșea pe două
   rânduri, tăiat la mijlocul cuvântului — „Lexma / rk". Nu e o urâțenie de așezare, e un
   ALT CUVÂNT: omul citește pe card o marcă pe care n-o are nimeni. Se vedea cel mai bine
   pe telefon (390 px), unde cardul e îngust și ochiul cade întâi pe pătrat.
   ⭐ De azi: un singur rând, scurtat cu „…" când nu încape. Un cuvânt scurtat SE VEDE că
   e scurtat, pe când unul rupt pare întreg — iar numele plin e oricum alături, pe rândul
   modelului, și în bula pătratului.
   ⚠️ `display: block` cu `line-height` cât cutia, nu `flex`: `text-overflow` cere o cutie
   de text, iar pe un container flex n-are pe ce se aplica. 38px = 40 minus cele două
   margini de 1px (`box-sizing: border-box` e global, rândul 638). */
.ap-marca {
  flex: 0 0 auto;
  display: block;
  width: 40px; height: 40px; border-radius: var(--rot);
  background: var(--fond-slab); color: var(--text-slab); border: 1px solid var(--linie);
  font-size: var(--t-xs); font-weight: 700; letter-spacing: .03em;
  text-align: center; line-height: 38px; padding: 0 2px;
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
}
.ap-nume { font-size: var(--t-mare); font-weight: 600; line-height: 1.2; }
.ap-nume a { color: var(--text); text-decoration: none; }
.ap-nume a:hover { color: var(--accent); }
/* ⭐⭐ CLIC PE TOT CARDUL, DINTR-O SINGURĂ ANCORĂ („stretched link").
   Un <a> care înghite cardul ar fi fost HTML NEVALID: subsolul dispecerului are legăturile
   lui („lămurește", „pune pe contract"), iar o ancoră în altă ancoră o rup browserele unde
   vor — și primul lucru pierdut e chiar clicul pe card. Aici ancora rămâne una singură, pe
   nume, iar ::after-ul ei acoperă cardul. */
.ap-nume a::after { content: ""; position: absolute; inset: 0; }
/* Legăturile din subsol trec PESTE pătura de mai sus, altfel ar fi acoperite de ea.
   ⛔⛔ ȘI FAPTA DESCOPERITULUI (10.09.2026), din exact același motiv, plătit înainte de a
   fi văzut: butonul „Începe citirea" e un `<button>` într-un `<form>`, iar pătura
   `::after` a legăturii întinse l-ar fi acoperit COMPLET. Nu s-ar fi văzut nimic greșit pe
   ecran — butonul e desenat, arată bine — dar clicul pe el ar fi deschis fișa aparatului
   în loc să pornească citirea. Cea mai tăcută formă a unui buton mort. */
.ap-randuri a, .ap-loc a, .ap-fapta { position: relative; z-index: 1; }
.ap-serie {
  font-family: var(--font-cod); font-size: var(--t-mic); color: var(--text-stins);
  margin-top: 1px; overflow-wrap: anywhere;
}
/* Avertismentul pe limba omului („hârtie blocată — oprește tiparul"), sub pastilă. */
.ap-avert { font-size: var(--t-mic2); margin-top: 3px; line-height: var(--ritm); }

/* ---------- SEMNUL DE LEGĂTURĂ: „mai vorbim cu ăsta?" ----------
   ⭐⭐ CERUT DE NELU (10.09.2026): „fiecare card de echipament poartă starea de legătură,
   pe TOATE ecranele unde apare." Iar seara, a doua jumătate: „starea online/offline a
   colectoarelor ȘI a aparatelor vreau să fie mai vizibilă; acum avem doar un text cu
   litere mici și nu e evidențiat. Vreau să evidențiem cu bulină verde/gri PESTE TOT."

   ⛔⛔ DOUĂ CULORI, NU TREI. `.pt.gri-desc` — bulina GOALĂ (fond stins, contur), cu care
   se despărțea „n-am întrebat" de „am întrebat și n-a răspuns" — A FOST ȘTEARSĂ, la
   cererea lui: „doar se schimbă mesajul din dreptul bulinei". Deosebirea o poartă TEXTUL,
   care se citește oricum de aproape; bulina rămâne cu o singură treabă, aceea de a prinde
   ochiul de la doi metri. Trei nuanțe cer o legendă, două nu cer nimic.

   ⛔⛔ MUTAT AICI DIN `stilHarta`, NU SCRIS A DOUA OARĂ. Cele cinci reguli trăiau în foaia
   INLINE a hărții — deci componenta care despărțea legătura de starea aparatului era
   ferecată în singurul ecran pe care omul NU se uită când vrea să afle ce e cu un
   echipament al unei firme. Cardul de pe fila Parc, cel din portal și amândouă capetele de
   fișă n-o puteau desena, oricât ar fi cerut-o cineva.

   ⚠️ Culorile lui NU sunt culorile hărții — de aceea clasele au alt prefix (`pt`), ca să
   nu se confunde la o corecție grăbită. „gri" e „am întrebat și n-a răspuns" (o veste
   proastă); „gri-desc" e „în afara scării" — nemonitorizat, încă necitit, neîntrebat. */
.sem { display: inline-flex; align-items: center; gap: var(--sp-1); font-size: var(--t-mic); color: var(--text-slab); }
/* ⛔⛔ IMPLICITUL E GRI, ȘI E O REPARAȚIE (10.09.2026, găsită măsurând jetoanele înainte de
   a scrie o linie — cerută de Nelu după runda cyanului, unde implicitul ieșise ROȘU).
   Aici nu era roșu: nu era NIMIC. `.pt` n-avea niciun fond, deci o clasă nerecunoscută
   desena o bulină TRANSPARENTĂ de 9 px — adică un ecran pe care starea pur și simplu
   lipsește, fără nicio urmă că lipsește. Iar acum, când bulina e purtată de zece ecrane
   în loc de patru, tăcerea aia s-ar fi văzut ultima. Necunoscutul e gri: „nu se știe". */
.pt { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; display: inline-block;
  background: var(--neutru-semn); }
.pt.verde { background: var(--ok-semn); }
.pt.gri { background: var(--neutru-semn); }

/* ---------- CORPUL: tonerele la stânga, contoarele la dreapta ---------- */
.ap-corp { display: flex; gap: var(--sp-4); flex-wrap: wrap; align-items: flex-start; }
/* ⛔⛔ `min-width: 0` NU E ORNAMENT — repară o derulare laterală GĂSITĂ ÎN CHROME (runda 9,
   10.09.2026), pe un echipament care n-a raportat NICIUN consumabil.

   `flex: 0 0 auto` spune „cât îți trebuie, și nu te micșora". Cu bare, „cât îți trebuie" e
   lățimea măsurată (42 px de bară) și totul e în regulă. FĂRĂ bare, coloana poartă în
   schimb PROPOZIȚIA („Echipamentul n-a raportat niciun consumabil la ultima măsurătoare"),
   iar un element flex are, implicit, `min-width: auto` — adică refuză să scadă sub lățimea
   celui mai lung cuvânt-rând al conținutului. La 390 px cutia ieșea la 416 px și împingea
   PAGINA cu 27 px; la 768 px, cu 3.

   ⚠️ DEFECT VECHI, nu adus de rundă: măsurat și cu semnul de legătură scos (sabotajul
   `--fara-semn`), derularea rămâne. N-a fost văzut până azi fiindcă niciun set de probă
   n-avea un echipament FĂRĂ consumabile — a treia oară aceeași lecție („o secțiune e
   nemăsurată dacă fixture-ul n-are starea ei").

   ⛔ CELE DOUĂ ÎMPREUNĂ, ȘI NICIUNA SINGURĂ — măsurat, nu presupus: cu `min-width: 0` dar
   `flex-shrink: 0`, cutia tot refuză să scadă și derularea rămâne (probat, 27 px la 390).
   Cu shrink dar fără `min-width: 0`, podeaua de `auto` o oprește tot acolo.

   ⚠️ BARELE NU SE MICȘOREAZĂ, și de-aia `flex-basis` rămâne `auto`: cu patru bare desenate
   conținutul cere ~190 px, iar cardul are ~330 px chiar pe telefon — deci nu se ajunge la
   micșorare. Shrink-ul mușcă DOAR pe cutia care poartă o propoziție, adică exact cazul
   pentru care e pus. */
.ap-tonere { flex: 0 1 auto; min-width: 0; }
/* ⚠️ Contoarele cresc, tonerele nu: barele au lățime măsurată (42 px, 14b), iar cifrele
   au nevoie de tot spațiul rămas ca eticheta și valoarea să stea la capetele rândului. */
.ap-contoare { flex: 1 1 150px; min-width: 150px; }
.ap-tonere .kpi-et, .ap-contoare .kpi-et { margin-bottom: var(--sp-1); }
.ap-loc { font-size: var(--t-mic2); color: var(--text-slab); }


/* ---------- CAPUL PUNCTULUI DE LUCRU: pin · nume · adresă ----------
   ⭐ CERUT DE NELU (08.09.2026): „PUNCT DE LUCRU ca un card mare: pin 📍 + nume/adresă +
   «pe hartă»". Pinul e un EMOJI, nu o imagine: se vede la fel în amândouă modurile, nu
   cere un fișier și nu se face pătrat gol pe niciun sistem.

   AICI, nu în foaia unui ecran, fiindcă același cap se desenează pe fila Parc a fișei
   (dispecer) ȘI în portalul clientului — două seturi de șabloane, o singură formă. */
.pct-pin { font-style: normal; margin-right: 2px; }
/* Adresa PUNCTULUI (unde stă aparatul), nu a firmei — vezi comentariul din șablon.
   ⚠️ `margin-left` o aliniază sub nume, nu sub pin: altfel al doilea rând pornea cu două
   caractere mai la stânga și capul arăta strâmb. */
.pct-adresa { margin-left: 1.35em; }

/* ---------- COLECTORUL, ÎNĂUNTRUL PUNCTULUI ----------
   ⭐ Iconiță + nume + pastilă + „a raportat acum X", iar la dreapta acțiunea lui.
   ⛔ ICONIȚA E UN SEMN DE TEXT, nu o siglă: aceeași hotărâre ca la pătratul de marcă. */
.col-cap { display: flex; align-items: center; gap: var(--sp-2); flex-wrap: wrap; }
.col-icon {
  display: inline-flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; border-radius: var(--rot-mic);
  background: var(--fond-slab); border: 1px solid var(--linie);
  color: var(--text-stins); font-size: var(--t-mic);
}
.col-nume { font-weight: 600; }
/* ⛔ `.col-cand` A DISPĂRUT (10.09.2026), și n-a fost mutată: e ȘTEARSĂ. Purta „a raportat
   acum 21 sec" ca al doilea text de lângă pastila colectorului. De când starea e un singur
   semn — bulină plus cuvinte —, vârsta stă ÎN cuvintele lui, iar regula rămasă aici ar fi
   fost o vopsea pe care n-o mai cere nimeni. */
/* ---------- CELE TREI FAPTE ALE MAȘINII, CA SUB-CARDURI VERTICALE (10.09.2026) ----------
   ⛔⛔ AICI ERA `.col-actiuni { margin-left: auto }`, ȘI ERA GREȘIT.
   Regula împingea cele trei butoane la capătul RÂNDULUI DE TITLU, unde se strângeau peste
   pastile și peste numele mașinii — plutind în colțul dreapta-sus, peste conținut. Nu asta
   e macheta validată: faptele stau în CORPUL cardului, una sub alta, fiecare cu titlul ei,
   cu butonul standard al temei și cu rezultatul CHIAR sub buton.
   ⚠️ Regula veche s-a ȘTERS, nu s-a lăsat alături: un stil rămas fără element e capcana
   pe care o știe casa — primul care îl vede crede că ecranul îl folosește. */
/* ⚠️ `max-width: 520px` RĂMÂNE CIFRĂ FIXĂ, și s-a verificat (12.09.2026): la runda 24 a
   fost schimbată în `min(520px, 100%)`, crezând că pe telefon cardul cere 520 într-o cutie
   de 306. ⛔ SABOTAJUL A IEȘIT VERDE — `.col-fapte` e bloc, deci lățimea lui vine oricum de
   la părinte, iar maximul nu poate umfla nimic. Schimbarea s-a dat înapoi: o reparație care
   nu repară nimic e o linie pe care cineva o va apăra degeaba peste un an. */
.col-fapte { margin: var(--sp-3) 0 var(--sp-3) var(--sp-3); display: flex;
             flex-direction: column; gap: var(--sp-1); max-width: 520px; }
/* Sub-cardul unei fapte. Fond slab, nu chenar plin: e o unealtă înăuntrul unui card, iar
   două chenaruri la 1 px distanță se citesc ca o greșeală de randare (regula cardului).
   ⛔⛔ COMPACT (10.09.2026, macheta „parc-cap-vertical"): un RÂND — numele la stânga,
   butonul la dreapta —, iar rezultatul mărunt dedesubt. Prima formă punea sub fiecare
   titlu un paragraf de două rânduri: trei paragrafe pe fiecare mașină, citite o dată și
   recitite de o mie de ori. Explicația s-a mutat sub „?" (`.dece`), regula casei din
   22.08 — „faptul scurt, de ce-ul discret". */
.fapta { background: var(--fond-slab); border: 1px solid var(--linie-slaba);
         border-radius: var(--rot); padding: var(--sp-2) var(--sp-3); }
.fapta-rand { display: flex; align-items: center; gap: var(--sp-3); }
/* Numele crește, butonul rămâne cât îi trebuie: așa butoanele celor trei fapte se aliniază
   pe aceeași verticală, oricât de lung ar fi numele. */
.fapta-titlu { flex: 1 1 auto; min-width: 0; font-size: var(--t-mic2); font-weight: 600; }
.fapta-titlu .dece { margin-left: var(--sp-1); }
.fapta-rand form { flex: 0 0 auto; }
/* Rezultatul stă SUB rândul faptei, nu într-o casetă comună a mașinii. */
.fapta-rez { margin-top: var(--sp-1); line-height: var(--ritm); overflow-wrap: anywhere; }
.fapta-rez > div + div { margin-top: 2px; }
/* ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⛔⛔ AICI PASTILA POARTĂ O PROPOZIȚIE, DECI SE RUPE (12.09.2026, măsurat la 390 px).  ║
   ║                                                                                       ║
   ║ Tema spune, o dată pentru tot produsul, `.pastila, .badge { white-space: nowrap }` —  ║
   ║ și e regula bună, fiindcă o pastilă obișnuită poartă un cuvânt („activ", „gata").     ║
   ║ Faptele mașinii scriu în ele MOTIVUL întreg, fiindcă acolo el e chiar informația:     ║
   ║ „expirat — colectorul nu l-a luat în 15 minute (e oprit sau fără legătură)".          ║
   ║ ⛔ MĂSURAT: pastila asta ieșea cu 109 px din cutia ei la 390 px și împingea pagina.   ║
   ║                                                                                       ║
   ║ ⚠️ ACELAȘI TIPAR CA LA LISTA DE PE HARTĂ (runda 22, caseta lui `.hc-rand`): un        ║
   ║ `overflow-wrap` pus mai sus nu poate face nimic, fiindcă `nowrap` interzice ruperea   ║
   ║ din capul locului. Se stinge exact unde textul a încetat să fie un cuvânt.            ║
   ║ ⭐ AICI, la componentă, nu în celula de tabel: aceleași trei fapte se desenează ȘI pe  ║
   ║ fila Parc a firmei, unde nu există nicio coloană de acțiuni — iar o reparație pusă    ║
   ║ acolo ar fi lăsat al doilea ecran cu defectul.                                         ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
.fapta-rez .badge, .fapta-rez .pastila, .fapta-rez .semn { white-space: normal; }
/* Aparatele stau vizibil SUB colectorul care le citește: retragerea e ierarhia, scrisă
   cu spațiu în loc de o linie în plus. */
.col-corp { margin-left: var(--sp-3); }

/* ---------- CAPUL FILEI PARC: HARTA ȘI PUNCTELE, UNUL LÂNGĂ ALTUL (10.09.2026) ----------
   ⭐ CERUT DE NELU: „SUS, 2 carduri: harta cu pinii tuturor punctelor + lista punctelor."
   ⚠️ `minmax(0, 1fr)` pe amândouă coloanele, nu `1fr` gol: cutia hărții are lățime proprie,
   iar fără minimul zero grila i-ar da voie să împingă coloana din dreapta afară din card.
   Sub 900 px trec una sub alta — harta rămâne întâi, fiindcă ea răspunde la „unde". */
.parc-cap { display: grid; gap: var(--sp-3); grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); }
/* ⚠️ 820, nu 900 (08.09.2026): era al doilea prag al produsului, pentru un singur grid.
   Un prag în plus înseamnă o fâșie de lățimi (821–900) în care capul de aparat se poartă
   altfel decât tot restul, fără ca cineva să fi hotărât asta. Un prag, un loc. */
@media (max-width: 820px) { .parc-cap { grid-template-columns: minmax(0, 1fr); } }
/* Cardurile din cap își împart înălțimea: unul scurt lângă unul lung arată ca o greșeală. */
.parc-cap > .card { margin-bottom: 0; }
.hp-card { display: flex; flex-direction: column; }
.hp-card .hp-harta { flex: 1 1 auto; min-height: 260px; }
/* ---------- TITLUL CARDULUI DE HARTĂ: numele la stânga, drumul la dreapta ----------
   ⛔⛔ PRINS CU OCHII PE ECRAN (10.09.2026): cu `float: right` pe legătură, titlul și ea
   ieșeau LIPITE — „puncteledeschide harta". Un text simplu lângă un element flotant nu are
   nici spațiu sigur, nici o regulă de așezare care să-i despartă.
   ⚠️ SELECTORUL MERGE PE `.hp-card h3`, NU pe o clasă a titlului: `static/sectiuni.js` mută
   titlul într-un `<summary>` și îi ȘTERGE clasele, deci o regulă legată de clasa lui ar fi
   dispărut la prima randare în browser — și numai acolo. */
.hp-card h3 { display: flex; align-items: baseline; gap: var(--sp-3); }
.hp-titlu { flex: 0 1 auto; min-width: 0; }
/* Legătura se împinge la capătul rândului: e ACȚIUNEA secțiunii, ca peste tot în produs. */
.hp-tot { margin-left: auto; flex: 0 0 auto; white-space: nowrap;
          font-size: var(--t-mic2); text-transform: none; letter-spacing: normal; font-weight: 400; }
.hp-balon strong { display: block; }

/* ---------- RÂNDUL UNUI PUNCT DE LUCRU, ÎN CARDUL DE SUS ----------
   ⛔ Rândul, nu un card: sunt câteva pe firmă, iar un chenar în jurul fiecăruia ar fi
   făcut din lista de locuri un teanc de cutii — chiar defectul reparat la 08.09 în
   celălalt sens (un card mare care înghițea tot parcul). */
.pct-rand { padding: var(--sp-3) 0; border-top: 1px solid var(--linie-slaba); }
.pct-rand:first-of-type { border-top: 0; padding-top: 0; }
.pct-sus { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
.pct-nume { font-size: var(--t-baza); }
/* ⛔ `.pct-stare` A DISPĂRUT (10.09.2026), din același motiv: rândul punctului își scria
   cuvintele de stare cu regula lui, lângă o bulină `.punct-stare` a lui. Amândouă au fost
   înlocuite de componenta comună (`.sem` + `.pt`), care le poartă pe amândouă — deci aici
   nu mai rămâne nimic de definit. */
/* Numărul de aparate se împinge la dreapta: e MĂSURA punctului, citită pe coloană. */
.pct-nr { margin-left: auto; font-size: var(--t-mic); color: var(--text-stins);
          font-variant-numeric: tabular-nums; }
.pct-col { margin-top: 2px; }
.pct-actiune { margin-top: var(--sp-2); }
.pct-cod { margin-top: var(--sp-2); }

/* ---------- FILTRUL PE COLECTOR, ȘI GRUPUL UNEI MAȘINI ----------
   Pastilele sunt `.filtru`, aceleași ca pe hartă și pe Mesaje — vezi secțiunea lor. */
.parc-filtre { display: flex; gap: var(--sp-1); flex-wrap: wrap; margin-top: var(--sp-3); }
/* Grupul: un card pe mașină. Titlul lui e rândul colectorului, deja stilat mai sus. */
.grup-parc .col-loc { margin: 2px 0 var(--sp-3) 30px; }
.grup-parc .col-actiune { margin: var(--sp-2) 0 0; }

/* ---------- SUBSOLUL DISPECERULUI: cele trei coloane ale tabelului de dinainte ---------- */
.ap-randuri {
  display: flex; flex-wrap: wrap; gap: var(--sp-1) var(--sp-3);
  border-top: 1px solid var(--linie-slaba); padding-top: var(--sp-2);
  font-size: var(--t-mic); line-height: var(--ritm);
}
.ap-rand { display: inline-flex; align-items: baseline; gap: 4px; }

/* ══════════════════════════════════════════════════════════════════════════════════════
   15. SECȚIUNI PLIATE
   ══════════════════════════════════════════════════════════════════════════════════════
   ⚠️ `details.dece-pliat` are regulile lui mai sus și NU trebuie prinsă aici — de aceea
   selectorul e pe `.pliat`, nu pe `details` gol. */
.pliat { border-top: 1px solid var(--linie-slaba); }
.pliat > summary {
  padding: var(--sp-3) var(--sp-4); cursor: pointer;
  font-size: var(--t-mic2); font-weight: 600; color: var(--text-slab);
}
.pliat > summary:hover { background: var(--fond-slab); color: var(--text); }

/* ---------- SECȚIUNEA UNEI PAGINI: cardul cu titlu, cu săgeata lui ----------
   ⭐⭐ AICI ERA, PÂNĂ LA 06.09.2026, ÎN <style>-UL FIȘEI APARATULUI — un singur ecran din
   nouăzeci. Cerința („orice secțiune de pe orice pagină are săgeata de pliere") nu se
   putea împlini copiind zece rânduri de CSS în treizeci de fișiere; forma unei secțiuni
   se scrie o dată, ca a cardului sau a insignei.

   Elementul e `<details>` NATIV. Pe fișa aparatului e scris așa în șablon; pe restul îl
   construiește static/sectiuni.js din cardul cu `data-sectiune`. Aceleași reguli prind
   amândouă drumurile, fiindcă amândouă ajung la același element.

   ⚠️ Titlul rămâne un <h2>/<h3> ÎNĂUNTRUL lui <summary>: fără el secțiunea își pierde
   rangul din structura paginii (și o gardă care taie cardurile la următorul <h3> începe
   să măsoare altceva). `font: inherit` îl aduce la litera mică și rărită a lui
   `.sec-titlu`, deci un ecran cu <h2> și unul cu <h3> arată în sfârșit la fel. */
details.sectiune > summary {
  list-style: none; cursor: pointer; display: flex; align-items: center; gap: var(--sp-2);
}
details.sectiune > summary::-webkit-details-marker { display: none; }
details.sectiune > summary::before {
  content: "▸"; color: var(--text-stins); font-size: var(--t-xs); transition: transform .12s;
}
details.sectiune[open] > summary::before { transform: rotate(90deg); }
details.sectiune > summary:hover { color: var(--accent); }
/* ⚠️ MARGINILE DOAR PE `.sec-titlu`, nu pe orice mâner. Celălalt fel de titlu de secțiune
   din produs e `.sect` — bara cu linie sub ea, din portal —, iar ea își are propriile
   `padding` și `border-bottom`. O margine de jos pusă peste ele ar fi despărțit bara de
   tabelul de sub ea, pe un ecran în care nu s-a cerut nicio schimbare. */
details.sectiune > summary.sec-titlu { margin: 0; }
details.sectiune[open] > summary.sec-titlu { margin: 0 0 var(--sp-2); }
details.sectiune > summary > h2,
details.sectiune > summary > h3 {
  margin: 0; font: inherit; color: inherit;
  text-transform: inherit; letter-spacing: inherit;
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   16. MODALE
   ══════════════════════════════════════════════════════════════════════════════════════
   `<dialog>` nativ: focalizarea prinsă, Escape care închide și fundalul inert vin de la
   browser. O cutie făcută cu div-uri le-ar fi cerut pe toate trei în JS, iar cea care se
   uită mereu e prinderea focalizării. */
dialog, .modal {
  border: 1px solid var(--linie); border-radius: var(--rot-mare);
  background: var(--fond-card); color: var(--text);
  padding: var(--sp-5); box-shadow: var(--umbra-plutire);
  max-width: min(560px, calc(100vw - 2 * var(--sp-5)));
}
dialog::backdrop { background: rgba(0, 0, 0, .45); }
.modal-titlu { margin: 0 0 var(--sp-3); font-size: var(--t-mare); font-weight: 700; }
.modal-actiuni { margin-top: var(--sp-5); display: flex; gap: var(--sp-2); justify-content: flex-end; }

/* ══════════════════════════════════════════════════════════════════════════════════════
   16b. CALC — CALCULATORUL DE PREȚ, UNEALTĂ UNIVERSALĂ (runda 15, 11.09.2026)
   ══════════════════════════════════════════════════════════════════════════════════════
   ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⭐⭐ Nelu: „calculatorul ca tool universal pe site, ce se poate deschide pe toate      ║
   ║ paginile". Butonul „Calc" din bară deschide o FEREASTRĂ PĂTRATĂ, care se mută trasă   ║
   ║ de antet (locul îl scrie `static/calc.js` în `--calc-x` / `--calc-y`). Pe Consumabile ║
   ║ același calculator stă și într-un card. Pe telefon fereastra ia tot ecranul (§19c).    ║
   ║ ⛔ Rândurile de curs și câmpurile au stat până azi în foaia ecranelor (`stilCursCard`);║
   ║ de când calculatorul e în bară, e pe TOATE ecranele interne, deci foaia e a temei.     ║
   ║ ⛔ REZULTATUL E STRÂNS: prețul final, UN buton de copiat, lanțul într-un rând mic.     ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
.bs .bs-calc {
  display: inline-flex; align-items: center; gap: var(--sp-1); flex: 0 0 auto;
  background: transparent; color: var(--bara-text); border: 1px solid var(--bara-linie);
  border-radius: var(--rot-mic); padding: var(--sp-1) var(--sp-2);
  font: inherit; font-size: var(--t-mic2); line-height: 1; cursor: pointer;
}
.bs .bs-calc:hover, .bs .bs-calc[aria-expanded="true"] { background: var(--bara-hover); color: var(--bara-text-tare); }
.bs .bs-calc-pict { width: 14px; height: 14px; flex: 0 0 auto; }

/* FEREASTRA. ⚠️ `dialog` NEMODAL (`show()`): pagina de dedesubt rămâne vie, iar un clic în
   afara ferestrei o închide. `display` se pune doar pe `[open]` — pus pe elementul închis,
   ar fi bătut regula browserului care îl ascunde. */
dialog.calc-fereastra {
  position: fixed; inset: auto; margin: 0; padding: 0; z-index: 1100;
  left: var(--calc-x, auto); right: auto;
  top: var(--calc-y, calc(var(--bs-inaltime) + var(--sp-1)));
  width: min(22rem, calc(100vw - 2 * var(--sp-3)));
  aspect-ratio: 1 / 1; max-width: none; max-height: calc(100vh - 2 * var(--sp-3));
  overflow: hidden;
}
dialog.calc-fereastra[open] { display: flex; flex-direction: column; }
.calc-cap {
  display: flex; align-items: center; gap: var(--sp-2); flex: 0 0 auto;
  padding: var(--sp-1) var(--sp-1) var(--sp-1) var(--sp-3);
  border-bottom: 1px solid var(--linie); font-size: var(--t-mic2);
  cursor: move; user-select: none; touch-action: none;
}
.calc-cap strong { margin-right: auto; }
.calc-inchide {
  background: transparent; border: 0; border-radius: var(--rot-mic); padding: 0;
  width: 32px; height: 32px; font-size: var(--t-mare); line-height: 1;
  color: var(--text-slab); cursor: pointer;
}
.calc-inchide:hover { background: var(--fond-slab); color: var(--text); }
.calc-corp { flex: 1 1 auto; overflow-y: auto; padding: var(--sp-2) var(--sp-3) var(--sp-3); }
.calc-sursa { font-size: var(--t-xs); color: var(--text-stins); text-transform: uppercase; letter-spacing: .03em; }

/* CALCULATORUL ÎNSUȘI — același în fereastră și în cardul de pe Consumabile. */
.calc .curs-rand { display: flex; align-items: baseline; gap: var(--sp-1); margin-top: 2px;
                   font-variant-numeric: tabular-nums; font-size: var(--t-mic2); }
.calc .curs-rand .sg { font-weight: 700; }
/* ⚠️ La un COST, o creștere e o veste proastă — săgeata în sus poartă culoarea de rău. */
.calc .curs-rand .sg.sus { color: var(--rau-text); }
.calc .curs-rand .sg.jos { color: var(--ok-text); }
.calc .curs-rand .dl { color: var(--text-stins); font-size: var(--t-xs); }
.calc .curs-gol { color: var(--text-stins); margin-top: var(--sp-1); font-size: var(--t-mic2); }
.calc-campuri {
  margin-top: var(--sp-2); padding-top: var(--sp-2); border-top: 1px solid var(--linie);
  display: grid; grid-template-columns: minmax(0, 1fr) 5.5rem; gap: var(--sp-1) var(--sp-2);
}
.calc-campuri label { display: flex; flex-direction: column; gap: 2px; margin: 0;
                      font-size: var(--t-xs); color: var(--text-slab); }
.calc-campuri input[type=text], .calc-campuri select { width: 100%; min-width: 0; }
.calc-campuri .calc-regula { grid-column: 1 / -1; flex-direction: row; align-items: center; gap: var(--sp-1); }
.calc-rez { margin-top: var(--sp-2); }
.calc-final { display: flex; align-items: baseline; gap: var(--sp-2); flex-wrap: wrap; }
.calc-final-et { font-size: var(--t-xs); color: var(--text-slab); }
.calc-final-vl { font-size: var(--t-mare); font-weight: 700; font-variant-numeric: tabular-nums; }
/* ⛔ „COPIAZĂ" RĂMÂNE CUM ERA (Nelu: calculatorul „e foarte bine făcut, nu îl modificăm").
   Până la runda uniformizării butoanelor își lua plinul din `button` gol; de când implicitul
   e butonul GOL, plinul i se scrie aici, pe nume, cu exact aceleași jetoane. Proba din Chrome
   îi compară desenul cu fotografia de dinainte. */
.calc-copie { margin-left: auto; background: var(--buton-fond); color: var(--buton-text); border-color: transparent; }
.calc-copie:hover { background: var(--buton-fond-hover); color: var(--buton-text); border-color: transparent; }
.calc-copie:active { background: var(--accent-tare); }
.calc-lant { margin-top: 2px; font-size: var(--t-xs); color: var(--text-stins); font-variant-numeric: tabular-nums; }
.calc-eroare { font-size: var(--t-mic2); color: var(--rau-text); }

/* ---------- CARDUL DISCRET (runda 15) ----------
   ⭐ Pentru un card care însoțește ecranul fără să-i fure ochiul: legenda culorilor de pe
   hartă. Fond mai stins, literă mai mică, mai puțin aer — ⛔ nimic ascuns, nimic tăiat. */
.card.discret { background: var(--fond-slab); padding: var(--sp-1) var(--sp-3); }
.card.discret .sec-titlu { font-size: var(--t-xs); margin: var(--sp-2) 0 2px; }
/* ⚠️ Marginile de mai sus sunt ale subtitlului dinăuntru („Bulina de legătură"), nu ale
   mânerului. Pe mâner ar fi bătut `summary.sec-titlu { margin: 0 }` din §15, iar strânsă
   legenda ajungea la 72 px pe telefon (44 ținta degetului + 28 margini) în loc de un rând mic. */
.card.discret > details.sectiune > summary,
.card.discret > details.sectiune > summary > .sec-titlu { margin: 0; }
.card.discret > details.sectiune[open] > summary { margin-bottom: 2px; }
.card.discret .probleme-rand { gap: 0; margin-top: 0; }
.card.discret .probleme-rand .pb, .card.discret .sem { font-size: var(--t-xs); line-height: 1.35; }

/* ---------- VESTEA DE DUPĂ APĂSARE, SUB BARĂ (runda 17) ----------
   ⭐ De la runda 17 pagina își ține locul după orice apăsare (static/pozitie.js). Dar vestea
   ecranului („Semnalarea a fost închisă", o eroare) e scrisă SUS, în capul paginii — deci
   ar fi rămas deasupra ecranului, iar o eroare nevăzută îl face pe om să apese din nou.
   Ce a apărut NOU deasupra ecranului se arată și aici, sub bară.
   ⛔ Nu e un fel nou de veste: e o RAMĂ în jurul vestei pe care ecranul a scris-o deja, cu
   clasele ei — o eroare rămâne eroare, o reușită rămâne reușită.
   Se închide din ×, sau singură când omul derulează până la vestea din pagină. Sub bară și
   peste filele lipite (900), sub bară (1000) și sub fereastra „Calc" (1100). */
.veste-plutitoare {
  position: fixed; z-index: 950;
  top: calc(var(--bs-inaltime) + var(--sp-2));
  left: 50%; transform: translateX(-50%);
  width: min(40rem, calc(100vw - 2 * var(--sp-3)));
  display: flex; align-items: flex-start; gap: var(--sp-1);
  background: var(--fond-card); border: 1px solid var(--linie); border-radius: var(--rot-mic);
  box-shadow: var(--umbra-plutire); padding: var(--sp-1);
}
.veste-plutitoare-corp { flex: 1 1 auto; min-width: 0; }
.veste-plutitoare-corp > * { margin: 0; }
.veste-plutitoare-corp > * + * { margin-top: var(--sp-1); }
.veste-plutitoare-inchide {
  flex: 0 0 auto; background: transparent; border: 0; border-radius: var(--rot-mic); padding: 0;
  width: 44px; height: 44px; font-size: var(--t-mare); line-height: 1;
  color: var(--text-slab); cursor: pointer;
}
.veste-plutitoare-inchide:hover { background: var(--fond-slab); color: var(--text); }

/* ══════════════════════════════════════════════════════════════════════════════════════
   17. RÂNDUL DE FILTRE ȘI PAGINAREA
   ══════════════════════════════════════════════════════════════════════════════════════
   Aceeași așezare pe orice listă care poate crește: CĂUTAREA PRIMA (singurul control
   folosit fără să te uiți), apoi dropdownurile, apoi butonul, iar la capătul din dreapta
   cifra „câte din câte". */
.fl { display: flex; gap: var(--sp-2); align-items: flex-end; flex-wrap: wrap; margin-bottom: var(--sp-3); }
.fl label { display: block; font-size: var(--t-xs); color: var(--text-slab); margin: 0 0 var(--sp-1); }
.fl input[type=search], .fl select { width: auto; font-size: var(--t-mic2); padding: var(--sp-1) var(--sp-2); }
.fl input[type=search] { min-width: 220px; }
.fl button { font-size: var(--t-mic2); padding: var(--sp-1) var(--sp-3); }
.fl .fl-bifa { display: flex; align-items: center; gap: var(--sp-1); padding-bottom: var(--sp-1); }
.fl .fl-bifa label { display: inline; margin: 0; font-size: var(--t-mic2); color: var(--text); }
/* Intervalul de zile de pe rândul de filtre (runda 16): două câmpuri de dată și cuvântul
   dintre ele, ținute pe același rând de bază ca celelalte controale. Eticheta rămâne
   deasupra PRIMULUI câmp, ca la orice alt filtru — un al doilea „Până în" scris ca
   etichetă ar fi rupt aliniamentul rândului. */
.fl .fl-cand { display: flex; align-items: flex-end; gap: var(--sp-1); flex-wrap: wrap; }
.fl .fl-cand > label { flex-basis: 100%; }
.fl .fl-cand .fl-pana { font-size: var(--t-xs); color: var(--text-slab); padding-bottom: var(--sp-2); }
.fl .fl-cand input[type=text] { width: 9em; font-size: var(--t-mic2); padding: var(--sp-1) var(--sp-2); }
/* ⛔ Pe rândul de filtre câmpul de dată e cât ziua lui, nu cât rândul (18.09.2026): cu
   pictograma în loc de ziua browserului, `.camp-data { width: 100% }` îl întindea pe tot
   rândul, iar „până la" cădea pe al doilea rând, sub „Interval". */
.fl .fl-cand .camp-data { width: auto; }
.fl .fl-cand .camp-data input[type=text] { flex: 0 0 9em; }
.fl .fl-numar {
  margin-left: auto; color: var(--text-slab); font-size: var(--t-mic2);
  padding-bottom: var(--sp-1); font-variant-numeric: tabular-nums;
}
.fl-tot { margin: 0 0 var(--sp-3); font-size: var(--t-mic2); }

/* ══════════════════════════════════════════════════════════════════════════════════════
   9b. CĂUTAREA SE FACE LA COMANDĂ — lupa și nota
   ══════════════════════════════════════════════════════════════════════════════════════
   ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⛔⛔ CERINȚA (Nelu, 11.09.2026): „se vede că e o căutare de dat: butonul de lupă lângă║
   ║ căsuță, și cât timp ce scrie nu s-a căutat încă, se spune scurt că e de apăsat Enter."║
   ║                                                                                       ║
   ║ Amândouă se pun SINGURE, din `static/cautare.js` — deci nu există în produs o căutare ║
   ║ fără buton, oricâte ecrane s-ar mai scrie. Aici e doar înfățișarea lor.                ║
   ╠══════════════════════════════════════════════════════════════════════════════════════╣
   ║ ⛔⛔ CUTIA CĂUTĂRII E ÎNALTĂ CÂT PERECHEA, NIMIC MAI MULT (08.09.2026, corectură      ║
   ║ văzută de Nelu pe producție).                                                         ║
   ║                                                                                       ║
   ║ CE S-A VĂZUT: pe `/oferte/consumabile`, câmpul de căutare stătea la înălțimea         ║
   ║ ETICHETELOR „Marcă" și „Model", iar selectoarele lor rămâneau cu un rând mai jos.     ║
   ║ La fel pe `/utilizatori?tab=clienti`, față de „Caută în coloana". MĂSURAT în Chrome,  ║
   ║ înainte: câmpul cu 28–29 px mai sus decât primul select vecin, în PATRU locuri.       ║
   ║                                                                                       ║
   ║ CAUZA: nota stătea ÎN FLUX sub pereche, cu locul rezervat. Rândul de filtre aliniază  ║
   ║ la BAZĂ (`align-items: flex-end`), deci ce se așeza pe linia selectoarelor era        ║
   ║ capătul de jos al NOTEI — iar câmpul urca exact cu înălțimea ei. Cât timp eticheta    ║
   ║ ocupa un rând DEASUPRA câmpului, cele două se anulau din întâmplare; de când eticheta ║
   ║ se ascunde (`position: absolute`), rămâne doar împingerea.                             ║
   ╠══════════════════════════════════════════════════════════════════════════════════════╣
   ║ ⭐⭐ RĂSPUNSUL: nota IESE DIN FLUX. ⛔ NU se pune o etichetă goală și nu se rezervă un ║
   ║ spațiu „de aceeași înălțime" ca eticheta ascunsă — o cifră care trebuie ținută egală  ║
   ║ cu alta se desparte de ea la prima retușare a tipografiei. Scoasă din flux, cutia e   ║
   ║ înaltă exact cât perechea, iar alinierea la bază a rândului de filtre așază câmpul    ║
   ║ CHIAR pe linia selectoarelor, oricât ar scrie nota.                                   ║
   ║                                                                                       ║
   ║ ⭐ Și rezervarea locului („`min-height` + `visibility: hidden`", ca rândul să nu sară  ║
   ║ la fiecare literă) A DISPĂRUT ca grijă, nu ca purtare: ce nu e în flux nu poate       ║
   ║ împinge nimic, nici aprins, nici stins. O regulă mai puțin, nu una în plus.            ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
/* ⭐⭐ PERECHEA: CÂMPUL ȘI BUTONUL, UNUL LÂNGĂ ALTUL, LA ACEEAȘI ÎNĂLȚIME.
   ⛔ `align-items: stretch` NU e decor: cu `center`, butonul și câmpul ies de înălțimi
   diferite (au margini interioare diferite), iar perechea arată ca două lucruri lipite
   din greșeală. Întinse, ele au exact aceeași înălțime, oricare ar fi litera.
   ⛔ `position: relative` NU e decor nici el: e ancora notei de mai jos. Fără el, nota ar
   fi căzut față de prima rudă poziționată — adică față de altceva pe fiecare ecran.

   ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⛔⛔ `flex-wrap: nowrap` PE LARG — și e chiar reparația, nu o preferință.              ║
   ║                                                                                       ║
   ║ Cutia stă într-un înveliș care se strânge pe conținut (un `<span>` din rândul de      ║
   ║ filtre), deci LĂȚIMEA ei o dă conținutul. Cât timp nota era în flux, ea era cea mai   ║
   ║ lată piesă dinăuntru — deci lățimea perechii venea DE LA TEXTUL NOTEI. Măsurat: cutia ║
   ║ ieșea 354 px, iar butonul încăpea lângă câmp DIN ÎNTÂMPLARE. Scoasă nota din flux,    ║
   ║ cutia s-a strâns la 233 px și butonul a coborât sub câmp — pe ecranul de birou.       ║
   ║                                                                                       ║
   ║ ⭐ Cu `nowrap`, lățimea cerută e chiar CÂMPUL + BUTONUL: perechea își cere singură     ║
   ║ locul de care are nevoie, fără să depindă de câte litere scrie într-o notă care nici  ║
   ║ nu se vede. Pe telefon se pune `wrap` înapoi (vezi blocul de ecran mic), fiindcă      ║
   ║ acolo butonul TREBUIE să treacă sub câmp.                                              ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
.cauta-cutie {
  display: flex; align-items: stretch; gap: var(--sp-2);
  flex-wrap: nowrap; min-width: 0; position: relative;
}
.cauta-cutie input[type=search] { flex: 1 1 14rem; min-width: 0; }
/* ⛔ `white-space: nowrap`: cuvântul de pe buton nu se rupe niciodată în două rânduri.
   Cerința rundei, cuvânt cu cuvânt: „nu se întoarce la simbol și nu se taie textul". */
.cauta-buton {
  flex: 0 0 auto; white-space: nowrap;
  font-size: var(--t-mic2); line-height: 1; padding: var(--sp-1) var(--sp-3);
}
/* Nota atârnă SUB pereche, fără să facă parte din ea — vezi caseta de sus. */
.cauta-nota {
  position: absolute; top: 100%; left: 0; right: 0; margin-top: 2px;
  font-size: var(--t-xs); line-height: 1.2; color: var(--text-slab);
  pointer-events: none;
}

/* ══════════ CĂUTAREA PE ECRAN MIC — regulile ei stau AICI, nu în §19b ══════════
   ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⛔⛔ O INTEROGARE DE MEDIA NU BATE CASCADA (08.09.2026, plătit în chiar runda asta).   ║
   ║                                                                                       ║
   ║ Regulile de telefon ale căutării stăteau în blocul mare din §19b — care e scris       ║
   ║ ÎNAINTEA componentelor în fișier. La specificitate egală câștigă ULTIMA regulă, deci  ║
   ║ `.cauta-cutie input[type=search] { flex: 1 1 100% }` de acolo era anulată de regula   ║
   ║ de birou de mai sus. Era o regulă MOARTĂ, pe care o gardă o citea și o găsea în       ║
   ║ regulă; perechea se rupea pe două rânduri doar din `width: 100%` al butonului.        ║
   ║                                                                                       ║
   ║ ⭐ Aici, imediat după regulile de birou ale aceleiași componente, fiecare dintre ele   ║
   ║ chiar se aplică — și tot ce ține de căutare se citește într-un singur loc.             ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝
   ⭐⭐ PE TELEFON, BUTONUL TRECE SUB CÂMP, PE TOATĂ LĂȚIMEA (11.09.2026).
   ⛔ Măsurat la 390 px: din cei 342 px rămași după marginile paginii, câmpul are nevoie de
   cel puțin 220 (regula lui din rândul de filtre), iar butonul scris cere ~78 plus spațiul
   dintre ele — deci pe același rând câmpul ar fi coborât sub minimul lui și textul de fundal
   („cod, nume sau brand") s-ar fi tăiat. Răspunsul NU e întoarcerea la un simbol și nu e
   tăierea cuvântului: perechea se desface pe două rânduri, fiecare pe toată lățimea, iar
   butonul capătă ținta degetului fără să i se ceară o lățime anume. */
@media (max-width: 820px), (max-height: 560px) and (max-width: 1024px) {
  /* ⛔ `wrap` se cere ÎNAPOI: pe larg cutia e `nowrap`, ca lățimea perechii să vină de la
     câmp și buton, nu de la textul unei note care nici nu se vede. Fără rândul ăsta,
     „butonul trece sub câmp" n-ar mai avea unde. */
  .cauta-cutie { flex-wrap: wrap; }
  .cauta-cutie input[type=search] { flex: 1 1 100%; }
  .cauta-buton { width: 100%; min-height: var(--tinta); }
}

/* ⭐ ETICHETA SCOASĂ DIN OCHI, DAR NU DIN PAGINĂ (11.09.2026).
   Cu butonul scriind „Caută", eticheta de deasupra câmpului scria același cuvânt la doi
   centimetri distanță. ⛔ Nu se ȘTERGE: rămâne legată de câmp, deci cititorul de ecran
   spune în continuare ce se caută acolo. Vezi caseta din static/cautare.js.
   ⚠️ `clip-path`, nu `display: none`: ascunsă cu display, eticheta ar fi dispărut și
   pentru cititorul de ecran — adică exact ce nu trebuie. */
.doar-pentru-cititor {
  position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

/* ⭐⭐ RÂNDUL DE FILTRE CRESCUT DE COMPONENTA CAPULUI DE TABEL (11.09.2026).
   Vezi static/sortare.js: peste opt rânduri, orice tabel întreg în pagină capătă singur o
   căsuță de căutare și un dropdown cu CHIAR coloanele din antetul lui. ⛔ Formele nu se
   redefinesc — e același `.fl` de mai sus, ca ochiul să găsească aceleași controale în
   același loc pe listele care îl scriu de mână și pe cele care îl primesc. */
.fl[data-filtru-tabel] { margin-bottom: var(--sp-2); }

/* ⛔ `tr[hidden]` CU `!important`, și nu e pedanterie: `display` al unui rând e pus de
   foaia browserului (`tr { display: table-row }`), iar orice regulă de-a noastră care ar
   ținti `tbody tr` ar fi bătut atributul — adică filtrarea ar fi ascuns rândurile
   „cu succes", pe ecrane pe care ele rămâneau la vedere. */
tr[hidden] { display: none !important; }

/* Mesajul „n-am găsit nimic" — o singură celulă, pe toată lățimea. ⛔ NU e un rând stins:
   e chiar răspunsul la ce a tastat omul, deci se citește. */
tr.fl-gol td { color: var(--text-slab); font-style: italic; text-align: center;
  padding: var(--sp-4) var(--sp-2); }
.pgn {
  margin-top: var(--sp-2); color: var(--text-stins); font-size: var(--t-mic);
  display: flex; gap: var(--sp-3); align-items: baseline;
}

/* ══════════ CĂUTAREA DE PE HARTĂ — UN CONTROL, NU UN CARD (runda 18, 12.09.2026) ══════════
   ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⛔⛔ AICI, DUPĂ COMPONENTA CĂUTĂRII, ȘI NU ÎNAINTEA EI. Regulile de mai jos îngustează ║
   ║ perechea câmp+buton pentru locul ei de pe hartă (`.harta-cauta .cauta-cutie`). Scrise  ║
   ║ mai sus, ele ar fi fost ANULATE de regulile componentei — cascadă, la specificitate    ║
   ║ egală — iar foaia ar fi arătat completă la citit. Aceeași capcană plătită la 08.09     ║
   ║ (§19b înaintea componentelor) și la 11.09 (prima regulă `.cauta-cutie`).                ║
   ╠══════════════════════════════════════════════════════════════════════════════════════╣
   ║ ⛔ NU POARTĂ CLASA `plutitor`, ȘI NU E O SCĂPARE. `plutitor` coboară cardurile SUB     ║
   ║ hartă pe telefon, fiindcă un card acoperă tocmai ce vine să explice. Căsuța de căutat  ║
   ║ nu explică nimic: e un CONTROL, ca butoanele de zoom, iar pe telefon harta ia toată    ║
   ║ înălțimea rămasă sub bară — coborâtă sub ea, căutarea ar fi ieșit din ecran, adică o   ║
   ║ funcție pierdută, nu una mutată. Sub prag se STRÂNGE la un cuvânt, deci ocupă exact    ║
   ║ cât un buton de zoom: 44 px, ținta degetului, dată de regula temei pe `summary`.        ║
   ╠══════════════════════════════════════════════════════════════════════════════════════╣
   ║ ⭐ CULORILE VIN DIN GRUPA „CE STĂ PESTE DALE" (`--dale-*`), nu din cea a paginii:       ║
   ║ dalele rămân deschise în amândouă modurile, deci un câmp întunecat ar fi fost o pată   ║
   ║ neagră pe o hartă albă. ⚠️ `--dale-camp` și `--dale-buton` existau în foaie și nu erau ║
   ║ chemate de nimeni — erau scrise CHIAR pentru un câmp și un buton peste dale.            ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
/* ⭐⭐ LĂȚIMEA VINE DIN FÂȘIA DIN DREAPTA (runda 20, 12.09.2026), nu dintr-o cifră scrisă
   aici. De când căsuța stă în colțul din DREAPTA sus, lățimea ei nu mai e o chestiune de
   estetică: e chiar jumătatea împărțelii cu fereastra „Calc", care se deschide tot pe
   dreapta. Cealaltă jumătate o citește `static/calc.js` din ACELAȘI jeton. Vezi caseta lui
   `--fasia-dreapta` din §1.
   ⛔ Un pas mare mai puțin decât fâșia: în fâșie intră și marginea de 10 px pe care Leaflet
   o pune sub controalele lui, și aerul dintre căsuță și fereastra calculatorului. */
.harta-cauta { background: var(--dale-carte); color: var(--dale-text);
  width: calc(var(--fasia-dreapta) - var(--sp-5));
  border-radius: var(--rot); box-shadow: var(--umbra-plutire); padding: var(--sp-2); }
.harta-cauta-corp { display: block; }
/* Controlul strâns e NEVĂZUT pe birou: acolo căsuța încape întreagă. Sub prag, regula lui
   e mai jos, în blocul de ecran mic. */
.harta-cauta-strans { display: none; }
/* Lățimea perechii: a CÂMPULUI plus a butonului, nu una a ecranului — controlul stă într-un
   colț, deci nu poate lua toată dala.
   ⛔ ȘI NOTA COMPONENTEI INTRĂ ÎN FLUX AICI (de aceea `flex-wrap: wrap`), pe rândul ei — e
   chiar opusul reparației din 08.09, cu motivul ei. Acolo nota stătea în afara fluxului sub
   pereche, iar rândul de FILTRE, care aliniază la BAZĂ, urca din cauza ei câmpul cu 28 px.
   Aici nu e niciun rând de filtre: controlul stă singur peste dale, deci nimic nu se poate
   ridica. În schimb, lăsată absolută, nota ar fi căzut PESTE vestea de dedesubt — două
   propoziții suprapuse în colțul hărții. */
.harta-cauta .cauta-cutie { width: 100%; max-width: 100%; flex-wrap: wrap; }
.harta-cauta .cauta-nota { position: static; flex: 1 1 100%; color: var(--dale-text-stins); }
.harta-cauta input[type=search] { background: var(--dale-camp); color: var(--dale-text); }
.harta-cauta .cauta-buton { background: var(--dale-buton); color: var(--dale-text); }
/* ══════════ LISTA REZULTATELOR, SUB CĂSUȚĂ (runda 21, 12.09.2026) ══════════
   ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⭐⭐⭐ CERINȚA LUI NELU: „poate să găsească mai multe în urma căutării și acestea       ║
   ║ trebuie afișate sub căsuța de căutare. Deci textele de sub căsuța de căutare trebuie  ║
   ║ să afișeze toate locațiile găsite."                                                    ║
   ║                                                                                       ║
   ║ ⚠️ Asta RĂSTOARNĂ „să nu mai scrie nimic sub căsuță" de la runda 20 — acolo vorbea     ║
   ║ despre propozițiile de STARE („harta s-a mutat pe punct"), nu despre rezultate.        ║
   ║ Locul de sub căsuță e de azi al listei; propozițiile alea au dispărut din produs.      ║
   ╠══════════════════════════════════════════════════════════════════════════════════════╣
   ║ ⛔ ÎNĂLȚIMEA E MĂRGINITĂ, ȘI NU E UN MOFT: cinci rânduri de 44 px plus căsuța fac      ║
   ║ ~300 px în colțul unei hărți deschise tocmai ca să vezi harta. Peste prag lista        ║
   ║ derulează în ea însăși — ⚠️ iar controlul e deja izolat de rotița hărții                ║
   ║ (disableScrollPropagation, în MPSHarta.control), deci derularea listei NU face zoom.   ║
   ║ ⛔ Cifra e în `rem`, nu în `vh`: pe telefonul ținut pe lat înălțimea ferestrei e 390 px,║
   ║ iar un procent din ea ar fi lăsat listei două rânduri.                                 ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
.harta-cauta-lista { margin: var(--sp-1) 0 0; max-height: 15rem; overflow-y: auto; overflow-x: hidden; }
/* ⛔ ȚINTA DEGETULUI PE FIECARE RÂND — cerința rundei, spusă pe cifre. `min-height`, nu o
   înălțime fixă: o adresă lungă se rupe pe două rânduri și trebuie să încapă întreagă.
   ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⛔⛔ `white-space: normal` NU E DE PRISOS, ȘI A FOST PRINS CU OCHII PE ECRAN           ║
   ║ (12.09.2026, după ce proba din Chrome trecuse verde pe tot).                          ║
   ║                                                                                       ║
   ║ Rândul e un `<button>` — trebuie să fie, ca să se apese cu tastatura și să se anunțe  ║
   ║ singur cititorului de ecran. Dar tema spune, o dată pentru tot produsul, `button, .btn ║
   ║ { white-space: nowrap }`, fiindcă un buton obișnuit poartă un cuvânt sau două. Aici    ║
   ║ rândul poartă „Bulevardul Eroilor, Cotroceni, Sector 5, Bucharest, 050514, Romania":   ║
   ║ MĂSURAT, lista ieșea 418 px lată într-o cutie de 285, cu bară de derulare laterală și  ║
   ║ adresele tăiate la jumătate. `overflow-wrap: anywhere` de pe nume nu putea face nimic  ║
   ║ — `nowrap` interzice ruperea din capul locului.                                        ║
   ║ ⚠️ De aceea și `overflow-x: hidden` pe listă: derularea pe verticală o cere pe cea      ║
   ║ laterală (regula CSS), iar o bară orizontală într-un colț de hartă e o capcană.        ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
.harta-cauta-lista .hc-rand {
  display: flex; align-items: center; gap: var(--sp-2);
  width: 100%; min-height: var(--tinta); padding: var(--sp-1) var(--sp-2);
  border: 0; border-radius: var(--rot-mic); background: none; color: var(--dale-text);
  font: inherit; font-size: var(--t-mic); line-height: 1.35; text-align: left; cursor: pointer;
  white-space: normal;
}
.harta-cauta-lista .hc-rand:hover { background: var(--dale-buton); }
/* Rândul pe care STĂ harta acum. ⛔ Nu doar o vopsea: și o dungă în capăt, fiindcă pe dale
   un fond deschis peste alt fond deschis se pierde. */
.harta-cauta-lista .hc-rand.ales { background: var(--dale-buton); font-weight: 600;
  box-shadow: inset 2px 0 0 var(--pin-cautat); }
.harta-cauta-lista .hc-nume { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; }
/* ⭐⭐ SEMNUL DIN CAPUL RÂNDULUI — „se deosebește limpede ce e punct de-al lui și ce e adresă
   găsită". ⛔ ACELEAȘI DOUĂ DESENE CA PE HARTĂ: punctul de lucru e un cerc (ca `.pin`),
   adresa găsită e o picătură în culoarea pinului de căutare (ca `.pin-cautat`) — deci rândul
   din listă și pinul de pe hartă spun același lucru, fără niciun cuvânt în plus.
   ⚠️ Cuvântul EXISTĂ totuși, ascuns vizual (`doar-pentru-cititor`): un semn mut nu spune
   nimic cui ascultă pagina. */
.harta-cauta-lista .hc-semn { flex: 0 0 auto; width: 13px; height: 13px; }
.harta-cauta-lista .hc-semn-punct { border-radius: 50%; background: var(--accent); }
.harta-cauta-lista .hc-semn-adresa { border-radius: 50% 50% 50% 0; transform: rotate(-45deg);
  background: var(--pin-cautat); }
/* ⭐⭐ CELE DOUĂ FELURI DE VESTE SE DEOSEBESC PE ECRAN, nu doar în cuvinte. `intreb` (se
   caută / „primele N") e stins: nu cere nimic de la om. `neintrebat` poartă culoarea de
   avertisment, fiindcă acolo CHIAR e ceva de reparat — ori serviciul nu e configurat, ori
   n-a răspuns. ⛔ Nu se poate lăsa pe text: un om care se uită la hartă citește culoarea
   înainte de propoziție.
   ⚠️ Aici erau patru clase. `gasit` și `negasit` au PLECAT cu propozițiile lor (runda 21):
   ce s-a găsit se vede în listă, iar „n-am găsit" e de azi tăcere — hotărârea lui Nelu. */
.harta-cauta-veste { margin: var(--sp-1) 0 0; font-size: var(--t-mic); line-height: 1.35; }
.harta-cauta-veste:first-child { margin-top: 0; }
/* ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⛔⛔ RÂNDUL „PRIMELE {n}" RĂMÂNE LA VEDERE CÂND LISTA DERULEAZĂ — prins cu ochii pe    ║
   ║ ecran (12.09.2026), nu de vreo probă.                                                 ║
   ║                                                                                       ║
   ║ Cu cinci adrese lungi (fiecare pe două rânduri) lista trece de cele 15 rem ale ei și  ║
   ║ derulează; rândul care spune „primele 5 — serviciul poate avea mai multe" e ULTIMUL,  ║
   ║ deci cădea sub marginea de jos. Adică exact jumătatea cerută de Nelu („spune câte      ║
   ║ arăți ȘI ce faci cu restul") se vedea numai dacă derulai după ea.                      ║
   ║ ⚠️ Fondul e `--dale-camp`, OPAC: `--dale-carte` e alb 94 %, iar rândurile care         ║
   ║ derulează pe sub s-ar fi văzut prin propoziție.                                        ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝ */
.harta-cauta-lista .harta-cauta-veste:last-child {
  position: sticky; bottom: 0; background: var(--dale-camp);
  padding: var(--sp-1) 0 0; margin-top: 0;
}
.harta-cauta-veste.intreb { color: var(--dale-text-stins); }
.harta-cauta-veste.neintrebat { color: var(--dale-avert); font-weight: 600; }

/* ⭐⭐ PINUL DE CĂUTARE — O PICĂTURĂ, NU UN CERC (runda 18).
   ⛔ ALT DESEN decât pinii punctelor de lucru, cerut anume: ei sunt cercuri cu numărul de
   echipamente înăuntru (`.pin`) sau bulina albastră a locului fără colector
   (`.pin-client`). Un al doilea cerc, fie și de altă culoare, s-ar fi citit ca o a șasea
   stare — iar el nu e nicio stare: e răspunsul la ce s-a scris în căsuță, și pleacă la
   golirea ei. Forma e cea a pinului care se trage cu mâna (`.pin-pus`), mai mare.
   ⚠️ Desenat din CSS, nu din imaginea implicită a bibliotecii: noi vendorăm doar leaflet.js
   și leaflet.css, deci imaginea aceea ar fi 404 și pinul ar apărea ca o iconiță ruptă. */
.pin-cautat { width: 26px; height: 26px; border-radius: 50% 50% 50% 0;
  transform: rotate(-45deg); background: var(--pin-cautat);
  border: 2px solid var(--pe-pin); box-shadow: var(--umbra-pin); }

@media (max-width: 820px), (max-height: 560px) and (max-width: 1024px) {
  /* ⭐⭐ SUB PRAG CĂSUȚA SE STRÂNGE LA UN CUVÂNT. Măsurat: la 390 px, perechea deschisă plus
     vestea iau ~120 px pe înălțime în colțul hărții — pe un ecran deschis tocmai ca să vezi
     harta. Strânsă, e un buton cât cele de zoom.
     ⛔ `<details>` GOL plus `:has()`, aceeași mecanică ca butonul de filtre: căsuța rămâne
     scrisă O SINGURĂ DATĂ în șablon, iar niciun script nu hotărăște nimic la nicio lățime. */
  /* ⛔ `width: auto` CERUT ÎNAPOI: pe birou căsuța ia fâșia din dreapta, ca fereastra
     „Calc" să aibă unde se deschide fără s-o acopere. Sub prag nu există fâșie de împărțit
     (calculatorul ia tot ecranul, hotărârea rundei 15), iar o lățime fixă ar fi întins
     controlul STRÂNS — adică un buton de 320 px cu cuvântul „Caută" în mijloc. */
  .harta-cauta { padding: 0; background: none; box-shadow: none; width: auto; }
  .harta-cauta-strans { display: block; }
  /* ⛔⛔ FĂRĂ `min-height` AICI, ȘI E O REGULĂ ȘTEARSĂ, NU UITATĂ (12.09.2026).
     Prima scriere o avea — și sabotajul M6, care o scotea, N-A ÎNROȘIT PROBA: controlul a
     rămas 44 px înalt fiindcă `summary` e DEJA în lista de controale a temei, câteva rânduri
     mai sus. Adică era o regulă moartă, dintre cele pe care o gardă le citește și le găsește
     în regulă. ⭐ Înălțimea rămâne unde e scrisă o dată, pentru toate controalele produsului.
     ⚠️ `min-width` RĂMÂNE: lista generală n-o dă decât bifelor, iar aici ea apără ținta
     degetului în ziua în care pe control ar scrie un cuvânt mai scurt. */
  .harta-cauta-strans > summary {
    list-style: none; cursor: pointer; user-select: none;
    display: flex; align-items: center; justify-content: center;
    min-width: var(--tinta); padding: 0 var(--sp-3);
    background: var(--dale-carte); color: var(--dale-text);
    border-radius: var(--rot); box-shadow: var(--umbra-plutire);
    font-size: var(--t-mic2); font-weight: 600; white-space: nowrap;
  }
  .harta-cauta-strans > summary::-webkit-details-marker { display: none; }
  /* Deschis, cuvântul pleacă și rămâne semnul de închidere: „Caută" scris de două ori la
     doi centimetri (pe control și pe butonul componentei) e chiar risipa interzisă de
     bugetul de cuvinte. ⛔ Semnul de închidere trebuie să EXISTE: o acoperire fără cale de
     închidere e o capcană — aceeași regulă ca la fereastra lui „Calc". */
  .harta-cauta-strans[open] > summary > span { display: none; }
  .harta-cauta-strans[open] > summary::after { content: "×"; font-size: var(--t-mare); line-height: 1; }
  .harta-cauta:has(.harta-cauta-strans:not([open])) .harta-cauta-corp { display: none; }
  .harta-cauta:has(.harta-cauta-strans[open]) .harta-cauta-corp {
    margin-top: var(--sp-2); padding: var(--sp-2);
    background: var(--dale-carte); border-radius: var(--rot); box-shadow: var(--umbra-plutire);
  }
  /* ⛔ LĂȚIMEA SE MĂSOARĂ DIN ECRAN, nu din litere: la 390 px un câmp de 19rem ar fi ieșit
     prin marginea din dreapta, adică derulare laterală pe pagină. Marginea de 10 px a
     controalelor Leaflet se scade de două ori, ca să rămână aer și în dreapta. */
  .harta-cauta .cauta-cutie { width: calc(100vw - 4 * var(--sp-5)); max-width: 19rem; }
  /* ╔══════════════════════════════════════════════════════════════════════════════════╗
     ║ ⛔⛔ LISTA E MAI SCURTĂ SUB PRAG, ȘI CIFRA E MĂSURATĂ, NU ALEASĂ (12.09.2026).     ║
     ║                                                                                   ║
     ║ Prima scriere punea doar `9rem` — și proba din Chrome a înroșit-o. Măsurat la     ║
     ║ 844×390 (telefonul ținut pe LAT): harta începe la 97 px (sub bară și sub rândul   ║
     ║ de filtre) și se termină la 390, deci are 293 px cu totul; căsuța deschisă începe ║
     ║ la 107 și, cu o listă de 132 px, ajungea la 402 — adică 12 px DINCOLO de marginea ║
     ║ de jos a ecranului. Rezultatele găsite nu se puteau citi.                          ║
     ║                                                                                   ║
     ║ ⭐ DE ACEEA A DOUA MĂRGINIRE E O PROPORȚIE, NU UN NUMĂR DE PIXELI SCĂZUT dintr-o  ║
     ║ înălțime: un `calc(100vh - 290px)` ar fi codificat înălțimea de AZI a barei și a  ║
     ║ filtrelor, iar la primul rând adăugat acolo s-ar fi rupt tăcut. `25vh` se mută cu ║
     ║ ecranul: la 390 px înălțime dă 97 px (căsuța se termină la 367, cu 23 px de aer), ║
     ║ la 844 dă 211, iar acolo câștigă cele 9 rem.                                       ║
     ╚══════════════════════════════════════════════════════════════════════════════════╝ */
  .harta-cauta-lista { max-height: min(9rem, 25vh); }
  /* ╔══════════════════════════════════════════════════════════════════════════════════╗
     ║ ⛔⛔ ȘI BALONUL NU POATE FI MAI LAT DE JUMĂTATE DE ECRAN — tot o măsurătoare       ║
     ║ (12.09.2026, 390×844): balonul pinului de căutare ieșea prin marginea din STÂNGA. ║
     ║                                                                                   ║
     ║ Cauza e cea din 27.08, în forma ei de telefon: tooltipurile Leaflet n-au auto-pan.║
     ║ Cu `direction: auto` biblioteca îl așază LATERAL față de pin, iar pinul unei      ║
     ║ adrese găsite cade chiar în MIJLOCUL hărții — deci un balon de 42ch (~294 px) pe  ║
     ║ un ecran de 390 începe la −99 px. Mărginit la jumătate de ecran, el încape        ║
     ║ oricare dintre cele două laturi ar alege biblioteca.                               ║
     ║ ⚠️ Regula e a BALONULUI, deci ține și pentru cel al unui client: e aceeași         ║
     ║ componentă, cerința lui Nelu („prin aceeași componentă"), deci și aceeași reparație.║
     ╠══════════════════════════════════════════════════════════════════════════════════╣
     ║ ⛔⛔ TREI CLASE ÎN SELECTOR, ȘI NU E UN MOFT — e chiar capcana cascadei plătită de ║
     ║ două ori în proiect. Foaia temei se încarcă ÎNAINTEA stilului ecranelor, iar      ║
     ║ `max-width: 42ch` al balonului stă în stilul hărții (harta_sablon.go). La          ║
     ║ specificitate egală câștigă cel de-al doilea, iar o interogare de media NU adaugă ║
     ║ specificitate: scrisă `.leaflet-tooltip.balon`, regula de aici ar fi fost citită  ║
     ║ de om ca aplicată și ANULATĂ tăcut pe ecran. `.leaflet-pane` e părintele real al  ║
     ║ tooltipului (panoul lui Leaflet), deci selectorul e adevărat, nu umflat.          ║
     ╚══════════════════════════════════════════════════════════════════════════════════╝ */
  .leaflet-pane .leaflet-tooltip.balon { max-width: calc(50vw - var(--sp-5)); }
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   18. GRAFICE
   ══════════════════════════════════════════════════════════════════════════════════════
   ⛔ Stilul e HOTĂRÂT, nu ales de fiecare grafic: linie de 2 px, estimarea punctată,
   pragul ca linie, paletă fixă, fără umbre, fără gradient, fără animații, cifre tabulare
   pe axe. Culorile ies din `--grafic-*`; desenul îl face `grafic.js`, care le CITEȘTE de
   aici — deci un grafic nu poate ajunge în altă paletă decât restul produsului, iar modul
   întunecat se moștenește fără o a doua listă de culori. */
.grafic { position: relative; background: var(--grafic-fond); }
.grafic, .grafic * { font-variant-numeric: tabular-nums; }
/* uPlot desenează seriile pe canvas, dar axele, legenda și cursorul sunt DOM. */
.grafic .u-title { font-size: var(--t-mic2); font-weight: 600; color: var(--text); }
.grafic .u-legend { font-size: var(--t-mic); color: var(--text-slab); margin-top: var(--sp-2); }
.grafic .u-legend .u-marker { border-radius: 2px; }
.grafic .u-legend th { background: none; border: 0; padding: 0 var(--sp-2) 0 0; text-transform: none; letter-spacing: 0; font-weight: 600; }
.grafic .u-legend td { border: 0; padding: 0 var(--sp-3) 0 0; }
.grafic .u-legend tr:nth-child(even) td { background: none; }
.grafic .u-select { background: var(--accent-slab); }
.grafic .u-cursor-x, .grafic .u-cursor-y { border-color: var(--linie); }
/* Legenda scrisă de noi, sub grafic: aceleași forme ca pastilele de stare. */
.grafic-legenda { display: flex; gap: var(--sp-4); flex-wrap: wrap; font-size: var(--t-mic); color: var(--text-slab); margin-top: var(--sp-2); }
.grafic-legenda span { display: inline-flex; align-items: center; gap: var(--sp-1); }
.grafic-legenda i { display: inline-block; width: 18px; height: 0; border-top-width: 2px; border-top-style: solid; }
.grafic-legenda i.masurat { border-top-color: var(--grafic-1); }
.grafic-legenda i.estimat { border-top-color: var(--grafic-1); border-top-style: dotted; }
.grafic-legenda i.prag { border-top-color: var(--rau-semn); }
.grafic-legenda i.a-doua { border-top-color: var(--grafic-2); }

/* ══════════════════════════════════════════════════════════════════════════════════════
   19b. ECRANUL MIC — TOATE REGULILE DE TELEFON ȘI TABLETĂ, ÎNTR-UN SINGUR LOC
   ══════════════════════════════════════════════════════════════════════════════════════
   ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⛔⛔ REGULA E A TEMEI, NU A ECRANELOR (hotărârea lui Nelu, 08.09.2026).               ║
   ║                                                                                       ║
   ║ Până azi harta își scria singură trei interogări de media, iar cardul de curs își     ║
   ║ hotăra locul dintr-un `matchMedia('640px')` în JavaScript — un AL PATRULEA prag, pe   ║
   ║ care garda de lățime nici nu-l putea vedea, fiindcă ea citește CSS. Urmarea, măsurată:║
   ║ pe o tabletă de 768 px cardul de curs plutea peste hartă, iar la rotirea telefonului  ║
   ║ rămânea unde fusese pus la încărcare — hotărârea se lua o dată, la `load`.            ║
   ║                                                                                       ║
   ║ De azi: **un singur prag (820 px), într-un singur fișier**, iar garda cere ca NICIUN  ║
   ║ ecran să nu conțină vreo interogare de media. Un ecran care are nevoie de altceva pe  ║
   ║ telefon cere o REGULĂ aici, cu numele ei — nu o excepție la el acasă.                 ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝

   ⚠️ Blocul de mai jos e cel de LĂȚIME. Ce ține de un ecran mic pe ORICARE latură —
   plutitorii și harta — stă în §19c, mai jos, fiindcă un telefon ținut pe lat are 844 px
   lățime și n-ar fi intrat niciodată aici. */

@media (max-width: 820px) {
  /* ---------- CELE PATRU CIFRE SE AȘAZĂ CÂTE ÎNCAP ----------
     ⛔ AICI, ȘI NUMAI AICI, `auto-fit` E RĂSPUNSUL BUN: sub prag n-a mai rămas loc de
     patru, iar între 2 și 1 alege chiar lățimea ecranului — 2 pe o tabletă în picioare
     (768: carduri de 359 px), 1 pe telefon (390: 351 px). Peste prag el ar fi ales
     uneori TREI, adică trei carduri sus și al patrulea singur dedesubt; vezi caseta de
     la `.kpi`, secțiunea 14b. */
  .kpi { grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); }

  /* ---------- TABELUL DEVINE CARD ----------
     ╔══════════════════════════════════════════════════════════════════════════════════╗
     ║ ⛔ SCRIS O SINGURĂ DATĂ, AICI — niciun ecran nu-l cere și niciunul nu-l poate      ║
     ║ ocoli. Cele 71 de tabele cu antet îl moștenesc, inclusiv cel scris mâine.          ║
     ║                                                                                   ║
     ║ ⭐ ETICHETELE VIN DIN ANTETUL PROPRIU AL TABELULUI: `static/sortare.js` scrie pe   ║
     ║ fiecare celulă `data-et` cu textul coloanei ei, și marchează rândul de antet cu    ║
     ║ `data-antet`. Acolo, fiindcă acolo se făceau deja EXACT aceleași patru citiri      ║
     ║ (care rând e antetul, ce scrie într-o celulă, a câta celulă e coloana n, care      ║
     ║ rânduri atârnă) pentru sortare și pentru căutare — scrise a treia oară, cele trei  ║
     ║ ar fi încetat să fie de acord ce scrie în aceeași celulă.                          ║
     ║ ⛔ Fără JS, tabelul rămâne tabel și derulează, ca până azi: se pierde forma, nu     ║
     ║ datele.                                                                            ║
     ╚══════════════════════════════════════════════════════════════════════════════════╝ */
  .sx:has(table[data-card]) { overflow-x: visible; border-radius: 0; }
  table[data-card] { border: 0; display: block; background: none; }
  table[data-card] > thead, table[data-card] tr[data-antet] { display: none; }
  table[data-card] > tbody, table[data-card] > tfoot { display: block; }
  table[data-card] > * > tr {
    display: block; background: var(--fond-card);
    border: 1px solid var(--linie); border-radius: var(--rot-mare);
    padding: var(--sp-2) var(--sp-3); margin-bottom: var(--sp-2);
  }
  /* Zebra n-are ce căuta pe carduri: ea despărțea RÂNDURI lipite, iar astea sunt deja
     despărțite de chenar. Lăsată, ar fi făcut jumătate din carduri să pară stinse. */
  table[data-card] > tbody > tr:nth-child(even) > td,
  table[data-card] > tbody > tr:hover > td { background: none; }
  table[data-card] > * > tr > td {
    display: flex; justify-content: space-between; align-items: baseline; gap: var(--sp-3);
    border: 0; padding: var(--sp-1) 0; text-align: left;
    /* ⛔ Lipirea coloanei de acțiuni se STINGE: nu mai există derulare de care s-o lipim,
       iar un `sticky` rămas ar fi scos ultima celulă din cardul ei. */
    position: static; box-shadow: none;
  }
  table[data-card] > * > tr > td::before {
    content: attr(data-et); color: var(--text-slab); font-size: var(--t-mic2);
    flex: 0 0 auto; max-width: 45%; text-align: left;
  }
  /* ⛔⛔ CELULA-CARD NU ARE VOIE SĂ ÎMPINGĂ PAGINA (măsurat 13.09.2026, runda 11).
     Celula e `flex`, iar un element de flex are implicit `min-width: auto` — adică refuză
     să se strângă sub lățimea conținutului lui. Un buton („Stabilește tariful", 114 px)
     lipit de eticheta lui ieșea din card la 420 px pe un ecran de 371, iar PAGINA ÎNTREAGĂ
     căpăta derulare orizontală. Măsurat pe fișa contractului, dar regula e a TUTUROR
     tabelelor prefăcute în carduri: ce nu încape se rupe pe rândul următor, nu lățește.
     ⚠️ `min-width: 0` singur nu ajunge: fără rupere, un cuvânt lung tot nu se strânge. */
  table[data-card] > * > tr > td > * { min-width: 0; overflow-wrap: anywhere; }
  table[data-card] > * > tr > td { flex-wrap: wrap; }
  /* Prima celulă e NUMELE lucrului: fără etichetă, mai mare, pe rând propriu. */
  table[data-card] > * > tr > td:first-child {
    display: block; font-weight: 600; font-size: var(--t-mare);
    padding-bottom: var(--sp-1); margin-bottom: var(--sp-1);
    border-bottom: 1px solid var(--linie-slaba);
  }
  table[data-card] > * > tr > td:first-child::before { content: none; }
  /* Acțiunile, pe rândul lor, întregi — cerința: „acțiunile pe rând propriu". */
  table[data-card] > * > tr > td.actiuni, table[data-card] > * > tr > td:last-child {
    display: flex; flex-wrap: wrap; gap: var(--sp-2); justify-content: flex-start;
    padding-top: var(--sp-2); margin-top: var(--sp-1);
    border-top: 1px solid var(--linie-slaba);
  }
  table[data-card] > * > tr > td:last-child::before { content: none; }
  /* ⛔⛔ COLOANA DE ACȚIUNI LIPITĂ NU RĂMÂNE LIPITĂ ÎN CARD (15.09.2026, văzut pe captura de 390 px a
     contractului). Regula de la „ACȚIUNILE NU IES NICIODATĂ DIN ECRAN" (§11) se recunoaște din
     FORMĂ — ultima coloană cu antet gol — ori din clasa `.actiuni`, iar varianta de zebră a clasei
     (`.sx table tbody tr:nth-child(even) td.actiuni`, 0,3,4) bate regula cardului de mai sus (0,2,4):
     celula cu săgeata își păstra fondul de zebră și umbra, iar în cardul al doilea apărea un
     dreptunghi gri sub săgeată. ⚠️ Prima reparație prindea doar forma cu antet gol și n-a mușcat —
     antetul fără nume nu mai e `:empty` după componenta de tabel; a arătat-o captura, nu ochiul.
     Perechea de aici poartă `[data-card]` și `:nth-child(n)` (0,4,3 / 0,4,4), deci câștigă doar pe
     tabelele prefăcute în carduri. ⚠️ Și a doua formă a pierdut, măsurat în Chrome: varianta cu
     `:has(...)` a regulii lipite cântărește (0,4,4), iar pe zebră (0,5,5). De aceea selectorul al
     treilea repetă exact forma ei, plus `[data-card]` și `:nth-child(n)`: (0,6,4).
     Proba: `_dev-probe-contract-ecran.js`, „celula săgeții". */
  .sx table[data-card] > * > tr:nth-child(n) > td.actiuni,
  .sx table[data-card] > * > tr:nth-child(n) > :last-child,
  .sx table[data-card]:has(tr > th:last-child:empty) > * > tr:nth-child(n) > :last-child {
    position: static; background: none; box-shadow: none;
  }
  /* O celulă goală n-are ce arăta pe telefon: eticheta ei singură ar fi un rând care
     spune „Telefon —". ⚠️ Se ascunde CELULA, nu coloana: pe alt rând ea are conținut. */
  table[data-card] > * > tr > td[data-gol] { display: none; }
  /* ⛔ ȘI COLOANELE DE CONTEXT RĂMÂN ASCUNSE ÎN CARD. Regula lor e mai sus (`th.ctx`), dar
     selectorul cardului e mai specific și i-o anula — văzut pe ecran: cardul unei persoane
     scria din nou ID, funcția, telefonul și locația, adică tot ce hotărârea le scosese.
     ⚠️ Nu e o economie de spațiu vertical (în card el e ieftin), e chiar hotărârea din
     08.09: pe telefon rămâne ce se caută printre rânduri — numele, starea, cifra și
     acțiunea. Restul e la o apăsare, pe fișa lucrului. */
  table[data-card] > * > tr > td.ctx, table[data-card] > * > tr > th.ctx { display: none; }
  /* Rândul de filtre al listei rămâne, dar pe o coloană. */
  .fl { flex-direction: column; align-items: stretch; }
  .fl input, .fl select { width: 100%; }

  /* ---------- HARTA, LA LĂȚIME MICĂ ----------
     Doar ce ține chiar de lățime. Așezarea hărții a trecut în §19c: ea se schimbă și când
     ecranul e SCUND, nu doar când e îngust. */
  .urg { max-width: 18ch; }
  .filtre { padding: var(--sp-2) var(--sp-3); }
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   19c. ECRANUL MIC PE ORICARE LATURĂ — CE PLUTEȘTE, ȘI HARTA
   ══════════════════════════════════════════════════════════════════════════════════════
   ╔══════════════════════════════════════════════════════════════════════════════════════╗
   ║ ⛔⛔ DE CE E UN AL DOILEA BLOC, ȘI NU ÎNCĂ NIȘTE RÂNDURI ÎN §19b.                     ║
   ║                                                                                       ║
   ║ §19b întreabă „e ecranul ÎNGUST?". Regulile de aici răspund la altă întrebare: „mai   ║
   ║ e loc pentru ceva care plutește?". La 844×390 — un telefon ținut pe lat — prima       ║
   ║ întrebare zice NU (844 > 820) și a doua zice DA, e o problemă. Măsurat în seara lui   ║
   ║ 08.09: bara plus filtrele luau 156 px din 390, panoul de 452 px plutea peste hartă,   ║
   ║ iar legenda și cursul rămâneau controale Leaflet, adică tot peste hartă.              ║
   ║                                                                                       ║
   ║ ⚠️ Nu sunt praguri „în plus": sunt aceeași hotărâre („ce plutește coboară") pusă pe   ║
   ║ măsura care o cere. Cele două cifre stau în :root, lângă --prag-telefon.              ║
   ╚══════════════════════════════════════════════════════════════════════════════════════╝

   ---------- CE PLUTEȘTE PE BIROU NU SE AȘAZĂ ÎNAINTEA CONȚINUTULUI PE TELEFON ----------
   ⭐ `.plutitor` — un element care pe birou stă PESTE conținut (cardul de curs în colțul
   hărții, legenda, panoul punctului de lucru). Sub prag el coboară în curgerea paginii,
   DUPĂ conținutul principal. ⛔ Nu se ascunde și nu se strânge automat: ce plutește poartă
   informație, iar un panou care dispare pe telefon e o funcție pierdută, nu una mutată. */

@media (max-width: 820px), (max-height: 560px) and (max-width: 1024px) {
  /* ---------- ȚINTA DEGETULUI ----------
     Lista e a CONTROALELOR, nu a tuturor legăturilor: o legătură dintr-un paragraf de
     proză nu e un buton, iar 44 px pe ea ar fi rupt rândul de text în două.
     ⛔ AICI, ȘI NU ÎN §19b: degetul e o problemă a ECRANULUI PE CARE ÎL ATINGI, iar un
     telefon ținut pe lat (844×390) e tot un telefon — cu regula pe lățime, butoanele
     hărții rămâneau la 26 px exact pe ecranul unde harta ocupă tot. */
  .btn, a.btn, button, summary, select,
  input[type="submit"], input[type="button"], input[type="checkbox"], input[type="radio"],
  /* ⭐⭐ `.nav-loc a.navig` ADĂUGAT LA RUNDA 22 (12.09.2026), cerut de Nelu odată cu
     balonul care se deschide la apăsare: „ținta de 44 px pe cele două butoane".
     ⛔ „Copiază locația" o avea deja — e un `button`. „Navighează ↗" era atunci o LEGĂTURĂ,
     deci trebuia NUMITĂ aici. De la runda balonului (14.09.2026) e buton gol mic, ca vecinul
     lui (`a.btn`, deja pe listă), deci rândul ei a rămas doar ca plasă: dacă cineva îi scoate
     clasa de buton, ținta degetului nu pleacă odată cu ea. */
  /* ⭐ `.actiuni-form a` ADĂUGAT LA RUNDA UNIFORMIZĂRII (14.09.2026): ținta rămâne pe toate
     cele trei forme, iar legătura e o formă de control acolo unde stă ca un control — în
     rândul de acțiuni al unui tabel, al unui card, al unui formular. */
  .pg-act, .filtru, .comutator a, .taburi a, .cap-sort, .nav-loc a.navig,
  td.actiuni a, td.actiuni button, .actiuni-form a, .actiuni-form button, .butoane a, .butoane button {
    min-height: var(--tinta);
  }
  /* Un `<a>` e inline: fără `inline-flex`, `min-height` nu-l atinge deloc. */
  a.btn, .pg-act, .filtru, .comutator a, .taburi a, td.actiuni a, .actiuni-form a, .butoane a, .nav-loc a.navig {
    display: inline-flex; align-items: center;
  }
  input[type="checkbox"], input[type="radio"] { min-width: var(--tinta); }
  /* Butoanele bibliotecii de hartă sunt tot lucruri pe care le apeși cu degetul: 26 px
     implicit, prea mici. Le atingem noi — pagina e a noastră. */
  .leaflet-touch .leaflet-bar a, .leaflet-bar a {
    width: var(--tinta); height: var(--tinta); line-height: var(--tinta);
  }

  /* ---------- FILTRELE SE STRÂNG ÎNTR-UN BUTON ----------
     ⛔ Măsurat: pe /dashboard la 390 px, rândul de filtre se rupea pe TREI rânduri și lua
     126 px — al doilea consumator de ecran după bară. Acum e un buton care spune câte
     filtre sunt aprinse; apăsat, le deschide.
     ⚠️ Aceeași mecanică cu bara: `<details>` GOL plus `:has()`, ca filtrele să rămână
     scrise O SINGURĂ DATĂ și să fie inline pe birou.
     ⛔⛔ ȘI ASTA A TRECUT DIN §19b AICI (08.09 seara): pe PEISAJ (844×390) filtrele nu se
     strângeau deloc — 88 px măsurați din 390, adică aproape un sfert din ecran, pe pagina
     deschisă tocmai ca să vezi harta. Înălțimea e cea care lipsește pe un telefon ținut pe
     lat, iar regula care o apără n-avea voie să atârne de lățime. */
  .filtre-buton { display: block; flex: 0 0 auto; background: var(--fond-card);
                  border-bottom: 1px solid var(--linie); }
  .filtre-buton > summary {
    list-style: none; cursor: pointer; user-select: none;
    display: flex; align-items: center; gap: var(--sp-2);
    min-height: var(--tinta); padding: 0 var(--sp-3);
    font-size: var(--t-mic2); font-weight: 600; color: var(--text-slab);
  }
  .filtre-buton > summary::-webkit-details-marker { display: none; }
  .filtre-buton > summary::after { content: "▾"; margin-left: auto; opacity: .65; }
  .filtre-buton[open] > summary::after { content: "▴"; }
  .zona-filtre:has(.filtre-buton:not([open])) .filtre { display: none; }

  .plutitor {
    position: static; inset: auto; width: 100%; max-width: none;
    border-radius: 0; box-shadow: none;
    border-top: 1px solid var(--linie); background: var(--fond-card);
  }
  /* Într-o coloană flex, `order` îl duce după conținut chiar dacă în markup stă înaintea
     lui — altfel fiecare ecran ar fi trebuit să-și rescrie ordinea din HTML. */
  .plutitor { order: 90; }

  /* ---------- HARTA ----------
     `.zona` devine o coloană: harta primește o înălțime GARANTATĂ, iar panoul punctului de
     lucru coboară sub ea.
     ⛔ Pagina redevine derulabilă — vezi caseta lui `--inaltime-ecran`. */
  :root { --inaltime-ecran: auto; }
  body { min-height: 100%; }

  .zona { display: flex; flex-direction: column; min-height: 0; }
  /* ╔══════════════════════════════════════════════════════════════════════════════════╗
     ║ ⛔⛔ HARTA IA CE A RĂMAS SUB BARĂ ȘI FILTRE, NU UN PROCENT DIN FEREASTRĂ.          ║
     ║ (Nelu, 08.09 seara, pe telefonul lui: „pe peisaj harta e o fâșie".)                ║
     ║                                                                                   ║
     ║ Măsurat înainte, la 844×390: bară 69 + filtre 88 = 157 px, iar harta primea 45 %  ║
     ║ din fereastră = **176 px**, adică 55 % din cei 321 rămași sub bară. Un procent din ║
     ║ fereastră nu știe nimic despre ce stă deasupra lui: pe portret 45 % era mai puțin  ║
     ║ decât ce rămăsese liber (deci se pierdea ecran), iar pe peisaj era o fâșie.        ║
     ║                                                                                   ║
     ║ ⭐ `--harta-loc` e SCRIS DE COMPONENTĂ (`static/harta-masura.js`), din ce a rămas  ║
     ║ măsurat sub tot ce stă deasupra hărții — nu din bară plus filtre numite pe nume:   ║
     ║ o cifră scrisă aici s-ar fi despărțit de bară la primul rând în plus, tăcut.       ║
     ║ ⚠️ Rezerva de 45dvh rămâne pentru pagina FĂRĂ JavaScript: acolo harta nu e         ║
     ║ oricum o hartă (Leaflet nu rulează), dar cutia nu are voie să fie zero.            ║
     ║ ⛔ Regula e a TEMEI, iar componenta scrie cifra pe FIECARE hartă pe care o          ║
     ║ urmărește: care hartă umple ecranul se hotărăște AICI, prin selector. Cardul de    ║
     ║ 260 px de pe fișa clientului o primește și el, și n-o citește nimeni.              ║
     ╚══════════════════════════════════════════════════════════════════════════════════╝
     ⚠️ `dvh` DUPĂ `vh`, nu în loc: pe telefon `vh` se socotește cu bara de adresă ASCUNSĂ,
     deci 45vh e mai mult decât 45% din ce se vede. `dvh` e înălțimea de acum, cea
     adevărată. Rândul cu `vh` rămâne ca rezervă pentru un browser care nu cunoaște
     unitatea — el sare peste declarația pe care n-o înțelege. */
  /* ╔══════════════════════════════════════════════════════════════════════════════════╗
     ║ ⛔⛔ `relative`, NU `static` — ȘI E UN DEFECT REPARAT, prins în Chrome (08.09 seara).║
     ║ Leaflet îi scrie containerului `style.position = "relative"` DIRECT PE ELEMENT     ║
     ║ dacă îl găsește `static` la construcție (ca panourile lui absolute să aibă de ce   ║
     ║ se agăța). Un stil inline bate orice foaie: harta încărcată întâi pe telefon       ║
     ║ rămânea `relative` și pe birou, unde ecranul o vrea `absolute; inset: 0` — deci    ║
     ║ un bloc obișnuit fără înălțime. MĂSURAT: la trecerea 390 → 1400 px, cutia hărții   ║
     ║ ajungea **1400×0**, adică harta dispărea cu totul.                                 ║
     ║ ⭐ Cerută `relative` de la bun început, biblioteca n-o mai rescrie, nu rămâne niciun║
     ║ stil inline, iar foaia hotărăște singură pe amândouă ecranele. ⚠️ Și e oricum forma ║
     ║ corectă: panourile Leaflet sunt absolute și trebuie să se agațe de CUTIA HĂRȚII,   ║
     ║ nu de `.zona` de deasupra ei.                                                      ║
     ╚══════════════════════════════════════════════════════════════════════════════════╝ */
  #harta { position: relative; flex: 1 1 auto; min-height: 45vh; min-height: 45dvh;
           min-height: var(--harta-loc, 45dvh); order: 10; }
  .fara-dale { position: static; min-height: 45vh; min-height: 45dvh; order: 10; }
  #panouri { position: static; width: 100%; padding: 0; }
  .panou { border-radius: 0; height: auto; max-height: 70vh; }

  /* ⭐⭐ LEGENDA COBOARĂ AICI (runda 14). Pe birou plutește în colțul stânga-jos, pe telefon
     cade sub hartă. ⛔ Fără nicio regulă a ei: cere componentei clasa de mai jos, care
     exista deja tocmai pentru „un card nou montat pe hartă". Cardul de curs a stat alături
     o rundă și a plecat în bară, ca „Calc" (runda 15). */
  .plutitor-sub-harta {
    flex: 0 0 auto; background: var(--fond-card);
    border-top: 1px solid var(--linie); padding: var(--sp-2) var(--sp-3) var(--sp-3);
    order: 95;
  }

  /* ---------- „CALC" PE TELEFON: PE TOT ECRANUL, CU BUTON DE ÎNCHIDERE (runda 15) ----------
     ⚠️ Fereastra lipită sub buton n-are loc pe un ecran mic (aprobat de Nelu). Întinsă peste
     tot ecranul ea ACOPERĂ pagina, deci × din antet capătă ținta întreagă a degetului — o
     acoperire fără cale de închidere e o capcană. Locul ales cu mouse-ul pe birou nu se
     citește aici: `--calc-x` / `--calc-y` sunt bătute de valorile de mai jos.
     ⛔ Fără prag în JavaScript: scriptul vede doar că fereastra a ieșit cât ecranul. */
  dialog.calc-fereastra {
    left: 0; top: 0; width: 100%; height: 100%; max-height: none;
    aspect-ratio: auto; border: 0; border-radius: 0;
  }
  .calc-cap { cursor: default; padding-left: var(--sp-4); }
  .calc-inchide { width: var(--tinta); height: var(--tinta); }
}

/* ══════════════════════════════════════════════════════════════════════════════════════
   19. TIPĂRIRE
   ══════════════════════════════════════════════════════════════════════════════════════
   Bara și filtrele nu se tipăresc: pe hârtie navigația e cerneală cheltuită degeaba. */
@media print {
  .bs, .fl, .pgn, .pg-act { display: none !important; }
  body { background: #ffffff; color: #000000; }
  .card, table { border-color: #999999; }
}
