/* ==========================================================================
   REVINO - foaie de stil
   Schema de culori: alb, negru, galben (galbenul pe butoane si pe chenarele
   din lista de produse). Responsive, optimizat pentru tableta la casa.

   Contrastul: galbenul este folosit doar ca fundal sub text negru sau ca
   chenar, niciodata ca text pe alb, pentru ca nu ar trece pragul WCAG AA.
   ========================================================================== */

:root {
    --negru: #111111;
    --negru-moale: #2b2b2b;
    --gri: #6b6b6b;
    --gri-linie: #e2e2e2;
    --gri-fundal: #f6f6f6;
    --alb: #ffffff;
    /* Culoarea textului care sta DIRECT pe accent.
       Nu este o alegere de gust: se calculeaza din luminanta accentului, in
       includes/brand.php. Pe galben iese negru, pe bleumarin iese alb.
       Fara ea, o firma cu accent inchis ar avea butoane cu text negru pe
       fundal inchis - adica butoane fara text. */
    --pe-accent: #111111;
    /* ----------------------------------------------------------------
       DE CE EXISTA --text SI --pe-negru

       --negru avea TREI roluri: culoarea textului, culoarea suprafetelor
       inchise (bara de sus, butoane pline), si culoarea marginilor de
       accentuare. In tema luminoasa o singura valoare le acopera pe toate.

       In tema intunecata se despart: textul trebuie DESCHIS, suprafata
       trebuie INCHISA. Cu o singura variabila, ori textul devine invizibil
       pe card, ori bara de sus devine alba.

       La fel --alb: era si suprafata paginii, si culoarea textului care sta
       pe suprafetele inchise (`.btn-dark`).

       Valorile de aici sunt IDENTICE cu cele de dinainte, deci tema
       luminoasa arata exact la fel. Diferenta apare numai in tema
       intunecata.
       ---------------------------------------------------------------- */
    /* Textul principal, pe suprafata --alb. */
    --text: #111111;
    /* Textul care sta pe suprafetele --negru (bara de sus, butoane pline). */
    --pe-negru: #ffffff;
    --galben: #ffd400;
    --galben-inchis: #e6bf00;
    --galben-palid: #fff8d6;
    /* ###################################################################
       CONTURUL PENTRU CE SE SPRIJINA DOAR PE CULOARE - implicit.

       DEFECT GASIT DE VERIFICAREA „fiecare var(--x) exista": variabila era
       folosita in cinci locuri, dar definita NUMAI de `brand_css()`, la
       rulare. Iar acela intoarce șir GOL cand culorile nu au fost schimbate -
       adica pe instalarea obisnuita. Deci pe tema luminoasa, cu galbenul
       implicit, `--galben-contur` nu exista, si CSS-ul sarea peste
       proprietatile care o foloseau, in liniște:

         - barele din grafice rămâneau fara contur, iar conturul e chiar ce le
           face vizibile pe alb (galben pe alb: 1,43:1, sub pragul de 3:1);
         - bara de progres si cea de distribuție nu-si mai arătau capătul,
           adica informatia;
         - bulinele umplute pierdeau marginea;
         - iar la notele cu stele, `outline` pe `:focus-visible` devenea
           invalid - deci navigarea de la tastatura nu se mai vedea deloc.

       Tema intunecata nu era atinsa: `brand_css_dark()` o scrie intotdeauna.

       Valoarea de aici este exact ce socotește `visible_on('#ffd400',
       '#ffffff')` - accentul mutat pana la 3:1 fata de pagina. Cand patronul
       schimba culoarea, blocul de la `brand_css()` o suprascrie.
       ################################################################### */
    --galben-contur: #b09200;
    /* Text secundar pe fundal negru. Gri deschis, nu --gri: acela este pentru
       fundal alb si pe negru ar avea contrast prea mic. Raportul aici este de
       aproximativ 9,5:1, peste cerinta AAA. */
    --gri-pe-negru: #b8b8b8;
    /* Text secundar pe fundal galben. Negru pur ar fi prea dur pentru un
       paragraf; galbenul foarte inchis pastreaza un contrast de ~5,6:1. */
    --galben-text: #5c4c00;
    /* ----------------------------------------------------------------
       CULORILE DE STARE. Toate sase trebuie sa fie VARIABILE.

       O culoare scrisa fix aici este o culoare pe care tema intunecata NU o
       poate corecta. S-a vazut: `.alert-error` avea `background: #fdeeed`,
       aproape alb, iar in tema intunecata textul este deschis - deci alb pe
       alb, ilizibil. La fel `.card-voided` (#fcfcfc) si chihlimbarul de stoc
       scazut (#8a6100).

       Valorile sunt cele scrise pana acum, deci tema luminoasa arata la fel.
       Paletele din includes/brand.php le suprascriu pe amandoua temele.
       ---------------------------------------------------------------- */
    --roeu: #b3261e;
    --verde: #1b6b3a;
    /* Chihlimbar: „aproape s-a terminat". Nici roșu, nici accentul firmei. */
    --ambra: #8a6100;
    /* Fundalurile panourilor de mesaj. */
    --rosu-palid: #fdeeed;
    --verde-palid: #eef7f1;
    /* Un alb cu o umbra mai putin: cardul unei cumparaturi anulate. */
    --alb-moale: #fcfcfc;
    /* Spune browserului ce fel de tema este. Fara asta, controalele native -
       casetele de bifat, listele derulante, barele de derulare - rămân
       luminoase pe o pagina intunecata, si se vede. */
    color-scheme: light;
    --radius: 10px;
    --umbra: 0 1px 2px rgba(0, 0, 0, .08), 0 4px 14px rgba(0, 0, 0, .05);
}

* { box-sizing: border-box; }

/* Atributul `hidden` din HTML trebuie sa ascunda, oricare ar fi restul foii.
   Browserul il implementeaza ca `display: none`, dar in foaia proprie - deci
   ORICE regula de `display` scrisa aici il invinge, pentru ca regulile autorului
   au prioritate fata de cele ale browserului.
   
   Exact asta s-a intamplat cu butoanele de produs de la casa: `.product` are
   `display: flex`, deci `button.hidden = true` din JavaScript nu ascundea nimic,
   iar taburile si cautarea pareau ca nu functioneaza. Aceeasi problema o aveau
   butonul „Șterge" (`.btn` este `inline-block`) si panoul de avertizare
   (`.alert` este bloc).
   
   `!important` este justificat aici: nu este o preferinta de stil, este
   comportamentul definit de HTML pentru acest atribut. */
[hidden] { display: none !important; }

html { -webkit-text-size-adjust: 100%; }

body {
    margin: 0;
    background: var(--gri-fundal);
    color: var(--text);
    font: 16px/1.55 system-ui, -apple-system, "Segoe UI", Roboto, Arial, sans-serif;
}

h1, h2, h3 { line-height: 1.25; margin: 0 0 .6rem; }
h1 { font-size: 1.75rem; }
h2 { font-size: 1.3rem; }
h3 { font-size: 1.05rem; }
p { margin: 0 0 .9rem; }
a { color: var(--text); }

/* ----------------------------------------------------------------- bara sus */
.topbar {
    background: var(--negru);
    color: var(--pe-negru);
    border-bottom: 4px solid var(--galben);
}

.topbar-inner {
    max-width: 1100px;
    margin: 0 auto;
    padding: .7rem 1rem;
    display: flex;
    align-items: center;
    gap: 1rem;
    flex-wrap: wrap;
}

.brand {
    color: var(--pe-negru);
    font-weight: 800;
    letter-spacing: .14em;
    text-decoration: none;
    font-size: 1.1rem;
}

.brand::after {
    content: "";
    display: inline-block;
    width: .5rem; height: .5rem;
    margin-left: .45rem;
    border-radius: 50%;
    background: var(--galben);
}

/* MOTTOUL, in bara de sus, dupa nume si bulina.
 *
 * SE ASCUNDE PE ECRANE INGUSTE. Bara are un singur rand si trebuie sa ducă
 * numele, navigarea, numele omului autentificat, ieșirea si butonul de tema.
 * Pe un telefon nu incap toate; mottoul e decor, si decorul pleaca primul.
 *
 * `display: none`, nu font mai mic: micsorat pana sa incapa ar ajunge oricum
 * de necitit, iar un text de 9 pixeli in bara arata ca un defect.
 *
 * De la 700px in sus apare. Acolo mai e loc, si tot acolo bara de navigare nu
 * mai e strânsa in meniul cu ☰. */
.brand-motto { display: none; }

@media (min-width: 700px) {
    .brand-motto {
        display: inline;
        /* Text secundar pe fundal inchis: --gri-pe-negru e calculat la 9,5:1
           fata de suprafata barei, in amandouă temele. Vezi brand.php. */
        color: var(--gri-pe-negru);
        font-size: .85rem;
        margin-left: .6rem;
        /* Nu se rupe in doua rânduri: ar inalta bara. Ce nu incape se taie cu
           trei puncte - iar limita de 60 de caractere face asta rar. */
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
        max-width: 22rem;
    }
}

/* La tipărire nu are ce sa caute: hartia poarta cifre, nu sloganuri. */
@media print {
    .brand-motto { display: none; }
}

.nav { display: flex; gap: .35rem; flex-wrap: wrap; margin-right: auto; }

.nav a {
    color: var(--pe-negru);
    text-decoration: none;
    padding: .4rem .7rem;
    border-radius: 6px;
    font-size: .95rem;
    border: 1px solid transparent;
}

.nav a:hover { border-color: var(--galben); }
.nav a.active { background: var(--galben); color: var(--pe-accent); font-weight: 700; }

/* Partea dreapta a barei: numele, Ieșire, si butonul de tema.
 *
 * `margin-left:auto` sta pe GRUP, nu pe blocul cu numele. Motivul: butonul de
 * tema trebuie sa fie in dreapta sus si pe paginile fara nimeni autentificat
 * (intrare, inregistrare), unde blocul cu numele nu exista. Pus pe fiecare,
 * doua margini auto ar imparti spatiul liber intre ele si numele ar ajunge pe
 * la mijloc. */
.topbar-right { display: flex; align-items: center; gap: .6rem; margin-left: auto; }
.who { font-size: .9rem; color: #d7d7d7; }
/* Butonul de tema, in bara de sus.
 *
 * Textul foloseste --pe-negru: variabila inseamna exact „text pe suprafata
 * --negru", si se calculeaza pe fiecare paleta. In tema luminoasa iese
 * #ffffff, adica ce era scris fix aici; in cea intunecata, ce trebuie pe
 * #242424. Chenarul rămâne fix: e decorativ, iar butonul se recunoaste dupa
 * semnul din el. */
.tema-toggle {
    background: none;
    border: 1px solid #555;
    color: var(--pe-negru);
    font-size: 1rem;
    line-height: 1;
    border-radius: 999px;
    padding: .3rem .5rem;
    cursor: pointer;
    margin-left: .4rem;
}
.tema-toggle:hover { border-color: var(--galben); }
.tema-toggle:focus-visible { outline: 3px solid var(--galben); outline-offset: 2px; }

.nav-toggle { display: none; background: none; border: 1px solid #555; color: var(--pe-negru);
    font-size: 1.1rem; border-radius: 6px; padding: .2rem .55rem; cursor: pointer; }

/* --------------------------------------------------------------- structura */
.container { max-width: 900px; margin: 0 auto; padding: 1.5rem 1rem 3rem; }
.container.wide { max-width: 1180px; }

.footer {
    text-align: center;
    color: var(--gri);
    font-size: .85rem;
    padding: 1.5rem 1rem 2.5rem;
}

/* ===========================================================================
   ADAUGAREA UNUI PRODUS: UN BUTON, IAR FORMULARUL CA POP-UP
   ===========================================================================
   Structura e un `<details>` (vezi comentariul din admin/products.php pentru de
   ce nu `<dialog>`). Ce e aici e numai imbracarea:

     - inchis, `<summary>` arata ca un buton obisnuit;
     - deschis, panoul se ridica peste pagina, cu fundal intunecat in spate.

   TOTUL E O PODOABA. Fara aceasta foaie de stil - sau pe un browser care nu
   cunoaste `<details>` - rămâne un formular desfasurat in pagina. Adica exact
   ce era inainte, deci nimeni nu rămâne fara posibilitatea de a adauga un
   produs. */

.prod-adauga {
    margin-bottom: 1rem;
}

/* Triunghiul implicit al lui <summary> se scoate: elementul poarta clasa `.btn`,
   deci arata ca un buton - iar un buton cu o săgețică de „desfasoara" langa el
   trimite un mesaj greșit.

   Se scoate in doua feluri, pentru ca browserele nu sunt de acord care e cel
   bun: `list-style` pentru cele noi, `::-webkit-details-marker` pentru Safari.

   RESTUL VINE DIN `.btn`, nu se scrie a doua oara aici. Prima versiune copia
   fundalul, culoarea, marginea si conturul de focalizare - iar copia a ieșit
   deja greșita in doua locuri: `border-color: var(--negru)` si
   `outline: 3px solid var(--negru)`, amandoua invizibile pe tema intunecata.
   `tests/tema.php` le-a prins inainte sa deschid pagina. `.btn` le avea deja
   corecte (`--text` la amandoua), pentru ca acolo fusese gandit o data. */
.prod-adauga > summary {
    list-style: none;
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    gap: .4rem;
}

.prod-adauga > summary::-webkit-details-marker { display: none; }

/* ---- DESCHIS: panoul peste pagina ---- */

/* Fundalul intunecat. Se deseneaza cu ::before pe <details>, nu cu un element
   in plus in HTML: e decor, si decorul n-are ce sa caute in structura paginii.
   `position: fixed` il ține pe loc si cand pagina se derulează dedesubt. */
.prod-adauga[open]::before {
    content: "";
    position: fixed;
    inset: 0;
    background: rgba(0, 0, 0, .55);
    z-index: 60;
}

.prod-adauga[open] > .prod-adauga-panou {
    position: fixed;
    z-index: 61;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: min(46rem, calc(100vw - 2rem));

    /* SE DERULEAZA IN INTERIOR, si asta nu e un amanunt: formularul are
       vreo zece câmpuri, iar pe un telefon in portret nu incape niciodata
       intreg. Fara `overflow`, butonul „Adaugă produsul" ar cadea sub
       marginea ecranului si n-ar exista nicio cale de a-l apasa. */
    max-height: calc(100vh - 2rem);
    overflow-y: auto;
    -webkit-overflow-scrolling: touch;

    background: var(--alb);
    border: 2px solid var(--galben);
    border-radius: 12px;
    padding: 1.2rem;
}

.prod-adauga[open] > .prod-adauga-panou h2 { margin-top: 0; }

/* Butonul rămâne pe loc in pagina, dar SUB fundalul intunecat: `z-index` 59
   fata de 60. Deci cat timp panoul e deschis nu se poate apasa - nici din
   greseala, nici intenționat.

   E voit. Inchiderea se face din „Renunță", care e o legatura obisnuita catre
   pagina: merge si cu JavaScript oprit. Un `<summary>` lasat apasabil peste
   fundal ar fi un al doilea fel de a inchide, in alt loc de pe ecran, si
   primul lucru pe care l-ar apasa cineva care vrea sa iasa. */
.prod-adauga[open] > summary {
    position: relative;
    z-index: 59;
}

.prod-adauga-butoane {
    display: flex;
    flex-wrap: wrap;
    gap: .6rem;
    align-items: center;
    margin-top: 1rem;
}

/* GRUPUL DE CAMPURI DIN FORMULARE LUNGI
 *
 * A FOST SCRIS DE DOUA ORI CA `style="..."` DIRECT IN admin/brand.php - o data
 * pentru iconițe, o data pentru rețele. Doua copii ale aceleiasi rame, care se
 * pot despărți la prima schimbare.
 *
 * Mutat aici pentru ca tests/wizard-brand.php cere ca fiecare clasa folosita in
 * pagina sa existe in foaia de stil: prima versiune a rețelelor avea
 * `class="fieldset"` inventat, iar testul a prins-o inainte sa ajung sa deschid
 * pagina. */
.fieldset {
    border: 1px solid var(--gri-linie);
    border-radius: var(--radius);
    padding: 1rem;
    margin: 1.5rem 0 0;
}

.fieldset legend {
    padding: 0 .4rem;
    font-weight: 700;
}

/* ICONITELE DE SOCIAL MEDIA DIN SUBSOL
 *
 * Apar numai pe paginile de client, si numai cele completate in
 * Admin -> Aspect. Vezi includes/socials.php.
 *
 * `flex-wrap` pentru ca sase iconițe cu titlu inainte nu incap pe un ecran de
 * 320 de pixeli - se rup pe doua randuri, centrate. */
.socials {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    justify-content: center;
    gap: .25rem;
    margin-bottom: .9rem;
}

.socials-titlu {
    margin-right: .35rem;
}

/* TINTA DE APASAT E DE 44 DE PIXELI, desenul de 20.
 *
 * Nu e o preferinta: 44 este minimul recomandat pentru un deget pe telefon, iar
 * subsolul e ultimul loc de pe pagina - se apasa cu policele, in graba. Un
 * `<a>` de 20 de pixeli se rateaza si nimeni nu mai incearca a doua oara.
 *
 * Padding-ul face diferenta, nu marimea desenului: asa iconițele rămân
 * discrete, dar zona apasabila e generoasa. */
.social-link {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    width: 44px;
    height: 44px;
    color: var(--gri);
    border-radius: 50%;
    text-decoration: none;
}

.social-link:hover,
.social-link:focus-visible {
    color: var(--pe-negru);
    background: var(--gri-fundal);
}

/* Desenele folosesc `stroke="currentColor"`, deci culoarea vine de pe legatura
 * si se schimba singura la trecerea cu mouse-ul si pe tema intunecata. */
.social-icon {
    width: 20px;
    height: 20px;
    display: block;
}

.card {
    background: var(--alb);
    border: 1px solid var(--gri-linie);
    border-radius: var(--radius);
    padding: 1.25rem;
    margin-bottom: 1.25rem;
    box-shadow: var(--umbra);
}

.card-yellow { border: 2px solid var(--galben); }

/* ------------------------------- animatia de intrare (doar pagina de intrare) */
/*
 * Logo-ul apare mare pe mijloc, pe fundal alb, si se micsoreaza pana la locul
 * lui din pagina. Durata totala: 750ms. Peste atat devine ceva de asteptat.
 *
 * CUM ESTE FACUTA SA NU POATA STRICA PAGINA
 * -----------------------------------------
 * Riscul unei animatii de intrare este unul singur, dar grav: un panou alb
 * care acopera tot si NU dispare. Atunci pagina de intrare a aplicatiei este
 * complet inutilizabila, si nu pentru toata lumea - doar pentru cine are
 * browserul sau setarea nepotrivita. Adica exact felul de defect care nu se
 * observa la testare.
 *
 * De aceea:
 *
 *   1. `.intro` este `display: none` IMPLICIT. Se aprinde doar cand un script
 *      pune clasa `intro-on` pe <html>. Fara JavaScript, panoul nu exista.
 *   2. Daca aceasta foaie de stil nu se incarca, `<div class="intro">` este un
 *      div gol, fara `position: fixed` si fara fundal. Nu acopera nimic.
 *   3. Animatia se termina in `visibility: hidden` cu `forwards`, deci panoul
 *      dispare din CSS, nu pentru ca JavaScript-ul l-a scos. Chiar daca scriptul
 *      moare imediat dupa ce a pornit-o, panoul tot pleaca.
 *   4. `pointer-events: none` de la inceput: cat timp animatia ruleaza, un click
 *      ajunge la butonul de dedesubt. Animatia nu poate bloca niciodata pe
 *      cineva grabit.
 *
 * Fiecare fel de esec duce la „fara animatie", niciodata la „pagina alba".
 *
 * Landingul este exact, fara sa se masoare nimic in JavaScript: animatia
 * logo-ului se termina in `transform: none`, adica in locul lui firesc din
 * pagina, oricare ar fi el. Doar punctul de PORNIRE este aproximat cu vh, iar
 * acolo precizia nu se vede - ochiul urmareste unde ajunge, nu de unde pleaca.
 */
.intro {
    display: none;
}

.intro-on .intro {
    display: block;
    position: fixed;
    inset: 0;
    background: var(--alb);
    z-index: 50;
    /* Nu prinde niciodata clickurile. Vezi punctul 4 mai sus. */
    pointer-events: none;
    animation: intro-alb .75s ease forwards;
}

/* Logo-ul trece peste panoul alb cat timp se micsoreaza. */
.intro-on .brand-hero {
    position: relative;
    z-index: 60;
    animation: intro-logo .7s cubic-bezier(.22, .8, .3, 1) forwards;
}

@keyframes intro-alb {
    /* Alb opac pana la jumatate, apoi se stinge. Logo-ul ajunge la locul lui
       aproximativ cand albul termina de plecat. */
    0%, 45% { opacity: 1; }
    100%    { opacity: 0; visibility: hidden; }
}

@keyframes intro-logo {
    0% {
        /* 2.6x si coborat spre mijlocul ecranului. 30vh este o aproximare a
           distantei dintre locul firesc al logo-ului si centrul ecranului. */
        transform: translateY(30vh) scale(2.6);
    }
    100% {
        /* Locul lui firesc, prin definitie. De aici vine landingul exact. */
        transform: none;
    }
}

/*
 * Cine a cerut sistemului mai putina miscare nu primeste nici animatie, nici
 * panou alb. Regula sta DUPA cele de mai sus ca sa le invinga, si acopera si
 * cazul in care scriptul a pus deja clasa.
 */
@media (prefers-reduced-motion: reduce) {
    .intro, .intro-on .intro { display: none; }
    .intro-on .brand-hero { animation: none; }
}

/* ------------------------------------- cei trei pasi de pe pagina de intrare */
/*
 * Inainte erau trei carduri albe identice, cu titlu si text gri mic. Nu era
 * nimic in neregula cu ele, dar nu se uita nimeni la ele: galbenul - singura
 * culoare tare a aplicatiei - lipsea cu totul, iar textul `small muted` arata
 * ca literele mici din contract.
 *
 * Acum: carduri negre cu cifra mare in fundal, iar al treilea galben plin.
 * Al treilea este rasplata, deci trebuie sa se vada dintr-o privire care
 * dintre cei trei pasi merita.
 *
 * ATENȚIE la nume: clasa NU se numeste .step. Aceea exista deja, pentru
 * patratele barei de progres, si ar fi doua lucruri diferite cu acelasi nume.
 */
.howto {
    display: grid;
    gap: 1.25rem;
    /* Aceeasi masura ca .grid-3, ca sa se rupa pe telefon in acelasi punct. */
    grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
    margin-bottom: 1.25rem;
}

.howto-card {
    /* position + overflow: cifra din fundal este pozitionata absolut si trebuie
       tăiata la marginea cardului, altfel iese peste vecin. */
    position: relative;
    overflow: hidden;
    background: var(--negru);
    border-radius: var(--radius);
    padding: 1.1rem;
}

.howto-card-reward { background: var(--galben); }

/*
 * Cifra mare din fundal. Este decor, deci in HTML are aria-hidden: un cititor
 * de ecran ar spune „1" de doua ori, o data pentru cifra si o data pentru
 * titlu.
 */
.howto-num {
    position: absolute;
    top: -.4rem;
    right: .35rem;
    font-size: 4rem;
    font-weight: 800;
    line-height: 1;
    color: var(--negru-moale);
    /* Nu se poate selecta cu mouse-ul: nu este text de citit. */
    -webkit-user-select: none;
    user-select: none;
}

.howto-card-reward .howto-num { color: var(--galben-inchis); }

/*
 * Iconițele folosesc stroke="currentColor", deci culoarea se da o singura data,
 * aici, si se schimba impreuna cu fundalul cardului.
 */
.howto-icon {
    display: block;
    width: 26px;
    height: 26px;
    margin-bottom: .55rem;
    /* Peste cifra din fundal, nu sub ea. */
    position: relative;
    color: var(--galben);
}

.howto-card-reward .howto-icon { color: var(--text); }

/*
 * La fel: titlul si textul trec peste cifra - `position: relative` fara z-index
 * le pune deasupra, pentru ca elementele pozitionate se deseneaza in ordinea din
 * document, iar cifra este scrisa inaintea lor.
 *
 * padding-right ține titlul in afara colțului ocupat de cifra. Fara el, pe o
 * tabletă unde grila are doua coloane, primul rand al titlului ar trece peste
 * cifra - se citeste, dar arata murdar.
 */
.howto-card h3 {
    position: relative;
    margin: 0 0 .3rem;
    padding-right: 1.8rem;
    color: var(--pe-negru);
}

.howto-card p {
    position: relative;
    margin: 0;
    font-size: .9rem;
    line-height: 1.5;
    color: var(--gri-pe-negru);
}

.howto-card-reward h3 { color: var(--pe-accent); }
.howto-card-reward p { color: var(--galben-text); }

/* ------------------------------------------- logo-ul de pe pagina de intrare */
.brand-hero { margin: .2rem 0 .9rem; line-height: 1; }

/* Textul de rezervă, cât timp nu există un fișier de logo. */
.brand-hero-text { font-size: 1.75rem; letter-spacing: .06em; }

/* Logo-ul propriu-zis. Lățimea urmează ecranul, între 160 și 340 px, iar
   înălțimea se calculează din proporțiile fișierului — deci merge la fel de
   bine cu un logo lat sau cu unul pătrat, fără să-l deformeze. */
.brand-hero-img {
    display: block;
    margin: 0 auto;
    width: clamp(160px, 46vw, 340px);
    height: auto;
    /* Nu se întinde peste înălțimea utilă a unui telefon în modul portret. */
    max-height: 26vh;
    object-fit: contain;
}

@media (max-width: 400px) {
    .brand-hero-img { width: clamp(140px, 60vw, 260px); }
}

/* La tipărire, logo-ul rămâne mic și negru pe alb. */
@media print {
    .brand-hero-img { width: 180px; max-height: none; }
}

/* O cumparatura anulata: fara galben, cu o dunga roșie in stanga. Se vede
   dintr-o privire ca nu este o cumparatura obisnuita. */
.card-voided {
    border: 1px solid var(--gri-linie);
    border-left: 6px solid var(--roeu);
    background: var(--alb-moale);
}

.card-voided h2, .card-voided h1 { color: var(--gri); }
.card h2 { margin-top: 0; }
.muted { color: var(--gri); }
.small { font-size: .875rem; }
.center { text-align: center; }
.right { text-align: right; }
.mono { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; }
.mt { margin-top: 1rem; }
.nowrap { white-space: nowrap; }

.grid { display: grid; gap: 1.25rem; }

/* UN RAND DE INDICATORI ISI TINE SINGUR SPATIUL DE DEDESUBT.
 *
 * `.grid` da distanta DINTRE casute, prin `gap`, dar nimic dedesubt. Iar
 * `.stat` nu are margine proprie, dinadins: intr-o grila, o margine pe copil
 * se adauga INAUNTRUL celulei, deci casuta nu ar mai umple celula si randurile
 * ar ieși de inaltimi diferite.
 *
 * Rezultatul era ca titlul „Activitate" se lipea de randul de casute de
 * deasupra, iar cardul „Cumpărături" de randul de dedesubt - in timp ce doua
 * carduri obisnuite aveau 1,25rem intre ele, pentru ca `.card` are margine.
 * Aceeasi pagina, doua distante diferite intre lucruri de acelasi fel.
 *
 * DE CE O CLASA, SI NU `.grid { margin-bottom }`
 *
 * `.grid` se foloseste si INAUNTRUL cardurilor, pentru randuri de câmpuri
 * (vezi install.php, admin/setari.php). Acolo o margine ar adauga spatiu peste
 * padding-ul cardului. Iar `.grid:has(.stat)` ar rezolva-o elegant, dar
 * `:has()` nu exista pe telefoanele si tabletele mai vechi de 2023 - si tocmai
 * acelea ajung la casa.
 *
 * NU se pune pe grilele de indicatori din INTERIORUL unui card: acolo
 * spatiul il da padding-ul cardului. Vezi admin/client.php. */
.stats { margin-bottom: 1.25rem; }

/* SECTIUNILE CU ANCORA NU SE LIPESC DE MARGINEA DE SUS.
 *
 * Filtrele de pe pagina de statistici se intorc la secțiunea lor prin ancora
 * (`dashboard.php?p=90#cumparaturi`), altfel fiecare apasare ar duce in capul
 * paginii. Fara `scroll-margin-top`, browserul pune titlul exact pe marginea
 * ecranului si pare tăiat.
 *
 * `scroll-margin-top`, nu `padding`: schimba doar UNDE se oprește derularea,
 * nu aranjarea paginii. */
h2[id], .card[id] { scroll-margin-top: 1rem; }
.grid-2 { grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); }
.grid-3 { grid-template-columns: repeat(auto-fit, minmax(210px, 1fr)); }
.grid-4 { grid-template-columns: repeat(auto-fit, minmax(170px, 1fr)); }
.row { display: flex; gap: .6rem; flex-wrap: wrap; align-items: center; }
.row-between { display: flex; gap: .6rem; flex-wrap: wrap;
    align-items: center; justify-content: space-between; }

/* ---------------------------------------------------------------- butoane */
.btn {
    display: inline-block;
    background: var(--galben);
    color: var(--pe-accent);
    border: 2px solid var(--galben-inchis);
    border-radius: 8px;
    padding: .6rem 1.1rem;
    font: inherit;
    font-weight: 700;
    text-decoration: none;
    cursor: pointer;
    transition: transform .05s ease, background .15s ease;
}

.btn:hover { background: var(--galben-inchis); }
.btn:active { transform: translateY(1px); }
.btn:focus-visible { outline: 3px solid var(--text); outline-offset: 2px; }
.btn[disabled] { opacity: .5; cursor: not-allowed; }

.btn-dark { background: var(--negru); color: var(--pe-negru); border-color: var(--text); }
.btn-dark:hover { background: var(--negru-moale); }

.btn-ghost { background: transparent; color: var(--pe-negru); border-color: var(--galben); }
.btn-ghost:hover { background: var(--galben); color: var(--pe-accent); }

.btn-outline { background: var(--alb); color: var(--text); border-color: var(--text); }
.btn-outline:hover { background: var(--galben); color: var(--pe-accent); }

.btn-danger { background: var(--alb); color: var(--roeu); border-color: var(--roeu); }
.btn-danger:hover { background: var(--roeu); color: var(--pe-negru); }

.btn-sm { padding: .3rem .65rem; font-size: .85rem; border-radius: 6px; }
.btn-lg { padding: .9rem 1.6rem; font-size: 1.15rem; width: 100%; }

/* --------------------------------------------------------------- formulare */
label { display: block; font-weight: 600; margin: 0 0 .3rem; font-size: .92rem; }

/* `textarea` E IN LISTA, si a fost adaugat cand a apărut pagina de parere.
 *
 * Pana atunci nicio pagina nu avea unul, deci lipsa lui nu se vedea. Un
 * textarea nestilizat nu e rupt - browserul ii da o rama proprie - dar arata
 * din alta aplicatie: alta rama, alt font, alta rotunjire, langa niste câmpuri
 * care se potrivesc intre ele. */
input[type=text], input[type=email], input[type=password], input[type=date],
input[type=number], input[type=search], select, textarea {
    width: 100%;
    padding: .6rem .7rem;
    border: 2px solid var(--gri-linie);
    border-radius: 8px;
    background: var(--alb);
    color: var(--text);
    font: inherit;
}

textarea {
    /* Se intinde in jos, nu in lateral: intins pe orizontala ar ieși din card
     * pe telefon, si nimic din pagina nu s-ar mai alinia. */
    resize: vertical;
    min-height: 5rem;
    line-height: 1.45;
}

input:focus, select:focus, textarea:focus {
    border-color: var(--galben-inchis);
    outline: 2px solid var(--galben);
    outline-offset: 1px;
}

.field { margin-bottom: .9rem; }
.field-error input { border-color: var(--roeu); }
.error-text { color: var(--roeu); font-size: .85rem; margin: .25rem 0 0; }

/* ------------------------------------------- butonul „arata parola” */
.pw-wrap { position: relative; display: block; }

/* Loc pentru buton, ca textul sa nu treaca pe sub el. */
.pw-wrap input { padding-right: 3rem; }

.pw-reveal {
    position: absolute;
    right: .3rem;
    top: 50%;
    transform: translateY(-50%);
    display: flex;
    align-items: center;
    justify-content: center;
    width: 2.4rem;
    height: 2.4rem;
    padding: 0;
    background: transparent;
    border: 2px solid transparent;
    border-radius: 6px;
    color: var(--gri);
    cursor: pointer;
}

.pw-reveal:hover { color: var(--text); background: var(--galben-palid); }
.pw-reveal:focus-visible { outline: 3px solid var(--galben); outline-offset: 1px; }

/* Cand parola este vizibila, butonul o spune si vizual, nu doar prin iconita. */
.pw-reveal[aria-pressed="true"] {
    color: var(--text);
    background: var(--galben);
    border-color: var(--galben-inchis);
}

/* Potrivirea celor doua parole, in timp ce se scrie. Culoarea singura nu
   ajunge: mesajul are si un semn, ✓ sau ✕, pentru cine nu distinge verdele
   de rosu. */
.match-status {
    font-size: .85rem;
    margin: .3rem 0 0;
    min-height: 1.2em; /* nu sare aranjarea cand apare sau dispare textul */
    font-weight: 600;
}

.match-status.is-ok { color: var(--verde); }
.match-status.is-bad { color: var(--roeu); }
.match-status.is-typing { color: var(--gri); font-weight: 400; }

input[aria-invalid="true"] { border-color: var(--roeu); }

.check { display: flex; gap: .55rem; align-items: flex-start; margin-bottom: 1rem; }
.check input { width: 1.15rem; height: 1.15rem; margin-top: .18rem; accent-color: var(--text); }
.check label { font-weight: 400; margin: 0; }

/* --------------------------------------------------------------- mesaje */
.alert {
    border-radius: 8px;
    padding: .8rem 1rem;
    margin-bottom: 1rem;
    border: 2px solid var(--text);
    background: var(--alb);
}

.alert-success { border-color: var(--verde); background: var(--verde-palid); }
.alert-error { border-color: var(--roeu); background: var(--rosu-palid); }
.alert-info { border-color: var(--galben-inchis); background: var(--galben-palid); }

/* --------------------------------------------------------------- tabele */
.table-wrap { overflow-x: auto; }

table { width: 100%; border-collapse: collapse; background: var(--alb); }
th, td { padding: .6rem .65rem; text-align: left; border-bottom: 1px solid var(--gri-linie); }
th { background: var(--negru); color: var(--pe-negru); font-size: .85rem;
    text-transform: uppercase; letter-spacing: .04em; }
tbody tr:hover { background: var(--galben-palid); }
td.num, th.num { text-align: right; white-space: nowrap; }
tfoot td { font-weight: 700; border-top: 2px solid var(--text); }

/* --------------------------------------------------------------- statistici */
.stat {
    background: var(--alb);
    border: 1px solid var(--gri-linie);
    border-left: 6px solid var(--galben);
    border-radius: var(--radius);
    padding: 1rem 1.1rem;
    box-shadow: var(--umbra);
}

.stat .value { font-size: 2rem; font-weight: 800; line-height: 1.1; }

/* Moneda, in casuta mare: mai mica decat cifra.
 *
 * `em`, nu `rem`: se leaga de dimensiunea cifrei de langa ea, deci rămâne
 * proporțional daca `.value` se schimba vreodata. `white-space: nowrap` pe tot
 * blocul, ca „3.017,60 lei" sa nu se rupa intre numar si eticheta - asta era
 * chiar defectul. Vezi suma_html(). */
.stat .value { white-space: nowrap; }
.stat .value .unit { font-size: .5em; font-weight: 700; }
.stat .label { color: var(--gri); font-size: .85rem; text-transform: uppercase;
    letter-spacing: .05em; }

/* --------------------------------------------------------------- cod QR */
.qr-box {
    display: inline-block;
    background: var(--alb);
    border: 3px solid var(--text);
    border-radius: var(--radius);
    padding: .75rem;
    line-height: 0;
}

.qr-box svg { width: 100%; height: auto; max-width: 320px; }
.qr-token { letter-spacing: .12em; font-weight: 700; }

/* Parola temporara: mare si rarita, ca sa poata fi citita cu voce tare fara
   sa fie confundate caracterele. */
/* Cardul de instalare pe ecranul principal. Discret: nu e o reclamă. */
.install-card { border-left: 6px solid var(--text); }
.install-card h2 { font-size: 1.05rem; }

.temp-password {
    font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
    font-size: clamp(1.4rem, 6vw, 2.2rem);
    font-weight: 800;
    letter-spacing: .18em;
    background: var(--negru);
    color: var(--galben);
    padding: .7rem .9rem;
    border-radius: 10px;
    text-align: center;
    margin: .6rem 0 1rem;
    user-select: all;
    word-break: break-all;
}

/* --------------------------------------------------------------- progres */
/* --------------------------------------------------------------- progres

   BULINELE STAU PE UN SINGUR RAND, ORICATE SUNT (pana la 12).

   Inainte era `flex-wrap: wrap` cu `min-width: 40px`. Mergea la 6, dar la 10
   pe un telefon ieșea un rand de 7 si unul de 3 - arata ca o greseala.

   `flex: 1 1 0` pe bulinie impărte spatiul in mod egal, fara sa fie nevoie sa
   se stie cate sunt. Peste 12, render_progress trece pe o bara: la atatia pasi
   nimeni nu numara bulinele, si nici nu ar mai fi loc pentru cifre in ele.
   --------------------------------------------------------------------- */
.progress {
    display: flex;
    gap: .3rem;
    /* NU wrap: bulinele se strâng, nu trec pe randul urmator. */
    flex-wrap: nowrap;
    margin: .5rem 0;
}

.step {
    /* Se strâng: baza 0, deci latimea vine din `flex-grow` si din spatiul
       disponibil. `min-width: 0` este necesar - implicitul `auto` ar refuza
       sa coboare sub latimea conținutului si bulinele ar da pe dinafara. */
    flex: 1 1 0;
    min-width: 0;
    /* 44px este minimul pentru o ținta atinsa cu degetul. Se pastreaza pe
       verticala chiar si cand bulinele se ingusteaza. */
    height: 44px;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 2px solid var(--gri-linie);
    border-radius: 8px;
    background: var(--alb);
    color: var(--gri);
    font-weight: 700;
}

/* Bulina plina fata de cea goala: culoarea singura duce informatia, deci
   conturul, nu `--galben-inchis` (1.75:1 pe alb). */
.step-done { background: var(--galben); border-color: var(--galben-contur); color: var(--pe-accent); }
.step-reward { border-color: var(--text); border-style: dashed; font-size: .9rem; }
.step-reward.step-done { background: var(--negru); color: var(--galben); border-style: solid; }
.progress-count { font-size: 1.1rem; margin: .2rem 0 0; }

/* ---------------------------------------------------------------- grafic

   Culorile vin din variabilele temei, deci graficul se schimba singur cand se
   trece pe intuneric. Un grafic desenat cu JS pe <canvas> ar fi trebuit
   redesenat; unul cu culori scrise fix ar fi rămas luminos pe pagina inchisa.
   ---------------------------------------------------------------------- */
.chart {
    display: block;
    width: 100%;
    /* Inaltime fixa in pixeli, latime elastica: `preserveAspectRatio="none"`
       din SVG intinde desenul, deci barele se lățesc pe un ecran mare fara sa
       se inalte. */
    height: 260px;
    margin: .5rem 0;
}

/* CONTURUL PE CE SE SPRIJINA DOAR PE CULOARE
   ------------------------------------------
   Galbenul pe alb are contrast 1.43:1. Pragul WCAG pentru elemente grafice
   (1.4.11) este 3:1. Pentru un buton nu conteaza - are text, se vede ce este.
   Dar la o bara de grafic, INALTIMEA este informatia, iar marginea ei fata de
   fundal este singurul lucru care o arata.
   `--galben-contur` este accentul mutat pana la 3:1 fata de pagina. Umplerea
   rămâne accentul, deci galbenul nu se schimba. Vezi visible_on() in brand.php.
   Se pune NUMAI aici, la bare si la buline - nu pe butoane, ca sa nu se
   schimbe aspectul unde nu era nevoie. */
.chart-bar {
    fill: var(--galben);
    stroke: var(--galben-contur);
    stroke-width: 1;
}
/* Bara se lumineaza cand mausul e pe coloana ei.
 *
 * Selectorul merge pe PARINTE: `:hover` pe zona transparenta de atins nu poate
 * colora un frate, dar `<g class="chart-col">:hover` coloreaza orice
 * descendent. Vezi render_chart() pentru de ce zona de atins este separata de
 * bara.
 *
 * Se schimba doar umplerea, nu dimensiunea: o bara care creste la hover mută
 * desenul sub maus si face graficul sa tremure cand plimbi mausul peste el. */
.chart-col:hover .chart-bar { fill: var(--galben-inchis); }

/* Liniile de reper si axa NU primesc mausul.
 *
 * Fara asta, dunga de 1,5px a axei de jos - desenata PESTE zonele de atins - ar
 * inghiti hover-ul pe ultimul rand de pixeli, iar titlul ar dispărea cand
 * mausul coboara spre etichete. */
.chart-grid { stroke: var(--gri-linie); stroke-width: 1; pointer-events: none; }
.chart-axis-line {
    stroke: var(--gri-linie);
    stroke-width: 1.5;
    pointer-events: none;
}

/* Textele din SVG NU moștenesc `font-family` de la pagina in toate browserele,
   deci se pune aici. */
.chart-axis, .chart-label {
    font-family: inherit;
    font-size: 13px;
    fill: var(--gri);
}

/* Barele de filtrare: butoane-legaturi, nu formular. Se pot deschide in tab nou
   si pot fi salvate la favorite. */
.range-presets { display: flex; flex-wrap: wrap; gap: .3rem; margin: 0 0 .6rem; }
.range-presets .tab { padding: .35rem .7rem; font-size: .9rem; }

/* Bara pentru cicluri lungi (peste REVINO_STEPS_MAX pasi). */
.progress-bar {
    height: 20px;
    background: var(--gri-fundal);
    border: 2px solid var(--gri-linie);
    border-radius: 999px;
    overflow: hidden;
    margin: .5rem 0;
}

.progress-bar-fill {
    height: 100%;
    background: var(--galben);
    /* Marginea din dreapta arata CAT s-a umplut: aceea este informatia, si fara
       contur se pierde intre galben si fundalul deschis al barei. */
    border-right: 2px solid var(--galben-contur);
    /* Fara tranzitie: bara se deseneaza o data, la incarcarea paginii. O
       animatie ar face-o sa porneasca de la zero si sa creasca - frumos o
       singura data, obositor la a zecea cumparatura a zilei. */
    border-radius: 999px;
}

/* ------------------------------------------------------------ grupul adresei
   Patru câmpuri care sunt un singur lucru: stradă, număr, oraș, județ. Fără un
   chenar și un titlu, cele patru etichete ar arăta ca patru întrebări fără
   legătură între ele, iar clientul nu ar ști că le poate lăsa pe toate goale.

   `fieldset` și `legend`, nu un div cu un h3: cititoarele de ecran anunță
   legenda înaintea fiecărui câmp din grup, deci cine nu vede ecranul aude
   „Adresă, opțional - Stradă" în loc de un „Stradă" venit de nicăieri. */
.adresa-grup { border: 1px solid var(--gri-linie); border-radius: var(--radius);
    padding: .8rem .9rem .3rem; margin: 0 0 1rem; }

.adresa-grup legend { padding: 0 .4rem; font-weight: 700; font-size: .95rem; }

/* Ultimul ajutor din grup nu mai are nevoie de spatiu dedesubt: chenarul il
   inchide oricum. */
.adresa-grup > p:last-child { margin-bottom: .5rem; }

/* --------------------------------------------------------------- marjă negativă
   Un produs vândut sub cost. Roșu, dar nu numai roșu: în rapoarte cifra e
   însoțită de cuvântul „pierdere", iar aici de semnul minus din procent. */
.marja-rea { color: var(--roeu); }

/* ----------------------------------------------- semnul de schimbare procentuală
   „▲ +12%" sub o cifră mare. Săgeata NU e ornament: cine nu deosebește roșul
   de verde citește semnul din ea. Aceeași regulă ca la bulinele de progres —
   culoarea adaugă, nu înlocuiește.

   Neutru implicit. Verde sau roșu numai când creșterea are un sens limpede;
   la „reduceri acordate" rămâne neutru, pentru că o creștere poate fi vestea
   cea mai bună sau cea mai rea. Vezi activity_delta(). */
.delta { display: inline-block; font-size: .8rem; font-weight: 700;
    margin: .15rem 0 0; color: var(--gri);
    font-variant-numeric: tabular-nums; white-space: nowrap; }

.delta-bun { color: var(--verde); }
.delta-rau { color: var(--roeu); }

/* ------------------------------------------------------------- matricea zi×oră
   Tabel cu intensitate: cu cât căsuța e mai închisă, cu atât s-a vândut mai
   mult atunci. Cinci trepte, nu un gradient continuu: ochiul nu deosebește
   oricum mai mult, iar patru culori se pot verifica una câte una la contrast.

   INTENSITATEA NU E SINGURA INFORMATIE: în fiecare căsuță scrie și cifra, iar
   `title` spune ziua și ora în cuvinte. Cine nu deosebește nuanțele - sau se
   uită pe hârtie alb-negru - are tot ce trebuie. Aceeași regulă ca la bulinele
   de progres: culoarea adaugă, nu înlocuiește. */
.matrice th { font-size: .8rem; padding: .4rem .3rem; }
.matrice td { padding: .35rem .3rem; text-align: center;
    font-variant-numeric: tabular-nums; font-size: .85rem; }

/* Capul de rând - ziua - stă pe fundalul obișnuit al tabelului, nu pe negru:
   este o etichetă, nu un titlu de coloană. */
.matrice tbody th { background: var(--gri-fundal); color: var(--text);
    text-transform: none; letter-spacing: 0; text-align: left;
    white-space: nowrap; }

/* Treptele. Se construiesc din accent prin transparență, deci urmează paleta
   în amândouă temele - un `#fff3c4` scris fix ar fi rămas galben deschis pe
   fundal închis, adică text negru pe galben pal în tema întunecată. */
.matrice td.mx-0 { color: var(--gri); }
.matrice td.mx-1 { background: color-mix(in srgb, var(--galben) 25%, transparent); }
.matrice td.mx-2 { background: color-mix(in srgb, var(--galben) 50%, transparent); }
.matrice td.mx-3 { background: color-mix(in srgb, var(--galben) 75%, transparent); }
.matrice td.mx-4 { background: var(--galben); color: var(--pe-accent);
    font-weight: 700; }

/* Rezerva pentru browsere fara `color-mix` (Safari mai vechi de 16.2, Chrome
   sub 111). Fara ea, cele trei trepte de mijloc ar fi complet transparente si
   matricea ar arata goala - iar cifrele ar rămâne singurul semn. Se pune
   INAINTE, ca declaratia cu color-mix sa o suprascrie unde se poate. */
@supports not (background: color-mix(in srgb, red 50%, transparent)) {
    .matrice td.mx-1 { background: var(--galben-palid); }
    .matrice td.mx-2 { background: var(--galben-palid); }
    .matrice td.mx-3 { background: var(--galben); }
}

@media print {
    /* Fundalurile nu se tipăresc implicit. Cifra rămâne oricum, iar căsuța cea
       mai plină primește contur ca să se vadă vârful și pe hârtie. */
    .matrice td.mx-4 { border: 2px solid #000; -webkit-print-color-adjust: exact;
        print-color-adjust: exact; }
}

/* ------------------------------------------------------ bare de distributie
   Pagina de demografie: cate persoane in fiecare grup. Bare ORIZONTALE, nu
   verticale ca in grafic - etichetele sunt cuvinte („sâmbătă", „25-34"), iar
   sub o bara verticala un cuvant trebuie fie rotit, fie taiat.

   Se desenează cu un grid de trei coloane, ca eticheta, bara si cifra sa fie
   aliniate pe toate rândurile. Cu float sau inline-block, o eticheta mai lunga
   ar impinge bara ei mai la dreapta decat pe celelalte, si comparatia dintre
   bare - singurul rost al desenului - ar devena inselatoare. */
.dist { display: grid; grid-template-columns: minmax(4.5rem, auto) 1fr auto;
    gap: .35rem .6rem; align-items: center; margin: .5rem 0 0; }

.dist-et { font-size: .9rem; }

.dist-bara { background: var(--gri-fundal); border: 1px solid var(--gri-linie);
    border-radius: 999px; height: 14px; overflow: hidden; }

.dist-umplere { height: 100%; background: var(--galben);
    /* Contur in dreapta: fara el, o bara galbena pe fundal deschis nu-si arata
       capatul, iar capatul este chiar informatia. Aceeasi regula ca la
       .progress-bar-fill. */
    border-right: 2px solid var(--galben-contur);
    border-radius: 999px;
    /* Latimea minima: un grup cu un singur om ar avea 0.4% si nu s-ar vedea
       deloc - ar arata ca zero, care e altceva. */
    min-width: 3px; }

.dist-nr { font-size: .9rem; font-variant-numeric: tabular-nums;
    white-space: nowrap; }

/* Grupul „prea puțini pentru a raporta": alta culoare, ca sa nu fie citit ca
   un grup demografic adevarat. */
.dist-umplere.dist-ascuns { background: var(--gri-linie); border-right-color: var(--gri); }

@media print {
    /* Barele se tiparesc: un raport demografic pe hartie fara bare este o
       coloana de cifre. Fundalurile insa nu se tiparesc implicit in niciun
       browser, deci umplerea ar ieși alba. Conturul o face vizibila oricum. */
    .dist-umplere { border: 1px solid #000; background: #ccc !important;
        -webkit-print-color-adjust: exact; print-color-adjust: exact; }
}

/* ------------------------------------------------- lista de produse la casa */
.products { display: grid; gap: .7rem; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); }

.product {
    /* Chenarul galben cerut pentru lista de produse. */
    border: 3px solid var(--galben);
    border-radius: var(--radius);
    background: var(--alb);
    padding: .7rem;
    text-align: left;
    font: inherit;
    cursor: pointer;
    display: flex;
    flex-direction: column;
    gap: .25rem;
    min-height: 92px;
}

.product:hover { background: var(--galben-palid); }
.product:focus-visible { outline: 3px solid var(--text); outline-offset: 2px; }
.product .name { font-weight: 700; line-height: 1.25; }
.product .price { color: var(--gri); font-size: .85rem; text-decoration: line-through; }
.product .final { font-weight: 800; }
.product.in-cart { border-color: var(--text); background: var(--galben-palid); }

/* Stocul pe butonul de la casa.
   Starea obisnuita este discreta: cu 100 de produse pe ecran, o sută de numere
   colorate ar fi zgomot. Cand mai sunt puține, aceeasi eticheta devine galbena
   si scrie „ultimele N" - altfel un numar mic printre numere mari ar trece
   neobservat la a douazecea scanare. */
.product-left {
    font-size: .72rem;
    font-weight: 600;
    color: var(--gri);
    letter-spacing: .01em;
}

.product-left.is-low {
    font-weight: 700;
    color: var(--ambra);
    text-transform: uppercase;
    background: var(--galben-palid);
    border: 1px solid var(--galben-inchis);
    border-radius: 4px;
    padding: 0 .25rem;
    align-self: flex-start;
}

/* „preț întreg", pe butonul unui produs din afara fidelizarii (migrarea 017).

   ACELASI DESEN CA `.product-left.is-low`, si dinadins: amandoua spun „la acest
   produs uita-te de doua ori". Un al treilea fel de a atrage atentia, cu alta
   culoare, ar face butoanele un carnaval in care nimic nu mai iese in evidenta.

   Nu e o eticheta de eroare: produsul se vinde perfect normal. De asta e galben
   („ia aminte"), nu roșu („s-a intamplat ceva rau"). */
.product-intreg {
    font-size: .72rem;
    font-weight: 700;
    color: var(--ambra);
    text-transform: uppercase;
    letter-spacing: .01em;
    background: var(--galben-palid);
    border: 1px solid var(--galben-inchis);
    border-radius: 4px;
    padding: 0 .25rem;
    align-self: flex-start;
}

/* „rămân 17" langa numele produsului, in coș. Arata cat va fi in vitrina DUPA
   ce se confirma coșul, deci casierul vede scaderea inainte sa apese. */
.cart-stock {
    font-size: .75rem;
    color: var(--gri);
    font-weight: 400;
    white-space: nowrap;
}

/* Poza mica de pe butonul de produs, la casa. */
.product-thumb {
    width: 100%;
    height: 58px;
    object-fit: cover;
    border-radius: 6px;
    background: var(--gri-fundal);
    margin-bottom: .15rem;
}
.product .badge {
    align-self: flex-start;
    background: var(--negru);
    color: var(--galben);
    border-radius: 999px;
    font-size: .75rem;
    font-weight: 700;
    padding: .05rem .5rem;
}

/* ------------------------------------------- catalogul de produse (client) */
.catalog {
    display: grid;
    gap: 1rem;
    grid-template-columns: repeat(auto-fill, minmax(215px, 1fr));
    margin-bottom: 1.25rem;
}

.catalog-item {
    display: flex;
    flex-direction: column;
    background: var(--alb);
    border: 3px solid var(--galben);
    border-radius: var(--radius);
    overflow: hidden;
    box-shadow: var(--umbra);
}

.catalog-image { position: relative; background: var(--gri-fundal); }

/* Raport fix, ca rândurile grilei să fie aliniate chiar dacă pozele
   încărcate au proporții diferite. */
.product-image {
    display: block;
    width: 100%;
    aspect-ratio: 4 / 3;
    object-fit: cover;
    background: var(--gri-fundal);
}

/* PLASTURELE PENTRU PRODUSELE FARA POZA
   -------------------------------------
   Inainte: acelasi desen de aparat de fotografiat pentru toate. Intr-o grila
   cu sase produse fara poza, aceea arata ca sase găuri identice.
   Acum: inițiala produsului, pe o nuanta derivata din numele lui. Culoarea si
   litera vin din PHP (vezi product_patch_html), pentru ca trebuie sa fie
   stabile pentru acelasi produs; aici rămâne doar așezarea. */
.product-patch {
    display: flex;
    align-items: center;
    justify-content: center;
    font-weight: 800;
    /* Litera se scaleaza cu latimea cartonasului, nu fix in pixeli: pe telefon
       cartonasele sunt mai inguste, iar o litera de 3rem ar ieși din ele. */
    font-size: clamp(1.6rem, 22cqw, 3.4rem);
    container-type: inline-size;
    line-height: 1;
    user-select: none;
}

/* Rezerva pentru browserele fara unitati de container (inainte de 2023): fara
   ea, `22cqw` nu inseamna nimic si litera rămâne la marimea moștenita. */
@supports not (container-type: inline-size) {
    .product-patch { font-size: 2.4rem; }
}

.product-image-thumb.product-patch { font-size: 1.1rem; }

/* Rezerva pentru browserele fara suport pentru aspect-ratio (inainte de 2021).
   Fara ea, poza s-ar afisa la inaltimea ei naturala si ar strica grila. */
@supports not (aspect-ratio: 4 / 3) {
    .product-image { height: 165px; }
}

.product-image-thumb {
    width: 96px;
    height: 72px;
    aspect-ratio: auto;
    border-radius: 8px;
    border: 2px solid var(--gri-linie);
    flex: 0 0 auto;
}

.catalog-badge {
    position: absolute;
    top: .5rem;
    left: .5rem;
    background: var(--negru);
    color: var(--galben);
    font-weight: 800;
    font-size: .85rem;
    padding: .1rem .5rem;
    border-radius: 999px;
}

.catalog-body { padding: .75rem .8rem .85rem; display: flex; flex-direction: column; flex: 1; }
.catalog-name { font-size: 1rem; margin: 0 0 .2rem; }
.catalog-desc { font-size: .82rem; color: var(--gri); margin: 0 0 .55rem; line-height: 1.4; }

.catalog-prices { margin: auto 0 0; display: flex; align-items: baseline; gap: .45rem; flex-wrap: wrap; }
.catalog-old { color: var(--gri); text-decoration: line-through; font-size: .88rem; }
.catalog-new { font-size: 1.2rem; font-weight: 800; }
.catalog-saved { font-size: .78rem; color: var(--gri); margin: .15rem 0 0; }

/* Ultimele bucati. Chenar galben, nu text rosu: nu este o eroare, este o
   informatie utila. */
.catalog-stock {
    font-size: .78rem;
    font-weight: 700;
    margin: .4rem 0 0;
    padding: .2rem .45rem;
    background: var(--galben-palid);
    border: 1px solid var(--galben-inchis);
    border-radius: 5px;
    align-self: flex-start;
}

/* ------------------------------------------------------- taburi de categorii

   Legaturi, nu butoane: pe telefon incap pe doua rânduri fara sa se
   inghesuie, iar tabul selectat se vede si fara culoare (are chenar plin si
   text ingrosat), pentru ecranele alb-negru si pentru cine nu distinge
   galbenul. */
.tabs {
    display: flex;
    flex-wrap: wrap;
    gap: .4rem;
    margin: 0 0 1rem;
}

/* Aceeasi clasa se foloseste si pe <a> (pagina clientului, legaturi) si pe
   <button> (casa, filtrare fara reincarcare). `font: inherit` este pentru
   butoane: fara el ar folosi fontul implicit al browserului si ar arata altfel
   decat taburile din pagina clientului. */
.tab {
    display: inline-flex;
    align-items: center;
    gap: .35rem;
    padding: .5rem .85rem;
    border: 2px solid var(--gri-linie);
    border-radius: 999px;
    background: var(--alb);
    color: var(--text);
    text-decoration: none;
    font: inherit;
    font-size: .92rem;
    font-weight: 600;
    cursor: pointer;
    /* Ținta de atins cu degetul pe tableta de la casa. */
    min-height: 2.6rem;
}

.tab:hover { border-color: var(--galben-inchis); background: var(--galben-palid); }
.tab:focus-visible { outline: 3px solid var(--galben); outline-offset: 2px; }

.tab.is-active {
    background: var(--galben);
    border-color: var(--text);
    font-weight: 800;
}

/* Tabul gol rămâne apasabil, dar se vede ca nu are nimic in el. */
.tab.is-empty { color: var(--gri); border-style: dashed; }

.tab-count {
    font-size: .78rem;
    font-weight: 700;
    padding: .05rem .4rem;
    border-radius: 999px;
    background: var(--gri-fundal);
    color: var(--text);
}

.tab.is-active .tab-count { background: var(--alb); }

/* ------------------------------------------------------------------- stoc */

/* Numarul de bucati in tabelul din administrare. Cifrele aliniate una sub
   alta se compara mult mai repede cu privirea. */
.stock-num {
    font-variant-numeric: tabular-nums;
    font-weight: 700;
    white-space: nowrap;
}

.stock-out { color: var(--roeu); }
.stock-low { color: var(--ambra); }

.stock-bar {
    display: block;
    height: 5px;
    margin-top: .25rem;
    border-radius: 3px;
    background: var(--gri-linie);
    overflow: hidden;
}

.stock-bar span {
    display: block;
    height: 100%;
    background: var(--negru);
}

/* Aceeasi culoare ca numarul de langa ea.
 *
 * Era #c98a00, scris fix - iar pe pista deschisa (--gri-linie, #e2e2e2) avea
 * 2,28:1, sub pragul de 3:1 pentru elemente grafice: nu se vedea cat de plina
 * este bara. Cu --ambra iese peste prag in ambele teme, si bara are exact
 * culoarea cifrei de langa ea. */
.stock-bar.is-low span { background: var(--ambra); }
.stock-bar.is-out span { background: var(--roeu); }

/* Arata ca o eticheta de câmp, dar nu este un <label>: bifele de dedesubt au
   fiecare propriul <label>, iar unul care nu duce nicaieri ar induce in eroare
   cititoarele de ecran. */
.label-like {
    display: block;
    font-weight: 600;
    margin: 0 0 .3rem;
    font-size: .92rem;
}

/* Formularul de adaugare de bucati, despartit de restul cardului. */
.stock-add {
    margin-top: .9rem;
    padding-top: .8rem;
    border-top: 1px solid var(--gri-linie);
}

/* Bifele de categorii din formularul de produs. */
.cat-picker {
    display: flex;
    flex-wrap: wrap;
    gap: .3rem .9rem;
    margin: .1rem 0 0;
}

.cat-picker .check { margin-bottom: .35rem; }
.cat-picker label { font-weight: 400; margin: 0; }

/* Eticheta cu numele categoriei, in listele de produse. */
.cat-tag {
    display: inline-block;
    font-size: .75rem;
    padding: .1rem .45rem;
    margin: 0 .2rem .2rem 0;
    border: 1px solid var(--gri-linie);
    border-radius: 999px;
    color: var(--text);
    white-space: nowrap;
}

/* ------------------------------------------- produsele in panoul de admin */
.product-admin-head { display: flex; gap: .8rem; align-items: flex-start; }
.product-admin-off { opacity: .72; }
.product-admin form { margin: 0; }
.product-admin .row { align-items: flex-end; }

/* --------------------------------- lista de produse care se expandeaza
 *
 * Randul are doua fete, una langa alta:
 *
 *   [ <details> - partea pe care se apasa ][ formular de stoc ]
 *
 * Formularul de stoc NU poate sta in <summary>: un click intr-un camp de text
 * pus acolo deschide sau inchide randul, diferit de la un browser la altul.
 * Deci sta ca frate al lui <details>, aliniat sus, langa sumar.
 */
.prod-filtru { padding: .8rem 1rem; margin: 0 0 1rem; }
.prod-filtru .row { align-items: flex-end; }

.prod-lista { display: flex; flex-direction: column; gap: .5rem; }

.prod-rand {
    display: flex;
    gap: .6rem;
    align-items: flex-start;
    /* var(--alb), ca .card. NU o variabila --card: aceea nu exista, si o
     * culoare inexistenta ar da un fundal transparent - randurile s-ar
     * amesteca intre ele, si in tema intunecata ar fi de necitit. */
    background: var(--alb);
    border: 1px solid var(--gri-linie);
    border-radius: var(--radius);
    padding: .5rem .7rem;
}
.prod-rand-off { opacity: .72; }

/* Cea care se apasa creste; formularul de stoc rămâne cat ii trebuie. */
.prod-det { flex: 1 1 auto; min-width: 0; }

.prod-sumar {
    display: flex;
    gap: .7rem;
    align-items: center;
    cursor: pointer;
    /* Zona de apasare pe telefon: tot randul, nu doar textul. */
    padding: .2rem 0;
    /* Triunghiul implicit al browserului rămâne, dar mutat la capat. */
    list-style-position: inside;
}
.prod-sumar::-webkit-details-marker { color: var(--gri); }

/* Miniatura de pe card are 96x72 - prea inalta pentru un rand de lista, ar face
 * lista de doua ori mai lunga decat trebuie. */
.prod-sumar .product-image-thumb { width: 56px; height: 42px; }

.prod-sumar-text { display: flex; flex-direction: column; gap: .15rem; min-width: 0; }
.prod-nume { font-weight: 700; }
.prod-meta {
    display: flex;
    flex-wrap: wrap;
    gap: .5rem;
    align-items: center;
    font-size: .85rem;
}
/* Bara de stoc, pe un rand cu numarul. Pe card era sub el. */
.prod-meta .stock-bar { width: 3.5rem; margin: 0 0 0 .3rem; }
.prod-meta .stock-num { display: inline-flex; align-items: center; }

.prod-corp {
    /* Aliniat cu textul din sumar, nu cu poza: altfel formularele ar porni de
     * sub miniatura si ar arata rupte. */
    padding: .7rem 0 .3rem;
    border-top: 1px solid var(--gri-linie);
    margin-top: .5rem;
}
.prod-corp form { margin: 0; }
.prod-corp .row { align-items: flex-end; }

.prod-stoc { flex: 0 0 auto; align-self: flex-start; }
.prod-stoc .row { align-items: center; gap: .3rem; }
.prod-stoc input[name="pieces"] { max-width: 6.2rem; }
.prod-stoc .check { margin: .3rem 0 0; }
.prod-stoc .check label { font-size: .72rem; color: var(--gri); }

/* Pe telefon formularul de stoc trece sub sumar: doua coloane pe un ecran de
 * 360px ar lasa numele produsului pe trei rânduri. */
@media (max-width: 34rem) {
    .prod-rand { flex-wrap: wrap; }
    .prod-det { flex-basis: 100%; }
    .prod-stoc { flex-basis: 100%; border-top: 1px dashed var(--gri-linie);
        padding-top: .5rem; }
}

/* --------------------------------------------------------------- scanner */
.scanner-frame {
    position: relative;
    background: var(--negru);
    border: 3px solid var(--galben);
    border-radius: var(--radius);
    overflow: hidden;
    aspect-ratio: 4 / 3;
}

.scanner-frame video { width: 100%; height: 100%; object-fit: cover; display: block; }

.scanner-frame .reticle {
    position: absolute;
    inset: 18%;
    border: 3px solid var(--galben);
    border-radius: 12px;
    pointer-events: none;
}

/* Chenarul de vizare pulseaza doar cat timp se scaneaza. */
body.scanning .scanner-frame .reticle { animation: pulse 1.4s ease-in-out infinite; }

@keyframes pulse {
    0%, 100% { box-shadow: 0 0 0 0 rgba(255, 212, 0, .55); }
    50%      { box-shadow: 0 0 0 10px rgba(255, 212, 0, 0); }
}

@media (prefers-reduced-motion: reduce) {
    body.scanning .scanner-frame .reticle { animation: none; }
}

.scan-status {
    margin: .8rem 0 0;
    padding: .55rem .7rem;
    border-radius: 8px;
    border: 2px solid var(--gri-linie);
    background: var(--gri-fundal);
    font-size: .9rem;
}

.scan-status-ok { border-color: var(--galben-inchis); background: var(--galben-palid); }
.scan-status-error { border-color: var(--roeu); background: var(--rosu-palid); }

/* Merge, dar nu ideal: camera frontala porneste, insa codul apare in oglinda.
   Chenar galben inchis, nu rosu - nu este o eroare. */
.scan-status-warn { border-color: var(--galben-inchis); background: var(--galben-palid); }

/* Verdictul verificarii: mare, ca sa fie citit de la un metru, fara sa se
   aplece casierul peste tableta. */
.scan-verdict {
    margin: .9rem 0 0;
    padding: .7rem .9rem;
    border-radius: 10px;
    border: 3px solid var(--text);
    font-size: 1.05rem;
    font-weight: 700;
    line-height: 1.35;
}

.scan-verdict.is-ok { background: var(--galben); border-color: var(--galben-inchis); }
.scan-verdict.is-error { background: var(--roeu); border-color: var(--roeu); color: var(--pe-negru); }

#soundToggle[aria-pressed="false"] { opacity: .65; }

#diagBox summary { cursor: pointer; }
#diagBox td:last-child, #diagBox th:last-child { white-space: nowrap; }

/* ------------------------------------- cautarea clientului dupa nume sau cod */
.search-field { position: relative; }

.suggestions {
    position: absolute;
    z-index: 30;
    left: 0;
    right: 0;
    top: calc(100% - 1.4rem);
    margin: .2rem 0 0;
    padding: 0;
    list-style: none;
    background: var(--alb);
    border: 3px solid var(--text);
    border-radius: var(--radius);
    box-shadow: 0 8px 24px rgba(0, 0, 0, .18);
    max-height: 330px;
    overflow-y: auto;
}

.suggestion {
    display: grid;
    grid-template-columns: auto 1fr;
    grid-template-areas: "badge name" "badge meta";
    gap: 0 .6rem;
    align-items: center;
    padding: .55rem .7rem;
    cursor: pointer;
    border-bottom: 1px solid var(--gri-linie);
}

.suggestion:last-child { border-bottom: none; }
.suggestion.is-active { background: var(--galben-palid); }

.suggestion-badge {
    grid-area: badge;
    align-self: center;
    background: var(--galben);
    border: 2px solid var(--galben-inchis);
    border-radius: 999px;
    font-weight: 800;
    font-size: .82rem;
    padding: .15rem .55rem;
    white-space: nowrap;
}

.suggestion-badge.is-reward { background: var(--negru); color: var(--galben); border-color: var(--text); }
.suggestion-name { grid-area: name; font-weight: 700; }
.suggestion-meta { grid-area: meta; font-size: .78rem; color: var(--gri); }

/* Pe ecrane mici lista ocupa toata latimea cardului, ca sa fie usor de atins. */
@media (max-width: 720px) {
    .suggestion { padding: .7rem; }
    .suggestion-name { font-size: 1rem; }
}

.scan-result { border: 3px solid var(--text); border-radius: var(--radius);
    background: var(--alb); padding: 1rem; }
.discount-big { font-size: 2.6rem; font-weight: 800; line-height: 1; }
.discount-big.reward { background: var(--negru); color: var(--galben);
    display: inline-block; padding: .1rem .6rem; border-radius: 8px; }

.pill { display: inline-block; border: 2px solid var(--text); border-radius: 999px;
    padding: .1rem .6rem; font-size: .8rem; font-weight: 700; }
.pill-on { background: var(--galben); }
.pill-off { background: var(--alb); color: var(--gri); border-color: var(--gri-linie); }

/* --------------------------------------------------------------- telefon */
@media (max-width: 720px) {
    .tema-toggle { order: 2; margin-left: auto; }
    .nav-toggle { display: block; order: 3; margin-left: .3rem; }
    .nav { display: none; width: 100%; order: 4; }

    /* Meniul deschis ține minte starea intre pagini (vezi includes/layout.php).
       Deci ramane deschis cat timp cineva umbla prin aplicație - si atunci
       merita sa fie o lista adevarata, nu butoane inghesuite pe un rand. */
    body.nav-open .nav {
        display: flex;
        flex-direction: column;
        gap: 0;
        margin-top: .5rem;
        border-top: 1px solid #333;
    }

    body.nav-open .nav a {
        /* 44px este minimul recomandat pentru o țintă de atins cu degetul.
           Sub atat, cine are mana mare sau e grabit nimereste alaturi - iar la
           casa, cu clienți in fata, asta costa timp. */
        min-height: 44px;
        display: flex;
        align-items: center;
        border-radius: 0;
        border: none;
        border-bottom: 1px solid #333;
        padding: .6rem .2rem;
        font-size: 1.05rem;
    }

    /* Pe telefon nu exista hover, deci `:hover` nu ajuta la nimic. Pagina
       curenta se vede dupa o dunga galbena in stanga - se citeste dintr-o
       privire, si nu muta textul. */
    body.nav-open .nav a.active {
        background: transparent;
        color: var(--galben);
        border-left: 4px solid var(--galben);
        padding-left: .6rem;
    }

    /* Pe telefon, partea dreapta trece pe un rand propriu, pe toata
       latimea: numele intr-un capat, Ieșire si butonul de tema in celalalt.
       Inainte regula era pe `.topbar-user`, un div care nu mai exista in HTML
       - deci pe telefon numele si butonul se inghesuiau langa navigare. */
    .topbar-right { order: 5; width: 100%; justify-content: space-between; }
    h1 { font-size: 1.45rem; }

    /* Bulinele, pe telefon: spatiu mai mic intre ele si text mai mic, ca sa
       incapa 12 pe un rand pe un ecran de 360px. */
    .progress { gap: .2rem; }
    .step { font-size: .85rem; }
    .step-reward { font-size: .7rem; }
    .container { padding: 1rem .8rem 2.5rem; }

    /* ------------------------------------------------------------------
       TABURILE SE DERULEAZA LATERAL, NU PE MAI MULTE RANDURI

       Pe desktop taburile trec pe rândul urmator (flex-wrap: wrap) si e
       bine: exista loc. Pe telefon, cu opt categorii, ar ieși trei rânduri
       de taburi care impinge produsele sub marginea ecranului - iar
       produsele sunt motivul pentru care cineva a deschis pagina.

       DOUA CAPCANE, amandoua rezolvate mai jos:

       1. CONTURUL DE FOCALIZARE SE TAIE.
          `overflow-x: auto` nu se poate combina cu `overflow-y: visible`:
          CSS le face pe amandoua `auto`. Deci conturul galben de la
          `:focus-visible`, care iese 2px in afara tabului, ar fi tăiat sus
          si jos - si cine navigheaza cu tastatura nu ar mai vedea unde
          este. Se lasa loc cu padding, si conturul incape.

       2. NU SE VEDE CA MAI URMEAZA CEVA.
          Un tab tăiat exact la marginea ecranului arata ca sfarsitul
          listei. `scroll-padding-right` plus faptul ca ultimul tab rămâne
          pe jumatate vizibil spun ochiului ca lista continua.
       ------------------------------------------------------------------ */
    .tabs {
        flex-wrap: nowrap;
        overflow-x: auto;
        /* Loc pentru conturul de focalizare, sus si jos. */
        padding: 3px 0;
        /* Derulare cu inerție pe iOS. Fara ea, degetul „se lipeste". */
        -webkit-overflow-scrolling: touch;
        /* Marginea din dreapta la derulare: ultimul tab nu se lipeste de
           marginea ecranului. */
        scroll-padding-right: 1rem;
    }

    /* Taburile nu se strâng: un nume lung rămâne pe un rand, altfel
       „Băuturi calde" s-ar rupe in doua si tabul ar ieși inalt. */
    .tab {
        flex: 0 0 auto;
        white-space: nowrap;
    }

    /* Bara de derulare: subtire, dar VIZIBILA. Ascunsa cu totul, nimic nu ar
       spune ca lista continua. */
    .tabs::-webkit-scrollbar { height: 4px; }
    .tabs::-webkit-scrollbar-thumb {
        background: var(--gri-linie);
        border-radius: 999px;
    }
}

/* --------------------------------------------------------------- tipărire

   TIPARIREA FOLOSESTE INTOTDEAUNA CULORI LUMINOASE.

   Fara blocul de aici, cineva care are tema intunecata si apasa „Tipărește"
   primeste TEXT ALB PE HARTIE ALBA: fundalul se forteaza pe #fff, dar culoarea
   textului vine din --text, care in tema intunecata este aproape alb.

   Rezultatul ar fi o foaie care pare goala - iar pe pagina codului QR, unde
   butonul de tipărire este chiar langa cod, s-ar intampla des.

   Se refac deci valorile luminoase, si pentru media query, si pentru
   suprascrierea manuala. `!important` nu este necesar: blocul este mai jos in
   fisier si are aceeasi specificitate, deci câștiga.
   ------------------------------------------------------------------------- */
@media print {
    :root, html.tema-intunecata, html.tema-luminoasa {
        color-scheme: light;
        --text: #111111;
        --alb: #ffffff;
        --gri: #6b6b6b;
        --gri-linie: #e2e2e2;
        --gri-fundal: #f6f6f6;
        --negru: #111111;
        --pe-negru: #ffffff;
    }

    .topbar, .footer, .btn { display: none; }
    body { background: #fff; color: #111; }
    .card { box-shadow: none; border: 1px solid #000; }
}

/* ----------------------------------------------------------------------
   COMUTATORUL DE LIMBA (paginile clientului)

   Butoane-legaturi, nu un <select>: un select cere doua atingeri pe telefon
   si nu se poate salva la favorite. Aici fiecare limba este o adresa.

   Se afiseaza doar cand exista cel putin doua limbi - vezi
   lang_switcher_html(), care intoarce sir gol altfel. Un buton care nu face
   nimic este mai rau decat niciun buton.
   ---------------------------------------------------------------------- */
.lang-switch {
    display: flex;
    gap: .3rem;
    justify-content: flex-end;
    margin: 0 0 .6rem;
}

.lang-opt {
    padding: .25rem .55rem;
    font-size: .82rem;
    border: 1px solid var(--gri-linie);
    border-radius: 6px;
    color: var(--gri);
    text-decoration: none;
    background: var(--alb);
}

.lang-opt:hover { border-color: var(--galben-inchis); background: var(--galben-palid); }
.lang-opt:focus-visible { outline: 3px solid var(--galben); outline-offset: 2px; }

.lang-opt.is-active {
    background: var(--galben);
    border-color: var(--galben);
    color: var(--pe-accent);
    font-weight: 600;
}

/* La tiparire nu are ce sa caute: hartia nu are butoane. */
@media print {
    .lang-switch { display: none; }
}

/* ----------------------------------------------------------------------
   ECRANELE FARA DATE

   Nu sunt o eroare, sunt un inceput - si arata altfel decat o eroare
   dinadins: fara roșu, fara chenar de avertisment. Centrat, cu spatiu in
   jur, ca sa nu para ca s-a rupt ceva.

   Vezi render_empty() in includes/layout.php.
   ---------------------------------------------------------------------- */
.empty {
    text-align: center;
    padding: 2.2rem 1.2rem;
    background: var(--alb);
    border: 1px solid var(--gri-linie);
    border-radius: 12px;
    margin: .8rem 0;
}

/* Semnul: un cerc cu litera sau simbolul dat. Nu o iconita desenata - o
   litera merge in orice font si nu are nevoie de SVG pe fiecare pagina. */
.empty-mark {
    width: 3rem;
    height: 3rem;
    margin: 0 auto .8rem;
    border-radius: 50%;
    background: var(--galben-palid);
    color: var(--galben-text);
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 1.5rem;
    font-weight: 800;
    line-height: 1;
}

.empty-title {
    font-size: 1.05rem;
    font-weight: 700;
    margin: 0 0 .3rem;
    color: var(--text);
}

.empty-text {
    color: var(--gri);
    font-size: .92rem;
    margin: 0 auto 1rem;
    /* Limita de latime: un rând de 90 de caractere se citeste greu, iar
       explicatia are voie sa fie o propozitie intreaga. */
    max-width: 34rem;
}

.empty .btn { margin-top: 0; }

@media print {
    .empty { border: none; }
    .empty .btn { display: none; }
}

/* ===========================================================================
 * ROATA PREMIILOR
 *
 * `conic-gradient` face feliile, o rotație face restul. Fara nicio biblioteca:
 * REVINO trebuie sa meargă fara internet.
 *
 * DIMENSIUNEA E IN `min()`, nu fixa: pe un telefon de 320px o roata de 300px ar
 * ieși din ecran, iar pe desktop una de 90vw ar fi absurda.
 * ======================================================================== */
.roata-cadru {
    position: relative;
    width: min(300px, 78vw);
    height: min(300px, 78vw);
    margin: 0 auto;
}

.roata-disc {
    width: 100%;
    height: 100%;
    border-radius: 50%;
    border: 4px solid var(--negru);
    box-shadow: var(--umbra);
    /* Fara `transition` la inceput, DINADINS: se pune din JS abia inainte de
     * rotire. Altfel prima desenare a paginii ar anima de la 0, iar roata ar
     * tresari la fiecare incarcare. */
}

/* BUTUCUL DIN MIJLOC, cu logoul firmei.
 *
 * Element frate cu discul, nu copil: rotația se pune pe `.roata-disc`, deci
 * orice copil s-ar fi rotit cu el - logoul cu capul in jos, de patru ori pe
 * invartire.
 *
 * `overflow: hidden` plus `border-radius: 50%` fac decupajul rotund, iar
 * `object-fit: cover` umple cercul.
 *
 * DE STIUT CAND ALEGI LOGOUL: `cover` TAIE. Un logo lat cu numele scris
 * („RESTAURANT EXEMPLU") isi pierde capetele si rămâne cu mijlocul - deci in
 * butuc arata bine un logo patrat sau o pictograma, nu un text lung. Butucul e
 * facut dinadins mare (38%), ca sa se salveze cat se poate dintr-un logo lat.
 *
 * Fara logo rămâne cercul alb, si e in regula: o roata adevarata ARE un butuc.
 * Nu se ascunde, ca desenul sa nu difere intre doua instalari. */
.roata-mijloc {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -50%);
    width: 38%;
    height: 38%;
    border-radius: 50%;
    overflow: hidden;
    background: var(--alb);
    border: 3px solid var(--negru);
    box-shadow: var(--umbra);
    /* Sub ac (z-index 2), peste disc. */
    z-index: 1;
}

.roata-mijloc img {
    display: block;
    width: 100%;
    height: 100%;
    object-fit: cover;
}

/* Acul, sus. Un triunghi din borduri - fara imagine, fara SVG. */
.roata-ac {
    position: absolute;
    top: -10px;
    left: 50%;
    transform: translateX(-50%);
    width: 0;
    height: 0;
    border-left: 11px solid transparent;
    border-right: 11px solid transparent;
    border-top: 20px solid var(--negru);
    z-index: 2;
    /* CONTUR ALB, ADAUGAT CAND FELIILE AU DEVENIT ACCENT + INCHIS.
     *
     * Acul e desenat in `--negru`, iar jumatatea lui de jos cade PESTE disc.
     * Cand felia de sus e tot `--negru` - se intampla la fiecare a doua
     * aranjare - acul dispare in ea, si atunci nu se mai vede pe ce s-a oprit
     * roata. `drop-shadow` merge pe triunghiul din borduri, unde o bordura
     * obisnuita n-ar avea unde sa se prinda. */
    filter: drop-shadow(0 0 1.5px var(--alb))
            drop-shadow(0 0 1.5px var(--alb));
}

/* ===========================================================================
 * PAREREA CLIENTULUI: cele cinci stele
 *
 * ARATA CA STELE, SUNT BUTOANE RADIO. Nu sunt desenate cu JavaScript: fiecare
 * stea e un `<input type="radio">` ascuns plus un semn. Deci se pot apasa cu
 * tastatura, le citeste un cititor de ecran, si formularul merge fara JS.
 *
 * Butonul e ascuns cu `position: absolute; opacity: 0`, NU cu `display: none`:
 * un element cu `display: none` nu poate primi focus, deci nu s-ar putea alege
 * o nota cu tastatura. Ascuns asa, primeste focus - iar conturul se pune pe
 * stea, prin `:focus-visible + .stea-semn`.
 *
 * Steaua aleasa se coloreaza cu `:checked`. Fara JS nu se pot colora si cele
 * de dinaintea ei (CSS nu poate merge inapoi printre frati), deci se coloreaza
 * DOAR cea aleasa, iar cifra de dedesubt spune limpede ce nota e - asa nu
 * rămâne nicio indoiala ca „a treia stea" inseamna 3.
 * ======================================================================== */
.stele {
    display: flex;
    gap: .35rem;
    margin: .2rem 0 .3rem;
}

.stea {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: .1rem;
    cursor: pointer;
    /* Suprafata de apasat: cel putin 44px, cat cere un deget pe telefon. */
    min-width: 2.75rem;
    padding: .3rem .1rem;
    border-radius: 8px;
    /* Eticheta e `label`, iar `label` are font-weight 600 mai sus. Steaua nu e
     * un nume de câmp, deci nu se ingroasa. */
    font-weight: 400;
    margin: 0;
}

.stea input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
    margin: 0;
}

.stea-semn {
    font-size: 2rem;
    line-height: 1;
    color: var(--gri-linie);
}

.stea-nr {
    font-size: .78rem;
    color: var(--gri);
}

.stea:hover .stea-semn { color: var(--galben-inchis); }
.stea input:checked ~ .stea-semn { color: var(--galben); }
.stea input:checked ~ .stea-nr { color: var(--text); font-weight: 700; }

.stea input:focus-visible ~ .stea-semn {
    outline: 2px solid var(--galben-contur);
    outline-offset: 2px;
    border-radius: 4px;
}

/* Un răspuns de-al meu, in lista de jos. Linie despartitoare intre ele, dar nu
 * dupa ultimul - altfel cardul pare tăiat la mijloc. */
.parere-rand {
    padding: .5rem 0;
    border-bottom: 1px solid var(--gri-linie);
}
.parere-rand:last-child { border-bottom: 0; padding-bottom: 0; }

.roata-lista { margin: .4rem 0 .8rem; padding-left: 1.2rem; }
.roata-lista li { margin-bottom: .25rem; }

/* LISTA DE PREMII CU POZE
 *
 * Clasa se pune pe <ul> DOAR cand cel putin un premiu are poza - hotararea se
 * ia o data, in PHP, nu pe fiecare rând. Vezi comentariul din roata.php.
 *
 * BULINELE SE SCOT: o bulina si o poza pe acelasi rând sunt doua semne pentru
 * acelasi lucru, iar bulina ajunge lipita de marginea pozei.
 *
 * Randul e `flex` cu `align-items: center`: numele produsului sta la mijlocul
 * pozei, nu sus. La un nume care se rupe pe doua randuri, centrat arata legat
 * de poza; aliniat sus arata ca doua elemente puse una lânga alta. */
.roata-lista-poze {
    list-style: none;
    padding-left: 0;
}

.roata-lista-poze li {
    display: flex;
    align-items: center;
    gap: .6rem;
    margin-bottom: .5rem;
}

/* 4:3 ca poza sa nu fie tăiată altfel decat in catalog - acolo e tot 4/3, deci
 * un produs arata la fel in ambele locuri. */
.roata-poza {
    flex: 0 0 auto;
    width: 64px;
    height: 48px;
    object-fit: cover;
    border-radius: 8px;
    border: 2px solid var(--gri-linie);
    background: var(--gri-fundal);
}

/* SLOTUL GOL, pentru premiul fara poza.
 *
 * Nu are nici fundal, nici margine, nici inițiala - DINADINS. Alegerea a fost
 * facuta explicit: cand produsul n-are poza, nu se deseneaza nimic.
 *
 * Slotul rămâne insa pe loc, ca textul tuturor randurilor sa porneasca din
 * acelasi punct. Intr-o lista de trei-cinci randuri, indentarea zimtata se
 * citeste ca o defecțiune; un gol de aceeasi mărime se citeste ca o poza care
 * lipsește. Nu e la fel de bine ca o poza, dar e ce a fost cerut - si e mai
 * puțin rau decat un plasture inventat pentru un produs nefotografiat.
 *
 * `background: none` si `border: 0` calca peste .roata-poza de mai sus: clasa
 * se pune pe amandoua ca dimensiunea sa fie scrisa intr-un singur loc. */
.roata-poza-lipsa {
    display: block;
    background: none;
    border: 0;
}

/* PREMIUL NERIDICAT, pe cardul de produs din lista clientului.
 *
 * Prețul vechi rămâne vizibil si tăiat: „gratis" fara prețul de dinainte nu
 * spune cat valorează premiul. */
.premiu-eticheta {
    display: inline-block;
    background: var(--negru);
    color: var(--pe-negru);
    font-size: .72rem;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .04em;
    padding: .12rem .4rem;
    border-radius: var(--radius);
}

/* CINE NU DESCHIDE ROATA SA NU FIE PACALIT DE MISCARE.
 *
 * `prefers-reduced-motion` este cerut de cei cu rau de mișcare sau migrene, si
 * o roata care se invarte trei secunde este exact ce evita. Rezultatul se vede
 * la fel - doar ca dintr-o data. */
@media (prefers-reduced-motion: reduce) {
    .roata-disc { transition: none !important; }
}

/* ------------------------------------------------- meniul complet, la casa */

/* Coloana cu poza, in tabelul din cashier/meniu.php.
 *
 * Latimea e FIXA, si de asta: fara ea, coloana ar fi cat cea mai lata poza din
 * grup, iar numele produselor ar porni de la alta margine in fiecare categorie.
 * Pe o pagina care se citește cu ochiul in timp ce clientul așteaptă, coloanele
 * care sar sunt cel mai greu de urmarit. */
.meniu-poza {
    width: 96px;
    padding-right: 0;
}

.meniu-poza .product-image-thumb {
    display: block;
    margin: 0;
}

/* Rândul unui produs care NU se poate vinde acum: epuizat sau oprit.
 *
 * SE ESTOMPEAZA, NU SE ASCUNDE - asta e tot rostul paginii: casierul trebuie
 * sa poata răspunde „avem, dar s-a terminat azi". Pentru asta produsul trebuie
 * sa fie pe ecran, doar sa nu arate ca unul disponibil.
 *
 * Opacitatea rămâne la .55, nu mai jos: sub atat, textul gri deschis din
 * descriere cade sub pragul de contrast din tests/culori.php - iar rândul ar
 * deveni exact ce nu trebuie, adica de necitit. */
.meniu-rand-off {
    opacity: .55;
}

.meniu-rand-off strong {
    text-decoration: line-through;
}

/* -------------------------------------------- istoricul bonurilor, la casa */

/* Filtrul de perioada. Acelasi desen ca `.prod-filtru`, si dinadins: amandoua
   sunt un rând de câmpuri deasupra unei liste lungi, iar doua feluri de a arata
   acelasi lucru fac aplicatia sa para cusuta din bucati. */
.bon-filtru { padding: .8rem 1rem; margin: 0 0 1rem; }
.bon-filtru .row { align-items: flex-end; }

/* Un bon. Mai strâns decat un card obisnuit: pe o pagina sunt douazeci, iar
   spatiile implicite ar face din derulare o treaba de un minut. */
.bon { padding: .8rem 1rem; margin-bottom: .6rem; }

.bon table { margin-top: .2rem; }

/* Totalurile de la piciorul bonului: despartite de linii, ca pe hartie.
   Cifrele aliniate una sub alta se compara cu privirea, fara sa fie citite. */
.bon tfoot td {
    border-top: 1px solid var(--gri-linie);
    font-variant-numeric: tabular-nums;
}

.bon tfoot tr:last-child td { border-top-width: 2px; }

/* Inainte / unde ești / mai vechi. Pe telefon cele trei se pun unul sub altul,
   ca butoanele sa rămână destul de mari pentru un deget. */
.bon-paginare { padding: .6rem 1rem; gap: .5rem; flex-wrap: wrap; }
