Design system
Design system

Fondations

Le vocabulaire du système — 239 tokens sur 268, générés depuis tokens/Desktop.tokens.json par npm run tokens. Les 29 autres décrivent un objet plutôt que le système : ils sont documentés dans Composants. Rien sur cette page n'est écrit en dur : chaque valeur affichée est lue dans la variable CSS correspondante.

Couleurs

Les descriptions viennent de Figma. Elles portent les ratios de contraste mesurés — c'est la doctrine d'usage du système, pas de la décoration.

Fonds

  • --color-bg-default#FFFFFF ← --ramp-white

    The page ground. This system stays on white; there is no dark mode.

  • --color-bg-surface#F3F0FF ← --ramp-accent-25

    Lavender mist. Raised surfaces that sit on the ground: cards, inputs, dialogs.

  • --color-bg-section#ECE1FF ← --ramp-accent-50

    Section lavender. Tints a whole region or slide, never a card. Supports the brand's one-tint-per-section rule.

  • --color-bg-feature#3F2BFF ← --ramp-accent-500

    A full-bleed indigo panel. Use white text on it (7.00:1).

  • --color-bg-celebrate#E1FF91 ← --ramp-highlight-200

    A full-bleed lime panel, reserved for genuine celebration. Use default text on it (12.32:1).

  • --color-bg-neutral#F3F2F5 ← --ramp-neutral-100

    Fond neutre teinté : une barre d’onglets, un panneau. Ne remplace pas bg/surface.

  • --color-bg-selection#D8D2FF ← --ramp-accent-100

    Fond du texte sélectionné.

Bordures

  • --color-border-default#D8D2FF ← --ramp-accent-100

    Pale lavender hairline, never grey. Aliases color/accent/100 since 27/08, when it was darkened so a chip could be seen at all: with no border, an unselected chip on the page ground was literally invisible. Decorative only at 1.44:1 on white — never let a border be the sole separator between two pieces of content. It does not reach the 3:1 that WCAG 1.4.11 asks of the visible boundary of a control; in this ramp only accent/300 does (3.23:1), at the price of a far more present indigo on all 33 places that read this variable.

  • --color-border-strong#E4E1E8 ← --ramp-neutral-300

    The heavier rule used to frame a photograph.

  • --color-border-focus#3F2BFF ← --ramp-accent-500

    The keyboard focus ring. 7.00:1 on the ground, well past the 3:1 asked of UI boundaries.

  • --color-border-subtle#D8D2FF ← --ramp-accent-100

    Trait décoratif, jamais seul séparateur.

  • --color-border-focus-on-accent#FFFFFF ← --ramp-white

    Anneau de focus sur un fond indigo.

  • --color-border-danger#DC2626 ← --ramp-red-500

    Contour d’un champ en erreur.

  • --color-border-control#665BFF ← --ramp-accent-400

    Le contour visible d’un champ, d’une case ou d’un chip. 3:1 minimum sur le sol, la surface et la section (4,66 / 4,15 / 3,72).

  • --color-border-accent#3F2BFF ← --ramp-accent-500

    Liseré d’accent : le contour d’un tag.

  • --color-border-hover#A9A5B0 ← --ramp-neutral-500

    Bordure d’un champ survolé. Décorative : 2,41:1 sur le sol.

Feedback

  • --color-feedback-warning-bg#FFF3D1 ← --ramp-sun-100

    Teinte pâle de la famille.

  • --color-feedback-warning-border#FFD264 ← --ramp-sun-300

    Contour décoratif de la famille.

  • --color-feedback-warning-text#6B4403 ← --ramp-sun-800

    Texte sur la teinte pâle et sur le sol.

  • --color-feedback-warning-solid#F7BA2E ← --ramp-sun-400

    Pastille, icône, remplissage fort.

  • --color-feedback-info-bg#DDF7F3 ← --ramp-teal-100

    Teinte pâle de la famille.

  • --color-feedback-info-border#84DDD1 ← --ramp-teal-300

    Contour décoratif de la famille.

  • --color-feedback-info-text#0E524D ← --ramp-teal-800

    Texte sur la teinte pâle et sur le sol.

  • --color-feedback-info-solid#22A89B ← --ramp-teal-500

    Pastille, icône, remplissage fort.

  • --color-feedback-success-bg#E4F6E9 ← --ramp-green-100

    Teinte pâle de la famille.

  • --color-feedback-success-border#9CDDAF ← --ramp-green-300

    Contour décoratif de la famille.

  • --color-feedback-success-text#205433 ← --ramp-green-800

    Texte sur la teinte pâle et sur le sol.

  • --color-feedback-success-solid#48A66B ← --ramp-green-500

    Pastille, icône, remplissage fort. Pas du texte courant : 3,02:1 sur le sol.

  • --color-feedback-danger-bg#FFECE9 ← --ramp-red-100

    Teinte pâle de la famille.

  • --color-feedback-danger-border#FFB5AC ← --ramp-red-300

    Contour décoratif de la famille.

  • --color-feedback-danger-text#801F1B ← --ramp-red-800

    Texte sur la teinte pâle et sur le sol.

  • --color-feedback-danger-solid#DC2626 ← --ramp-red-500

    Pastille, icône, astérisque, texte court : le rouge plein. 4,83:1 sur le sol.

Texte

  • --color-text-default#2F2D2E ← --ramp-neutral-900

    Warm near-black, never pure black. 13.67:1 on the ground.

  • --color-text-muted#6A676D ← --ramp-neutral-600

    The one quiet text step. 5.56:1 on the ground, 4.96:1 on surface. On section lavender it is 4.45:1 — large text only there.

  • --color-text-accent#3F2BFF ← --ramp-accent-500

    Accent text: links, eyebrows, numerals. Safe at body size (7.00:1 on the ground).

  • --color-text-on-accent#FFFFFF ← --ramp-white

    Text on an indigo fill. 7.00:1.

  • --color-text-on-accent-soft#D8D2FF ← --ramp-accent-100

    Secondary text on an indigo fill. 4.86:1 — passes, but leave it for supporting copy.

  • --color-text-on-highlight#2F2D2E ← --ramp-neutral-900

    Text on a lime fill. 12.32:1.

  • --color-text-disabled#A9A5B0 ← --ramp-neutral-500

    Texte d’un élément inactif. 2,41:1, exempté : jamais pour du contenu.

  • --color-text-on-danger#FFFFFF ← --ramp-white

    Texte sur un fond de danger.

  • --color-text-on-success#2F2D2E ← --ramp-neutral-900

    Texte sur un fond de succès.

  • --color-text-on-warning#2F2D2E ← --ramp-neutral-900

    Texte sur un fond d’avertissement.

  • --color-text-accent-hover#3525E5 ← --ramp-accent-600

    Texte d’accent survolé. 8,24:1 sur le sol.

  • --color-text-secondary#4A4750 ← --ramp-neutral-700

    Texte courant dense : le corps d’un dialogue. 9,10:1 sur le sol. Entre text/default et text/muted.

Rampe neutre

  • --ramp-neutral-100#F3F2F5

    Tinted fill, wireframe fill.

  • --ramp-neutral-200#EDECEF

    The backdrop around a slide.

  • --ramp-neutral-300#E4E1E8

    Image frame, wireframe border.

  • --ramp-neutral-400#C9C5D0

    Wireframe line. Not a text colour.

  • --ramp-neutral-500#A9A5B0

    2.41:1 on white — decorative only. Never use for text, at any size.

  • --ramp-neutral-600#6A676D

    The quiet text step. See color.text.muted.

  • --ramp-neutral-700#4A4750

    Dense body copy. 9.10:1 on the ground.

  • --ramp-neutral-800#3D393E

    Text on a neutral-100 fill. 10.16:1.

  • --ramp-neutral-900#2F2D2E

    The primary ink. See color.text.default.

Rampe accent — indigo

  • --ramp-accent-25#F3F0FF

    Teinte pâle de l’accent. Valeur de bg/surface.

  • --ramp-accent-50#ECE1FF

    Teinte de l’accent. Valeur de bg/section.

  • --ramp-accent-100#D8D2FF

    Tinted fill behind accent text; secondary ink on indigo.

  • --ramp-accent-200#B2A8FF

    Derived step.

  • --ramp-accent-300#8C7DFF

    Chart tints, muted accents.

  • --ramp-accent-400#665BFF

    Derived step.

  • --ramp-accent-500#3F2BFF

    The brand indigo. Everything accent runs through this.

  • --ramp-accent-600#3525E5

    Hover state for indigo fills.

  • --ramp-accent-700#2C1ECC

    Pressed state for indigo fills.

  • --ramp-accent-800#1C0991

    Text on an accent-100 fill. 9.74:1.

  • --ramp-accent-900#0D0759

    Derived step, deepest.

Rampe highlight — lime

  • --ramp-highlight-100#F3FFD7

    The palest lime fill.

  • --ramp-highlight-200#E1FF91

    The brand lime. This ramp's base sits at 200, not 500, because the lime is a surface and not an ink.

  • --ramp-highlight-300#CFED7B

    Derived step.

  • --ramp-highlight-400#B6D558

    Derived step.

  • --ramp-highlight-500#9EBA41

    Derived step. Not the brand value — see 200.

  • --ramp-highlight-600#7E972A

    Derived step.

  • --ramp-highlight-700#60741A

    Derived step.

  • --ramp-highlight-800#44530E

    Text on a highlight-100 fill. 8.07:1. Reach here when lime has to carry text.

  • --ramp-highlight-900#2B3505

    Derived step, deepest.

Typographie

Familles

  • "Poppins", system-ui, sans-serif--font-family-heading

    Geometric sans, set at bold. Headings, buttons, brand marks. Free from Google Fonts; already in the Google Slides font picker.

  • "Inter", system-ui, -apple-system, sans-serif--font-family-body

    Neo-grotesque. Body copy and everything in the interface. Free from Google Fonts.

Graisses

  • Concevoir, tester, décider — puis recommencer.--font-weight-regular — 400
  • Concevoir, tester, décider — puis recommencer.--font-weight-medium — 500
  • Concevoir, tester, décider — puis recommencer.--font-weight-semibold — 600
  • Concevoir, tester, décider — puis recommencer.--font-weight-bold — 700

Échelle de tailles

  • Concevoir, tester, décider — puis recommencer.--font-size-display — 2.625rem

    H1, and the headline on a title slide.

  • Concevoir, tester, décider — puis recommencer.--font-size-title — 2rem

    H2, and a section divider slide.

  • Concevoir, tester, décider — puis recommencer.--font-size-subtitle — 1.5625rem

    H3.

  • Concevoir, tester, décider — puis recommencer.--font-size-heading — 1.25rem

    H4, and a dialog title.

  • Concevoir, tester, décider — puis recommencer.--font-size-brand — 1.125rem

    The wordmark in a header bar.

  • Concevoir, tester, décider — puis recommencer.--font-size-body-lg — 1.0625rem

    A lead paragraph, one notch above body.

  • Concevoir, tester, décider — puis recommencer.--font-size-subheading — 1rem

    H5.

  • Concevoir, tester, décider — puis recommencer.--font-size-body — 0.9375rem

    The default reading size.

  • Concevoir, tester, décider — puis recommencer.--font-size-ui — 0.875rem

    Buttons, inputs, nav links, table cells. Deliberately one size so a button and a field sit level side by side.

  • Concevoir, tester, décider — puis recommencer.--font-size-body-sm — 0.8125rem

    Dense body copy, card body, and the H6 eyebrow. H6 and small body share this size — that is intentional, not a duplicate.

  • Concevoir, tester, décider — puis recommencer.--font-size-caption — 0.75rem

    Field labels.

  • Concevoir, tester, décider — puis recommencer.--font-size-label — 0.6875rem

    Table headers, card metadata, figure captions. Anything at this size must use text.default or text.muted — nothing dimmer passes AA here.

  • Concevoir, tester, décider — puis recommencer.--font-size-micro — 0.625rem

    The uppercase kicker on a card. The smallest size in the system.

Interlignes

  • Concevoir, tester, décider — puis recommencer. Un système de design ne vaut que par ce qu'il rend évident au moment de décider. Concevoir, tester, décider — puis recommencer.

    --font-line-height-tight — 1.12
  • Concevoir, tester, décider — puis recommencer. Un système de design ne vaut que par ce qu'il rend évident au moment de décider. Concevoir, tester, décider — puis recommencer.

    --font-line-height-snug — 1.2
  • Concevoir, tester, décider — puis recommencer. Un système de design ne vaut que par ce qu'il rend évident au moment de décider. Concevoir, tester, décider — puis recommencer.

    --font-line-height-body — 1.55

Interlettrages

  • Interlettrage--font-letter-spacing-tight — -0.015em
  • Interlettrage--font-letter-spacing-normal — 0em
  • Interlettrage--font-letter-spacing-wide — 0.02em
  • Interlettrage--font-letter-spacing-wider — 0.08em
  • Interlettrage--font-letter-spacing-widest — 0.1em

Espacements

Rayons

Contrôles

La géométrie d'un contrôle de formulaire — ce qu'un espacement ne sait pas dire. Une case à cocher n'a pas la taille d'un écart, et une piste d'interrupteur n'a pas celle d'un rembourrage : ces trois mesures ont leur propre famille parce qu'elles décrivent un objet qu'on vise, pas un intervalle entre deux choses.

Elles sont peu nombreuses et c'est voulu : tout ce qui se compose depuis un espacement reste composé. La largeur d'une piste vaut space/xl + space/lg — 40 exactement — et n'a donc pas de variable.

Traits

Deux crans, et rien de plus : le trait au repos, et la marque de focus. Le fichier Figma en dessinait un troisième — 1,5, sur les deux zones de dépôt — quand 1 est dessiné 217 fois ailleurs. Un même geste fait deux fois n'est pas une échelle, et les deux nœuds ont été redessinés.

Opacités

Une seule valeur, pour un seul rôle : ce qu'un objet désactivé perd. Le fichier en dessinait trois — 0,4 sur les contrôles compacts, 0,5 sur les surfaces, 0,6 sur les champs de texte — pour la même intention. Elles ont été ramenées à une.

Elle se stocke en pourcentage dans Figma, comme un interligne : c'est ce que la liaison de variable attend côté dessin. npm run tokens divise par 100.

Ombres

Figma n'a pas de type de variable « ombre » : une variable y est couleur, nombre, texte ou booléen. Chaque partie est donc nommée seule et liée à l'effet dans le fichier — le dessin et le code lisent la même valeur, et rien ne peut diverger. npm run tokens les remet bout à bout. Un composant utilise la ligne composée, jamais les parties.

La couche de contact

Toutes les ombres du système posent la même seconde couche, très près de la surface. Ce n'est pas une ombre : elle est nommée une fois et entre dans chacune des précédentes.

  • --shadow-contact-y1px

    Vertical offset. The contact layer, shared by every shadow in the system. It is also shadow/sm on its own — the faintest lift there is. Tinted with the text ink, never black.

  • --shadow-contact-blur2px

    Blur radius. The contact layer, shared by every shadow in the system. It is also shadow/sm on its own — the faintest lift there is. Tinted with the text ink, never black.

  • --shadow-contact-spread0px

    Spread. The contact layer, shared by every shadow in the system. It is also shadow/sm on its own — the faintest lift there is. Tinted with the text ink, never black.

  • --shadow-contact-colorrgb(47 45 46 / 0.04)

    The contact layer, shared by every shadow in the system. It is also shadow/sm on its own — the faintest lift there is. Tinted with the text ink, never black. No shadow in this system has a horizontal offset, so none is named.

Les couleurs d'ombre ne suivent pas l'encre. Elles valent ramp.neutral.900 à trois opacités, mais un alias Figma emporte l'opacité avec la couleur : on ne peut pas pointer l'encre et n'en changer que la transparence. Les trois sont donc des couleurs littérales. Si l'encre du système change, elles sont à reprendre à la main — c'est le seul point du groupe qui puisse dériver.

Aucune ombre n'a de décalage horizontal. Le 0 de tête n'est pas un token : c'est une règle du système, écrite dans build-tokens.mjs avec la couche de contact. Le jour où une ombre en demande un, il devient une variable comme les autres.

Mouvement

Trois durées et trois courbes. La règle tient en une ligne : un changement de couleur prend quick, un déplacement prend default, une entrée ou une sortie prend slow. Survolez une piste pour rejouer le mouvement — la pastille voyage avec le token de sa ligne, pas avec une valeur écrite ici.

Durées

À courbe constante — easing.standard.

  • --motion-duration-quick — 140ms

    140ms. Colour changes and fades — anything that does not travel: a hover fill, an opacity swap. Do NOT use it for movement; at this speed a path cannot be read.

  • --motion-duration-default — 200ms

    200ms. Movement inside the screen: something that slides from one place to another while staying visible. The nav pill travels on this one.

  • --motion-duration-slow — 320ms

    320ms. Things that enter or leave the screen — a dialog, a drawer. Not yet used: it waits for the contact dialog. Do NOT use it for a hover; it would feel broken.

Courbes

À durée constante — duration.slow, assez longue pour qu'on lise la différence.

  • --motion-easing-standard — cubic-bezier(0.4, 0, 0.2, 1)

    An object that moves while staying on screen: it leaves briskly and settles. The default curve — reach for this one first, and pair it with duration.default.

  • --motion-easing-enter — cubic-bezier(0, 0, 0.2, 1)

    Something arriving: full speed at the start, gentle landing. Pair with duration.slow. Only for what comes from outside the screen.

  • --motion-easing-exit — cubic-bezier(0.4, 0, 1, 1)

    Something leaving: gentle start, then gone. Pair with duration.slow. Never on something that stays — it reads as a departure.

Mouvement réduit. Sous prefers-reduced-motion: reduce, ce sont les trois durées qui tombent à 0ms, dans tokens.css. Aucun composant n'a à connaître la préférence, et les pistes ci-dessus s'arrêtent aussi. Le système ne supprime pas les états — un onglet courant reste signalé, un bouton survolé reste survolé : il supprime le trajet.

Layout

Métadonnées des 4 modes Figma. Ce sont les seuls tokens qui varient d'un mode à l'autre — redimensionnez la fenêtre pour les voir changer. Ils sont informatifs : rien ne les consomme pour l'instant.