{
  "nom": "The \"Strates\" system",
  "langue": "en",
  "page": "https://florianbutour.com/en/system",
  "genere": "2026-11-04T15:25:25.255Z",
  "introduction": [
    "The system behind this site, from token to page template. Three colours carry the page: white to read, blue to assert, black to identify. Two typefaces: Archivo for headings, Schibsted Grotesk for everything else.",
    "It is organised in five levels, each built from the previous one. Components are generic: a card, a button, a tag, with their variants. How the site uses them is described at the level of organisms and templates."
  ],
  "ecritsLies": [
    {
      "titre": "A design system that stops at the button",
      "these": "Business patterns extend the components of a design system by organising interactions around recurring tasks.",
      "url": "https://florianbutour.com/en/writing/a-design-system-that-stops-at-the-button"
    },
    {
      "titre": "AI, the product’s second user",
      "these": "When an agent acts on someone’s behalf, designing the product means defining what that person can delegate to it, how they stay in control and how they understand what was done.",
      "url": "https://florianbutour.com/en/writing/ai-the-products-second-user"
    }
  ],
  "niveaux": {
    "jetons": {
      "titre": "Tokens",
      "description": "The base decisions, named by role and never by value. No component uses a colour, size or spacing that is not a token."
    },
    "atomes": {
      "titre": "Atoms",
      "description": "The smallest interface elements, with no domain content. They only use tokens."
    },
    "molecules": {
      "titre": "Molecules",
      "description": "Atoms assembled into an element with a function: a card, a header, a tooltip."
    },
    "organismes": {
      "titre": "Organisms",
      "description": "Molecules and atoms assembled for a task of the site: copying a link, presenting a method pillar, navigating."
    },
    "gabarits": {
      "titre": "Templates",
      "description": "Page structures. Each template serves both languages; pages only pass it the language."
    }
  },
  "jetons": {
    "color": {
      "background": {
        "canvas": {
          "$type": "color",
          "$value": "#ffffff",
          "$description": "Page background.",
          "$extensions": {
            "css": "--color-background-canvas"
          }
        },
        "brand": {
          "$type": "color",
          "$value": "#1f2be0",
          "$description": "Hero column, Position block, On tags, hover fill.",
          "$extensions": {
            "css": "--color-background-brand"
          }
        },
        "inverse": {
          "$type": "color",
          "$value": "#0d0d0d",
          "$description": "Identity bar, dark board, footer.",
          "$extensions": {
            "css": "--color-background-inverse"
          }
        },
        "subtle": {
          "$type": "color",
          "$value": "#f5f5f5",
          "$description": "Inset, figure frame, floating box, card hover.",
          "$extensions": {
            "css": "--color-background-subtle"
          }
        },
        "overlay": {
          "$type": "color",
          "$value": "rgb(13 13 13 / 0.4)",
          "$description": "Veil behind an open dialog.",
          "$extensions": {
            "css": "--color-background-overlay"
          }
        }
      },
      "surface": {
        "inactive": {
          "$type": "color",
          "$value": "#e7e7e7",
          "$description": "Off tag.",
          "$extensions": {
            "css": "--color-surface-inactive"
          }
        },
        "placeholder": {
          "$type": "color",
          "$value": "#d4d4d4",
          "$description": "Placeholder for a visual not yet delivered (preview only).",
          "$extensions": {
            "css": "--color-surface-placeholder"
          }
        }
      },
      "text": {
        "primary": {
          "$type": "color",
          "$value": "#0d0d0d",
          "$description": "Headings and body text. 19.4:1 on canvas.",
          "$extensions": {
            "css": "--color-text-primary"
          }
        },
        "secondary": {
          "$type": "color",
          "$value": "#2a2a2a",
          "$description": "Secondary text. 14.4:1 on canvas.",
          "$extensions": {
            "css": "--color-text-secondary"
          }
        },
        "muted": {
          "$type": "color",
          "$value": "#737373",
          "$description": "Metadata, captions, labels. 4.7:1 on canvas.",
          "$extensions": {
            "css": "--color-text-muted"
          }
        },
        "supporting": {
          "$type": "color",
          "$value": "#5c5c59",
          "$description": "Text of an Off tag. 5.4:1 on surface/inactive.",
          "$extensions": {
            "css": "--color-text-supporting"
          }
        },
        "inverse": {
          "$type": "color",
          "$value": "#ffffff",
          "$description": "Text on blue or black. 8.5:1 on brand, 19.4:1 on inverse.",
          "$extensions": {
            "css": "--color-text-inverse"
          }
        },
        "on-brand-secondary": {
          "$type": "color",
          "$value": "#daddff",
          "$description": "Secondary text on blue. 6.4:1 on brand.",
          "$extensions": {
            "css": "--color-text-on-brand-secondary"
          }
        },
        "on-brand-muted": {
          "$type": "color",
          "$value": "rgb(255 255 255 / 0.8)",
          "$description": "Text of an On tag. 5.9:1 on brand.",
          "$extensions": {
            "css": "--color-text-on-brand-muted"
          }
        },
        "on-dark-muted": {
          "$type": "color",
          "$value": "#9a9a9a",
          "$description": "Secondary text on black. 6.9:1 on inverse.",
          "$extensions": {
            "css": "--color-text-on-dark-muted"
          }
        }
      },
      "border": {
        "default": {
          "$type": "color",
          "$value": "#e7e7e7",
          "$description": "Subtle separators between rows and cards. Decorative.",
          "$extensions": {
            "css": "--color-border-default"
          }
        },
        "ink": {
          "$type": "color",
          "$value": "#0d0d0d",
          "$description": "Rule under headings, outline of the rule button, floating box.",
          "$extensions": {
            "css": "--color-border-ink"
          }
        },
        "white": {
          "$type": "color",
          "$value": "#ffffff",
          "$description": "Button outline on dark backgrounds.",
          "$extensions": {
            "css": "--color-border-white"
          }
        },
        "on-dark": {
          "$type": "color",
          "$value": "#333333",
          "$description": "Separators on black.",
          "$extensions": {
            "css": "--color-border-on-dark"
          }
        }
      }
    },
    "fontWeight": {
      "regular": {
        "$type": "fontWeight",
        "$value": 400,
        "$description": "Body, Lead, Caption, Label.",
        "$extensions": {
          "css": "--font-weight-regular"
        }
      },
      "medium": {
        "$type": "fontWeight",
        "$value": 500,
        "$description": "UI, Body Strong, emphasis (`strong`), floating box titles.",
        "$extensions": {
          "css": "--font-weight-medium"
        }
      },
      "extrabold": {
        "$type": "fontWeight",
        "$value": 800,
        "$description": "Heading/40 and Heading/24.",
        "$extensions": {
          "css": "--font-weight-extrabold"
        }
      },
      "black": {
        "$type": "fontWeight",
        "$value": 900,
        "$description": "Display.",
        "$extensions": {
          "css": "--font-weight-black"
        }
      }
    },
    "typography": {
      "display": {
        "$type": "typography",
        "$value": {
          "fontFamily": "'Archivo', 'Arial Black', system-ui, sans-serif",
          "fontWeight": 900,
          "fontSize": "clamp(2.5rem, 1.972rem + 2.254vw, 4rem)",
          "lineHeight": "0.9375",
          "letterSpacing": "-0.06em"
        },
        "$description": "Page title, hero line, Position statement, email address.",
        "$extensions": {
          "css": ".text-display"
        }
      },
      "heading-40": {
        "$type": "typography",
        "$value": {
          "fontFamily": "'Archivo', 'Arial Black', system-ui, sans-serif",
          "fontWeight": 800,
          "fontSize": "clamp(1.75rem, 1.486rem + 1.127vw, 2.5rem)",
          "lineHeight": "1",
          "letterSpacing": "-0.035em"
        },
        "$description": "Section and L card headings, pillar titles.",
        "$extensions": {
          "css": ".text-heading-40"
        }
      },
      "heading-24": {
        "$type": "typography",
        "$value": {
          "fontFamily": "'Archivo', 'Arial Black', system-ui, sans-serif",
          "fontWeight": 800,
          "fontSize": "clamp(1.25rem, 1.162rem + 0.376vw, 1.5rem)",
          "lineHeight": "1",
          "letterSpacing": "-0.035em"
        },
        "$description": "M card headings, subheadings, L tag.",
        "$extensions": {
          "css": ".text-heading-24"
        }
      },
      "lead": {
        "$type": "typography",
        "$value": {
          "fontFamily": "'Schibsted Grotesk', system-ui, -apple-system, 'Segoe UI', sans-serif",
          "fontWeight": 400,
          "fontSize": "clamp(1.1875rem, 1.121rem + 0.282vw, 1.375rem)",
          "lineHeight": "1.3636"
        },
        "$description": "Standfirst, insets, blue column sentence.",
        "$extensions": {
          "css": ".text-lead"
        }
      },
      "body": {
        "$type": "typography",
        "$value": {
          "fontFamily": "'Schibsted Grotesk', system-ui, -apple-system, 'Segoe UI', sans-serif",
          "fontWeight": 400,
          "fontSize": "1.0625rem",
          "lineHeight": "1.5294"
        },
        "$description": "Body text.",
        "$extensions": {
          "css": ".text-body"
        }
      },
      "body-strong": {
        "$type": "typography",
        "$value": {
          "fontFamily": "'Schibsted Grotesk', system-ui, -apple-system, 'Segoe UI', sans-serif",
          "fontWeight": 500,
          "fontSize": "1.0625rem",
          "lineHeight": "1.5294"
        },
        "$description": "Emphasised sentence start.",
        "$extensions": {
          "css": ".text-body-strong"
        }
      },
      "ui": {
        "$type": "typography",
        "$value": {
          "fontFamily": "'Schibsted Grotesk', system-ui, -apple-system, 'Segoe UI', sans-serif",
          "fontWeight": 500,
          "fontSize": "0.9375rem",
          "lineHeight": "1.3333"
        },
        "$description": "Navigation, follow-up links, contents.",
        "$extensions": {
          "css": ".text-ui"
        }
      },
      "caption": {
        "$type": "typography",
        "$value": {
          "fontFamily": "'Schibsted Grotesk', system-ui, -apple-system, 'Segoe UI', sans-serif",
          "fontWeight": 400,
          "fontSize": "0.8125rem",
          "lineHeight": "1.5385"
        },
        "$description": "Metadata, captions, S tags.",
        "$extensions": {
          "css": ".text-caption"
        }
      },
      "label": {
        "$type": "typography",
        "$value": {
          "fontFamily": "'Schibsted Grotesk', system-ui, -apple-system, 'Segoe UI', sans-serif",
          "fontWeight": 400,
          "fontSize": "0.75rem",
          "lineHeight": "1.1667",
          "textTransform": "uppercase"
        },
        "$description": "Eyebrows and section labels, in capitals.",
        "$extensions": {
          "css": ".text-label"
        }
      }
    },
    "spacing": {
      "2": {
        "$type": "dimension",
        "$value": {
          "value": 2,
          "unit": "px"
        },
        "$extensions": {
          "css": "--space-2"
        }
      },
      "4": {
        "$type": "dimension",
        "$value": {
          "value": 4,
          "unit": "px"
        },
        "$extensions": {
          "css": "--space-4"
        }
      },
      "6": {
        "$type": "dimension",
        "$value": {
          "value": 6,
          "unit": "px"
        },
        "$extensions": {
          "css": "--space-6"
        }
      },
      "8": {
        "$type": "dimension",
        "$value": {
          "value": 8,
          "unit": "px"
        },
        "$extensions": {
          "css": "--space-8"
        }
      },
      "12": {
        "$type": "dimension",
        "$value": {
          "value": 12,
          "unit": "px"
        },
        "$extensions": {
          "css": "--space-12"
        }
      },
      "16": {
        "$type": "dimension",
        "$value": {
          "value": 16,
          "unit": "px"
        },
        "$extensions": {
          "css": "--space-16"
        }
      },
      "20": {
        "$type": "dimension",
        "$value": {
          "value": 20,
          "unit": "px"
        },
        "$extensions": {
          "css": "--space-20"
        }
      },
      "24": {
        "$type": "dimension",
        "$value": {
          "value": 24,
          "unit": "px"
        },
        "$extensions": {
          "css": "--space-24"
        }
      },
      "32": {
        "$type": "dimension",
        "$value": {
          "value": 32,
          "unit": "px"
        },
        "$extensions": {
          "css": "--space-32"
        }
      },
      "40": {
        "$type": "dimension",
        "$value": {
          "value": 40,
          "unit": "px"
        },
        "$extensions": {
          "css": "--space-40"
        }
      },
      "48": {
        "$type": "dimension",
        "$value": {
          "value": 48,
          "unit": "px"
        },
        "$extensions": {
          "css": "--space-48"
        }
      },
      "56": {
        "$type": "dimension",
        "$value": {
          "value": 56,
          "unit": "px"
        },
        "$extensions": {
          "css": "--space-56"
        }
      },
      "64": {
        "$type": "dimension",
        "$value": {
          "value": 64,
          "unit": "px"
        },
        "$extensions": {
          "css": "--space-64"
        }
      },
      "72": {
        "$type": "dimension",
        "$value": {
          "value": 72,
          "unit": "px"
        },
        "$extensions": {
          "css": "--space-72"
        }
      },
      "80": {
        "$type": "dimension",
        "$value": {
          "value": 80,
          "unit": "px"
        },
        "$extensions": {
          "css": "--space-80"
        }
      },
      "96": {
        "$type": "dimension",
        "$value": {
          "value": 96,
          "unit": "px"
        },
        "$extensions": {
          "css": "--space-96"
        }
      },
      "112": {
        "$type": "dimension",
        "$value": {
          "value": 112,
          "unit": "px"
        },
        "$extensions": {
          "css": "--space-112"
        }
      },
      "128": {
        "$type": "dimension",
        "$value": {
          "value": 128,
          "unit": "px"
        },
        "$extensions": {
          "css": "--space-128"
        }
      }
    },
    "layout": {
      "max": {
        "$value": "90rem",
        "$description": "Maximum content width (1,440 px).",
        "$extensions": {
          "css": "--layout-max"
        }
      },
      "gutter": {
        "$value": "clamp(1.25rem, 0.458rem + 3.38vw, 3.5rem)",
        "$description": "Single side margin, from 20 to 56 px.",
        "$extensions": {
          "css": "--layout-gutter"
        }
      },
      "nav-height": {
        "$value": "5.375rem",
        "$description": "Navigation height (86 px).",
        "$extensions": {
          "css": "--layout-nav-height"
        }
      },
      "offset": {
        "$value": "19rem",
        "$description": "Indent of cards in lists (304 px).",
        "$extensions": {
          "css": "--layout-offset"
        }
      },
      "strates-width": {
        "$value": "16.25rem",
        "$description": "Column of vertical tag groups (260 px).",
        "$extensions": {
          "css": "--layout-strates-width"
        }
      },
      "section": {
        "$value": "8.75rem",
        "$description": "Top of home sections and hero, 404 page (140 px).",
        "$extensions": {
          "css": "--layout-section"
        }
      },
      "ecrit-tete": {
        "$value": "16.5rem",
        "$description": "Top of writing pages (264 px).",
        "$extensions": {
          "css": "--layout-ecrit-tete"
        }
      },
      "page-tete": {
        "$value": "clamp(5rem, 0.6rem + 18.78vw, 17.5rem)",
        "$description": "Top of inner pages, from 80 to 280 px.",
        "$extensions": {
          "css": "--layout-page-tete"
        }
      }
    },
    "motion": {
      "duration": {
        "$type": "duration",
        "$value": {
          "value": 200,
          "unit": "ms"
        },
        "$description": "Hovers, button and navigation fills (200 ms).",
        "$extensions": {
          "css": "--motion-duration"
        }
      },
      "duration-long": {
        "$type": "duration",
        "$value": {
          "value": 400,
          "unit": "ms"
        },
        "$description": "Card sweep, reveals, method figures (400 ms).",
        "$extensions": {
          "css": "--motion-duration-long"
        }
      },
      "ease": {
        "$type": "cubicBezier",
        "$value": [
          0.2,
          0,
          0,
          1
        ],
        "$description": "Curve shared by all motion.",
        "$extensions": {
          "css": "--motion-ease"
        }
      }
    }
  },
  "regles": {
    "couleurs": [
      "A single accent, blue, always as a flat fill.",
      "On blue, text uses text/inverse, text/on-brand-secondary or text/on-brand-muted, never text/muted.",
      "Black frames the identity (bar under the hero, footer). No third background.",
      "text/muted (4.7:1) is for metadata and captions, from 12 px, never for a sentence that must be read. It stays on canvas: on background/subtle it drops to 4.3:1, below the AA threshold.",
      "A component only uses these roles (`--color-<group>-<name>`), never a hard-coded value."
    ],
    "typographie": [
      "Archivo is only for headings, never for a sentence longer than three lines.",
      "Capitals come from Label, never from the typed text.",
      "An emphasised sentence start uses Body Strong or `strong`, never a weight applied by hand.",
      "Each style sets its own weight, whatever element carries it (an h3 heading in Label stays Regular)."
    ],
    "graisses": [
      "A weight always comes from a token or a text style.",
      "`strong` is Medium everywhere, through a global rule."
    ],
    "espacements": [
      "Margins, indents, gaps and offsets only use the `--space-<px>` scale.",
      "Every pixel dimension is even.",
      "Large layout measures use the `--layout-*` tokens."
    ],
    "miseEnPage": [
      "A single side margin, `--layout-gutter`, 56 px on desktop, 20 px on mobile.",
      "Breakpoints: mobile below 40rem, tablet from 40 to 64rem, desktop beyond."
    ],
    "mouvement": [
      "Tags are never animated.",
      "Reveals happen once, when entering the screen."
    ]
  },
  "composants": [
    {
      "id": "Bouton",
      "nom": "Button",
      "niveau": "atomes",
      "fichier": "src/components/atomes/Bouton.astro",
      "figma": [
        "2:493",
        "8:480"
      ],
      "role": "Triggers an action or leads to a page. Rendered as a link when it has an address, as a button otherwise.",
      "variantes": [
        "plein (filled): light background; on hover, a blue fill sweeps the button from its left edge.",
        "contour (outline): white outline, for dark surfaces; on hover, a white fill.",
        "accent: blue fill, white text. Primary action on a light background.",
        "filet (rule): ink outline on white. Secondary action on a light background.",
        "Sizes M (16 × 24 px) and S (12 × 20 px).",
        "Unavailable: if the address is still \"À compléter\", the button becomes neutral text (preview only)."
      ],
      "proprietes": [
        {
          "nom": "variante",
          "type": "'plein' | 'contour' | 'accent' | 'filet'",
          "obligatoire": false,
          "defaut": "'plein'",
          "description": "Appearance of the button."
        },
        {
          "nom": "taille",
          "type": "'M' | 'S'",
          "obligatoire": false,
          "defaut": "'M'",
          "description": "M by default, S in floating boxes."
        },
        {
          "nom": "href",
          "type": "string",
          "obligatoire": false,
          "description": "Address; without it, the button is a button element."
        }
      ],
      "slots": [
        {
          "nom": "defaut",
          "description": "Label."
        }
      ],
      "faire": [
        "A short label that states the action or the destination.",
        "On a dark background, plein or contour; on a light background, accent or filet."
      ],
      "eviter": [
        "A button for a link in running text: use Link.",
        "Two accent buttons side by side."
      ],
      "accessibilite": [
        "Visible focus: 2 px outline in the text colour.",
        "Outside a form, `type` is \"button\"; it can be replaced (\"submit\" in a dialog)."
      ],
      "composeDe": [],
      "utilisePar": [
        "CopieLienIA",
        "Accueil",
        "Parcours"
      ],
      "exemple": "<Bouton variante=\"plein\" href=\"/travaux\">Voir les travaux ↓</Bouton>\n<Bouton variante=\"accent\" taille=\"S\" type=\"submit\" value=\"copier\">Copier</Bouton>"
    },
    {
      "id": "Encart",
      "nom": "Inset",
      "niveau": "atomes",
      "fichier": "src/components/atomes/Encart.astro",
      "figma": [],
      "role": "Sets an introductory text apart on a light grey background.",
      "variantes": [
        "A single appearance. Padding goes from 24 × 32 to 20 px on mobile."
      ],
      "proprietes": [],
      "slots": [
        {
          "nom": "defaut",
          "description": "Text of the inset."
        }
      ],
      "faire": [
        "One paragraph in Lead, right under a header."
      ],
      "eviter": [
        "Several insets in a row.",
        "An inset for an alert or a status message."
      ],
      "accessibilite": [
        "The background is decorative; the text keeps its contrast (17.8:1 in text/primary)."
      ],
      "composeDe": [],
      "utilisePar": [
        "Accueil",
        "Cas",
        "Ecrit"
      ],
      "exemple": "<Encart><p class=\"text-lead\">Chapô du cas.</p></Encart>"
    },
    {
      "id": "Etiquette",
      "nom": "Tag",
      "niveau": "atomes",
      "fichier": "src/components/atomes/Etiquette.astro",
      "figma": [
        "2:494"
      ],
      "role": "A text band that qualifies a content, such as a layer touched or a practice.",
      "variantes": [
        "Size S: Caption on a 28 px band. On in blue, Off in grey.",
        "Size L: Heading/24 on a blue fill, white text. Used as a heading."
      ],
      "proprietes": [
        {
          "nom": "taille",
          "type": "'S' | 'L'",
          "obligatoire": false,
          "defaut": "'S'",
          "description": "S (band) or L (heading)."
        },
        {
          "nom": "etat",
          "type": "boolean",
          "obligatoire": false,
          "defaut": "true",
          "description": "On (true) or Off (false)."
        },
        {
          "nom": "etatTexte",
          "type": "string",
          "obligatoire": false,
          "description": "Text read after the label, for example \"touched\"."
        },
        {
          "nom": "balise",
          "type": "'span' | 'h2' | 'h3' | 'h4'",
          "obligatoire": false,
          "defaut": "'span'",
          "description": "Rendered element; a heading level when the tag names a block."
        }
      ],
      "slots": [
        {
          "nom": "defaut",
          "description": "Label."
        }
      ],
      "faire": [
        "Give the state as text with `etatTexte` when On and Off carry meaning.",
        "Group the tags of one content in a Tag group."
      ],
      "eviter": [
        "Animating a tag or making it clickable.",
        "A tag for an action."
      ],
      "accessibilite": [
        "The state is never carried by colour alone: `etatTexte` is read after the label.",
        "Off: text/supporting on surface/inactive, 5.4:1."
      ],
      "composeDe": [],
      "utilisePar": [
        "Carte",
        "GroupeEtiquettes"
      ],
      "exemple": "<Etiquette etat={false} etatTexte=\"non touchée\">modèle</Etiquette>\n<Etiquette taille=\"L\" balise=\"h3\">surfaces</Etiquette>"
    },
    {
      "id": "Lien",
      "nom": "Link",
      "niveau": "atomes",
      "fichier": "src/components/atomes/Lien.astro",
      "figma": [],
      "role": "A link outside running text, not underlined at rest, underlined on hover.",
      "variantes": [
        "Any text style (UI, Heading/24…)."
      ],
      "proprietes": [
        {
          "nom": "href",
          "type": "string",
          "obligatoire": true,
          "description": "Address."
        },
        {
          "nom": "texte",
          "type": "string",
          "obligatoire": false,
          "description": "Text style class, for example \"text-ui\"."
        }
      ],
      "slots": [
        {
          "nom": "defaut",
          "description": "Label."
        }
      ],
      "faire": [
        "A label that states the destination, with an arrow when it leads onward."
      ],
      "eviter": [
        "A link inside a paragraph: running text underlines its links."
      ],
      "accessibilite": [
        "Outside running text, its position and style are enough to recognise it; focus stays visible."
      ],
      "composeDe": [],
      "utilisePar": [
        "PiedDePage",
        "Cas",
        "Ecrit"
      ],
      "exemple": "<Lien texte=\"text-ui\" href=\"/ecrits\">← Tous les écrits</Lien>"
    },
    {
      "id": "Carte",
      "nom": "Card",
      "niveau": "molecules",
      "fichier": "src/components/molecules/Carte.astro",
      "figma": [
        "2:489",
        "9:1600",
        "2:491"
      ],
      "role": "Presents a content in summary, with or without a visual, and leads to it.",
      "variantes": [
        "Row appearance, size L: Heading/40 title, text and metadata. Without a visual, tags in a column on the right; with a visual (400 × 300, on the left), tags under the text.",
        "Row appearance, size M: Heading/24 title, tags in a row under the text.",
        "Frame appearance: border, visual on top, no link; the title can be an L tag.",
        "304 px indent on desktop: by default in size M and in size L without a visual."
      ],
      "proprietes": [
        {
          "nom": "taille",
          "type": "'L' | 'M'",
          "obligatoire": false,
          "defaut": "'M'",
          "description": "L or M."
        },
        {
          "nom": "apparence",
          "type": "'ligne' | 'cadre'",
          "obligatoire": false,
          "defaut": "'ligne'",
          "description": "ligne (clickable list row) or cadre (framed block)."
        },
        {
          "nom": "titre",
          "type": "string",
          "obligatoire": true,
          "description": "Card title."
        },
        {
          "nom": "texte",
          "type": "string",
          "obligatoire": true,
          "description": "Description or thesis."
        },
        {
          "nom": "meta",
          "type": "string",
          "obligatoire": false,
          "description": "Metadata line in Caption, for example \"company · domain\"."
        },
        {
          "nom": "href",
          "type": "string",
          "obligatoire": false,
          "description": "Address of the content (row appearance)."
        },
        {
          "nom": "visuel",
          "type": "{ src?: ImageMetadata | string; alt: string; largeur?: number; hauteur?: number }",
          "obligatoire": false,
          "description": "Image and its alternative text; without an image, a fill holds the space in preview."
        },
        {
          "nom": "etiquettes",
          "type": "ItemEtiquette[]",
          "obligatoire": false,
          "description": "Tags of the Tag group."
        },
        {
          "nom": "etiquettesLibelle",
          "type": "string",
          "obligatoire": false,
          "description": "Name of the tag list for assistive technologies."
        },
        {
          "nom": "retrait",
          "type": "boolean",
          "obligatoire": false,
          "description": "304 px indent on desktop."
        },
        {
          "nom": "titreEtiquette",
          "type": "boolean",
          "obligatoire": false,
          "defaut": "false",
          "description": "Title rendered as an L tag (frame appearance)."
        },
        {
          "nom": "niveau",
          "type": "2 | 3 | 4",
          "obligatoire": false,
          "defaut": "3",
          "description": "Heading level."
        },
        {
          "nom": "lang",
          "type": "string",
          "obligatoire": false,
          "description": "Language of the content, if it differs from the page."
        }
      ],
      "slots": [],
      "faire": [
        "Stack row cards in a list, separated by their rule.",
        "Keep one size per list: L for case studies, M for writing."
      ],
      "eviter": [
        "A second link inside a row card: the whole card is already clickable.",
        "A frame card for content to open."
      ],
      "accessibilite": [
        "The link sits on the title and stretches over the whole card; there is a single tab stop.",
        "On keyboard focus, the background sweeps the card as on hover.",
        "The heading level follows the page hierarchy (`niveau`)."
      ],
      "composeDe": [
        "Etiquette",
        "GroupeEtiquettes"
      ],
      "utilisePar": [
        "Accueil",
        "Ecrit",
        "ListeEcrits",
        "ListeTravaux"
      ],
      "exemple": "<Carte taille=\"L\" titre=\"…\" texte=\"…\" meta=\"Entreprise · domaine\" href=\"/travaux/…\"\n  visuel={{ src: image, alt: '…' }} etiquettes={etiquettesStrates(strates, ui)} etiquettesLibelle=\"Strates touchées\" />\n<Carte {...carteDEcrit(ecrit, locale, ui)} retrait={false} />"
    },
    {
      "id": "EnTete",
      "nom": "Header",
      "niveau": "molecules",
      "fichier": "src/components/molecules/EnTete.astro",
      "figma": [
        "2:488"
      ],
      "role": "Opens a page or a section with a Display heading.",
      "variantes": [
        "Section: 20 px under the heading, set on a 3 px ink rule.",
        "Page: 72 px under the heading (40 px on mobile), with or without a rule."
      ],
      "proprietes": [
        {
          "nom": "titre",
          "type": "string",
          "obligatoire": true,
          "description": "Heading text."
        },
        {
          "nom": "niveau",
          "type": "1 | 2",
          "obligatoire": false,
          "defaut": "2",
          "description": "1 at the top of a page, 2 in a section."
        },
        {
          "nom": "id",
          "type": "string",
          "obligatoire": false,
          "description": "Heading identifier, for aria-labelledby and anchors."
        },
        {
          "nom": "espace",
          "type": "'section' | 'page'",
          "obligatoire": false,
          "defaut": "'section'",
          "description": "section or page."
        },
        {
          "nom": "filet",
          "type": "boolean",
          "obligatoire": false,
          "defaut": "true",
          "description": "Ink rule under the heading."
        }
      ],
      "slots": [],
      "faire": [
        "A single level 1 header per page."
      ],
      "eviter": [
        "A header for a card or block title: use the Heading styles."
      ],
      "accessibilite": [
        "`niveau` sets h1 or h2; `id` lets the enclosing section be named."
      ],
      "composeDe": [],
      "utilisePar": [
        "Accueil",
        "Cas",
        "Contact",
        "Ecrit",
        "ListeEcrits",
        "ListeTravaux",
        "Parcours"
      ],
      "exemple": "<EnTete titre=\"Travaux\" niveau={1} espace=\"page\" />"
    },
    {
      "id": "Figure",
      "nom": "Figure",
      "niveau": "molecules",
      "fichier": "src/components/molecules/Figure.astro",
      "figma": [
        "119:8515"
      ],
      "role": "An illustration on a grey background and its caption, in a frame with fixed proportions.",
      "variantes": [
        "The frame keeps its proportions (`ratio`); figures of the same rank replace each other without the page moving."
      ],
      "proprietes": [
        {
          "nom": "src",
          "type": "string",
          "obligatoire": true,
          "description": "Image address, in public/."
        },
        {
          "nom": "legende",
          "type": "string",
          "obligatoire": true,
          "description": "Caption in Caption."
        },
        {
          "nom": "alt",
          "type": "string",
          "obligatoire": false,
          "defaut": "''",
          "description": "Alternative text; empty when the caption is enough."
        },
        {
          "nom": "ratio",
          "type": "string",
          "obligatoire": false,
          "defaut": "'676 / 578'",
          "description": "Frame proportions."
        }
      ],
      "slots": [],
      "faire": [
        "A caption that describes what the figure shows."
      ],
      "eviter": [
        "A caption that repeats the nearby heading."
      ],
      "accessibilite": [
        "By default the illustration is decorative (empty alt) and the caption describes it; an alternative text can be passed."
      ],
      "composeDe": [],
      "utilisePar": [
        "Accueil"
      ],
      "exemple": "<Figure src=\"/images/methode/cadrer.svg\" legende=\"Fig. 04 · Un parcours, ses moments et ses frictions\" />"
    },
    {
      "id": "GroupeEtiquettes",
      "nom": "Tag group",
      "niveau": "molecules",
      "fichier": "src/components/molecules/GroupeEtiquettes.astro",
      "figma": [],
      "role": "A list of S tags, each On or Off.",
      "variantes": [
        "Vertical: 260 px column. Horizontal: 140 px bands.",
        "Folding below a breakpoint: in a row, with stretched tags (mobile) or at their natural width (tablet)."
      ],
      "proprietes": [
        {
          "nom": "etiquettes",
          "type": "ItemEtiquette[]",
          "obligatoire": true,
          "description": "Label, state and state text of each tag."
        },
        {
          "nom": "libelle",
          "type": "string",
          "obligatoire": false,
          "description": "Name of the list for assistive technologies."
        },
        {
          "nom": "orientation",
          "type": "'verticale' | 'horizontale'",
          "obligatoire": false,
          "defaut": "'verticale'",
          "description": "verticale or horizontale."
        },
        {
          "nom": "replier",
          "type": "'mobile' | 'tablette'",
          "obligatoire": false,
          "description": "Breakpoint below which the group goes into a row."
        }
      ],
      "slots": [],
      "faire": [
        "The same tags in the same order for one content type (the three layers, always in the order surfaces, design system, model)."
      ],
      "eviter": [
        "Mixing tags of different kinds in one group."
      ],
      "accessibilite": [
        "A list named by `libelle`; each state is read as text."
      ],
      "composeDe": [
        "Etiquette"
      ],
      "utilisePar": [
        "Carte",
        "PilierDeMethode",
        "Cas",
        "Parcours"
      ],
      "exemple": "<GroupeEtiquettes etiquettes={[{ libelle: 'surfaces', etat: true, etatTexte: 'touchée' }]}\n  libelle=\"Strates touchées\" orientation=\"horizontale\" replier=\"mobile\" />"
    },
    {
      "id": "Infobulle",
      "nom": "Tooltip",
      "niveau": "molecules",
      "fichier": "src/components/molecules/Infobulle.astro",
      "figma": [
        "111:5507"
      ],
      "role": "Shows a text before an action, on hover and keyboard focus of its host.",
      "variantes": [
        "Below the host, or above when space is lacking; aligned to the start or the end of the host."
      ],
      "proprietes": [
        {
          "nom": "id",
          "type": "string",
          "obligatoire": true,
          "description": "Identifier, for aria-describedby."
        },
        {
          "nom": "titre",
          "type": "string",
          "obligatoire": true,
          "description": "Box title."
        },
        {
          "nom": "alignement",
          "type": "'debut' | 'fin'",
          "obligatoire": false,
          "defaut": "'debut'",
          "description": "Edge of the host it aligns to (desktop)."
        }
      ],
      "slots": [
        {
          "nom": "defaut",
          "description": "Text shown."
        }
      ],
      "faire": [
        "Show what is about to happen (the text that will be copied), not the label again."
      ],
      "eviter": [
        "Essential information that cannot be found elsewhere on a touch screen."
      ],
      "accessibilite": [
        "WCAG 1.4.13: it stays open under the pointer, closes with Escape and hides nothing permanently.",
        "Linked to its trigger by aria-describedby (`id`)."
      ],
      "composeDe": [],
      "utilisePar": [
        "CopieLienIA"
      ],
      "exemple": "<div data-infobulle-hote style=\"position: relative\">\n  <Bouton aria-describedby=\"apercu\">Copier</Bouton>\n  <Infobulle id=\"apercu\" titre=\"Ce texte sera copié\">…</Infobulle>\n</div>"
    },
    {
      "id": "Modale",
      "nom": "Dialog",
      "niveau": "molecules",
      "fichier": "src/components/molecules/Modale.astro",
      "figma": [
        "111:5507"
      ],
      "role": "A dialog box that asks for confirmation.",
      "variantes": [
        "Same box as the tooltip; actions as S buttons, accent then filet."
      ],
      "proprietes": [
        {
          "nom": "id",
          "type": "string",
          "obligatoire": true,
          "description": "Identifier; the title receives `<id>-titre`."
        },
        {
          "nom": "titre",
          "type": "string",
          "obligatoire": true,
          "description": "Box title."
        }
      ],
      "slots": [
        {
          "nom": "defaut",
          "description": "Text shown."
        },
        {
          "nom": "actions",
          "description": "Buttons, whose value becomes the return value of the dialog."
        }
      ],
      "faire": [
        "Two actions at most, the primary action first."
      ],
      "eviter": [
        "A dialog opened without an action from the person."
      ],
      "accessibilite": [
        "Native dialog element opened with showModal(); focus is trapped inside and Escape closes it.",
        "A click outside the box closes it."
      ],
      "composeDe": [],
      "utilisePar": [
        "CopieLienIA"
      ],
      "exemple": "<Modale id=\"confirmation\" titre=\"Ce texte sera copié\">\n  …\n  <Fragment slot=\"actions\">\n    <Bouton variante=\"accent\" taille=\"S\" type=\"submit\" value=\"copier\">Copier</Bouton>\n    <Bouton variante=\"filet\" taille=\"S\" type=\"submit\" value=\"annuler\">Annuler</Bouton>\n  </Fragment>\n</Modale>"
    },
    {
      "id": "CopieLienIA",
      "nom": "Copy the AI link",
      "niveau": "organismes",
      "fichier": "src/components/organismes/CopieLienIA.astro",
      "figma": [],
      "role": "Copies a prompt ready to paste into an AI assistant, with the address of the site's agent version.",
      "variantes": [
        "With hover: the tooltip shows the text, the click copies.",
        "Touch screen: the dialog shows the text and asks for confirmation.",
        "If the browser refuses the copy, the dialog opens with the text to copy by hand."
      ],
      "proprietes": [
        {
          "nom": "libelle",
          "type": "string",
          "obligatoire": true,
          "description": "Button label."
        },
        {
          "nom": "confirmation",
          "type": "string",
          "obligatoire": true,
          "description": "Message after copying."
        },
        {
          "nom": "echec",
          "type": "string",
          "obligatoire": true,
          "description": "Message if the copy fails."
        },
        {
          "nom": "apercu",
          "type": "string",
          "obligatoire": true,
          "description": "Title of the tooltip and the dialog."
        },
        {
          "nom": "prompt",
          "type": "string",
          "obligatoire": true,
          "description": "Copied text; {lien} becomes the address of the agent version."
        },
        {
          "nom": "confirmer",
          "type": "string",
          "obligatoire": true,
          "description": "Primary action of the dialog."
        },
        {
          "nom": "annuler",
          "type": "string",
          "obligatoire": true,
          "description": "Secondary action of the dialog."
        },
        {
          "nom": "variante",
          "type": "'plein' | 'contour'",
          "obligatoire": false,
          "defaut": "'plein'",
          "description": "Button variant."
        },
        {
          "nom": "alignement",
          "type": "'debut' | 'fin'",
          "obligatoire": false,
          "defaut": "'debut'",
          "description": "Tooltip alignment."
        },
        {
          "nom": "emplacement",
          "type": "string",
          "obligatoire": true,
          "description": "Placement, sent to audience measurement."
        }
      ],
      "slots": [],
      "faire": [
        "Always show the text before copying it."
      ],
      "eviter": [
        "Copying without confirmation on a touch screen."
      ],
      "accessibilite": [
        "Absent without JavaScript or clipboard; the link to the agent version is then enough.",
        "The result is announced in a role=\"status\" region."
      ],
      "composeDe": [
        "Bouton",
        "Infobulle",
        "Modale"
      ],
      "utilisePar": [
        "Accueil"
      ],
      "exemple": "<CopieLienIA {...textes} variante=\"contour\" alignement=\"fin\" emplacement=\"hero\" />"
    },
    {
      "id": "EmailCopiable",
      "nom": "Copyable email",
      "niveau": "organismes",
      "fichier": "src/components/organismes/EmailCopiable.astro",
      "figma": [],
      "role": "The email address, large, copied in one click.",
      "variantes": [
        "On hover and focus, the text turns blue from left to right."
      ],
      "proprietes": [
        {
          "nom": "locale",
          "type": "Locale",
          "obligatoire": true,
          "description": "Language of the texts."
        }
      ],
      "slots": [],
      "faire": [
        "A single large address per page."
      ],
      "eviter": [
        "Using it on a light background: the text is white at rest."
      ],
      "accessibilite": [
        "Without JavaScript or clipboard, the address remains a mailto link.",
        "The button announces the address and the action; the result is announced in a role=\"status\" region.",
        "In forced colours mode, the text returns to a solid colour."
      ],
      "composeDe": [],
      "utilisePar": [
        "PiedDePage",
        "Contact"
      ],
      "exemple": "<EmailCopiable locale={locale} />"
    },
    {
      "id": "Navigation",
      "nom": "Navigation",
      "niveau": "organismes",
      "fichier": "src/components/organismes/Navigation.astro",
      "figma": [
        "2:487"
      ],
      "role": "The logo, the sections of the site and the link to the other language.",
      "variantes": [
        "Link states: rest, hover (blue fill), active page (8 px bar).",
        "Mobile: full-screen menu on the native Popover API.",
        "Stuck at the top, hidden when scrolling down, back when scrolling up."
      ],
      "proprietes": [
        {
          "nom": "locale",
          "type": "Locale",
          "obligatoire": true,
          "description": "Language of the page."
        },
        {
          "nom": "alternate",
          "type": "string",
          "obligatoire": false,
          "description": "Address of the equivalent page in the other language."
        }
      ],
      "slots": [],
      "faire": [
        "Only show a section once content is published."
      ],
      "eviter": [
        "A link to the other language without an equivalent page."
      ],
      "accessibilite": [
        "aria-current is \"page\" on the exact page, \"true\" on a sub-page.",
        "The mobile menu opens and closes without JavaScript, and with Escape.",
        "Keyboard focus always brings the navigation back."
      ],
      "composeDe": [],
      "utilisePar": [
        "BaseLayout"
      ],
      "exemple": "<Navigation locale={locale} alternate={path('travaux', 'en')} />"
    },
    {
      "id": "PiedDePage",
      "nom": "Footer",
      "niveau": "organismes",
      "fichier": "src/components/organismes/PiedDePage.astro",
      "figma": [
        "2:492"
      ],
      "role": "The large email address, the signature, useful links and the location.",
      "variantes": [
        "Without the large address on the Contact page, which already carries it."
      ],
      "proprietes": [
        {
          "nom": "locale",
          "type": "Locale",
          "obligatoire": true,
          "description": "Language of the texts."
        },
        {
          "nom": "avecEmail",
          "type": "boolean",
          "obligatoire": false,
          "defaut": "true",
          "description": "Shows the large address."
        }
      ],
      "slots": [],
      "faire": [
        "Short links, separated by middle dots."
      ],
      "eviter": [
        "Repeating the main navigation there."
      ],
      "accessibilite": [
        "contentinfo region, named by a hidden heading."
      ],
      "composeDe": [
        "Lien",
        "EmailCopiable"
      ],
      "utilisePar": [
        "BaseLayout"
      ],
      "exemple": "<PiedDePage locale={locale} avecEmail={false} />"
    },
    {
      "id": "PilierDeMethode",
      "nom": "Method pillar",
      "niveau": "organismes",
      "fichier": "src/components/organismes/PilierDeMethode.astro",
      "figma": [
        "2:490"
      ],
      "role": "A stage of the method, its sentence and its practices.",
      "variantes": [
        "On the home page (desktop, with JavaScript), the active pillar is complete and the others shrink to their title."
      ],
      "proprietes": [
        {
          "nom": "titre",
          "type": "string",
          "obligatoire": true,
          "description": "Pillar name."
        },
        {
          "nom": "description",
          "type": "string",
          "obligatoire": true,
          "description": "Pillar sentence."
        },
        {
          "nom": "pratiques",
          "type": "string[]",
          "obligatoire": true,
          "description": "Practices, as tags."
        },
        {
          "nom": "niveau",
          "type": "2 | 3 | 4",
          "obligatoire": false,
          "defaut": "3",
          "description": "Heading level."
        }
      ],
      "slots": [],
      "faire": [
        "Short practices, as On tags."
      ],
      "eviter": [
        "Practices as Off tags: they describe what is done, all are On."
      ],
      "accessibilite": [
        "When shrunk, inactive pillars keep their text for screen readers."
      ],
      "composeDe": [
        "GroupeEtiquettes"
      ],
      "utilisePar": [
        "Accueil"
      ],
      "exemple": "<PilierDeMethode titre=\"Cadrer\" description=\"…\" pratiques={['Entretiens', 'Tests d’utilisabilité']} />"
    },
    {
      "id": "Planche",
      "nom": "Board",
      "niveau": "organismes",
      "fichier": "src/components/organismes/Planche.astro",
      "figma": [
        "27:412"
      ],
      "role": "A closing message, a heading over several lines and paragraphs.",
      "variantes": [
        "Light, before the footer.",
        "Dark, followed by content passed as a slot; it joins the footer (Contact page)."
      ],
      "proprietes": [
        {
          "nom": "libelle",
          "type": "string",
          "obligatoire": false,
          "description": "Eyebrow in Label."
        },
        {
          "nom": "titre",
          "type": "string[]",
          "obligatoire": true,
          "description": "Heading, one line per entry."
        },
        {
          "nom": "texte",
          "type": "string[]",
          "obligatoire": true,
          "description": "Paragraphs in Lead."
        },
        {
          "nom": "sombre",
          "type": "boolean",
          "obligatoire": false,
          "defaut": "false",
          "description": "Dark variant."
        },
        {
          "nom": "nom",
          "type": "string",
          "obligatoire": false,
          "description": "Region name."
        },
        {
          "nom": "niveau",
          "type": "2 | 3 | 4",
          "obligatoire": false,
          "defaut": "2",
          "description": "Heading level."
        }
      ],
      "slots": [
        {
          "nom": "defaut",
          "description": "Content under the text (dark variant)."
        }
      ],
      "faire": [
        "A short heading, one line per idea."
      ],
      "eviter": [
        "Two boards on one page."
      ],
      "accessibilite": [
        "Region named by its heading, or by `nom` if the page shows several."
      ],
      "composeDe": [],
      "utilisePar": [
        "Cas",
        "Contact",
        "Ecrit",
        "ListeEcrits",
        "ListeTravaux",
        "Parcours"
      ],
      "exemple": "<Planche libelle={ui.planche.libelle} titre={ui.planche.titre} texte={ui.planche.texte} />\n<Planche titre={…} texte={…} sombre><EmailCopiable locale={locale} /></Planche>"
    }
  ],
  "gabarits": [
    {
      "id": "Accueil",
      "fichier": "src/gabarits/Accueil.astro",
      "description": "Hero, layers, work, position, method and writing.",
      "composants": [
        "Bouton",
        "Encart",
        "Carte",
        "EnTete",
        "Figure",
        "CopieLienIA",
        "PilierDeMethode"
      ]
    },
    {
      "id": "Cas",
      "fichier": "src/gabarits/Cas.astro",
      "description": "A case study, from summary to decisions and their rules.",
      "composants": [
        "Encart",
        "Lien",
        "EnTete",
        "GroupeEtiquettes",
        "Planche"
      ]
    },
    {
      "id": "Contact",
      "fichier": "src/gabarits/Contact.astro",
      "description": "The message and the copyable address, on a dark board.",
      "composants": [
        "EnTete",
        "EmailCopiable",
        "Planche"
      ]
    },
    {
      "id": "Ecrit",
      "fichier": "src/gabarits/Ecrit.astro",
      "description": "A piece of writing, its thesis, cited cases and related writing.",
      "composants": [
        "Encart",
        "Lien",
        "Carte",
        "EnTete",
        "Planche"
      ]
    },
    {
      "id": "ListeEcrits",
      "fichier": "src/gabarits/ListeEcrits.astro",
      "description": "List of writing, as M cards.",
      "composants": [
        "Carte",
        "EnTete",
        "Planche"
      ]
    },
    {
      "id": "ListeTravaux",
      "fichier": "src/gabarits/ListeTravaux.astro",
      "description": "List of case studies, as L cards with a visual.",
      "composants": [
        "Carte",
        "EnTete",
        "Planche"
      ]
    },
    {
      "id": "Parcours",
      "fichier": "src/gabarits/Parcours.astro",
      "description": "Experience and education.",
      "composants": [
        "Bouton",
        "EnTete",
        "GroupeEtiquettes",
        "Planche"
      ]
    },
    {
      "id": "Systeme",
      "fichier": "src/gabarits/Systeme.astro",
      "description": "This page.",
      "composants": [
        "Bouton",
        "Encart",
        "Etiquette",
        "Lien",
        "Carte",
        "EnTete",
        "Figure",
        "GroupeEtiquettes",
        "Infobulle",
        "Modale",
        "CopieLienIA",
        "EmailCopiable",
        "PilierDeMethode",
        "Planche"
      ]
    }
  ]
}