card-01-ghost-icon
card-15-notched-float-statement
Vignette éditoriale chanfreinée, flottante et contourée
Porter un ENGAGEMENT — un titre affirmatif et son développement de plusieurs lignes — dans une vignette à silhouette de ticket qui flotte au-dessus d'un fond sombre : contour clair épais, ombre portée qui suit le chanfrein, texte justifié et coupé qui remplit la vignette jusqu'au dernier pixel.
cardwebslide426×454px22 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
Trois à six promesses de même rang sur un fond sombre — méthode, engagements, différenciateurs — chacune valant un paragraphe et non une ligne. Une seule prend la variante `--end`, et c'est une FIN de série, pas un « le plus important ».
Éviter quand
Le développement tient en une ligne (la vignette se vide et le contour épais n'encadre plus rien : c'est card-02-notched-brief qu'il faut), la colonne descend sous ~260 px (le texte justifié y ouvre des rivières que la césure n'absorbe plus), ou le fond de page est clair — le contour clair et l'ombre noire n'y détachent rien.
Notes
Le fragment livré est la variante de FIN (`vl-notched-float--end`) : c'est l'état le plus serré en contraste (corps #404C35 sur #F5C518, 5,68:1, contre 7,4:1 sur la vignette marine), et un benchmark ne garde que ce qu'il mesure. DEUX lois de rendu portent ce pattern, et aucune n'est cosmétique. (1) Un filtre s'applique AVANT le clip-path : une ombre posée sur l'élément chanfreiné est découpée avec lui et disparaît — sans erreur, sans warning. Elle vit donc un cran au-dessus, d'où la racine non clippée. Corollaire payé au passage : `drop-shadow()` n'accepte PAS de rayon d'étalement ; une quatrième longueur rend la fonction invalide et le filtre entier est ignoré, toujours en silence. (2) Un clip-path mange les bordures : le contour est l'aplat de la couche clippée, la carte étant peinte par `::before` inséré de son épaisseur — et le chanfrein intérieur se DÉDUIT (décaler une oblique à 45° de b raccourcit sa coupe de b(2−√2) ≈ 0,586 b), faute de quoi le contour s'épaissit dans les deux angles coupés. Piège de MESURE, même arbitrage que card-10 : `bin/check.mjs` lit `background-color` et jamais `background-image`, et il ne voit pas un `::before`. Le fond réel du texte étant l'aplat de carte, c'est LUI qui est déclaré en `background-color` et le contour qui est peint en `background-image` — sans quoi le contraste se mesurait contre le contour clair, un fond que le texte ne touche jamais. Ce n'est pas une variante de card-02-notched-brief, dont le `avoid_when` renvoie explicitement ici (« l'explication dépasse quatre lignes ⇒ c'est un paragraphe qui mérite sa colonne ») et qui n'a ni double chanfrein, ni contour, ni ombre ; ni de card-10-kpi-notch-tile, qui partage la seule silhouette et porte un CHIFFRE, sans contour ni flottement.
Mots-clés
Benchmarks — la géométrie, en assertions vérifiables
Rejouables par node bin/check.mjs card-15-notched-float-statement : le pattern se prouve, il ne se croit pas.
| assertion | mesure | attendu |
|---|---|---|
| vignette un rien plus haute que large | W / H | 0.938 ± 0.03 |
| chanfrein ≈ 10,3 % de la largeur | notch('.vl-notched-float__card') / W | 0.103 ± 0.02 |
| le polygone porte 6 sommets : DEUX coins coupés, pas un ni quatre | (cs('.vl-notched-float__card','clipPath').match(/,/g) || []).length + 1 | 6 ± 0 |
| la coupe commence au coin haut-droit (l'autre est son opposé sur la diagonale) | notchCorner('.vl-notched-float__card') === 'tr' ? 1 : 0 | 1 |
| les coins non coupés gardent un rayon ≈ 3,5 % de la largeur | num('.vl-notched-float__card','borderTopLeftRadius') / W | 0.035 ± 0.015 |
| L'OMBRE EST SUR LA RACINE : un filtre s'applique avant le clip, posée plus bas elle serait découpée | cs('.vl-notched-float','filter').indexOf('drop-shadow') >= 0 ? 1 : 0 | 1 |
| la racine n'est PAS clippée — c'est ce qui laisse l'ombre exister | cs('.vl-notched-float','clipPath') === 'none' ? 1 : 0 | 1 |
| la couche clippée ne porte AUCUN filtre — sinon l'ombre se découpe avec elle | cs('.vl-notched-float__card','filter') === 'none' ? 1 : 0 | 1 |
| le contour n'est pas un `border` : un clip-path le mangerait | num('.vl-notched-float__card','borderTopWidth') | 0 ± 0 |
| contour ≈ 0,61 % de la largeur — épais, mais un contour | parseFloat(cs('.vl-notched-float','--nfs-bw')) / W | 0.0061 ± 0.002 |
| le contour existe bel et bien : l'aplat de carte est inséré de l'épaisseur déclarée | Math.abs(box('.vl-notched-float__fill').left - parseFloat(cs('.vl-notched-float','--nfs-bw'))) | ≤ 0.6 |
| la césure ne dépend d'aucun document d'accueil : le fragment déclare sa LANGUE | $('.vl-notched-float__p').closest('[lang]') ? 1 : 0 | 1 |
| CHANFREIN INTÉRIEUR DÉDUIT : b(2−√2) ≈ 0,586 b de moins que l'extérieur, sinon le contour s'épaissit dans les angles | (notch('.vl-notched-float__card') - notch('.vl-notched-float__fill')) / parseFloat(cs('.vl-notched-float','--nfs-bw')) | 0.586 ± 0.02 |
| marge intérieure gauche ≈ 8 % de la largeur | num('.vl-notched-float__card','paddingLeft') / W | 0.0798 ± 0.02 |
| le titre ouvre la vignette : il colle la marge du haut | box('.vl-notched-float__t').top - num('.vl-notched-float__card','paddingTop') | 0 ± 2 |
| saut typographique titre / corps entre 1,25 et 1,5 — un titre, pas un chiffre héros | num('.vl-notched-float__t','fontSize') / num('.vl-notched-float__p','fontSize') | 1.25 → 1.5 |
| le corps est JUSTIFIÉ — c'est la signature du pattern | cs('.vl-notched-float__p','textAlign') === 'justify' ? 1 : 0 | 1 |
| la césure est active : sans elle une colonne étroite justifiée ouvre des rivières | cs('.vl-notched-float__p','hyphens') === 'auto' ? 1 : 0 | 1 |
| LA VIGNETTE EST PLEINE : moins d'une ligne de corps entre le texte et la marge du bas | H - box('.vl-notched-float__p').bottom - num('.vl-notched-float__card','paddingBottom') | -2 → 34 |
| contraste du titre ≥ 4,5 | contrast('.vl-notched-float__t') | ≥ 4.5 |
| contraste du corps ≥ 4,5 — c'est lui qui plafonne, pas le titre | contrast('.vl-notched-float__p') | ≥ 4.5 |
| aucun débordement du contenu hors de la vignette | overflow('.vl-notched-float') | ≤ 0 |
Le code
patterns/card-15-notched-float-statement.html
Télécharger<!-- card-15-notched-float-statement — vignette éditoriale chanfreinée qui FLOTTE.
Couleurs via --vl-* uniquement. Trois niveaux, et chacun existe pour une raison de
rendu, pas de style : la racine porte l'OMBRE (un filtre s'applique AVANT le
clip-path, donc une ombre posée sur l'élément clippé est découpée avec lui et
disparaît) ; `__card` porte le clip et l'aplat de CONTOUR (un clip-path mange les
bordures, le contour est donc un aplat, jamais un `border`) ; `::before` porte la
carte, insérée de l'épaisseur du contour.
`vl-notched-float--end` est la variante d'accent : UNE par rangée, et c'est une FIN. -->
<article class="vl-notched-float">
<div class="vl-notched-float__card">
<span class="vl-notched-float__fill" aria-hidden="true"></span>
<p class="vl-notched-float__t">La polyvalence métiers et systèmes des consultants</p>
<p class="vl-notched-float__p" lang="fr">Un même consultant tient la norme comptable et l'outil qui la produit. Le sujet n'est jamais coupé en deux entre un fonctionnel et un technique qui se renvoient la question d'un comité à l'autre. Le client garde un seul interlocuteur, et la question ne fait pas d'aller-retour.</p>
</div>
</article>
<style>
.vl-notched-float {
--nfs-notch: var(--vl-notch, 44px);
--nfs-bw: var(--vl-border, 2.6px);
/* Le chanfrein intérieur se DÉDUIT, il ne se choisit pas : décaler une oblique à 45°
de b raccourcit sa coupe de b(2 − √2) ≈ 0,586 b. Sans ce facteur le contour
s'épaissit dans les deux angles coupés, et c'est la seule chose que l'œil y voit. */
--nfs-notch-in: calc(var(--nfs-notch) - var(--nfs-bw) * 0.586);
--nfs-radius: var(--vl-radius, 15px);
--nfs-edge: var(--vl-edge);
--nfs-fill: var(--vl-card);
--nfs-ink: var(--vl-ink);
--nfs-ink-2: var(--vl-ink-muted);
width: 426px; height: 454px;
filter: drop-shadow(var(--vl-shadow));
transition: filter .22s ease, transform .22s ease;
font-family: Inter, system-ui, -apple-system, "Segoe UI", sans-serif;
}
.vl-notched-float:hover {
transform: translateY(-6px);
filter: drop-shadow(var(--vl-shadow-hover));
}
.vl-notched-float--end {
--nfs-edge: var(--vl-gold-edge);
--nfs-fill: var(--vl-gold);
--nfs-ink: var(--vl-on-gold);
--nfs-ink-2: var(--vl-on-gold-muted);
}
.vl-notched-float__card {
position: relative; isolation: isolate; box-sizing: border-box;
height: 100%; display: flex; flex-direction: column; align-items: flex-start;
padding: 34px; border-radius: var(--nfs-radius);
background-color: var(--nfs-fill);
background-image: linear-gradient(var(--nfs-edge), var(--nfs-edge));
clip-path: polygon(
0 0, calc(100% - var(--nfs-notch)) 0, 100% var(--nfs-notch),
100% 100%, var(--nfs-notch) 100%, 0 calc(100% - var(--nfs-notch))
);
}
.vl-notched-float__fill {
content: ''; position: absolute; inset: var(--nfs-bw); z-index: -1;
border-radius: calc(var(--nfs-radius) - var(--nfs-bw));
background: var(--nfs-fill);
clip-path: polygon(
0 0, calc(100% - var(--nfs-notch-in)) 0, 100% var(--nfs-notch-in),
100% 100%, var(--nfs-notch-in) 100%, 0 calc(100% - var(--nfs-notch-in))
);
}
.vl-notched-float__t {
margin: 0; font-size: 29px; line-height: 1.22; font-weight: 600;
letter-spacing: -0.018em; color: var(--nfs-ink);
}
/* Justifier une colonne étroite sans césure ouvre des rivières de blanc : ici la césure
n'est pas un ornement, c'est ce qui rend le drapeau justifié tenable. Elle suppose un
`lang` sur le document — sans lui, aucun dictionnaire, aucune coupe. */
.vl-notched-float__p {
margin: 16px 0 0; font-size: 22px; line-height: 1.52; color: var(--nfs-ink-2);
text-align: justify; hyphens: auto; -webkit-hyphens: auto;
hyphenate-limit-chars: 6 3 2;
}
</style>
systems/ref-20-finengy-navy-notched.json
Télécharger:root {
--vl-bg: #0D2A3D;
--vl-card: #1A3A52;
--vl-edge: rgba(244,247,249,0.34);
--vl-gold: #F5C518;
--vl-gold-edge: rgba(255,224,102,0.95);
--vl-ink: #FFFFFF;
--vl-ink-muted: rgba(244,247,249,0.72);
--vl-on-gold: #0D2A3D;
--vl-on-gold-muted: rgba(13,42,61,0.78);
--vl-notch: 44px;
--vl-radius: 15px;
--vl-border: 2.6px;
--vl-shadow: 0 15px 21px rgba(0,0,0,0.55);
--vl-shadow-hover: 0 26px 31px rgba(0,0,0,0.62);
--vl-gap: 40px;
--vl-margin: 120px;
}
les métadonnées — patterns/card-15-notched-float-statement.json (télécharger)
{
"name": "Vignette éditoriale chanfreinée, flottante et contourée",
"family": "card",
"ref": "ref-20-finengy-navy-notched",
"intent": "Porter un ENGAGEMENT — un titre affirmatif et son développement de plusieurs lignes — dans une vignette à silhouette de ticket qui flotte au-dessus d'un fond sombre : contour clair épais, ombre portée qui suit le chanfrein, texte justifié et coupé qui remplit la vignette jusqu'au dernier pixel.",
"when_to_use": "Trois à six promesses de même rang sur un fond sombre — méthode, engagements, différenciateurs — chacune valant un paragraphe et non une ligne. Une seule prend la variante `--end`, et c'est une FIN de série, pas un « le plus important ».",
"avoid_when": "Le développement tient en une ligne (la vignette se vide et le contour épais n'encadre plus rien : c'est card-02-notched-brief qu'il faut), la colonne descend sous ~260 px (le texte justifié y ouvre des rivières que la césure n'absorbe plus), ou le fond de page est clair — le contour clair et l'ombre noire n'y détachent rien.",
"media": [
"web",
"slide"
],
"tags": [
"carte",
"vignette",
"chanfrein",
"notch",
"contour",
"bordure",
"ombre",
"flottante",
"engagement",
"promesse",
"justifie",
"cesure",
"paragraphe",
"rangee",
"accent",
"fond-sombre",
"editorial"
],
"vars": [
{
"name": "--vl-card",
"role": "aplat de la vignette neutre — c'est LUI qui est sous le texte",
"default": "#1A3A52"
},
{
"name": "--vl-edge",
"role": "contour clair épais ; c'est un aplat, pas un `border`",
"default": "rgba(244,247,249,0.34)"
},
{
"name": "--vl-gold",
"role": "aplat de la variante de FIN",
"default": "#F5C518"
},
{
"name": "--vl-gold-edge",
"role": "contour de la variante de fin",
"default": "rgba(255,224,102,0.95)"
},
{
"name": "--vl-ink",
"role": "titre sur la vignette neutre",
"default": "#FFFFFF"
},
{
"name": "--vl-ink-muted",
"role": "corps sur la vignette neutre",
"default": "rgba(244,247,249,0.72)"
},
{
"name": "--vl-on-gold",
"role": "titre sur l'aplat de fin",
"default": "#0D2A3D"
},
{
"name": "--vl-on-gold-muted",
"role": "corps sur l'aplat de fin — c'est le contraste le plus SERRÉ du pattern (5,68:1)",
"default": "rgba(13,42,61,0.78)"
},
{
"name": "--vl-notch",
"role": "longueur du chanfrein, posée sur les DEUX coins de la diagonale",
"default": "44px"
},
{
"name": "--vl-radius",
"role": "rayon des deux coins non coupés",
"default": "15px"
},
{
"name": "--vl-border",
"role": "épaisseur du contour ; le chanfrein intérieur s'en déduit",
"default": "2.6px"
},
{
"name": "--vl-shadow",
"role": "ombre portée au repos, posée sur la RACINE et jamais sur la couche clippée",
"default": "0 15px 21px rgba(0,0,0,0.55)"
},
{
"name": "--vl-shadow-hover",
"role": "ombre au survol, avec un lift de 6 px",
"default": "0 26px 31px rgba(0,0,0,0.62)"
}
],
"slots": [
"titre",
"corps"
],
"geometry": {
"root": ".vl-notched-float",
"frame": [
426,
454
],
"ratios": {
"width_over_height": 0.938,
"notch_over_width": 0.103,
"border_over_width": 0.0061,
"radius_over_width": 0.035,
"pad_x_over_width": 0.0798,
"titre_over_corps": 1.318,
"lift_over_height": 0.0132,
"pad_y_over_height": 0.0749
},
"type_px": {
"titre": 29,
"corps": 22
},
"pad_ratio": {
"top": 0.0749,
"x": 0.0798,
"bottom": 0.0749
}
},
"benchmarks": [
{
"name": "vignette un rien plus haute que large",
"measure": "W / H",
"expect": 0.938,
"tol": 0.03
},
{
"name": "chanfrein ≈ 10,3 % de la largeur",
"measure": "notch('.vl-notched-float__card') / W",
"expect": 0.103,
"tol": 0.02
},
{
"name": "le polygone porte 6 sommets : DEUX coins coupés, pas un ni quatre",
"measure": "(cs('.vl-notched-float__card','clipPath').match(/,/g) || []).length + 1",
"expect": 6,
"tol": 0
},
{
"name": "la coupe commence au coin haut-droit (l'autre est son opposé sur la diagonale)",
"measure": "notchCorner('.vl-notched-float__card') === 'tr' ? 1 : 0",
"expect": 1
},
{
"name": "les coins non coupés gardent un rayon ≈ 3,5 % de la largeur",
"measure": "num('.vl-notched-float__card','borderTopLeftRadius') / W",
"expect": 0.035,
"tol": 0.015
},
{
"name": "L'OMBRE EST SUR LA RACINE : un filtre s'applique avant le clip, posée plus bas elle serait découpée",
"measure": "cs('.vl-notched-float','filter').indexOf('drop-shadow') >= 0 ? 1 : 0",
"expect": 1
},
{
"name": "la racine n'est PAS clippée — c'est ce qui laisse l'ombre exister",
"measure": "cs('.vl-notched-float','clipPath') === 'none' ? 1 : 0",
"expect": 1
},
{
"name": "la couche clippée ne porte AUCUN filtre — sinon l'ombre se découpe avec elle",
"measure": "cs('.vl-notched-float__card','filter') === 'none' ? 1 : 0",
"expect": 1
},
{
"name": "le contour n'est pas un `border` : un clip-path le mangerait",
"measure": "num('.vl-notched-float__card','borderTopWidth')",
"expect": 0,
"tol": 0
},
{
"name": "contour ≈ 0,61 % de la largeur — épais, mais un contour",
"measure": "parseFloat(cs('.vl-notched-float','--nfs-bw')) / W",
"expect": 0.0061,
"tol": 0.002
},
{
"name": "le contour existe bel et bien : l'aplat de carte est inséré de l'épaisseur déclarée",
"measure": "Math.abs(box('.vl-notched-float__fill').left - parseFloat(cs('.vl-notched-float','--nfs-bw')))",
"max": 0.6
},
{
"name": "la césure ne dépend d'aucun document d'accueil : le fragment déclare sa LANGUE",
"measure": "$('.vl-notched-float__p').closest('[lang]') ? 1 : 0",
"expect": 1
},
{
"name": "CHANFREIN INTÉRIEUR DÉDUIT : b(2−√2) ≈ 0,586 b de moins que l'extérieur, sinon le contour s'épaissit dans les angles",
"measure": "(notch('.vl-notched-float__card') - notch('.vl-notched-float__fill')) / parseFloat(cs('.vl-notched-float','--nfs-bw'))",
"expect": 0.586,
"tol": 0.02
},
{
"name": "marge intérieure gauche ≈ 8 % de la largeur",
"measure": "num('.vl-notched-float__card','paddingLeft') / W",
"expect": 0.0798,
"tol": 0.02
},
{
"name": "le titre ouvre la vignette : il colle la marge du haut",
"measure": "box('.vl-notched-float__t').top - num('.vl-notched-float__card','paddingTop')",
"expect": 0,
"tol": 2
},
{
"name": "saut typographique titre / corps entre 1,25 et 1,5 — un titre, pas un chiffre héros",
"measure": "num('.vl-notched-float__t','fontSize') / num('.vl-notched-float__p','fontSize')",
"min": 1.25,
"max": 1.5
},
{
"name": "le corps est JUSTIFIÉ — c'est la signature du pattern",
"measure": "cs('.vl-notched-float__p','textAlign') === 'justify' ? 1 : 0",
"expect": 1
},
{
"name": "la césure est active : sans elle une colonne étroite justifiée ouvre des rivières",
"measure": "cs('.vl-notched-float__p','hyphens') === 'auto' ? 1 : 0",
"expect": 1
},
{
"name": "LA VIGNETTE EST PLEINE : moins d'une ligne de corps entre le texte et la marge du bas",
"measure": "H - box('.vl-notched-float__p').bottom - num('.vl-notched-float__card','paddingBottom')",
"min": -2,
"max": 34
},
{
"name": "contraste du titre ≥ 4,5",
"measure": "contrast('.vl-notched-float__t')",
"min": 4.5
},
{
"name": "contraste du corps ≥ 4,5 — c'est lui qui plafonne, pas le titre",
"measure": "contrast('.vl-notched-float__p')",
"min": 4.5
},
{
"name": "aucun débordement du contenu hors de la vignette",
"measure": "overflow('.vl-notched-float')",
"max": 0
}
],
"notes": "Le fragment livré est la variante de FIN (`vl-notched-float--end`) : c'est l'état le plus serré en contraste (corps #404C35 sur #F5C518, 5,68:1, contre 7,4:1 sur la vignette marine), et un benchmark ne garde que ce qu'il mesure. DEUX lois de rendu portent ce pattern, et aucune n'est cosmétique. (1) Un filtre s'applique AVANT le clip-path : une ombre posée sur l'élément chanfreiné est découpée avec lui et disparaît — sans erreur, sans warning. Elle vit donc un cran au-dessus, d'où la racine non clippée. Corollaire payé au passage : `drop-shadow()` n'accepte PAS de rayon d'étalement ; une quatrième longueur rend la fonction invalide et le filtre entier est ignoré, toujours en silence. (2) Un clip-path mange les bordures : le contour est l'aplat de la couche clippée, la carte étant peinte par `::before` inséré de son épaisseur — et le chanfrein intérieur se DÉDUIT (décaler une oblique à 45° de b raccourcit sa coupe de b(2−√2) ≈ 0,586 b), faute de quoi le contour s'épaissit dans les deux angles coupés. Piège de MESURE, même arbitrage que card-10 : `bin/check.mjs` lit `background-color` et jamais `background-image`, et il ne voit pas un `::before`. Le fond réel du texte étant l'aplat de carte, c'est LUI qui est déclaré en `background-color` et le contour qui est peint en `background-image` — sans quoi le contraste se mesurait contre le contour clair, un fond que le texte ne touche jamais. Ce n'est pas une variante de card-02-notched-brief, dont le `avoid_when` renvoie explicitement ici (« l'explication dépasse quatre lignes ⇒ c'est un paragraphe qui mérite sa colonne ») et qui n'a ni double chanfrein, ni contour, ni ombre ; ni de card-10-kpi-notch-tile, qui partage la seule silhouette et porte un CHIFFRE, sans contour ni flottement.",
"id": "card-15-notched-float-statement"
}
À 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