chore: initial DSMMG v0.2 — refonte architecturale complète
Release / Release / open changeset PR (push) Has been cancelled
CI / Build, typecheck, test, a11y (push) Has been cancelled

Mise en place du Design System ManageMate Group v0.2 — refonte du
système de tokens (préfixe --mmg-color-*), 9 presets accent
user-themable validés WCAG AA, overlays Radix UI + Floating UI,
Storybook 8 + Vitest + axe-core en CI, doc Astro Starlight,
DESIGN.md (format google-labs-code) et exports tokens DTCG/CSS/
TS/Figma/Tailwind v3 et v4.

- 4 packages monorepo pnpm : @managemate/{tokens,css,react,icons}
- 62 composants React headless-first (Sheet, HoverCard, ContextMenu,
  Slider, ToggleGroup, AvatarGroup, UserCard, ProfileHeader,
  MetricCard, PricingCard, FeatureCard, Text/Display/Eyebrow/Lead…)
- Lint contraste WCAG : 37/37 paires AA, branché CI
- Toast pile Sonner-style avec ResizeObserver
- Theming user (9 presets) sans casser sémantique fixe
- Identité Synapse (rose #D12B6A) préservée

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Dinawo
2026-05-04 22:07:57 +02:00
parent 5e019857fc
commit 62317f2ad7
172 changed files with 31397 additions and 1 deletions
+43
View File
@@ -0,0 +1,43 @@
{
"name": "@managemate/css",
"version": "0.1.0",
"description": "DSMMG vanilla CSS — tokens, base, components, utilities",
"license": "UNLICENSED",
"private": true,
"sideEffects": [
"*.css"
],
"main": "./dist/index.css",
"style": "./dist/index.css",
"exports": {
".": {
"style": "./dist/index.css",
"default": "./dist/index.css"
},
"./tokens": "./dist/tokens.css",
"./base": "./dist/base.css",
"./utilities": "./dist/utilities.css",
"./src/*": "./src/*",
"./package.json": "./package.json"
},
"files": [
"dist",
"src"
],
"scripts": {
"build": "pnpm run build:bundle && pnpm run build:tokens && pnpm run build:base && pnpm run build:utilities",
"build:bundle": "postcss src/index.css --output dist/index.css",
"build:tokens": "postcss src/tokens.css --output dist/tokens.css",
"build:base": "postcss src/base.css --output dist/base.css",
"build:utilities": "postcss src/utilities.css --output dist/utilities.css",
"build:min": "cross-env NODE_ENV=production pnpm run build"
},
"devDependencies": {
"autoprefixer": "^10.4.20",
"cross-env": "^7.0.3",
"cssnano": "^7.0.7",
"postcss": "^8.5.0",
"postcss-cli": "^11.0.0",
"postcss-import": "^16.1.0"
}
}
+19
View File
@@ -0,0 +1,19 @@
/**
* @managemate/css — postcss build pipeline.
* Aplatit les @import (postcss-import) et conserve les @layer correctement.
* cssnano en production pour minification.
*/
import postcssImport from "postcss-import";
import autoprefixer from "autoprefixer";
import cssnano from "cssnano";
export default {
plugins: [
postcssImport(),
autoprefixer(),
process.env.NODE_ENV === "production" &&
cssnano({
preset: ["default", { discardComments: { removeAll: false } }],
}),
].filter(Boolean),
};
+177
View File
@@ -0,0 +1,177 @@
/* ════════════════════════════════════════════════════════════════
DSMMG — Reset + base
════════════════════════════════════════════════════════════════ */
*,
*::before,
*::after {
box-sizing: border-box;
}
html {
-webkit-text-size-adjust: 100%;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
text-rendering: optimizeLegibility;
scroll-behavior: smooth;
}
body {
margin: 0;
font-family: var(--mmg-font-sans);
font-size: var(--mmg-font-size-base);
line-height: var(--mmg-line-height-normal);
color: var(--mmg-color-text-secondary);
background: var(--mmg-color-bg-page);
transition: background var(--mmg-duration-base) var(--mmg-ease-default),
color var(--mmg-duration-base) var(--mmg-ease-default);
}
h1, h2, h3, h4, h5, h6 {
margin: 0;
font-family: var(--mmg-font-sans);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
line-height: var(--mmg-line-height-tight);
}
h1 { font-size: var(--mmg-font-size-4xl); letter-spacing: -0.02em; }
h2 { font-size: var(--mmg-font-size-3xl); letter-spacing: -0.01em; }
h3 { font-size: var(--mmg-font-size-2xl); }
h4 { font-size: var(--mmg-font-size-xl); }
h5 { font-size: var(--mmg-font-size-lg); }
h6 { font-size: var(--mmg-font-size-base); }
p { margin: 0; }
a {
color: var(--mmg-color-accent);
text-decoration: none;
transition: color var(--mmg-duration-fast) var(--mmg-ease-default);
}
a:hover { color: var(--mmg-color-accent-hover); text-decoration: underline; }
img, svg, video {
display: block;
max-width: 100%;
height: auto;
}
button {
font: inherit;
cursor: pointer;
}
input, textarea, select, button {
font-family: inherit;
}
code, pre {
font-family: var(--mmg-font-mono);
font-size: 0.9em;
}
/* Focus visible global */
:focus-visible {
outline: 2px solid var(--mmg-color-accent);
outline-offset: 2px;
border-radius: 4px;
}
/* ════════════════════════════════════════════════════════════════
Sélection texte — accent marqué avec teinte chaude (Vercel-style).
Le user a explicitement demandé un effet visible. AA respecté :
accent à 35% + texte primary garde un contraste ≥ 4.5:1 sur la
plupart des fonds. Décoration text-shadow pour un effet "halo".
════════════════════════════════════════════════════════════════ */
::selection {
background: color-mix(in srgb, var(--mmg-color-accent) 36%, transparent);
color: var(--mmg-color-text-primary);
text-shadow: 0 0 8px color-mix(in srgb, var(--mmg-color-accent) 24%, transparent);
}
/* Sur fond accent (CTA, hero, badges solides) on inverse pour rester lisible. */
[data-mmg-on-accent] ::selection,
.mmg-hero ::selection,
.mmg-btn--primary ::selection,
.mmg-badge--solid ::selection {
background: color-mix(in srgb, var(--mmg-color-accent-on) 32%, transparent);
color: var(--mmg-color-accent-on);
text-shadow: none;
}
/* Scrollbars (WebKit + Firefox) ——————————————————— */
* {
scrollbar-width: thin;
scrollbar-color: var(--mmg-color-border-strong) transparent;
}
*::-webkit-scrollbar { width: 10px; height: 10px; }
*::-webkit-scrollbar-track { background: transparent; }
*::-webkit-scrollbar-thumb {
background: var(--mmg-color-border-strong);
border-radius: 8px;
border: 2px solid var(--mmg-color-bg-page);
background-clip: padding-box;
}
*::-webkit-scrollbar-thumb:hover { background: var(--mmg-color-text-tertiary); background-clip: padding-box; }
*::-webkit-scrollbar-corner { background: transparent; }
/* kbd ——————————————————— */
kbd {
display: inline-block;
padding: 2px 6px;
font-family: var(--mmg-font-mono);
font-size: 0.85em;
font-weight: var(--mmg-font-weight-medium);
color: var(--mmg-color-text-secondary);
background: var(--mmg-color-bg-muted);
border: 1px solid var(--mmg-color-border);
border-bottom-width: 2px;
border-radius: 4px;
line-height: 1;
}
/* — prefers-reduced-motion ————————————————————————————
WCAG SC 2.3.3 (AAA) + bonne pratique AA. Coupe quasiment
toutes les animations pour les utilisateurs sensibles
(vestibulaire, migraine, attention). Conserve transitions
d'opacité < 200ms qui sont neutres. */
@media (prefers-reduced-motion: reduce) {
*,
*::before,
*::after {
animation-duration: 0.001ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.001ms !important;
scroll-behavior: auto !important;
}
}
/* Skip link */
.mmg-skip-link {
position: absolute;
top: -200%;
left: var(--mmg-space-2);
z-index: var(--mmg-z-tooltip);
padding: var(--mmg-space-3) var(--mmg-space-4);
background: var(--mmg-color-accent);
color: var(--mmg-color-accent-on);
border-radius: var(--mmg-radius-md);
text-decoration: none;
font-weight: var(--mmg-font-weight-semi);
}
.mmg-skip-link:focus {
top: var(--mmg-space-2);
}
/* Helpers visuels — ne pas dépendre de Tailwind */
.mmg-sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
+467
View File
@@ -0,0 +1,467 @@
/* ════════════════════════════════════════════════════════════════
Advanced — Stepper, Accordion, Tooltip, Tag, Progress, Drawer,
Menu, FAB, Highlight, Quote, Callout, FileUpload,
SearchBar, Combobox
════════════════════════════════════════════════════════════════ */
/* ─────────────────────────────────────────────
Stepper (DSFR style)
───────────────────────────────────────────── */
.mmg-stepper {
margin-bottom: var(--mmg-space-6);
}
.mmg-stepper__progress {
font-size: var(--mmg-font-size-xs);
font-weight: var(--mmg-font-weight-bold);
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--mmg-color-accent);
margin-bottom: var(--mmg-space-2);
}
.mmg-stepper__title {
font-size: var(--mmg-font-size-xl);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
margin-bottom: var(--mmg-space-2);
}
.mmg-stepper__bar {
display: flex;
gap: 4px;
margin-bottom: var(--mmg-space-3);
}
.mmg-stepper__bar-item {
flex: 1;
height: 4px;
background: var(--mmg-color-bg-muted);
border-radius: 2px;
}
.mmg-stepper__bar-item--done { background: var(--mmg-color-accent); }
.mmg-stepper__bar-item--current { background: var(--mmg-color-accent); }
.mmg-stepper__next {
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-tertiary);
}
.mmg-stepper__next strong { color: var(--mmg-color-text-primary); }
/* ─────────────────────────────────────────────
Accordion
───────────────────────────────────────────── */
.mmg-accordion {
border-bottom: 1px solid var(--mmg-color-border-soft);
}
.mmg-accordion__btn {
width: 100%;
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--mmg-space-3);
padding: var(--mmg-space-4) var(--mmg-space-1);
background: transparent;
border: 0;
text-align: left;
font-family: inherit;
font-size: var(--mmg-font-size-base);
font-weight: var(--mmg-font-weight-semi);
color: var(--mmg-color-text-primary);
cursor: pointer;
}
.mmg-accordion__btn:hover { color: var(--mmg-color-accent); }
.mmg-accordion__chevron {
transition: transform var(--mmg-duration-base) var(--mmg-ease-emphasis);
flex-shrink: 0;
}
.mmg-accordion[data-open="true"] .mmg-accordion__chevron {
transform: rotate(180deg);
}
.mmg-accordion__panel {
display: none;
padding: 0 var(--mmg-space-1) var(--mmg-space-4);
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-secondary);
line-height: var(--mmg-line-height-normal);
}
.mmg-accordion[data-open="true"] .mmg-accordion__panel {
display: block;
}
/* Tooltip legacy CSS supprimé : le composant utilise désormais Radix UI
Tooltip et les styles vivent dans components/overlays.css. Les anciennes
classes .mmg-tooltip-wrap / .mmg-tooltip--top|bottom|left|right /
.mmg-tooltip--visible étaient dead code et conflictuaient (opacity 0
par défaut → tooltip Radix invisible). */
/* ─────────────────────────────────────────────
Tag (différent du Badge)
───────────────────────────────────────────── */
.mmg-tag {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 4px 10px;
font-size: var(--mmg-font-size-xs);
font-weight: var(--mmg-font-weight-medium);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-sm);
background: var(--mmg-color-bg-surface);
color: var(--mmg-color-text-secondary);
}
.mmg-tag--clickable {
cursor: pointer;
transition: all var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-tag--clickable:hover {
background: var(--mmg-color-bg-muted);
border-color: var(--mmg-color-border-strong);
}
.mmg-tag--selected {
background: var(--mmg-color-accent);
color: var(--mmg-color-accent-on);
border-color: var(--mmg-color-accent);
}
/* ─────────────────────────────────────────────
Progress (linéaire)
───────────────────────────────────────────── */
.mmg-progress {
height: 8px;
background: var(--mmg-color-bg-muted);
border-radius: var(--mmg-radius-pill);
overflow: hidden;
}
.mmg-progress__bar {
height: 100%;
background: var(--mmg-color-accent);
transition: width var(--mmg-duration-base) var(--mmg-ease-emphasis);
border-radius: inherit;
}
.mmg-progress--success .mmg-progress__bar { background: var(--mmg-color-success); }
.mmg-progress--warning .mmg-progress__bar { background: var(--mmg-color-warning); }
.mmg-progress--danger .mmg-progress__bar { background: var(--mmg-color-danger); }
.mmg-progress--indeterminate .mmg-progress__bar {
width: 30% !important;
animation: mmg-progress-indeterminate 1.4s ease-in-out infinite;
}
@keyframes mmg-progress-indeterminate {
0% { transform: translateX(-100%); }
100% { transform: translateX(400%); }
}
/* ─────────────────────────────────────────────
Drawer (panneau latéral)
───────────────────────────────────────────── */
.mmg-drawer-backdrop {
position: fixed;
inset: 0;
background: var(--mmg-color-bg-overlay);
z-index: var(--mmg-z-modal);
animation: mmg-fade-in var(--mmg-duration-base) var(--mmg-ease-default);
}
.mmg-drawer {
position: fixed;
top: 0;
right: 0;
height: 100vh;
width: 400px;
max-width: 90vw;
background: var(--mmg-color-bg-surface);
box-shadow: var(--mmg-shadow-3);
z-index: calc(var(--mmg-z-modal) + 1);
display: flex;
flex-direction: column;
animation: mmg-drawer-in var(--mmg-duration-base) var(--mmg-ease-emphasis);
}
.mmg-drawer--left {
right: auto;
left: 0;
animation-name: mmg-drawer-in-left;
}
.mmg-drawer__header {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--mmg-space-5) var(--mmg-space-6);
border-bottom: 1px solid var(--mmg-color-border-soft);
}
.mmg-drawer__body {
flex: 1;
overflow-y: auto;
padding: var(--mmg-space-5) var(--mmg-space-6);
}
.mmg-drawer__footer {
padding: var(--mmg-space-4) var(--mmg-space-6);
border-top: 1px solid var(--mmg-color-border-soft);
display: flex;
justify-content: flex-end;
gap: var(--mmg-space-2);
}
@keyframes mmg-drawer-in {
from { transform: translateX(100%); }
to { transform: translateX(0); }
}
@keyframes mmg-drawer-in-left {
from { transform: translateX(-100%); }
to { transform: translateX(0); }
}
/* ─────────────────────────────────────────────
Menu / Dropdown
───────────────────────────────────────────── */
.mmg-menu {
position: absolute;
z-index: var(--mmg-z-dropdown);
min-width: 200px;
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-md);
box-shadow: var(--mmg-shadow-2);
padding: var(--mmg-space-1);
animation: mmg-menu-in var(--mmg-duration-fast) var(--mmg-ease-emphasis);
}
@keyframes mmg-menu-in {
from { opacity: 0; transform: translateY(-4px); }
to { opacity: 1; transform: translateY(0); }
}
.mmg-menu__item {
display: flex;
align-items: center;
gap: var(--mmg-space-2);
width: 100%;
padding: 8px 12px;
background: transparent;
border: 0;
border-radius: var(--mmg-radius-sm);
font: inherit;
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-secondary);
text-align: left;
cursor: pointer;
text-decoration: none;
}
.mmg-menu__item:hover {
background: var(--mmg-color-bg-muted);
color: var(--mmg-color-text-primary);
text-decoration: none;
}
.mmg-menu__item--danger { color: var(--mmg-color-danger); }
.mmg-menu__item--danger:hover { background: var(--mmg-color-danger-soft); color: var(--mmg-color-danger-strong); }
.mmg-menu__divider {
height: 1px;
background: var(--mmg-color-border-soft);
margin: var(--mmg-space-1) 0;
border: 0;
}
.mmg-menu__label {
padding: 6px 12px 4px;
font-size: var(--mmg-font-size-xs);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-quaternary);
text-transform: uppercase;
letter-spacing: 0.06em;
}
/* ─────────────────────────────────────────────
FAB (Floating Action Button — Material style)
───────────────────────────────────────────── */
.mmg-fab {
position: fixed;
bottom: var(--mmg-space-6);
right: var(--mmg-space-6);
width: 56px;
height: 56px;
border-radius: 50%;
background: var(--mmg-color-accent);
color: var(--mmg-color-accent-on);
border: 0;
box-shadow: var(--mmg-shadow-3);
display: flex;
align-items: center;
justify-content: center;
font-size: 24px;
cursor: pointer;
z-index: var(--mmg-z-sticky);
transition: transform var(--mmg-duration-fast) var(--mmg-ease-emphasis),
background var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-fab:hover {
transform: scale(1.08);
background: var(--mmg-color-accent-hover);
}
.mmg-fab:active { transform: scale(0.96); }
/* ─────────────────────────────────────────────
Highlight (DSFR) — citation/encart marqué
───────────────────────────────────────────── */
.mmg-highlight {
border-left: 4px solid var(--mmg-color-accent);
padding: var(--mmg-space-4) var(--mmg-space-5);
background: var(--mmg-color-accent-soft);
border-radius: 0 var(--mmg-radius-md) var(--mmg-radius-md) 0;
font-size: var(--mmg-font-size-base);
color: var(--mmg-color-text-primary);
}
/* ─────────────────────────────────────────────
Quote (citation visuelle, plus chargée)
───────────────────────────────────────────── */
.mmg-quote {
position: relative;
padding: var(--mmg-space-6) var(--mmg-space-7);
background: var(--mmg-color-bg-surface);
border-radius: var(--mmg-radius-card);
border: 1px solid var(--mmg-color-border);
font-size: var(--mmg-font-size-lg);
line-height: var(--mmg-line-height-snug);
color: var(--mmg-color-text-primary);
font-style: italic;
}
.mmg-quote::before {
content: "“";
position: absolute;
top: -8px;
left: var(--mmg-space-4);
font-size: 80px;
line-height: 1;
color: var(--mmg-color-accent);
font-family: Georgia, serif;
font-style: normal;
}
.mmg-quote__author {
display: block;
margin-top: var(--mmg-space-3);
font-size: var(--mmg-font-size-sm);
font-style: normal;
font-weight: var(--mmg-font-weight-semi);
color: var(--mmg-color-text-tertiary);
}
/* ─────────────────────────────────────────────
Callout (mise en avant horizontale)
───────────────────────────────────────────── */
.mmg-callout {
display: flex;
flex-direction: column;
gap: var(--mmg-space-3);
padding: var(--mmg-space-6);
background: var(--mmg-color-bg-raised);
border-radius: var(--mmg-radius-card);
border: 1px solid var(--mmg-color-border);
}
.mmg-callout__title {
font-size: var(--mmg-font-size-lg);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
margin: 0;
}
.mmg-callout__body {
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-secondary);
}
/* ─────────────────────────────────────────────
Banner (annonce hero secondaire)
───────────────────────────────────────────── */
.mmg-banner {
display: flex;
align-items: center;
gap: var(--mmg-space-4);
padding: var(--mmg-space-5) var(--mmg-space-6);
background: linear-gradient(120deg, var(--mmg-color-accent) 0%, var(--mmg-color-accent-strong) 100%);
color: var(--mmg-color-accent-on);
border-radius: var(--mmg-radius-card);
box-shadow: var(--mmg-shadow-2);
}
.mmg-banner__title {
font-size: var(--mmg-font-size-lg);
font-weight: var(--mmg-font-weight-bold);
margin: 0;
color: inherit; /* hérite la couleur blanche du parent .mmg-banner */
}
.mmg-banner__desc {
font-size: var(--mmg-font-size-sm);
opacity: 0.92;
color: inherit;
}
.mmg-banner__action {
margin-left: auto;
}
/* ─────────────────────────────────────────────
File upload (drag & drop)
───────────────────────────────────────────── */
.mmg-upload {
position: relative;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: var(--mmg-space-2);
padding: var(--mmg-space-7) var(--mmg-space-5);
background: var(--mmg-color-bg-raised);
border: 2px dashed var(--mmg-color-border-strong);
border-radius: var(--mmg-radius-card);
text-align: center;
cursor: pointer;
transition: border-color var(--mmg-duration-fast) var(--mmg-ease-default),
background var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-upload:hover,
.mmg-upload[data-dragging="true"] {
border-color: var(--mmg-color-accent);
background: var(--mmg-color-accent-soft);
}
.mmg-upload__icon {
font-size: 32px;
color: var(--mmg-color-accent);
}
.mmg-upload__text {
font-weight: var(--mmg-font-weight-semi);
color: var(--mmg-color-text-primary);
}
.mmg-upload__hint {
font-size: var(--mmg-font-size-xs);
color: var(--mmg-color-text-tertiary);
}
.mmg-upload input[type="file"] {
position: absolute;
inset: 0;
opacity: 0;
cursor: pointer;
}
/* ─────────────────────────────────────────────
Search bar (combinée — input + button)
───────────────────────────────────────────── */
.mmg-search {
display: flex;
align-items: stretch;
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-pill);
overflow: hidden;
transition: border-color var(--mmg-duration-fast) var(--mmg-ease-default),
box-shadow var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-search:focus-within {
border-color: var(--mmg-color-accent);
box-shadow: var(--mmg-shadow-focus);
}
.mmg-search__input {
flex: 1;
border: 0;
padding: 10px 18px;
background: transparent;
font: inherit;
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-primary);
outline: none;
}
.mmg-search__btn {
background: var(--mmg-color-accent);
color: var(--mmg-color-accent-on);
border: 0;
padding: 0 var(--mmg-space-5);
font-weight: var(--mmg-font-weight-semi);
font-size: var(--mmg-font-size-sm);
cursor: pointer;
}
.mmg-search__btn:hover { background: var(--mmg-color-accent-hover); }
+428
View File
@@ -0,0 +1,428 @@
/* ════════════════════════════════════════════════════════════════
Article — pages de contenu type service-public.gouv.fr
════════════════════════════════════════════════════════════════ */
.mmg-article {
background: var(--mmg-color-bg-page);
}
/* ─────────────────────────────────────────────
Header de l'article
───────────────────────────────────────────── */
.mmg-article__header {
background: var(--mmg-color-bg-surface);
border-bottom: 1px solid var(--mmg-color-border-soft);
padding-block: var(--mmg-space-7) var(--mmg-space-9);
}
.mmg-article__eyebrow {
display: inline-flex;
align-items: center;
font-size: var(--mmg-font-size-xs);
font-weight: var(--mmg-font-weight-bold);
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--mmg-color-accent);
margin-bottom: var(--mmg-space-3);
}
.mmg-article__title {
font-size: clamp(2rem, 4vw, 3rem);
line-height: 1.15;
letter-spacing: -0.02em;
font-weight: var(--mmg-font-weight-extra);
color: var(--mmg-color-text-primary);
margin: 0;
max-width: 24ch;
}
.mmg-article__lead {
font-size: var(--mmg-font-size-xl);
line-height: var(--mmg-line-height-snug);
color: var(--mmg-color-text-secondary);
margin-top: var(--mmg-space-5);
max-width: 60ch;
}
.mmg-article__meta {
margin-top: var(--mmg-space-5);
display: flex;
flex-wrap: wrap;
gap: var(--mmg-space-4);
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-tertiary);
}
/* ─────────────────────────────────────────────
Layout principal : main + aside
───────────────────────────────────────────── */
.mmg-article__layout {
max-width: var(--mmg-container-max);
margin-inline: auto;
padding-inline: var(--mmg-space-5);
padding-block: var(--mmg-space-9);
display: grid;
grid-template-columns: minmax(0, 1fr) 280px;
gap: var(--mmg-space-9);
}
@media (min-width: 768px) {
.mmg-article__layout { padding-inline: var(--mmg-space-7); }
}
@media (max-width: 1024px) {
.mmg-article__layout { grid-template-columns: 1fr; gap: var(--mmg-space-7); }
}
.mmg-article__main { min-width: 0; max-width: 720px; }
/* ─────────────────────────────────────────────
Prose — typographie pour contenu rédactionnel
───────────────────────────────────────────── */
.mmg-prose {
color: var(--mmg-color-text-secondary);
font-size: var(--mmg-font-size-base);
line-height: 1.7;
}
.mmg-prose > * + * {
margin-top: var(--mmg-space-4);
}
.mmg-prose > h2 {
margin-top: var(--mmg-space-9);
margin-bottom: var(--mmg-space-3);
font-size: var(--mmg-font-size-2xl);
font-weight: var(--mmg-font-weight-bold);
letter-spacing: -0.01em;
color: var(--mmg-color-text-primary);
scroll-margin-top: 100px;
position: relative;
}
/* Bar horizontal au-dessus du titre — DSFR/Apple HIG style.
Aligné gauche sur le titre, hauteur fine, jamais en marge. */
.mmg-prose > h2::before {
content: "";
display: block;
width: 40px;
height: 4px;
background: var(--mmg-color-accent);
border-radius: 2px;
margin-bottom: var(--mmg-space-3);
}
.mmg-prose > h3 {
margin-top: var(--mmg-space-7);
margin-bottom: var(--mmg-space-2);
font-size: var(--mmg-font-size-lg);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
scroll-margin-top: 100px;
}
.mmg-prose > p {
margin: 0;
}
.mmg-prose > ul,
.mmg-prose > ol {
padding-left: var(--mmg-space-5);
display: flex;
flex-direction: column;
gap: var(--mmg-space-2);
}
.mmg-prose > ul { list-style: disc; }
.mmg-prose > ol { list-style: decimal; }
.mmg-prose strong { color: var(--mmg-color-text-primary); font-weight: var(--mmg-font-weight-bold); }
.mmg-prose a {
color: var(--mmg-color-accent);
text-decoration: underline;
text-underline-offset: 0.2em;
text-decoration-thickness: 1px;
}
.mmg-prose a:hover {
text-decoration-thickness: 2px;
color: var(--mmg-color-accent-hover);
}
.mmg-prose code {
font-family: var(--mmg-font-mono);
font-size: 0.9em;
background: var(--mmg-color-bg-muted);
padding: 2px 6px;
border-radius: 4px;
color: var(--mmg-color-text-primary);
}
.mmg-prose pre {
background: var(--mmg-color-bg-muted);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-md);
padding: var(--mmg-space-4);
overflow-x: auto;
font-size: var(--mmg-font-size-sm);
}
.mmg-prose blockquote {
border-left: 4px solid var(--mmg-color-accent);
padding-left: var(--mmg-space-4);
margin: 0;
color: var(--mmg-color-text-secondary);
font-style: italic;
}
.mmg-prose hr {
margin-block: var(--mmg-space-7);
border: 0;
height: 1px;
background: var(--mmg-color-border-soft);
}
/* — Callout DSFR-style dans le corps ——————————————————— */
.mmg-prose__callout {
display: flex;
gap: var(--mmg-space-3);
padding: var(--mmg-space-4) var(--mmg-space-5);
border-radius: var(--mmg-radius-md);
border-left: 4px solid var(--mmg-color-info);
background: var(--mmg-color-info-soft);
color: var(--mmg-color-text-primary);
font-size: var(--mmg-font-size-sm);
line-height: 1.6;
margin-block: var(--mmg-space-5);
}
.mmg-prose__callout--warning {
border-left-color: var(--mmg-color-warning);
background: var(--mmg-color-warning-soft);
}
.mmg-prose__callout--important {
border-left-color: var(--mmg-color-danger);
background: var(--mmg-color-danger-soft);
}
.mmg-prose__callout-icon { flex-shrink: 0; margin-top: 2px; }
.mmg-prose__callout-icon[class*="warning"] { color: var(--mmg-color-warning); }
.mmg-prose__callout-icon[class*="important"] { color: var(--mmg-color-danger); }
.mmg-prose__callout-icon { color: var(--mmg-color-info); }
.mmg-prose__callout--warning .mmg-prose__callout-icon { color: var(--mmg-color-warning); }
.mmg-prose__callout--important .mmg-prose__callout-icon { color: var(--mmg-color-danger); }
.mmg-prose__callout-title {
display: block;
color: var(--mmg-color-text-primary);
margin-bottom: 4px;
}
/* ─────────────────────────────────────────────
Aside — Voir aussi, documents
───────────────────────────────────────────── */
.mmg-aside {
display: flex;
flex-direction: column;
gap: var(--mmg-space-7);
}
.mmg-aside--sticky {
position: sticky;
top: 100px;
align-self: start;
}
.mmg-aside__section {
border-top: 2px solid var(--mmg-color-accent);
padding-top: var(--mmg-space-4);
}
.mmg-aside__title {
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-bold);
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--mmg-color-text-primary);
margin: 0 0 var(--mmg-space-3);
}
.mmg-aside__links {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 0;
}
.mmg-aside__links a {
display: flex;
align-items: flex-start;
gap: var(--mmg-space-2);
padding: var(--mmg-space-2) 0;
color: var(--mmg-color-text-secondary);
font-size: var(--mmg-font-size-sm);
line-height: 1.5;
text-decoration: none;
border-bottom: 1px solid var(--mmg-color-border-soft);
}
.mmg-aside__links a:hover {
color: var(--mmg-color-accent);
text-decoration: underline;
}
.mmg-aside__links a > [class*="mmg-icon"] {
flex-shrink: 0;
margin-top: 4px;
color: var(--mmg-color-accent);
}
.mmg-aside__links li:last-child a { border-bottom: 0; }
.mmg-aside__docs {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: var(--mmg-space-2);
}
.mmg-aside__docs a {
display: flex;
align-items: flex-start;
gap: var(--mmg-space-3);
padding: var(--mmg-space-3);
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-md);
text-decoration: none;
color: var(--mmg-color-text-secondary);
transition:
background var(--mmg-duration-fast) var(--mmg-ease-default),
border-color var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-aside__docs a:hover {
background: var(--mmg-color-bg-raised);
border-color: var(--mmg-color-accent-border);
}
.mmg-aside__docs a > [class*="mmg-icon"] {
flex-shrink: 0;
color: var(--mmg-color-danger);
}
.mmg-aside__doc-label {
display: block;
font-weight: var(--mmg-font-weight-semi);
color: var(--mmg-color-text-primary);
font-size: var(--mmg-font-size-sm);
}
.mmg-aside__doc-meta {
display: block;
font-size: var(--mmg-font-size-xs);
color: var(--mmg-color-text-tertiary);
margin-top: 2px;
}
/* ─────────────────────────────────────────────
TOC — table des matières
───────────────────────────────────────────── */
.mmg-toc__list {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: 0;
}
.mmg-toc__link {
display: flex;
gap: var(--mmg-space-2);
padding: var(--mmg-space-2) var(--mmg-space-3);
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-tertiary);
text-decoration: none;
line-height: 1.4;
border-left: 2px solid var(--mmg-color-border-soft);
transition: all var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-toc__link:hover {
color: var(--mmg-color-text-primary);
border-left-color: var(--mmg-color-text-tertiary);
}
.mmg-toc__link--active {
color: var(--mmg-color-accent);
border-left-color: var(--mmg-color-accent);
font-weight: var(--mmg-font-weight-semi);
background: var(--mmg-color-accent-soft);
}
.mmg-toc__num {
color: var(--mmg-color-text-quaternary);
font-family: var(--mmg-font-mono);
font-size: var(--mmg-font-size-xs);
flex-shrink: 0;
}
/* ─────────────────────────────────────────────
Article footer — last update + share + feedback
───────────────────────────────────────────── */
.mmg-article__footer {
margin-top: var(--mmg-space-9);
padding-top: var(--mmg-space-7);
border-top: 1px solid var(--mmg-color-border-soft);
display: flex;
flex-direction: column;
gap: var(--mmg-space-5);
}
.mmg-article__updated {
display: inline-flex;
align-items: center;
gap: var(--mmg-space-2);
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-tertiary);
}
.mmg-article__updated [class*="mmg-icon"] { color: var(--mmg-color-text-tertiary); }
.mmg-article__share {
display: flex;
align-items: center;
gap: var(--mmg-space-3);
flex-wrap: wrap;
}
.mmg-article__share-label {
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-semi);
color: var(--mmg-color-text-primary);
}
.mmg-article__share-btn {
width: 40px;
height: 40px;
display: inline-flex;
align-items: center;
justify-content: center;
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: 50%;
cursor: pointer;
color: var(--mmg-color-text-secondary);
text-decoration: none;
transition:
background var(--mmg-duration-fast) var(--mmg-ease-default),
color var(--mmg-duration-fast) var(--mmg-ease-default),
border-color var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-article__share-btn:hover {
background: var(--mmg-color-accent-soft);
border-color: var(--mmg-color-accent-border);
color: var(--mmg-color-accent);
}
.mmg-article__feedback {
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-card);
padding: var(--mmg-space-5);
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: var(--mmg-space-3);
}
.mmg-article__feedback-label {
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-semi);
color: var(--mmg-color-text-primary);
}
.mmg-article__feedback-btn {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 8px 16px;
background: var(--mmg-color-bg-page);
border: 1px solid var(--mmg-color-border-strong);
border-radius: var(--mmg-radius-pill);
font: inherit;
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-semi);
color: var(--mmg-color-text-primary);
cursor: pointer;
min-height: 36px;
transition:
background var(--mmg-duration-fast) var(--mmg-ease-default),
border-color var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-article__feedback-btn:hover {
background: var(--mmg-color-accent-soft);
border-color: var(--mmg-color-accent);
color: var(--mmg-color-accent-strong);
}
+108
View File
@@ -0,0 +1,108 @@
/* ════════════════════════════════════════════════════════════════
Avatar — initiales, image, statut, couleurs auto-générées.
════════════════════════════════════════════════════════════════ */
.mmg-avatar {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
width: 40px;
height: 40px;
border-radius: 50%;
overflow: hidden;
background: var(--mmg-color-accent-soft);
color: var(--mmg-color-accent-strong);
font-weight: var(--mmg-font-weight-semi);
font-size: var(--mmg-font-size-sm);
line-height: 1;
letter-spacing: -0.01em;
user-select: none;
text-transform: uppercase;
}
.mmg-avatar > img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
/* Sizes */
.mmg-avatar--xs { width: 20px; height: 20px; font-size: 9px; }
.mmg-avatar--sm { width: 28px; height: 28px; font-size: 11px; }
.mmg-avatar--md { width: 40px; height: 40px; font-size: var(--mmg-font-size-sm); }
.mmg-avatar--lg { width: 56px; height: 56px; font-size: var(--mmg-font-size-lg); }
.mmg-avatar--xl { width: 72px; height: 72px; font-size: var(--mmg-font-size-xl); }
.mmg-avatar--2xl { width: 96px; height: 96px; font-size: var(--mmg-font-size-2xl); }
/* Shape */
.mmg-avatar--square { border-radius: 12px; }
.mmg-avatar--xs.mmg-avatar--square { border-radius: 4px; }
.mmg-avatar--sm.mmg-avatar--square { border-radius: 6px; }
.mmg-avatar--lg.mmg-avatar--square { border-radius: 14px; }
.mmg-avatar--xl.mmg-avatar--square { border-radius: 16px; }
.mmg-avatar--2xl.mmg-avatar--square { border-radius: 20px; }
/* Bordure (utile pour AvatarGroup) — utilise box-shadow pour ne pas
décaler la taille interne. */
.mmg-avatar--bordered {
box-shadow: 0 0 0 2px var(--mmg-color-bg-surface);
}
/* Couleurs auto-générées des initiales — palette catégorielle stable. */
.mmg-avatar--neutral { background: var(--mmg-color-bg-muted); color: var(--mmg-color-text-secondary); }
.mmg-avatar--brand { background: var(--mmg-color-accent-soft); color: var(--mmg-color-accent-strong); }
.mmg-avatar--blue { background: var(--mmg-color-blue-100); color: var(--mmg-color-blue-800); }
.mmg-avatar--green { background: var(--mmg-color-green-100); color: var(--mmg-color-green-800); }
.mmg-avatar--amber { background: var(--mmg-color-amber-100); color: var(--mmg-color-amber-800); }
.mmg-avatar--violet { background: var(--mmg-color-violet-100); color: var(--mmg-color-violet-800); }
[data-mmg-theme="dark"] .mmg-avatar--blue { background: rgba(96, 165, 250, 0.18); color: var(--mmg-color-blue-d-300); }
[data-mmg-theme="dark"] .mmg-avatar--green { background: rgba(52, 211, 153, 0.18); color: var(--mmg-color-green-d-300); }
[data-mmg-theme="dark"] .mmg-avatar--amber { background: rgba(251, 191, 36, 0.18); color: var(--mmg-color-amber-d-300); }
[data-mmg-theme="dark"] .mmg-avatar--violet { background: rgba(167, 139, 250, 0.18); color: var(--mmg-color-violet-d-300); }
/* — Status indicator (presence) ————————————————————————— */
.mmg-avatar__status {
position: absolute;
right: 0;
bottom: 0;
width: 30%;
height: 30%;
min-width: 8px;
min-height: 8px;
max-width: 14px;
max-height: 14px;
border-radius: 50%;
box-shadow: 0 0 0 2px var(--mmg-color-bg-surface);
}
.mmg-avatar__status--online { background: var(--mmg-color-success); }
.mmg-avatar__status--away { background: var(--mmg-color-warning); }
.mmg-avatar__status--busy { background: var(--mmg-color-danger); }
.mmg-avatar__status--offline { background: var(--mmg-color-text-quaternary); }
/* AvatarGroup — empilement avec overlap négatif */
.mmg-avatar-group {
display: inline-flex;
align-items: center;
}
.mmg-avatar-group .mmg-avatar {
margin-left: -10px;
transition: transform var(--mmg-duration-fast) var(--mmg-ease-emphasis);
}
.mmg-avatar-group .mmg-avatar:first-child { margin-left: 0; }
.mmg-avatar-group .mmg-avatar:hover { transform: translateY(-2px); z-index: 1; }
.mmg-avatar-group--xs .mmg-avatar { margin-left: -6px; }
.mmg-avatar-group--sm .mmg-avatar { margin-left: -8px; }
.mmg-avatar-group--lg .mmg-avatar { margin-left: -14px; }
.mmg-avatar-group--xl .mmg-avatar { margin-left: -18px; }
.mmg-avatar-group--2xl .mmg-avatar { margin-left: -24px; }
.mmg-avatar-group__more {
background: var(--mmg-color-bg-muted);
color: var(--mmg-color-text-secondary);
font-size: var(--mmg-font-size-xs);
font-variant-numeric: tabular-nums;
}
+260
View File
@@ -0,0 +1,260 @@
/* ════════════════════════════════════════════════════════════════
Button — Material 3 / Fluent 2 inspired
- State layer overlay au hover (subtil, pas de flash de couleur)
- Variantes : primary, tonal, secondary, outlined, ghost, elevated, danger, success
- Radius modéré (10px) — moins agressif que pill, plus moderne que carré
════════════════════════════════════════════════════════════════ */
.mmg-btn {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
gap: var(--mmg-space-2);
padding: 10px 22px;
font-family: inherit;
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-semi);
line-height: 1.2;
letter-spacing: 0.005em;
border: 1px solid transparent;
border-radius: var(--mmg-radius-pill); /* Pill par défaut — Google M3 style */
background: transparent;
color: var(--mmg-color-text-primary);
cursor: pointer;
text-decoration: none;
user-select: none;
white-space: nowrap;
isolation: isolate;
transition:
background var(--mmg-duration-fast) var(--mmg-ease-default),
border-color var(--mmg-duration-fast) var(--mmg-ease-default),
color var(--mmg-duration-fast) var(--mmg-ease-default),
box-shadow var(--mmg-duration-base) var(--mmg-ease-default),
transform var(--mmg-duration-fast) var(--mmg-ease-emphasis);
}
/* — State layer (overlay qui s'opacifie au hover/focus/press) — */
.mmg-btn::before {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
background: currentColor;
opacity: 0;
pointer-events: none;
transition: opacity var(--mmg-duration-fast) var(--mmg-ease-default);
z-index: -1;
}
.mmg-btn:hover:not(:disabled)::before { opacity: 0.12; }
.mmg-btn:focus-visible::before { opacity: 0.16; }
.mmg-btn:active:not(:disabled)::before { opacity: 0.22; }
.mmg-btn:focus-visible {
outline: 0;
box-shadow: var(--mmg-shadow-focus);
}
.mmg-btn:active:not(:disabled) {
transform: scale(0.97);
}
/* Disabled — tokens dédiés (jamais opacity seule, pas accessible) */
.mmg-btn:disabled,
.mmg-btn[aria-disabled="true"] {
background: var(--mmg-color-state-disabled-bg) !important;
color: var(--mmg-color-state-disabled-text) !important;
border-color: var(--mmg-color-state-disabled-border) !important;
box-shadow: none !important;
cursor: not-allowed;
pointer-events: none;
}
.mmg-btn:disabled::before,
.mmg-btn[aria-disabled="true"]::before {
display: none;
}
/* — Variants ————————————————————— */
/* Primary — solid brand, ombre teintée marque pour cliquabilité */
.mmg-btn--primary {
background: var(--mmg-color-accent);
color: var(--mmg-color-accent-on);
border-color: transparent;
box-shadow: var(--mmg-shadow-accent);
}
.mmg-btn--primary::before { background: var(--mmg-color-accent-on); }
.mmg-btn--primary:hover:not(:disabled) {
color: var(--mmg-color-accent-on);
box-shadow: var(--mmg-shadow-accent-hover);
}
/* Tonal (Material 3) — fond pâle, texte foncé brand */
.mmg-btn--tonal {
background: var(--mmg-color-accent-soft);
color: var(--mmg-color-accent-strong);
border-color: transparent;
}
.mmg-btn--tonal::before { background: var(--mmg-color-accent); }
.mmg-btn--tonal:hover:not(:disabled) { color: var(--mmg-color-accent-strong); }
/* Secondary — outline rose */
.mmg-btn--secondary {
background: transparent;
color: var(--mmg-color-accent);
border-color: var(--mmg-color-accent);
}
.mmg-btn--secondary::before { background: var(--mmg-color-accent); }
.mmg-btn--secondary:hover:not(:disabled) { color: var(--mmg-color-accent-strong); border-color: var(--mmg-color-accent-strong); }
/* Tertiary (Fluent default) — neutre avec border */
.mmg-btn--tertiary {
background: var(--mmg-color-bg-surface);
color: var(--mmg-color-text-primary);
border-color: var(--mmg-color-border-strong);
}
.mmg-btn--tertiary::before { background: var(--mmg-color-text-primary); }
/* Dark : bg surface (#14171F) sur page (#0B0D14) = contraste 1.3:1, le
bouton "disparaît" dans le fond. On remonte sur bg-raised + on ajoute
un halo blanc pour décoller. */
[data-mmg-theme="dark"] .mmg-btn--tertiary {
background: var(--mmg-color-bg-raised);
border-color: var(--mmg-color-border-strong);
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.04);
}
/* Ghost (Fluent subtle) — transparent, hover révèle un fond */
.mmg-btn--ghost {
background: transparent;
color: var(--mmg-color-text-secondary);
border-color: transparent;
}
.mmg-btn--ghost::before { background: var(--mmg-color-text-primary); }
.mmg-btn--ghost:hover:not(:disabled) { color: var(--mmg-color-text-primary); }
/* Dark : pas de force sur le texte (sinon le hover perd sa différenciation).
text-secondary = #C9CED9 → contraste 11:1 sur bg-page #0B0D14 (AAA). */
/* Elevated (Material 3) — fond surface avec ombre, plane au hover */
.mmg-btn--elevated {
background: var(--mmg-color-bg-surface);
color: var(--mmg-color-accent);
border-color: transparent;
box-shadow: var(--mmg-shadow-elevated);
}
[data-mmg-theme="dark"] .mmg-btn--elevated {
background: var(--mmg-color-bg-raised);
}
.mmg-btn--elevated::before { background: var(--mmg-color-accent); }
.mmg-btn--elevated:hover:not(:disabled) {
box-shadow: var(--mmg-shadow-elevated-hover);
transform: translateY(-1px);
}
.mmg-btn--elevated:active:not(:disabled) { transform: translateY(0); }
/* Danger / Success */
.mmg-btn--danger {
background: var(--mmg-color-danger);
color: var(--mmg-color-accent-on);
border-color: transparent;
box-shadow: var(--mmg-shadow-flat);
}
.mmg-btn--danger::before { background: var(--mmg-color-accent-on); }
.mmg-btn--danger:hover:not(:disabled) { color: var(--mmg-color-accent-on); }
.mmg-btn--success {
background: var(--mmg-color-success);
color: var(--mmg-color-accent-on);
border-color: transparent;
box-shadow: var(--mmg-shadow-flat);
}
.mmg-btn--success::before { background: var(--mmg-color-accent-on); }
.mmg-btn--success:hover:not(:disabled) { color: var(--mmg-color-accent-on); }
/* — Sizes — radius pill par défaut, le padding gère la taille ————————— */
.mmg-btn--xs { padding: 4px 14px; font-size: var(--mmg-font-size-xs); }
.mmg-btn--sm { padding: 7px 18px; font-size: var(--mmg-font-size-xs); }
.mmg-btn--md { padding: 10px 22px; font-size: var(--mmg-font-size-sm); }
.mmg-btn--lg { padding: 13px 30px; font-size: var(--mmg-font-size-base); }
.mmg-btn--xl { padding: 17px 38px; font-size: var(--mmg-font-size-lg); }
/* — Icon-only (cercle parfait) ————————————— */
.mmg-btn--icon-only {
padding: 10px;
width: 40px;
height: 40px;
border-radius: 50%;
position: relative;
}
.mmg-btn--icon-only.mmg-btn--xs { padding: 4px; width: 28px; height: 28px; }
.mmg-btn--icon-only.mmg-btn--sm { padding: 7px; width: 34px; height: 34px; }
.mmg-btn--icon-only.mmg-btn--lg { padding: 13px; width: 48px; height: 48px; }
.mmg-btn--icon-only.mmg-btn--xl { padding: 17px; width: 56px; height: 56px; }
/* Touch target zone invisible — garantit 44×44 minimum (WCAG SC 2.5.5)
sans augmenter la taille visible. Active uniquement sous tailles 40px. */
.mmg-btn--icon-only::after {
content: "";
position: absolute;
inset: 50% 50%;
width: var(--mmg-touch-min);
height: var(--mmg-touch-min);
transform: translate(-50%, -50%);
z-index: 0;
}
.mmg-btn--icon-only.mmg-btn--lg::after,
.mmg-btn--icon-only.mmg-btn--xl::after {
/* La cible visible suffit déjà */
display: none;
}
/* — Square (alternative — radius modéré façon DSFR) ——————— */
.mmg-btn--square { border-radius: 8px; }
.mmg-btn--square.mmg-btn--lg { border-radius: 10px; }
.mmg-btn--square.mmg-btn--xl { border-radius: 12px; }
.mmg-btn--square.mmg-btn--icon-only { border-radius: 8px; }
/* Compat : alias inverse pour basculer EXPLICITEMENT en pill (déjà par défaut) */
.mmg-btn--pill { border-radius: var(--mmg-radius-pill); }
/* — Block (full width) ————————————— */
.mmg-btn--block { width: 100%; }
/* — Group ————————————————————— */
.mmg-btn-group {
display: inline-flex;
flex-wrap: wrap;
gap: var(--mmg-space-2);
}
.mmg-btn-group--vertical {
flex-direction: column;
align-items: stretch;
}
/* — Loading state ————————————————————— */
.mmg-btn--loading {
position: relative;
color: transparent !important;
pointer-events: none;
}
.mmg-btn--loading > * { visibility: hidden; }
.mmg-btn--loading::after {
content: "";
position: absolute;
width: 16px;
height: 16px;
border: 2px solid currentColor;
border-top-color: transparent;
border-radius: 50%;
animation: mmg-spin 0.7s linear infinite;
color: var(--mmg-color-accent-on);
visibility: visible;
z-index: 1;
}
.mmg-btn--secondary.mmg-btn--loading::after,
.mmg-btn--tertiary.mmg-btn--loading::after,
.mmg-btn--ghost.mmg-btn--loading::after,
.mmg-btn--tonal.mmg-btn--loading::after,
.mmg-btn--elevated.mmg-btn--loading::after {
color: var(--mmg-color-accent);
}
@keyframes mmg-spin {
to { transform: rotate(360deg); }
}
+926
View File
@@ -0,0 +1,926 @@
/* ════════════════════════════════════════════════════════════════
Chrome — Header, Footer, Breadcrumb, Sidebar, Topbar, Tabs, Pagination
════════════════════════════════════════════════════════════════ */
/* ─────────────────────────────────────────────
Header (landing/marketing) — DSFR multi-ligne
───────────────────────────────────────────── */
.mmg-header {
position: sticky;
top: 0;
z-index: var(--mmg-z-sticky);
background: var(--mmg-color-bg-surface);
border-bottom: 1px solid var(--mmg-color-border-soft);
backdrop-filter: blur(8px);
}
.mmg-header__inner {
display: grid;
grid-template-columns: auto 1fr auto;
align-items: center;
height: 64px;
gap: var(--mmg-space-5);
}
.mmg-header__brand {
display: inline-flex;
align-items: center;
gap: var(--mmg-space-2);
text-decoration: none;
color: var(--mmg-color-text-primary);
border-radius: var(--mmg-radius-md);
padding: 6px 10px;
/* Pas de margin négatif — laisse le grid faire l'alignement */
transition: background var(--mmg-duration-fast) var(--mmg-ease-default);
height: 44px;
}
.mmg-header__brand:hover,
.mmg-header__brand:focus-visible {
background: var(--mmg-color-bg-muted);
color: var(--mmg-color-text-primary);
text-decoration: none;
}
/* Logo carré, plus discret (pas de gradient/ombre) — Linear/Vercel-like */
.mmg-header__logo {
width: 28px;
height: 28px;
border-radius: 8px;
background: var(--mmg-color-accent);
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--mmg-color-accent-on);
font-weight: var(--mmg-font-weight-extra);
font-size: 12px;
letter-spacing: -0.02em;
flex-shrink: 0;
}
.mmg-header__name {
font-size: var(--mmg-font-size-base);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
letter-spacing: -0.005em;
}
/* Mode "institutional" — multi-ligne pour pages publiques type DSFR */
.mmg-header--institutional .mmg-header__inner {
height: 88px;
}
.mmg-header--institutional .mmg-header__brand {
height: 64px;
}
.mmg-header--institutional .mmg-header__logo {
width: 44px;
height: 44px;
border-radius: 10px;
font-size: 15px;
}
.mmg-header__brand-text {
display: flex;
flex-direction: column;
line-height: 1.2;
}
.mmg-header__brand-top {
font-size: 10px;
font-weight: var(--mmg-font-weight-bold);
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--mmg-color-text-tertiary);
}
.mmg-header__service {
font-size: var(--mmg-font-size-base);
font-weight: var(--mmg-font-weight-bold);
letter-spacing: -0.01em;
color: var(--mmg-color-text-primary);
margin-top: 1px;
}
.mmg-header__service-tagline {
font-size: var(--mmg-font-size-xs);
color: var(--mmg-color-text-tertiary);
margin-top: 1px;
font-weight: var(--mmg-font-weight-medium);
}
.mmg-header__nav {
display: flex;
align-items: center;
gap: var(--mmg-space-1);
height: 44px;
/* Aligné à gauche, adjacent au brand — pattern Linear/Vercel
(Le grid parent garantit l'alignement vertical exact) */
}
.mmg-header__nav a {
padding: 8px 14px;
border-radius: var(--mmg-radius-pill);
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-medium);
color: var(--mmg-color-text-secondary);
text-decoration: none;
transition: background var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-header__nav a:hover {
background: var(--mmg-color-bg-muted);
color: var(--mmg-color-text-primary);
text-decoration: none;
}
.mmg-header__nav a[aria-current="page"] {
color: var(--mmg-color-accent);
font-weight: var(--mmg-font-weight-semi);
}
/* — Mega-menu (DSFR-style) ————————————————————————————— */
.mmg-header__nav-item {
position: relative;
}
.mmg-header__nav-trigger {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 8px 14px;
background: transparent;
border: 0;
border-radius: var(--mmg-radius-pill);
font: inherit;
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-medium);
color: var(--mmg-color-text-secondary);
cursor: pointer;
white-space: nowrap;
}
.mmg-header__nav-trigger:hover,
.mmg-header__nav-trigger[aria-expanded="true"] {
background: var(--mmg-color-bg-muted);
color: var(--mmg-color-text-primary);
}
.mmg-header__nav-trigger[aria-expanded="true"] .mmg-header__nav-chevron {
transform: rotate(180deg);
}
.mmg-header__nav-chevron {
transition: transform var(--mmg-duration-fast) var(--mmg-ease-emphasis);
font-size: 0.85em;
opacity: 0.7;
}
.mmg-megamenu {
position: absolute;
top: calc(100% + 4px);
left: 50%;
transform: translateX(-50%);
z-index: var(--mmg-z-dropdown);
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-panel);
box-shadow: var(--mmg-shadow-3);
padding: var(--mmg-space-6);
min-width: 600px;
max-width: 880px;
animation: mmg-megamenu-in var(--mmg-duration-base) var(--mmg-ease-emphasis);
}
@keyframes mmg-megamenu-in {
from { opacity: 0; transform: translate(-50%, -8px); }
to { opacity: 1; transform: translate(-50%, 0); }
}
.mmg-megamenu__grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: var(--mmg-space-6);
}
.mmg-megamenu__col-title {
font-size: var(--mmg-font-size-xs);
font-weight: var(--mmg-font-weight-bold);
text-transform: uppercase;
letter-spacing: 0.06em;
color: var(--mmg-color-text-tertiary);
margin-bottom: var(--mmg-space-3);
}
.mmg-megamenu__list {
display: flex;
flex-direction: column;
gap: 2px;
list-style: none;
padding: 0;
margin: 0;
}
.mmg-megamenu__link {
display: flex;
align-items: flex-start;
gap: var(--mmg-space-3);
padding: var(--mmg-space-2) var(--mmg-space-3);
border-radius: var(--mmg-radius-md);
text-decoration: none;
color: var(--mmg-color-text-secondary);
transition: background var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-megamenu__link:hover {
background: var(--mmg-color-bg-muted);
color: var(--mmg-color-text-primary);
text-decoration: none;
}
.mmg-megamenu__link-icon {
flex-shrink: 0;
margin-top: 2px;
color: var(--mmg-color-accent);
}
.mmg-megamenu__link-content { min-width: 0; }
.mmg-megamenu__link-label {
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-semi);
color: var(--mmg-color-text-primary);
display: block;
}
.mmg-megamenu__link-desc {
font-size: var(--mmg-font-size-xs);
color: var(--mmg-color-text-tertiary);
display: block;
margin-top: 2px;
}
.mmg-megamenu__featured {
background: var(--mmg-color-accent-soft);
border-radius: var(--mmg-radius-card);
padding: var(--mmg-space-5);
display: flex;
flex-direction: column;
gap: var(--mmg-space-3);
}
.mmg-megamenu__featured-title {
font-size: var(--mmg-font-size-base);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-accent-strong);
}
.mmg-megamenu__featured-desc {
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-secondary);
line-height: var(--mmg-line-height-snug);
}
.mmg-header__actions {
display: flex;
align-items: center;
gap: var(--mmg-space-2);
height: 44px;
}
@media (max-width: 768px) {
.mmg-header__nav { display: none; }
}
/* ─────────────────────────────────────────────
Footer
───────────────────────────────────────────── */
.mmg-footer {
background: var(--mmg-color-bg-surface);
border-top: 1px solid var(--mmg-color-border);
padding-block: var(--mmg-space-9) var(--mmg-space-5);
margin-top: var(--mmg-space-12);
}
.mmg-footer__top {
display: grid;
grid-template-columns: 2fr repeat(3, 1fr);
gap: var(--mmg-space-7);
margin-bottom: var(--mmg-space-8);
}
@media (max-width: 768px) {
.mmg-footer__top { grid-template-columns: 1fr 1fr; }
}
.mmg-footer__col-title {
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
margin-bottom: var(--mmg-space-3);
}
.mmg-footer__col-list {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: var(--mmg-space-2);
}
.mmg-footer__col-list a {
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-tertiary);
text-decoration: none;
}
.mmg-footer__col-list a:hover {
color: var(--mmg-color-accent);
text-decoration: underline;
}
.mmg-footer__bottom {
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: var(--mmg-space-3);
padding-top: var(--mmg-space-5);
border-top: 1px solid var(--mmg-color-border-soft);
font-size: var(--mmg-font-size-xs);
color: var(--mmg-color-text-quaternary);
}
/* ─────────────────────────────────────────────
Breadcrumb
───────────────────────────────────────────── */
.mmg-breadcrumb {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: var(--mmg-space-1);
font-size: var(--mmg-font-size-xs);
color: var(--mmg-color-text-tertiary);
padding: var(--mmg-space-3) 0;
}
.mmg-breadcrumb a {
color: var(--mmg-color-text-tertiary);
text-decoration: none;
}
.mmg-breadcrumb a:hover {
color: var(--mmg-color-accent);
text-decoration: underline;
}
.mmg-breadcrumb__sep {
color: var(--mmg-color-text-quaternary);
margin: 0 4px;
}
.mmg-breadcrumb__current {
color: var(--mmg-color-text-primary);
font-weight: var(--mmg-font-weight-semi);
}
/* ─────────────────────────────────────────────
Sidebar (SaaS app shell)
───────────────────────────────────────────── */
.mmg-app-shell {
display: flex;
min-height: 100vh;
background: var(--mmg-color-bg-page);
}
.mmg-sidebar {
width: 240px;
background: var(--mmg-color-bg-surface);
border-right: 1px solid var(--mmg-color-border);
display: flex;
flex-direction: column;
flex-shrink: 0;
}
.mmg-sidebar__header {
padding: var(--mmg-space-4) var(--mmg-space-5);
border-bottom: 1px solid var(--mmg-color-border-soft);
display: flex;
align-items: center;
gap: var(--mmg-space-2);
}
.mmg-sidebar__body {
flex: 1;
overflow-y: auto;
padding: var(--mmg-space-3);
display: flex;
flex-direction: column;
gap: var(--mmg-space-1);
}
.mmg-sidebar__category {
font-size: 9px;
font-weight: var(--mmg-font-weight-bold);
text-transform: uppercase;
letter-spacing: 0.1em;
color: var(--mmg-color-text-quaternary);
padding: var(--mmg-space-3) var(--mmg-space-3) var(--mmg-space-1);
}
.mmg-sidebar__item {
display: flex;
align-items: center;
gap: var(--mmg-space-2);
padding: 8px var(--mmg-space-3);
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-secondary);
text-decoration: none;
border-radius: var(--mmg-radius-md);
transition: background var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-sidebar__item:hover {
background: var(--mmg-color-bg-muted);
color: var(--mmg-color-text-primary);
text-decoration: none;
}
.mmg-sidebar__item[aria-current="page"] {
background: var(--mmg-color-accent-soft);
color: var(--mmg-color-accent-strong);
font-weight: var(--mmg-font-weight-semi);
}
.mmg-sidebar__footer {
padding: var(--mmg-space-3);
border-top: 1px solid var(--mmg-color-border-soft);
}
.mmg-app-main {
flex: 1;
display: flex;
flex-direction: column;
min-width: 0;
}
.mmg-topbar {
height: 56px;
background: var(--mmg-color-bg-surface);
border-bottom: 1px solid var(--mmg-color-border);
padding-inline: var(--mmg-space-5);
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--mmg-space-4);
flex-shrink: 0;
}
.mmg-topbar__title {
font-size: var(--mmg-font-size-base);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
}
.mmg-topbar__actions {
display: flex;
align-items: center;
gap: var(--mmg-space-2);
}
/* ─────────────────────────────────────────────
Tabs
───────────────────────────────────────────── */
.mmg-tabs {
display: flex;
border-bottom: 1px solid var(--mmg-color-border);
margin-bottom: var(--mmg-space-5);
gap: 0;
overflow-x: auto;
}
.mmg-tabs__btn {
background: transparent;
border: 0;
padding: var(--mmg-space-3) var(--mmg-space-5);
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-semi);
color: var(--mmg-color-text-tertiary);
cursor: pointer;
border-bottom: 2px solid transparent;
margin-bottom: -1px;
transition: color var(--mmg-duration-fast) var(--mmg-ease-default);
white-space: nowrap;
}
.mmg-tabs__btn:hover { color: var(--mmg-color-text-primary); }
.mmg-tabs__btn[aria-selected="true"] {
color: var(--mmg-color-accent);
border-bottom-color: var(--mmg-color-accent);
}
/* ─────────────────────────────────────────────
Pagination
───────────────────────────────────────────── */
.mmg-pagination {
display: flex;
align-items: center;
gap: 4px;
list-style: none;
padding: 0;
margin: 0;
}
.mmg-pagination li button,
.mmg-pagination li a {
min-width: 36px;
height: 36px;
display: inline-flex;
align-items: center;
justify-content: center;
padding: 0 10px;
border-radius: var(--mmg-radius-md);
background: transparent;
border: 1px solid transparent;
color: var(--mmg-color-text-secondary);
text-decoration: none;
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-medium);
cursor: pointer;
}
.mmg-pagination li button:hover,
.mmg-pagination li a:hover {
background: var(--mmg-color-bg-muted);
text-decoration: none;
}
.mmg-pagination li [aria-current="page"] {
background: var(--mmg-color-accent);
color: var(--mmg-color-accent-on);
border-color: var(--mmg-color-accent);
}
/* ─────────────────────────────────────────────
Avatar
───────────────────────────────────────────── */
.mmg-avatar {
display: inline-flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
border-radius: 50%;
background: var(--mmg-color-accent-soft);
color: var(--mmg-color-accent-strong);
font-size: var(--mmg-font-size-xs);
font-weight: var(--mmg-font-weight-bold);
overflow: hidden;
}
.mmg-avatar img { width: 100%; height: 100%; object-fit: cover; }
.mmg-avatar--sm { width: 28px; height: 28px; font-size: 10px; }
.mmg-avatar--lg { width: 48px; height: 48px; font-size: var(--mmg-font-size-sm); }
.mmg-avatar--xl { width: 64px; height: 64px; font-size: var(--mmg-font-size-base); }
/* ─────────────────────────────────────────────
DataTable (avancée)
───────────────────────────────────────────── */
.mmg-datatable {
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-card);
overflow: hidden;
}
.mmg-datatable__toolbar {
display: flex;
align-items: center;
gap: var(--mmg-space-3);
padding: var(--mmg-space-3) var(--mmg-space-4);
border-bottom: 1px solid var(--mmg-color-border-soft);
background: var(--mmg-color-bg-raised);
}
.mmg-datatable__toolbar-search { flex: 1; max-width: 320px; }
.mmg-datatable__toolbar-actions {
display: flex;
gap: var(--mmg-space-2);
margin-left: auto;
}
.mmg-datatable__scroll {
overflow-x: auto;
}
.mmg-datatable table {
width: 100%;
border-collapse: collapse;
font-size: var(--mmg-font-size-sm);
}
.mmg-datatable th,
.mmg-datatable td {
text-align: left;
padding: var(--mmg-density-padding-y) var(--mmg-density-padding-x);
border-bottom: 1px solid var(--mmg-color-border-soft);
height: var(--mmg-density-row-height);
}
.mmg-datatable--dense th,
.mmg-datatable--dense td {
padding: 4px var(--mmg-space-3);
height: 32px;
}
.mmg-datatable th {
background: var(--mmg-color-bg-muted);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
font-size: var(--mmg-font-size-xs);
text-transform: uppercase;
letter-spacing: 0.04em;
white-space: nowrap;
user-select: none;
position: sticky;
top: 0;
z-index: 1;
}
.mmg-datatable th[data-sortable="true"] {
cursor: pointer;
}
.mmg-datatable th[data-sortable="true"]:hover {
background: var(--mmg-color-bg-subtle);
color: var(--mmg-color-accent);
}
.mmg-datatable__sort-indicator {
display: inline-flex;
margin-left: 4px;
opacity: 0.4;
transition: opacity var(--mmg-duration-fast);
}
.mmg-datatable th[aria-sort] .mmg-datatable__sort-indicator { opacity: 1; color: var(--mmg-color-accent); }
.mmg-datatable tbody tr { transition: background var(--mmg-duration-fast) var(--mmg-ease-default); }
.mmg-datatable tbody tr:hover { background: var(--mmg-color-bg-raised); }
.mmg-datatable tbody tr[data-selected="true"] { background: var(--mmg-color-accent-soft); }
.mmg-datatable tbody tr:last-child td { border-bottom: 0; }
.mmg-datatable__cell--checkbox { width: 40px; padding-right: 0; }
.mmg-datatable__footer {
display: flex;
align-items: center;
justify-content: space-between;
flex-wrap: wrap;
gap: var(--mmg-space-3);
padding: var(--mmg-space-3) var(--mmg-space-4);
border-top: 1px solid var(--mmg-color-border-soft);
background: var(--mmg-color-bg-raised);
font-size: var(--mmg-font-size-xs);
color: var(--mmg-color-text-tertiary);
}
.mmg-datatable__empty {
padding: var(--mmg-space-9) var(--mmg-space-5);
text-align: center;
color: var(--mmg-color-text-tertiary);
}
.mmg-datatable__empty h4 {
font-size: var(--mmg-font-size-base);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
margin: var(--mmg-space-3) 0 var(--mmg-space-1);
}
.mmg-datatable__empty p { font-size: var(--mmg-font-size-sm); margin-bottom: var(--mmg-space-3); }
.mmg-datatable__loading {
padding: var(--mmg-space-6);
display: flex;
flex-direction: column;
gap: var(--mmg-space-3);
align-items: center;
color: var(--mmg-color-text-tertiary);
}
/* ─────────────────────────────────────────────
Command Menu (Cmd+K — palette)
───────────────────────────────────────────── */
.mmg-cmdk-backdrop {
position: fixed;
inset: 0;
background: var(--mmg-color-bg-overlay);
z-index: var(--mmg-z-modal);
display: flex;
align-items: flex-start;
justify-content: center;
padding: 10vh var(--mmg-space-4) var(--mmg-space-4);
animation: mmg-fade-in var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-cmdk {
width: 100%;
max-width: 580px;
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-panel);
box-shadow: var(--mmg-shadow-3);
overflow: hidden;
animation: mmg-modal-in var(--mmg-duration-base) var(--mmg-ease-emphasis);
display: flex;
flex-direction: column;
max-height: 70vh;
}
.mmg-cmdk__input-wrap {
display: flex;
align-items: center;
gap: var(--mmg-space-3);
padding: var(--mmg-space-4) var(--mmg-space-5);
border-bottom: 1px solid var(--mmg-color-border-soft);
}
.mmg-cmdk__input-wrap .mmg-icon { color: var(--mmg-color-text-tertiary); }
.mmg-cmdk__input {
flex: 1;
background: transparent;
border: 0;
outline: 0;
font: inherit;
font-size: var(--mmg-font-size-base);
color: var(--mmg-color-text-primary);
}
.mmg-cmdk__input::placeholder { color: var(--mmg-color-text-quaternary); }
.mmg-cmdk__kbd {
font-size: var(--mmg-font-size-xs);
background: var(--mmg-color-bg-muted);
border: 1px solid var(--mmg-color-border);
border-radius: 4px;
padding: 2px 6px;
color: var(--mmg-color-text-tertiary);
font-family: var(--mmg-font-mono);
}
.mmg-cmdk__list {
flex: 1;
overflow-y: auto;
padding: var(--mmg-space-2);
}
.mmg-cmdk__group-label {
font-size: var(--mmg-font-size-xs);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-quaternary);
text-transform: uppercase;
letter-spacing: 0.06em;
padding: var(--mmg-space-3) var(--mmg-space-3) var(--mmg-space-1);
}
.mmg-cmdk__item {
display: flex;
align-items: center;
gap: var(--mmg-space-3);
padding: 10px 12px;
border-radius: var(--mmg-radius-md);
cursor: pointer;
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-secondary);
}
.mmg-cmdk__item[aria-selected="true"] {
background: var(--mmg-color-accent-soft);
color: var(--mmg-color-accent-strong);
}
.mmg-cmdk__item-shortcut {
margin-left: auto;
display: flex;
gap: 4px;
}
.mmg-cmdk__empty {
padding: var(--mmg-space-7) var(--mmg-space-5);
text-align: center;
color: var(--mmg-color-text-tertiary);
font-size: var(--mmg-font-size-sm);
}
.mmg-cmdk__footer {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--mmg-space-2) var(--mmg-space-4);
border-top: 1px solid var(--mmg-color-border-soft);
background: var(--mmg-color-bg-raised);
font-size: var(--mmg-font-size-xs);
color: var(--mmg-color-text-quaternary);
gap: var(--mmg-space-3);
}
.mmg-cmdk__footer-key {
display: inline-flex;
align-items: center;
gap: 4px;
}
/* ─────────────────────────────────────────────
DatePicker
───────────────────────────────────────────── */
.mmg-datepicker {
position: absolute;
z-index: var(--mmg-z-dropdown);
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-md);
box-shadow: var(--mmg-shadow-2);
padding: var(--mmg-space-3);
width: 304px;
}
.mmg-datepicker__header {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 var(--mmg-space-1) var(--mmg-space-2);
}
.mmg-datepicker__nav {
background: transparent;
border: 0;
width: 32px;
height: 32px;
border-radius: 50%;
cursor: pointer;
display: inline-flex;
align-items: center;
justify-content: center;
color: var(--mmg-color-text-secondary);
}
.mmg-datepicker__nav:hover { background: var(--mmg-color-bg-muted); color: var(--mmg-color-text-primary); }
.mmg-datepicker__title {
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
font-size: var(--mmg-font-size-sm);
}
.mmg-datepicker__weekdays {
display: grid;
grid-template-columns: repeat(7, 1fr);
margin-bottom: var(--mmg-space-1);
}
.mmg-datepicker__weekday {
font-size: 10px;
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-quaternary);
text-align: center;
text-transform: uppercase;
padding: 4px 0;
letter-spacing: 0.04em;
}
.mmg-datepicker__grid {
display: grid;
grid-template-columns: repeat(7, 1fr);
gap: 2px;
}
.mmg-datepicker__day {
height: 36px;
background: transparent;
border: 0;
border-radius: var(--mmg-radius-md);
cursor: pointer;
font: inherit;
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-secondary);
display: flex;
align-items: center;
justify-content: center;
position: relative;
}
.mmg-datepicker__day:hover:not(:disabled) {
background: var(--mmg-color-bg-muted);
color: var(--mmg-color-text-primary);
}
.mmg-datepicker__day--outside {
color: var(--mmg-color-text-quaternary);
}
.mmg-datepicker__day--today {
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-accent);
}
.mmg-datepicker__day--today::after {
content: "";
position: absolute;
bottom: 4px;
width: 4px;
height: 4px;
background: var(--mmg-color-accent);
border-radius: 50%;
}
.mmg-datepicker__day[aria-selected="true"] {
background: var(--mmg-color-accent);
color: var(--mmg-color-accent-on);
font-weight: var(--mmg-font-weight-bold);
}
.mmg-datepicker__day[aria-selected="true"]::after { background: white; }
.mmg-datepicker__day:disabled { opacity: 0.35; cursor: not-allowed; }
/* Range picker — jours entre start et end */
.mmg-datepicker__day--between {
background: var(--mmg-color-accent-soft);
color: var(--mmg-color-accent-strong);
border-radius: 0;
}
.mmg-datepicker__day--endpoint {
background: var(--mmg-color-accent);
color: var(--mmg-color-accent-on);
font-weight: var(--mmg-font-weight-bold);
}
.mmg-datepicker__footer {
display: flex;
justify-content: space-between;
padding: var(--mmg-space-2) var(--mmg-space-1) 0;
border-top: 1px solid var(--mmg-color-border-soft);
margin-top: var(--mmg-space-2);
}
/* ─────────────────────────────────────────────
Table (basique — conservée pour compat)
───────────────────────────────────────────── */
.mmg-table {
width: 100%;
border-collapse: collapse;
font-size: var(--mmg-font-size-sm);
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-card);
overflow: hidden;
}
.mmg-table th,
.mmg-table td {
text-align: left;
padding: var(--mmg-density-padding-y) var(--mmg-density-padding-x);
border-bottom: 1px solid var(--mmg-color-border-soft);
height: var(--mmg-density-row-height);
}
.mmg-table th {
background: var(--mmg-color-bg-muted);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
font-size: var(--mmg-font-size-xs);
text-transform: uppercase;
letter-spacing: 0.04em;
}
.mmg-table tbody tr:hover { background: var(--mmg-color-bg-raised); }
.mmg-table tbody tr:last-child td { border-bottom: 0; }
/* ─────────────────────────────────────────────
Stat card (dashboards)
───────────────────────────────────────────── */
.mmg-stat {
display: flex;
align-items: center;
gap: var(--mmg-space-3);
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-card);
padding: var(--mmg-space-4);
}
.mmg-stat__icon {
width: 40px;
height: 40px;
border-radius: var(--mmg-radius-pill);
background: var(--mmg-color-accent-soft);
color: var(--mmg-color-accent);
display: flex;
align-items: center;
justify-content: center;
font-size: 20px;
}
.mmg-stat__value {
font-size: var(--mmg-font-size-2xl);
font-weight: var(--mmg-font-weight-extra);
color: var(--mmg-color-text-primary);
line-height: 1;
}
.mmg-stat__label {
font-size: var(--mmg-font-size-xs);
color: var(--mmg-color-text-tertiary);
margin-top: 2px;
}
+133
View File
@@ -0,0 +1,133 @@
/* ════════════════════════════════════════════════════════════════
Extras — SegmentedControl, DescriptionList, Sparkline, Kbd
════════════════════════════════════════════════════════════════ */
/* ─────────────────────────────────────────────
SegmentedControl (Apple HIG-style)
───────────────────────────────────────────── */
.mmg-segmented {
display: inline-flex;
padding: 3px;
background: var(--mmg-color-bg-muted);
border-radius: var(--mmg-radius-pill);
gap: 2px;
position: relative;
isolation: isolate;
}
.mmg-segmented--full { display: flex; width: 100%; }
.mmg-segmented__item {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
flex: 1;
padding: 7px 16px;
background: transparent;
border: 0;
border-radius: var(--mmg-radius-pill);
font-family: inherit;
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-medium);
color: var(--mmg-color-text-tertiary);
cursor: pointer;
white-space: nowrap;
/* Touch target */
min-height: 36px;
transition:
background var(--mmg-duration-fast) var(--mmg-ease-default),
color var(--mmg-duration-fast) var(--mmg-ease-default),
box-shadow var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-segmented__item:hover:not(:disabled):not(.mmg-segmented__item--active) {
color: var(--mmg-color-text-primary);
}
.mmg-segmented__item:focus-visible {
outline: 0;
box-shadow: var(--mmg-shadow-focus);
}
.mmg-segmented__item--active {
background: var(--mmg-color-bg-surface);
color: var(--mmg-color-text-primary);
font-weight: var(--mmg-font-weight-semi);
box-shadow: var(--mmg-shadow-1);
}
.mmg-segmented__item:disabled {
color: var(--mmg-color-state-disabled-text);
cursor: not-allowed;
}
.mmg-segmented--sm .mmg-segmented__item { padding: 5px 12px; font-size: var(--mmg-font-size-xs); min-height: 32px; }
.mmg-segmented--lg .mmg-segmented__item { padding: 10px 20px; font-size: var(--mmg-font-size-base); min-height: 44px; }
/* ─────────────────────────────────────────────
DescriptionList (DSFR-like)
───────────────────────────────────────────── */
.mmg-dlist {
margin: 0;
padding: 0;
}
.mmg-dlist__row {
padding: var(--mmg-space-3) 0;
border-bottom: 1px solid var(--mmg-color-border-soft);
}
.mmg-dlist__row:last-child {
border-bottom: 0;
}
.mmg-dlist--horizontal .mmg-dlist__row {
display: grid;
grid-template-columns: minmax(180px, 1fr) 2fr;
gap: var(--mmg-space-4);
align-items: start;
}
.mmg-dlist--vertical .mmg-dlist__row {
display: flex;
flex-direction: column;
gap: 2px;
}
.mmg-dlist__label {
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-semi);
color: var(--mmg-color-text-tertiary);
margin: 0;
}
.mmg-dlist__value {
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-primary);
margin: 0;
}
@media (max-width: 640px) {
.mmg-dlist--horizontal .mmg-dlist__row {
grid-template-columns: 1fr;
gap: 2px;
}
}
/* ─────────────────────────────────────────────
Sparkline
───────────────────────────────────────────── */
.mmg-sparkline {
display: block;
overflow: visible;
}
/* ─────────────────────────────────────────────
Kbd component (override de la base si besoin) —
.mmg-kbd reprend les styles de base sur kbd.
───────────────────────────────────────────── */
.mmg-kbd {
display: inline-block;
padding: 2px 6px;
font-family: var(--mmg-font-mono);
font-size: 0.85em;
font-weight: var(--mmg-font-weight-medium);
color: var(--mmg-color-text-secondary);
background: var(--mmg-color-bg-muted);
border: 1px solid var(--mmg-color-border);
border-bottom-width: 2px;
border-radius: 4px;
line-height: 1;
}
@@ -0,0 +1,123 @@
/* ════════════════════════════════════════════════════════════════
FeatureCard — icône + titre + description + lien.
Variant `glow` ajoute un border-gradient animé au hover (Vercel-style).
════════════════════════════════════════════════════════════════ */
.mmg-feature-card {
position: relative;
display: flex;
flex-direction: column;
gap: var(--mmg-space-3);
padding: var(--mmg-space-6);
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-card);
isolation: isolate;
transition:
transform var(--mmg-duration-base) var(--mmg-ease-emphasis),
border-color var(--mmg-duration-base) var(--mmg-ease-default);
}
.mmg-feature-card:hover {
transform: translateY(-2px);
border-color: var(--mmg-color-border-strong);
}
/* — Icon coloré ——————————————————————————————— */
.mmg-feature-card__icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 48px;
height: 48px;
border-radius: 14px;
margin-bottom: var(--mmg-space-2);
}
.mmg-feature-card__icon--brand { background: var(--mmg-color-accent-soft); color: var(--mmg-color-accent); }
.mmg-feature-card__icon--blue { background: var(--mmg-color-blue-100); color: var(--mmg-color-blue-600); }
.mmg-feature-card__icon--green { background: var(--mmg-color-green-100); color: var(--mmg-color-green-600); }
.mmg-feature-card__icon--amber { background: var(--mmg-color-amber-100); color: var(--mmg-color-amber-600); }
.mmg-feature-card__icon--violet { background: var(--mmg-color-violet-100); color: var(--mmg-color-violet-600); }
.mmg-feature-card__icon--neutral { background: var(--mmg-color-bg-muted); color: var(--mmg-color-text-secondary); }
[data-mmg-theme="dark"] .mmg-feature-card__icon--blue { background: rgba(96, 165, 250, 0.16); color: var(--mmg-color-blue-d-300); }
[data-mmg-theme="dark"] .mmg-feature-card__icon--green { background: rgba(52, 211, 153, 0.16); color: var(--mmg-color-green-d-300); }
[data-mmg-theme="dark"] .mmg-feature-card__icon--amber { background: rgba(251, 191, 36, 0.16); color: var(--mmg-color-amber-d-300); }
[data-mmg-theme="dark"] .mmg-feature-card__icon--violet { background: rgba(167, 139, 250, 0.16); color: var(--mmg-color-violet-d-300); }
.mmg-feature-card__title {
margin: 0;
font-size: var(--mmg-font-size-lg);
font-weight: var(--mmg-font-weight-bold);
letter-spacing: -0.01em;
color: var(--mmg-color-text-primary);
}
.mmg-feature-card__desc {
margin: 0;
font-size: var(--mmg-font-size-sm);
line-height: 1.55;
color: var(--mmg-color-text-tertiary);
}
.mmg-feature-card__link {
margin-top: auto;
display: inline-flex;
align-items: center;
gap: 4px;
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-semi);
color: var(--mmg-color-accent);
text-decoration: none;
transition: gap var(--mmg-duration-fast) var(--mmg-ease-emphasis);
}
.mmg-feature-card__link:hover {
gap: 8px;
text-decoration: none;
}
/* — Variant glow : hover propre (border accent + ombre teintée + lift) ——
L'ancienne version utilisait un conic-gradient masqué qui produisait
un effet fragmenté/coupé selon les browsers (mask-composite: exclude
pas toujours fiable, animation de rotation visible derrière le bord
arrondi). Cette version : bordure accent franche, ombre teintée à 3
niveaux, halo radial subtil interne, micro-lift de l'icône. Sobre,
universel, pas de transform: rotate qui peut "déborder". */
.mmg-feature-card--glow {
transition:
transform var(--mmg-duration-base) var(--mmg-ease-emphasis),
border-color var(--mmg-duration-base) var(--mmg-ease-default),
box-shadow var(--mmg-duration-base) var(--mmg-ease-default);
}
.mmg-feature-card--glow:hover {
transform: translateY(-3px);
border-color: var(--mmg-color-accent);
box-shadow:
0 0 0 1px var(--mmg-color-accent),
0 12px 40px -10px color-mix(in srgb, var(--mmg-color-accent) 38%, transparent),
0 4px 12px -4px color-mix(in srgb, var(--mmg-color-accent) 22%, transparent);
}
.mmg-feature-card--glow .mmg-feature-card__icon {
transition: transform var(--mmg-duration-base) var(--mmg-ease-emphasis);
}
.mmg-feature-card--glow:hover .mmg-feature-card__icon {
transform: scale(1.06);
}
/* Halo radial interne très subtil — donne de la profondeur sans alourdir */
.mmg-feature-card--glow::after {
content: "";
position: absolute;
inset: 0;
border-radius: inherit;
background: radial-gradient(circle at 50% 0%,
color-mix(in srgb, var(--mmg-color-accent) 8%, transparent) 0%,
transparent 60%);
opacity: 0;
transition: opacity var(--mmg-duration-base) var(--mmg-ease-default);
pointer-events: none;
z-index: 0;
}
.mmg-feature-card--glow:hover::after { opacity: 1; }
.mmg-feature-card--glow > * { position: relative; z-index: 1; }
@media (prefers-reduced-motion: reduce) {
.mmg-feature-card--glow:hover { transform: none; }
.mmg-feature-card--glow:hover .mmg-feature-card__icon { transform: none; }
}
+529
View File
@@ -0,0 +1,529 @@
/* ════════════════════════════════════════════════════════════════
Feedback — Alert, Notice, Badge, Toast, Modal, Skeleton
════════════════════════════════════════════════════════════════ */
/* — Alert (contextuel sur la page) ————————— */
.mmg-alert {
display: flex;
align-items: flex-start;
gap: var(--mmg-space-3);
padding: var(--mmg-space-4) var(--mmg-space-5);
border: 1px solid;
border-left-width: 4px;
border-radius: var(--mmg-radius-md);
background: var(--mmg-color-info-soft);
border-color: var(--mmg-color-info-border);
border-left-color: var(--mmg-color-info);
}
.mmg-alert--success {
background: var(--mmg-color-success-soft);
border-color: var(--mmg-color-success-border);
border-left-color: var(--mmg-color-success);
}
.mmg-alert--warning {
background: var(--mmg-color-warning-soft);
border-color: var(--mmg-color-warning-border);
border-left-color: var(--mmg-color-warning);
}
.mmg-alert--danger {
background: var(--mmg-color-danger-soft);
border-color: var(--mmg-color-danger-border);
border-left-color: var(--mmg-color-danger);
}
.mmg-alert__icon {
flex-shrink: 0;
font-size: 20px;
line-height: 1;
margin-top: 2px;
}
.mmg-alert--success .mmg-alert__icon { color: var(--mmg-color-success); }
.mmg-alert--warning .mmg-alert__icon { color: var(--mmg-color-warning); }
.mmg-alert--danger .mmg-alert__icon { color: var(--mmg-color-danger); }
.mmg-alert--info .mmg-alert__icon, .mmg-alert__icon { color: var(--mmg-color-info); }
.mmg-alert__body { flex: 1; min-width: 0; }
.mmg-alert__title {
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
margin-bottom: 2px;
}
.mmg-alert__desc {
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-secondary);
}
.mmg-alert__close {
background: transparent;
border: 0;
cursor: pointer;
color: var(--mmg-color-text-tertiary);
font-size: 18px;
padding: 0;
margin-left: auto;
}
/* — Notice (bandeau pleine largeur) ————————— */
.mmg-notice {
width: 100%;
padding: var(--mmg-space-3) var(--mmg-space-5);
background: var(--mmg-color-accent-soft);
border-bottom: 1px solid var(--mmg-color-accent-border);
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-accent-strong);
text-align: center;
}
.mmg-notice--info { background: var(--mmg-color-info-soft); border-color: var(--mmg-color-info-border); color: var(--mmg-color-info-strong); }
.mmg-notice--warning { background: var(--mmg-color-warning-soft); border-color: var(--mmg-color-warning-border); color: var(--mmg-color-warning-strong); }
.mmg-notice--danger { background: var(--mmg-color-danger-soft); border-color: var(--mmg-color-danger-border); color: var(--mmg-color-danger-strong); }
/* — Badge — refonte modern (Linear / Vercel / Stripe) ——————————————
Plus tight, texte légèrement uppercase tracking, dot indicator
intégré en option, hover lift discret. */
.mmg-badge {
display: inline-flex;
align-items: center;
gap: 6px;
padding: 2px 8px;
font-size: 11px;
font-weight: var(--mmg-font-weight-semi);
letter-spacing: 0.005em;
line-height: 1.4;
border-radius: 6px;
border: 1px solid;
background: var(--mmg-color-bg-muted);
color: var(--mmg-color-text-secondary);
border-color: var(--mmg-color-border);
white-space: nowrap;
vertical-align: middle;
}
/* Variantes "soft" — fond très léger + bordure teintée + texte foncé.
AA respecté sur tous les tones (text strong sur soft donne ≥ 4.5:1). */
.mmg-badge--brand { background: var(--mmg-color-accent-soft); color: var(--mmg-color-accent-strong); border-color: var(--mmg-color-accent-border); }
.mmg-badge--success { background: var(--mmg-color-success-soft); color: var(--mmg-color-success-strong); border-color: var(--mmg-color-success-border); }
.mmg-badge--warning { background: var(--mmg-color-warning-soft); color: var(--mmg-color-warning-strong); border-color: var(--mmg-color-warning-border); }
.mmg-badge--danger { background: var(--mmg-color-danger-soft); color: var(--mmg-color-danger-strong); border-color: var(--mmg-color-danger-border); }
.mmg-badge--info { background: var(--mmg-color-info-soft); color: var(--mmg-color-info-strong); border-color: var(--mmg-color-info-border); }
/* Variant solid — bouton-like, pleine couleur. À réserver pour CTA
discrets / notifications pulse / promo pricing. */
.mmg-badge--solid {
background: var(--mmg-color-accent);
color: var(--mmg-color-accent-on);
border-color: var(--mmg-color-accent);
}
/* Variant outline — pour les badges "neutres" sur fonds chargés. */
.mmg-badge--outline {
background: transparent;
color: var(--mmg-color-text-secondary);
border-color: var(--mmg-color-border-strong);
}
/* Sizes */
.mmg-badge--sm { padding: 1px 6px; font-size: 10px; gap: 4px; }
.mmg-badge--lg { padding: 4px 10px; font-size: var(--mmg-font-size-xs); gap: 6px; }
/* Dot indicator — pour status badges (online, en cours, etc.) */
.mmg-badge__dot {
display: inline-block;
width: 6px;
height: 6px;
border-radius: 50%;
background: currentColor;
flex-shrink: 0;
}
/* Variant "pulse" — anime le dot pour signaler du temps réel */
.mmg-badge__dot--pulse {
position: relative;
}
.mmg-badge__dot--pulse::after {
content: "";
position: absolute;
inset: -3px;
border-radius: 50%;
background: currentColor;
opacity: 0.5;
animation: mmg-badge-pulse 1.6s ease-out infinite;
}
@keyframes mmg-badge-pulse {
0% { transform: scale(0.8); opacity: 0.6; }
100% { transform: scale(1.8); opacity: 0; }
}
@media (prefers-reduced-motion: reduce) {
.mmg-badge__dot--pulse::after { animation: none; opacity: 0; }
}
/* ════════════════════════════════════════════════════════════════
Toasts — pile façon Sonner (architecture absolute + JS-measured)
Chaque toast est en position: absolute, ancré bottom: 0 (positions
bottom-*) ou top: 0 (positions top-*). Le composant React :
- mesure les heights via ResizeObserver
- calcule deux offsets par toast : --mmg-toast-collapsed-y (état repos,
stack-offset × index) et --mmg-toast-expanded-y (somme des heights
précédentes + gap × index)
- fixe la hauteur du region (front-most en repos, somme totale en hover)
Cette technique évite les bugs de margin: -100% (qui se résolvent sur
la largeur, pas la hauteur). Référence : github.com/emilkowalski/sonner.
════════════════════════════════════════════════════════════════ */
.mmg-toast-region {
position: fixed;
z-index: var(--mmg-z-toast);
list-style: none;
padding: 0;
margin: 0;
pointer-events: none;
width: 380px;
max-width: calc(100% - var(--mmg-space-5) * 2);
/* hauteur posée inline par le composant React, transition pour adoucir */
transition: height 320ms var(--mmg-ease-emphasis);
}
.mmg-toast-region--bottom-right { bottom: var(--mmg-space-5); right: var(--mmg-space-5); }
.mmg-toast-region--bottom-left { bottom: var(--mmg-space-5); left: var(--mmg-space-5); }
.mmg-toast-region--top-right { top: var(--mmg-space-5); right: var(--mmg-space-5); }
.mmg-toast-region--top-left { top: var(--mmg-space-5); left: var(--mmg-space-5); }
/* — Toast individuel — design moderne (Sonner / Vercel / Linear) ————————
- Pas de barre colorée à gauche (look 2018 admin panel).
- Indication de severity via la couleur de l'icône uniquement.
- Border subtile + ombre layered (deux niveaux pour la profondeur).
- Padding tight, typo dense.
- backdrop-filter blur en dark pour effet "verre dépoli". */
.mmg-toast {
position: absolute;
left: 0;
right: 0;
display: flex;
align-items: flex-start;
gap: 10px;
padding: 14px 14px 14px 16px;
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: 14px;
box-shadow:
0 1px 1px rgba(0, 0, 0, 0.04),
0 6px 16px -4px rgba(15, 15, 30, 0.10),
0 2px 4px -2px rgba(15, 15, 30, 0.06);
pointer-events: auto;
animation: mmg-toast-in-bottom 360ms var(--mmg-ease-emphasis);
transition:
transform 380ms var(--mmg-ease-emphasis),
opacity 200ms var(--mmg-ease-default);
}
/* Dark : fond légèrement raised + verre dépoli + halo blanc minimal pour
décoller des fonds très sombres. */
[data-mmg-theme="dark"] .mmg-toast {
background: color-mix(in srgb, var(--mmg-color-bg-raised) 90%, transparent);
backdrop-filter: blur(14px) saturate(140%);
-webkit-backdrop-filter: blur(14px) saturate(140%);
border-color: var(--mmg-color-border);
box-shadow:
0 1px 0 rgba(255, 255, 255, 0.04) inset,
0 8px 24px -6px rgba(0, 0, 0, 0.55),
0 2px 6px -2px rgba(0, 0, 0, 0.40);
}
.mmg-toast-region--bottom-right .mmg-toast,
.mmg-toast-region--bottom-left .mmg-toast {
bottom: 0;
transform-origin: bottom center;
/* État repos : décalage vers le haut + scale-down par stack index */
transform: translateY(var(--mmg-toast-collapsed-y, 0))
scale(var(--mmg-toast-scale, 1));
}
.mmg-toast-region--top-right .mmg-toast,
.mmg-toast-region--top-left .mmg-toast {
top: 0;
transform-origin: top center;
transform: translateY(var(--mmg-toast-collapsed-y, 0))
scale(var(--mmg-toast-scale, 1));
animation-name: mmg-toast-in-top;
}
/* Au hover/focus : déploiement, plein scale, offset = somme des heights */
.mmg-toast-region[data-expanded] .mmg-toast {
transform: translateY(var(--mmg-toast-expanded-y, 0)) scale(1);
}
/* Au-delà de visibleCount, on masque (mais le DOM reste pour aria-live) */
.mmg-toast-region:not([data-expanded]) .mmg-toast[data-stack-index="3"],
.mmg-toast-region:not([data-expanded]) .mmg-toast[data-stack-index="4"],
.mmg-toast-region:not([data-expanded]) .mmg-toast[data-stack-index="5"] {
opacity: 0;
pointer-events: none;
}
/* — Severities — plus de border-left coloré. La severity est portée
uniquement par la couleur de l'icône (qui prime déjà aria-role=alert
pour danger). Si on veut un signal redondant : `data-severity` permet
un hint subtil sur la border. */
.mmg-toast[data-severity="success"] { border-color: color-mix(in srgb, var(--mmg-color-success) 28%, var(--mmg-color-border)); }
.mmg-toast[data-severity="warning"] { border-color: color-mix(in srgb, var(--mmg-color-warning) 28%, var(--mmg-color-border)); }
.mmg-toast[data-severity="danger"] { border-color: color-mix(in srgb, var(--mmg-color-danger) 32%, var(--mmg-color-border)); }
.mmg-toast[data-severity="info"] { border-color: color-mix(in srgb, var(--mmg-color-info) 24%, var(--mmg-color-border)); }
/* — Sous-éléments ——————————————————————————————————— */
.mmg-toast__icon {
flex-shrink: 0;
width: 18px;
height: 18px;
margin-top: 1px;
display: inline-flex;
align-items: center;
justify-content: center;
}
.mmg-toast__body { flex: 1; min-width: 0; }
.mmg-toast__title {
font-weight: var(--mmg-font-weight-semi);
color: var(--mmg-color-text-primary);
font-size: var(--mmg-font-size-sm);
line-height: 1.45;
letter-spacing: -0.005em;
}
.mmg-toast__desc {
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-tertiary);
margin-top: 2px;
line-height: 1.45;
}
.mmg-toast__action {
margin-top: 8px;
display: inline-flex;
align-items: center;
padding: 4px 10px;
background: var(--mmg-color-bg-muted);
color: var(--mmg-color-text-primary);
border: 1px solid var(--mmg-color-border);
border-radius: 8px;
font: inherit;
font-size: var(--mmg-font-size-xs);
font-weight: var(--mmg-font-weight-semi);
cursor: pointer;
transition:
background var(--mmg-duration-fast) var(--mmg-ease-default),
border-color var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-toast__action:hover {
background: var(--mmg-color-bg-raised);
border-color: var(--mmg-color-border-strong);
text-decoration: none;
}
.mmg-toast__close {
background: transparent;
border: 0;
cursor: pointer;
color: var(--mmg-color-text-quaternary);
width: 22px;
height: 22px;
padding: 0;
border-radius: 8px;
flex-shrink: 0;
display: inline-flex;
align-items: center;
justify-content: center;
/* Apparition au hover du toast (Sonner-style) */
opacity: 0;
transform: scale(0.92);
transition:
opacity var(--mmg-duration-fast) var(--mmg-ease-default),
transform var(--mmg-duration-fast) var(--mmg-ease-emphasis),
background var(--mmg-duration-fast) var(--mmg-ease-default),
color var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-toast:hover .mmg-toast__close,
.mmg-toast:focus-within .mmg-toast__close {
opacity: 1;
transform: scale(1);
}
/* Front-most en collapsed : close visible direct (pile au repos) */
.mmg-toast-region:not([data-expanded]) .mmg-toast[data-front] .mmg-toast__close {
opacity: 1;
transform: scale(1);
}
.mmg-toast__close:hover {
background: var(--mmg-color-bg-muted);
color: var(--mmg-color-text-primary);
}
.mmg-toast__close:focus-visible {
outline: 0;
box-shadow: var(--mmg-shadow-focus);
opacity: 1;
transform: scale(1);
}
/* — Animations d'entrée ——————————————————————————————————— */
@keyframes mmg-toast-in-bottom {
from {
opacity: 0;
transform: translateY(calc(var(--mmg-toast-collapsed-y, 0) + 32px))
scale(var(--mmg-toast-scale, 1));
}
}
@keyframes mmg-toast-in-top {
from {
opacity: 0;
transform: translateY(calc(var(--mmg-toast-collapsed-y, 0) - 32px))
scale(var(--mmg-toast-scale, 1));
}
}
/* prefers-reduced-motion : on garde la pile en évitant le mouvement.
Tous les toasts sauf le front sont cachés (pas de pile visuelle pulsante). */
@media (prefers-reduced-motion: reduce) {
.mmg-toast {
animation: none;
transition: opacity 120ms;
}
.mmg-toast-region:not([data-expanded]) .mmg-toast:not([data-front]) {
opacity: 0;
pointer-events: none;
}
.mmg-toast-region[data-expanded] .mmg-toast {
/* On affiche tout en colonne via offset déjà calculé en JS */
}
}
/* Forced colors / High Contrast Mode */
@media (forced-colors: active) {
.mmg-toast { border: 1px solid CanvasText; }
}
/* — Modal ————————— */
.mmg-modal-backdrop {
position: fixed;
inset: 0;
background: var(--mmg-color-bg-overlay);
z-index: var(--mmg-z-modal);
display: flex;
align-items: center;
justify-content: center;
padding: var(--mmg-space-4);
animation: mmg-fade-in var(--mmg-duration-base) var(--mmg-ease-default);
}
.mmg-modal {
background: var(--mmg-color-bg-surface);
border-radius: var(--mmg-radius-panel);
box-shadow: var(--mmg-shadow-3);
max-width: 560px;
width: 100%;
max-height: 90vh;
display: flex;
flex-direction: column;
overflow: hidden;
animation: mmg-modal-in var(--mmg-duration-base) var(--mmg-ease-emphasis);
}
.mmg-modal--lg { max-width: 800px; }
.mmg-modal--sm { max-width: 400px; }
.mmg-modal__header {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--mmg-space-5) var(--mmg-space-6);
border-bottom: 1px solid var(--mmg-color-border-soft);
}
.mmg-modal__title {
font-size: var(--mmg-font-size-lg);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
}
.mmg-modal__close {
background: transparent;
border: 0;
cursor: pointer;
color: var(--mmg-color-text-tertiary);
padding: var(--mmg-space-1);
border-radius: 50%;
}
.mmg-modal__close:hover {
background: var(--mmg-color-bg-muted);
color: var(--mmg-color-text-primary);
}
.mmg-modal__body {
padding: var(--mmg-space-6);
overflow-y: auto;
flex: 1;
}
.mmg-modal__footer {
display: flex;
justify-content: flex-end;
gap: var(--mmg-space-2);
padding: var(--mmg-space-4) var(--mmg-space-6);
border-top: 1px solid var(--mmg-color-border-soft);
background: var(--mmg-color-bg-raised);
}
@keyframes mmg-fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes mmg-modal-in {
from { opacity: 0; transform: scale(0.96) translateY(8px); }
to { opacity: 1; transform: scale(1) translateY(0); }
}
/* — Empty state ————————— */
.mmg-empty {
display: flex;
flex-direction: column;
align-items: center;
text-align: center;
padding: var(--mmg-space-9) var(--mmg-space-5);
gap: var(--mmg-space-3);
}
.mmg-empty--compact {
padding: var(--mmg-space-5) var(--mmg-space-4);
gap: var(--mmg-space-2);
}
.mmg-empty__title {
font-size: var(--mmg-font-size-lg);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
margin: var(--mmg-space-2) 0 0;
}
.mmg-empty--compact .mmg-empty__title {
font-size: var(--mmg-font-size-base);
margin-top: var(--mmg-space-1);
}
.mmg-empty__desc {
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-tertiary);
max-width: 480px;
line-height: var(--mmg-line-height-snug);
}
.mmg-empty__actions {
display: flex;
gap: var(--mmg-space-2);
margin-top: var(--mmg-space-2);
flex-wrap: wrap;
justify-content: center;
}
/* — Skeleton (loading) ————————— */
.mmg-skeleton {
background: linear-gradient(90deg, var(--mmg-color-bg-muted) 25%, var(--mmg-color-bg-subtle) 50%, var(--mmg-color-bg-muted) 75%);
background-size: 200% 100%;
border-radius: var(--mmg-radius-sm);
animation: mmg-shimmer 1.4s ease-in-out infinite;
display: block;
}
.mmg-skeleton--text { height: 14px; margin-bottom: 6px; }
.mmg-skeleton--title { height: 24px; margin-bottom: 10px; }
.mmg-skeleton--circle { border-radius: 50%; aspect-ratio: 1; }
@keyframes mmg-shimmer {
0% { background-position: 200% 0; }
100% { background-position: -200% 0; }
}
/* — Spinner ————————— */
.mmg-spinner {
display: inline-block;
width: 20px;
height: 20px;
border: 2px solid var(--mmg-color-accent-border);
border-top-color: var(--mmg-color-accent);
border-radius: 50%;
animation: mmg-spin 0.7s linear infinite;
}
.mmg-spinner--sm { width: 14px; height: 14px; border-width: 1.5px; }
.mmg-spinner--lg { width: 32px; height: 32px; border-width: 3px; }
+257
View File
@@ -0,0 +1,257 @@
/* ════════════════════════════════════════════════════════════════
Form — Field, Input, Select, Textarea, Checkbox, Radio, Switch
════════════════════════════════════════════════════════════════ */
/* — Field group (label + control + hint/error) ————————— */
.mmg-field {
display: flex;
flex-direction: column;
gap: var(--mmg-space-1);
margin-bottom: var(--mmg-space-4);
}
.mmg-field__label {
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-semi);
color: var(--mmg-color-text-primary);
}
.mmg-field__label--required::after {
content: " *";
color: var(--mmg-color-danger);
}
.mmg-field__hint {
font-size: var(--mmg-font-size-xs);
color: var(--mmg-color-text-tertiary);
margin-top: 2px;
}
.mmg-field__error {
font-size: var(--mmg-font-size-xs);
color: var(--mmg-color-danger);
margin-top: 2px;
}
.mmg-field__success {
font-size: var(--mmg-font-size-xs);
color: var(--mmg-color-success);
margin-top: 2px;
}
/* — Input + Textarea + Select shared ————————— */
.mmg-input,
.mmg-textarea,
.mmg-select {
display: block;
width: 100%;
padding: 10px 14px;
font-family: inherit;
font-size: var(--mmg-font-size-sm);
line-height: 1.4;
color: var(--mmg-color-text-primary);
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-md);
transition: border-color var(--mmg-duration-fast) var(--mmg-ease-default),
box-shadow var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-input::placeholder,
.mmg-textarea::placeholder {
color: var(--mmg-color-text-quaternary);
}
.mmg-input:hover:not(:disabled),
.mmg-textarea:hover:not(:disabled),
.mmg-select:hover:not(:disabled) {
border-color: var(--mmg-color-border-strong);
}
.mmg-input:focus,
.mmg-textarea:focus,
.mmg-select:focus {
outline: 0;
border-color: var(--mmg-color-accent);
box-shadow: var(--mmg-shadow-focus);
}
.mmg-input:disabled,
.mmg-textarea:disabled,
.mmg-select:disabled {
background: var(--mmg-color-bg-muted);
color: var(--mmg-color-text-tertiary);
cursor: not-allowed;
}
.mmg-field--error .mmg-input,
.mmg-field--error .mmg-textarea,
.mmg-field--error .mmg-select {
border-color: var(--mmg-color-danger);
}
.mmg-field--error .mmg-input:focus,
.mmg-field--error .mmg-textarea:focus,
.mmg-field--error .mmg-select:focus {
box-shadow: 0 0 0 3px rgba(220, 38, 38, 0.18);
}
.mmg-field--success .mmg-input,
.mmg-field--success .mmg-textarea {
border-color: var(--mmg-color-success);
}
.mmg-textarea {
min-height: 96px;
resize: vertical;
}
/* — Input avec icône préfixe/suffixe ————————— */
.mmg-input-wrap {
position: relative;
display: flex;
align-items: center;
}
.mmg-input-wrap .mmg-input {
padding-left: 38px;
}
.mmg-input-wrap--with-suffix .mmg-input {
padding-right: 38px;
}
.mmg-input-wrap__icon {
position: absolute;
left: 12px;
pointer-events: none;
color: var(--mmg-color-text-tertiary);
}
.mmg-input-wrap__icon--suffix {
left: auto;
right: 12px;
pointer-events: auto;
}
/* — Sizes ————————————————————— */
.mmg-input--sm,
.mmg-select--sm,
.mmg-textarea--sm {
padding: 6px 10px;
font-size: var(--mmg-font-size-xs);
}
.mmg-input--lg,
.mmg-select--lg,
.mmg-textarea--lg {
padding: 14px 18px;
font-size: var(--mmg-font-size-base);
}
/* — Select natif arrow ————————— */
.mmg-select {
appearance: none;
background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='%237875A1' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'/%3E%3C/svg%3E");
background-repeat: no-repeat;
background-position: right 12px center;
background-size: 16px;
padding-right: 36px;
}
/* — Checkbox + Radio ————————————————————— */
.mmg-check {
display: inline-flex;
align-items: flex-start;
gap: var(--mmg-space-2);
cursor: pointer;
user-select: none;
}
.mmg-check__input {
appearance: none;
flex-shrink: 0;
width: 18px;
height: 18px;
margin: 0;
background: var(--mmg-color-bg-surface);
border: 1.5px solid var(--mmg-color-border-strong);
border-radius: 4px;
transition: background var(--mmg-duration-fast) var(--mmg-ease-default),
border-color var(--mmg-duration-fast) var(--mmg-ease-default);
cursor: pointer;
position: relative;
}
.mmg-check__input[type="radio"] {
border-radius: 50%;
}
.mmg-check__input:hover { border-color: var(--mmg-color-accent); }
.mmg-check__input:focus-visible {
outline: 0;
box-shadow: var(--mmg-shadow-focus);
}
.mmg-check__input:checked {
background: var(--mmg-color-accent);
border-color: var(--mmg-color-accent);
}
.mmg-check__input[type="checkbox"]:checked::after {
content: "";
position: absolute;
inset: 0;
background: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='20 6 9 17 4 12'/%3E%3C/svg%3E") center/12px no-repeat;
}
.mmg-check__input[type="radio"]:checked::after {
content: "";
position: absolute;
inset: 4px;
background: white;
border-radius: 50%;
}
.mmg-check__input:disabled {
cursor: not-allowed;
opacity: 0.5;
}
.mmg-check__label {
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-secondary);
line-height: 1.4;
}
/* — Switch ————————————————————— */
.mmg-switch {
display: inline-flex;
align-items: center;
gap: var(--mmg-space-2);
cursor: pointer;
user-select: none;
}
.mmg-switch__input {
appearance: none;
width: 36px;
height: 20px;
background: var(--mmg-color-border-strong);
border-radius: 9999px;
position: relative;
transition: background var(--mmg-duration-fast) var(--mmg-ease-default);
cursor: pointer;
}
.mmg-switch__input::after {
content: "";
position: absolute;
top: 2px;
left: 2px;
width: 16px;
height: 16px;
background: white;
border-radius: 50%;
transition: transform var(--mmg-duration-fast) var(--mmg-ease-emphasis);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);
}
.mmg-switch__input:checked {
background: var(--mmg-color-accent);
}
.mmg-switch__input:checked::after {
transform: translateX(16px);
}
.mmg-switch__input:focus-visible {
outline: 0;
box-shadow: var(--mmg-shadow-focus);
}
.mmg-switch__input:disabled { cursor: not-allowed; opacity: 0.5; }
/* — Fieldset ————————————————————— */
.mmg-fieldset {
border: 0;
padding: 0;
margin: 0 0 var(--mmg-space-6);
}
.mmg-fieldset__legend {
font-size: var(--mmg-font-size-base);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
margin-bottom: var(--mmg-space-4);
}
@@ -0,0 +1,51 @@
/* ════════════════════════════════════════════════════════════════
HoverCard — preview riche au survol (Radix UI HoverCard).
Plus large que Tooltip, contenu structuré, animation douce.
════════════════════════════════════════════════════════════════ */
.mmg-hover-card {
z-index: var(--mmg-z-tooltip);
width: 320px;
max-width: calc(100vw - 32px);
padding: var(--mmg-space-4);
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: 14px;
box-shadow:
0 1px 1px rgba(0, 0, 0, 0.04),
0 12px 32px -6px rgba(15, 15, 30, 0.16),
0 4px 8px -2px rgba(15, 15, 30, 0.08);
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-primary);
animation: mmg-hover-card-in 220ms var(--mmg-ease-emphasis);
}
.mmg-hover-card[data-state="closed"] {
animation: mmg-hover-card-out 160ms var(--mmg-ease-default);
}
[data-mmg-theme="dark"] .mmg-hover-card {
background: color-mix(in srgb, var(--mmg-color-bg-raised) 92%, transparent);
backdrop-filter: blur(12px) saturate(140%);
-webkit-backdrop-filter: blur(12px) saturate(140%);
box-shadow:
0 1px 0 rgba(255, 255, 255, 0.04) inset,
0 12px 32px -6px rgba(0, 0, 0, 0.55),
0 4px 8px -2px rgba(0, 0, 0, 0.40);
}
.mmg-hover-card__arrow {
fill: var(--mmg-color-bg-surface);
filter: drop-shadow(0 -1px 0 var(--mmg-color-border));
}
[data-mmg-theme="dark"] .mmg-hover-card__arrow {
fill: var(--mmg-color-bg-raised);
}
@keyframes mmg-hover-card-in {
from { opacity: 0; transform: translateY(-4px) scale(0.98); }
}
@keyframes mmg-hover-card-out {
to { opacity: 0; transform: translateY(-4px) scale(0.98); }
}
@media (prefers-reduced-motion: reduce) {
.mmg-hover-card { animation: none !important; }
}
+453
View File
@@ -0,0 +1,453 @@
/* ════════════════════════════════════════════════════════════════
Layout — Container, Grid, Stack, Card, Tile
════════════════════════════════════════════════════════════════ */
.mmg-container {
width: 100%;
max-width: var(--mmg-container-max);
margin-inline: auto;
padding-inline: var(--mmg-space-5);
}
.mmg-container--narrow { max-width: var(--mmg-container-narrow); }
.mmg-container--wide { max-width: var(--mmg-container-wide); }
.mmg-container--fluid { max-width: none; }
@media (min-width: 768px) {
.mmg-container { padding-inline: var(--mmg-space-7); }
}
/* — Grid responsive ————————————————————————— */
.mmg-grid {
display: grid;
gap: var(--mmg-space-5);
grid-template-columns: repeat(12, minmax(0, 1fr));
}
.mmg-grid--gap-sm { gap: var(--mmg-space-3); }
.mmg-grid--gap-lg { gap: var(--mmg-space-7); }
.mmg-col-1 { grid-column: span 1; }
.mmg-col-2 { grid-column: span 2; }
.mmg-col-3 { grid-column: span 3; }
.mmg-col-4 { grid-column: span 4; }
.mmg-col-5 { grid-column: span 5; }
.mmg-col-6 { grid-column: span 6; }
.mmg-col-7 { grid-column: span 7; }
.mmg-col-8 { grid-column: span 8; }
.mmg-col-9 { grid-column: span 9; }
.mmg-col-10 { grid-column: span 10; }
.mmg-col-11 { grid-column: span 11; }
.mmg-col-12 { grid-column: span 12; }
@media (max-width: 767px) {
.mmg-grid { grid-template-columns: 1fr; }
[class*="mmg-col-"] { grid-column: 1 / -1; }
}
/* — Stack vertical ————————————————————————— */
.mmg-stack {
display: flex;
flex-direction: column;
gap: var(--mmg-space-4);
}
.mmg-stack--xs { gap: var(--mmg-space-1); }
.mmg-stack--sm { gap: var(--mmg-space-2); }
.mmg-stack--md { gap: var(--mmg-space-4); }
.mmg-stack--lg { gap: var(--mmg-space-6); }
.mmg-stack--xl { gap: var(--mmg-space-8); }
/* — Inline horizontal ————————————————————————— */
.mmg-inline {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: var(--mmg-space-3);
}
.mmg-inline--end { justify-content: flex-end; }
.mmg-inline--between { justify-content: space-between; }
.mmg-inline--center { justify-content: center; }
/* — Section ————————————————————————— */
.mmg-section {
padding-block: var(--mmg-space-10);
}
.mmg-section--sm { padding-block: var(--mmg-space-7); }
.mmg-section--lg { padding-block: var(--mmg-space-12); }
.mmg-section--surface { background: var(--mmg-color-bg-surface); }
.mmg-section--muted { background: var(--mmg-color-bg-muted); }
.mmg-section--brand-soft { background: var(--mmg-color-accent-soft); }
/* — Card ————————————————————————— */
.mmg-card {
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-card);
padding: var(--mmg-space-6);
box-shadow: var(--mmg-shadow-1);
transition: box-shadow var(--mmg-duration-base) var(--mmg-ease-default),
transform var(--mmg-duration-base) var(--mmg-ease-default);
}
.mmg-card--raised { box-shadow: var(--mmg-shadow-2); }
.mmg-card--flat { box-shadow: none; }
.mmg-card--no-padding { padding: 0; }
.mmg-card__header {
display: flex;
align-items: flex-start;
justify-content: space-between;
margin-bottom: var(--mmg-space-4);
gap: var(--mmg-space-3);
}
.mmg-card__title {
font-size: var(--mmg-font-size-lg);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
}
.mmg-card__desc {
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-tertiary);
}
.mmg-card__footer {
margin-top: var(--mmg-space-5);
padding-top: var(--mmg-space-4);
border-top: 1px solid var(--mmg-color-border-soft);
}
/* — Tile (carte cliquable, style DSFR + hover soigné) ——————————— */
.mmg-tile {
position: relative;
display: flex;
flex-direction: column;
gap: var(--mmg-space-3);
padding: var(--mmg-space-6);
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-card);
box-shadow: var(--mmg-shadow-1);
text-decoration: none;
color: inherit;
overflow: hidden;
isolation: isolate;
transition:
transform var(--mmg-duration-base) var(--mmg-ease-emphasis),
box-shadow var(--mmg-duration-base) var(--mmg-ease-default),
border-color var(--mmg-duration-base) var(--mmg-ease-default);
}
/* Liseré rose qui se révèle en haut au hover */
.mmg-tile::before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
height: 4px;
background: linear-gradient(90deg, var(--mmg-color-accent) 0%, var(--mmg-color-accent-strong) 100%);
transform: scaleX(0);
transform-origin: left center;
transition: transform var(--mmg-duration-base) var(--mmg-ease-emphasis);
z-index: 1;
}
.mmg-tile:hover {
transform: translateY(-4px);
box-shadow: var(--mmg-shadow-3);
border-color: var(--mmg-color-accent-border);
text-decoration: none;
color: inherit;
}
.mmg-tile:hover::before {
transform: scaleX(1);
}
.mmg-tile:hover .mmg-tile__title {
color: var(--mmg-color-accent);
}
.mmg-tile:hover .mmg-tile__arrow {
transform: translateX(4px);
opacity: 1;
}
.mmg-tile:active { transform: translateY(-1px); }
.mmg-tile__icon {
width: 48px;
height: 48px;
border-radius: var(--mmg-radius-icon);
display: flex;
align-items: center;
justify-content: center;
background: var(--mmg-color-accent-soft);
color: var(--mmg-color-accent);
font-size: 22px;
flex-shrink: 0;
}
.mmg-tile__pictogram {
width: 80px;
height: 80px;
margin-bottom: var(--mmg-space-2);
flex-shrink: 0;
}
/* — IconBlock (carré coloré avec icône, alternative aux pictos) ——— */
.mmg-iconblock {
display: inline-flex;
align-items: center;
justify-content: center;
width: 56px;
height: 56px;
border-radius: 16px;
background: var(--mmg-color-accent-soft);
color: var(--mmg-color-accent);
font-size: 26px;
flex-shrink: 0;
position: relative;
transition:
background var(--mmg-duration-base) var(--mmg-ease-default),
transform var(--mmg-duration-base) var(--mmg-ease-emphasis);
}
.mmg-iconblock--xs { width: 32px; height: 32px; border-radius: 10px; font-size: 16px; }
.mmg-iconblock--sm { width: 40px; height: 40px; border-radius: 12px; font-size: 20px; }
.mmg-iconblock--md { width: 56px; height: 56px; border-radius: 16px; font-size: 26px; }
.mmg-iconblock--lg { width: 72px; height: 72px; border-radius: 20px; font-size: 32px; }
.mmg-iconblock--xl { width: 96px; height: 96px; border-radius: 24px; font-size: 44px; }
.mmg-iconblock--brand { background: var(--mmg-color-accent-soft); color: var(--mmg-color-accent); }
.mmg-iconblock--success { background: var(--mmg-color-success-soft); color: var(--mmg-color-success); }
.mmg-iconblock--warning { background: var(--mmg-color-warning-soft); color: var(--mmg-color-warning); }
.mmg-iconblock--danger { background: var(--mmg-color-danger-soft); color: var(--mmg-color-danger); }
.mmg-iconblock--info { background: var(--mmg-color-info-soft); color: var(--mmg-color-info); }
.mmg-iconblock--neutral { background: var(--mmg-color-bg-muted); color: var(--mmg-color-text-secondary); }
/* Variant "filled" — fond plein, icône inverse. Ombre teintée via
color-mix sur l'accent courant pour s'adapter au preset user et au dark. */
.mmg-iconblock--filled {
background: var(--mmg-color-accent);
color: var(--mmg-color-accent-on);
box-shadow:
0 2px 6px color-mix(in srgb, var(--mmg-color-accent) 25%, transparent),
0 4px 12px color-mix(in srgb, var(--mmg-color-accent) 18%, transparent);
}
.mmg-iconblock--filled.mmg-iconblock--success {
background: var(--mmg-color-success); color: #fff;
box-shadow: 0 2px 6px color-mix(in srgb, var(--mmg-color-success) 25%, transparent);
}
.mmg-iconblock--filled.mmg-iconblock--warning {
background: var(--mmg-color-warning); color: #fff;
box-shadow: 0 2px 6px color-mix(in srgb, var(--mmg-color-warning) 25%, transparent);
}
.mmg-iconblock--filled.mmg-iconblock--danger {
background: var(--mmg-color-danger); color: #fff;
box-shadow: 0 2px 6px color-mix(in srgb, var(--mmg-color-danger) 25%, transparent);
}
.mmg-iconblock--filled.mmg-iconblock--info {
background: var(--mmg-color-info); color: #fff;
box-shadow: 0 2px 6px color-mix(in srgb, var(--mmg-color-info) 25%, transparent);
}
/* Variant "outline" — bordure colorée */
.mmg-iconblock--outline {
background: transparent;
border: 2px solid currentColor;
}
/* Variant "gradient" — dégradé accent. Ombre teintée via color-mix. */
.mmg-iconblock--gradient {
background: linear-gradient(135deg, var(--mmg-color-accent) 0%, var(--mmg-color-accent-strong) 100%);
color: var(--mmg-color-accent-on);
box-shadow:
0 4px 12px color-mix(in srgb, var(--mmg-color-accent) 25%, transparent),
inset 0 1px 0 rgba(255, 255, 255, 0.18);
}
/* Animation au hover du parent .mmg-tile */
.mmg-tile:hover .mmg-iconblock { transform: scale(1.05); }
.mmg-tile__title {
font-size: var(--mmg-font-size-lg);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
transition: color var(--mmg-duration-fast) var(--mmg-ease-default);
display: flex;
align-items: center;
gap: var(--mmg-space-2);
}
.mmg-tile__arrow {
display: inline-flex;
opacity: 0;
transform: translateX(-4px);
transition:
transform var(--mmg-duration-base) var(--mmg-ease-emphasis),
opacity var(--mmg-duration-base) var(--mmg-ease-default);
color: var(--mmg-color-accent);
}
.mmg-tile__desc {
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-tertiary);
line-height: var(--mmg-line-height-snug);
}
.mmg-tile--horizontal {
flex-direction: row;
align-items: flex-start;
}
.mmg-tile--horizontal .mmg-tile__pictogram {
margin-bottom: 0;
}
/* — Variantes de taille ————————————————————— */
.mmg-tile--sm {
padding: var(--mmg-space-4);
gap: var(--mmg-space-2);
}
.mmg-tile--sm .mmg-tile__title {
font-size: var(--mmg-font-size-base);
}
.mmg-tile--sm .mmg-tile__desc {
font-size: var(--mmg-font-size-xs);
}
.mmg-tile--sm .mmg-tile__icon {
width: 36px;
height: 36px;
font-size: 18px;
border-radius: 10px;
}
.mmg-tile--sm .mmg-tile__pictogram {
width: 56px;
height: 56px;
}
.mmg-tile--lg {
padding: var(--mmg-space-7);
gap: var(--mmg-space-4);
}
.mmg-tile--lg .mmg-tile__title {
font-size: var(--mmg-font-size-xl);
}
.mmg-tile--lg .mmg-tile__desc {
font-size: var(--mmg-font-size-base);
}
.mmg-tile--lg .mmg-tile__icon {
width: 64px;
height: 64px;
font-size: 28px;
border-radius: 16px;
}
.mmg-tile--lg .mmg-tile__pictogram {
width: 96px;
height: 96px;
}
/* ════════════════════════════════════════════════════════════════
Hero — landing
Light : gradient saturé accent → accent-strong, texte accent-on (blanc).
Dark : SURFACE NEUTRE + halos accent diffus aux coins. Le pink-on-pink
en dark était inutilisable (texte washed-out, boutons tonal invisibles).
On garde la marque via les glows, pas en saturant tout l'espace.
════════════════════════════════════════════════════════════════ */
.mmg-hero {
position: relative;
padding-block: var(--mmg-space-12);
background: linear-gradient(135deg, var(--mmg-color-accent) 0%, var(--mmg-color-accent-strong) 100%);
color: var(--mmg-color-accent-on);
overflow: hidden;
}
.mmg-hero__title {
font-size: var(--mmg-font-size-5xl);
font-weight: var(--mmg-font-weight-extra);
letter-spacing: -0.02em;
color: var(--mmg-color-accent-on);
margin-bottom: var(--mmg-space-4);
}
.mmg-hero__lead {
font-size: var(--mmg-font-size-xl);
color: var(--mmg-color-accent-on);
opacity: 0.92;
max-width: 640px;
margin-bottom: var(--mmg-space-6);
}
@media (max-width: 767px) {
.mmg-hero__title { font-size: var(--mmg-font-size-4xl); }
.mmg-hero__lead { font-size: var(--mmg-font-size-lg); }
}
/* — Dark : surface neutre + glow accent en radial gradients ———————— */
[data-mmg-theme="dark"] .mmg-hero {
background:
radial-gradient(circle at 18% 8%,
color-mix(in srgb, var(--mmg-color-accent) 28%, transparent) 0%,
transparent 45%),
radial-gradient(circle at 88% 92%,
color-mix(in srgb, var(--mmg-color-accent) 18%, transparent) 0%,
transparent 55%),
var(--mmg-color-bg-surface);
color: var(--mmg-color-text-primary);
}
[data-mmg-theme="dark"] .mmg-hero__title {
color: var(--mmg-color-text-primary);
}
[data-mmg-theme="dark"] .mmg-hero__lead {
color: var(--mmg-color-text-secondary);
opacity: 1;
}
/* Liseré subtil en bas du Hero dark pour séparer du contenu suivant */
[data-mmg-theme="dark"] .mmg-hero::after {
content: "";
position: absolute;
inset: auto 0 0 0;
height: 1px;
background: linear-gradient(90deg, transparent, var(--mmg-color-border), transparent);
}
/* — Boutons dans le Hero — restylés selon le contexte —————————————
Light Hero (fond accent saturé) : tonal et ghost étaient illisibles
parce qu'ils héritaient des accent-soft / accent-strong → rose sur rose.
On les bascule sur fond accent-on (blanc) translucide. */
.mmg-hero .mmg-btn--tonal {
background: color-mix(in srgb, var(--mmg-color-accent-on) 22%, transparent);
color: var(--mmg-color-accent-on);
border-color: color-mix(in srgb, var(--mmg-color-accent-on) 18%, transparent);
}
.mmg-hero .mmg-btn--tonal:hover:not(:disabled) {
background: color-mix(in srgb, var(--mmg-color-accent-on) 32%, transparent);
color: var(--mmg-color-accent-on);
}
.mmg-hero .mmg-btn--tonal::before {
background: var(--mmg-color-accent-on);
}
.mmg-hero .mmg-btn--ghost {
color: var(--mmg-color-accent-on);
border: 1px solid color-mix(in srgb, var(--mmg-color-accent-on) 35%, transparent);
}
.mmg-hero .mmg-btn--ghost:hover:not(:disabled) {
color: var(--mmg-color-accent-on);
background: color-mix(in srgb, var(--mmg-color-accent-on) 12%, transparent);
}
.mmg-hero .mmg-btn--ghost::before {
background: var(--mmg-color-accent-on);
}
/* Dark Hero (fond surface neutre) : on revient aux variants standards.
Le fond n'est plus saturé donc tonal et ghost reprennent leur look
normal et restent lisibles. */
[data-mmg-theme="dark"] .mmg-hero .mmg-btn--tonal {
background: var(--mmg-color-accent-soft);
color: var(--mmg-color-accent-strong);
border-color: var(--mmg-color-accent-border);
}
[data-mmg-theme="dark"] .mmg-hero .mmg-btn--tonal:hover:not(:disabled) {
background: color-mix(in srgb, var(--mmg-color-accent) 24%, transparent);
color: var(--mmg-color-accent-strong);
}
[data-mmg-theme="dark"] .mmg-hero .mmg-btn--ghost {
color: var(--mmg-color-text-secondary);
border: 1px solid transparent;
}
[data-mmg-theme="dark"] .mmg-hero .mmg-btn--ghost:hover:not(:disabled) {
color: var(--mmg-color-text-primary);
background: var(--mmg-color-bg-muted);
border-color: var(--mmg-color-border);
}
/* — Divider ————————————————————————— */
.mmg-divider {
height: 1px;
background: var(--mmg-color-border-soft);
border: 0;
margin: var(--mmg-space-5) 0;
}
+109
View File
@@ -0,0 +1,109 @@
/* ════════════════════════════════════════════════════════════════
MetricCard — KPI avec valeur, delta coloré, sparkline.
Pattern Linear / Vercel / Stripe Dashboard.
════════════════════════════════════════════════════════════════ */
.mmg-metric-card {
position: relative;
display: flex;
flex-direction: column;
gap: var(--mmg-space-2);
padding: var(--mmg-space-5);
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-card);
text-decoration: none;
color: inherit;
font: inherit;
text-align: left;
overflow: hidden;
transition:
border-color var(--mmg-duration-base) var(--mmg-ease-default),
transform var(--mmg-duration-base) var(--mmg-ease-emphasis),
box-shadow var(--mmg-duration-base) var(--mmg-ease-default);
}
.mmg-metric-card--interactive {
cursor: pointer;
}
.mmg-metric-card--interactive:hover {
border-color: var(--mmg-color-border-strong);
transform: translateY(-2px);
box-shadow: var(--mmg-shadow-2);
}
.mmg-metric-card--interactive:focus-visible {
outline: 0;
border-color: var(--mmg-color-accent);
box-shadow: var(--mmg-shadow-focus);
}
.mmg-metric-card__head {
display: inline-flex;
align-items: center;
gap: var(--mmg-space-2);
color: var(--mmg-color-text-tertiary);
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-medium);
}
.mmg-metric-card__icon {
display: inline-flex;
align-items: center;
justify-content: center;
width: 24px;
height: 24px;
border-radius: 8px;
background: var(--mmg-color-bg-muted);
color: var(--mmg-color-text-secondary);
}
.mmg-metric-card__value {
font-size: var(--mmg-font-size-3xl);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
letter-spacing: -0.02em;
line-height: 1.1;
font-variant-numeric: tabular-nums;
}
.mmg-metric-card__footer {
display: inline-flex;
align-items: center;
gap: var(--mmg-space-2);
flex-wrap: wrap;
font-size: var(--mmg-font-size-xs);
}
.mmg-metric-card__delta {
display: inline-flex;
align-items: center;
gap: 4px;
padding: 2px 8px;
border-radius: var(--mmg-radius-pill);
font-weight: var(--mmg-font-weight-semi);
font-variant-numeric: tabular-nums;
}
.mmg-metric-card__delta--success {
background: var(--mmg-color-success-soft);
color: var(--mmg-color-success-strong);
}
.mmg-metric-card__delta--danger {
background: var(--mmg-color-danger-soft);
color: var(--mmg-color-danger-strong);
}
.mmg-metric-card__delta--neutral {
background: var(--mmg-color-bg-muted);
color: var(--mmg-color-text-secondary);
}
.mmg-metric-card__delta--rotated svg,
.mmg-metric-card__delta--rotated .mmg-icon {
transform: rotate(90deg);
}
.mmg-metric-card__period {
color: var(--mmg-color-text-quaternary);
}
.mmg-metric-card__sparkline {
margin-top: var(--mmg-space-2);
height: 48px;
display: flex;
align-items: stretch;
}
.mmg-metric-card__sparkline > * { width: 100%; }
+289
View File
@@ -0,0 +1,289 @@
/* ════════════════════════════════════════════════════════════════
Overlays — Tooltip, Popover, Dialog, Menu (Radix-backed)
Les composants Radix posent leur propre positionnement via inline-styles
et data-attributes. Nos sélecteurs ciblent les classes mmg-* sans
override de position/transform.
data-state attributes Radix : "open"/"closed"/"delayed-open"
data-side : "top"/"right"/"bottom"/"left"
data-align : "start"/"center"/"end"
════════════════════════════════════════════════════════════════ */
/* — Tooltip ——————————————————————————————————— */
.mmg-tooltip {
z-index: var(--mmg-z-tooltip);
padding: var(--mmg-space-2) var(--mmg-space-3);
font-size: var(--mmg-font-size-xs);
font-weight: var(--mmg-font-weight-medium);
line-height: 1.4;
color: var(--mmg-color-text-inverse);
background: var(--mmg-color-text-primary);
border-radius: var(--mmg-radius-sm);
box-shadow: var(--mmg-shadow-2);
user-select: none;
pointer-events: none;
max-width: 280px;
animation: mmg-tooltip-in 120ms var(--mmg-ease-emphasis);
}
.mmg-tooltip[data-state="closed"] {
animation: mmg-tooltip-out 100ms var(--mmg-ease-default);
}
.mmg-tooltip__arrow {
fill: var(--mmg-color-text-primary);
}
@keyframes mmg-tooltip-in {
from { opacity: 0; transform: scale(0.96); }
to { opacity: 1; transform: scale(1); }
}
@keyframes mmg-tooltip-out {
to { opacity: 0; transform: scale(0.96); }
}
/* — Popover ——————————————————————————————————— */
.mmg-popover {
z-index: var(--mmg-z-dropdown);
min-width: 220px;
padding: var(--mmg-space-3);
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-md);
box-shadow: var(--mmg-shadow-3);
animation: mmg-popover-in 160ms var(--mmg-ease-emphasis);
}
.mmg-popover[data-state="closed"] {
animation: mmg-popover-out 120ms var(--mmg-ease-default);
}
.mmg-popover:focus-visible {
outline: 0;
}
.mmg-popover__arrow {
fill: var(--mmg-color-bg-surface);
/* Bordure de l'arrow : Radix permet via stroke */
filter: drop-shadow(0 -1px 0 var(--mmg-color-border));
}
@keyframes mmg-popover-in {
from { opacity: 0; transform: translateY(-4px) scale(0.98); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes mmg-popover-out {
to { opacity: 0; transform: translateY(-4px) scale(0.98); }
}
/* — Dialog (Radix Modal) ——————————————————————————————————— */
.mmg-dialog__overlay {
position: fixed;
inset: 0;
z-index: var(--mmg-z-modal);
background: var(--mmg-color-bg-overlay);
backdrop-filter: blur(2px);
animation: mmg-dialog-overlay-in 160ms var(--mmg-ease-default);
}
.mmg-dialog__overlay[data-state="closed"] {
animation: mmg-dialog-overlay-out 120ms var(--mmg-ease-default);
}
@keyframes mmg-dialog-overlay-in {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes mmg-dialog-overlay-out {
to { opacity: 0; }
}
.mmg-dialog {
position: fixed;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
z-index: calc(var(--mmg-z-modal) + 1);
display: flex;
flex-direction: column;
width: calc(100% - var(--mmg-space-6));
max-height: calc(100dvh - var(--mmg-space-9));
background: var(--mmg-color-bg-surface);
border-radius: var(--mmg-radius-card);
box-shadow: var(--mmg-shadow-3);
animation: mmg-dialog-in 200ms var(--mmg-ease-emphasis);
}
.mmg-dialog[data-state="closed"] {
animation: mmg-dialog-out 150ms var(--mmg-ease-default);
}
.mmg-dialog:focus-visible {
outline: 0;
}
.mmg-dialog--sm { max-width: 420px; }
.mmg-dialog--md { max-width: 560px; }
.mmg-dialog--lg { max-width: 720px; }
.mmg-dialog--xl { max-width: 960px; }
.mmg-dialog--full {
max-width: none;
width: calc(100% - var(--mmg-space-6));
height: calc(100dvh - var(--mmg-space-9));
}
.mmg-dialog__header {
display: flex;
align-items: center;
justify-content: space-between;
gap: var(--mmg-space-3);
padding: var(--mmg-space-5) var(--mmg-space-6) 0;
}
.mmg-dialog__title {
margin: 0;
font-size: var(--mmg-font-size-xl);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
}
.mmg-dialog__description {
padding: var(--mmg-space-2) var(--mmg-space-6) 0;
margin: 0;
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-tertiary);
}
.mmg-dialog__body {
flex: 1 1 auto;
padding: var(--mmg-space-4) var(--mmg-space-6);
overflow-y: auto;
}
.mmg-dialog__body:empty { padding: 0; }
.mmg-dialog__footer {
padding: var(--mmg-space-4) var(--mmg-space-6) var(--mmg-space-5);
border-top: 1px solid var(--mmg-color-border-soft);
}
.mmg-dialog__close {
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
padding: 0;
background: transparent;
color: var(--mmg-color-text-tertiary);
border: 0;
border-radius: 50%;
cursor: pointer;
transition: background var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-dialog__close:hover { background: var(--mmg-color-bg-muted); color: var(--mmg-color-text-primary); }
.mmg-dialog__close:focus-visible {
outline: 0;
box-shadow: var(--mmg-shadow-focus);
}
@keyframes mmg-dialog-in {
from { opacity: 0; transform: translate(-50%, -48%) scale(0.96); }
to { opacity: 1; transform: translate(-50%, -50%) scale(1); }
}
@keyframes mmg-dialog-out {
to { opacity: 0; transform: translate(-50%, -48%) scale(0.96); }
}
/* — Menu (DropdownMenu Radix) ——————————————————————————————————— */
/* Note : .mmg-menu existait déjà dans chrome.css (legacy) — on enrichit
pour Radix sans casser les anciens usages. */
.mmg-menu {
z-index: var(--mmg-z-dropdown);
min-width: 220px;
padding: var(--mmg-space-1);
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-md);
box-shadow: var(--mmg-shadow-2);
animation: mmg-popover-in 140ms var(--mmg-ease-emphasis);
}
.mmg-menu[data-state="closed"] {
animation: mmg-popover-out 100ms var(--mmg-ease-default);
}
.mmg-menu__item {
display: flex;
align-items: center;
gap: var(--mmg-space-2);
width: 100%;
padding: var(--mmg-space-2) var(--mmg-space-3);
background: transparent;
color: var(--mmg-color-text-primary);
border: 0;
border-radius: var(--mmg-radius-sm);
font-size: var(--mmg-font-size-sm);
text-align: left;
text-decoration: none;
cursor: pointer;
user-select: none;
outline: 0;
transition: background var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-menu__item[data-highlighted],
.mmg-menu__item.mmg-menu__item--active,
.mmg-menu__item:hover:not([data-disabled]) {
background: var(--mmg-color-bg-muted);
}
.mmg-menu__item[data-disabled],
.mmg-menu__item[aria-disabled="true"] {
color: var(--mmg-color-text-quaternary);
cursor: not-allowed;
pointer-events: none;
}
.mmg-menu__item--danger {
color: var(--mmg-color-danger);
}
.mmg-menu__item--danger[data-highlighted],
.mmg-menu__item--danger:hover {
background: var(--mmg-color-danger-soft);
}
.mmg-menu__divider {
height: 1px;
margin: var(--mmg-space-1) 0;
background: var(--mmg-color-border-soft);
border: 0;
}
.mmg-menu__label {
padding: var(--mmg-space-2) var(--mmg-space-3) var(--mmg-space-1);
font-size: var(--mmg-font-size-xs);
font-weight: var(--mmg-font-weight-semi);
color: var(--mmg-color-text-quaternary);
text-transform: uppercase;
letter-spacing: 0.04em;
}
.mmg-menu__shortcut {
margin-left: auto;
font-family: var(--mmg-font-mono);
font-size: var(--mmg-font-size-xs);
color: var(--mmg-color-text-tertiary);
}
.mmg-menu__empty {
padding: var(--mmg-space-3) var(--mmg-space-3);
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-tertiary);
text-align: center;
}
/* — Combobox (étend mmg-menu) ———————————————————— */
.mmg-combobox__list {
overflow-y: auto;
}
/* — Forced colors / High Contrast (Windows) ——————————— */
@media (forced-colors: active) {
.mmg-tooltip,
.mmg-popover,
.mmg-menu,
.mmg-dialog {
border: 1px solid CanvasText;
}
.mmg-menu__item[data-highlighted] {
background: Highlight;
color: HighlightText;
forced-color-adjust: none;
}
}
/* prefers-reduced-motion : Radix respecte data-state mais on coupe nos
keyframes par sécurité. */
@media (prefers-reduced-motion: reduce) {
.mmg-tooltip,
.mmg-popover,
.mmg-menu,
.mmg-dialog,
.mmg-dialog__overlay {
animation: none !important;
}
}
@@ -0,0 +1,130 @@
/* ════════════════════════════════════════════════════════════════
PricingCard — carte de tarification.
════════════════════════════════════════════════════════════════ */
.mmg-pricing-card {
position: relative;
display: flex;
flex-direction: column;
gap: var(--mmg-space-5);
padding: var(--mmg-space-7);
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-card);
transition:
transform var(--mmg-duration-base) var(--mmg-ease-emphasis),
border-color var(--mmg-duration-base) var(--mmg-ease-default);
}
.mmg-pricing-card:hover {
transform: translateY(-2px);
border-color: var(--mmg-color-border-strong);
}
.mmg-pricing-card--highlighted {
border-width: 2px;
border-color: var(--mmg-color-accent);
background:
linear-gradient(180deg,
color-mix(in srgb, var(--mmg-color-accent) 4%, var(--mmg-color-bg-surface)) 0%,
var(--mmg-color-bg-surface) 100%);
box-shadow: 0 8px 32px -12px color-mix(in srgb, var(--mmg-color-accent) 30%, transparent);
}
[data-mmg-theme="dark"] .mmg-pricing-card--highlighted {
background:
linear-gradient(180deg,
color-mix(in srgb, var(--mmg-color-accent) 8%, var(--mmg-color-bg-surface)) 0%,
var(--mmg-color-bg-surface) 100%);
}
.mmg-pricing-card__badge {
position: absolute;
top: var(--mmg-space-4);
right: var(--mmg-space-4);
padding: 4px 10px;
background: var(--mmg-color-accent);
color: var(--mmg-color-accent-on);
border-radius: var(--mmg-radius-pill);
font-size: var(--mmg-font-size-xs);
font-weight: var(--mmg-font-weight-semi);
letter-spacing: 0.01em;
box-shadow: var(--mmg-shadow-accent-soft);
}
.mmg-pricing-card__head {
display: flex;
flex-direction: column;
gap: var(--mmg-space-2);
}
.mmg-pricing-card__name {
margin: 0;
font-size: var(--mmg-font-size-xl);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
letter-spacing: -0.015em;
}
.mmg-pricing-card__desc {
margin: 0;
color: var(--mmg-color-text-tertiary);
font-size: var(--mmg-font-size-sm);
line-height: 1.5;
}
.mmg-pricing-card__price {
display: flex;
align-items: baseline;
gap: var(--mmg-space-2);
flex-wrap: wrap;
}
.mmg-pricing-card__price-value {
font-size: var(--mmg-font-size-4xl);
font-weight: var(--mmg-font-weight-extra);
letter-spacing: -0.025em;
color: var(--mmg-color-text-primary);
line-height: 1;
font-variant-numeric: tabular-nums;
}
.mmg-pricing-card__price-period {
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-tertiary);
}
.mmg-pricing-card__features {
list-style: none;
padding: 0;
margin: 0;
display: flex;
flex-direction: column;
gap: var(--mmg-space-2);
border-top: 1px solid var(--mmg-color-border-soft);
padding-top: var(--mmg-space-4);
}
.mmg-pricing-card__feature {
display: flex;
align-items: flex-start;
gap: var(--mmg-space-2);
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-secondary);
line-height: 1.5;
}
.mmg-pricing-card__feature-icon {
flex-shrink: 0;
margin-top: 3px;
color: var(--mmg-color-success);
}
.mmg-pricing-card__feature--excluded {
color: var(--mmg-color-text-quaternary);
}
.mmg-pricing-card__feature--excluded .mmg-pricing-card__feature-icon {
color: var(--mmg-color-text-quaternary);
}
.mmg-pricing-card__feature--excluded span {
text-decoration: line-through;
text-decoration-color: var(--mmg-color-text-quaternary);
}
.mmg-pricing-card__cta {
margin-top: auto;
}
.mmg-pricing-card__cta > * {
width: 100%;
}
@@ -0,0 +1,112 @@
/* ════════════════════════════════════════════════════════════════
ProfileHeader — cover image + avatar en débord (LinkedIn / GitHub).
════════════════════════════════════════════════════════════════ */
.mmg-profile-header {
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-card);
overflow: hidden;
}
.mmg-profile-header__cover {
position: relative;
height: 160px;
background: var(--mmg-color-bg-muted);
}
.mmg-profile-header__cover img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
.mmg-profile-header__cover-gradient {
position: absolute;
inset: 0;
background:
radial-gradient(circle at 18% 20%,
color-mix(in srgb, var(--mmg-color-accent) 32%, transparent), transparent 55%),
radial-gradient(circle at 82% 80%,
color-mix(in srgb, var(--mmg-color-accent) 20%, transparent), transparent 60%),
linear-gradient(135deg, var(--mmg-color-accent-strong) 0%, var(--mmg-color-accent) 100%);
}
.mmg-profile-header__body {
position: relative;
padding: 0 var(--mmg-space-6) var(--mmg-space-5);
}
.mmg-profile-header__avatar-wrap {
position: relative;
margin-top: -48px;
margin-bottom: var(--mmg-space-3);
display: inline-block;
}
.mmg-profile-header__avatar-wrap .mmg-avatar {
/* Anneau plus marqué pour décoller de la cover */
box-shadow: 0 0 0 4px var(--mmg-color-bg-surface);
}
.mmg-profile-header__main {
display: flex;
flex-direction: column;
gap: var(--mmg-space-3);
}
.mmg-profile-header__heading {
display: flex;
align-items: flex-start;
justify-content: space-between;
gap: var(--mmg-space-4);
flex-wrap: wrap;
}
.mmg-profile-header__name {
margin: 0;
font-size: var(--mmg-font-size-2xl);
font-weight: var(--mmg-font-weight-bold);
letter-spacing: -0.015em;
color: var(--mmg-color-text-primary);
}
.mmg-profile-header__subtitle {
margin-top: 4px;
color: var(--mmg-color-text-tertiary);
font-size: var(--mmg-font-size-sm);
}
.mmg-profile-header__badges {
margin-top: var(--mmg-space-2);
display: flex;
gap: var(--mmg-space-1);
flex-wrap: wrap;
}
.mmg-profile-header__actions {
display: inline-flex;
align-items: center;
gap: var(--mmg-space-2);
}
.mmg-profile-header__bio {
margin: 0;
color: var(--mmg-color-text-secondary);
font-size: var(--mmg-font-size-sm);
line-height: 1.55;
max-width: 60ch;
}
.mmg-profile-header__stats {
margin: 0;
padding: var(--mmg-space-3) 0 0;
display: flex;
flex-wrap: wrap;
gap: var(--mmg-space-6);
border-top: 1px solid var(--mmg-color-border-soft);
}
.mmg-profile-header__stat { display: block; }
.mmg-profile-header__stat-label {
font-size: var(--mmg-font-size-xs);
color: var(--mmg-color-text-tertiary);
text-transform: uppercase;
letter-spacing: 0.04em;
}
.mmg-profile-header__stat-value {
margin: 2px 0 0;
font-size: var(--mmg-font-size-lg);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
font-variant-numeric: tabular-nums;
}
+164
View File
@@ -0,0 +1,164 @@
/* ════════════════════════════════════════════════════════════════
Sheet — panneau latéral / drawer (Radix Dialog avec slide-in).
Side : right (défaut), left, top, bottom.
Size : sm (320), md (480), lg (640), xl (820), full.
Focus trap, scroll lock, escape — tout natif Radix.
════════════════════════════════════════════════════════════════ */
.mmg-sheet__overlay {
position: fixed;
inset: 0;
z-index: var(--mmg-z-modal);
background: var(--mmg-color-bg-overlay);
backdrop-filter: blur(2px);
animation: mmg-sheet-overlay-in 200ms var(--mmg-ease-default);
}
.mmg-sheet__overlay[data-state="closed"] {
animation: mmg-sheet-overlay-out 160ms var(--mmg-ease-default);
}
@keyframes mmg-sheet-overlay-in { from { opacity: 0; } }
@keyframes mmg-sheet-overlay-out { to { opacity: 0; } }
.mmg-sheet {
position: fixed;
z-index: calc(var(--mmg-z-modal) + 1);
display: flex;
flex-direction: column;
background: var(--mmg-color-bg-surface);
box-shadow: 0 0 0 1px var(--mmg-color-border), -16px 0 48px rgba(15, 15, 30, 0.16);
outline: 0;
}
[data-mmg-theme="dark"] .mmg-sheet {
box-shadow: 0 0 0 1px var(--mmg-color-border), -16px 0 48px rgba(0, 0, 0, 0.55);
}
/* — Côtés ——————————————————————————— */
.mmg-sheet--right {
top: 0; right: 0; bottom: 0;
width: 100%;
border-left: 1px solid var(--mmg-color-border);
animation: mmg-sheet-in-right 320ms var(--mmg-ease-emphasis);
}
.mmg-sheet--left {
top: 0; left: 0; bottom: 0;
width: 100%;
border-right: 1px solid var(--mmg-color-border);
animation: mmg-sheet-in-left 320ms var(--mmg-ease-emphasis);
}
.mmg-sheet--top {
top: 0; left: 0; right: 0;
border-bottom: 1px solid var(--mmg-color-border);
border-bottom-left-radius: var(--mmg-radius-card);
border-bottom-right-radius: var(--mmg-radius-card);
animation: mmg-sheet-in-top 320ms var(--mmg-ease-emphasis);
}
.mmg-sheet--bottom {
bottom: 0; left: 0; right: 0;
border-top: 1px solid var(--mmg-color-border);
border-top-left-radius: var(--mmg-radius-card);
border-top-right-radius: var(--mmg-radius-card);
animation: mmg-sheet-in-bottom 320ms var(--mmg-ease-emphasis);
}
.mmg-sheet--right[data-state="closed"] { animation: mmg-sheet-out-right 220ms var(--mmg-ease-default); }
.mmg-sheet--left[data-state="closed"] { animation: mmg-sheet-out-left 220ms var(--mmg-ease-default); }
.mmg-sheet--top[data-state="closed"] { animation: mmg-sheet-out-top 220ms var(--mmg-ease-default); }
.mmg-sheet--bottom[data-state="closed"] { animation: mmg-sheet-out-bottom 220ms var(--mmg-ease-default); }
/* — Sizes ——————————————————————————— */
.mmg-sheet--right.mmg-sheet--sm,
.mmg-sheet--left.mmg-sheet--sm { max-width: 320px; }
.mmg-sheet--right.mmg-sheet--md,
.mmg-sheet--left.mmg-sheet--md { max-width: 480px; }
.mmg-sheet--right.mmg-sheet--lg,
.mmg-sheet--left.mmg-sheet--lg { max-width: 640px; }
.mmg-sheet--right.mmg-sheet--xl,
.mmg-sheet--left.mmg-sheet--xl { max-width: 820px; }
.mmg-sheet--right.mmg-sheet--full,
.mmg-sheet--left.mmg-sheet--full { max-width: 100%; }
.mmg-sheet--top.mmg-sheet--sm,
.mmg-sheet--bottom.mmg-sheet--sm { max-height: 30dvh; }
.mmg-sheet--top.mmg-sheet--md,
.mmg-sheet--bottom.mmg-sheet--md { max-height: 50dvh; }
.mmg-sheet--top.mmg-sheet--lg,
.mmg-sheet--bottom.mmg-sheet--lg { max-height: 70dvh; }
.mmg-sheet--top.mmg-sheet--xl,
.mmg-sheet--bottom.mmg-sheet--xl { max-height: 85dvh; }
.mmg-sheet--top.mmg-sheet--full,
.mmg-sheet--bottom.mmg-sheet--full { height: 100dvh; max-height: 100dvh; }
/* — Sous-éléments ——————————————————————————— */
.mmg-sheet__header {
display: flex;
align-items: flex-start;
gap: var(--mmg-space-3);
padding: var(--mmg-space-5) var(--mmg-space-6) var(--mmg-space-3);
border-bottom: 1px solid var(--mmg-color-border-soft);
}
.mmg-sheet__header-text { flex: 1; min-width: 0; }
.mmg-sheet__title {
margin: 0;
font-size: var(--mmg-font-size-xl);
font-weight: var(--mmg-font-weight-bold);
color: var(--mmg-color-text-primary);
letter-spacing: -0.01em;
}
.mmg-sheet__description {
margin: 4px 0 0;
font-size: var(--mmg-font-size-sm);
color: var(--mmg-color-text-tertiary);
line-height: 1.5;
}
.mmg-sheet__close {
flex-shrink: 0;
display: inline-flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
padding: 0;
background: transparent;
color: var(--mmg-color-text-tertiary);
border: 0;
border-radius: 8px;
cursor: pointer;
transition: background var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-sheet__close:hover { background: var(--mmg-color-bg-muted); color: var(--mmg-color-text-primary); }
.mmg-sheet__close:focus-visible {
outline: 0;
box-shadow: var(--mmg-shadow-focus);
}
.mmg-sheet__body {
flex: 1 1 auto;
padding: var(--mmg-space-5) var(--mmg-space-6);
overflow-y: auto;
}
.mmg-sheet__footer {
display: flex;
justify-content: flex-end;
gap: var(--mmg-space-2);
padding: var(--mmg-space-4) var(--mmg-space-6);
border-top: 1px solid var(--mmg-color-border-soft);
background: var(--mmg-color-bg-raised);
}
/* — Animations ——————————————————————————— */
@keyframes mmg-sheet-in-right { from { transform: translateX(100%); } }
@keyframes mmg-sheet-out-right { to { transform: translateX(100%); } }
@keyframes mmg-sheet-in-left { from { transform: translateX(-100%); } }
@keyframes mmg-sheet-out-left { to { transform: translateX(-100%); } }
@keyframes mmg-sheet-in-top { from { transform: translateY(-100%); } }
@keyframes mmg-sheet-out-top { to { transform: translateY(-100%); } }
@keyframes mmg-sheet-in-bottom { from { transform: translateY(100%); } }
@keyframes mmg-sheet-out-bottom { to { transform: translateY(100%); } }
@media (prefers-reduced-motion: reduce) {
.mmg-sheet, .mmg-sheet__overlay { animation: none !important; }
}
/* Forced colors */
@media (forced-colors: active) {
.mmg-sheet { border: 1px solid CanvasText; }
}
+102
View File
@@ -0,0 +1,102 @@
/* ════════════════════════════════════════════════════════════════
Slider — sélecteur de valeur (Radix UI Slider)
Track fin, range accent, thumb pill avec halo focus, scale au hover.
════════════════════════════════════════════════════════════════ */
.mmg-slider {
position: relative;
display: flex;
align-items: center;
user-select: none;
touch-action: none;
width: 100%;
height: 24px;
}
.mmg-slider[data-orientation="vertical"] {
flex-direction: column;
width: 24px;
height: 100%;
min-height: 120px;
}
.mmg-slider__track {
position: relative;
flex-grow: 1;
background: var(--mmg-color-bg-muted);
border-radius: 9999px;
height: 6px;
overflow: hidden;
}
.mmg-slider[data-orientation="vertical"] .mmg-slider__track {
width: 6px;
height: 100%;
}
.mmg-slider__range {
position: absolute;
background: var(--mmg-color-accent);
border-radius: 9999px;
height: 100%;
}
.mmg-slider[data-orientation="vertical"] .mmg-slider__range {
width: 100%;
height: auto;
}
.mmg-slider__thumb {
position: relative;
display: block;
width: 18px;
height: 18px;
background: var(--mmg-color-bg-surface);
border: 2px solid var(--mmg-color-accent);
border-radius: 50%;
cursor: grab;
outline: 0;
transition:
transform var(--mmg-duration-fast) var(--mmg-ease-emphasis),
box-shadow var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-slider__thumb:hover {
transform: scale(1.12);
}
.mmg-slider__thumb:active {
cursor: grabbing;
transform: scale(1.18);
}
.mmg-slider__thumb:focus-visible {
box-shadow: var(--mmg-shadow-focus);
}
.mmg-slider--disabled {
opacity: 0.55;
pointer-events: none;
}
.mmg-slider__value {
position: absolute;
bottom: calc(100% + 8px);
left: 50%;
transform: translateX(-50%);
padding: 2px 8px;
background: var(--mmg-color-text-primary);
color: var(--mmg-color-bg-surface);
border-radius: 6px;
font-size: var(--mmg-font-size-xs);
font-weight: var(--mmg-font-weight-semi);
font-variant-numeric: tabular-nums;
white-space: nowrap;
pointer-events: none;
opacity: 0;
transition: opacity var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-slider__thumb:hover .mmg-slider__value,
.mmg-slider__thumb:focus .mmg-slider__value,
.mmg-slider__thumb[data-disabled] .mmg-slider__value {
opacity: 1;
}
@media (forced-colors: active) {
.mmg-slider__thumb { border: 2px solid CanvasText; }
.mmg-slider__range { background: Highlight; }
}
@@ -0,0 +1,107 @@
/* ════════════════════════════════════════════════════════════════
Theme picker — sélecteur de couleur d'accent
Pattern radiogroup, pastilles cliquables, focus-visible, état checked.
════════════════════════════════════════════════════════════════ */
.mmg-theme-picker {
display: flex;
flex-direction: column;
gap: var(--mmg-space-3);
}
.mmg-theme-picker__legend {
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-semi);
color: var(--mmg-color-text-primary);
}
.mmg-theme-picker__group {
display: flex;
flex-wrap: wrap;
gap: var(--mmg-space-2);
}
.mmg-theme-picker__swatch {
position: relative;
display: inline-flex;
align-items: center;
justify-content: center;
width: 36px;
height: 36px;
padding: 0;
background: transparent;
border: 2px solid transparent;
border-radius: 50%;
cursor: pointer;
transition:
border-color var(--mmg-duration-fast) var(--mmg-ease-default),
transform var(--mmg-duration-fast) var(--mmg-ease-emphasis),
box-shadow var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-theme-picker__swatch-color {
display: block;
width: 24px;
height: 24px;
border-radius: 50%;
background: var(--mmg-swatch-color);
/* Bordure subtile pour la pastille slate sur fond clair (contraste 3:1 mini) */
box-shadow: inset 0 0 0 1px rgba(0, 0, 0, 0.10);
transition: transform var(--mmg-duration-fast) var(--mmg-ease-emphasis);
}
.mmg-theme-picker__swatch:hover .mmg-theme-picker__swatch-color {
transform: scale(1.08);
}
.mmg-theme-picker__swatch--selected {
border-color: var(--mmg-color-text-primary);
}
.mmg-theme-picker__swatch:focus-visible {
outline: 0;
border-color: var(--mmg-color-accent);
box-shadow: var(--mmg-shadow-focus);
}
.mmg-theme-picker__swatch-check {
position: absolute;
inset: 0;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
/* Mix-blend pour rester lisible sur n'importe quelle teinte d'accent */
mix-blend-mode: difference;
/* RGAA 9 : couleur jamais seule. Le check est un signal redondant. */
}
.mmg-theme-picker__reset {
align-self: flex-start;
padding: 4px 12px;
font-size: var(--mmg-font-size-xs);
color: var(--mmg-color-text-tertiary);
background: transparent;
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-pill);
cursor: pointer;
transition:
color var(--mmg-duration-fast) var(--mmg-ease-default),
border-color var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-theme-picker__reset:hover {
color: var(--mmg-color-text-primary);
border-color: var(--mmg-color-border-strong);
}
.mmg-theme-picker__reset:focus-visible {
outline: 0;
border-color: var(--mmg-color-accent);
box-shadow: var(--mmg-shadow-focus);
}
/* Forced colors / High Contrast Mode (Windows) */
@media (forced-colors: active) {
.mmg-theme-picker__swatch--selected {
border-color: Highlight;
}
}
@@ -0,0 +1,75 @@
/* ════════════════════════════════════════════════════════════════
ToggleGroup — groupe de boutons toggle (Radix UI).
Variants : outline (défaut, bordure) / solid (fond accent).
Sizes : sm / md / lg.
════════════════════════════════════════════════════════════════ */
.mmg-toggle-group {
display: inline-flex;
align-items: stretch;
border-radius: var(--mmg-radius-md);
background: var(--mmg-color-bg-muted);
padding: 3px;
gap: 2px;
border: 1px solid var(--mmg-color-border);
}
.mmg-toggle-group__item {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 6px;
padding: 6px 12px;
background: transparent;
color: var(--mmg-color-text-secondary);
border: 0;
border-radius: calc(var(--mmg-radius-md) - 4px);
font-family: inherit;
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-medium);
cursor: pointer;
user-select: none;
outline: 0;
white-space: nowrap;
transition:
background var(--mmg-duration-fast) var(--mmg-ease-default),
color var(--mmg-duration-fast) var(--mmg-ease-default),
box-shadow var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-toggle-group__item:hover:not([data-disabled]) {
color: var(--mmg-color-text-primary);
}
.mmg-toggle-group__item[data-state="on"] {
background: var(--mmg-color-bg-surface);
color: var(--mmg-color-text-primary);
box-shadow:
0 0 0 1px var(--mmg-color-border),
0 1px 2px rgba(0, 0, 0, 0.06);
}
.mmg-toggle-group__item[data-disabled] {
color: var(--mmg-color-text-quaternary);
cursor: not-allowed;
}
.mmg-toggle-group__item:focus-visible {
box-shadow: var(--mmg-shadow-focus);
}
/* Sizes */
.mmg-toggle-group--sm .mmg-toggle-group__item { padding: 4px 10px; font-size: var(--mmg-font-size-xs); }
.mmg-toggle-group--lg .mmg-toggle-group__item { padding: 9px 16px; font-size: var(--mmg-font-size-base); }
/* Variant solid : item actif passe en accent plein */
.mmg-toggle-group--solid .mmg-toggle-group__item[data-state="on"] {
background: var(--mmg-color-accent);
color: var(--mmg-color-accent-on);
box-shadow: none;
}
/* Forced colors */
@media (forced-colors: active) {
.mmg-toggle-group__item[data-state="on"] {
background: Highlight;
color: HighlightText;
forced-color-adjust: none;
}
}
+218
View File
@@ -0,0 +1,218 @@
/* ════════════════════════════════════════════════════════════════
Typography — système typographique DSMMG
3 familles d'échelles, à utiliser selon le contexte :
═══ DISPLAY ═══════════════════════════════════════════════
Pour les pages marketing / landing produits (HRTime, Synapse,
Forge, Orbit). Tailles XXL, extra-bold, tracking serré pour
un look éditorial moderne (Vercel / Linear / Stripe).
mmg-text-display-2xl 72px → Hero "événement" (premier écran d'un produit)
mmg-text-display-xl 60px → Hero standard de page produit
mmg-text-display-lg 48px → Hero secondaire / section feature
mmg-text-display-md 36px → Sous-section marketing
═══ HEADLINES ═══════════════════════════════════════════════
Pour les apps métier (Synapse, HRTime app, Forge, Orbit) et
l'Espace-Client. Hiérarchie h1 → h6 sémantique.
mmg-text-h1 36px → titre de page
mmg-text-h2 30px → section
mmg-text-h3 24px → sous-section
mmg-text-h4 20px → groupe / card title
mmg-text-h5 17px → sub-card
mmg-text-h6 15px → label fort
═══ BODY ═══════════════════════════════════════════════════
mmg-text-body-lg 17px → paragraphes marketing aérés
mmg-text-body 15px → texte courant (défaut <p>)
mmg-text-body-sm 13px → UI dense, hint
mmg-text-body-xs 11px → métadonnées, footnotes
═══ AUXILIAIRES ═════════════════════════════════════════════
mmg-text-eyebrow 13px uppercase tracking → label au-dessus d'un titre
mmg-text-lead 20px regular → chapô sous Hero
mmg-text-overline 11px uppercase tracking → labels de groupe
mmg-text-caption 11px regular → légendes d'image, annotations
mmg-text-kbd mono → raccourcis clavier (déjà dans base.css)
════════════════════════════════════════════════════════════════ */
/* — Display ——————————————————————————————————— */
.mmg-text-display-2xl,
.mmg-text-display-xl,
.mmg-text-display-lg,
.mmg-text-display-md {
font-family: var(--mmg-font-sans);
font-weight: var(--mmg-font-weight-extra);
letter-spacing: -0.025em;
line-height: 1.05;
color: var(--mmg-color-text-primary);
/* Légère optimisation rendering pour grandes tailles */
text-rendering: optimizeLegibility;
font-feature-settings: "ss01", "ss02";
}
.mmg-text-display-2xl {
font-size: clamp(48px, 6vw + 1rem, 72px);
letter-spacing: -0.035em;
line-height: 1;
}
.mmg-text-display-xl {
font-size: clamp(40px, 5vw + 1rem, 60px);
letter-spacing: -0.03em;
}
.mmg-text-display-lg {
font-size: clamp(32px, 4vw + 0.5rem, 48px);
letter-spacing: -0.025em;
line-height: 1.1;
}
.mmg-text-display-md {
font-size: clamp(28px, 3vw + 0.5rem, 36px);
letter-spacing: -0.02em;
line-height: 1.15;
}
/* — Headlines (sémantiques h1-h6) ——————————————————— */
.mmg-text-h1 {
font-family: var(--mmg-font-sans);
font-size: var(--mmg-font-size-4xl);
font-weight: var(--mmg-font-weight-bold);
letter-spacing: -0.02em;
line-height: 1.2;
color: var(--mmg-color-text-primary);
}
.mmg-text-h2 {
font-family: var(--mmg-font-sans);
font-size: var(--mmg-font-size-3xl);
font-weight: var(--mmg-font-weight-bold);
letter-spacing: -0.015em;
line-height: 1.25;
color: var(--mmg-color-text-primary);
}
.mmg-text-h3 {
font-family: var(--mmg-font-sans);
font-size: var(--mmg-font-size-2xl);
font-weight: var(--mmg-font-weight-bold);
letter-spacing: -0.01em;
line-height: 1.3;
color: var(--mmg-color-text-primary);
}
.mmg-text-h4 {
font-family: var(--mmg-font-sans);
font-size: var(--mmg-font-size-xl);
font-weight: var(--mmg-font-weight-semi);
letter-spacing: -0.005em;
line-height: 1.35;
color: var(--mmg-color-text-primary);
}
.mmg-text-h5 {
font-family: var(--mmg-font-sans);
font-size: var(--mmg-font-size-lg);
font-weight: var(--mmg-font-weight-semi);
line-height: 1.4;
color: var(--mmg-color-text-primary);
}
.mmg-text-h6 {
font-family: var(--mmg-font-sans);
font-size: var(--mmg-font-size-base);
font-weight: var(--mmg-font-weight-semi);
line-height: 1.45;
color: var(--mmg-color-text-primary);
}
/* — Body ——————————————————————————————————— */
.mmg-text-body-lg {
font-size: var(--mmg-font-size-lg);
font-weight: var(--mmg-font-weight-regular);
line-height: 1.6;
color: var(--mmg-color-text-secondary);
}
.mmg-text-body {
font-size: var(--mmg-font-size-base);
font-weight: var(--mmg-font-weight-regular);
line-height: 1.55;
color: var(--mmg-color-text-secondary);
}
.mmg-text-body-sm {
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-regular);
line-height: 1.5;
color: var(--mmg-color-text-secondary);
}
.mmg-text-body-xs {
font-size: var(--mmg-font-size-xs);
font-weight: var(--mmg-font-weight-regular);
line-height: 1.45;
color: var(--mmg-color-text-tertiary);
}
/* — Auxiliaires ——————————————————————————————— */
.mmg-text-eyebrow {
display: inline-block;
font-size: var(--mmg-font-size-sm);
font-weight: var(--mmg-font-weight-semi);
letter-spacing: 0.06em;
text-transform: uppercase;
color: var(--mmg-color-accent);
line-height: 1.2;
}
.mmg-text-lead {
font-size: var(--mmg-font-size-xl);
font-weight: var(--mmg-font-weight-regular);
line-height: 1.5;
letter-spacing: -0.005em;
color: var(--mmg-color-text-secondary);
max-width: 60ch;
}
.mmg-text-overline {
font-size: var(--mmg-font-size-xs);
font-weight: var(--mmg-font-weight-semi);
letter-spacing: 0.08em;
text-transform: uppercase;
color: var(--mmg-color-text-tertiary);
}
.mmg-text-caption {
font-size: var(--mmg-font-size-xs);
font-weight: var(--mmg-font-weight-regular);
line-height: 1.4;
color: var(--mmg-color-text-tertiary);
}
/* — Modificateurs alignement / poids ————————————————————— */
.mmg-text--mono { font-family: var(--mmg-font-mono); letter-spacing: 0; }
.mmg-text--tabular { font-variant-numeric: tabular-nums; }
.mmg-text--balance { text-wrap: balance; } /* Pour titres : équilibre les retours à la ligne */
.mmg-text--pretty { text-wrap: pretty; } /* Pour body : évite les veuves/orphelines */
/* — Texte gradient (Vercel signature) ————————————————————
Applicable à n'importe quel titre via .mmg-text--gradient.
Utilise l'accent + accent-strong pour rester theming-aware. */
.mmg-text--gradient {
background: linear-gradient(135deg,
var(--mmg-color-accent) 0%,
var(--mmg-color-accent-strong) 100%);
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
}
/* — Texte gradient "rainbow" (effet hero exceptionnel) ——————
À utiliser AVEC PARCIMONIE — un seul par page max. */
.mmg-text--rainbow {
background: linear-gradient(90deg,
var(--mmg-color-accent),
var(--mmg-color-violet-500),
var(--mmg-color-blue-500),
var(--mmg-color-accent));
background-size: 300% 100%;
-webkit-background-clip: text;
background-clip: text;
-webkit-text-fill-color: transparent;
color: transparent;
animation: mmg-text-rainbow 8s linear infinite;
}
@keyframes mmg-text-rainbow {
to { background-position: 300% 0; }
}
@media (prefers-reduced-motion: reduce) {
.mmg-text--rainbow { animation: none; background-position: 0 0; }
}
+85
View File
@@ -0,0 +1,85 @@
/* ════════════════════════════════════════════════════════════════
UserCard — carte utilisateur compacte.
════════════════════════════════════════════════════════════════ */
.mmg-user-card {
display: flex;
align-items: center;
gap: var(--mmg-space-3);
padding: var(--mmg-space-3) var(--mmg-space-4);
background: var(--mmg-color-bg-surface);
border: 1px solid var(--mmg-color-border);
border-radius: var(--mmg-radius-md);
text-decoration: none;
color: inherit;
font: inherit;
text-align: left;
width: 100%;
transition:
background var(--mmg-duration-fast) var(--mmg-ease-default),
border-color var(--mmg-duration-fast) var(--mmg-ease-default),
transform var(--mmg-duration-fast) var(--mmg-ease-emphasis),
box-shadow var(--mmg-duration-fast) var(--mmg-ease-default);
}
.mmg-user-card--sm { padding: var(--mmg-space-2) var(--mmg-space-3); gap: var(--mmg-space-2); }
.mmg-user-card--lg { padding: var(--mmg-space-4) var(--mmg-space-5); gap: var(--mmg-space-4); }
.mmg-user-card--interactive {
cursor: pointer;
}
.mmg-user-card--interactive:hover {
border-color: var(--mmg-color-border-strong);
background: var(--mmg-color-bg-raised);
}
.mmg-user-card--interactive:active {
transform: translateY(1px);
}
.mmg-user-card--interactive:focus-visible {
outline: 0;
border-color: var(--mmg-color-accent);
box-shadow: var(--mmg-shadow-focus);
}
.mmg-user-card__body {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 2px;
}
.mmg-user-card__name {
font-weight: var(--mmg-font-weight-semi);
color: var(--mmg-color-text-primary);
font-size: var(--mmg-font-size-sm);
line-height: 1.3;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.mmg-user-card__role {
font-size: var(--mmg-font-size-xs);
color: var(--mmg-color-text-tertiary);
line-height: 1.4;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.mmg-user-card__meta {
font-size: var(--mmg-font-size-xs);
color: var(--mmg-color-text-quaternary);
line-height: 1.4;
margin-top: 2px;
}
.mmg-user-card__actions {
flex-shrink: 0;
display: inline-flex;
align-items: center;
gap: var(--mmg-space-1);
/* Cliquer sur un bouton dans actions ne déclenche PAS la card */
}
.mmg-user-card__actions :where(button, a) {
z-index: 1;
}
.mmg-user-card--lg .mmg-user-card__name { font-size: var(--mmg-font-size-base); }
.mmg-user-card--lg .mmg-user-card__role { font-size: var(--mmg-font-size-sm); }
+35
View File
@@ -0,0 +1,35 @@
/* ════════════════════════════════════════════════════════════════
DSMMG — Bundle complet
Importez ce fichier pour obtenir tout le DS.
Cascade @layer ordonnée pour permettre aux consommateurs de
surcharger proprement sans !important :
reset → tokens → base → components → utilities (consumer override)
════════════════════════════════════════════════════════════════ */
@layer reset, tokens, base, components, utilities;
@import "./tokens.css" layer(tokens);
@import "./base.css" layer(base);
@import "./components/layout.css" layer(components);
@import "./components/button.css" layer(components);
@import "./components/form.css" layer(components);
@import "./components/feedback.css" layer(components);
@import "./components/chrome.css" layer(components);
@import "./components/advanced.css" layer(components);
@import "./components/extras.css" layer(components);
@import "./components/article.css" layer(components);
@import "./components/overlays.css" layer(components);
@import "./components/sheet.css" layer(components);
@import "./components/hover-card.css" layer(components);
@import "./components/slider.css" layer(components);
@import "./components/toggle-group.css" layer(components);
@import "./components/avatar.css" layer(components);
@import "./components/user-card.css" layer(components);
@import "./components/profile-header.css" layer(components);
@import "./components/metric-card.css" layer(components);
@import "./components/pricing-card.css" layer(components);
@import "./components/feature-card.css" layer(components);
@import "./components/typography.css" layer(components);
@import "./components/theme-picker.css" layer(components);
@import "./utilities.css" layer(utilities);
+10
View File
@@ -0,0 +1,10 @@
/* ════════════════════════════════════════════════════════════════
DSMMG — Tokens entry
Préfixe : --mmg-color-* pour tout ce qui est couleur,
--mmg-space/font/radius/duration/... pour les autres.
Architecture : primitives → semantic → accent (presets), system non-color.
════════════════════════════════════════════════════════════════ */
@import "./tokens/primitives.css";
@import "./tokens/semantic.css";
@import "./tokens/accent.css";
@import "./tokens/system.css";
+209
View File
@@ -0,0 +1,209 @@
/* ════════════════════════════════════════════════════════════════
DSMMG — Accent tokens (user-themable)
--mmg-color-accent-* est le SEUL ensemble de tokens accent que les
composants doivent consommer. La couleur est ré-aliasée selon
[data-mmg-accent="..."] sur <html>, persisté côté user.
Défaut = synapse (rose ManageMate). Aucun composant ne réfère
--mmg-color-synapse-* directement.
Presets fournis : synapse, rose, blue, violet, green, amber, red,
cyan, slate. 9 presets, tous validés WCAG AA contre fonds light/dark.
════════════════════════════════════════════════════════════════ */
/* — Default (synapse) — light theme ——————— */
:root,
[data-mmg-theme="light"],
[data-mmg-accent="synapse"] {
--mmg-color-accent: var(--mmg-color-synapse-500);
--mmg-color-accent-hover: var(--mmg-color-synapse-600);
--mmg-color-accent-active: var(--mmg-color-synapse-700);
--mmg-color-accent-soft: var(--mmg-color-synapse-50);
--mmg-color-accent-border: var(--mmg-color-synapse-200);
--mmg-color-accent-strong: var(--mmg-color-synapse-800);
--mmg-color-accent-on: var(--mmg-color-neutral-0);
}
/* — Presets — light theme ——————— */
[data-mmg-accent="rose"] {
--mmg-color-accent: var(--mmg-color-rose-500);
--mmg-color-accent-hover: var(--mmg-color-rose-600);
--mmg-color-accent-active: var(--mmg-color-rose-700);
--mmg-color-accent-soft: var(--mmg-color-rose-50);
--mmg-color-accent-border: var(--mmg-color-rose-200);
--mmg-color-accent-strong: var(--mmg-color-rose-800);
--mmg-color-accent-on: var(--mmg-color-neutral-0);
}
[data-mmg-accent="blue"] {
--mmg-color-accent: var(--mmg-color-blue-500);
--mmg-color-accent-hover: var(--mmg-color-blue-600);
--mmg-color-accent-active: var(--mmg-color-blue-700);
--mmg-color-accent-soft: var(--mmg-color-blue-50);
--mmg-color-accent-border: var(--mmg-color-blue-200);
--mmg-color-accent-strong: var(--mmg-color-blue-800);
--mmg-color-accent-on: var(--mmg-color-neutral-0);
}
[data-mmg-accent="violet"] {
--mmg-color-accent: var(--mmg-color-violet-500);
--mmg-color-accent-hover: var(--mmg-color-violet-600);
--mmg-color-accent-active: var(--mmg-color-violet-700);
--mmg-color-accent-soft: var(--mmg-color-violet-50);
--mmg-color-accent-border: var(--mmg-color-violet-200);
--mmg-color-accent-strong: var(--mmg-color-violet-800);
--mmg-color-accent-on: var(--mmg-color-neutral-0);
}
[data-mmg-accent="green"] {
/* Green-500 (#0E9F6E) sur blanc = 3.39:1 → fail AA texte. Bump vers
green-700 pour passer 5.5:1 AA confortablement. */
--mmg-color-accent: var(--mmg-color-green-700);
--mmg-color-accent-hover: var(--mmg-color-green-800);
--mmg-color-accent-active: var(--mmg-color-green-900);
--mmg-color-accent-soft: var(--mmg-color-green-50);
--mmg-color-accent-border: var(--mmg-color-green-200);
--mmg-color-accent-strong: var(--mmg-color-green-800);
--mmg-color-accent-on: var(--mmg-color-neutral-0);
}
[data-mmg-accent="amber"] {
/* Amber-500 (#D97706) sur bg-page = 2.96:1 → fail AA composant (3:1).
Bump à amber-600 (#B45309) pour 3.5:1. accent-on reste text-primary
car amber-600 est jaune-orange foncé (texte foncé est mieux qu'un
blanc qui rendrait un contraste insuffisant aussi). */
--mmg-color-accent: var(--mmg-color-amber-600);
--mmg-color-accent-hover: var(--mmg-color-amber-700);
--mmg-color-accent-active: var(--mmg-color-amber-800);
--mmg-color-accent-soft: var(--mmg-color-amber-50);
--mmg-color-accent-border: var(--mmg-color-amber-200);
--mmg-color-accent-strong: var(--mmg-color-amber-800);
--mmg-color-accent-on: var(--mmg-color-neutral-0);
}
[data-mmg-accent="red"] {
--mmg-color-accent: var(--mmg-color-red-500);
--mmg-color-accent-hover: var(--mmg-color-red-600);
--mmg-color-accent-active: var(--mmg-color-red-700);
--mmg-color-accent-soft: var(--mmg-color-red-50);
--mmg-color-accent-border: var(--mmg-color-red-200);
--mmg-color-accent-strong: var(--mmg-color-red-800);
--mmg-color-accent-on: var(--mmg-color-neutral-0);
/* Note : preset accent rouge ≠ couleur sémantique danger.
Le composant Alert/danger reste --mmg-color-danger-*. */
}
[data-mmg-accent="cyan"] {
/* Cyan-500 (#0891B2) sur blanc = 3.68:1 → fail AA texte. Bump vers
cyan-700 pour passer 6.5:1 AA confortablement. */
--mmg-color-accent: var(--mmg-color-cyan-700);
--mmg-color-accent-hover: var(--mmg-color-cyan-800);
--mmg-color-accent-active: var(--mmg-color-cyan-900);
--mmg-color-accent-soft: var(--mmg-color-cyan-50);
--mmg-color-accent-border: var(--mmg-color-cyan-200);
--mmg-color-accent-strong: var(--mmg-color-cyan-800);
--mmg-color-accent-on: var(--mmg-color-neutral-0);
}
[data-mmg-accent="slate"] {
--mmg-color-accent: var(--mmg-color-slate-700);
--mmg-color-accent-hover: var(--mmg-color-slate-800);
--mmg-color-accent-active: var(--mmg-color-slate-900);
--mmg-color-accent-soft: var(--mmg-color-slate-100);
--mmg-color-accent-border: var(--mmg-color-slate-300);
--mmg-color-accent-strong: var(--mmg-color-slate-900);
--mmg-color-accent-on: var(--mmg-color-neutral-0);
}
/* ════════════════════════════════════════════════════════════════
Dark theme — accent tuned (saturation réduite, luminosité montée)
Override global de l'accent quand [data-mmg-theme="dark"] est posé.
Combine avec [data-mmg-accent="..."] pour preset user en dark.
════════════════════════════════════════════════════════════════ */
[data-mmg-theme="dark"],
[data-mmg-theme="dark"][data-mmg-accent="synapse"] {
--mmg-color-accent: var(--mmg-color-synapse-d-500);
--mmg-color-accent-hover: var(--mmg-color-synapse-d-400);
--mmg-color-accent-active: var(--mmg-color-synapse-d-600);
--mmg-color-accent-soft: var(--mmg-color-synapse-d-soft);
--mmg-color-accent-border: var(--mmg-color-synapse-d-border);
--mmg-color-accent-strong: var(--mmg-color-synapse-d-300);
--mmg-color-accent-on: var(--mmg-color-neutral-0);
}
[data-mmg-theme="dark"][data-mmg-accent="rose"] {
--mmg-color-accent: var(--mmg-color-rose-d-500);
--mmg-color-accent-hover: var(--mmg-color-rose-d-400);
--mmg-color-accent-active: var(--mmg-color-rose-d-600);
--mmg-color-accent-soft: var(--mmg-color-rose-d-soft);
--mmg-color-accent-border: var(--mmg-color-rose-d-border);
--mmg-color-accent-strong: var(--mmg-color-rose-d-300);
--mmg-color-accent-on: var(--mmg-color-neutral-0);
}
[data-mmg-theme="dark"][data-mmg-accent="blue"] {
--mmg-color-accent: var(--mmg-color-blue-d-500);
--mmg-color-accent-hover: var(--mmg-color-blue-d-400);
--mmg-color-accent-active: var(--mmg-color-blue-d-600);
--mmg-color-accent-soft: var(--mmg-color-blue-d-soft);
--mmg-color-accent-border: var(--mmg-color-blue-d-border);
--mmg-color-accent-strong: var(--mmg-color-blue-d-300);
--mmg-color-accent-on: var(--mmg-color-neutral-900);
}
[data-mmg-theme="dark"][data-mmg-accent="violet"] {
--mmg-color-accent: var(--mmg-color-violet-d-500);
--mmg-color-accent-hover: var(--mmg-color-violet-d-400);
--mmg-color-accent-active: var(--mmg-color-violet-d-600);
--mmg-color-accent-soft: var(--mmg-color-violet-d-soft);
--mmg-color-accent-border: var(--mmg-color-violet-d-border);
--mmg-color-accent-strong: var(--mmg-color-violet-d-300);
--mmg-color-accent-on: var(--mmg-color-violet-900);
}
[data-mmg-theme="dark"][data-mmg-accent="green"] {
--mmg-color-accent: var(--mmg-color-green-d-500);
--mmg-color-accent-hover: var(--mmg-color-green-d-400);
--mmg-color-accent-active: var(--mmg-color-green-d-600);
--mmg-color-accent-soft: var(--mmg-color-green-d-soft);
--mmg-color-accent-border: var(--mmg-color-green-d-border);
--mmg-color-accent-strong: var(--mmg-color-green-d-300);
--mmg-color-accent-on: var(--mmg-color-green-900);
}
[data-mmg-theme="dark"][data-mmg-accent="amber"] {
--mmg-color-accent: var(--mmg-color-amber-d-500);
--mmg-color-accent-hover: var(--mmg-color-amber-d-400);
--mmg-color-accent-active: var(--mmg-color-amber-d-600);
--mmg-color-accent-soft: var(--mmg-color-amber-d-soft);
--mmg-color-accent-border: var(--mmg-color-amber-d-border);
--mmg-color-accent-strong: var(--mmg-color-amber-d-300);
--mmg-color-accent-on: var(--mmg-color-amber-900);
}
[data-mmg-theme="dark"][data-mmg-accent="red"] {
--mmg-color-accent: var(--mmg-color-red-d-500);
--mmg-color-accent-hover: var(--mmg-color-red-d-400);
--mmg-color-accent-active: var(--mmg-color-red-d-600);
--mmg-color-accent-soft: var(--mmg-color-red-d-soft);
--mmg-color-accent-border: var(--mmg-color-red-d-border);
--mmg-color-accent-strong: var(--mmg-color-red-d-300);
--mmg-color-accent-on: var(--mmg-color-neutral-0);
}
[data-mmg-theme="dark"][data-mmg-accent="cyan"] {
--mmg-color-accent: var(--mmg-color-cyan-d-500);
--mmg-color-accent-hover: var(--mmg-color-cyan-d-400);
--mmg-color-accent-active: var(--mmg-color-cyan-d-600);
--mmg-color-accent-soft: var(--mmg-color-cyan-d-soft);
--mmg-color-accent-border: var(--mmg-color-cyan-d-border);
--mmg-color-accent-strong: var(--mmg-color-cyan-d-300);
--mmg-color-accent-on: var(--mmg-color-cyan-900);
}
[data-mmg-theme="dark"][data-mmg-accent="slate"] {
--mmg-color-accent: var(--mmg-color-slate-d-500);
--mmg-color-accent-hover: var(--mmg-color-slate-d-400);
--mmg-color-accent-active: var(--mmg-color-slate-d-600);
--mmg-color-accent-soft: var(--mmg-color-slate-d-soft);
--mmg-color-accent-border: var(--mmg-color-slate-d-border);
--mmg-color-accent-strong: var(--mmg-color-slate-d-300);
--mmg-color-accent-on: var(--mmg-color-slate-900);
}
@media (prefers-color-scheme: dark) {
:root:not([data-mmg-theme="light"]):not([data-mmg-accent]) {
--mmg-color-accent: var(--mmg-color-synapse-d-500);
--mmg-color-accent-hover: var(--mmg-color-synapse-d-400);
--mmg-color-accent-active: var(--mmg-color-synapse-d-600);
--mmg-color-accent-soft: var(--mmg-color-synapse-d-soft);
--mmg-color-accent-border: var(--mmg-color-synapse-d-border);
--mmg-color-accent-strong: var(--mmg-color-synapse-d-300);
}
}
+205
View File
@@ -0,0 +1,205 @@
/* ════════════════════════════════════════════════════════════════
DSMMG — Primitive color palettes
Raw color ramps. JAMAIS consommées directement par les composants.
Toujours référencer via les tokens sémantiques ou l'accent.
Chaque rampe : 50, 100, 200, 300, 400, 500, 600, 700, 800, 900.
════════════════════════════════════════════════════════════════ */
:root {
/* — Neutral grayscale (texte, bg, border) ——————— */
--mmg-color-neutral-0: #FFFFFF;
--mmg-color-neutral-50: #F7F6FB;
--mmg-color-neutral-100: #F0EFF9;
--mmg-color-neutral-150: #EDEDFA;
--mmg-color-neutral-200: #E4E3F4;
--mmg-color-neutral-300: #C9C7E0;
--mmg-color-neutral-400: #AAA8C9;
--mmg-color-neutral-500: #7875A1;
--mmg-color-neutral-600: #56557A;
--mmg-color-neutral-700: #3B3A56;
--mmg-color-neutral-800: #1F1E32;
--mmg-color-neutral-900: #111120;
/* Dark grays (utilisés en thème sombre, indépendants de neutral pour ne
pas écraser les valeurs light en cascade) */
--mmg-color-gray-d-bg: #0B0D14;
--mmg-color-gray-d-surface: #14171F;
--mmg-color-gray-d-raised: #1C2029;
--mmg-color-gray-d-muted: #252A35;
--mmg-color-gray-d-subtle: #181B23;
--mmg-color-gray-d-border: #2D323D;
--mmg-color-gray-d-border-soft: #1F242E;
--mmg-color-gray-d-border-strong: #424857;
--mmg-color-gray-d-text-1: #F5F7FA;
--mmg-color-gray-d-text-2: #C9CED9;
--mmg-color-gray-d-text-3: #8D93A4;
--mmg-color-gray-d-text-4: #6B7185;
/* — Synapse (rose corporate ManageMate, défaut accent) ——————— */
--mmg-color-synapse-50: #FEF0F4;
--mmg-color-synapse-100: #FCE0EA;
--mmg-color-synapse-200: #FAD0DF;
--mmg-color-synapse-300: #F4A0BD;
--mmg-color-synapse-400: #ED608E;
--mmg-color-synapse-500: #D12B6A;
--mmg-color-synapse-600: #BA245F;
--mmg-color-synapse-700: #A82257;
--mmg-color-synapse-800: #831B45;
--mmg-color-synapse-900: #5A132F;
/* Dark-mode tuned — équilibre vibrance / confort visuel.
Itération 1 : #E83A7E (HSL 335 78% 57%) — neon, piquait les yeux.
Itération 2 : #E66B97 (HSL 338 68% 66%) — trop pastel, perdait la marque.
Final : #E94B91 (HSL 335 76% 60%) — saturation 76% (-2pts), luminosité
60% (+3pts) → garde la vibrance rose Synapse, sans neon, sans pastel.
Référence Linear pink dark : ~#E54187, Stripe pink dark : ~#EB5097. */
--mmg-color-synapse-d-300: #F0A5C1;
--mmg-color-synapse-d-400: #ED75A6;
--mmg-color-synapse-d-500: #E94B91;
--mmg-color-synapse-d-600: #D8307C;
--mmg-color-synapse-d-soft: rgba(233, 75, 145, 0.14);
--mmg-color-synapse-d-border: rgba(233, 75, 145, 0.38);
/* — Rose (preset alternatif plus pastel) ——————— */
--mmg-color-rose-50: #FFF1F2;
--mmg-color-rose-100: #FFE4E6;
--mmg-color-rose-200: #FECDD3;
--mmg-color-rose-300: #FDA4AF;
--mmg-color-rose-400: #FB7185;
--mmg-color-rose-500: #E11D48;
--mmg-color-rose-600: #BE123C;
--mmg-color-rose-700: #9F1239;
--mmg-color-rose-800: #881337;
--mmg-color-rose-900: #4C0519;
--mmg-color-rose-d-300: #FB7185;
--mmg-color-rose-d-400: #F43F5E;
--mmg-color-rose-d-500: #FB7185;
--mmg-color-rose-d-600: #E11D48;
--mmg-color-rose-d-soft: rgba(251, 113, 133, 0.16);
--mmg-color-rose-d-border: rgba(251, 113, 133, 0.40);
/* — Blue ——————— */
--mmg-color-blue-50: #EFF6FF;
--mmg-color-blue-100: #DBEAFE;
--mmg-color-blue-200: #BFDBFE;
--mmg-color-blue-300: #93C5FD;
--mmg-color-blue-400: #60A5FA;
--mmg-color-blue-500: #2563EB;
--mmg-color-blue-600: #1D4ED8;
--mmg-color-blue-700: #1E40AF;
--mmg-color-blue-800: #1E3A8A;
--mmg-color-blue-900: #172554;
--mmg-color-blue-d-300: #93C5FD;
--mmg-color-blue-d-400: #60A5FA;
--mmg-color-blue-d-500: #60A5FA;
--mmg-color-blue-d-600: #3B82F6;
--mmg-color-blue-d-soft: rgba(96, 165, 250, 0.16);
--mmg-color-blue-d-border: rgba(96, 165, 250, 0.40);
/* — Violet ——————— */
--mmg-color-violet-50: #F5F3FF;
--mmg-color-violet-100: #EDE9FE;
--mmg-color-violet-200: #DDD6FE;
--mmg-color-violet-300: #C4B5FD;
--mmg-color-violet-400: #A78BFA;
--mmg-color-violet-500: #7C3AED;
--mmg-color-violet-600: #6D28D9;
--mmg-color-violet-700: #5B21B6;
--mmg-color-violet-800: #4C1D95;
--mmg-color-violet-900: #2E1065;
--mmg-color-violet-d-300: #C4B5FD;
--mmg-color-violet-d-400: #A78BFA;
--mmg-color-violet-d-500: #A78BFA;
--mmg-color-violet-d-600: #8B5CF6;
--mmg-color-violet-d-soft: rgba(167, 139, 250, 0.16);
--mmg-color-violet-d-border: rgba(167, 139, 250, 0.40);
/* — Green (HRTime) ——————— */
--mmg-color-green-50: #ECFDF5;
--mmg-color-green-100: #D1FAE5;
--mmg-color-green-200: #BAEFD3;
--mmg-color-green-300: #6EE7B7;
--mmg-color-green-400: #34D399;
--mmg-color-green-500: #0E9F6E;
--mmg-color-green-600: #0B8861;
--mmg-color-green-700: #086B4D;
--mmg-color-green-800: #064E3B;
--mmg-color-green-900: #022C22;
--mmg-color-green-d-300: #A7F3D0;
--mmg-color-green-d-400: #6EE7B7;
--mmg-color-green-d-500: #34D399;
--mmg-color-green-d-600: #10B981;
--mmg-color-green-d-soft: rgba(52, 211, 153, 0.16);
--mmg-color-green-d-border: rgba(52, 211, 153, 0.40);
/* — Amber (Orbit) ——————— */
--mmg-color-amber-50: #FFFBEB;
--mmg-color-amber-100: #FEF3C7;
--mmg-color-amber-200: #FDE68A;
--mmg-color-amber-300: #FCD34D;
--mmg-color-amber-400: #FBBF24;
--mmg-color-amber-500: #D97706;
--mmg-color-amber-600: #B45309;
--mmg-color-amber-700: #92400E;
--mmg-color-amber-800: #78350F;
--mmg-color-amber-900: #451A03;
--mmg-color-amber-d-300: #FDE68A;
--mmg-color-amber-d-400: #FCD34D;
--mmg-color-amber-d-500: #FBBF24;
--mmg-color-amber-d-600: #F59E0B;
--mmg-color-amber-d-soft: rgba(251, 191, 36, 0.16);
--mmg-color-amber-d-border: rgba(251, 191, 36, 0.40);
/* — Red (warnings forts, palette accent rouge) ——————— */
--mmg-color-red-50: #FEF2F2;
--mmg-color-red-100: #FEE2E2;
--mmg-color-red-200: #FECACA;
--mmg-color-red-300: #FCA5A5;
--mmg-color-red-400: #F87171;
--mmg-color-red-500: #DC2626;
--mmg-color-red-600: #B91C1C;
--mmg-color-red-700: #991B1B;
--mmg-color-red-800: #7F1D1D;
--mmg-color-red-900: #450A0A;
--mmg-color-red-d-300: #FCA5A5;
--mmg-color-red-d-400: #F87171;
--mmg-color-red-d-500: #F87171;
--mmg-color-red-d-600: #EF4444;
--mmg-color-red-d-soft: rgba(248, 113, 113, 0.16);
--mmg-color-red-d-border: rgba(248, 113, 113, 0.40);
/* — Cyan ——————— */
--mmg-color-cyan-50: #ECFEFF;
--mmg-color-cyan-100: #CFFAFE;
--mmg-color-cyan-200: #A5F3FC;
--mmg-color-cyan-300: #67E8F9;
--mmg-color-cyan-400: #22D3EE;
--mmg-color-cyan-500: #0891B2;
--mmg-color-cyan-600: #0E7490;
--mmg-color-cyan-700: #155E75;
--mmg-color-cyan-800: #164E63;
--mmg-color-cyan-900: #083344;
--mmg-color-cyan-d-300: #67E8F9;
--mmg-color-cyan-d-400: #22D3EE;
--mmg-color-cyan-d-500: #22D3EE;
--mmg-color-cyan-d-600: #06B6D4;
--mmg-color-cyan-d-soft: rgba(34, 211, 238, 0.16);
--mmg-color-cyan-d-border: rgba(34, 211, 238, 0.40);
/* — Slate (preset accent neutre élégant pour ceux qui veulent moins de couleur) ——————— */
--mmg-color-slate-50: #F8FAFC;
--mmg-color-slate-100: #F1F5F9;
--mmg-color-slate-200: #E2E8F0;
--mmg-color-slate-300: #CBD5E1;
--mmg-color-slate-400: #94A3B8;
--mmg-color-slate-500: #475569;
--mmg-color-slate-600: #334155;
--mmg-color-slate-700: #1E293B;
--mmg-color-slate-800: #0F172A;
--mmg-color-slate-900: #020617;
--mmg-color-slate-d-300: #CBD5E1;
--mmg-color-slate-d-400: #94A3B8;
--mmg-color-slate-d-500: #94A3B8;
--mmg-color-slate-d-600: #64748B;
--mmg-color-slate-d-soft: rgba(148, 163, 184, 0.16);
--mmg-color-slate-d-border: rgba(148, 163, 184, 0.40);
}
+181
View File
@@ -0,0 +1,181 @@
/* ════════════════════════════════════════════════════════════════
DSMMG — Semantic tokens
Mappent les primitives à des rôles UI. CONSOMMÉS par les composants.
Light + dark via [data-mmg-theme] / prefers-color-scheme.
════════════════════════════════════════════════════════════════ */
:root,
[data-mmg-theme="light"] {
/* — Surfaces ————————————————————————————————— */
--mmg-color-bg-page: var(--mmg-color-neutral-50);
--mmg-color-bg-surface: var(--mmg-color-neutral-0);
--mmg-color-bg-raised: #FAFAFE;
--mmg-color-bg-muted: var(--mmg-color-neutral-150);
--mmg-color-bg-subtle: var(--mmg-color-neutral-100);
--mmg-color-bg-overlay: rgba(13, 12, 24, 0.55);
/* — Borders ————————————————————————————————— */
--mmg-color-border: var(--mmg-color-neutral-200);
--mmg-color-border-soft: #EEECFD;
--mmg-color-border-strong: var(--mmg-color-neutral-300);
/* — Texte ————————————————————————————————————————————————
text-tertiary bumpé de neutral-500 (4.02:1, fail AA) à neutral-600
(7.85:1, pass AA) pour garantir le contraste sur hint/placeholder/
caption qui sont du texte SMALL. text-quaternary descend d'un cran. */
--mmg-color-text-primary: var(--mmg-color-neutral-900);
--mmg-color-text-secondary: var(--mmg-color-neutral-700);
--mmg-color-text-tertiary: var(--mmg-color-neutral-600);
--mmg-color-text-quaternary: var(--mmg-color-neutral-500);
--mmg-color-text-inverse: var(--mmg-color-neutral-0);
/* — Sémantique (FIXE — ne change jamais avec l'accent user) —————— */
--mmg-color-success: #059669;
--mmg-color-success-soft: var(--mmg-color-green-50);
--mmg-color-success-border: #A7F3D0;
--mmg-color-success-strong: var(--mmg-color-green-800);
--mmg-color-success-on: var(--mmg-color-neutral-0);
/* Amber-500 (#D97706) sur bg-page = 2.96:1 → fail AA composant. Bump
vers amber-600 pour passer 3.5:1 AA confortablement. */
--mmg-color-warning: var(--mmg-color-amber-600);
--mmg-color-warning-soft: var(--mmg-color-amber-50);
--mmg-color-warning-border: var(--mmg-color-amber-200);
--mmg-color-warning-strong: var(--mmg-color-amber-700);
--mmg-color-warning-on: var(--mmg-color-neutral-0);
--mmg-color-danger: var(--mmg-color-red-500);
--mmg-color-danger-soft: var(--mmg-color-red-50);
--mmg-color-danger-border: var(--mmg-color-red-200);
--mmg-color-danger-strong: var(--mmg-color-red-700);
--mmg-color-danger-on: var(--mmg-color-neutral-0);
--mmg-color-info: var(--mmg-color-blue-500);
--mmg-color-info-soft: var(--mmg-color-blue-50);
--mmg-color-info-border: var(--mmg-color-blue-200);
--mmg-color-info-strong: var(--mmg-color-blue-700);
--mmg-color-info-on: var(--mmg-color-neutral-0);
/* — Ombres ————————————————————————————————— */
--mmg-shadow-1: 0 1px 4px rgba(80, 60, 180, 0.07), 0 0 0 1px rgba(80, 60, 180, 0.06);
--mmg-shadow-2: 0 4px 16px rgba(80, 60, 180, 0.09), 0 0 0 1px rgba(80, 60, 180, 0.04);
--mmg-shadow-3: 0 12px 32px rgba(80, 60, 180, 0.12);
--mmg-shadow-elevated: 0 1px 3px rgba(0, 0, 0, 0.08), 0 1px 2px rgba(0, 0, 0, 0.04);
--mmg-shadow-elevated-hover: 0 4px 8px rgba(0, 0, 0, 0.10), 0 2px 4px rgba(0, 0, 0, 0.06);
--mmg-shadow-flat: 0 1px 2px rgba(0, 0, 0, 0.04);
/* Ombres teintées accent — calculées à partir de --mmg-color-accent. */
--mmg-shadow-accent: 0 1px 2px color-mix(in srgb, var(--mmg-color-accent) 25%, transparent),
0 2px 6px color-mix(in srgb, var(--mmg-color-accent) 20%, transparent);
--mmg-shadow-accent-hover: 0 2px 4px color-mix(in srgb, var(--mmg-color-accent) 30%, transparent),
0 6px 14px color-mix(in srgb, var(--mmg-color-accent) 25%, transparent);
--mmg-shadow-accent-soft: 0 2px 6px color-mix(in srgb, var(--mmg-color-accent) 22%, transparent);
--mmg-shadow-focus: 0 0 0 3px color-mix(in srgb, var(--mmg-color-accent) 25%, transparent);
/* — Artwork (pictogrammes) ——————————— */
--mmg-color-art-major: var(--mmg-color-accent);
--mmg-color-art-minor: var(--mmg-color-accent-strong);
--mmg-color-art-light: var(--mmg-color-accent-soft);
--mmg-color-art-dark: #1F2347;
--mmg-color-art-accent: var(--mmg-color-blue-500);
/* — États système ————————————————————— */
--mmg-color-state-disabled-bg: var(--mmg-color-neutral-100);
--mmg-color-state-disabled-text: var(--mmg-color-neutral-400);
--mmg-color-state-disabled-border: var(--mmg-color-neutral-200);
--mmg-color-state-selection-bg: color-mix(in srgb, var(--mmg-color-accent) 22%, transparent);
--mmg-color-state-selection-text: var(--mmg-color-text-primary);
}
/* ════════════════════════════════════════════════════════════════
Dark theme — surfaces neutres, accent pop
════════════════════════════════════════════════════════════════ */
[data-mmg-theme="dark"] {
--mmg-color-bg-page: var(--mmg-color-gray-d-bg);
--mmg-color-bg-surface: var(--mmg-color-gray-d-surface);
--mmg-color-bg-raised: var(--mmg-color-gray-d-raised);
--mmg-color-bg-muted: var(--mmg-color-gray-d-muted);
--mmg-color-bg-subtle: var(--mmg-color-gray-d-subtle);
--mmg-color-bg-overlay: rgba(0, 0, 0, 0.78);
--mmg-color-border: var(--mmg-color-gray-d-border);
--mmg-color-border-soft: var(--mmg-color-gray-d-border-soft);
--mmg-color-border-strong: var(--mmg-color-gray-d-border-strong);
--mmg-color-text-primary: var(--mmg-color-gray-d-text-1);
--mmg-color-text-secondary: var(--mmg-color-gray-d-text-2);
--mmg-color-text-tertiary: var(--mmg-color-gray-d-text-3);
--mmg-color-text-quaternary: var(--mmg-color-gray-d-text-4);
/* Sémantique dark */
--mmg-color-success: var(--mmg-color-green-d-500);
--mmg-color-success-soft: var(--mmg-color-green-d-soft);
--mmg-color-success-border: var(--mmg-color-green-d-border);
--mmg-color-success-strong: var(--mmg-color-green-d-300);
--mmg-color-warning: var(--mmg-color-amber-d-500);
--mmg-color-warning-soft: var(--mmg-color-amber-d-soft);
--mmg-color-warning-border: var(--mmg-color-amber-d-border);
--mmg-color-warning-strong: var(--mmg-color-amber-d-300);
--mmg-color-warning-on: var(--mmg-color-amber-900);
--mmg-color-danger: var(--mmg-color-red-d-500);
--mmg-color-danger-soft: var(--mmg-color-red-d-soft);
--mmg-color-danger-border: var(--mmg-color-red-d-border);
--mmg-color-danger-strong: var(--mmg-color-red-d-300);
--mmg-color-info: var(--mmg-color-blue-d-500);
--mmg-color-info-soft: var(--mmg-color-blue-d-soft);
--mmg-color-info-border: var(--mmg-color-blue-d-border);
--mmg-color-info-strong: var(--mmg-color-blue-d-300);
/* Ombres : noir + halo blanc subtil */
--mmg-shadow-1: 0 1px 3px rgba(0, 0, 0, 0.55), 0 0 0 1px rgba(255, 255, 255, 0.04);
--mmg-shadow-2: 0 6px 18px rgba(0, 0, 0, 0.60), 0 0 0 1px rgba(255, 255, 255, 0.05);
--mmg-shadow-3: 0 16px 40px rgba(0, 0, 0, 0.70), 0 0 0 1px rgba(255, 255, 255, 0.06);
--mmg-shadow-elevated: 0 1px 3px rgba(0, 0, 0, 0.40), 0 0 0 1px rgba(255, 255, 255, 0.05);
--mmg-shadow-elevated-hover: 0 4px 12px rgba(0, 0, 0, 0.50), 0 0 0 1px rgba(255, 255, 255, 0.06);
--mmg-shadow-flat: 0 0 0 1px rgba(255, 255, 255, 0.04);
--mmg-shadow-focus: 0 0 0 3px color-mix(in srgb, var(--mmg-color-accent) 55%, transparent);
/* États dark */
--mmg-color-state-disabled-bg: #1E222C;
--mmg-color-state-disabled-text: #5A6072;
--mmg-color-state-disabled-border: var(--mmg-color-gray-d-border);
/* Artwork dark */
--mmg-color-art-light: #1E222C;
--mmg-color-art-dark: #E5E8F0;
}
/* prefers-color-scheme: dark — applique les overrides si l'user n'a pas
forcé [data-mmg-theme]. */
@media (prefers-color-scheme: dark) {
:root:not([data-mmg-theme="light"]) {
--mmg-color-bg-page: var(--mmg-color-gray-d-bg);
--mmg-color-bg-surface: var(--mmg-color-gray-d-surface);
--mmg-color-bg-raised: var(--mmg-color-gray-d-raised);
--mmg-color-bg-muted: var(--mmg-color-gray-d-muted);
--mmg-color-bg-subtle: var(--mmg-color-gray-d-subtle);
--mmg-color-bg-overlay: rgba(0, 0, 0, 0.78);
--mmg-color-border: var(--mmg-color-gray-d-border);
--mmg-color-border-soft: var(--mmg-color-gray-d-border-soft);
--mmg-color-border-strong: var(--mmg-color-gray-d-border-strong);
--mmg-color-text-primary: var(--mmg-color-gray-d-text-1);
--mmg-color-text-secondary: var(--mmg-color-gray-d-text-2);
--mmg-color-text-tertiary: var(--mmg-color-gray-d-text-3);
--mmg-color-text-quaternary: var(--mmg-color-gray-d-text-4);
--mmg-color-success: var(--mmg-color-green-d-500);
--mmg-color-success-soft: var(--mmg-color-green-d-soft);
--mmg-color-success-border: var(--mmg-color-green-d-border);
--mmg-color-warning: var(--mmg-color-amber-d-500);
--mmg-color-warning-soft: var(--mmg-color-amber-d-soft);
--mmg-color-warning-border: var(--mmg-color-amber-d-border);
--mmg-color-danger: var(--mmg-color-red-d-500);
--mmg-color-danger-soft: var(--mmg-color-red-d-soft);
--mmg-color-danger-border: var(--mmg-color-red-d-border);
--mmg-color-info: var(--mmg-color-blue-d-500);
--mmg-color-info-soft: var(--mmg-color-blue-d-soft);
--mmg-color-info-border: var(--mmg-color-blue-d-border);
}
}
+98
View File
@@ -0,0 +1,98 @@
/* ════════════════════════════════════════════════════════════════
DSMMG — System tokens (non-color)
Espacements, rayons, typographie, motion, density, z-index, layout.
════════════════════════════════════════════════════════════════ */
:root {
/* — Rayons ————————————————————————————————— */
--mmg-radius-pill: 9999px;
--mmg-radius-sm: 8px;
--mmg-radius-md: 12px;
--mmg-radius-card: 20px;
--mmg-radius-panel: 24px;
--mmg-radius-icon: 12px;
/* — Espacement (4pt grid) ————————————————————— */
--mmg-space-0: 0;
--mmg-space-1: 4px;
--mmg-space-2: 8px;
--mmg-space-3: 12px;
--mmg-space-4: 16px;
--mmg-space-5: 20px;
--mmg-space-6: 24px;
--mmg-space-7: 32px;
--mmg-space-8: 40px;
--mmg-space-9: 48px;
--mmg-space-10: 64px;
--mmg-space-11: 80px;
--mmg-space-12: 120px;
/* — Typographie ————————————————————————————————— */
--mmg-font-sans: "Figtree", system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
--mmg-font-mono: ui-monospace, "JetBrains Mono", "SF Mono", Menlo, monospace;
--mmg-font-size-xs: 11px;
--mmg-font-size-sm: 13px;
--mmg-font-size-base: 15px;
--mmg-font-size-lg: 17px;
--mmg-font-size-xl: 20px;
--mmg-font-size-2xl: 24px;
--mmg-font-size-3xl: 30px;
--mmg-font-size-4xl: 36px;
--mmg-font-size-5xl: 48px;
--mmg-line-height-tight: 1.2;
--mmg-line-height-snug: 1.4;
--mmg-line-height-normal: 1.6;
--mmg-font-weight-regular: 400;
--mmg-font-weight-medium: 500;
--mmg-font-weight-semi: 600;
--mmg-font-weight-bold: 700;
--mmg-font-weight-extra: 800;
/* — Motion ————————————————————————————————— */
--mmg-ease-default: cubic-bezier(0.4, 0, 0.2, 1);
--mmg-ease-emphasis: cubic-bezier(0.2, 0.8, 0.2, 1);
--mmg-duration-fast: 120ms;
--mmg-duration-base: 200ms;
--mmg-duration-slow: 320ms;
/* — Layout ————————————————————————————————— */
--mmg-container-max: 1200px;
--mmg-container-narrow: 800px;
--mmg-container-wide: 1440px;
--mmg-z-dropdown: 100;
--mmg-z-sticky: 200;
--mmg-z-modal: 1000;
--mmg-z-toast: 1100;
--mmg-z-tooltip: 1200;
/* — Touch targets (Apple HIG / WCAG SC 2.5.5) ————— */
--mmg-touch-min: 44px;
/* — Densité (multiplicateurs) ————————————————————————
comfortable = défaut, cozy = pro, compact = power user.
Appliqué via [data-mmg-density] sur sous-arbre. */
--mmg-density-scale: 1;
--mmg-density-row-height: 44px;
--mmg-density-input-height: 40px;
--mmg-density-padding-x: var(--mmg-space-4);
--mmg-density-padding-y: var(--mmg-space-3);
}
[data-mmg-density="cozy"] {
--mmg-density-scale: 0.85;
--mmg-density-row-height: 36px;
--mmg-density-input-height: 36px;
--mmg-density-padding-x: var(--mmg-space-3);
--mmg-density-padding-y: var(--mmg-space-2);
}
[data-mmg-density="compact"] {
--mmg-density-scale: 0.72;
--mmg-density-row-height: 28px;
--mmg-density-input-height: 30px;
--mmg-density-padding-x: var(--mmg-space-2);
--mmg-density-padding-y: 4px;
}
+141
View File
@@ -0,0 +1,141 @@
/* ════════════════════════════════════════════════════════════════
DSMMG — Utility classes
Composables, opt-in, sans charger un composant. Préfixe mmg-u-.
════════════════════════════════════════════════════════════════ */
/* — Layout primitives ————————————————————————— */
.mmg-u-stack { display: flex; flex-direction: column; }
.mmg-u-stack-1 { gap: var(--mmg-space-1); }
.mmg-u-stack-2 { gap: var(--mmg-space-2); }
.mmg-u-stack-3 { gap: var(--mmg-space-3); }
.mmg-u-stack-4 { gap: var(--mmg-space-4); }
.mmg-u-stack-6 { gap: var(--mmg-space-6); }
.mmg-u-stack-8 { gap: var(--mmg-space-7); }
.mmg-u-flex { display: flex; }
.mmg-u-flex-row { display: flex; flex-direction: row; }
.mmg-u-flex-col { display: flex; flex-direction: column; }
.mmg-u-grid { display: grid; }
.mmg-u-inline { display: inline-flex; }
.mmg-u-items-start { align-items: flex-start; }
.mmg-u-items-center { align-items: center; }
.mmg-u-items-end { align-items: flex-end; }
.mmg-u-items-stretch { align-items: stretch; }
.mmg-u-justify-start { justify-content: flex-start; }
.mmg-u-justify-center { justify-content: center; }
.mmg-u-justify-end { justify-content: flex-end; }
.mmg-u-justify-between { justify-content: space-between; }
.mmg-u-justify-around { justify-content: space-around; }
.mmg-u-gap-1 { gap: var(--mmg-space-1); }
.mmg-u-gap-2 { gap: var(--mmg-space-2); }
.mmg-u-gap-3 { gap: var(--mmg-space-3); }
.mmg-u-gap-4 { gap: var(--mmg-space-4); }
.mmg-u-gap-6 { gap: var(--mmg-space-6); }
.mmg-u-cluster { display: flex; flex-wrap: wrap; gap: var(--mmg-space-3); align-items: center; }
.mmg-u-center { display: grid; place-items: center; }
.mmg-u-spacer { flex: 1 1 auto; }
.mmg-u-w-full { width: 100%; }
.mmg-u-h-full { height: 100%; }
/* — Visibility ————————————————————————— */
.mmg-u-hidden { display: none !important; }
.mmg-u-invisible { visibility: hidden; }
/* — Text ————————————————————————— */
.mmg-u-text-xs { font-size: var(--mmg-font-size-xs); }
.mmg-u-text-sm { font-size: var(--mmg-font-size-sm); }
.mmg-u-text-base { font-size: var(--mmg-font-size-base); }
.mmg-u-text-lg { font-size: var(--mmg-font-size-lg); }
.mmg-u-text-xl { font-size: var(--mmg-font-size-xl); }
.mmg-u-text-2xl { font-size: var(--mmg-font-size-2xl); }
.mmg-u-text-primary { color: var(--mmg-color-text-primary); }
.mmg-u-text-secondary { color: var(--mmg-color-text-secondary); }
.mmg-u-text-tertiary { color: var(--mmg-color-text-tertiary); }
.mmg-u-text-accent { color: var(--mmg-color-accent); }
.mmg-u-text-success { color: var(--mmg-color-success); }
.mmg-u-text-danger { color: var(--mmg-color-danger); }
.mmg-u-text-warning { color: var(--mmg-color-warning); }
.mmg-u-text-left { text-align: left; }
.mmg-u-text-center { text-align: center; }
.mmg-u-text-right { text-align: right; }
.mmg-u-font-regular { font-weight: var(--mmg-font-weight-regular); }
.mmg-u-font-medium { font-weight: var(--mmg-font-weight-medium); }
.mmg-u-font-semi { font-weight: var(--mmg-font-weight-semi); }
.mmg-u-font-bold { font-weight: var(--mmg-font-weight-bold); }
.mmg-u-truncate {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
/* — Background / surfaces ————————————————————————— */
.mmg-u-bg-page { background: var(--mmg-color-bg-page); }
.mmg-u-bg-surface { background: var(--mmg-color-bg-surface); }
.mmg-u-bg-raised { background: var(--mmg-color-bg-raised); }
.mmg-u-bg-muted { background: var(--mmg-color-bg-muted); }
.mmg-u-bg-accent { background: var(--mmg-color-accent); color: var(--mmg-color-accent-on); }
/* — Margins / paddings ————————————————————————— */
.mmg-u-m-0 { margin: 0; }
.mmg-u-mt-1 { margin-top: var(--mmg-space-1); }
.mmg-u-mt-2 { margin-top: var(--mmg-space-2); }
.mmg-u-mt-3 { margin-top: var(--mmg-space-3); }
.mmg-u-mt-4 { margin-top: var(--mmg-space-4); }
.mmg-u-mt-6 { margin-top: var(--mmg-space-6); }
.mmg-u-mb-1 { margin-bottom: var(--mmg-space-1); }
.mmg-u-mb-2 { margin-bottom: var(--mmg-space-2); }
.mmg-u-mb-3 { margin-bottom: var(--mmg-space-3); }
.mmg-u-mb-4 { margin-bottom: var(--mmg-space-4); }
.mmg-u-mb-6 { margin-bottom: var(--mmg-space-6); }
.mmg-u-p-0 { padding: 0; }
.mmg-u-p-2 { padding: var(--mmg-space-2); }
.mmg-u-p-3 { padding: var(--mmg-space-3); }
.mmg-u-p-4 { padding: var(--mmg-space-4); }
.mmg-u-p-6 { padding: var(--mmg-space-6); }
/* — Radius / shadow ————————————————————————— */
.mmg-u-rounded-sm { border-radius: var(--mmg-radius-sm); }
.mmg-u-rounded-md { border-radius: var(--mmg-radius-md); }
.mmg-u-rounded-pill { border-radius: var(--mmg-radius-pill); }
.mmg-u-rounded-card { border-radius: var(--mmg-radius-card); }
.mmg-u-shadow-1 { box-shadow: var(--mmg-shadow-1); }
.mmg-u-shadow-2 { box-shadow: var(--mmg-shadow-2); }
.mmg-u-shadow-3 { box-shadow: var(--mmg-shadow-3); }
.mmg-u-shadow-flat { box-shadow: var(--mmg-shadow-flat); }
/* — A11y ————————————————————————— */
.mmg-u-sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border: 0;
}
.mmg-u-focus-visible {
outline: 2px solid var(--mmg-color-accent);
outline-offset: 2px;
}
/* — Forced colors (Windows High Contrast) ————————————————————————— */
@media (forced-colors: active) {
.mmg-u-bg-accent,
.mmg-u-text-accent {
forced-color-adjust: none;
}
}