@layer reset, tokens, contract, icons, theme, base, elements, a11y;

/* ── reset ── */
@layer reset {
/* Peels — Reset
   Browser inconsistency corrections
   Sources: TODO (wip: Comeau, Bell, Grant, CSS-Bench)
   ════════════════════════════════════════════════════════ */

*,
*::before,
*::after {
  box-sizing: border-box;
}

html {
  -moz-text-size-adjust: none;
  -webkit-text-size-adjust: none;
  text-size-adjust: none;
}

*:not(dialog) {
  margin: 0;
}

ul[role="list"],
ol[role="list"] {
  list-style: none;
}

button,
input,
select,
textarea {
  font: inherit;
  color: inherit;
}

textarea:not([rows]) {
  min-height: 10em;
}


/* ════════════════════════════════════════════════════════
   Reset design choices (opinionated)
   Not directly browser corrections
   ════════════════════════════════════════════════════════ */

p {
  text-wrap: pretty;
}

:where(h1, h2, h3, h4, h5, h6) {
  text-wrap: balance;
}

html {
  scrollbar-gutter: stable;
}

@media (prefers-reduced-motion: no-preference) {
  html {
    interpolate-size: allow-keywords;
  }
}

body {
  min-block-size: 100dvb;
  line-height: 1.5;
}

p,
h1,
h2,
h3,
h4,
h5,
h6 {
  overflow-wrap: break-word;
}



/* audio exclu de block-size:auto : n'a pas de dimensions intrinsèques CSS,
   sa hauteur vient du UA stylesheet. height:auto l'écrase → collapse à 0.
   iframe exclu aussi : height:auto ne calcule pas depuis le ratio intrinsèque
   comme pour img/video → iframe déformée (largeur réduite, hauteur fixe).
   Cf. Bulma #2060, CSSWG #13248. */
:where(audio, canvas, embed, iframe, img, object, picture, svg, video) {
  display: block;
  max-inline-size: 100%;
}

:where(canvas, embed, img, object, picture, svg, video) {
  block-size: auto;
}

:where(textarea) {
  resize: block;
}

:where(:root) {
  cursor: default;
}

:where([aria-busy="true" i]) {
  cursor: progress;
}

:where([aria-disabled="true" i], [disabled]) {
  cursor: not-allowed;
}

:where(h1, h2, h3, h4, button, input, label) {
  line-height: 1.1;
}


}

/* ── tokens ── */
@layer tokens {
/* tokens/color.css */
/* Peels — Socle : tokens de couleur
   Architecture 3 natures : marque (brand/action/accent) + neutre (rampe) + statuts.
   L'auteur d'un thème surcharge les inputs (brand/action/accent + neutre) — jamais les dérivations.
   Le socle dérive les variantes par job (text/bg/bg-hover/bg-soft/border) via oklch(from ...) et color-mix,
   sur le même pattern que les statuts. _contract.css mappe vers --peels-*.
   ════════════════════════════════════════════════════════ */

/* ─── Forçage du schéma sans thème nommé ───
   data-theme-mode="light|dark" fonctionne sur :root, [data-theme] et
   [data-color-theme] même sans thème déclaré. Les règles par nom dans
   themes/<name>/color.css restent prioritaires (layer theme, plus tard). */
:root[data-theme-mode="light"],
[data-theme][data-theme-mode="light"],
[data-color-theme][data-theme-mode="light"] { color-scheme: light; }

:root[data-theme-mode="dark"],
[data-theme][data-theme-mode="dark"],
[data-color-theme][data-theme-mode="dark"] { color-scheme: dark; }

:root,
[data-theme],
[data-color-theme] {

  /* ─── color-scheme : bascule light/dark via data-theme-mode ───
     Règles génériques pour que light-dark() fonctionne sur tout bloc
     [data-theme] avec data-theme-mode="light" ou "dark". */
  color-scheme: light dark;

  /* ─── Inputs de marque (charte graphique) ───
     brand  : couleur d'identité de la marque (le rouge du logo, le violet Peels)
     action : couleur d'interaction (boutons, liens, focus) — défaut = brand
     accent : couleur d'emphase (titres, décor) — défaut = brand
     Un thème monochrome ne fournit que --brand.
     Defaults = Minimal Neutral (tweakcn) : gris pur, zéro chroma. */
  --brand:  light-dark(oklch(0.205 0 0), oklch(0.922 0 0));
  --action: var(--brand);
  --accent: var(--brand);

  /* ─── Neutre — rampe structurelle (6 valeurs, 1 famille)
     Defaults = Minimal Neutral (tweakcn) : gris pur, zéro chroma. ─── */
  --neutral-bg:           light-dark(oklch(1 0 0),     oklch(0.205 0 0));
  --neutral-bg-elevated:  light-dark(oklch(0.995 0 0), oklch(0.165 0 0));
  --neutral-bg-sunken:    light-dark(oklch(0.95 0 0),  oklch(0.269 0 0));
  --neutral-text:         light-dark(oklch(0.145 0 0), oklch(0.985 0 0));
  --neutral-text-muted:   light-dark(oklch(0.556 0 0), oklch(0.708 0 0));
  --neutral-border:       light-dark(oklch(0.95 0 0),  oklch(0.269 0 0));

  /* ─── Dérivations brand (par job) — l'auteur ne touche jamais ─── */
  --brand-text:      light-dark(
    oklch(from var(--brand) calc(l - 0.20) c h),
    oklch(from var(--brand) calc(l + 0.15) c h)
  );
  --brand-bg:        var(--brand);
  --brand-bg-hover:  light-dark(
    oklch(from var(--brand) calc(l - 0.05) c h),
    oklch(from var(--brand) calc(l + 0.05) c h)
  );
  --brand-bg-soft:   color-mix(in oklab, var(--brand) 10%, var(--neutral-bg));
  --brand-border:    light-dark(
    oklch(from var(--brand) calc(l + 0.10) calc(c * 0.5) h),
    oklch(from var(--brand) calc(l - 0.05) calc(c * 0.6) h)
  );

  /* ─── Dérivations action (boutons, liens, focus) ─── */
  --action-text:      light-dark(
    oklch(from var(--action) calc(l - 0.20) c h),
    oklch(from var(--action) calc(l + 0.15) c h)
  );
  --action-bg:        var(--action);
  --action-bg-hover:  light-dark(
    oklch(from var(--action) calc(l - 0.05) c h),
    oklch(from var(--action) calc(l + 0.05) c h)
  );
  --action-bg-soft:   color-mix(in oklab, var(--action) 10%, var(--neutral-bg));
  --action-border:    light-dark(
    oklch(from var(--action) calc(l + 0.10) calc(c * 0.5) h),
    oklch(from var(--action) calc(l - 0.05) calc(c * 0.6) h)
  );

  /* ─── Dérivations accent (titres, décor, emphase) ─── */
  --accent-text:      light-dark(
    oklch(from var(--accent) calc(l - 0.20) c h),
    oklch(from var(--accent) calc(l + 0.15) c h)
  );
  --accent-bg:        var(--accent);
  --accent-bg-hover:  light-dark(
    oklch(from var(--accent) calc(l - 0.05) c h),
    oklch(from var(--accent) calc(l + 0.05) c h)
  );
  --accent-bg-soft:   color-mix(in oklab, var(--accent) 10%, var(--neutral-bg));
  --accent-border:    light-dark(
    oklch(from var(--accent) calc(l + 0.10) calc(c * 0.5) h),
    oklch(from var(--accent) calc(l - 0.05) calc(c * 0.6) h)
  );

  /* ─── Gradients — composés depuis brand/accent ─── */
  --color-gradient-page: linear-gradient(
    135deg,
    var(--neutral-bg) 0%,
    var(--neutral-bg-sunken) 100%
  );
  --color-gradient-hero: linear-gradient(
    160deg,
    var(--neutral-bg-sunken) 0%,
    var(--neutral-bg) 50%,
    var(--neutral-bg-elevated) 100%
  );
  --color-gradient-banner: linear-gradient(
    120deg,
    var(--brand-bg) 0%,
    var(--accent-bg) 100%
  );
  --color-gradient-card: linear-gradient(
    180deg,
    var(--neutral-bg-elevated) 0%,
    var(--neutral-bg-sunken) 55%,
    var(--brand-bg) 100%
  );
  --color-gradient-conic: conic-gradient(
    var(--action-bg) 0 28%,
    var(--accent-bg) 0 67%,
    var(--brand-bg) 0 100%
  );
  --color-gradient-stripes: linear-gradient(
    45deg,
    var(--neutral-bg) 0 75%,
    var(--action-bg) 0 85%,
    var(--accent-bg) 0 92%,
    var(--brand-bg) 0 100%
  );

  /* ─── Statuts — sources indépendantes ─── */
  --status-success: oklch(0.62 0.17 150);
  --status-danger:  oklch(0.58 0.22 25);
  --status-warning: oklch(0.78 0.16 72);
  --status-info:    oklch(0.55 0.15 250);

  /* ─── Statuts — variantes dérivées ─── */
  --status-success-bg:     light-dark(
    color-mix(in oklab, var(--status-success) 8%, var(--neutral-bg)),
    color-mix(in oklab, var(--status-success) 12%, var(--neutral-bg))
  );
  --status-success-text:   light-dark(
    oklch(from var(--status-success) calc(l - 0.15) c h),
    oklch(from var(--status-success) calc(l + 0.13) c h)
  );
  --status-success-border: light-dark(
    oklch(from var(--status-success) calc(l + 0.15) calc(c * 0.5) h),
    oklch(from var(--status-success) calc(l - 0.05) calc(c * 0.6) h)
  );

  --status-danger-bg:     light-dark(
    color-mix(in oklab, var(--status-danger) 8%, var(--neutral-bg)),
    color-mix(in oklab, var(--status-danger) 12%, var(--neutral-bg))
  );
  --status-danger-text:   light-dark(
    oklch(from var(--status-danger) calc(l - 0.12) c h),
    oklch(from var(--status-danger) calc(l + 0.15) c h)
  );
  --status-danger-border: light-dark(
    oklch(from var(--status-danger) calc(l + 0.15) calc(c * 0.5) h),
    oklch(from var(--status-danger) calc(l - 0.05) calc(c * 0.6) h)
  );

  --status-warning-bg:     light-dark(
    color-mix(in oklab, var(--status-warning) 8%, var(--neutral-bg)),
    color-mix(in oklab, var(--status-warning) 12%, var(--neutral-bg))
  );
  --status-warning-text:   light-dark(
    oklch(from var(--status-warning) calc(l - 0.20) c h),
    oklch(from var(--status-warning) calc(l + 0.10) c h)
  );
  --status-warning-border: light-dark(
    oklch(from var(--status-warning) calc(l + 0.10) calc(c * 0.5) h),
    oklch(from var(--status-warning) calc(l - 0.05) calc(c * 0.6) h)
  );

  --status-info-bg:     light-dark(
    color-mix(in oklab, var(--status-info) 8%, var(--neutral-bg)),
    color-mix(in oklab, var(--status-info) 12%, var(--neutral-bg))
  );
  --status-info-text:   light-dark(
    oklch(from var(--status-info) calc(l - 0.15) c h),
    oklch(from var(--status-info) calc(l + 0.13) c h)
  );
  --status-info-border: light-dark(
    oklch(from var(--status-info) calc(l + 0.15) calc(c * 0.5) h),
    oklch(from var(--status-info) calc(l - 0.05) calc(c * 0.6) h)
  );
}

/* tokens/shape.css */
/* Peels — Socle : tokens de forme
   Valeurs brutes neutres. Toujours chargé (layer tokens), sous tous les thèmes.
   ════════════════════════════════════════════════════════ */

:root {

  /* ─── Rayons de bordure ─── */
  --radius-xs:   0.25rem;
  --radius-s:    0.35rem;
  --radius-m:    0.62rem;
  --radius-l:    0.8rem;
  --radius-xl:   1rem;
  --radius-pill: 100vmax;
}

/* tokens/space.css */
/* Peels — Socle : tokens d'espacement
   Valeurs brutes neutres. Toujours chargé (layer tokens), sous tous les thèmes.
   ════════════════════════════════════════════════════════ */

:root {

  /* @link https://utopia.fyi/space/calculator?c=360,19,1.2,1240,26,1.25,5,2,&s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&g=s,l,xl,12 */
  --space-3xs: clamp(0.3125rem, 0.2614rem + 0.2273vi, 0.4375rem);
  --space-2xs: clamp(0.625rem,  0.5483rem + 0.3409vi, 0.8125rem);
  --space-xs:  clamp(0.875rem,  0.7216rem + 0.6818vi, 1.25rem);
  --space-s:   clamp(1.1875rem, 1.0085rem + 0.7955vi, 1.625rem);
  --space-m:   clamp(1.8125rem, 1.5568rem + 1.1364vi, 2.4375rem);
  --space-l:   clamp(2.375rem,  2.017rem  + 1.5909vi, 3.25rem);
  --space-xl:  clamp(3.5625rem, 3.0256rem + 2.3864vi, 4.875rem);
  --space-2xl: clamp(4.75rem,   4.0341rem + 3.1818vi, 6.5rem);
  --space-3xl: clamp(7.125rem,  6.0511rem + 4.7727vi, 9.75rem);

  /* ─── Paires fluides ─── */
  --space-3xs-2xs: clamp(0.3125rem, 0.108rem  + 0.9091vi, 0.8125rem);
  --space-2xs-xs:  clamp(0.625rem,  0.3693rem + 1.1364vi, 1.25rem);
  --space-xs-s:    clamp(0.875rem,  0.5682rem + 1.3636vi, 1.625rem);
  --space-s-m:     clamp(1.1875rem, 0.6761rem + 2.2727vi, 2.4375rem);
  --space-m-l:     clamp(1.8125rem, 1.2244rem + 2.6136vi, 3.25rem);
  --space-l-xl:    clamp(2.375rem,  1.3523rem + 4.5455vi, 4.875rem);
  --space-xl-2xl:  clamp(3.5625rem, 2.3608rem + 5.3409vi, 6.5rem);
  --space-2xl-3xl: clamp(4.75rem,   2.7045rem + 9.0909vi, 9.75rem);
  --space-s-l:     clamp(1.1875rem, 0.3438rem + 3.75vi,   3.25rem);
}

/* tokens/type.css */
/* Peels — Socle : tokens typographiques
   Valeurs brutes neutres. Toujours chargé (layer tokens), sous tous les thèmes.
   Garantit que chaque nom de token résout. Un thème peut surcharger.
   ════════════════════════════════════════════════════════ */

:root {

  /* @link https://utopia.fyi/type/calculator?c=360,19,1.2,1240,26,1.25,5,2,&s=0.75|0.5|0.25,1.5|2|3|4|6,s-l&g=s,l,xl,12 */
  --size-step--2: clamp(0.8247rem, 0.7366rem + 0.3915vi, 1.04rem);
  --size-step--1: clamp(0.9896rem, 0.8626rem + 0.5644vi, 1.3rem);
  --size-step-0:  clamp(1.1875rem, 1.0085rem + 0.7955vi, 1.625rem);
  --size-step-1:  clamp(1.425rem,  1.177rem  + 1.1023vi, 2.0313rem);
  --size-step-2:  clamp(1.71rem,   1.3708rem + 1.5074vi, 2.5391rem);
  --size-step-3:  clamp(2.052rem,  1.5931rem + 2.0397vi, 3.1738rem);
  --size-step-4:  clamp(2.4624rem, 1.8468rem + 2.7362vi, 3.9673rem);
  --size-step-5:  clamp(2.9549rem, 2.135rem  + 3.644vi,  4.9591rem);

  /* ─── Graisses ─── */
  --weight-regular:  400;
  --weight-medium:   500;
  --weight-semibold: 600;
  --weight-bold:     700;

  /* ─── Stacks de fontes système ─── */
  --font-sans:  system-ui, ui-sans-serif, sans-serif;
  --font-serif: "Iowan Old Style", "Palatino Linotype", Georgia, serif;
  --font-mono:  "Consolas", "Cascadia Mono", ui-monospace, monospace;
}
}

/* ── contract ── */
@layer contract {
/* Peels — Contract — LE CONTRAT DE THÈME
   Les rôles --peels-* : la surface de theming sémantique.
   Chaque rôle mappe un token (socle tokens/) vers un usage.
   Surcharger un token = effet global ; surcharger un rôle = effet ciblé.
   Les éléments consomment ces rôles avec des fallbacks locaux ; aucun layer de knobs global n'est requis.
   Voir THEMING.md.
   ════════════════════════════════════════════════════════ */

:root,
[data-theme] {

  /* ─── Typographie ─── */
  --peels-font-prose:             var(--font-sans);
  --peels-font-heading:           var(--font-sans);
  --peels-font-ui:                var(--font-sans);
  --peels-font-mono:              var(--font-mono);
  --peels-font-weight-ui:         600;
  --peels-font-weight-heading:    700;

  --peels-text-base:              var(--size-step-0);
  --peels-text-small:             var(--size-step--1);
  --peels-text-xsmall:            var(--size-step--2);

  --peels-leading:                1.6;
  --peels-leading-fine:           1.2;

  /* ─── Rôles couleur — couleurs brutes dans les rôles principaux ───
     brand = identité, action = interaction, accent = emphase.
     Les couleurs définies par l'auteur apparaissent telles quelles.
     Dérivations seulement pour rôles subtils (hover, tints, bordures). */
  --peels-surface-page:           var(--neutral-bg);
  --peels-surface-panel:          var(--neutral-bg-elevated);
  --peels-surface-panel-soft:     var(--neutral-bg-sunken);
  --peels-surface-hover:          var(--neutral-bg-sunken);
  --peels-surface-active:         var(--neutral-bg-sunken);

  --peels-brand:                  var(--brand);
  --peels-text-body:              var(--neutral-text);
  --peels-headings-color:            var(--accent);
  --peels-text-muted:             var(--neutral-text-muted);
  --peels-text-accent:            var(--accent);
  --peels-text-accent-alt:        var(--brand);
  --peels-text-link:              var(--action);
  --peels-text-link-hover:        var(--action);

  --peels-border-subtle:          var(--neutral-border);
  --peels-border-strong:          var(--action);
  --peels-border-accent:          var(--accent);

  /* ─── Focus ───
     focus-color/width/offset/style/radius : outline global (currentColor)
     focus-ring : anneau accentué des contrôles de formulaire */
  --peels-focus-ring:             var(--action);
  --peels-focus-color:            currentColor;
  --peels-focus-offset:           0.15em;
  --peels-focus-style:            solid;
  --peels-focus-width:            2px;
  --peels-focus-radius:           1px;
  --peels-color-highlight:        var(--accent);

  /* ─── Actions boutons (primitives de 2e plan) ─── */
  --peels-btn-base:               var(--action);

  /* ─── Accents sémantiques (statuts — notifications, alerts) ─── */
  --peels-accent-info:            var(--status-info);
  --peels-accent-success:         var(--status-success);
  --peels-accent-warning:         var(--status-warning);
  --peels-accent-danger:          var(--status-danger);

  --peels-gradient-page:          var(--color-gradient-page);
  --peels-gradient-hero:          var(--color-gradient-hero);
  --peels-gradient-banner:        var(--color-gradient-banner);
  --peels-gradient-card:          var(--color-gradient-card);
  --peels-gradient-conic:         var(--color-gradient-conic);
  --peels-gradient-stripes:       var(--color-gradient-stripes);

  /* ─── Globales ─── */
  --peels-border-width:           1px;
  --peels-transition-duration-fast: 0.15s;
  --peels-transition-duration-base: 0.25s;
  --peels-transition-easing:      ease;
  --peels-disabled-opacity:         0.5;
  --peels-line-height-flat:        1;

  /* ─── Élévation ─── */
  --peels-elevation-1:            0 0.125rem 0.375rem -0.0625rem oklch(0% 0 0 / 0.08);
  --peels-elevation-2:            0 0.25rem 0.75rem -0.125rem oklch(0% 0 0 / 0.12);
  --peels-elevation-3:            0 0.5rem 1.5rem -0.25rem oklch(0% 0 0 / 0.16);
  --peels-elevation-hover:        var(--peels-elevation-1);

  /* ─── Espacement ─── */
  --peels-gutter:                 var(--space-m);
  --peels-gap-prose:              var(--space-s-m);
  --peels-gap-component:          var(--space-s);
  --peels-gap-sm:                 var(--space-xs);
  --peels-padding-block:          var(--space-s-m);
  --peels-gap-section:            var(--space-xl);

  /* ─── Densité des contrôles (boutons, inputs…) ───
     Taille indépendante de la prose : --peels-control-font-size découple
     la taille des contrôles du corps de texte, et min-height en em suit. */
  --peels-control-gap:            0.5em;
  --peels-control-font-size:      var(--peels-text-xsmall);
  --peels-control-padding-block:  var(--space-2xs);
  --peels-control-padding-inline: 1em;
  --peels-control-min-height:     2.5em;

  /* ─── Rayon commun ─── */
  --peels-component-radius:       var(--radius-s);
  --peels-media-radius:           var(--radius-s);

  /* ─── Utilitaires de dérivation (pas des tokens de design) ─── */
  --u-shift-hover:   -0.05;
  --u-shift-active:  -0.10;

  /* ─── Strates d'empilement (z-index globaux) ───
     Ordre relatif centralisé pour éviter les conflits.
     Les composants consomment la strate qui correspond à leur rôle. */
  --peels-z-sticky:  10;   /* header, sidebar — strate sticky */
  --peels-z-above:   20;   /* burger, toggle — au-dessus du sticky */
  --peels-z-top:    100;   /* notification — au-dessus de tout */
}

}

/* ── icons ── */
@layer icons {
/* Peels — layer icons
   Système d'icônes : assets bruts → rôles sémantiques → mécanisme.
   Technique : Lea Verou, "The best way to use icons in Web UIs" (2026).
   ════════════════════════════════════════════════════════ */

/* ─── Assets bruts (SVG data-URI) ───
   data-URI : évite le piège de résolution des URLs relatives
   (résolues contre la feuille qui utilise l'icône, pas celle
   qui la déclare). Pour des fichiers SVG : URLs root-relative. */
:root {
  --peels-icon-svg-check: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'><path d='M20 6L9 17l-5-5'/></svg>");
  --peels-icon-svg-external: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M15 3h6v6'/><path d='M10 14L21 3'/><path d='M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6'/></svg>");
  --peels-icon-svg-chevron: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M6 9l6 6 6-6'/></svg>");
  --peels-icon-svg-chevron-left: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M15 18l-6-6 6-6'/></svg>");
  --peels-icon-svg-chevron-right: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M9 18l6-6-6-6'/></svg>");
  --peels-icon-svg-trash: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M3 6h18'/><path d='M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2'/><path d='M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6'/><path d='M10 11v6'/><path d='M14 11v6'/></svg>");
  --peels-icon-svg-download: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'><path d='M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4'/><path d='M7 10l5 5 5-5'/><path d='M12 15V3'/></svg>");
  --peels-icon-svg-minus: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='black' stroke-width='4' stroke-linecap='round'><path d='M4 12h16'/></svg>");
  /* Variante CanvasText : couleurs système (mode sombre, forced-colors)
     pour les icônes en background-image (ex. chevron de select). */
  --peels-icon-svg-chevron-canvas: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='14' height='14' viewBox='0 0 12 12' fill='none' style='color-scheme:light dark'%3E%3Cpath d='M2.5 4.25L6 7.75L9.5 4.25' stroke='CanvasText' stroke-width='1.85' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
}

/* ─── Rôles sémantiques ───
   Un thème remappe ces rôles pour swapper un set d'icônes
   entier, sans toucher aux assets ni à la table data-icon. */
:root {
  --peels-icon-check: var(--peels-icon-svg-check);
  --peels-icon-external: var(--peels-icon-svg-external);
  --peels-icon-chevron: var(--peels-icon-svg-chevron);
  --peels-icon-chevron-left: var(--peels-icon-svg-chevron-left);
  --peels-icon-chevron-right: var(--peels-icon-svg-chevron-right);
  --peels-icon-trash: var(--peels-icon-svg-trash);
  --peels-icon-download: var(--peels-icon-svg-download);
  --peels-icon-minus: var(--peels-icon-svg-minus);
}

/* ─── Interface : --peels-icon existe, indéfinie par défaut ───
   initial → guaranteed-invalid → aucune icône tant que le
   consommateur ne définit rien (attribut ou CSS). */
:root {
  --peels-icon: initial;
}

/* ─── Table d'intention : l'attribut identifie l'icône ───
   Ajouter une ligne par icône consommable via data-icon. */
[data-icon="check"]    { --peels-icon: var(--peels-icon-check); }
[data-icon="external"] { --peels-icon: var(--peels-icon-external); }
[data-icon="chevron"]  { --peels-icon: var(--peels-icon-chevron); }
[data-icon="trash"]    { --peels-icon: var(--peels-icon-trash); }
[data-icon="download"] { --peels-icon: var(--peels-icon-download); }

/* ─── Déclencheurs non hérités : sinon tout descendant
      d'un élément iconé recevrait lui aussi une icône ─── */
@property --peels-icon-start {
  syntax: '*';
  inherits: false;
}
@property --peels-icon-end {
  syntax: '*';
  inherits: false;
}

/* ─── Le pseudo-élément n'existe que si la variable est définie ─── */
@container style(--peels-icon-start) {
  ::before {
    --peels-icon-start: inherit;
    content: "";
    display: inline-block;
    overflow: hidden;
    vertical-align: calc(
      0.5cap - var(--peels-icon-size, 1em) / 2 + var(--peels-icon-voffset, -0.02em)
    );
    inline-size: var(--peels-icon-size, 1em);
    block-size: var(--peels-icon-size, 1em);
    margin-inline-end: var(--peels-icon-gap, 0.3em);
    background-color: var(--peels-icon-color, currentColor);
    mask: var(--peels-icon-start) no-repeat center / contain;
    pointer-events: none;
    flex: none;
    forced-color-adjust: none;
  }
}

@container style(--peels-icon-end) {
  ::after {
    --peels-icon-end: inherit;
    content: "";
    display: inline-block;
    overflow: hidden;
    vertical-align: calc(
      0.5cap - var(--peels-icon-size, 1em) / 2 + var(--peels-icon-voffset, -0.02em)
    );
    inline-size: var(--peels-icon-size, 1em);
    block-size: var(--peels-icon-size, 1em);
    margin-inline-start: var(--peels-icon-gap, 0.3em);
    background-color: var(--peels-icon-color, currentColor);
    mask: var(--peels-icon-end) no-repeat center / contain;
    pointer-events: none;
    flex: none;
    forced-color-adjust: none;
  }
}

/* ─── Placement ───
   Porteur d'attribut : départ à start sur tout élément.
   Hôtes courants : --peels-icon défini côté CSS redirige vers start. */
[data-icon],
i, a, button, [role="button"] {
  --peels-icon-start: var(--peels-icon);
}

[data-icon][data-icon-side="end"] {
  --peels-icon-start: initial;
  --peels-icon-end: var(--peels-icon);
}

:where([data-icon]):empty {
  --peels-icon-gap: 0;
}

/* ─── Cas sémantique automatique ─── */
a[download] {
  --peels-icon-end: var(--peels-icon-download);
}

/* ─── Cas contextuels — exemples documentés, non livrés ───
   a[target="_blank"] { --peels-icon: var(--peels-icon-external) }
     → géré par peels-link (voir cet élément).
   button[type="submit"] { --peels-icon: var(--peels-icon-check) }
   a[href$=".pdf"] { --peels-icon-end: var(--peels-icon-download) } */

/* ─── Workarounds WebKit (bugs 301609, 325900) ───
   Une animation 0s force WebKit à re-résoudre le style.
   `inherit` peu fiable sur propriété non-héritée enregistrée :
   on la déclare héritée et on la reset sur les descendants. */
@keyframes peels-icon-webkit-301609 {}

@supports ((-webkit-nbsp-mode: normal) or (-webkit-touch-callout: none) or (font: -apple-system-body)) and (content-visibility: auto) {
  ::before, ::after {
    animation: peels-icon-webkit-301609 0s;
  }

  @property --peels-icon-start {
    syntax: '*';
    inherits: true;
  }
  @property --peels-icon-end {
    syntax: '*';
    inherits: true;
  }

  @container style(--peels-icon-start) {
    * { --peels-icon-start: initial; }
  }
  @container style(--peels-icon-end) {
    * { --peels-icon-end: initial; }
  }
}

}

/* ── theme ── */
@layer theme {
/* themes/peels/color.css */
/* Peels — Thème peels — axe couleur
   Cas 2 : palette tricolore — golden orange (brand) + violet (action) + corail (accent),
   sur neutre blue-gray / prism #232136 en dark.
   brand ≠ action ≠ accent : chaque rôle a sa propre teinte.
   action et accent diffèrent de ceux du thème doc.
   Surcharge les inputs --brand/--action/--accent (+ neutre).
   Le socle dérive les variantes par job. _contract.css mappe vers --peels-*.
   Activé par : data-theme="peels" ou data-color-theme="peels" sur :root ou tout ancêtre
   ════════════════════════════════════════════════════════ */

[data-theme="peels"],
[data-color-theme="peels"] {

  /* ─── Inputs de marque ───
     brand  = golden orange (identité Peels)
     action = violet (liens/boutons/focus — complémentaire de l'orange)
     accent = corail (titres/emphase — distinct de brand et de l'accent doc bleu) */
  --brand:  light-dark(oklch(0.7049 0.1867 47.6044), oklch(0.7576 0.1590 55.9344));
  --action: light-dark(oklch(0.55 0.15 270), oklch(0.70 0.15 270));
  --accent: light-dark(oklch(0.55 0.15 25),  oklch(0.70 0.15 25));

  /* ─── Neutre — blue-gray en light / prism #232136 en dark.
     Rampe dark recalibrée autour du nouveau bg (#232136 = oklch(0.2604 0.039 287.7)). ─── */
  --neutral-bg:           light-dark(oklch(1.0000 0      0),        #232136);
  --neutral-bg-elevated:  light-dark(oklch(1.0000 0      0),        oklch(0.32 0.04 287.7));
  --neutral-bg-sunken:    light-dark(oklch(0.9683 0.0069 247.8956), oklch(0.20 0.04 287.7));
  --neutral-text:         light-dark(oklch(0.2077 0.0398 265.7549), oklch(0.9842 0.0034 287.7));
  --neutral-text-muted:   light-dark(oklch(0.5544 0.0407 257.4166), oklch(0.70 0.03 287.7));
  --neutral-border:       light-dark(oklch(0.9288 0.0126 255.5078), oklch(0.40 0.04 287.7));

  /* ─── Dérivations action/accent : texte blanc sur fond coloré en light,
     noir en dark (meilleur contraste que la recette mécanique). ─── */
  --action-text: light-dark(oklch(1 0 0), oklch(0.12 0 0));
  --accent-text: light-dark(oklch(1 0 0), oklch(0.12 0 0));

  /* ─── Statuts ─── */
  --status-success: light-dark(oklch(0.696 0.149 162), oklch(0.780 0.140 162));
  --status-danger:  light-dark(oklch(0.577 0.215 27),  oklch(0.700 0.190 27));
  --status-warning: light-dark(oklch(0.769 0.165 70),  oklch(0.850 0.140 70));
  --status-info:    light-dark(oklch(0.623 0.188 260), oklch(0.740 0.160 260));

  /* ─── Titres — couleurs par niveau (identité Peels) ───
     Base (.webc) : tous à --peels-headings-color. Le thème peels différencie. */
  --peels-headings-color-h2: var(--peels-text-accent);
  --peels-headings-color-h3: color-mix(in oklab, var(--peels-headings-color) 60%, var(--peels-text-body));
  --peels-headings-color-h4: var(--peels-text-accent-alt);
  --peels-headings-color-h5: var(--peels-text-body);
  --peels-headings-color-h6: var(--peels-text-muted);

  /* ─── Identité — blockquote/hr/mark ───
     Base (.webc) : couleurs neutres (border-subtle, jaune surligneur).
     Le thème peels apporte la couleur de marque. */
  --peels-blockquote-border: var(--peels-border-accent);
  --peels-hr-color:          var(--peels-border-accent);
  --peels-mark-bg:           oklch(from var(--accent) l c h / 0.25);
}

[data-theme="peels"][data-theme-mode="light"],
[data-color-theme="peels"][data-theme-mode="light"] { color-scheme: light; }

[data-theme="peels"][data-theme-mode="dark"],
[data-color-theme="peels"][data-theme-mode="dark"]  { color-scheme: dark; }

/* themes/peels/space.css */
/* Peels — Thème peels — axe espacement
   Activé par : data-theme (tout thème composite) ou data-space-theme="default" (axe seul)
   ════════════════════════════════════════════════════════ */

[data-theme="peels"],
[data-space-theme="default"] {
  --peels-gutter:                 var(--space-m);
  /* --peels-gap-component:          var(--space-s); */
  --peels-padding-block:          var(--space-s-m);
  --peels-gap-section:            var(--space-xl);
}

/* themes/peels/type.css */
/* Peels — Thème peels — axe typographie (Atkinson Hyperlegible Next + League Spartan)
   Activé par : data-theme="peels" (thème complet) ou data-type-theme="default" (axe seul)
   ════════════════════════════════════════════════════════ */

@font-face {
  font-family: "Atkinson Hyperlegible Next";
  src: url("../fonts/AtkinsonHyperlegibleNext-VF.woff2") format("woff2");
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Atkinson Hyperlegible Next";
  src: url("../fonts/AtkinsonHyperlegibleNext-LatinExt-VF.woff2") format("woff2");
  font-weight: 200 800;
  font-style: normal;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "Atkinson Hyperlegible Next";
  src: url("../fonts/AtkinsonHyperlegibleNext-Italic-VF.woff2") format("woff2");
  font-weight: 200 800;
  font-style: italic;
  font-display: swap;
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Atkinson Hyperlegible Next";
  src: url("../fonts/AtkinsonHyperlegibleNext-LatinExt-Italic-VF.woff2") format("woff2");
  font-weight: 200 800;
  font-style: italic;
  font-display: swap;
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

@font-face {
  font-family: "League Spartan";
  src: url("../fonts/LeagueSpartan-VF.woff2") format("woff2");
  font-weight: 100 900;
  font-style: normal;
  font-display: swap;
}

[data-theme="peels"],
[data-type-theme="default"] {
  --peels-font-ui:      "Atkinson Hyperlegible Next", var(--font-sans);
  --peels-font-prose:   "Atkinson Hyperlegible Next", var(--font-sans);
  --peels-font-heading: "League Spartan", var(--font-sans);
  --peels-font-mono:    var(--font-mono);
  --peels-font-weight-ui: 600;

  --peels-text-base:    var(--size-step-0);
  --peels-text-small:   var(--size-step--1);
  --peels-text-xsmall:  var(--size-step--2);

  --peels-leading:      1.6;
  --peels-leading-fine: 1.1;

  --peels-headings-weight-h1: 200;
  --peels-headings-tracking: -0.03em;
}

/* themes/airy/space.css */
/* Peels — Thème airy — axe espacement
   Très aéré, lecture confortable
   Activé par : data-space-theme="airy" sur :root ou tout ancêtre
   ════════════════════════════════════════════════════════ */

[data-space-theme="airy"] {
  --peels-gutter:                 var(--space-l);
  --peels-gap-component:          var(--space-m);
  --peels-padding-block:          var(--space-l);
  --peels-gap-section:            var(--space-2xl);
  --peels-control-gap:            var(--space-xs);
  --peels-control-padding-inline: var(--space-m);
}

/* themes/compact/space.css */
/* Peels — Thème compact — axe espacement
   Densité maximale, interface pro
   Activé par : data-space-theme="compact" sur :root ou tout ancêtre
   ════════════════════════════════════════════════════════ */

[data-space-theme="compact"] {
  --peels-gutter:                 var(--space-xs);
  --peels-gap-component:          var(--space-xs);
  --peels-padding-block:          var(--space-xs-s);
  --peels-gap-section:            var(--space-m);
  --peels-control-gap:            var(--space-3xs);
  --peels-control-padding-inline: var(--space-2xs);
}

/* themes/crimson/color.css */
/* Peels — Thème crimson — axe couleur
   Cas test : marque rouge dont le logo s'affiche en noir/blanc dans l'interface.
   brand = rouge (identité), action = neutre (noir/blanc — pas de boutons rouges),
   accent = brand (rouge réservé aux titres et emphase décorative).
   Démontre la séparation brand ≠ action : une marque rouge n'implique pas des boutons rouges.
   Surcharge les inputs --brand/--action/--accent. Neutre = socle par défaut (gris pur).
   Le socle dérive les variantes par job. _contract.css mappe vers --peels-*.
   Activé par : data-color-theme="crimson" sur :root ou tout ancêtre
   ════════════════════════════════════════════════════════ */

[data-color-theme="crimson"] {

  /* ─── Inputs de marque ───
     brand  = rouge (couleur du logo, identité)
     action = neutre (boutons noirs en clair, blancs en sombre — pas de rouge pour les actions)
     accent = brand (rouge utilisé pour titres et emphase décorative) */
  --brand:  light-dark(oklch(0.55 0.220 25), oklch(0.65 0.220 25));
  --action: var(--neutral-text);
  --accent: var(--brand);

  /* ─── Neutre : socle par défaut (gris pur) — pas de surcharge ─── */

  /* ─── Statuts ─── */
  --status-success: light-dark(oklch(0.62 0.17 150), oklch(0.78 0.14 162));
  --status-danger:  light-dark(oklch(0.58 0.22 25),  oklch(0.70 0.19 27));
  --status-warning: light-dark(oklch(0.78 0.16 72),  oklch(0.85 0.14 70));
  --status-info:    light-dark(oklch(0.55 0.15 250), oklch(0.74 0.16 260));
}

/* themes/editorial/type.css */
/* Peels — Thème editorial — axe typographie (serif)
   UI en sans-serif, prose + titres en serif transitionnel
   Activé par : data-type-theme="editorial" sur :root ou tout ancêtre
   ════════════════════════════════════════════════════════ */

[data-type-theme="editorial"] {
  --peels-font-ui:      var(--font-sans);
  --peels-font-prose:   var(--font-serif);
  --peels-font-heading: var(--font-serif);
  --peels-font-mono:    var(--font-mono);
  --peels-font-weight-ui: 600;

  --peels-text-base:    var(--size-step-0);
  --peels-text-small:   var(--size-step--1);
  --peels-text-xsmall:  var(--size-step--2);

  --peels-leading:      1.65;
  --peels-leading-fine: 1.15;
}

/* themes/ferrari/color.css */
/* Peels — Thème ferrari — axe couleur
   Cas 6 : charte de marque réelle — Ferrari.
   brand = Rosso Corsa (#DA291C, accent d'identité — pas de boutons rouges),
   action = noir/blanc cinématique (boutons noirs en clair, blancs en sombre),
   accent = jaune heritage (emphase décorative — tradition Ferrari).
   Neutre = noir/blanc pur (cinématique, haute contraste).
   Démontre brand ≠ action : une marque rouge n'implique pas des boutons rouges.
   Activé par : data-color-theme="ferrari" sur :root ou tout ancêtre
   ════════════════════════════════════════════════════════ */

[data-theme="ferrari"],
[data-color-theme="ferrari"] {

  /* ─── Inputs de marque (charte Ferrari) ───
     brand  = Rosso Corsa (rouge d'identité — logo, décor, pas boutons)
     action = neutre cinématique (noir en clair, blanc en sombre)
     accent = jaune heritage (emphase — tradition, accents décoratifs) */
  --brand:  light-dark(oklch(0.56 0.22 27), oklch(0.65 0.22 27));  /* Rosso Corsa — même chroma */
  --action: light-dark(oklch(0.15 0 0), oklch(0.92 0 0));          /* black / white */
  --accent: light-dark(oklch(0.82 0.17 90), oklch(0.85 0.17 90));  /* heritage yellow — même chroma */

  /* ─── Neutre — noir/blanc cinématique (haute contraste) ─── */
  --neutral-bg:           light-dark(oklch(1 0 0),    oklch(0.08 0 0));
  --neutral-bg-elevated:  light-dark(oklch(0.99 0 0), oklch(0.12 0 0));
  --neutral-bg-sunken:    light-dark(oklch(0.96 0 0), oklch(0.05 0 0));
  --neutral-text:         light-dark(oklch(0.12 0 0), oklch(0.95 0 0));
  --neutral-text-muted:   light-dark(oklch(0.50 0 0), oklch(0.60 0 0));
  --neutral-border:       light-dark(oklch(0.90 0 0), oklch(0.20 0 0));

  /* ─── Dérivations manuelles (niveau 2+) — on ne laisse pas le socle approximer
     la charte de marque. Rosso Corsa reste saturé, le texte sur rouge est blanc,
     le texte sur jaune heritage est noir, les boutons noirs/blancs conservent
     leur contraste cinématique. ─── */
  --brand-text:      light-dark(oklch(0.98 0 0), oklch(0.98 0 0));  /* blanc sur rouge */
  --brand-bg-hover:  light-dark(oklch(0.62 0.22 27), oklch(0.68 0.22 27));
  --brand-bg-soft:   color-mix(in oklab, var(--brand) 10%, var(--neutral-bg));
  --brand-border:    light-dark(oklch(0.80 0.10 27), oklch(0.50 0.15 27));

  --action-text:     light-dark(oklch(0.98 0 0), oklch(0.12 0 0));  /* blanc sur noir, noir sur blanc */
  --action-bg-hover: light-dark(oklch(0.25 0 0), oklch(0.85 0 0));
  --action-bg-soft:  color-mix(in oklab, var(--action) 10%, var(--neutral-bg));
  --action-border:   light-dark(oklch(0.40 0 0), oklch(0.70 0 0));

  --accent-text:     light-dark(oklch(0.18 0 0), oklch(0.18 0 0));  /* noir sur jaune */
  --accent-bg-hover: light-dark(oklch(0.78 0.17 90), oklch(0.82 0.17 90));
  --accent-bg-soft:  color-mix(in oklab, var(--accent) 10%, var(--neutral-bg));
  --accent-border:   light-dark(oklch(0.60 0.10 90), oklch(0.60 0.10 90));

  /* ─── Statuts ─── */
  --status-success: light-dark(oklch(0.62 0.17 150), oklch(0.78 0.14 162));
  --status-danger:  light-dark(oklch(0.58 0.22 25),  oklch(0.70 0.19 27));
  --status-warning: light-dark(oklch(0.78 0.16 72),  oklch(0.85 0.14 70));
  --status-info:    light-dark(oklch(0.55 0.15 250), oklch(0.74 0.16 260));
}

[data-theme="ferrari"][data-theme-mode="light"],
[data-color-theme="ferrari"][data-theme-mode="light"] { color-scheme: light; }
[data-theme="ferrari"][data-theme-mode="dark"],
[data-color-theme="ferrari"][data-theme-mode="dark"]  { color-scheme: dark; }

/* themes/forest/color.css */
/* Peels — Thème forest — axe couleur
   Tons verts profonds, naturels. Brand = vert, neutre teinté vert.
   Surcharge les inputs --brand/--action/--accent (+ neutre).
   Le socle dérive les variantes par job. _contract.css mappe vers --peels-*.
   Activé par : data-color-theme="forest" sur :root ou tout ancêtre
   ════════════════════════════════════════════════════════ */

[data-color-theme="forest"] {

  /* ─── Inputs de marque ─── */
  --brand:  light-dark(oklch(0.50 0.160 145), oklch(0.68 0.160 150));
  --action: var(--brand);
  --accent: var(--brand);

  /* ─── Neutre — teinté vert ─── */
  --neutral-bg:           light-dark(oklch(0.97 0.010 145), oklch(0.16 0.020 145));
  --neutral-bg-elevated:  light-dark(oklch(0.99 0.008 145), oklch(0.20 0.025 145));
  --neutral-bg-sunken:    light-dark(oklch(0.94 0.015 145), oklch(0.14 0.018 145));
  --neutral-text:         light-dark(oklch(0.25 0.020 145), oklch(0.85 0.020 145));
  --neutral-text-muted:   light-dark(oklch(0.55 0.020 145), oklch(0.50 0.020 145));
  --neutral-border:       light-dark(oklch(0.88 0.010 145), oklch(0.25 0.020 145));

  /* ─── Statuts (harmonisés tons verts) ─── */
  --status-success: light-dark(oklch(0.55 0.15 155), oklch(0.70 0.14 158));
  --status-danger:  light-dark(oklch(0.55 0.17 25),  oklch(0.65 0.18 20));
  --status-warning: light-dark(oklch(0.75 0.14 75),  oklch(0.78 0.13 80));
  --status-info:    light-dark(oklch(0.55 0.12 200), oklch(0.68 0.12 200));
}

/* themes/itadori/color.css */
/* Peels — Thème itadori — axe couleur
   Cas 3 : palette riche — 3 couleurs distinctes (brand ≠ action ≠ accent).
   Source : tweakcn "Itadori Yuji" (red-orange + dark blue + pink).
   brand = red-orange (identité), action = dark blue (interactions),
   accent = pink (emphase décorative). Démontre la séparation totale des 3 rôles.
   Surcharge les inputs --brand/--action/--accent (+ neutre).
   Le socle dérive les variantes par job. _contract.css mappe vers --peels-*.
   Activé par : data-color-theme="itadori" sur :root ou tout ancêtre
   ════════════════════════════════════════════════════════ */

[data-theme="itadori"],
[data-color-theme="itadori"] {

  /* ─── Inputs de marque ───
     brand  = red-orange (identité, hue 28)
     action = dark blue (boutons/liens, hue 267 — contraste fort avec brand)
     accent = pink/red (emphase décorative, hue 8 — complémentaire) */
  --brand:  light-dark(oklch(0.5882 0.2309 28.2936), oklch(0.6453 0.2404 27.3106));
  --action: light-dark(oklch(0.3303 0.0753 267.1046), oklch(0.2604 0.0471 267.4902));
  --accent: light-dark(oklch(0.8342 0.0950 7.8239),   oklch(0.6986 0.1954 14.1660));

  /* ─── Neutre — blue-gray léger (Itadori Yuji) ─── */
  --neutral-bg:           light-dark(oklch(0.9911 0      0),        oklch(0.1645 0.0086 274.3354));
  --neutral-bg-elevated:  light-dark(oklch(1.0000 0      0),        oklch(0.2145 0.0184 270.4182));
  --neutral-bg-sunken:    light-dark(oklch(0.9674 0.0013 286.3752), oklch(0.2739 0.0055 286.0326));
  --neutral-text:         light-dark(oklch(0.1763 0.0140 258.3572), oklch(0.9911 0      0));
  --neutral-text-muted:   light-dark(oklch(0.5517 0.0138 285.9385), oklch(0.7118 0.0129 286.0665));
  --neutral-border:       light-dark(oklch(0.9197 0.0040 286.3202), oklch(0.2739 0.0055 286.0326));

  /* ─── Dérivations semi-manuelles — on garde les recettes mécaniques pour
     hover/border, mais on impose les foregrounds de tweakcn (primary-foreground,
     secondary-foreground, accent-foreground) car le texte sur brand/action/accent
     est calibré dans la source. ─── */
  --brand-text:  light-dark(oklch(1 0 0), oklch(1 0 0));        /* primary-foreground = white */
  --action-text: light-dark(oklch(1 0 0), oklch(1 0 0));        /* secondary-foreground = white */
  --accent-text: light-dark(oklch(0.3155 0.1064 18.1157),
                            oklch(0.3155 0.1064 18.1157));     /* accent-foreground = dark red */

  /* ─── Statuts ─── */
  --status-success: light-dark(oklch(0.696 0.149 162), oklch(0.780 0.140 162));
  --status-danger:  light-dark(oklch(0.577 0.215 27),  oklch(0.700 0.190 27));
  --status-warning: light-dark(oklch(0.769 0.165 70),  oklch(0.850 0.140 70));
  --status-info:    light-dark(oklch(0.623 0.188 260), oklch(0.740 0.160 260));
}

[data-theme="itadori"][data-theme-mode="light"],
[data-color-theme="itadori"][data-theme-mode="light"] { color-scheme: light; }
[data-theme="itadori"][data-theme-mode="dark"],
[data-color-theme="itadori"][data-theme-mode="dark"]  { color-scheme: dark; }

/* themes/mono/type.css */
/* Peels — Thème mono — axe typographie
   Tout en monospace — style terminal/code
   Activé par : data-type-theme="mono" sur :root ou tout ancêtre
   ════════════════════════════════════════════════════════ */

[data-type-theme="mono"] {
  --peels-font-ui:      var(--font-mono);
  --peels-font-prose:   var(--font-mono);
  --peels-font-heading: var(--font-mono);
  --peels-font-mono:    var(--font-mono);
  --peels-font-weight-ui: 500;

  --peels-text-base:    var(--size-step-0);
  --peels-text-small:   var(--size-step--1);
  --peels-text-xsmall:  var(--size-step--2);

  --peels-leading:      1.6;
  --peels-leading-fine: 1.25;
}

/* themes/rosepine/color.css */
/* Peels — Thème rosepine — axe couleur
   Cas 5 : palette nommée — Rosé Pine (niveau 3 : mapping direct des rôles).
   Source : Rosé Pine (main/dawn) — 12 couleurs nommées par rôle.
   brand = love (rose), action = pine (teal), accent = iris (purple).
   Neutre = base/surface/overlay/text/muted + border dérivé.
   Démontre l'intégration d'une palette nommée complète sans dérivation.
   Activé par : data-color-theme="rosepine" sur :root ou tout ancêtre
   ════════════════════════════════════════════════════════ */

[data-theme="rosepine"],
[data-color-theme="rosepine"] {

  /* ─── Inputs de marque (Rosé Pine named roles) ───
     brand  = love (rose/red — identité)
     action = pine (teal/blue — interactions, contraste avec brand)
     accent = iris (purple — emphase décorative) */
  --brand:  light-dark(#b4637a, #eb6f92);  /* love */
  --action: light-dark(#286983, #31748f);  /* pine */
  --accent: light-dark(#907aa9, #c4a7e7);  /* iris */

  /* ─── Neutre — Rosé Pine base/surface/overlay/text/muted ─── */
  --neutral-bg:           light-dark(#faf4ed, #191724);  /* base */
  --neutral-bg-elevated:  light-dark(#fffaf3, #1f1d2e);  /* surface */
  --neutral-bg-sunken:    light-dark(#f2e9e0, #26233a);  /* overlay */
  --neutral-text:         light-dark(#575279, #e0def4);  /* text */
  --neutral-text-muted:   light-dark(#9893a5, #6e6a86);  /* muted */
  --neutral-border:       light-dark(
    color-mix(in oklab, #797593 15%, #faf4ed),  /* subtle × base (light) */
    color-mix(in oklab, #908caa 15%, #191724)   /* subtle × base (dark) */
  );

  /* ─── Dérivations manuelles (niveau 3) — on sort des recettes mécaniques.
     Texte sur brand/action/accent = surface light / base dark.
     Hover/border choisis dans les couleurs nommées Rosé Pine. ─── */
  --brand-text:      light-dark(#fffaf3, #191724);
  --brand-bg-hover:  light-dark(#a0506a, #f0809d);
  --brand-bg-soft:   color-mix(in oklab, var(--brand) 10%, var(--neutral-bg));
  --brand-border:    light-dark(#d0a8b0, #403d52);

  --action-text:     light-dark(#fffaf3, #191724);
  --action-bg-hover: light-dark(#1f5a70, #3a9fbf);
  --action-bg-soft:  color-mix(in oklab, var(--action) 10%, var(--neutral-bg));
  --action-border:   light-dark(#a0c0d0, #393552);

  --accent-text:     light-dark(#fffaf3, #191724);
  --accent-bg-hover: light-dark(#806090, #b080d0);
  --accent-bg-soft:  color-mix(in oklab, var(--accent) 10%, var(--neutral-bg));
  --accent-border:   light-dark(#c0b0d0, #393552);

  /* ─── Statuts — mappés sur les couleurs Rosé Pine ───
     success = foam, danger = love, warning = gold, info = pine */
  --status-success: light-dark(#56949f, #9ccfd8);  /* foam */
  --status-danger:  light-dark(#b4637a, #eb6f92);  /* love */
  --status-warning: light-dark(#ea9d34, #f6c177);  /* gold */
  --status-info:    light-dark(#286983, #31748f);  /* pine */
}

[data-theme="rosepine"][data-theme-mode="light"],
[data-color-theme="rosepine"][data-theme-mode="light"] { color-scheme: light; }
[data-theme="rosepine"][data-theme-mode="dark"],
[data-color-theme="rosepine"][data-theme-mode="dark"]  { color-scheme: dark; }

/* themes/warm/color.css */
/* Peels — Thème warm — axe couleur
   Tons orange/ambre, chaleureux. Brand = terracotta, accent = doré, neutre sable.
   Surcharge les inputs --brand/--action/--accent (+ neutre).
   Le socle dérive les variantes par job. _contract.css mappe vers --peels-*.
   Activé par : data-color-theme="warm" sur :root ou tout ancêtre
   ════════════════════════════════════════════════════════ */

[data-color-theme="warm"] {

  /* ─── Inputs de marque ─── */
  --brand:  light-dark(oklch(0.58 0.180 50), oklch(0.72 0.180 55));
  --action: var(--brand);
  --accent: light-dark(oklch(0.75 0.150 70), oklch(0.85 0.150 75));

  /* ─── Neutre — tons sable ─── */
  --neutral-bg:           light-dark(oklch(0.98 0.010 60), oklch(0.18 0.020 50));
  --neutral-bg-elevated:  light-dark(oklch(1    0.008 60), oklch(0.22 0.025 50));
  --neutral-bg-sunken:    light-dark(oklch(0.95 0.015 60), oklch(0.16 0.018 50));
  --neutral-text:         light-dark(oklch(0.25 0.020 50), oklch(0.85 0.020 55));
  --neutral-text-muted:   light-dark(oklch(0.55 0.015 55), oklch(0.50 0.020 50));
  --neutral-border:       light-dark(oklch(0.88 0.012 55), oklch(0.25 0.020 50));

  /* ─── Statuts (harmonisés tons chauds) ─── */
  --status-success: light-dark(oklch(0.58 0.14 155), oklch(0.70 0.14 160));
  --status-danger:  light-dark(oklch(0.55 0.16 25),  oklch(0.65 0.17 20));
  --status-warning: light-dark(oklch(0.78 0.15 65),  oklch(0.80 0.14 70));
  --status-info:    light-dark(oklch(0.55 0.12 230), oklch(0.68 0.12 235));
}
}

/* ── base ── */
@layer base {
/* Peels — Base
   Styles sémantiques HTML.
   ════════════════════════════════════════════════════════ */

body {
  font-family: var(--peels-font-prose);
  font-size: var(--peels-text-base);
  line-height: var(--peels-leading);
  accent-color: var(--peels-color-highlight);
  color: var(--peels-text-body);
  background-color: var(--peels-surface-page);
}



svg {
  block-size: 2ex;
  inline-size: auto;
  flex: none;
}

/* ─── Médias — base transverse pour replaced elements ─── */
/* Le reset (_reset.css) gère display:block, max-inline-size, block-size:auto.
   Ici : radius transverse via knob. Les styles spécifiques (audio, figcaption)
   sont dans leurs éléments .webc respectifs. */

:where(img, video, iframe, figure, audio[controls]) {
  border-radius: var(--peels-media-radius, 0);
}

a {
  color: currentcolor;
  text-decoration-thickness: 0.08em;
}

/* ─── Label — socle commun ───
   Inspiré de Blades (block, margin modeste, weight inherit) et Keel
   (weight 600 pour distinguer du texte de prose). Pas de font-size
   spécifique : le label hérite de la taille de son contexte. */
label {
  /* display: block; */
  font-size: var(--peels-label-size, var(--peels-control-font-size));
  font-weight: var(--peels-label-weight, var(--peels-font-weight-ui));
  /* margin-block-end: var(--peels-label-gap, var(--space-3xs)); */
}

/* ─── Focus visible — approche medienbäcker ─── */
/* Variables sur :root (définies dans _contract.css) permettent d'ajuster
   par contexte sans guerre de spécificité. currentColor garantit le contraste.

   Exceptions connues à traiter progressivement :
   - Éléments sur fond sombre (boutons accent, header mobile) : surcharger --peels-focus-color
   - Liens inline dans la prose : --peels-focus-style: none + underline au focus
   - Champs de formulaire : --peels-focus-offset plus généreux pour dégager la border
   - Éléments pleine largeur : offset négatif ou 0 pour ne pas dépasser le viewport
   - Parents avec overflow: hidden : l'outline peut être clippé */
:focus-visible {
  outline-color: var(--peels-focus-color, currentColor);
  outline-offset: var(--peels-focus-offset, 0.15em);
  outline-style: var(--peels-focus-style, solid);
  outline-width: var(--peels-focus-width, 2px);
  border-radius: var(--peels-focus-radius, 1px);
}

:focus:not(:focus-visible) {
  outline: none;
}

[role="tablist"]:has(:focus-visible) {
  outline: var(--peels-focus-width, 2px) var(--peels-focus-style, solid) var(--peels-focus-color, currentColor);
  outline-offset: var(--peels-focus-offset, 0.15em);
  border-radius: var(--peels-focus-radius, 1px);
}

::selection {
  background-color: var(--accent-bg-soft);
  color: currentColor;
}

/* ─── Rythme vertical — lobotomized owl ─── */
/* Pattern scoped aux conteneurs sémantiques. Gère premier (pas de marge-top
   via +) et dernier (pas de marge-bottom par absence) sans cas spécial.
   Cible uniquement les éléments de prose pour ne pas perturber les
   div/grid/flex. :where() = spécificité 0, donc les règles spécifiques
   (headings asymétriques, blockquote, hr) gagnent. */
:where(article, section, main, aside) > * + :where(p, ul, ol, dl, blockquote, figure, pre, table, hr, address) {
  margin-block-start: var(--peels-gap-prose, var(--peels-gap-component));
}

/* ─── Nav — socle commun à toute navigation ─── */
/* <menu> est traité par les navigateurs comme <ul> (MDN). Pas de role="menu"
   implicite — on garde la navigation clavier native (Tab). */
nav :where(ul, ol, menu) {
  list-style: none;
  margin: 0;
  padding: 0;
}

/* text-decoration: none légitime en contexte nav : les liens sont regroupés
   visuellement. Contreparties obligatoires : hover, focus-visible, aria-current. */
nav a {
  text-decoration: none;
  color: var(--peels-nav-link-color, var(--peels-text-body));

  &:hover, &:focus-visible {
    color: var(--peels-nav-link-color-hover, var(--peels-text-accent));
    text-decoration: underline;
  }

  &[aria-current] {
    color: var(--peels-nav-link-color-current, var(--peels-text-body));
    font-weight: var(--peels-font-weight-ui);
  }
}


}

/* ── elements ── */
@layer elements {
/* peels-accordion.webc */
/* ─── Accordion — groupe details[name] exclusif ───
     Réutilise les variables --peels-details-* de peels-details.webc
     pour une cohérence parfaite. Le conteneur data-component="accordion"
     connecte visuellement les panneaux.
  ─── */

  [data-component="accordion"] {
    border: var(--peels-details-border, 1px solid var(--peels-border-subtle));
    border-radius: var(--peels-details-radius, var(--peels-component-radius));
    overflow: hidden;
    box-shadow: var(--peels-elevation-1, none);

    & > details {
      border: none;
      border-radius: 0;
      margin-block: 0;
      background-color: var(--peels-surface-panel);

      & + details {
        border-block-start: var(--peels-details-border, 1px solid var(--peels-border-subtle));
        margin-block-start: 0;
      }

      & > summary {
        padding: var(--peels-details-padding, var(--peels-padding-block));
        cursor: pointer;
        transition:
          background-color var(--peels-transition-duration-fast) var(--peels-transition-easing),
          color var(--peels-transition-duration-fast) var(--peels-transition-easing);

        &:hover {
          background-color: var(--peels-surface-hover);
        }

        &:focus-visible {
          outline: var(--peels-focus-width, 2px) var(--peels-focus-style, solid) var(--peels-focus-color, currentColor);
          outline-offset: var(--peels-focus-offset, 0.15em);
        }
      }

      &[open] > summary {
        margin-block-end: 0;
        background-color: var(--peels-surface-panel);
      }
    }
  }

/* peels-address.webc */
address {
    font-style: var(--peels-address-style, normal);
    line-height: var(--peels-leading);
    color: var(--peels-address-color, var(--peels-text-body));

    & a {
      color: var(--peels-text-link);
    }
  }

/* peels-alert.webc */
[role="alert"] {
    padding: var(--peels-padding-block);
    border-inline-start: var(--peels-alert-border-width, 4px) solid var(--peels-border-subtle);
    background-color: var(--peels-surface-panel);
    border-radius: var(--peels-alert-radius, var(--peels-component-radius));

    &[data-intent="info"] {
      border-color: var(--peels-accent-info);
      background-color: var(--peels-alert-info-bg, color-mix(in oklab, var(--peels-accent-info) 8%, var(--peels-surface-panel)));
    }
    &[data-intent="success"] {
      border-color: var(--peels-accent-success);
      background-color: var(--peels-alert-success-bg, color-mix(in oklab, var(--peels-accent-success) 8%, var(--peels-surface-panel)));
    }
    &[data-intent="warning"] {
      border-color: var(--peels-accent-warning);
      background-color: var(--peels-alert-warning-bg, color-mix(in oklab, var(--peels-accent-warning) 8%, var(--peels-surface-panel)));
    }
    &[data-intent="danger"] {
      border-color: var(--peels-accent-danger);
      background-color: var(--peels-alert-danger-bg, color-mix(in oklab, var(--peels-accent-danger) 8%, var(--peels-surface-panel)));
    }
  }

/* peels-audio.webc */
/* Audio natif : 300px par défaut. Knob pour rendre responsive.
     audio:not([controls]) caché — pas de player sans controls. */
  audio {
    &[controls] {
      inline-size: var(--peels-audio-inline-size, 100%);
    }

    &:not([controls]) {
      display: none;
    }
  }

/* peels-badge.webc */
[data-badge] {
    display: inline-block;
    font-size: var(--peels-text-xsmall);
    font-weight: var(--peels-font-weight-ui);
    padding: var(--peels-badge-padding, 0.15em 0.6em);
    border-radius: var(--peels-badge-radius, var(--radius-pill));
    background-color: var(--peels-surface-panel);
    color: var(--peels-text-body);

    &[data-badge="info"]    { background-color: var(--peels-accent-info); color: var(--peels-badge-info-color, var(--peels-surface-page)); }
    &[data-badge="success"] { background-color: var(--peels-accent-success); color: var(--peels-badge-success-color, var(--peels-surface-page)); }
    &[data-badge="warning"] { background-color: var(--peels-accent-warning); color: var(--peels-badge-warning-color, var(--peels-surface-page)); }
    &[data-badge="danger"]  { background-color: var(--peels-accent-danger); color: var(--peels-badge-danger-color, var(--peels-surface-page)); }
  }

/* peels-breadcrumb.webc */
/* ─── Breadcrumb — nav > ol (navigation ordonnée) ─── */
  nav:has(> ol) {
    & > ol {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      gap: var(--peels-breadcrumb-gap, 0);
      font-size: var(--peels-breadcrumb-font-size, var(--peels-text-small));
      list-style: none;
      margin: 0;
      padding: 0;

      /* Séparateur APRÈS l'item (::after, pas ::before du suivant) : un
         item caché (data-collapse) ne dessine pas son séparateur — les
         lignes enroulées ne commencent jamais par un « / » orphelin. */
      & > li:not(:last-child)::after {
        content: var(--peels-breadcrumb-separator, "/");
        margin-inline: var(--peels-breadcrumb-separator-margin, 0.25em);
        color: var(--peels-text-muted);
      }

      & > li > a {
        color: var(--peels-breadcrumb-link-color, var(--peels-text-muted));
        text-decoration: none;
        transition: color var(--peels-transition-duration-fast) var(--peels-transition-easing);

        &:hover {
          color: var(--peels-breadcrumb-link-color-hover, var(--peels-text-body));
          text-decoration: underline;
          text-underline-offset: var(--peels-link-underline-offset, 0.15em);
        }

        &:focus-visible {
          outline-color: var(--peels-focus-color, currentColor);
          outline-offset: var(--peels-focus-offset, 0.15em);
          outline-style: var(--peels-focus-style, solid);
          outline-width: var(--peels-focus-width, 2px);
          border-radius: var(--peels-focus-radius, 1px);
        }
      }

      & > li[aria-current] {
        color: var(--peels-breadcrumb-current-color, var(--peels-text-body));
        font-weight: var(--peels-breadcrumb-current-weight, var(--peels-font-weight-ui));
      }
    }
  }

  /* RTL — le séparateur directionnel se retourne (knob dédié, comme
     Blades/Pico : le « / » devient « \ »). Le consommateur qui personnalise
     le séparateur LTR doit aussi prévoir le sien en RTL. */
  nav:dir(rtl):has(> ol) > ol > li:not(:last-child)::after {
    content: var(--peels-breadcrumb-separator-rtl, "\\");
  }

/* peels-button.webc */
/* ═══ Base — stroked by default, powered by custom properties ═══
     Andy Bell pattern : le base définit les variables + le layout.
     Chaque variant override uniquement les variables.
     Spécificité : base (0,0,1) < variants (0,1,0) < group (0,1,1). */

  button,
  [role="button"],
  [type="submit"],
  [type="reset"],
  [type="button"] {
    /* ─── Configuration (stroked = défaut) ─── */
    --peels-btn-bg: transparent;
    --peels-btn-color: currentColor;
    --peels-btn-border: currentColor;
    --peels-btn-bg-hover: var(--peels-surface-hover);
    --peels-btn-border-hover: var(--peels-text-body);
    --peels-btn-color-hover: var(--peels-btn-color);
    /* padding / min-height / font-scale : variables libres (pas de
       déclaration ici — un contexte les pose sur lui-même et elles héritent,
       cf. toolbar). Défauts en fallback au point d'usage. */

    /* ─── Layout ─── */
    display: inline-flex;
    align-items: center;
    justify-content: center;
    vertical-align: middle;
    gap: var(--peels-control-gap, var(--space-3xs));
    min-block-size: var(
      --peels-btn-min-height,
      var(--peels-control-min-height)
    );
    padding-block: var(
      --peels-btn-padding-block,
      var(--peels-control-padding-block, var(--space-2xs))
    );
    padding-inline: var(
      --peels-btn-padding-inline,
      var(--peels-control-padding-inline, var(--space-s))
    );
    border: var(--peels-border-width) solid var(--peels-btn-border);
    border-radius: var(--peels-component-radius);
    font-family: var(--peels-font-ui);
    font-size: calc(1em * var(--peels-btn-font-scale, 0.85));
    font-weight: var(--peels-font-weight-ui);
    line-height: var(--peels-line-height-flat);
    text-box: trim-both cap alphabetic;
    text-decoration: none;
    background-color: var(--peels-btn-bg);
    color: var(--peels-btn-color);
    cursor: pointer;
    user-select: none;
    touch-action: manipulation;
    appearance: none;
    -webkit-tap-highlight-color: transparent;
    transition:
      background-color var(--peels-transition-duration-fast)
        var(--peels-transition-easing),
      border-color var(--peels-transition-duration-fast)
        var(--peels-transition-easing),
      color var(--peels-transition-duration-fast) var(--peels-transition-easing);

    &:hover:not(:disabled, [aria-disabled="true"]) {
      background-color: var(--peels-btn-bg-hover);
      border-color: var(--peels-btn-border-hover);
      color: var(--peels-btn-color-hover);
    }

    &:active:not(:disabled, [aria-disabled="true"]) {
      background-color: var(
        --peels-btn-bg-active,
        oklch(from var(--peels-btn-bg) calc(l + var(--u-shift-active)) c h)
      );
    }

    &:focus-visible {
      outline: var(--peels-focus-width) solid var(--peels-focus-ring);
      outline-offset: var(--peels-focus-offset);
    }

    &:focus:not(:focus-visible) {
      outline: none;
    }
  }

  /* ─── Disabled ─── */
  button:disabled,
  [aria-disabled="true"] {
    opacity: var(--peels-disabled-opacity, 0.25);
    cursor: not-allowed;
    pointer-events: none;
  }

  button[aria-disabled="true"] {
    pointer-events: auto;
  }

  /* ─── Submit → solid (action principale) ─── */
  [type="submit"] {
    --peels-btn-bg: var(--peels-btn-base);
    --peels-btn-color: var(--peels-surface-page);
    --peels-btn-border: var(--peels-btn-base);
    --peels-btn-bg-hover: oklch(
      from var(--peels-btn-base) calc(l + var(--u-shift-hover)) c h
    );
    --peels-btn-border-hover: oklch(
      from var(--peels-btn-base) calc(l + var(--u-shift-hover)) c h
    );
  }

  /* ─── data-variant="brand" — solid avec couleur de marque ─── */
  :where(
    button,
    [role="button"],
    [type="submit"],
    [type="reset"],
    [type="button"]
  )[data-variant="brand"] {
    --peels-btn-bg: var(--peels-brand, var(--brand));
    --peels-btn-color: var(--peels-surface-page);
    --peels-btn-border: var(--peels-brand, var(--brand));
    --peels-btn-bg-hover: oklch(
      from var(--peels-brand, var(--brand)) calc(l + var(--u-shift-hover)) c h
    );
    --peels-btn-border-hover: oklch(
      from var(--peels-brand, var(--brand)) calc(l + var(--u-shift-hover)) c h
    );
  }

  /* ─── data-variant="ghost" — true ghost (transparent, inversion au hover) ─── */
  :where(
    button,
    [role="button"],
    [type="submit"],
    [type="reset"],
    [type="button"]
  )[data-variant="ghost"] {
    --peels-btn-border: transparent;
    --peels-btn-bg-hover: var(--peels-text-body);
    --peels-btn-color-hover: var(--peels-surface-page);
    --peels-btn-border-hover: var(--peels-text-body);

    &:disabled,
    &[aria-disabled="true"] {
      text-decoration: line-through;
    }
  }

  /* ─── Groupe & toolbar — boutons collés + border unifiée ───
     Too narrow → horizontal scroll (flex: none avoids squashing;
     first/last-child corners stay valid since nothing wraps). */
  :is([role="group"], [role="toolbar"]):has(> button, > [role="button"]) {
    display: inline-flex;
    vertical-align: middle;
    overflow-x: auto;
    /* a flex parent floors items at min-content — allow shrink so
       the scrollport actually kicks in */
    min-inline-size: 0;
    /* room for focus rings inside the scrollport */
    padding: calc(var(--peels-focus-width) + var(--peels-focus-offset));

    & > button,
    & > [role="button"] {
      --peels-btn-border: var(--peels-text-body);
      flex: none;
      border-radius: 0;
      margin-inline-start: calc(var(--peels-border-width) * -1);

      &:first-child {
        border-start-start-radius: var(--peels-component-radius);
        border-end-start-radius: var(--peels-component-radius);
        margin-inline-start: 0;
      }

      &:last-child {
        border-start-end-radius: var(--peels-component-radius);
        border-end-end-radius: var(--peels-component-radius);
      }

      &:hover,
      &:focus-visible {
        z-index: 1;
      }
    }

    /* Solid buttons keep their own border (invisible = same color as bg) */
    & > [type="submit"]:not([data-variant]),
    & > [data-variant="brand"] {
      --peels-btn-border: var(--peels-btn-base);
    }
  }

  /* ─── Icône seule — auto-round ─── */
  button:has(> svg):not(:has(> span, > :not(svg):not(i[aria-hidden="true"]))),
  button:has(> i[aria-hidden="true"]):not(
      :has(> span, > :not(svg):not(i[aria-hidden="true"]))
    ) {
    --peels-btn-padding-inline: var(
      --peels-btn-padding-block,
      var(--peels-control-padding-block, var(--space-2xs))
    );
    min-inline-size: var(
      --peels-btn-min-height,
      var(--peels-control-min-height)
    );
    border-radius: var(--peels-btn-icon-radius, var(--radius-pill));
  }

  /* ─── Icône + texte — padding réduit côté icône ─── */
  button:has(> svg:first-child):has(> span) {
    padding-inline-start: var(
      --peels-btn-padding-block,
      var(--peels-control-padding-block, var(--space-2xs))
    );
  }

  button:has(> svg:last-child):has(> span) {
    padding-inline-end: var(
      --peels-btn-padding-block,
      var(--peels-control-padding-block, var(--space-2xs))
    );
  }

  /* ─── Toolbar — boutons compacts par contexte (contrainte d'espace) ───
     Le contexte pose les variables sur lui-même (pas de combinateur) :
     elles atteignent les boutons par héritage — robuste aux wrappers
     et aux frontières (shadow DOM). Cf. audit theming 03/09. */
  [role="toolbar"] {
    --peels-btn-min-height: clamp(2rem, 1.875rem + 0.568vi, 2.25rem);
    --peels-btn-font-scale: 0.7;
    --peels-btn-padding-inline: var(--peels-gap-sm);
  }

  /* ─── Loading — aria-busy (ARIA standard, pas de data-*) ─── */
  button[aria-busy="true"],
  [role="button"][aria-busy="true"] {
    cursor: progress;
    pointer-events: none;

    &::after {
      content: "";
      inline-size: 1em;
      block-size: 1em;
      flex: none;
      border: 2px solid currentColor;
      border-block-start-color: transparent;
      border-radius: 50%;
      animation: peels-btn-spin 0.6s linear infinite;
    }
  }

  @keyframes peels-btn-spin {
    to {
      transform: rotate(1turn);
    }
  }

  /* ─── Icônes dans les boutons ─── */
  button svg,
  [role="button"] svg,
  button i[aria-hidden="true"],
  [role="button"] i[aria-hidden="true"] {
    block-size: 1em;
    inline-size: 1em;
    flex: none;
    pointer-events: none;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  @supports (color: contrast-color(red)) {
    [type="submit"] {
      --peels-btn-color: contrast-color(var(--peels-btn-base));
    }
    :where(
      button,
      [role="button"],
      [type="submit"],
      [type="reset"],
      [type="button"]
    )[data-variant="brand"] {
      --peels-btn-color: contrast-color(var(--peels-brand, var(--brand)));
    }
  }

/* peels-callout.webc */
[data-component="callout"] {
    padding: var(--peels-callout-padding, var(--peels-padding-block));
    border: var(--peels-callout-border, 1px solid var(--peels-border-subtle));
    border-radius: var(--peels-callout-radius, var(--peels-component-radius));
    background-color: var(--peels-callout-bg, var(--peels-surface-panel-soft));
    color: var(--peels-callout-color, var(--peels-text-body));
    margin-block: var(--peels-callout-margin-block, var(--peels-gap-component));

    &[data-intent="info"] {
      border-color: var(--peels-callout-info-border, var(--peels-accent-info));
      background-color: var(--peels-callout-info-bg, oklch(from var(--peels-accent-info) l c h / 0.08));
    }

    &[data-intent="success"] {
      border-color: var(--peels-callout-success-border, var(--peels-accent-success));
      background-color: var(--peels-callout-success-bg, oklch(from var(--peels-accent-success) l c h / 0.08));
    }

    &[data-intent="warning"] {
      border-color: var(--peels-callout-warning-border, var(--peels-accent-warning));
      background-color: var(--peels-callout-warning-bg, oklch(from var(--peels-accent-warning) l c h / 0.08));
    }

    &[data-intent="danger"] {
      border-color: var(--peels-callout-danger-border, var(--peels-accent-danger));
      background-color: var(--peels-callout-danger-bg, oklch(from var(--peels-accent-danger) l c h / 0.08));
    }

    & p:first-child {
      margin-block-start: 0;
    }

    & p:last-child {
      margin-block-end: 0;
    }
  }

/* peels-card.webc */
[data-component="card"] {
    all: inherit;
  }

/* peels-checkbox.webc */
:where(fieldset:has(> label > input:is([type="checkbox"], [type="radio"]))) {
    display: grid;
    gap: var(--peels-choice-group-gap, var(--peels-control-gap));
  }

  label:has(> input:is([type="checkbox"], [type="radio"]):not([role="switch"])) {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: start;
    gap: var(--peels-control-gap);
    line-height: var(--peels-choice-leading, var(--peels-leading));
    font-weight: var(--peels-choice-weight, normal);
    cursor: pointer;

    & > input {
      line-height: inherit;
      margin-block-start: calc((1lh - round(var(--peels-control-size, 1.25em), 2px)) / 2);
    }
  }

  :is(th, td):has(> input:is([type="checkbox"], [type="radio"]):only-child) {
    inline-size: 1%;
    white-space: nowrap;
    padding-inline: var(--peels-table-choice-padding-inline, var(--peels-control-gap));
  }

  input:is([type="checkbox"], [type="radio"]):not([role="switch"]) {
    appearance: none;
    margin: 0;
    padding: 0;
    inline-size: round(var(--peels-control-size, 1.25em), 2px);
    block-size: round(var(--peels-control-size, 1.25em), 2px);
    aspect-ratio: 1;
    display: inline-grid;
    place-content: center;
    vertical-align: middle;
    font: inherit;
    font-size: var(--peels-control-font-size);
    color: var(--peels-color-highlight);
    background-color: var(--peels-surface-page);
    border: var(--peels-border-width) solid var(--peels-text-muted);
    border-radius: var(--peels-checkbox-radius, var(--peels-component-radius));
    cursor: pointer;
    transition:
      background-color var(--peels-transition-duration-fast) var(--peels-transition-easing),
      border-color var(--peels-transition-duration-fast) var(--peels-transition-easing),
      box-shadow var(--peels-transition-duration-fast) var(--peels-transition-easing);

    &[type="radio"] {
      border-radius: 50%;
    }

    &[type="checkbox"]::before {
      content: "";
      inline-size: 0.65em;
      block-size: 0.65em;
      transform: scale(0);
      transition: transform var(--peels-transition-duration-fast) var(--peels-transition-easing);
      background-color: var(--peels-surface-page);
      mask: var(--peels-checkbox-mark, var(--peels-icon-check, none)) no-repeat center / contain;
    }

    &:checked,
    &:indeterminate {
      border-color: currentColor;
      background-color: currentColor;

      &::before {
        transform: scale(1);
      }
    }

    &[type="radio"]:checked {
      box-shadow: inset 0 0 0 round(nearest, 0.22em, 1px) var(--peels-surface-page);
    }

    &:indeterminate::before {
      mask: var(--peels-checkbox-indeterminate-mark, var(--peels-icon-minus, none)) no-repeat center / contain;
    }

    &:hover:not(:disabled) {
      border-color: var(--peels-text-body);
    }

    &:focus-visible {
      outline: var(--peels-focus-width) solid var(--peels-focus-ring);
      outline-offset: var(--peels-focus-offset);
    }

    &:active:not(:disabled) {
      transform: scale(0.95);
    }

    &:is([aria-invalid="true"], :user-invalid) {
      border-color: var(--peels-accent-danger);
      color: var(--peels-accent-danger);
    }

    &:disabled {
      opacity: var(--peels-disabled-opacity);
      background-color: var(--peels-surface-panel-soft);
      cursor: not-allowed;
    }

    &:disabled:is(:checked, :indeterminate) {
      background-color: currentColor;
    }

    @media (forced-colors: active) {
      appearance: auto;

      &::before {
        display: none;
      }
    }
  }

/* peels-cluster.webc */
[data-layout~="cluster"] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--peels-cluster-gap, var(--peels-gap-component));
    align-items: center;
  }

/* peels-code.webc */
code, kbd, samp {
    font-family: var(--peels-font-mono);
    font-size: var(--peels-code-font-size, 0.875em);
  }

  :not(pre) > code {
    background-color: var(--peels-code-bg, var(--peels-surface-panel-soft));
    padding: var(--peels-code-padding, 0.15em 0.35em);
    border: var(--peels-code-border, var(--peels-border-width) solid var(--peels-border-subtle));
    border-radius: var(--peels-code-radius, 0.25em);
  }

  kbd {
    background-color: var(--peels-kbd-bg, var(--peels-surface-panel));
    border: var(--peels-kbd-border-width, var(--peels-border-width)) solid var(--peels-border-subtle);
    border-bottom-width: var(--peels-kbd-border-bottom-width, 2px);
    border-radius: var(--peels-code-radius, 0.25em);
    padding: var(--peels-kbd-padding, 0.1em 0.4em);
    font-weight: var(--peels-kbd-weight, 600);
  }

  samp {
    color: var(--peels-text-muted);
  }

  /* kbd inside samp = input echoed by system (MDN pattern) — no keycap, just bold */
  samp > kbd {
    background: none;
    border: none;
    padding: 0;
    font-weight: 700;
  }

  pre {
    background-color: var(--peels-pre-bg, var(--peels-surface-panel-soft));
    color: var(--peels-pre-color, inherit);
    padding: var(--peels-pre-padding, var(--peels-padding-block));
    border: var(--peels-pre-border, none);
    border-radius: var(--peels-pre-radius, var(--peels-component-radius));
    overflow-x: auto;
    line-height: var(--peels-leading-fine);

    & > code {
      background: none;
      padding: 0;
      border: none;
    }

    & > samp {
      color: inherit;
    }
  }

  /* ─── Terminal — bloc sombre sans extension ─── */
  /* data-purpose~="terminal" décrit l'intent (c'est un terminal), pas l'apparence.
     Surcharge les variables du pre — pas de !important, pas de wrapper. */
  pre[data-purpose~="terminal"] {
    --peels-pre-bg: var(--peels-terminal-bg, oklch(0.15 0 0));
    --peels-pre-color: var(--peels-terminal-fg, oklch(0.9 0 0));
  }

  /* Prompt et curseur — pas d'élément HTML sémantique, span dédié (pattern MDN) */
  pre[data-purpose~="terminal"] .prompt {
    color: var(--peels-terminal-prompt, var(--peels-text-link));
  }

  pre[data-purpose~="terminal"] .cursor {
    color: var(--peels-terminal-cursor, var(--peels-text-link));
  }

/* peels-content-container.webc */
[data-layout~="content"] {
    margin-inline: auto;
    padding-inline: var(--peels-content-padding-inline, var(--peels-gap-component));
    max-inline-size: var(--peels-content-max, 65ch);

    &[data-size="small"] {
      max-inline-size: var(--peels-content-max-small, 45ch);
    }

    &[data-size="large"] {
      max-inline-size: var(--peels-content-max-large, 80ch);
    }

    &[data-size="full"] {
      max-inline-size: 100%;
    }
  }

/* peels-details.webc */
/* --- Structurel (immuable) --- */
  summary {
    list-style: none;

    &::marker, &::-webkit-details-marker {
      display: none;
    }
  }

  /* --- Présentation (pilotable par variables) --- */
  details {
    border: var(--peels-details-border, 1px solid var(--peels-border-subtle));
    border-radius: var(--peels-details-radius, var(--peels-component-radius));
    padding: var(--peels-details-padding, var(--peels-padding-block));
    margin-block: var(--peels-details-margin-block, 0);

    &:not(:first-of-type) {
      border-top-left-radius: 0;
      border-top-right-radius: 0;
    }

    &:not(:last-of-type) {
      border-bottom-left-radius: 0;
      border-bottom-right-radius: 0;
    }

    & + details {
      margin-block-start: var(--peels-details-stack-offset, -1px);
    }

    &[open] > summary {
      margin-block-end: var(--peels-details-open-gap, 0.5em);
    }
  }

  summary {
    display: var(--peels-details-summary-display, flex);
    align-items: center;
    gap: var(--peels-details-summary-gap, 0.5em);
    padding: var(--peels-details-summary-padding, 0);
    font-weight: var(--peels-details-summary-weight, var(--peels-font-weight-ui));
    color: var(--peels-details-summary-color, inherit);
    position: var(--peels-details-summary-position, static);

    &:hover {
      color: var(--peels-details-summary-hover-color, var(--peels-text-body));
    }

    &:focus-visible {
      outline: var(--peels-focus-width, 2px) var(--peels-focus-style, solid) var(--peels-focus-color, currentColor);
      outline-offset: var(--peels-focus-offset, 0.15em);
    }

    &::after {
      content: var(--peels-details-marker, "›");
      font-size: var(--peels-details-marker-size, 1.1em);
      color: var(--peels-details-marker-color, var(--peels-text-muted));
      margin-inline-start: var(--peels-details-marker-margin-start, auto);
      margin-inline-end: var(--peels-details-marker-margin-end, 0);
      transition: rotate var(--peels-details-transition, 0.2s ease);
      position: var(--peels-details-marker-position, static);
      inset-inline-start: var(--peels-details-marker-inset-start, auto);
      inset-inline-end: var(--peels-details-marker-inset-end, auto);
      inset-block-start: var(--peels-details-marker-inset-block-start, auto);
      line-height: 1;
    }

    details[open] > &::after {
      rotate: var(--peels-details-marker-rotate, 90deg);
    }
  }

/* peels-dialog.webc */
dialog {
    border: var(--peels-dialog-border-width, var(--peels-border-width)) solid var(--peels-border-subtle);
    border-radius: var(--peels-component-radius);
    padding: var(--peels-gap-section);
    max-inline-size: var(--peels-dialog-max-size, min(90vw, 40rem));
    background-color: var(--peels-surface-page);
    color: var(--peels-text-body);
    box-shadow: var(--peels-dialog-shadow, var(--peels-elevation-3));

    &::backdrop {
      background: var(--peels-dialog-backdrop-bg, oklch(0 0 0 / 0.4));
    }
  }

  dialog {
    --peels-btn-border: var(--peels-dialog-btn-border, var(--peels-border-subtle));

    &:focus-visible {
      outline: var(--peels-focus-width, 2px)
        var(--peels-focus-style, solid)
        var(--peels-focus-color, currentColor);
      outline-offset: var(--peels-focus-offset, 0.15em);
    }
  }

/* peels-drawer.webc */
/* ─── Déclencheur — pas de style imposé, c'est un bouton ─── */
  /* Le bouton déclencheur est un <button> standard — peels-button le style.
     Le drawer ne style que le panneau [popover] et son bouton de fermeture. */

  /* ─── Panneau ─── */
  [popover][data-side] {
    margin: 0;
    padding: var(--peels-drawer-padding, var(--space-l) var(--space-m) var(--space-m));
    background: var(--peels-drawer-bg, var(--peels-surface-panel));
    border: var(--peels-drawer-border, none);
    block-size: var(--peels-drawer-block-size, 100dvh);
    inline-size: var(--peels-drawer-inline-size, min(20rem, 80vw));
    overflow-y: auto;
    overscroll-behavior: contain;

    --peels-drawer-direction: 1;

    &:dir(rtl) {
      --peels-drawer-direction: -1;
    }

    /* État fermé — hors écran */
    transform: translateX(calc(-100% * var(--peels-drawer-direction)));
    opacity: 0;
    transition:
      transform var(--peels-drawer-transition, var(--peels-transition-duration-base)) var(--peels-transition-easing),
      opacity var(--peels-drawer-transition, var(--peels-transition-duration-base)) var(--peels-transition-easing),
      overlay var(--peels-drawer-transition, var(--peels-transition-duration-base)) allow-discrete,
      display var(--peels-drawer-transition, var(--peels-transition-duration-base)) allow-discrete;

    /* Ancrage par côté — inset-*: auto désarme le inset:0 du UA
       stylesheet : sans lui, les deux côtés restent à 0 et le
       navigateur ignore le côté end (l'ancre suivrait la direction
       racine, pas data-side ni la direction de l'élément). */
    &[data-side="start"] {
      inset-inline-start: 0;
      inset-inline-end: auto;
    }

    /* data-side="end" — coulisse depuis l'autre bord */
    &[data-side="end"] {
      inset-inline-start: auto;
      inset-inline-end: 0;
      transform: translateX(calc(100% * var(--peels-drawer-direction)));
    }

    /* État ouvert */
    &:popover-open {
      transform: translateX(0);
      opacity: 1;
    }

    /* Backdrop */
    &::backdrop {
      background: var(--peels-drawer-backdrop, oklch(0 0 0 / 0.5));
      transition: background var(--peels-drawer-transition, var(--peels-transition-duration-base)) var(--peels-transition-easing);
    }
  }

  /* ─── Bouton de fermeture ─── */
  [popover][data-side] > [popovertargetaction="hide"] {
    position: absolute;
    inset-block-start: var(--peels-drawer-close-inset, var(--space-xs));
    inset-inline-end: var(--peels-drawer-close-inset, var(--space-xs));
    display: flex;
    align-items: center;
    justify-content: center;
    inline-size: var(--peels-drawer-close-size, 2.5rem);
    block-size: var(--peels-drawer-close-size, 2.5rem);
    padding: 0;
    background: transparent;
    border: none;
    color: var(--peels-drawer-close-color, var(--peels-text-body));
    cursor: pointer;
  }

/* peels-dropdown.webc */
/* ─── Dropdown — menu[popover] ancré sous son bouton ─── */
  menu[popover] {
    position-area: block-end span-inline-end;
    position-try-fallbacks: flip-block, flip-inline;
    margin: 0;
    margin-block-start: var(--peels-dropdown-offset, var(--space-3xs));
    padding: var(--peels-dropdown-padding, var(--space-3xs));
    list-style: none;
    background: var(--peels-dropdown-bg, var(--peels-surface-panel));
    color: var(--peels-text-body);
    border: var(--peels-border-width, 1px) solid var(--peels-dropdown-border, var(--peels-border-subtle));
    border-radius: var(--peels-dropdown-radius, var(--peels-component-radius));
    box-shadow: var(--peels-dropdown-shadow, var(--peels-elevation-2));

    & a {
      display: block;
      padding: var(--peels-dropdown-item-padding, var(--space-3xs) var(--space-s));
      border-radius: var(--peels-dropdown-radius, var(--peels-component-radius));
      color: inherit;
      text-decoration: none;
      white-space: nowrap;

      &:hover,
      &:focus-visible {
        background-color: var(--peels-dropdown-item-bg-hover, var(--peels-surface-hover));
      }

      &:active {
        color: var(--peels-text-accent);
      }
    }
  }

/* peels-feature-card.webc */
[data-component="card"][data-variant="feature"] {
    position: relative;
    overflow: hidden;
    min-block-size: var(--peels-featurecard-min-height, 16rem);
    display: flex;
    align-items: flex-end;

    & > img {
      position: absolute;
      inset: 0;
      inline-size: 100%;
      block-size: 100%;
      object-fit: cover;
      z-index: 0;
    }

    & > div {
      position: relative;
      z-index: 1;
      padding: var(--peels-featurecard-padding, var(--peels-gap-component));
      background: var(--peels-featurecard-overlay, linear-gradient(transparent 30%, oklch(0% 0 0 / 0.85) 100%));
      color: var(--peels-featurecard-color, var(--peels-surface-page));
      inline-size: 100%;
    }

    & h3 {
      color: inherit;
      margin-block-start: var(--peels-featurecard-title-gap, var(--peels-gap-sm));
    }

    & a {
      color: inherit;
      text-decoration: underline;
      text-underline-offset: 0.15em;
    }
  }

/* peels-field-notes.webc */
em[data-required] {
    color: var(--peels-required-color, var(--peels-accent-danger));
    font-style: normal;
    font-weight: var(--peels-required-weight, var(--weight-bold));
  }

  small[data-hint] {
    display: block;
    margin-block-start: var(--peels-control-gap);
    font-size: var(--peels-hint-size, calc(var(--peels-control-font-size) * 0.9));
    font-weight: var(--peels-hint-weight, 400);
    font-style: var(--peels-hint-style, italic);
    color: var(--peels-hint-color, var(--peels-text-muted));

    & + :where(input:not([type="checkbox"], [type="radio"]), select, textarea, progress, meter) {
      margin-block-start: var(--peels-control-gap);
    }
  }

  small[data-error] {
    display: none;
    margin-block-start: var(--peels-control-gap);
    font-size: var(--peels-error-size, calc(var(--peels-control-font-size) * 0.9));
    font-weight: var(--peels-error-weight, var(--peels-font-weight-ui));
    color: var(--peels-error-color, var(--peels-accent-danger));

    label:is([data-state="error"], :has(> [aria-invalid="true"], > :user-invalid)) > &,
    :where(input, select, textarea):is([aria-invalid="true"], :user-invalid) + & {
      display: block;
    }
  }

/* peels-fieldset.webc */
fieldset {
    border: var(--peels-fieldset-border-width, var(--peels-border-width)) solid var(--peels-border-subtle);
    border-radius: var(--peels-component-radius);
    padding-block: var(--peels-fieldset-padding-block, var(--space-s));
    padding-inline: var(--peels-fieldset-padding-inline, var(--space-s));
    margin: 0;

    & + fieldset {
      margin-block-start: var(--peels-fieldset-gap, var(--peels-gap-component));
    }
  }

  /* Séparation entre champs successifs dans un fieldset.
     Ne s'applique pas aux labels wrappant checkbox/radio (affichés en ligne). */
  fieldset > :not(legend) + label:not(:has(> input[type="checkbox"], > input[type="radio"])) {
    margin-block-start: var(--peels-fieldset-field-gap, var(--space-s));
  }

  legend {
    font-size: var(--peels-fieldset-legend-size, var(--peels-text-xsmall));
    font-weight: var(--peels-font-weight-ui);
    line-height: var(--peels-fieldset-legend-leading, var(--peels-leading-fine));
    padding-inline: var(--peels-legend-padding-inline, var(--peels-control-gap));
    margin-inline-start: calc(-1 * var(--peels-legend-padding-inline, var(--peels-control-gap)));
    /* margin-block-end: calc(-1 * var(--peels-legend-padding-block, var(--space-s))); */
  }

/* peels-figure.webc */
/* Figure — conteneur sémantique. Légende en enfant.
     Convention print : muted, small, italic, line-height serré, centré.
     Caption au-dessus ou en-dessous — :has() détecte la position automatiquement.
     Knobs : --peels-figcaption-color, --peels-figcaption-size, --peels-figcaption-gap,
     --peels-figcaption-style, --peels-figcaption-align, --peels-figcaption-leading. */
  figure {
    & figcaption {
      color: var(--peels-figcaption-color, var(--peels-text-muted));
      font-size: var(--peels-figcaption-size, var(--peels-text-small));
      font-style: var(--peels-figcaption-style, italic);
      line-height: var(--peels-figcaption-leading, var(--peels-leading-fine));
      text-align: var(--peels-figcaption-align, center);
    }

    &:has(* + figcaption) figcaption {
      margin-block-start: var(--peels-figcaption-gap, var(--peels-gap-sm));
    }

    &:has(figcaption + *) figcaption {
      margin-block-end: var(--peels-figcaption-gap, var(--peels-gap-sm));
    }
  }

/* peels-footer.webc */
@scope (:where(body, [data-root])) to (blockquote, figure, dialog) {
    footer {
      padding-block: var(--peels-footer-padding-block, var(--peels-gap-component));
      padding-inline: var(--peels-footer-padding-inline, var(--peels-gap-component));
      border-block-start: var(--peels-footer-border, 1px solid var(--peels-border-subtle));
      background-color: var(--peels-footer-bg, var(--peels-surface-panel));
      color: var(--peels-footer-color, var(--peels-text-body));
      display: flex;
      flex-wrap: wrap;
      gap: var(--peels-footer-gap, var(--peels-gap-sm));
      justify-content: space-between;
      align-items: center;

      & nav {
        display: flex;
        flex-wrap: wrap;
        gap: var(--peels-footer-nav-gap, var(--peels-gap-sm));
      }

      & a {
        color: var(--peels-footer-link-color, inherit);
        text-decoration: none;

        &:hover {
          text-decoration: underline;
        }
      }

      & small {
        font-size: var(--peels-footer-small-size, var(--peels-text-small));
      }
    }
  }

/* peels-form.webc */
form {
    display: grid;
    gap: var(--peels-gap-component);
  }

  /* en bloc : le texte du label et em[data-required] restent en ligne,
     tandis que les contrôles et notes (display: block) s'empilent dessous. */
  label {
    display: block;

    & > :where(input:not([type="checkbox"], [type="radio"]), select, textarea, progress, meter),
    & + :where(input:not([type="checkbox"], [type="radio"]), select, textarea, progress, meter) {
      margin-block-start: var(--peels-control-gap);
    }
  }

  /* Label d'un contrôle désactivé — texte estompé */
  label:has(> :is(:disabled, [aria-disabled="true"])) {
    color: var(--peels-text-muted);
    cursor: not-allowed;
  }

  /* ─── Boutons dans un formulaire ─── */
  form {
    & > [data-layout~="cluster"] {
      margin-block-start: var(--peels-gap-component);
    }
  }

/* peels-grid.webc */
[data-layout~="grid"] {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(var(--peels-grid-min, 15rem), 1fr));
    gap: var(--peels-grid-gap, var(--peels-gap-component));
  }

/* peels-header.webc */
/* ─── Header — mobile-first : panneau coulissant + burger par défaut ─── */
  /* Base = état mobile (conteneur étroit). Desktop = enhancement @container. */
  header:has(nav) {
    container-type: inline-size;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--peels-gap-component);
    padding-block: var(--peels-header-padding-block, var(--space-xs));
    padding-inline: var(--peels-header-padding-inline, var(--space-m));

    & > a {
      text-decoration: none;
      color: var(--peels-text-body);
    }

    /* ─── Toggle burger (état de base) ─── */
    & > [popovertarget] {
      display: flex;
      align-items: center;
      justify-content: center;
      width: var(--peels-header-toggle-size, 2.5rem);
      height: var(--peels-header-toggle-size, 2.5rem);
      background: transparent;
      border: none;
      cursor: pointer;
      padding: 0;
      color: var(--peels-text-body);

      & svg {
        width: var(--peels-header-toggle-size, 2.5rem);
        height: var(--peels-header-toggle-size, 2.5rem);

        & > path {
          fill: none;
          stroke: currentColor;
          stroke-width: 3;
          stroke-linecap: round;
          stroke-dashoffset: 0;
          transition: stroke-dasharray var(--peels-transition-duration-base) var(--peels-transition-easing),
                      stroke-dashoffset var(--peels-transition-duration-base) var(--peels-transition-easing);

          &:nth-child(1) { stroke-dasharray: 28 99; }
          &:nth-child(2) { stroke-dasharray: 28 28; }
          &:nth-child(3) { stroke-dasharray: 28 99; }
        }
      }
    }

    /* ─── Nav : panneau latéral coulissant depuis la gauche (état de base) ─── */
    & nav[popover] {
      --peels-header-direction: 1;

      flex-direction: column;
      align-items: stretch;
      gap: var(--peels-header-mobile-gap, var(--space-2xs));
      position: fixed;
      inset-block-start: 0;
      inset-inline-start: 0;
      /* Désarme le inset:0 du UA : sinon le côté end est ignoré
         et l'ancre suit la direction racine, pas celle du header. */
      inset-inline-end: auto;
      inline-size: min(var(--peels-header-menu-width, 20rem), 80vw);
      block-size: 100dvh;
      padding-block: var(--peels-header-menu-padding-block, var(--space-l));
      padding-inline: var(--peels-header-menu-padding-inline, var(--space-m));
      background: var(--peels-header-menu-bg, var(--peels-surface-panel));
      border: none;
      border-inline-end: var(--peels-header-menu-border, 1px solid var(--peels-border-subtle));
      overflow-y: auto;
      margin: 0;

      &:dir(rtl) {
        --peels-header-direction: -1;
      }

      transform: translateX(calc(-100% * var(--peels-header-direction)));
      opacity: 0;
      /* display/overlay maintiennent le panneau peint pendant la fermeture.
         Le ResizeObserver du script coupe les transitions au resize :
         sans lui, ce maintien flasherait au franchissement du breakpoint. */
      transition: transform var(--peels-transition-duration-base) var(--peels-transition-easing),
                  opacity var(--peels-transition-duration-base) var(--peels-transition-easing),
                  overlay var(--peels-transition-duration-base) allow-discrete,
                  display var(--peels-transition-duration-base) allow-discrete;

      &:popover-open {
        display: flex;
        transform: translateX(0);
        opacity: 1;
      }

      &::backdrop {
        background: var(--peels-header-backdrop, oklch(0 0 0 / 0.5));
        transition: background var(--peels-transition-duration-base) var(--peels-transition-easing);
      }

      & > menu {
        flex-direction: column;
      }

      /* Close button — simple X, fades in with the panel */
      & > [popovertargetaction="hide"] {
        position: absolute;
        inset-block-start: var(--peels-gap-sm);
        inset-inline-end: var(--peels-gap-sm);
        width: var(--peels-header-toggle-size, 2.5rem);
        height: var(--peels-header-toggle-size, 2.5rem);
        display: flex;
        align-items: center;
        justify-content: center;
        background: transparent;
        border: none;
        cursor: pointer;
        padding: 0;
        color: var(--peels-text-body);
        opacity: 0;
        transition: opacity var(--peels-transition-duration-base) var(--peels-transition-easing);

        & svg {
          width: 1.5rem;
          height: 1.5rem;

          & > path {
            fill: none;
            stroke: currentColor;
            stroke-width: 3;
            stroke-linecap: round;
          }
        }
      }

      &:popover-open > [popovertargetaction="hide"] {
        opacity: 1;
      }
    }

    @starting-style {
      & nav[popover]:popover-open {
        transform: translateX(calc(-100% * var(--peels-header-direction)));
        opacity: 0;
      }

      & nav[popover]::backdrop {
        background: transparent;
      }

      & nav[popover]:popover-open > [popovertargetaction="hide"] {
        opacity: 0;
      }
    }

    /* Burger SVG → X quand ouvert */
    &:has(nav[popover]:popover-open) > [popovertarget] {
      pointer-events: none;

      & svg > path {
        &:nth-child(1) { stroke-dasharray: 42 99; stroke-dashoffset: -64; }
        &:nth-child(2) { stroke-dasharray: 0 28; stroke-dashoffset: -14; }
        &:nth-child(3) { stroke-dasharray: 42 99; stroke-dashoffset: -64; }
      }
    }

    /* ─── Desktop : nav toujours visible, toggle caché ─── */
    @container (width >= 48rem) {
      & > [popovertarget] {
        display: none;
      }

      & nav[popover] {
        display: flex;
        align-items: center;
        gap: var(--peels-header-gap, var(--space-2xs));
        position: static;
        inset: auto;
        inline-size: auto;
        block-size: auto;
        margin: 0;
        padding: 0;
        border: none;
        background: transparent;
        border-radius: 0;
        max-inline-size: none;
        max-block-size: none;
        overflow: visible;
        transform: none;
        opacity: 1;
        transition: none;

        &::backdrop {
          display: none;
        }

        & > menu {
          flex-direction: row;
        }

        & > [popovertargetaction="hide"] {
          display: none;
        }
      }
    }
  }

/* peels-headings.webc */
:is(h1, h2, h3, h4, h5, h6) {
    font-family: var(--peels-font-heading);
    letter-spacing: var(--peels-headings-tracking, -0.02em);
    line-height: var(--peels-leading-fine);
    margin-block-start: var(--peels-headings-margin-block-start, var(--space-m));
    margin-block-end: var(--peels-headings-margin-block-end, var(--space-2xs));
  }

  h1,
  hgroup:has(h1) {
    color: var(--peels-headings-color-h1, var(--peels-headings-color));
    font-size: var(--peels-headings-size-h1, var(--size-step-4));
    font-weight: var(--peels-headings-weight-h1, 900);
  }
  h2,
  hgroup:has(h2) {
    color: var(--peels-headings-color-h2, var(--peels-headings-color));
    font-size: var(--peels-headings-size-h2, var(--size-step-3));
    font-weight: var(--peels-headings-weight-h2, 800);
  }
  h3,
  hgroup:has(h3) {
    color: var(--peels-headings-color-h3, var(--peels-headings-color));
    font-size: var(--peels-headings-size-h3, var(--size-step-2));
    font-weight: var(--peels-headings-weight-h3, 700);
  }
  h4,
  hgroup:has(h4) {
    color: var(--peels-headings-color-h4, var(--peels-headings-color));
    font-size: var(--peels-headings-size-h4, var(--size-step-1));
    font-weight: var(--peels-headings-weight-h4, 800);
  }
  h5 {
    color: var(--peels-headings-color-h5, var(--peels-headings-color));
    font-size: var(--peels-headings-size-h5, var(--size-step-1));
    font-weight: var(--peels-headings-weight-h5, 500);
  }
  h6 {
    color: var(--peels-headings-color-h6, var(--peels-headings-color));
    font-size: var(--peels-headings-size-h6, var(--size-step-0));
    font-weight: var(--peels-headings-weight-h6, 700);
  }


  :is(h1, h2, h3, h4, h5) + :is(h2, h3, h4, h5, h6) {
    margin-block-start: var(--peels-headings-adjacent-margin, var(--space-2xs));
  }

  :is(h1, h2, h3, h4, h5, h6):target {
    border-inline-start: var(--peels-focus-width) solid var(--peels-border-accent);
    padding-inline-start: var(--peels-headings-target-padding, var(--space-3xs));
  }

  /* ─── hgroup — titre + sous-titre sémantique ─── */
  hgroup {
    margin-block-start: var(--peels-headings-margin-block-start, var(--space-m));
    margin-block-end: var(--peels-headings-margin-block-end, var(--space-2xs));

    & > :is(h1, h2, h3, h4, h5, h6) {
      margin-block: 0;
    }

    & > p {
      margin-block: 0;
      margin-block-start: var(--peels-gap-sm);
      font-size: max(var(--peels-text-base), 0.6em);
      font-weight: var(--peels-headings-subtitle-weight, 400);
      color: var(--peels-text-muted);
    }
  }

/* peels-icon.webc */
/* ─── Démos du système (le mécanisme est dans le layer icons) ─── */

  /* Pack externe — Font Awesome : n'importe quel SVG en url() */
  [data-icon="github"] {
    --peels-icon: url("https://cdn.jsdelivr.net/npm/@fortawesome/fontawesome-free@6.5.2/svgs/brands/github.svg");
  }

  /* Hover contextuel (pattern de l'article) — pas d'attribut */
  button[data-icon="trash"]:hover {
    --peels-icon: var(--peels-icon-check, var(--peels-icon-svg-check, none));
  }

/* peels-iframe.webc */
iframe {
    aspect-ratio: var(--peels-iframe-ratio, 16 / 9);
    height: fit-content;
    inline-size: 100%;
    border: var(--peels-iframe-border, 0);
  }

/* peels-image.webc */
/* Reset + base média gèrent display:block, max-inline-size, block-size:auto,
     border-radius via --peels-media-radius. Pas de CSS spécifique nécessaire. */

/* peels-input.webc */
input:where(
    [type="text"], [type="email"], [type="tel"], [type="search"],
    [type="number"], [type="password"], [type="url"], [type="date"],
    [type="datetime-local"], [type="month"], [type="week"], [type="time"],
    [type="file"]
  ),
  textarea {
    display: block;
    width: 100%;
    min-block-size: var(--peels-input-min-block-size, var(--peels-control-min-height));
    padding-block: var(--peels-input-padding-block, var(--peels-control-padding-block, var(--space-2xs)));
    padding-inline: var(--peels-input-padding-inline, var(--peels-control-padding-inline, var(--space-s)));
    background-color: var(--peels-surface-page);
    border: var(--peels-input-border-width, var(--peels-border-width)) solid var(--peels-border-subtle);
    border-radius: var(--peels-component-radius);
    font: inherit;
    font-size: var(--peels-control-font-size);
    color: var(--peels-text-body);
    line-height: var(--peels-leading);
    transition: var(--peels-input-transition, border-color var(--peels-transition-duration-fast) var(--peels-transition-easing),
                box-shadow var(--peels-transition-duration-fast) var(--peels-transition-easing));

    &::placeholder {
      color: var(--peels-text-muted);
    }

    &:hover:not(:disabled, :focus-visible) {
      border-color: var(--peels-text-muted);
    }

    &:focus-visible {
      border-color: var(--peels-focus-ring);
      outline: none;
      box-shadow: 0 0 0 var(--peels-input-focus-outline-width, var(--peels-focus-width)) var(--peels-focus-ring);
    }

    &:focus:not(:focus-visible) {
      outline: none;
    }

    &:active {
      border-color: var(--peels-text-body);
    }

    &:disabled,
    &[aria-disabled="true"] {
      color: var(--peels-text-muted);
      background-color: var(--peels-surface-panel-soft);
      cursor: not-allowed;
    }

    &:read-only:not(:disabled) {
      background-color: var(--peels-surface-panel);
      color: var(--peels-text-muted);
      cursor: default;
    }

    &[aria-invalid="true"],
    &:user-invalid {
      border-color: var(--peels-accent-danger);

      &:focus-visible {
        box-shadow: 0 0 0 var(--peels-input-focus-outline-width, var(--peels-focus-width)) var(--peels-accent-danger);
      }
    }
  }

  

  /* Le textarea est l'exception : son minimum correspond à plusieurs lignes. */
  textarea {
    --peels-input-min-block-size:
      var(--peels-textarea-min-height, calc(var(--peels-leading, 1.6) * 4em));
    field-sizing: content;
    resize: vertical;
  }

  /* ─── Search — normalisation seule.
     Pas d'icône en background (décoratif) : le pattern recherche avec
     bouton loupe vit dans peels-search. On ne fait que neutraliser
     les décorations natives webkit pour un rendu identique aux autres inputs. ─── */
  input[type="search"] {
    appearance: none;

    &::-webkit-search-cancel-button,
    &::-webkit-search-results-button,
    &::-webkit-search-results-decoration {
      appearance: none;
    }
  }

  /* ─── File — bouton interne ::file-selector-button.
     Le champ hérite du bloc partagé ; seul le bouton interne est repeint. ─── */
  input[type="file"]::file-selector-button {
    appearance: none;
    min-block-size: var(--peels-control-min-height);
    padding: var(--peels-control-padding-block, var(--space-2xs)) var(--peels-control-padding-inline, var(--space-s));
    margin-inline-end: var(--peels-file-button-gap, var(--space-s));
    border: var(--peels-border-width) solid var(--peels-text-muted);
    border-radius: var(--peels-component-radius);
    background-color: transparent;
    color: var(--peels-text-body);
    font: inherit;
    font-size: calc(1em * var(--peels-btn-font-scale, 0.85));
    cursor: pointer;

    &:hover {
      background-color: var(--peels-surface-hover);
      border-color: var(--peels-text-body);
    }

    &:active {
      background-color: var(--peels-surface-active);
    }
  }

  input[type="file"]:disabled::file-selector-button {
    color: var(--peels-text-muted);
    border-color: var(--peels-border-subtle);
    cursor: not-allowed;
  }

  /* ─── Range — rendu natif avec accent Peels ─── */
  input[type="range"] {
    display: block;
    width: 100%;
    min-block-size: var(--peels-control-min-height);
    accent-color: var(--peels-color-highlight);
    cursor: pointer;

    &::-moz-range-track {
      block-size: var(--peels-range-track-height, 0.5rem);
      border: var(--peels-border-width) solid var(--peels-border-subtle);
      border-radius: var(--peels-range-track-radius, var(--radius-pill));
      background-color: var(--peels-range-track-bg, var(--peels-surface-panel-soft));
    }

    &::-moz-range-progress {
      block-size: var(--peels-range-track-height, 0.5rem);
      border-radius: var(--peels-range-track-radius, var(--radius-pill));
      border: var(
        --peels-range-gecko-progress-border,
        var(--peels-border-width) solid var(--peels-range-progress-bg, var(--peels-color-highlight))
      );
      background-color: var(--peels-range-progress-bg, var(--peels-color-highlight));
    }

    &::-moz-range-thumb {
      block-size: var(--peels-range-thumb-size, calc(var(--peels-range-track-height, 0.5rem) * 2));
      inline-size: var(--peels-range-thumb-size, calc(var(--peels-range-track-height, 0.5rem) * 2));
      background-color: var(--peels-range-thumb-bg, var(--peels-color-highlight));
      border: var(
        --peels-range-gecko-thumb-border,
        .125em solid var(--peels-surface-page)
      );
      border-radius: 50%;
      box-shadow: var(
        --peels-range-gecko-thumb-shadow,
        0 0 0 0.125em var(--peels-range-thumb-bg, var(--peels-color-highlight))
      );
    }

    &:hover::-moz-range-thumb {
      background-color: var(--peels-text-accent);
    }

    &:disabled::-moz-range-thumb {
      background-color: var(--peels-text-muted);
    }
  }

/* peels-link.webc */
/* ─── Contenu prose — exclut nav (géré par _base.css) ─── */
  :where(p, li, blockquote, figcaption, td, th, caption, dd, dt, address):not(nav *) a {
    color: var(--peels-link-color, var(--peels-text-link));
    text-decoration-thickness: var(--peels-link-decoration-thickness, 0.08em);
    text-underline-offset: var(--peels-link-underline-offset, 0.15em);
    text-decoration-skip-ink: auto;
    transition: color var(--peels-link-transition-duration, var(--peels-transition-duration-fast)) var(--peels-transition-easing),
                text-decoration-color var(--peels-link-transition-duration, var(--peels-transition-duration-fast)) var(--peels-transition-easing),
                text-decoration-style var(--peels-link-transition-duration, var(--peels-transition-duration-fast)) var(--peels-transition-easing);

    &:hover {
      color: var(--peels-link-color-hover, var(--peels-text-body));
      text-decoration-thickness: calc(var(--peels-link-decoration-thickness, 0.08em) * 2);
      text-decoration-style: var(--peels-link-hover-decoration-style, dotted);
    }

    &:visited {
      color: var(--peels-link-color-visited, var(--peels-text-muted));
    }

    &:active {
      color: var(--peels-link-color-active, var(--peels-text-body));
    }

    &[aria-current] {
      font-weight: var(--peels-font-weight-ui);
      text-decoration-thickness: var(--peels-link-current-decoration-thickness, 0.15em);
    }

    /* ─── Indicateur visuel : external / _blank — système d'icônes ─── */
    &:where([target="_blank"], [rel~="external"]) {
      --peels-icon-end: var(--peels-icon-external, var(--peels-icon-svg-external, none));
    }
  }

  /* ─── Titres cliquables ─── */
  :where(h1, h2, h3, h4, h5, h6) a {
    color: inherit;
    text-decoration: none;

    &:hover {
      color: var(--peels-link-color-hover, var(--peels-text-link-hover));
      text-decoration: underline;
      text-decoration-thickness: var(--peels-link-decoration-thickness, 0.08em);
      text-underline-offset: var(--peels-link-underline-offset, 0.15em);
    }
  }

  /* ─── Focus visible (commun prose + titres) ─── */
  :where(p, li, blockquote, figcaption, td, th, caption, dd, dt, address, h1, h2, h3, h4, h5, h6):not(nav *) a:focus-visible:not([href^="#"]) {
    background: var(--peels-link-focus-bg, color-mix(in srgb, currentcolor 15%, transparent));
    color: var(--peels-link-focus-color, var(--peels-text-body));
    outline: none;
  }

/* peels-list.webc */
/* ═══════════════════════════════════════════════════════════════
     LISTS — Unordered, ordered, and definition lists
     ═══════════════════════════════════════════════════════════════ */
  
  /* ─── Base list reset ─── */
  /* Exclut toutes les listes dans nav (gérées par _base.css nav socle).
     :not(nav *) couvre les listes imbriquées, pas seulement les enfants directs. */
  ol:not(nav *),
  ul:not(nav *) {
    padding-inline-start: var(--peels-list-padding-start, 1.5em);
    margin-block: var(--peels-list-margin-block, var(--peels-gap-prose));
  }

  /* ─── List items spacing ─── */
  ol:not(nav *) li + li,
  ul:not(nav *) li + li {
    margin-block-start: var(--peels-list-margin-block-start, var(--peels-list-item-gap, 0.25em));
  }

  /* ─── Unordered lists ─── */
  ul {
    list-style-type: var(--peels-list-bullet-style, disc);
  }

  /* ─── Ordered lists ─── */
  ol {
    list-style-type: var(--peels-list-number-style, decimal);
  }

  /* ─── Nested lists ─── */
  ol:not(nav *) ol,
  ol:not(nav *) ul,
  ul:not(nav *) ol,
  ul:not(nav *) ul {
    margin-block: var(--peels-list-nested-margin, 0.5em);
  }

  /* ─── Definition lists — défaut vertical (glossaire, FAQ) ─── */
  dl {
    margin-block: var(--peels-list-margin-block, var(--peels-gap-prose));
  }

  dt {
    font-weight: var(--peels-dt-weight, var(--peels-font-weight-ui));
    color: var(--peels-dt-color, var(--peels-text-body));
  }

  dd {
    margin-inline-start: var(--peels-dl-dd-indent, 1.5em);
    color: var(--peels-dd-color, var(--peels-text-muted));
  }

  dd + dt {
    margin-block-start: var(--peels-dl-pair-gap, 0.5em);
  }

  /* ─── Metadata — paires clé/valeur (key-value pairs) ─── */
  /* data-purpose~="metadata" décrit l'intent (pas la présentation).
     Mobile-first : empilé par défaut (dt au-dessus de dd), grille 2 colonnes
     activée quand le conteneur est assez large.
     @scope applique les règles sans pollution de spécificité.
     ponytail: @container dans @scope non supporté dans tous les navigateurs ;
     on utilise un @media minimal ici — le dl metadata est dans le flux
     principal, la largeur viewport reste un proxy acceptable. */
  @scope ([data-purpose~="metadata"]) {
    :scope {
      display: grid;
      gap: var(--peels-dl-row-gap, 0.25em) var(--peels-dl-column-gap, 1em);
    }

    dd {
      margin-inline-start: 0;
    }

    dd + dt {
      margin-block-start: 0;
    }

    @media (width >= 22rem) {
      :scope {
        grid-template-columns: var(--peels-dl-columns, auto 1fr);
      }
    }
  }

/* peels-login.webc */
/* ─── Pattern Login : contexte spécifique ─── */
  /* S'appuie sur les styles de Form, Input et Button */
  /* Le submit est accentué automatiquement par [type="submit"] */

/* peels-meter.webc */
meter {
    display: block;
    inline-size: 100%;
    block-size: var(--peels-meter-height, 0.65rem);
    appearance: none;
    border: var(--peels-border-width) solid var(--peels-border-subtle);
    border-radius: var(--peels-meter-radius, var(--radius-pill));
    background-color: var(--peels-meter-track-bg, var(--peels-surface-panel-soft));
    overflow: hidden;

    /* UA : display:grid + rows 1fr [line1] 2fr [line2] 1fr — la barre n'occupe
       que la moitié centrale. On garde la grille, une seule piste = 100%. */
    &::-webkit-meter-inner-element {
      block-size: 100%;
      grid-template-rows: [line1] 1fr [line2];
    }

    &::-webkit-meter-bar {
      block-size: 100%;
      background: var(--peels-meter-track-bg, var(--peels-surface-panel-soft));
      border: none;
      border-radius: var(--peels-meter-radius, var(--radius-pill));
    }

    /* background en shorthand : background-color seul laisse le dégradé UA. */
    &::-webkit-meter-optimum-value {
      background: var(--peels-meter-fill, var(--peels-color-highlight));
      border-radius: var(--peels-meter-radius, var(--radius-pill));
      transition: inline-size var(--peels-transition-duration-base) var(--peels-transition-easing);
    }

    &::-webkit-meter-suboptimum-value {
      background: var(--peels-meter-suboptimum-fill, var(--peels-accent-warning));
      border-radius: var(--peels-meter-radius, var(--radius-pill));
      transition: inline-size var(--peels-transition-duration-base) var(--peels-transition-easing);
    }

    &::-webkit-meter-even-less-good-value {
      background: var(--peels-meter-critical-fill, var(--peels-accent-danger));
      border-radius: var(--peels-meter-radius, var(--radius-pill));
      transition: inline-size var(--peels-transition-duration-base) var(--peels-transition-easing);
    }

    &::-moz-meter-bar {
      border-radius: var(--peels-meter-radius, var(--radius-pill));
      transition: inline-size var(--peels-transition-duration-base) var(--peels-transition-easing);
    }

    &:-moz-meter-optimum::-moz-meter-bar {
      background: var(--peels-meter-fill, var(--peels-color-highlight));
    }

    &:-moz-meter-sub-optimum::-moz-meter-bar {
      background: var(--peels-meter-suboptimum-fill, var(--peels-accent-warning));
    }

    &:-moz-meter-sub-sub-optimum::-moz-meter-bar {
      background: var(--peels-meter-critical-fill, var(--peels-accent-danger));
    }

    @media (forced-colors: active) {
      appearance: auto;
    }
  }

/* peels-nav.webc */
/* ─── Nav — layout horizontal de base ─── */
  nav :where(menu) {
    display: flex;
    align-items: var(--peels-nav-align, center);
    flex-wrap: wrap;
    gap: var(--peels-nav-gap, var(--peels-gap-component));
  }

  /* ─── Nav — plusieurs groupes (gauche/droite) ─── */
  /* nav devient flex pour que margin-inline-start: auto fonctionne.
     Cible structurellement les navs avec 2+ enfants directs.
     aside nav (sidenav, tree-nav) est vertical — exclu par contexte parent. */
  nav:has(> :nth-child(2)):not(aside nav):not([popover]) {
    display: flex;
    align-items: center;
    flex-wrap: wrap;
    gap: var(--peels-nav-gap, var(--peels-gap-component));
  }

  /* ─── Nav — débordement optionnel : data-overflow ─── */
  /* Une seule liste : le clip d'une ligne cache les items enroulés ; le
     bouton (dernier li) ancré au bas du menu descend dans la zone visible
     dès qu'un item s'enroule. Le popover vide porte l'état open/closed :
     aria-expanded natif, light-dismiss gratuit. Ouvert : on lève le clip,
     les lignes enroulées s'affichent dans le flux (accordéon) — rien de
     plus. shortcut: 1lh suppose que la ligne fait la hauteur de ligne du
     nav ; si les items sont plus hauts, ajuster
     --peels-nav-overflow-line (ex. calc(1lh + 0.5em)). */
  /* --_line est enregistrée en <length> : 1lh se calcule sur le nav et les
     descendants (bouton) héritent de la longueur, pas de leur propre lh. */
  @property --_line {
    syntax: "<length>";
    inherits: true;
    initial-value: 0px;
  }

  nav[data-overflow] {
    --_line: var(--peels-nav-overflow-line, 1lh);
    --_pad: var(--peels-nav-padding-block, var(--space-xs));
    /* Le bouton doit rester plus bas qu'une ligne pour tenir dans le clip
       — --peels-btn-min-height (44px cible AAA) réduit au plancher
       WCAG 2.5.8 AA, posé sur le contexte et hérité par le bouton. */
    --peels-btn-min-height: var(
      --peels-nav-overflow-btn-min-height,
      calc(var(--_line) - 0.35em)
    );

    /* inline-size: 100% — dans un contexte flex/inline la nav prend toute
       la largeur (sinon elle se rétrécit aux items et le bouton recouvre
       le dernier au lieu de se caler au bord droit). */
    inline-size: 100%;
    position: relative;
    /* Padding de barre comme le header (xs bloc / m inline). */
    padding-block: var(--_pad);
    padding-inline: var(--peels-nav-padding-inline, var(--space-m));
    overflow: clip;
    /* Le clip montre exactement une ligne : padding + ligne + padding. */
    max-block-size: calc(var(--_line) + var(--_pad) * 2);

    & menu {
      position: relative;
    }

    /* display: contents — le li disparaît de la boîte, le bouton s'ancre
       directement au menu (sinon la boîte du li, plus haute que le bouton,
       le décale au-dessus du clip). */
    & menu > li:has(> [popovertarget]) {
      display: contents;
    }

    & [popovertarget] {
      position: absolute;
      /* + --_pad : la ligne démarre après le padding du nav — sans lui le
         bouton resterait visible dans le clip même quand tout tient. */
      inset-block-end: max(
        calc(var(--_line) + var(--_pad)),
        calc(100% - var(--_line))
      );
      inset-inline-end: 0;
      /* Le bouton reste au-dessus des items qui glissent sous lui, avec un
         fond opaque pour qu'ils ne transparaissent pas sous son texte. */
      z-index: var(--peels-nav-overflow-btn-z, 1);
      border: none;
      background: var(--peels-nav-overflow-btn-bg, var(--peels-surface-panel));
      /* translateY recentre le bouton sur la ligne : sans lui son bord bas
         épouse le bas du clip alors que les items sont centrés. */
      translate: 0 calc(50% - var(--_line) / 2);
      font-size: var(--peels-nav-overflow-btn-size, 0.7em);
      line-height: var(--peels-nav-overflow-btn-line-height, 1.25);
      padding-block: 0;
    }

    /* État pur — le popover ne rend rien. */
    & [popover] {
      block-size: 0;
      border: none;
      padding: 0;
      margin: 0;
      overflow: clip;
    }

    /* Ouvert : on lève le clip — les lignes enroulées s'affichent dans le
       flux (accordéon). Le bouton reste ancré sur la première ligne. */
    &:has([popover]:popover-open) {
      max-block-size: none;
    }
  }

  /* La règle de groupement laisse la nav enrouler ses enfants ; avec
     data-overflow, marque et menu doivent rester sur la ligne — c'est le
     menu qui gère le débordement de ses items, pas la nav. Le menu est
     aligné en haut (start, pas center) : le clip doit montrer sa première
     ligne, pas son milieu. */
  nav[data-overflow]:not(aside nav) {
    flex-wrap: nowrap;
    align-items: start;
  }

/* peels-notification-bar.webc */
[data-component="notification-bar"] {
    position: sticky;
    inset-block-start: 0;
    z-index: var(--peels-z-top);
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: var(--peels-notification-gap, var(--peels-gap-sm));
    padding-block: var(--peels-notification-padding-block, var(--peels-gap-sm));
    padding-inline: var(--peels-notification-padding-inline, var(--peels-gap-component));
    background-color: var(--peels-notification-bg, var(--peels-surface-panel));
    color: var(--peels-notification-color, var(--peels-text-body));
    border-block-end: var(--peels-notification-border, 1px solid var(--peels-border-subtle));
    font-size: var(--peels-notification-size, var(--peels-text-small));

    & p {
      margin: 0;
    }

    & button {
      flex-shrink: 0;
      padding: var(--peels-notification-btn-padding, 0.25em 0.5em);
      background: none;
      border: none;
      color: inherit;
      cursor: pointer;
      font-size: inherit;
      line-height: 1;

      &:hover {
        opacity: 0.7;
      }
    }

    &[data-intent="info"] {
      background-color: var(--peels-notification-info-bg, oklch(from var(--peels-accent-info) l c h / 0.12));
      border-color: var(--peels-notification-info-border, var(--peels-accent-info));
    }

    &[data-intent="success"] {
      background-color: var(--peels-notification-success-bg, oklch(from var(--peels-accent-success) l c h / 0.12));
      border-color: var(--peels-notification-success-border, var(--peels-accent-success));
    }

    &[data-intent="warning"] {
      background-color: var(--peels-notification-warning-bg, oklch(from var(--peels-accent-warning) l c h / 0.12));
      border-color: var(--peels-notification-warning-border, var(--peels-accent-warning));
    }

    &[data-intent="danger"] {
      background-color: var(--peels-notification-danger-bg, oklch(from var(--peels-accent-danger) l c h / 0.12));
      border-color: var(--peels-notification-danger-border, var(--peels-accent-danger));
    }
  }

/* peels-pagination.webc */
/* ─── Pagination — nav > ul (liste de liens) ─── */
  nav:has(> ul) {
    & > ul {
      display: flex;
      flex-wrap: wrap;
      align-items: center;
      justify-content: var(--peels-pagination-justify, center);
      gap: var(--peels-pagination-gap, 0.25em);
      list-style: none;
      margin: 0;
      padding: 0;

      /* ─── Tous les liens — texte simple, pas de boîte ─── */
      & > li > a {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        min-inline-size: var(--peels-pagination-min-size, 1.5em);
        min-block-size: var(--peels-pagination-min-size, 1.5em);
        padding: var(--peels-pagination-padding, 0.15em 0.35em);
        text-decoration: none;
        color: var(--peels-text-body);
        transition: color var(--peels-transition-duration-fast) var(--peels-transition-easing);

        &:hover {
          color: var(--peels-pagination-link-color-hover, var(--peels-text-accent));
          text-decoration: underline;
          text-underline-offset: var(--peels-pagination-underline-offset, 0.2em);
        }

        &:active { color: var(--peels-text-accent); }

        &:focus-visible {
          outline-color: var(--peels-focus-color, currentColor);
          outline-offset: var(--peels-focus-offset, 0.15em);
          outline-style: var(--peels-focus-style, solid);
          outline-width: var(--peels-focus-width, 2px);
          border-radius: var(--peels-focus-radius, 1px);
        }

        &[aria-current] {
          color: var(--peels-pagination-current-color, var(--peels-text-accent));
          font-weight: var(--peels-pagination-current-weight, var(--peels-font-weight-ui));
        }

        &[aria-disabled="true"] {
          opacity: var(--peels-btn-disabled-opacity, 0.5);
          pointer-events: none;
        }
      }

      /* ─── Prev/Next — repérés par rel, chevron dessiné en mask ─── */
      /* Le lien peut rester vide : aria-label porte le nom, le chevron est
         décoratif. En RTL les glyphes sont échangés (miroir directionnel). */
      & > li > a[rel="prev"],
      & > li > a[rel="next"] {
        color: var(--peels-text-muted);

        &:hover {
          color: var(--peels-pagination-prevnext-color-hover, var(--peels-text-accent));
        }
      }

      & > li > a[rel="prev"]::before,
      & > li > a[rel="next"]::after {
        content: "";
        inline-size: var(--peels-pagination-chevron-size, 0.85em);
        block-size: var(--peels-pagination-chevron-size, 0.85em);
        background-color: currentColor;
        mask: var(--peels-pagination-chevron-glyph, none) no-repeat center / contain;
      }

      & > li > a[rel="prev"] { --peels-pagination-chevron-glyph: var(--peels-icon-svg-chevron-left, none); }
      & > li > a[rel="next"] { --peels-pagination-chevron-glyph: var(--peels-icon-svg-chevron-right, none); }
      & > li > a[rel="prev"]:dir(rtl) { --peels-pagination-chevron-glyph: var(--peels-icon-svg-chevron-right, none); }
      & > li > a[rel="next"]:dir(rtl) { --peels-pagination-chevron-glyph: var(--peels-icon-svg-chevron-left, none); }

      /* ─── Ellipses (…) ─── */
      & > li > span {
        color: var(--peels-text-muted);
      }
    }
  }

  /* ─── Pager autonome — nav ne contenant que des liens rel (sans liste) ─── */
  /* Cas réel : footer de la démo — nav > a[rel="prev"] + a[rel="next"].
     Grille auto-fit : deux moitiés, ou pleine ligne s'il n'y a qu'un lien. */
  nav:has(> a[rel]):not(:has(> :not(a[rel]))) {
    display: grid;
    grid-template-columns: repeat(auto-fit, minmax(var(--peels-pagination-pager-min, 15rem), 1fr));
    container-type: inline-size;

    & > a {
      display: flex;
      flex-direction: column;
      gap: var(--peels-pagination-pager-gap, 0.15em);
      padding: var(--peels-pagination-pager-padding, var(--peels-space-s, 0.75em) var(--peels-space-m, 1.25em));
      text-decoration: none;
      transition: background-color var(--peels-transition-duration-fast) var(--peels-transition-easing);

      /* Premier enfant = étiquette (« Précédent »/« Suivant »), dernier = titre */
      & > :first-child {
        font-size: var(--peels-text-small);
        color: var(--peels-text-muted);
      }

      & > :last-child {
        font-weight: var(--peels-font-weight-ui);
        color: var(--peels-text-body);
        transition: color var(--peels-transition-duration-fast) var(--peels-transition-easing);
      }

      &:hover {
        background-color: var(--peels-pagination-link-bg-hover, var(--peels-surface-hover));

        & > :last-child {
          color: var(--peels-text-accent);
        }
      }

      &:focus-visible {
        outline-color: var(--peels-focus-color, currentColor);
        outline-offset: var(--peels-focus-offset, 0.15em);
        outline-style: var(--peels-focus-style, solid);
        outline-width: var(--peels-focus-width, 2px);
        border-radius: var(--peels-focus-radius, 1px);
      }
    }

    & > a[rel="next"] {
      text-align: end;
    }

    /* Séparateur entre les deux moitiés — vertical côte à côte… */
    & > a + a {
      border-inline-start: var(--peels-border-width) solid var(--peels-border-subtle);
    }

    /* …horizontal quand les boîtes s'empilent (conteneur étroit). */
    @container (width < 30rem) {
      & > a + a {
        border-inline-start: none;
        border-block-start: var(--peels-border-width) solid var(--peels-border-subtle);
      }
    }
  }

/* peels-picto.webc */
[data-component="picto"] {
    display: flex;
    gap: var(--peels-picto-gap, var(--peels-gap-sm));
    align-items: flex-start;
    margin-block: var(--peels-picto-margin-block, var(--peels-gap-component));

    & svg {
      flex-shrink: 0;
      inline-size: var(--peels-picto-icon-size, 2rem);
      block-size: var(--peels-picto-icon-size, 2rem);
      color: var(--peels-picto-icon-color, var(--peels-text-accent));
    }

    & figcaption {
      display: flex;
      flex-direction: column;
      gap: var(--peels-picto-text-gap, 0.25em);

      & strong {
        font-weight: var(--peels-picto-title-weight, var(--peels-font-weight-ui));
        color: var(--peels-picto-title-color, var(--peels-text-body));
      }

      & span {
        color: var(--peels-picto-desc-color, var(--peels-text-muted));
        font-size: var(--peels-picto-desc-size, var(--peels-text-small));
      }
    }

    &[data-layout="center"] {
      flex-direction: column;
      align-items: center;
      text-align: center;
    }
  }

/* peels-picture.webc */
/* Reset gère display:block, max-inline-size, block-size:auto pour picture et img.
     Pas de CSS spécifique nécessaire. */

/* peels-progress.webc */
progress {
    display: block;
    inline-size: 100%;
    block-size: var(--peels-progress-height, 0.65rem);
    appearance: none;
    border: var(--peels-border-width) solid var(--peels-border-subtle);
    border-radius: var(--peels-progress-radius, var(--radius-pill));
    background-color: var(--peels-progress-track-bg, var(--peels-surface-panel-soft));
    overflow: hidden;

    &::-webkit-progress-bar {
      background-color: var(--peels-progress-track-bg, var(--peels-surface-panel-soft));
      border-radius: var(--peels-progress-radius, var(--radius-pill));
    }

    &::-webkit-progress-value {
      background-color: var(--peels-progress-fill, var(--peels-focus-ring));
      border-radius: var(--peels-progress-radius, var(--radius-pill));
      transition: inline-size var(--peels-transition-duration-base) var(--peels-transition-easing);
    }

    &::-moz-progress-bar {
      background-color: var(--peels-progress-fill, var(--peels-focus-ring));
      border-radius: var(--peels-progress-radius, var(--radius-pill));
    }

    /* État complété (100 %) */
    &:is([value="1"]:not([max]), [value="100"][max="100"])::-webkit-progress-value {
      background-color: var(--peels-progress-complete-fill, var(--peels-accent-success));
    }

    &:is([value="1"]:not([max]), [value="100"][max="100"])::-moz-progress-bar {
      background-color: var(--peels-progress-complete-fill, var(--peels-accent-success));
    }

    /* État indéterminé : segment franc en aller-retour (pattern Adam Argyle) */
    &:indeterminate::-webkit-progress-bar {
      background-image: linear-gradient(
        to right,
        var(--peels-progress-track-bg, var(--peels-surface-panel-soft)) 42%,
        var(--peels-progress-fill, var(--peels-focus-ring)) 0%,
        var(--peels-progress-fill, var(--peels-focus-ring)) 58%,
        var(--peels-progress-track-bg, var(--peels-surface-panel-soft)) 0%
      );
      background-size: 225% 100%;
      background-position: right;
      animation: peels-progress-indeterminate 1.8s infinite ease-in-out;
    }

    &:indeterminate::-moz-progress-bar {
      background-color: transparent;
      background-image: linear-gradient(
        to right,
        var(--peels-progress-track-bg, var(--peels-surface-panel-soft)) 42%,
        var(--peels-progress-fill, var(--peels-focus-ring)) 0%,
        var(--peels-progress-fill, var(--peels-focus-ring)) 58%,
        var(--peels-progress-track-bg, var(--peels-surface-panel-soft)) 0%
      );
      background-size: 225% 100%;
      background-position: right;
      animation: peels-progress-indeterminate 1.8s infinite ease-in-out;
    }

    @media (prefers-reduced-motion: reduce) {
      &:indeterminate::-webkit-progress-bar,
      &:indeterminate::-moz-progress-bar {
        animation: none;
        background-position: center;
      }
    }

    @media (forced-colors: active) {
      appearance: auto;
    }
  }

  @keyframes peels-progress-indeterminate {
    50% { background-position: left; }
  }

/* peels-push-down.webc */
/* ─── Panneau push-down ─── */
  /* En flow normal — pousse le contenu vers le bas.
     Animation grid-rows 0fr → 1fr (même technique que nav-category). */

  [data-push-down] {
    display: grid;
    grid-template-rows: 0fr;
    transition: grid-template-rows var(--peels-push-down-transition, 0.35s ease);

    & > * {
      overflow: hidden;
    }

    &[data-open] {
      grid-template-rows: 1fr;
    }

    /* Progressive enhancement : interpolate-size */
    @supports (interpolate-size: allow-keywords) {
      & {
        interpolate-size: allow-keywords;
        display: block;
        height: 0;
        overflow: hidden;
        transition: height var(--peels-push-down-transition, 0.35s ease);
      }

      &[data-open] {
        height: auto;
      }

      & > * {
        overflow: revert;
      }
    }
  }

/* peels-ruby.webc */
ruby {
    ruby-align: var(--peels-ruby-align, space-around);
  }

  rt {
    font-size: var(--peels-ruby-rt-size, 0.6em);
    color: var(--peels-ruby-rt-color, var(--peels-text-muted));
    line-height: var(--peels-line-height-flat);
  }

/* peels-search.webc */
search > form,
  form[role="search"] {
    display: flex;
    gap: var(--peels-gap-sm, 0.5em);
    align-items: center;

    & input[type="search"] {
      flex: 1;

      &:hover { border-color: var(--peels-border-strong); }
      &:focus-visible { outline: var(--peels-focus-width, 2px) var(--peels-focus-style, solid) var(--peels-focus-color, currentColor); }
      &:active { border-color: var(--peels-text-body); }
      &:disabled { opacity: var(--peels-disabled-opacity, 0.5); }
    }

    & button {
      flex-shrink: 0;
    }

    /* Bouton submit dans recherche : accent automatique via [type="submit"] */
  }

/* peels-select.webc */
select {
    display: block;
    width: 100%;
    padding-block: var(--peels-input-padding-block, var(--peels-control-padding-block, var(--space-2xs)));
    padding-inline: var(--peels-input-padding-inline, var(--peels-control-padding-inline, var(--space-s)));
    min-block-size: var(--peels-control-min-height);
    background-color: var(--peels-surface-page);
    border: var(--peels-input-border-width, var(--peels-border-width)) solid var(--peels-border-subtle);
    border-radius: var(--peels-component-radius);
    font: inherit;
    font-size: var(--peels-control-font-size);
    color: var(--peels-text-body);
    line-height: var(--peels-leading);
    cursor: pointer;
    transition: var(--peels-input-transition, border-color var(--peels-transition-duration-fast) var(--peels-transition-easing),
                box-shadow var(--peels-transition-duration-fast) var(--peels-transition-easing));

    &:not([multiple], [size]) {
      appearance: none;
      padding-inline-end: var(--peels-select-padding-end, 2.5em);
      background-image: var(--peels-select-chevron, var(--peels-icon-svg-chevron-canvas, none));
      background-repeat: no-repeat;
      background-position: right var(--peels-control-padding-inline, 1em) center;

      &:dir(rtl) {
        background-position: left var(--peels-control-padding-inline, 1em) center;
      }

      &:has(> option[value=""]:first-child:checked) {
        color: var(--peels-text-muted);
      }

      @supports (appearance: base-select) {
        &,
        &::picker(select) {
          appearance: base-select;
        }

        align-items: center;

        &::picker-icon {
          display: none;
        }

        &::picker(select) {
          margin-block-start: var(--peels-select-picker-offset, 0.25rem);
          padding-block: var(--peels-select-multiple-padding-block, var(--space-3xs));
          padding-inline: 0;
          background-color: var(--peels-surface-page);
          color: var(--peels-text-body);
          border: var(--peels-border-width) solid var(--peels-border-subtle);
          border-radius: var(--peels-component-radius);
          box-shadow: var(--peels-elevation-2);
          font: inherit;
          font-size: var(--peels-control-font-size);
        }

        & option {
          padding: var(--peels-select-option-padding, var(--space-3xs) var(--peels-control-padding-inline, var(--space-s)));
          gap: var(--peels-control-gap);

          &:hover,
          &:focus-visible {
            background-color: color-mix(in oklch, var(--peels-surface-hover), var(--peels-text-body) 8%);
            outline: none;
          }

          &:checked {
            background-color: color-mix(in oklch, var(--peels-surface-hover), var(--peels-text-body) 12%);
            color: var(--peels-text-body);
            font-weight: var(--peels-font-weight-ui);
          }

          &::checkmark {
            color: var(--peels-color-highlight);
            font-weight: var(--peels-font-weight-ui);
          }
        }
      }

      @media (forced-colors: active) {
        appearance: auto;
        background-image: none;
        padding-inline-end: var(--peels-input-padding-inline, var(--peels-control-padding-inline, var(--space-s)));
      }
    }

    &:is([multiple], [size]) {
      inline-size: var(--peels-select-multiple-width, fit-content);
      min-inline-size: var(--peels-select-multiple-min-width, 14rem);
      max-inline-size: 100%;
      padding-block: var(--peels-select-multiple-padding-block, var(--space-3xs));
      padding-inline: 0;
      overflow-y: auto;

      & option {
        padding: var(--peels-select-option-padding, var(--space-3xs) var(--peels-control-padding-inline, var(--space-s)));

        &:hover {
          background-color: color-mix(in oklch, var(--peels-surface-hover), var(--peels-text-body) 8%);
        }

        &:checked {
          background: linear-gradient(
            0deg,
            color-mix(in oklch, var(--peels-surface-hover), var(--peels-text-body) 12%),
            color-mix(in oklch, var(--peels-surface-hover), var(--peels-text-body) 12%)
          );
          color: var(--peels-text-body);
          font-weight: var(--peels-font-weight-ui);
        }
      }
    }

    &:hover:not(:disabled, :focus-visible) {
      border-color: var(--peels-text-muted);
    }

    &:active:not(:disabled) {
      border-color: var(--peels-text-body);
    }

    &:focus-visible {
      border-color: var(--peels-focus-ring);
      outline: none;
      box-shadow: 0 0 0 var(--peels-input-focus-outline-width, var(--peels-focus-width)) var(--peels-focus-ring);
    }

    &:focus:not(:focus-visible) {
      outline: none;
    }

    &[aria-invalid="true"],
    &:user-invalid {
      border-color: var(--peels-accent-danger);

      &:focus-visible {
        box-shadow: 0 0 0 var(--peels-input-focus-outline-width, var(--peels-focus-width)) var(--peels-accent-danger);
      }
    }

    &:disabled {
      color: var(--peels-text-muted);
      background-color: var(--peels-surface-panel-soft);
      border-color: var(--peels-border-subtle);
      cursor: not-allowed;
    }
  }

/* peels-sidebar.webc */
/* ─── Sidebar — conteneur latéral réutilisable ───
     Fournit les variables de personnalisation.
     Le layout (grid, colonnes, sticky, scroll) est à la charge du consommateur. */

  [data-layout~="sidebar"], [data-sidebar] {
    --peels-sidebar-width: 15rem;
    --peels-sidebar-min: 16rem;
    --peels-sidebar-max: clamp(18rem, 24vw, 22rem);
    --peels-sidebar-offset: 0;
    --peels-sidebar-footer-offset: 0;
  }

/* peels-sidenav.webc */
/* ─── Sidenav — liste verticale ─── */
  aside nav {
    --peels-nav-align: stretch;
    display: flex;
    flex-direction: column;

    & :where(menu, ul, ol) {
      display: flex;
      flex-direction: column;
      gap: var(--peels-sidenav-item-gap, 0);
      padding-block: var(--peels-sidenav-padding-block, var(--space-2xs));

      & a {
        display: block;
        padding-block: var(--peels-sidenav-link-padding-block, var(--space-3xs));
        padding-inline: var(--peels-sidenav-link-padding-inline, var(--space-m));
        font-size: var(--peels-sidenav-link-size, var(--peels-text-small));
        color: var(--peels-sidenav-link-color, var(--peels-text-muted));
        text-decoration: none;
        transition: background-color var(--peels-transition-duration-fast) var(--peels-transition-easing),
                    color var(--peels-transition-duration-fast) var(--peels-transition-easing);

        &:hover {
          color: var(--peels-sidenav-link-color-hover, var(--peels-text-body));
          background-color: var(--peels-sidenav-link-bg-hover, var(--peels-surface-hover));
          text-decoration: none;
        }

        &:focus-visible {
          color: var(--peels-sidenav-link-color-hover, var(--peels-text-body));
          text-decoration: none;
        }

        &:active {
          color: var(--peels-sidenav-link-color-current, var(--peels-text-body));
        }

        &[aria-current] {
          color: var(--peels-sidenav-link-color-current, var(--peels-text-body));
          background-color: var(--peels-sidenav-link-bg-current, var(--peels-surface-panel));
          font-weight: inherit;
        }
      }

      & strong {
        font-size: var(--peels-text-small);
        font-weight: var(--peels-font-weight-heading);
        color: var(--peels-text-muted);
        padding-block: var(--peels-sidenav-link-padding-block, var(--space-3xs));
        padding-inline: var(--peels-sidenav-link-padding-inline, var(--space-m));
      }
    }
  }

/* peels-spinner.webc */
:where([aria-busy="true"]):not(button, [role="button"]) {
    position: relative;
    color: var(--peels-text-muted);

    &::before {
      content: "";
      display: inline-block;
      width: var(--peels-spinner-size, 1em);
      height: var(--peels-spinner-size, 1em);
      margin-inline-end: var(--peels-spinner-gap, 0.5em);
      border: var(--peels-spinner-border-width, 2px) solid var(--peels-border-subtle);
      border-block-start-color: var(--peels-color-highlight);
      border-radius: 50%;
      vertical-align: middle;
      animation: peels-spin var(--peels-spinner-animation-duration, 0.6s) linear infinite;
    }
  }

  @keyframes peels-spin {
    to { rotate: 360deg; }
  }

/* peels-spotlight.webc */
[data-component="spotlight"] {
    position: relative;
    padding-block: var(--peels-spotlight-padding-block, var(--peels-gap-component));
    padding-inline: var(--peels-spotlight-padding-inline, var(--peels-gap-component));
    background-color: var(--peels-spotlight-bg, var(--peels-surface-panel));
    color: var(--peels-spotlight-color, var(--peels-text-body));
    margin-block: var(--peels-spotlight-margin-block, var(--peels-gap-component));
    overflow: hidden;

    &::before {
      content: "";
      position: absolute;
      inset-inline-start: 0;
      inset-block-start: 0;
      inset-block-end: 0;
      inline-size: var(--peels-spotlight-bar-width, 4px);
      background-color: var(--peels-spotlight-bar-color, var(--peels-text-accent));
    }

    & p:first-child {
      margin-block-start: 0;
    }

    & p:last-child {
      margin-block-end: 0;
    }
  }

/* peels-stack.webc */
[data-layout~="stack"] {
    display: flex;
    flex-direction: column;
    gap: var(--peels-stack-gap, var(--peels-gap-component));
  }

/* peels-switch.webc */
label:has(> input[role="switch"]) {
    display: grid;
    grid-template-columns: auto minmax(0, 1fr);
    align-items: start;
    gap: var(--peels-control-gap);
    line-height: var(--peels-choice-leading, var(--peels-leading));
    font-weight: var(--peels-choice-weight, normal);
    cursor: pointer;

    & > input[role="switch"] {
      line-height: inherit;
      margin-block-start: calc((1lh - round(var(--peels-switch-height, 1.25em), 2px)) / 2);
    }
  }

  input[role="switch"] {
    --peels-switch-direction: 1;

    appearance: none;
    margin: 0;
    box-sizing: content-box;
    display: inline-grid;
    align-items: center;
    grid: [track] 1fr / [track] 1fr;
    inline-size: calc(round(var(--peels-switch-height, 1.25em), 2px) * 1.75);
    block-size: round(var(--peels-switch-height, 1.25em), 2px);
    padding: 2px;
    font: inherit;
    font-size: var(--peels-control-font-size);
    color: var(--peels-color-highlight);
    background-color: var(--peels-surface-panel-soft);
    border: var(--peels-border-width) solid var(--peels-text-muted);
    border-radius: var(--peels-switch-radius, var(--radius-pill));
    vertical-align: middle;
    cursor: pointer;
    transition:
      background-color var(--peels-transition-duration-fast) var(--peels-transition-easing),
      border-color var(--peels-transition-duration-fast) var(--peels-transition-easing);

    &:dir(rtl) {
      --peels-switch-direction: -1;
    }

    &::before {
      content: "";
      grid-area: track;
      inline-size: round(var(--peels-switch-height, 1.25em), 2px);
      block-size: round(var(--peels-switch-height, 1.25em), 2px);
      border-radius: 50%;
      background-color: var(--peels-text-muted);
      transition:
        translate var(--peels-transition-duration-fast) var(--peels-transition-easing),
        background-color var(--peels-transition-duration-fast) var(--peels-transition-easing),
        transform var(--peels-transition-duration-fast) var(--peels-transition-easing);
    }

    &:hover:not(:disabled) {
      border-color: var(--peels-text-body);

      &::before {
        background-color: var(--peels-text-body);
      }
    }

    &:focus-visible {
      outline: var(--peels-focus-width) solid var(--peels-focus-ring);
      outline-offset: var(--peels-focus-offset);
    }

    &:active:not(:disabled)::before {
      transform: scale(0.9);
    }

    &:checked {
      background-color: currentColor;
      border-color: currentColor;

      &::before {
        background-color: var(--peels-surface-page);
        translate: calc(75% * var(--peels-switch-direction)) 0;
      }

      &:hover:not(:disabled) {
        color: var(--peels-text-accent);
        border-color: currentColor;

        &::before {
          background-color: var(--peels-surface-page);
        }
      }
    }

    &:disabled {
      opacity: var(--peels-disabled-opacity);
      cursor: not-allowed;
    }

    @media (forced-colors: active) {
      appearance: auto;
      padding: 0;
      inline-size: round(var(--peels-switch-height, 1.25em), 2px);

      &::before {
        display: none;
      }
    }
  }

/* peels-switcher.webc */
[data-layout~="switcher"] {
    display: flex;
    flex-wrap: wrap;
    gap: var(--peels-switcher-gap, var(--peels-gap-component));

    & > * {
      flex-grow: 1;
      flex-basis: calc((var(--peels-switcher-threshold, 30rem) - 100%) * 999);
    }
  }

/* peels-table.webc */
table {
    width: 100%;
    border-collapse: collapse;
    font-variant-numeric: tabular-nums;
    font-size: var(--peels-table-text-size, var(--peels-text-xsmall));
  }

  caption {
    font-size: var(--peels-text-small);
    color: var(--peels-text-muted);
    caption-side: var(--peels-table-caption-side, bottom);
    padding-block-start: var(--peels-table-caption-padding-block, var(--space-xs));
  }

  th, td {
    padding: var(--peels-table-padding, var(--space-2xs) var(--space-xs));
    text-align: start;
    border-block-end: var(--peels-border-width) solid var(--peels-border-subtle);
  }

  th {
    font-weight: var(--peels-font-weight-ui);
  }

  /* ─── data-numeric — alignement numérique (cellules sommables) ─── */
  [data-numeric] {
    text-align: end;
    font-variant-numeric: tabular-nums;
  }

  thead {
    background-color: var(--peels-table-header-bg, transparent);

    & th {
      border-block-end-width: var(--peels-table-header-border-width, 2px);
      border-block-end-color: var(--peels-table-header-border-color, var(--peels-text-body));
    }
  }

  /* ─── Zebra — basculable (transparent si non défini par le thème) ─── */
  tbody tr:nth-child(even) {
    background-color: var(--peels-table-zebra-bg, transparent);
  }

  tbody tr:hover {
    background-color: var(--peels-table-row-hover,
      color-mix(in oklch, var(--peels-surface-hover), var(--peels-text-body) 8%));
  }

  tfoot {
    font-size: var(--peels-text-small);
    color: var(--peels-text-muted);

    & td,
    & th {
      border-block-start: var(--peels-border-width) solid var(--peels-border-subtle);
      border-block-end: none;
    }

    & strong {
      font-weight: var(--peels-font-weight-ui);
      color: var(--peels-text-body);
    }
  }

  /* ─── Contexte "report" — zebra + thead contrasté via @scope ─── */
  /* Démontre le pattern conteneur : un wrapper data-context surcharge toutes
     les tables qu'il contient, sans attribut sur chaque <table>. */
  @scope ([data-context="report"]) {
    table {
      --peels-table-zebra-bg: var(--peels-surface-panel-soft);
      --peels-table-header-bg: var(--peels-text-body);
    }
    thead th {
      color: var(--peels-surface-page);
    }
  }

  /* Responsive — décision actée (mobile-first) :
     Les cellules wrappent leur contenu sur écran étroit (pas de white-space:nowrap
     par défaut), la table conserve width:100% et sa sémantique display:table.
     Pour les tables larges (nowrap, nombreuses colonnes), le pattern recommandé
     est un wrapper <div style="overflow-x:auto"> autour de la table — scroll
     horizontal contrôlé par le conteneur, sans hack display:block qui altère
     la sémantique table pour les AT. Le mode stacked (data-title sur <td>) est
     une évolution d'API séparée, pas un simple breakpoint — à décider si un cas
     concret le justifie. Ne pas masquer de colonnes ni réécrire les cellules via
     pseudo-contenu sans décision d'accessibilité. */
  /* TODO 2e passe :
     - Sticky thead : thead { position: sticky; top: 0; } pour tables longues
     - Row highlight : [data-highlight] sur <tr> pour ligne active/sélectionnée
     - Column expanders : <hr> dans <th> pour forcer largeur min (tables denses,
       cf. Blades) — pattern optionnel, pas dans le base
  */

/* peels-tabs.webc */
[role="tablist"] {
    display: flex;
    gap: var(--peels-tabs-gap, 0);
    border-block-end: var(--peels-tabs-border-width, 2px) solid var(--peels-border-subtle);
    overflow-x: auto;
    scrollbar-width: none;
  }

  [role="tab"] {
    padding: var(--peels-tab-padding, 0.5em 1em);
    font-weight: var(--peels-font-weight-ui);
    color: var(--peels-text-muted);
    border-block-end: var(--peels-tabs-border-width, 2px) solid transparent;
    margin-block-end: calc(var(--peels-tabs-border-width, 2px) * -1);
    cursor: pointer;
    background: none;
    border-inline: none;
    border-block-start: none;
    white-space: nowrap;

    &[aria-selected="true"] {
      color: var(--peels-text-body);
      border-block-end-color: var(--peels-color-highlight);
    }

    &:hover:not([aria-selected="true"]) {
      color: var(--peels-text-body);
    }

    &:focus-visible { outline: var(--peels-focus-width, 2px) var(--peels-focus-style, solid) var(--peels-focus-color, currentColor); }
    &:active { color: var(--peels-text-body); }
    &:disabled, &[aria-disabled="true"] { opacity: var(--peels-disabled-opacity, 0.5); }
  }

  [role="tabpanel"] {
    padding-block-start: var(--peels-padding-block);
  }

/* peels-text.webc */
blockquote {
    border-inline-start: var(--peels-blockquote-border-width, 3px) solid var(--peels-blockquote-border, var(--peels-border-subtle));
    padding: var(--peels-padding-block);
    margin-block: var(--peels-gap-prose);
    color: var(--peels-text-body);
    font-style: italic;
    line-height: var(--peels-leading-fine, inherit);

    & > p:last-child {
      margin-block-end: 0;
    }

    & > footer {
      font-size: var(--peels-text-small);
      font-style: normal;
      color: var(--peels-text-muted);
      margin-block-start: var(--peels-blockquote-footer-gap, 0.5em);

      & cite {
        font-weight: var(--peels-font-weight-ui);
      }
    }
  }

  mark {
    background-color: var(--peels-mark-bg, oklch(0.9 0.15 90 / 0.4));
    color: var(--peels-text-body);
    padding-inline: var(--peels-mark-padding-inline, 0.2em);
    border-radius: var(--peels-mark-radius, 0.15em);
  }

  small {
    font-size: var(--peels-text-small);
    color: var(--peels-text-muted);
  }

  del {
    color: var(--peels-text-muted);
    text-decoration: line-through;
  }

  ins {
    text-decoration-color: var(--peels-border-accent);
    text-underline-offset: var(--peels-text-underline-offset, 0.15em);
  }

  abbr[title] {
    text-decoration: underline dotted var(--peels-border-subtle);
    text-underline-offset: var(--peels-text-underline-offset, 0.15em);
    cursor: help;
  }

  /* ─── Inline sémantique — conventions typographiques ─── */
  cite {
    font-style: italic;
  }

  var {
    font-style: italic;
    font-family: var(--peels-font-mono);
  }

  dfn {
    font-style: italic;
  }

  sub,
  sup {
    font-size: var(--peels-text-small);
    line-height: 0;
    position: relative;
    vertical-align: baseline;
  }

  sub {
    bottom: -0.25em;
  }

  sup {
    top: -0.5em;
  }

  hr {
    border: none;
    border-top: var(--peels-hr-border-width, var(--peels-border-width)) solid var(--peels-hr-color, var(--peels-border-subtle));
    margin-block: var(--peels-gap-section);
  }

/* peels-tree-nav.webc */
/* ─── Tree Nav — navigation hiérarchique repliable ─── */
  /* Consomme peels-sidenav pour les liens feuilles dans <menu>.
     Consomme peels-details pour le repli (knobs --peels-details-*). */

  .tree-nav-item {
    --nav-cat-size: var(--peels-tree-nav-cat-size, 3.25rem);

    &:not(:first-of-type) {
      border-top: 1px solid var(--peels-border-subtle);
    }

    &:last-of-type {
      border-bottom: 1px solid var(--peels-border-subtle);
    }
  }

  /* ─── Titre de catégorie — lien + déclencheur de repli ─── */
  .tree-nav-cat {
    text-decoration: none;
    color: var(--peels-tree-nav-cat-color, var(--peels-text-body));
    font-size: var(--peels-tree-nav-cat-size-text, var(--peels-text-xsmall));
    font-weight: var(--peels-tree-nav-cat-weight, var(--peels-font-weight-ui));
    padding-block: var(--peels-tree-nav-cat-padding-block, var(--space-2xs));
    padding-inline: var(--peels-tree-nav-cat-padding-inline, var(--space-m));
    block-size: var(--nav-cat-size);
    display: flex;
    align-items: center;

    &:hover {
      color: var(--peels-tree-nav-cat-color-hover, var(--peels-text-accent));
    }
  }

  .tree-nav-item[aria-current="page"] > .tree-nav-cat {
    color: var(--peels-tree-nav-cat-color-current, var(--peels-text-accent));
    background: var(--peels-tree-nav-cat-bg-current, var(--peels-surface-page));
  }

  /* ─── Details — repli (consomme peels-details knobs) ─── */
  .tree-nav-item > details {
    --peels-details-border: none;
    --peels-details-radius: 0;
    --peels-details-padding: 0;
    --peels-details-stack-offset: 0;
    --peels-details-open-gap: 0;
    --peels-details-marker: "\25B6";
    --peels-details-marker-size: 0.65em;
    --peels-details-marker-rotate: 90deg;
    --peels-details-marker-margin-start: 0;
    --peels-details-summary-display: flex;
    --peels-details-summary-padding: 0;
    --peels-details-summary-position: static;

    position: relative;

    & > summary {
      cursor: pointer;
      color: var(--peels-text-muted);
      font-size: 0.7em;
      justify-content: center;
      block-size: var(--nav-cat-size);
      inline-size: var(--nav-cat-size);
      aspect-ratio: 1;
      border-inline-start: 1px solid var(--peels-border-subtle);
      position: absolute;
      top: calc(var(--nav-cat-size) * -1);
      inset-inline-end: 0;
    }

    border-block-start: 1px solid transparent;
    transition: border-color 0s 0.35s;

    &[open] {
      border-block-start-color: var(--peels-border-subtle);
      transition: border-color 0s;
    }

    /* ─── Liste enfants — animation grid-rows ─── */
    & > menu {
      list-style: none;
      padding: 0;
      margin: 0;
      display: grid;
      grid-template-rows: 0fr;
      transition: grid-template-rows 0.35s ease;

      & > * { overflow: hidden; }
    }

    &[open] > menu {
      grid-template-rows: 1fr;
    }

    /* Progressive enhancement : interpolate-size */
    @supports (interpolate-size: allow-keywords) {
      & {
        interpolate-size: allow-keywords;
      }

      & > menu {
        display: revert;
        grid-template-rows: revert;
        transition: none;

        & > * { overflow: revert; }
      }

      &[open] > menu {
        grid-template-rows: revert;
      }

      &::details-content {
        height: 0;
        overflow-y: clip;
        transition: height 0.35s ease,
                    content-visibility 0.35s ease allow-discrete;
      }

      &[open]::details-content {
        height: auto;
      }
    }
  }

  /* ─── Liens home/foot — hors catégories ─── */
  .tree-nav-home,
  .tree-nav-foot {
    display: block;
    padding: var(--peels-tree-nav-link-padding, var(--space-s) var(--space-m));
    font-size: var(--peels-tree-nav-link-size, var(--peels-text-small));
    text-decoration: none;
    color: var(--peels-tree-nav-link-color, var(--peels-text-muted));

    &:hover {
      color: var(--peels-text-body);
    }
  }

  .tree-nav-home {
    border-block-end: 1px solid var(--peels-border-subtle);
  }

  .tree-nav-foot {
    font-weight: var(--peels-font-weight-ui);
    border-block-start: 1px solid var(--peels-border-subtle);
    margin-block-start: auto;
  }

/* peels-video.webc */
/* Reset gère display:block, max-inline-size, block-size:auto.
     Base média gère border-radius via --peels-media-radius. Pas de CSS spécifique. */

/* peels-wrapper.webc */
[data-layout~="wrapper"] {
    max-inline-size: var(--peels-wrapper-max, 65rem);
    margin-inline: auto;
    padding-inline: var(--peels-gutter);
  }
}

/* ── a11y ── */
@layer a11y {
/* Peels — Accessibility
   Highest priority layer — overrides all other layers without !important
   Inspired by Miriam Suzanne's cascade layer architecture
   ════════════════════════════════════════════════════════ */

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation-duration: 0.01ms;
    animation-iteration-count: 1;
    transition-duration: 0.01ms;
    scroll-behavior: auto;
  }
}

:target {
  scroll-margin-block-start: 2ex;
}

:focus {
  scroll-margin-block-end: 8vh;
}

}