Naming

Design system-ul și codul vorbesc două limbaje diferite. Ambele sunt reale, ambele rămân tokenizate — dar de la 26 august 2026 limbajul canonic e cel de cod. Pagina asta e dicționarul, și e generată din tokens.semantics.json, nu scrisă de mână.

Două limbaje

Limbajul de design — nume de culori

--c-bej-1, --c-fog, --c-pink-tint. Astea sunt numele pe care le-a dat stakeholder-ul când a proiectat sistemul, și sunt numele corecte în camera în care se ia decizia: „tonalul e bej-1" e o propoziție despre culoare.

Limbajul de cod — nume de roluri

--muted, --muted-foreground, --accent. Convenția shadcn. Un rol supraviețuiește unei schimbări de valoare; un nume de culoare nu. --c-bej-1 devine o minciună în ziua în care suprafața tonală nu mai e bej.

Al doilea motiv, mai practic: o valoare poate purta două roluri. --c-white e și cardul și popover-ul; --c-bej-1 e și suprafața tonală și fill-ul secundar. În limbajul de culori sunt un token folosit în două locuri, deci nu poți schimba unul fără celălalt. În limbajul de roluri sunt două tokene care momentan au aceeași valoare.

Ce s-a decis

Canonic e limbajul de cod. Numele de rol e cel pe care îl scrii în componente noi, în contracte și în review. Numele de design nu se retrage: rămâne cheia tokenului, deci rămâne tokenizat și trasabil.

Dicționarul · tokens.semantics.json → role_name

sursa = JSON · generat de scripts/build-naming-dictionary.py

Suprafețe și text

Limbajul de designLimbajul de cod · canonicRolul
--c-bej-0--backgroundsuprafață pagină
--c-bej-05--muted-subtlehover de rând / listă — treapta dintre bej-0 și bej-1
--c-bej-1--mutedsuprafață tonală / control neutru
--c-fog--muted-foregroundtext secundar; focus ring
--c-ink--foregroundtext primar pe fundal deschis
--c-mist--placeholdertext terțiar / sufix
--c-white--cardsuprafață de bază

Brand

Limbajul de designLimbajul de cod · canonicRolul
--c-accent--primarybrand — stări interactive și acțiune principală
--c-accent-deep--primary-hoverbrand hover (alias)
--c-accent-tint--accentbrand tint (alias)
--c-accent-ultra--accent-subtlebrand wash (alias)

Linii și borduri

Limbajul de designLimbajul de cod · canonicRolul
--c-input-border--inputborder input și controale mici
--c-input-border-hover--input-hoverborder input/select/controale mici pe hover — două trepte peste --c-input-border
--c-input-border-tonal--input-tonalborder input/select pe varianta .tonal — treapta minimă peste 3:1, calibrată pe gazdă albă sau bej-0: fundalul bej-0 nu separă câmpul, deci conturul duce singur limita controlului
--c-rule--separatorseparator
--c-rule-card--borderborder container
--c-rule-hover--separator-hoverseparator pe hover — o treaptă peste --c-rule
--c-rule-soft--separator-subtleseparator discret

Acțiune distructivă

Limbajul de designLimbajul de cod · canonicRolul
--c-danger--destructivedestructive control fill

Familii de status

Limbajul de designLimbajul de cod · canonicRolul
--c-ai--aiprocesat / generat de AI — fill, stroke și text
--c-ai-bg--ai-subtlefundal AI
--c-ai-grad--ai-gradientgradient AI
--c-error--errormesagerie de eroare — fill / stroke
--c-error-bg--error-subtlefundal de mesaj de eroare
--c-error-text--error-subtle-foregroundtext de eroare — singurul token de text al familiei
--c-read--readstatus "citit / văzut" — fill
--c-read-bg--read-subtlefundal status "citit"
--c-read-text--read-subtle-foregroundtext status "citit" pe tint
--c-success--successstatus pozitiv — fill / stroke
--c-success-bg--success-subtlefundal status pozitiv
--c-success-text--success-subtle-foregroundtext status pozitiv — singurul token de text al familiei
--c-warn--warningstatus de atenție — fill / stroke
--c-warn-bg--warning-subtlefundal status de atenție
--c-warn-text--warning-subtle-foregroundtext status de atenție — singurul token de text al familiei

Overlay

Limbajul de designLimbajul de cod · canonicRolul
--c-backdrop--overlayscrim canonic — dim în spatele oricărui overlay de tip modal
--scrim-blur--overlay-blurscrim canonic — blur în spatele oricărui overlay de tip modal, pereche cu --c-backdrop

Altele

Limbajul de designLimbajul de cod · canonicRolul
--layout-max--layout-max-widthlățimea maximă a layout-ului funcțional pe desktop

Fără nume de rol, deliberat

Tokenele astea rămân doar în limbajul de design, iar motivul e declarat în tokens.semantics.json. Lista nu e o restanță: e o decizie per token, și un token nou nu poate intra în sistem fără una.

TokenDe ce nu are rol
--c-darkAlias deprecat al fill-ului destructiv; pastrat doar pentru paginile inghetate din doc-originale. Rolul e --destructive, pe --c-danger.
--c-dark-midStop intermediar intr-un gradient decorativ (avatar). Nu e un rol semantic — nimic nu il alege pentru ce inseamna.
--c-pdf-hlHighlight de selectie in PDF viewer. Suprafata unica a unei singure componente; un nume de rol ar sugera reutilizare.
--c-pinkValoare de paletă, nu rol. --primary punteaza pe --c-accent, care aliaseaza acest token; brandul isi pastreaza numele ca sa rămână evident ce culoare e.
--c-pink-deepValoare de paletă — rolul e --primary-hover, purtat de --c-accent-deep.
--c-pink-tintValoare de paletă — rolul e --accent, purtat de --c-accent-tint.
--c-pink-ultraValoare de paletă — rolul e --accent-subtle, purtat de --c-accent-ultra.
--c-rule-soft-solidAcelasi caz ca --c-rule-solid, pentru --c-rule-soft. Rolul e --separator-subtle.
--c-rule-solidFallback opac pentru --c-rule, folosit unde alpha nu compune corect (peste imagini/gradient). Acelasi rol, mecanism diferit — rolul e --separator.
--c-selectionNu are corespondent în limbajul aplicației, și nu dintr-o scăpare: shadcn/ui nu are un token de selecție. Controalele lui poartă utilitarele `selection:bg-primary` / `selection:text-primary-foreground`, adică refolosesc tokenul de BRAND pentru un gest care nu e al aplicației — exact defectul pentru care există tokenul ăsta. Deci nu există un nume de rol pe care să-l revendice; ce trebuie făcut la adopție e opusul, se ȘTERG clasele alea de pe controale (vezi react/README.md). Dacă aplicația își dă vreodată un nume propriu pentru banda de selecție, exempțiunea se înlocuiește cu `role_name`.

Gramatica familiilor de status

Fiecare familie primește aceleași patru sloturi, ca să nu fie nimic de ținut minte per familie:

--<familie>                        fill saturat — text alb pe el
--<familie>-foreground             albul acela
--<familie>-subtle                 tint-ul
--<familie>-subtle-foreground      textul pe tint

Familii: error, warning, success, read, ai. ai are doar trei sloturi, deliberat — --c-ai trece AA ca text pe toate suprafețele DS (cel mai prost caz 5.11), deci nu-i trebuie token de text separat și nu se bate unul „pentru simetrie". Excepția e acum vizibilă în nume, nu îngropată într-un anti-pattern.

Unde shadcn nu ajunge

  • shadcn nu are familii de status. Livrează --destructive și nimic altceva. Bono are cinci. Deci nu adoptăm lista de tokene shadcn — adoptăm gramatica (rol + -foreground) și o extindem.
  • --destructive nu e roșu. La Bono acțiunea distructivă e neagră (--c-danger, ink), iar roșul e rezervat mesageriei de eroare (--error). În shadcn cele două sunt același token. Aici sunt două, și nu sunt niciodată interschimbabile.
  • Feedback-ul rămâne pe numele Bono. shadcn are doar Alert (inline) plus toast; nu are nicio primitivă de banner la nivel de pagină. Cele trei niveluri Bono — .alert inline, .banner la nivel de pagină/flow, .page-banner global — sunt mai bogate decât convenția, deci convenția cedează. Vezi docs/feedback.md.
  • --placeholder, --separator*, --input-tonal, --overlay* sunt extensii locale: roluri reale în Bono pentru care shadcn nu are nume.

Invariantul

Fiecare token cu semantică are ori role_name, ori role_name_exempt cu un motiv scris. Nu ambele, niciodată niciunul. Două tokene nu pot revendica același nume de rol.

Consecința e cea care contează: un token nou nu poate intra în sistem fără ca cineva să decidă în ce limbaj trăiește. Garda e scripts/build-naming-dictionary.py --check, în CI lângă celelalte. Dacă pagina rămâne în urmă față de JSON, CI-ul pică — la fel ca foundation-colors.html, care a rămas în urmă de două ori exact pentru că își scria valorile de mână.