card-07-transactions

Carte transaction — identité + ligne de valeur

Poser un intitulé de flux (badge + titre + acteurs) en haut d'une carte blanche et sa ligne de valeur unique sur aplat doux collée en bas, sans jamais faire de la carte un tableau.

cardslideweb748×208px8 benchmarks

Télécharger le .zip

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

Bloc « dernière opération » ou « flux en cours » d'un dashboard : une identité, un groupe d'acteurs, une seule paire chiffrée. La pile d'avatars qui se recouvre signale un échange entre plusieurs parties.

Éviter quand

Il y a plus d'une ligne de valeur à montrer : au-delà d'une, ce n'est plus cette carte mais une LISTE, qui demande un séparateur et un rythme propres. Et sans acteurs à représenter, la pile d'avatars devient un ornement vide.

Notes

Le margin-top:auto de la ligne de valeur est ce qui la scelle au bas de la carte quelle que soit la hauteur de l'en-tête : un benchmark vérifie que son bas touche bien la marge basse. Le recouvrement des avatars (marge négative) est mesuré, pas relu à l'œil — c'est lui qui distingue un GROUPE d'une simple file. Les avatars sont des dégradés de tokens (menthe / lilas) à la place des photos de la source : un pattern doit rester rejouable sur n'importe quelle charte, une photo en dur l'en empêcherait.

Mots-clés

cartetransactionavatarspilefluxdashboardblancligne-valeurcrypto

Benchmarks — la géométrie, en assertions vérifiables

Rejouables par node bin/check.mjs card-07-transactions : le pattern se prouve, il ne se croit pas.

assertionmesureattendu
marges intérieures ≈ 4,9 % de la largeurnum('.vl-txn','paddingLeft') / W0.049 ± 0.02
badge carré (largeur ≈ hauteur)Math.abs(box('.vl-txn__badge').w - box('.vl-txn__badge').h)≤ 1
les avatars se RECOUVREENT (le 2e commence avant la fin du 1er)box('.vl-txn__av--2').left - box('.vl-txn__av--1').right≤ -2
ligne de valeur collée en bas (son bas touche la marge basse, ± 3 px)Math.abs((H - num('.vl-txn','paddingBottom')) - box('.vl-txn__row').bottom)≤ 3
le libellé de paire occupe la largeur restante (flex:1 → > 55 % de la carte)box('.vl-txn__pair').w / W≥ 0.55
contraste du titre ≥ 7 (il nomme le flux)contrast('.vl-txn__title')≥ 7
contraste de la valeur sur l'aplat doux ≥ 4,5 (petit corps, seuil plein)contrast('.vl-txn__pair')≥ 4.5
aucun débordement du contenu hors de la carteoverflow('.vl-txn')≤ 0

Le code

fragment — patterns/card-07-transactions.html Télécharger
<!-- card-07-transactions — fragment autonome. Couleurs via --vl-* uniquement, aucune valeur en dur. -->
<div class="vl-txn">
  <div class="vl-txn__head">
    <div class="vl-txn__id">
      <span class="vl-txn__badge">
        <svg viewBox="0 0 24 24" fill="none" stroke="var(--vl-ink-invert)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M4 8h13l-3-3M20 16H7l3 3"/></svg>
      </span>
      <div>
        <h2 class="vl-txn__title">Recent Transactions</h2>
        <p class="vl-txn__sub">Sell currency</p>
      </div>
    </div>
    <div class="vl-txn__avatars">
      <span class="vl-txn__av vl-txn__av--1"></span>
      <span class="vl-txn__av vl-txn__av--2"></span>
      <span class="vl-txn__menu">···</span>
    </div>
  </div>
  <div class="vl-txn__row">
    <span class="vl-txn__coin">
      <svg viewBox="0 0 24 24" fill="none" stroke="var(--vl-ink-invert)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="9"/><path d="M9 8h5a2.5 2.5 0 0 1 0 5H9zM9 13h6a2.5 2.5 0 0 1 0 5H9zM10 6v12"/></svg>
    </span>
    <span class="vl-txn__pair">12,53 ETH/I BTC</span>
    <span class="vl-txn__dots">⋮</span>
  </div>
</div>

<style>
/* Carte de transaction : en-tête (badge + identité + pile d'avatars) en haut, UNE ligne de
   valeur sur aplat doux collée en bas par margin-top:auto. La pile d'avatars se recouvre en
   marge négative — c'est ce chevauchement qui la lit comme un groupe et non comme une file. */
.vl-txn {
  width: 748px; height: 208px;
  background: var(--vl-surface-light); color: var(--vl-ink);
  border-radius: var(--vl-radius-card); padding: 26px;
  display: flex; flex-direction: column;
  font-family: Inter, -apple-system, "Helvetica Neue", Arial, sans-serif;
}
.vl-txn__head { display: flex; justify-content: space-between; align-items: flex-start; }
.vl-txn__id { display: flex; gap: 14px; align-items: center; }
.vl-txn__badge {
  width: 42px; height: 42px; border-radius: 13px; background: var(--vl-surface-dark);
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
}
.vl-txn__badge svg { width: 20px; height: 20px; }
.vl-txn__title { margin: 0; font-size: 18px; font-weight: 600; letter-spacing: -0.01em; }
.vl-txn__sub { margin: 2px 0 0; font-size: 11px; font-weight: 500; color: var(--vl-ink-muted); }
.vl-txn__avatars { display: flex; align-items: center; }
.vl-txn__av { width: 38px; height: 38px; border-radius: 50%; border: 2px solid var(--vl-surface-light); margin-left: -10px; }
.vl-txn__av:first-child { margin-left: 0; }
.vl-txn__av--1 { background: linear-gradient(135deg, var(--vl-mint), var(--vl-mint-deep)); }
.vl-txn__av--2 { background: linear-gradient(135deg, var(--vl-lilac), var(--vl-lilac-deep)); }
.vl-txn__menu {
  width: 38px; height: 38px; border-radius: 50%; background: var(--vl-lilac); color: var(--vl-surface-dark);
  margin-left: -10px; display: inline-flex; align-items: center; justify-content: center; font-weight: 700; letter-spacing: 1px;
}
.vl-txn__row {
  margin-top: auto; display: flex; align-items: center; gap: 14px;
  background: var(--vl-surface-soft); border-radius: var(--vl-radius-sub); padding: 16px 20px;
}
.vl-txn__coin {
  width: 34px; height: 34px; border-radius: 50%; background: var(--vl-surface-dark);
  display: inline-flex; align-items: center; justify-content: center; flex: 0 0 auto;
}
.vl-txn__coin svg { width: 16px; height: 16px; }
.vl-txn__pair { flex: 1; font-size: 15px; font-weight: 600; }
.vl-txn__dots { font-weight: 700; color: var(--vl-ink-muted); letter-spacing: 1px; }
</style>
tokens de la charte — systems/ref-11-finance-dashboard-mint.json Télécharger
:root {
  --vl-bg: #E6EAE4;
  --vl-board: #E6EAE4;
  --vl-surface-light: #FFFFFF;
  --vl-surface-soft: #F1F2EF;
  --vl-surface-dark: #141414;
  --vl-mint: #B4E3A0;
  --vl-mint-deep: #8FCE72;
  --vl-lilac: #B6ABE6;
  --vl-lilac-deep: #9A8ADE;
  --vl-ink: #181A17;
  --vl-ink-muted: #7C817A;
  --vl-ink-on-mint: #3D5A30;
  --vl-ink-on-lilac: #3E3270;
  --vl-ink-invert: #FFFFFF;
  --vl-ink-invert-muted: #9CA09A;
  --vl-hairline: #E3E5E1;
  --vl-hairline-invert: #333333;
  --vl-radius-card: 26px;
  --vl-radius-sub: 20px;
  --vl-radius-chip: 14px;
  --vl-gap: 20px;
}
les métadonnées — patterns/card-07-transactions.json (télécharger)
{
  "name": "Carte transaction — identité + ligne de valeur",
  "family": "card",
  "ref": "ref-11-finance-dashboard-mint",
  "intent": "Poser un intitulé de flux (badge + titre + acteurs) en haut d'une carte blanche et sa ligne de valeur unique sur aplat doux collée en bas, sans jamais faire de la carte un tableau.",
  "when_to_use": "Bloc « dernière opération » ou « flux en cours » d'un dashboard : une identité, un groupe d'acteurs, une seule paire chiffrée. La pile d'avatars qui se recouvre signale un échange entre plusieurs parties.",
  "avoid_when": "Il y a plus d'une ligne de valeur à montrer : au-delà d'une, ce n'est plus cette carte mais une LISTE, qui demande un séparateur et un rythme propres. Et sans acteurs à représenter, la pile d'avatars devient un ornement vide.",
  "tags": [
    "carte",
    "transaction",
    "avatars",
    "pile",
    "flux",
    "dashboard",
    "blanc",
    "ligne-valeur",
    "crypto"
  ],
  "vars": [
    {
      "name": "--vl-surface-soft",
      "role": "aplat doux de la ligne de valeur",
      "default": "#F1F2EF"
    },
    {
      "name": "--vl-surface-dark",
      "role": "fond du badge et de la pastille de devise",
      "default": "#141414"
    },
    {
      "name": "--vl-lilac",
      "role": "pastille de menu (fin de la pile d'avatars)",
      "default": "#B6ABE6"
    },
    {
      "name": "--vl-radius-card",
      "role": "rayon de la carte",
      "default": "26px"
    }
  ],
  "slots": [
    "badge",
    "title",
    "avatars",
    "value-row"
  ],
  "geometry": {
    "root": ".vl-txn",
    "frame": [
      748,
      208
    ],
    "ratios": {
      "pad_over_width": 0.049,
      "badge_over_width": 0.08
    },
    "type_px": {
      "title": 18,
      "pair": 15,
      "sub": 11
    },
    "pad_ratio": {
      "top": 0.125,
      "x": 0.049,
      "bottom": 0.125
    }
  },
  "benchmarks": [
    {
      "name": "marges intérieures ≈ 4,9 % de la largeur",
      "measure": "num('.vl-txn','paddingLeft') / W",
      "expect": 0.049,
      "tol": 0.02
    },
    {
      "name": "badge carré (largeur ≈ hauteur)",
      "measure": "Math.abs(box('.vl-txn__badge').w - box('.vl-txn__badge').h)",
      "max": 1
    },
    {
      "name": "les avatars se RECOUVREENT (le 2e commence avant la fin du 1er)",
      "measure": "box('.vl-txn__av--2').left - box('.vl-txn__av--1').right",
      "max": -2
    },
    {
      "name": "ligne de valeur collée en bas (son bas touche la marge basse, ± 3 px)",
      "measure": "Math.abs((H - num('.vl-txn','paddingBottom')) - box('.vl-txn__row').bottom)",
      "max": 3
    },
    {
      "name": "le libellé de paire occupe la largeur restante (flex:1 → > 55 % de la carte)",
      "measure": "box('.vl-txn__pair').w / W",
      "min": 0.55
    },
    {
      "name": "contraste du titre ≥ 7 (il nomme le flux)",
      "measure": "contrast('.vl-txn__title')",
      "min": 7
    },
    {
      "name": "contraste de la valeur sur l'aplat doux ≥ 4,5 (petit corps, seuil plein)",
      "measure": "contrast('.vl-txn__pair')",
      "min": 4.5
    },
    {
      "name": "aucun débordement du contenu hors de la carte",
      "measure": "overflow('.vl-txn')",
      "max": 0
    }
  ],
  "notes": "Le margin-top:auto de la ligne de valeur est ce qui la scelle au bas de la carte quelle que soit la hauteur de l'en-tête : un benchmark vérifie que son bas touche bien la marge basse. Le recouvrement des avatars (marge négative) est mesuré, pas relu à l'œil — c'est lui qui distingue un GROUPE d'une simple file. Les avatars sont des dégradés de tokens (menthe / lilas) à la place des photos de la source : un pattern doit rester rejouable sur n'importe quelle charte, une photo en dur l'en empêcherait.",
  "id": "card-07-transactions"
}

À côté