card-01-ghost-icon
card-12-inverted-kpi-row
Rangée de KPI dont un seul est inversé — et plus large
Ouvrir un tableau de bord par trois indicateurs de même nature dont UN SEUL est de premier rang, en lui appliquant deux fois le même geste de hiérarchie : l'aplat inversé ET une colonne 5 % plus large. Chaque carte range ses quatre informations dans le même ordre — libellé en haut, pastille de renvoi ancrée au coin opposé, chiffre poussé en bas, note collée dessous.
cardwebslide1286×219px16 benchmarks
Le fragment RÉEL, dans son propre document, sur le sol de sa charte — pas une image. Ce que vous voyez est exactement ce que vous collerez.
Employer quand
Bandeau d'ouverture d'un tableau de bord ou d'un rapport : trois à quatre valeurs comparables (un solde, un revenu, un volume) dont une seule commande l'attention. Le chiffre est court — quatre à six signes — et la note tient sur une ligne.
Éviter quand
Les valeurs ne sont pas comparables entre elles (la rangée suggère une lecture de gauche à droite qui n'existe pas), il y en a plus de quatre (la carte inversée cesse de dominer et la largeur différenciée devient un défaut d'alignement), ou plusieurs cartes doivent être mises en avant — deux aplats inversés dans une rangée annulent le seul geste de hiérarchie du système.
Notes
Le détail qui fait ce pattern est mesuré, pas approximatif : sur la source, la carte inversée fait 314 px là où les deux autres en font 300 et 305. Cinq pour cent. On serait tenté de lire un défaut d'alignement et de « corriger » vers trois colonnes égales — ce serait supprimer la moitié du geste. Deux benchmarks encadrent donc ce rapport des DEUX côtés : au moins 1,02 (sinon la largeur ne dit plus rien) et au plus 1,12 (au-delà, la rangée cesse d'être une rangée). Le comptage des aplats sombres est écrit en luminance et non sur une classe : deux cartes inversées posées plus tard par quelqu'un d'autre est exactement la régression qu'un contrôle par classe laisse passer. Le fragment livré est la rangée ENTIÈRE et non une carte isolée, parce que la règle de ce pattern est une règle de rangée : une carte seule ne peut ni être « la plus large » ni être « la seule inversée ». Livrer la carte aurait donné un objet mesurable sur lequel les deux assertions centrales n'auraient pas pu s'écrire.
Mots-clés
Benchmarks — la géométrie, en assertions vérifiables
Rejouables par node bin/check.mjs card-12-inverted-kpi-row : le pattern se prouve, il ne se croit pas.
| assertion | mesure | attendu |
|---|---|---|
| rangée basse : sa hauteur vaut ≈ 17 % de sa largeur | H / W | 0.17 ± 0.03 |
| LA CARTE INVERSÉE EST AUSSI LA PLUS LARGE — le geste de hiérarchie est appliqué deux fois | box('.vl-kpirow__card--lead').w / box('.vl-kpirow__card--b').w | 1.05 ± 0.03 |
| … mais à peine : au-delà de 12 % d'écart, ce n'est plus une hiérarchie, c'est une grille cassée | box('.vl-kpirow__card--lead').w / box('.vl-kpirow__card--b').w | ≤ 1.12 |
| UNE SEULE carte inversée dans la rangée | [...document.querySelectorAll('.vl-kpirow > *')].filter((e) => lum(parseRgb(getComputedStyle(e).backgroundColor)) < 0.2).length | 1 ± 0 |
| les trois cartes partagent leur ligne haute et leur ligne basse | Math.abs(box('.vl-kpirow__card--lead').top - box('.vl-kpirow__card--c').top) + Math.abs(box('.vl-kpirow__card--lead').bottom - box('.vl-kpirow__card--c').bottom) | ≤ 1.5 |
| gouttière ≈ 1,2 % de la largeur de rangée | num('.vl-kpirow','columnGap') / W | 0.0124 ± 0.006 |
| la pastille de renvoi est ancrée au coin haut-droit de sa carte | box('.vl-kpirow__card--lead').right - num('.vl-kpirow__card--lead','paddingRight') - box('.vl-kpirow__go').right | 0 ± 1.5 |
| la pastille est un disque | box('.vl-kpirow__go').w / box('.vl-kpirow__go').h | 1 ± 0.02 |
| le libellé ne court jamais sous la pastille | box('.vl-kpirow__go').left - box('.vl-kpirow__label').right | ≥ 8 |
| le chiffre est POUSSÉ EN BAS : son haut passe la mi-hauteur de la carte | (box('.vl-kpirow__fig').top - box('.vl-kpirow__card--lead').top) / box('.vl-kpirow__card--lead').h | ≥ 0.45 |
| saut typographique chiffre / libellé ≥ 2,6 | num('.vl-kpirow__fig','fontSize') / num('.vl-kpirow__label','fontSize') | ≥ 2.6 |
| la note est collée sous le chiffre : moins d'un demi-corps de note les sépare | (box('.vl-kpirow__note').top - box('.vl-kpirow__fig').bottom) / num('.vl-kpirow__note','fontSize') | ≤ 0.6 |
| aucun liseré sur les cartes | num('.vl-kpirow__card--b','borderTopWidth') | 0 ± 0 |
| contraste du chiffre inversé ≥ 4,5 | contrast('.vl-kpirow__fig') | ≥ 4.5 |
| contraste de la note inversée ≥ 4,5 — c'est elle qui plafonne, pas le chiffre | contrast('.vl-kpirow__note') | ≥ 4.5 |
| aucun débordement de la rangée | overflow('.vl-kpirow') | ≤ 0 |
Le code
patterns/card-12-inverted-kpi-row.html
Télécharger<!-- card-12-inverted-kpi-row — trois KPI de même nature, un seul de premier rang.
Couleurs via --vl-* uniquement. Le fragment est la RANGÉE et non une carte : la règle du
pattern est une règle de rangée (« la seule inversée », « la plus large »), et une carte
isolée ne peut porter ni l'une ni l'autre.
Quatre zones dans un ordre FIXE : libellé en haut-gauche, pastille de renvoi ancrée au
coin haut-droit, chiffre poussé en bas par `margin-top:auto`, note collée dessous. -->
<div class="vl-kpirow">
<article class="vl-kpirow__card vl-kpirow__card--lead">
<p class="vl-kpirow__label">Available to payout</p>
<span class="vl-kpirow__go" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 17 17 7M8.5 7H17v8.5"/></svg>
</span>
<p class="vl-kpirow__fig">$16.4K</p>
<p class="vl-kpirow__note"><b>Payout</b> · $6.1K will be available soon</p>
</article>
<article class="vl-kpirow__card vl-kpirow__card--b">
<p class="vl-kpirow__label">Today revenue</p>
<span class="vl-kpirow__go" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 17 17 7M8.5 7H17v8.5"/></svg>
</span>
<p class="vl-kpirow__fig">$6.4K</p>
<p class="vl-kpirow__note"><b>Payout</b> · $6.1K will be available soon</p>
</article>
<article class="vl-kpirow__card vl-kpirow__card--c">
<p class="vl-kpirow__label">Today sessions</p>
<span class="vl-kpirow__go" aria-hidden="true">
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M7 17 17 7M8.5 7H17v8.5"/></svg>
</span>
<p class="vl-kpirow__fig">400</p>
<p class="vl-kpirow__note"><b>Payout</b> · $6.1K will be available soon</p>
</article>
</div>
<style>
.vl-kpirow {
width: 1286px; height: 219px;
box-sizing: border-box;
display: grid;
/* 1,05fr contre 1fr : la carte de premier rang est AUSSI la plus large. Cinq pour cent, pas
davantage — au-delà de 12 % la rangée cesse d'être une rangée et se lit comme une grille
mal alignée. C'est un écart mesuré sur la source, pas une approximation. */
grid-template-columns: minmax(0, 1.05fr) minmax(0, 1fr) minmax(0, 1.02fr);
gap: var(--vl-gutter, 16px);
font-family: Montserrat, Poppins, Inter, "Helvetica Neue", Arial, sans-serif;
}
.vl-kpirow__card {
position: relative;
margin: 0; padding: 30px 32px 26px;
box-sizing: border-box;
background: var(--vl-module);
color: var(--vl-ink);
border-radius: var(--vl-radius-module, 29px);
display: flex; flex-direction: column;
}
/* UNE SEULE carte inversée. Deux annuleraient le seul geste de hiérarchie du système. */
.vl-kpirow__card--lead { background: var(--vl-invert); color: var(--vl-on-invert); }
.vl-kpirow__label { margin: 0; max-width: 74%; font-size: 20px; font-weight: 500; }
/* Hors du flux, ancrée au coin : la pastille appartient au cadre de la carte, pas à sa
phrase. Sur la carte inversée elle est PLEINE, sur les autres elle n'est qu'un liseré —
c'est la seule chose qui change entre les deux traitements, en plus du fond. */
.vl-kpirow__go {
position: absolute; top: 26px; right: 32px;
width: 46px; height: 46px; border-radius: 50%;
display: flex; align-items: center; justify-content: center;
box-shadow: inset 0 0 0 1.4px var(--vl-ramp-2);
}
.vl-kpirow__card--lead .vl-kpirow__go {
background: var(--vl-on-invert); color: var(--vl-invert); box-shadow: none;
}
.vl-kpirow__go svg { width: 20px; height: 20px; }
/* `margin-top:auto` pousse le chiffre en bas : le vide se met entre le libellé et le nombre,
jamais entre le nombre et sa note. C'est ce qui fait lire la carte de haut en bas d'un
coup au lieu de la faire parcourir. */
.vl-kpirow__fig {
margin: auto 0 6px;
font-size: 62px; line-height: 1; font-weight: 700; letter-spacing: -0.025em;
}
.vl-kpirow__note { margin: 0; font-size: 15px; color: var(--vl-ink-soft); }
.vl-kpirow__note b { font-weight: 600; color: var(--vl-ink); }
.vl-kpirow__card--lead .vl-kpirow__note { color: var(--vl-on-invert-soft); }
.vl-kpirow__card--lead .vl-kpirow__note b { color: var(--vl-on-invert); }
</style>
systems/ref-18-lime-sales-dashboard.json
Télécharger:root {
--vl-app: #FEFEFE;
--vl-module: #F2F2F2;
--vl-module-warm: #FBF9EC;
--vl-invert: #000000;
--vl-accent: #5FE85C;
--vl-ink: #0B0B0B;
--vl-ink-soft: #6B6B6B;
--vl-on-invert: #FFFFFF;
--vl-on-invert-soft: rgba(255,255,255,0.66);
--vl-hairline: #E6E6E6;
--vl-ramp-1: #E3E3E3;
--vl-ramp-2: #CCCCCC;
--vl-ramp-3: #999999;
--vl-ramp-4: #666666;
--vl-ramp-5: #000000;
--vl-radius-module: 29px;
--vl-radius-tile: 20px;
--vl-radius-pill: 999px;
--vl-gutter: 16px;
--vl-gutter-row: 11px;
--vl-rail-w: 95px;
--vl-margin: 30px;
--vl-header-h: 69px;
}
les métadonnées — patterns/card-12-inverted-kpi-row.json (télécharger)
{
"name": "Rangée de KPI dont un seul est inversé — et plus large",
"family": "card",
"ref": "ref-18-lime-sales-dashboard",
"intent": "Ouvrir un tableau de bord par trois indicateurs de même nature dont UN SEUL est de premier rang, en lui appliquant deux fois le même geste de hiérarchie : l'aplat inversé ET une colonne 5 % plus large. Chaque carte range ses quatre informations dans le même ordre — libellé en haut, pastille de renvoi ancrée au coin opposé, chiffre poussé en bas, note collée dessous.",
"when_to_use": "Bandeau d'ouverture d'un tableau de bord ou d'un rapport : trois à quatre valeurs comparables (un solde, un revenu, un volume) dont une seule commande l'attention. Le chiffre est court — quatre à six signes — et la note tient sur une ligne.",
"avoid_when": "Les valeurs ne sont pas comparables entre elles (la rangée suggère une lecture de gauche à droite qui n'existe pas), il y en a plus de quatre (la carte inversée cesse de dominer et la largeur différenciée devient un défaut d'alignement), ou plusieurs cartes doivent être mises en avant — deux aplats inversés dans une rangée annulent le seul geste de hiérarchie du système.",
"media": [
"web",
"slide"
],
"tags": [
"kpi",
"chiffre",
"stat",
"rangee",
"dashboard",
"tableau-de-bord",
"carte",
"inverse",
"hierarchie",
"solde",
"revenu",
"accent",
"renvoi"
],
"vars": [
{
"name": "--vl-module",
"role": "aplat des cartes secondaires",
"default": "#F2F2F2"
},
{
"name": "--vl-invert",
"role": "aplat de la carte de premier rang — UNE SEULE par rangée",
"default": "#000000"
},
{
"name": "--vl-ink",
"role": "libellé et chiffre sur carte secondaire",
"default": "#0B0B0B"
},
{
"name": "--vl-ink-soft",
"role": "note de bas de carte",
"default": "#6B6B6B"
},
{
"name": "--vl-on-invert",
"role": "encre sur la carte inversée",
"default": "#FFFFFF"
},
{
"name": "--vl-on-invert-soft",
"role": "note sur la carte inversée",
"default": "rgba(255,255,255,0.66)"
},
{
"name": "--vl-ramp-2",
"role": "liseré de la pastille de renvoi, cartes secondaires",
"default": "#CCCCCC"
},
{
"name": "--vl-radius-module",
"role": "rayon d'une carte",
"default": "29px"
},
{
"name": "--vl-gutter",
"role": "gouttière de la rangée",
"default": "16px"
}
],
"slots": [
"label",
"go",
"fig",
"note"
],
"geometry": {
"root": ".vl-kpirow",
"frame": [
1286,
219
],
"ratios": {
"height_over_width": 0.17,
"lead_over_second": 1.05,
"gutter_over_width": 0.0124,
"radius_over_card_width": 0.069,
"go_over_card_width": 0.109,
"fig_over_label": 3.1
},
"type_px": {
"fig": 62,
"label": 20,
"note": 15
},
"pad_ratio": {
"top": 0.137,
"x": 0.076,
"bottom": 0.119
}
},
"benchmarks": [
{
"name": "rangée basse : sa hauteur vaut ≈ 17 % de sa largeur",
"measure": "H / W",
"expect": 0.17,
"tol": 0.03
},
{
"name": "LA CARTE INVERSÉE EST AUSSI LA PLUS LARGE — le geste de hiérarchie est appliqué deux fois",
"measure": "box('.vl-kpirow__card--lead').w / box('.vl-kpirow__card--b').w",
"expect": 1.05,
"tol": 0.03
},
{
"name": "… mais à peine : au-delà de 12 % d'écart, ce n'est plus une hiérarchie, c'est une grille cassée",
"measure": "box('.vl-kpirow__card--lead').w / box('.vl-kpirow__card--b').w",
"max": 1.12
},
{
"name": "UNE SEULE carte inversée dans la rangée",
"measure": "[...document.querySelectorAll('.vl-kpirow > *')].filter((e) => lum(parseRgb(getComputedStyle(e).backgroundColor)) < 0.2).length",
"expect": 1,
"tol": 0
},
{
"name": "les trois cartes partagent leur ligne haute et leur ligne basse",
"measure": "Math.abs(box('.vl-kpirow__card--lead').top - box('.vl-kpirow__card--c').top) + Math.abs(box('.vl-kpirow__card--lead').bottom - box('.vl-kpirow__card--c').bottom)",
"max": 1.5
},
{
"name": "gouttière ≈ 1,2 % de la largeur de rangée",
"measure": "num('.vl-kpirow','columnGap') / W",
"expect": 0.0124,
"tol": 0.006
},
{
"name": "la pastille de renvoi est ancrée au coin haut-droit de sa carte",
"measure": "box('.vl-kpirow__card--lead').right - num('.vl-kpirow__card--lead','paddingRight') - box('.vl-kpirow__go').right",
"expect": 0,
"tol": 1.5
},
{
"name": "la pastille est un disque",
"measure": "box('.vl-kpirow__go').w / box('.vl-kpirow__go').h",
"expect": 1,
"tol": 0.02
},
{
"name": "le libellé ne court jamais sous la pastille",
"measure": "box('.vl-kpirow__go').left - box('.vl-kpirow__label').right",
"min": 8
},
{
"name": "le chiffre est POUSSÉ EN BAS : son haut passe la mi-hauteur de la carte",
"measure": "(box('.vl-kpirow__fig').top - box('.vl-kpirow__card--lead').top) / box('.vl-kpirow__card--lead').h",
"min": 0.45
},
{
"name": "saut typographique chiffre / libellé ≥ 2,6",
"measure": "num('.vl-kpirow__fig','fontSize') / num('.vl-kpirow__label','fontSize')",
"min": 2.6
},
{
"name": "la note est collée sous le chiffre : moins d'un demi-corps de note les sépare",
"measure": "(box('.vl-kpirow__note').top - box('.vl-kpirow__fig').bottom) / num('.vl-kpirow__note','fontSize')",
"max": 0.6
},
{
"name": "aucun liseré sur les cartes",
"measure": "num('.vl-kpirow__card--b','borderTopWidth')",
"expect": 0,
"tol": 0
},
{
"name": "contraste du chiffre inversé ≥ 4,5",
"measure": "contrast('.vl-kpirow__fig')",
"min": 4.5
},
{
"name": "contraste de la note inversée ≥ 4,5 — c'est elle qui plafonne, pas le chiffre",
"measure": "contrast('.vl-kpirow__note')",
"min": 4.5
},
{
"name": "aucun débordement de la rangée",
"measure": "overflow('.vl-kpirow')",
"max": 0
}
],
"notes": "Le détail qui fait ce pattern est mesuré, pas approximatif : sur la source, la carte inversée fait 314 px là où les deux autres en font 300 et 305. Cinq pour cent. On serait tenté de lire un défaut d'alignement et de « corriger » vers trois colonnes égales — ce serait supprimer la moitié du geste. Deux benchmarks encadrent donc ce rapport des DEUX côtés : au moins 1,02 (sinon la largeur ne dit plus rien) et au plus 1,12 (au-delà, la rangée cesse d'être une rangée).\n\nLe comptage des aplats sombres est écrit en luminance et non sur une classe : deux cartes inversées posées plus tard par quelqu'un d'autre est exactement la régression qu'un contrôle par classe laisse passer.\n\nLe fragment livré est la rangée ENTIÈRE et non une carte isolée, parce que la règle de ce pattern est une règle de rangée : une carte seule ne peut ni être « la plus large » ni être « la seule inversée ». Livrer la carte aurait donné un objet mesurable sur lequel les deux assertions centrales n'auraient pas pu s'écrire.",
"id": "card-12-inverted-kpi-row"
}
À côté
card-02-notched-brief
Carte chanfreinée de second rang
card-03-stat-accent
Vignette statistique sur accent
card-04-stat-barchart
Carte statistique à barres empilées
card-05-balance-gauge
Carte solde à jauge compteur
card-06-forecast-timeline