Icons

Un singur set — Lucide, grila 24×24 — printr-o singură clasă, .ic. Markup-ul poartă glifa copiată verbatim din assets/icons/; CSS-ul decide mărimea și grosimea liniei (optică, pe trepte). Așa nu poate deriva: înainte de 2026-09-10 sistemul avea 111 desene diferite, 6 grile și 9 grosimi, iar „warning" exista în patru variante.

Markup canonic · components/foundation-icons.json

sursa = JSON · generat de scripts/build-catalog.py · glifa = assets/icons/triangle-alert.svg

Specificația — ce e în markup, ce e în CSS

CeValoareDe unde
glifăLucide, copiată verbatimassets/icons/<nume>.svg — niciodată redesenată sau editată
grilăviewBox="0 0 24 24"markup — grila Lucide, cu 2px padding optic
grosimeîn pixeli de ecran, optic pe trepte: 12→1.25 · 14→1.5 · 16→1.5 · 18→1.75 · 20→1.75 · 24→2stroke-width pe fiecare clasă de mărime + vector-effect: non-scaling-stroke. În markup rămâne stroke-width="2" (valoarea Lucide) — CSS-ul o suprascrie
mărime.ic.xs 12 · .ic.sm 14 · .ic 16 · .ic.md 18 · .ic.lg 20 · .ic.xl 24CSS — clasa din scară, sau regula părintelui: în .btn și .toggle iconul poartă doar .ic și treapta părintelui îi dă mărimea (vezi „În butoane"). Nu atributele width/height
culoarecurrentColortextul de lângă icon — deci urmează automat tokenul -text al familiei. Pattern-ul de culoare: docs/foundation.md § Iconuri
a11yaria-hidden="true"iconul e decorativ, sensul e în text. Pe un control icon-only, aria-label stă pe buton, nu în SVG

Ancora e 16px: în playground-ul Lucide, Size 16 · Stroke 1.5 · Absolute stroke width ON. Celelalte trepte urcă sau coboară optic în jurul ei, iar la 24 linia e 2px — glifa Lucide exact așa cum e desenată.

Scara de mărimi — 12 / 14 / 16 / 18 / 20 / 24

Șase trepte, aceeași glifă, linia urcă optic cu mărimea (1.25 → 2px). Mărimea e o clasă; contextele care își știu mărimea (.btn, .toggle) o impun singure, pe treaptă, și acolo iconul poartă doar .ic. .ic.xs (12) există pentru treapta .xs a butonului și pentru text de 12px — nu pentru „mai mic că încape".

.ic.xs · 12
.ic.sm · 14
.ic · 16
.ic.md · 18
.ic.lg · 20
.ic.xl · 24

Grosimea liniei — optică, pe trepte, în pixeli de ecran

Un SVG își scalează linia odată cu desenul: stroke-width="2" pe grila 24 înseamnă 2px doar la 24 — la 16 dă 1.33, la 12 dă 1.0, subțire și tulbure pe ecran 1x. Nici o linie fixă nu merge: 1.5px absolut la orice mărime e 12% din icon la 12px și 6% la 24 — mic și îndesat, mare și palid. .ic pune linia în pixeli de ecran și o urcă optic, ca greutatea unei litere pe corpuri diferite: 1.25 / 1.5 / 1.5 / 1.75 / 1.75 / 2 pentru 12 / 14 / 16 / 18 / 20 / 24 (10% → 8% din icon).

cu .ic — optic: 1.25 / 1.5 / 1.5 / 1.75 / 1.75 / 2 (DS)
fără .ic — linia se scalează cu desenul (ce aveam înainte)

În butoane — butonul deține mărimea iconului

În .btn iconul poartă doar .ic. Treapta butonului îi dă mărimea, exact cum îi dă și font-size — o regulă pe treaptă în bono-ds.css, nimic în markup. Două scări: lângă text iconul urmărește litera; singur în cerc (.icon-only) stă o treaptă mai sus, ca să umple constant ~45-53% din buton. scripts/check-icons.py pică pe un .ic.sm/.md/.lg pus într-un buton.

TreaptăButon · textIcon lângă textIcon-onlyLinie
.btn.xs26px · 12px12121.25px
.btn.sm30px · 13px14161.5px
.btn40px · 14px16181.5px · 1.75px
.btn.lg44px · 16px20201.75px
icon-only · 12 / 16 / 18 / 20
lângă text · 12 / 14 / 16 / 20
distructiv · aceeași scară

Înainte de 2026-09-10 icon-only avea două valori (14 pe .xs/.sm, 18 pe implicit/.lg) — .xs citea aglomerat, .lg gol — iar butonul cu text nu-și dimensiona iconul deloc: un glif de 16px stătea și în 26, și în 44 de pixeli.

În context — culoarea vine din text

Adresa de facturare lipsește. Iconul ia --c-warn-text de la textul alertei — nu are nevoie de o culoare proprie.
trust = verde sau neutru, niciodată brand

Setul — assets/icons/

Doar glifele pe care le folosește sistemul. Lipsește una? O copiezi de pe lucide.dev în assets/icons/<nume>.svg, verbatim, și rulezi scripts/check-icons.py --write — grila de mai jos se regenerează singură. Nu se editează de mână.

arrow-left
arrow-right
bell
bold
book
calendar
camera
check
chevron-down
chevron-left
chevron-right
circle-alert
circle-arrow-right
circle-question-mark
circle-x
clock
columns-2
compass
copy
credit-card
database
download
ellipsis
eye
file
file-text
file-up
globe
house
info
italic
layers
layout-dashboard
layout-template
log-in
log-out
mail
menu
message-circle
pencil
plus
receipt
rows-2
save
search
settings
shield
text-align-center
text-align-end
text-align-start
trash-2
triangle-alert
type
upload
user
x

Reguli

  • Nu desena și nu edita o glifă. Fiecare icon e Lucide, copiat verbatim în assets/icons/. scripts/check-icons.py pică pe orice <svg stroke="currentColor"> care nu e o glifă vendorizată.
  • Nu regla grosimea din markup. stroke-width="2" rămâne (valoarea Lucide); clasa de mărime o randează pe scara optică (1.25 → 2px pe ecran). Alt număr = cineva a încercat să repare local deriva pe care CSS-ul a rezolvat-o deja.
  • Nu dimensiona din atribute și nu pune o mărime în buton. Mărimea e o clasă din scară; în .btn iconul poartă doar .ic și treapta butonului decide. Excepție: referințele -aligned, unde lint-ul #13 cere încă width/height pe un SVG din <button> — acolo atributul oglindește clasa, nu o contrazice.
  • O singură grilă: 24. O cale desenată pe 16 sau 20 nu va sta niciodată pe aceeași mărime optică lângă una Lucide.
  • O singură bibliotecă. Fără Heroicons / Feather / Material / Phosphor „doar pentru unul". Lucide are 1700+; dacă chiar lipsește, glifa se desenează pe grila și în stilul Lucide și intră ca schimbare de DS.
  • Stroke, nu fill. Lucide e stroke-only; o formă umplută citește ca altă familie. Fill au doar punctul din chipul de status și steagurile din .money-input — care nu sunt iconuri.
  • Culoarea nu e a iconului. currentColor ia culoarea textului de lângă el, deci tokenul -text al familiei. Iconurile de trust (lacăt, scut, ochi, semnătură) — --c-success sau neutru, niciodată brand. Pattern-ul complet: docs/foundation.md § Iconuri.