Aller au contenu
Bibliotheque UIJABS

Patterns produit 14 variantes

Les schemas devenus des attentes dans un logiciel metier. Un utilisateur qui a deja vu Linear, Notion ou Asana les cherche, et leur absence se remarque plus que leur presence. Trois regles : tout ce qui est atteignable au clavier doit l'etre, une action de masse est toujours annulable, et la palette de commandes s'ajoute a la navigation visible sans jamais la remplacer.

A. Navigation et recherche

Palette de commandes, recherche globale dans les donnees, barre laterale a sous-navigation, aide aux raccourcis.

Palette de commandes

Devenue une attente au-dela d'une dizaine de rubriques : au lieu de chercher dans un menu, on tape ce qu'on veut faire. Elle s'ouvre sur Cmd+K, se ferme sur Echap, et se pilote entierement aux fleches.

Voir le codeMasquer le code
<div class="pr-palette-scene">
  <div class="modale__voile"></div>
  <div class="pr-palette" role="dialog" aria-modal="true" aria-label="Palette de commandes">
    <div class="pr-palette__saisie"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg><input value="dev" placeholder="Rechercher ou taper une commande" autofocus><kbd class="btn__kbd">Echap</kbd></div>
    <div class="pr-palette__liste" role="listbox">
      <div class="pr-palette__groupe">Aller a</div>
      <div class="pr-palette__item is-actif" role="option" aria-selected="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"/><path d="M14 2v6h6M9 15h6"/></svg><span>Devis</span><kbd class="btn__kbd">G puis D</kbd></div>
      <div class="pr-palette__item" role="option"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg><span>Tableau de bord</span><kbd class="btn__kbd">G puis T</kbd></div>
      <div class="pr-palette__groupe">Actions</div>
      <div class="pr-palette__item" role="option"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg><span>Nouveau devis</span><kbd class="btn__kbd">N</kbd></div>
      <div class="pr-palette__item" role="option"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg><span>Exporter les devis du mois</span></div>
      <div class="pr-palette__groupe">Resultats</div>
      <div class="pr-palette__item" role="option"><span class="pr-palette__ref">2026-103</span><span>Krissi Julien &mdash; devis signe</span></div>
      <div class="pr-palette__item" role="option"><span class="pr-palette__ref">2026-118</span><span>Martin Sophie &mdash; devis envoye</span></div>
    </div>
    <div class="pr-palette__pied">
      <span><kbd class="btn__kbd">Haut</kbd><kbd class="btn__kbd">Bas</kbd> naviguer</span>
      <span><kbd class="btn__kbd">Entree</kbd> ouvrir</span>
      <span><kbd class="btn__kbd">Cmd K</kbd> rouvrir</span>
    </div>
  </div>
</div>
.pr-palette-scene {
  position: relative;
  display: grid;
  justify-items: center;
  align-items: start;
  width: 100%;
  min-height: 400px;
  padding: var(--sp-8) var(--sp-5) var(--sp-5);
  border-radius: var(--r-md);
  background: var(--c-surface-3);
  overflow: hidden;
}
.pr-palette {
  position: relative;
  z-index: 1;
  width: 100%;
  max-width: 580px;
  border: 1px solid var(--c-border);
  border-radius: var(--r-lg);
  background: var(--c-surface);
  box-shadow: var(--sh-4);
  overflow: hidden;
}
.pr-palette__saisie {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-4);
  border-bottom: 1px solid var(--c-border);
}
.pr-palette__saisie svg { width: 18px; height: 18px; color: var(--c-text-muted); flex: none; }
.pr-palette__saisie input {
  flex: 1;
  border: none;
  background: transparent;
  font-family: var(--font-ui);
  font-size: var(--fs-lg);
  color: var(--c-text);
  outline: none;
}
.pr-palette__liste { max-height: 260px; overflow-y: auto; padding: var(--sp-2); }
.pr-palette__groupe {
  padding: var(--sp-2) var(--sp-2) 4px;
  font-size: 10px;
  font-weight: var(--fw-bold);
  text-transform: uppercase;
  letter-spacing: .08em;
  color: var(--c-text-muted);
}
.pr-palette__item {
  display: flex;
  align-items: center;
  gap: var(--sp-3);
  padding: var(--sp-2) var(--sp-3);
  border-radius: var(--r-sm);
  font-size: var(--fs-md);
  color: var(--c-text);
  cursor: pointer;
}
.pr-palette__item svg { width: 16px; height: 16px; color: var(--c-text-muted); flex: none; }
.pr-palette__item > span:not(.pr-palette__ref) { flex: 1; }
.pr-palette__item kbd { margin-left: auto; }
.pr-palette__item.is-actif, .pr-palette__item:hover { background: var(--c-primary-soft); }
.pr-palette__item.is-actif svg { color: var(--c-primary); }
.pr-palette__ref { font-family: var(--font-mono); font-size: var(--fs-xs); color: var(--c-text-muted); flex: none; }
.pr-palette__pied {
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-4);
  padding: var(--sp-2) var(--sp-4);
  border-top: 1px solid var(--c-border);
  background: var(--c-surface-2);
  font-size: var(--fs-xs);
  color: var(--c-text-muted);
}
.pr-palette__pied span { display: inline-flex; align-items: center; gap: 5px; }
fixed inset-0 grid place-items-start pt-24 + un panneau de 620 px
Clients — 2
Martin SophieColombes (92) — 3 dossiers
Martinez PaulBondy (93) — 1 dossier
Devis — 1
2026-118Martin Sophie — chauffe-eau1 890,00 EUR — envoye le 29 aout
Documents — 4
Devis Martin.pdfDossier 2026-118 — 248 Ko
Recherche globale

Differente de la palette : elle cherche dans les DONNEES, pas dans les commandes. Les resultats sont groupes par type et le terme cherche est surligne dans chaque ligne.

Voir le codeMasquer le code
<div class="pr-recherche">
  <div class="pr-palette__saisie"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/></svg><input value="martin" placeholder="Rechercher"></div>
  <div class="pr-palette__liste">
    <div class="pr-palette__groupe">Clients &mdash; 2</div>
    <div class="pr-palette__item is-actif"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"/><path d="M14 2v6h6M9 15h6"/></svg><span><b>Martin</b> Sophie<small>Colombes (92) &mdash; 3 dossiers</small></span></div>
    <div class="pr-palette__item"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"/><path d="M14 2v6h6M9 15h6"/></svg><span><b>Martin</b>ez Paul<small>Bondy (93) &mdash; 1 dossier</small></span></div>
    <div class="pr-palette__groupe">Devis &mdash; 1</div>
    <div class="pr-palette__item"><span class="pr-palette__ref">2026-118</span><span><b>Martin</b> Sophie &mdash; chauffe-eau<small>1 890,00 EUR &mdash; envoye le 29 aout</small></span></div>
    <div class="pr-palette__groupe">Documents &mdash; 4</div>
    <div class="pr-palette__item"><svg viewBox="0 0 24 24" fill="none" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z" fill="#e8453c"/><path d="M14 2v6h6" fill="#fff" fill-opacity=".35"/><text x="12" y="17" font-family="system-ui,sans-serif" font-size="6.5" font-weight="700" fill="#fff" text-anchor="middle">PDF</text></svg><span>Devis <b>Martin</b>.pdf<small>Dossier 2026-118 &mdash; 248 Ko</small></span></div>
  </div>
</div>
.pr-recherche { width: 100%; max-width: 580px; border: 1px solid var(--c-border); border-radius: var(--r-lg); background: var(--c-surface); box-shadow: var(--sh-2); overflow: hidden; }
.pr-recherche .pr-palette__item span { display: flex; flex-direction: column; gap: 1px; }
.pr-recherche small { font-size: var(--fs-xs); color: var(--c-text-muted); font-weight: var(--fw-normal); }
.pr-recherche b { background: var(--c-warn-soft); color: var(--c-text); font-weight: var(--fw-bold); border-radius: 2px; padding: 0 1px; }
le terme cherche est enveloppe dans <b> cote serveur, pas surligne en CSS
Barre laterale a sous-navigation

Le schema dominant en 2026 : une rubrique s'ouvre en sous-menu contextuel plutot qu'en arborescence permanente. Seule la section courante est depliee, le reste reste replie.

Voir le codeMasquer le code
<div class="pr-cote-demo">
  <aside class="nav-cote">
    <div class="nav-cote__marque">JABS<span> CRM</span></div>
    <nav>
      <a href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/></svg> Tableau de bord</a>
      <a href="#" aria-current="page"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8Z"/><path d="M14 2v6h6M9 15h6"/></svg> Dossiers <b class="btn__badge">24</b></a>
      <div class="pr-sous">
        <a href="#" class="is-actif">En cours <span>12</span></a>
        <a href="#">A relancer <span>5</span></a>
        <a href="#">Signes <span>7</span></a>
        <a href="#">Archives</a>
      </div>
      <a href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="18" rx="2"/><path d="M16 2v4M8 2v4M3 10h18"/></svg> Planning</a>
      <a href="#"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="5" rx="1"/><path d="M5 9v10a1 1 0 0 0 1 1h12a1 1 0 0 0 1-1V9M10 13h4"/></svg> Documents</a>
    </nav>
    <div class="pr-cote-pied">
      <button class="btn btn--fantome btn--dense"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01"/></svg> Replier</button>
    </div>
  </aside>
  <div class="pr-cote-demo__zone"><span>Contenu de la page</span></div>
</div>
.pr-cote-demo { display: flex; gap: var(--sp-4); width: 100%; align-items: stretch; }
.pr-cote-demo .nav-cote { flex: none; }
.pr-cote-demo__zone {
  flex: 1;
  display: grid;
  place-items: center;
  min-height: 280px;
  border: 1px dashed var(--c-border);
  border-radius: var(--r-lg);
  color: var(--c-text-muted);
  font-size: var(--fs-sm);
}
.pr-sous { display: flex; flex-direction: column; gap: 1px; margin: 2px 0 var(--sp-2); padding-left: var(--sp-6); border-left: 1px solid var(--c-border); margin-left: 16px; }
.pr-sous a {
  display: flex; align-items: center; justify-content: space-between;
  padding: 5px var(--sp-3);
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
  color: var(--c-text-soft);
  text-decoration: none;
}
.pr-sous a span { font-size: var(--fs-xs); color: var(--c-text-muted); font-variant-numeric: tabular-nums; }
.pr-sous a:hover { background: var(--c-surface-2); color: var(--c-text); }
.pr-sous a.is-actif { background: var(--c-primary-soft); color: var(--c-primary-ink); font-weight: var(--fw-semi); }
.pr-cote-pied { margin-top: auto; padding-top: var(--sp-3); border-top: 1px solid var(--c-border); }
le sous-menu n'existe que sous la rubrique ouverte, jamais en permanence

Raccourcis clavier

?
Naviguer
Palette de commandes
Cmd K
Rechercher
/
Aller aux dossiers
GD
Aller au planning
GP
Agir
Nouveau dossier
N
Enregistrer
Cmd S
Tout selectionner
Cmd A
Annuler
Cmd Z
Aide aux raccourcis

Ouverte par la touche point d'interrogation. Elle ne remplace pas l'affichage des raccourcis dans les menus : elle sert a les decouvrir, pas a les retenir.

Voir le codeMasquer le code
<div class="pr-raccourcis">
  <div class="pr-raccourcis__tete"><h4>Raccourcis clavier</h4><kbd class="btn__kbd">?</kbd></div>
  <div class="pr-raccourcis__cols">
    <div>
      <h5>Naviguer</h5>
      <dl><dt>Palette de commandes</dt><dd><kbd class="btn__kbd">Cmd K</kbd></dd>
          <dt>Rechercher</dt><dd><kbd class="btn__kbd">/</kbd></dd>
          <dt>Aller aux dossiers</dt><dd><kbd class="btn__kbd">G</kbd><kbd class="btn__kbd">D</kbd></dd>
          <dt>Aller au planning</dt><dd><kbd class="btn__kbd">G</kbd><kbd class="btn__kbd">P</kbd></dd></dl>
    </div>
    <div>
      <h5>Agir</h5>
      <dl><dt>Nouveau dossier</dt><dd><kbd class="btn__kbd">N</kbd></dd>
          <dt>Enregistrer</dt><dd><kbd class="btn__kbd">Cmd S</kbd></dd>
          <dt>Tout selectionner</dt><dd><kbd class="btn__kbd">Cmd A</kbd></dd>
          <dt>Annuler</dt><dd><kbd class="btn__kbd">Cmd Z</kbd></dd></dl>
    </div>
  </div>
</div>
.pr-raccourcis { width: 100%; max-width: 560px; padding: var(--sp-5); border: 1px solid var(--c-border); border-radius: var(--r-lg); background: var(--c-surface); box-shadow: var(--sh-3); }
.pr-raccourcis__tete { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--sp-4); }
.pr-raccourcis__tete h4 { margin: 0; font-size: var(--fs-lg); font-weight: var(--fw-bold); }
.pr-raccourcis__cols { display: grid; grid-template-columns: 1fr 1fr; gap: var(--sp-6); }
.pr-raccourcis h5 { margin: 0 0 var(--sp-2); font-size: 10px; font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .08em; color: var(--c-text-muted); }
.pr-raccourcis dl { display: grid; grid-template-columns: 1fr auto; gap: 7px var(--sp-3); margin: 0; align-items: center; }
.pr-raccourcis dt { font-size: var(--fs-sm); color: var(--c-text-soft); }
.pr-raccourcis dd { margin: 0; display: flex; gap: 3px; }
@media (max-width: 560px) { .pr-raccourcis__cols { grid-template-columns: 1fr; gap: var(--sp-4); } }
grid-cols-2 gap-8, dl en grid-cols-[1fr_auto]

B. Manipulation des donnees

Edition en ligne, filtres a facettes avec comptes, vues enregistrees, actions de masse, kanban, tri multi-criteres.

ReferenceClientStatutMontant HT
2026-103 Krissi Julien Signe 4 000,00
2026-118 Envoye 1 790,00
2026-121 Durand Paul Brouillon 12 400,00enregistre
Edition en ligne

Modifier une valeur la ou on la voit, sans ouvrir de formulaire. Trois etats : lecture, edition, enregistrement. L'enregistrement se fait a la sortie du champ, jamais sur un bouton cache.

Voir le codeMasquer le code
<div class="tbl__cadre">
  <table class="tbl">
    <thead><tr><th>Reference</th><th>Client</th><th>Statut</th><th class="tbl__nombre">Montant HT</th></tr></thead>
    <tbody>
      <tr><td><code>2026-103</code></td>
        <td><span class="pr-edit">Krissi Julien<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M17 3a2.8 2.8 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/></svg></span></td>
        <td><span class="doc-etiq doc-etiq--ok">Signe</span></td>
        <td class="tbl__nombre"><span class="pr-edit">4 000,00<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M17 3a2.8 2.8 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/></svg></span></td></tr>
      <tr><td><code>2026-118</code></td>
        <td><span class="pr-edit is-edition"><input class="saisie" value="Martin Sophie"></span></td>
        <td><span class="doc-etiq doc-etiq--attente">Envoye</span></td>
        <td class="tbl__nombre"><span class="pr-edit">1 790,00<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M17 3a2.8 2.8 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/></svg></span></td></tr>
      <tr><td><code>2026-121</code></td>
        <td><span class="pr-edit">Durand Paul<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M17 3a2.8 2.8 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/></svg></span></td>
        <td><span class="doc-etiq doc-etiq--neutre">Brouillon</span></td>
        <td class="tbl__nombre is-enregistre"><span class="pr-edit">12 400,00</span><em>enregistre</em></td></tr>
    </tbody>
  </table>
</div>
.pr-edit {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  padding: 3px 6px;
  margin: -3px -6px;
  border-radius: var(--r-sm);
  cursor: text;
  transition: background-color var(--t-fast);
}
.pr-edit svg { width: 12px; height: 12px; color: var(--c-text-muted); opacity: 0; transition: opacity var(--t-fast); }
.pr-edit:hover { background: var(--c-surface-3); }
.pr-edit:hover svg { opacity: 1; }
.pr-edit.is-edition { padding: 0; margin: 0; background: transparent; }
.pr-edit .saisie { height: 30px; font-size: var(--fs-sm); }
.tbl td.is-enregistre { position: relative; animation: an-surligner 2s ease-out forwards; }
.tbl td.is-enregistre em {
  position: absolute; right: var(--sp-3); top: 50%;
  transform: translateY(-50%);
  font-style: normal; font-size: 10px; font-weight: var(--fw-bold);
  color: var(--c-success);
  animation: pr-effacer 2s ease-out forwards;
}
@keyframes pr-effacer { 0%, 60% { opacity: 1; } 100% { opacity: 0; } }
le crayon n'apparait qu'au survol ; le champ prend la place exacte du texte
Filtres a facettes

Chaque critere affiche le NOMBRE de resultats qu'il donnerait. Sans ce compte, l'utilisateur applique des filtres a l'aveugle et tombe sur une liste vide.

Voir le codeMasquer le code
<div class="pr-facettes">
  <aside>
    <div class="pr-facette">
      <h5>Statut</h5>
      <label class="coche"><input type="checkbox" checked><span class="coche__boite"></span> Signe <b>7</b></label>
      <label class="coche"><input type="checkbox" checked><span class="coche__boite"></span> Envoye <b>12</b></label>
      <label class="coche"><input type="checkbox"><span class="coche__boite"></span> Brouillon <b>5</b></label>
      <label class="coche pr-facette--vide"><input type="checkbox" disabled><span class="coche__boite"></span> Refuse <b>0</b></label>
    </div>
    <div class="pr-facette">
      <h5>Operation</h5>
      <label class="coche"><input type="checkbox"><span class="coche__boite"></span> Pompe a chaleur <b>14</b></label>
      <label class="coche"><input type="checkbox"><span class="coche__boite"></span> Chauffe-eau <b>6</b></label>
      <label class="coche"><input type="checkbox"><span class="coche__boite"></span> Isolation <b>4</b></label>
    </div>
    <div class="pr-facette">
      <h5>Montant</h5>
      <input class="saisie-curseur" type="range" min="0" max="20000" value="14000">
      <span class="champ__bornes"><span>0 EUR</span><span>14 000 EUR</span></span>
    </div>
  </aside>
  <div>
    <div class="doc-filtres__actifs" style="margin-bottom:12px">
      <span class="btn-etiquette btn-etiquette--accent">Signe <button aria-label="Retirer"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg></button></span>
      <span class="btn-etiquette btn-etiquette--accent">Envoye <button aria-label="Retirer"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg></button></span>
      <button class="btn btn--texte btn--dense">Tout effacer</button>
      <span class="cat-head__spacer"></span>
      <span class="tbl-outils__compte">19 dossiers</span>
    </div>
    <ul class="liste">
      <li><a href="#"><span class="liste__bloc"><strong>Krissi Julien</strong><small>2026-103 &mdash; PAC air/eau</small></span><strong>4 280 EUR</strong></a></li>
      <li><a href="#"><span class="liste__bloc"><strong>Martin Sophie</strong><small>2026-118 &mdash; chauffe-eau</small></span><strong>1 890 EUR</strong></a></li>
      <li><a href="#"><span class="liste__bloc"><strong>Lefevre Marc</strong><small>2026-092 &mdash; chaudiere</small></span><strong>3 950 EUR</strong></a></li>
    </ul>
  </div>
</div>
.pr-facettes { display: grid; grid-template-columns: 220px 1fr; gap: var(--sp-6); width: 100%; align-items: start; }
.pr-facette { padding-bottom: var(--sp-4); margin-bottom: var(--sp-4); border-bottom: 1px solid var(--c-border); }
.pr-facette:last-child { border-bottom: none; }
.pr-facette h5 { margin: 0 0 var(--sp-2); font-size: 10px; font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .08em; color: var(--c-text-muted); }
.pr-facette .coche { display: flex; width: 100%; padding: 4px 0; font-size: var(--fs-sm); }
.pr-facette .coche b { margin-left: auto; font-size: var(--fs-xs); font-weight: var(--fw-semi); color: var(--c-text-muted); font-variant-numeric: tabular-nums; }
.pr-facette--vide { opacity: .42; }
@media (max-width: 700px) { .pr-facettes { grid-template-columns: 1fr; } }
grid grid-cols-[220px_1fr] gap-6, chaque facette porte son compte
Vues enregistrees

Un jeu de filtres nomme et reutilisable. C'est ce qui evite de reconstruire le meme filtre chaque matin, et ce qui permet de le partager avec l'equipe.

Voir le codeMasquer le code
<div class="pr-vues">
  <button class="pr-vue is-actif">Mes dossiers <span>12</span></button>
  <button class="pr-vue">A relancer <span>5</span></button>
  <button class="pr-vue">Poses de la semaine <span>3</span></button>
  <button class="pr-vue pr-vue--partage">Equipe Nord <span>8</span><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01"/></svg></button>
  <button class="pr-vue pr-vue--neuf"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg> Enregistrer la vue courante</button>
</div>
.pr-vues { display: flex; flex-wrap: wrap; gap: var(--sp-2); width: 100%; padding-bottom: var(--sp-3); border-bottom: 1px solid var(--c-border); }
.pr-vue {
  display: inline-flex; align-items: center; gap: 7px;
  height: 32px; padding: 0 var(--sp-3);
  border: 1px solid var(--c-border);
  border-radius: var(--r-full);
  background: var(--c-surface);
  font-family: var(--font-ui); font-size: var(--fs-sm); font-weight: var(--fw-medium);
  color: var(--c-text-soft);
  cursor: pointer;
}
.pr-vue span { font-size: var(--fs-xs); color: var(--c-text-muted); font-variant-numeric: tabular-nums; }
.pr-vue svg { width: 13px; height: 13px; }
.pr-vue:hover { border-color: var(--c-border-strong); color: var(--c-text); }
.pr-vue.is-actif { background: var(--c-primary); border-color: var(--c-primary); color: var(--c-primary-text); font-weight: var(--fw-semi); }
.pr-vue.is-actif span { color: rgba(255,255,255,.75); }
.pr-vue--partage svg { color: var(--c-info); }
.pr-vue--neuf { border-style: dashed; color: var(--c-text-muted); }
les vues partagees portent un marqueur : on doit savoir si l'on modifie pour soi ou pour tous
4 lignes selectionnees sur cette page.
4 dossiers
4 dossiers deplaces vers Archives
Actions de masse

La barre n'apparait qu'a la premiere case cochee. Elle rappelle le nombre exact, distingue « tout ce qui est visible » de « tout ce qui existe », et propose d'annuler apres coup.

Voir le codeMasquer le code
<div class="pr-masse">
  <div class="pr-masse__avis">4 lignes selectionnees sur cette page. <button class="btn btn--texte btn--dense">Selectionner les 24 dossiers du filtre</button></div>
  <div class="doc-selection">
    <button class="btn btn--icone btn--fantome btn--sm" aria-label="Annuler la selection"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg></button>
    <strong>4 dossiers</strong>
    <span class="btn-barre__sep"></span>
    <button class="btn btn--fantome btn--dense"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4M7 10l5 5 5-5M12 15V3"/></svg> Exporter</button>
    <button class="btn btn--fantome btn--dense"><svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M3 6a2 2 0 0 1 2-2h4l2 2h8a2 2 0 0 1 2 2v10a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2Z"/></svg> Deplacer</button>
    <button class="btn btn--fantome btn--dense"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="2" y="4" width="20" height="16" rx="2"/><path d="m2 7 10 6 10-6"/></svg> Relancer</button>
    <span class="btn-barre__sep"></span>
    <button class="btn btn--fantome btn--dense doc-selection__danger"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M3 6h18M8 6V4h8v2M19 6l-1 14H6L5 6"/></svg> Supprimer</button>
  </div>
  <div class="toast"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m20 6-11 11-5-5"/></svg><span>4 dossiers deplaces vers Archives</span><button class="btn btn--texte btn--dense">Annuler</button></div>
</div>
.pr-masse { display: flex; flex-direction: column; align-items: center; gap: var(--sp-4); width: 100%; }
.pr-masse__avis {
  width: 100%;
  padding: var(--sp-2) var(--sp-4);
  border-radius: var(--r-md);
  background: var(--c-primary-soft);
  color: var(--c-primary-ink);
  font-size: var(--fs-sm);
  text-align: center;
}
la barre est en position fixe en bas, le message d'annulation la remplace
Devis envoyes
3 — 12 920 EUR
2026-118Martin SophieColombes — chauffe-eau1 890 EURMS
2026-121Durand PaulLe Raincy — isolation12 400 EURDP
2026-097Bernard AliceGagny — sans reponse depuis 14 j6 750 EURBA
Signes
2 — 8 230 EUR
2026-103Krissi JulienNeuilly — PAC air/eau4 280 EURJK
Deposer ici
En pose
1 — 3 950 EUR
2026-092Lefevre MarcChelles — chaudiere3 950 EURLM
Tableau kanban

Le meme jeu de donnees, vu par etape. Chaque colonne affiche son compte et son total : sans eux, on ne sait pas si une colonne qui deborde est un probleme ou la normale.

Voir le codeMasquer le code
<div class="pr-kanban">
  <div class="pr-col">
    <div class="pr-col__tete"><h5>Devis envoyes</h5><span>3 &mdash; 12 920 EUR</span></div>
    <article class="pr-carte"><b>2026-118</b><strong>Martin Sophie</strong><small>Colombes &mdash; chauffe-eau</small><span class="pr-carte__pied"><em>1 890 EUR</em><i class="personne__avatar">MS</i></span></article>
    <article class="pr-carte"><b>2026-121</b><strong>Durand Paul</strong><small>Le Raincy &mdash; isolation</small><span class="pr-carte__pied"><em>12 400 EUR</em><i class="personne__avatar">DP</i></span></article>
    <article class="pr-carte pr-carte--alerte"><b>2026-097</b><strong>Bernard Alice</strong><small>Gagny &mdash; sans reponse depuis 14 j</small><span class="pr-carte__pied"><em>6 750 EUR</em><i class="personne__avatar">BA</i></span></article>
  </div>
  <div class="pr-col">
    <div class="pr-col__tete"><h5>Signes</h5><span>2 &mdash; 8 230 EUR</span></div>
    <article class="pr-carte"><b>2026-103</b><strong>Krissi Julien</strong><small>Neuilly &mdash; PAC air/eau</small><span class="pr-carte__pied"><em>4 280 EUR</em><i class="personne__avatar">JK</i></span></article>
    <div class="pr-depose">Deposer ici</div>
  </div>
  <div class="pr-col">
    <div class="pr-col__tete"><h5>En pose</h5><span>1 &mdash; 3 950 EUR</span></div>
    <article class="pr-carte pr-carte--attrapee"><b>2026-092</b><strong>Lefevre Marc</strong><small>Chelles &mdash; chaudiere</small><span class="pr-carte__pied"><em>3 950 EUR</em><i class="personne__avatar">LM</i></span></article>
  </div>
</div>
.pr-kanban { display: flex; gap: var(--sp-3); width: 100%; overflow-x: auto; padding-bottom: var(--sp-2); }
.pr-col { flex: none; width: 250px; display: flex; flex-direction: column; gap: var(--sp-2); padding: var(--sp-3); border-radius: var(--r-lg); background: var(--c-surface-2); }
.pr-col__tete { display: flex; flex-direction: column; gap: 2px; padding-bottom: var(--sp-2); }
.pr-col__tete h5 { margin: 0; font-size: var(--fs-sm); font-weight: var(--fw-bold); color: var(--c-text); }
.pr-col__tete span { font-size: var(--fs-xs); color: var(--c-text-muted); font-variant-numeric: tabular-nums; }
.pr-carte {
  display: flex; flex-direction: column; gap: 3px;
  padding: var(--sp-3);
  border: 1px solid var(--c-border);
  border-radius: var(--r-md);
  background: var(--c-surface);
  cursor: grab;
  box-shadow: var(--sh-1);
  transition: box-shadow var(--t-fast), transform var(--t-fast);
}
.pr-carte:hover { box-shadow: var(--sh-2); }
.pr-carte b { font-family: var(--font-mono); font-size: 10.5px; color: var(--c-text-muted); }
.pr-carte strong { font-size: var(--fs-md); font-weight: var(--fw-semi); }
.pr-carte small { font-size: var(--fs-xs); color: var(--c-text-muted); line-height: 1.35; }
.pr-carte__pied { display: flex; align-items: center; justify-content: space-between; margin-top: var(--sp-2); }
.pr-carte__pied em { font-style: normal; font-size: var(--fs-sm); font-weight: var(--fw-bold); font-variant-numeric: tabular-nums; }
.pr-carte__pied .personne__avatar { width: 24px; height: 24px; font-size: 9.5px; }
.pr-carte--alerte { border-left: 3px solid var(--c-danger); }
.pr-carte--alerte small { color: var(--c-danger); font-weight: var(--fw-semi); }
.pr-carte--attrapee { transform: rotate(2deg) scale(1.02); box-shadow: var(--sh-4); cursor: grabbing; }
.pr-depose {
  display: grid; place-items: center;
  min-height: 66px;
  border: 2px dashed var(--c-primary);
  border-radius: var(--r-md);
  background: var(--c-primary-soft);
  color: var(--c-primary-ink);
  font-size: var(--fs-xs);
  font-weight: var(--fw-semi);
}
flex gap-3 overflow-x-auto, chaque colonne en flex-col avec un compte en tete
Trier par
1Statut
2Montant
Tri sur plusieurs colonnes

Trier par statut PUIS par montant. L'ordre des criteres est visible et reordonnable : sans cela, personne ne comprend pourquoi la liste est dans cet ordre.

Voir le codeMasquer le code
<div class="pr-tri">
  <div class="pr-tri__tete"><h5>Trier par</h5><button class="btn btn--texte btn--dense">Reinitialiser</button></div>
  <div class="pr-tri__ligne"><span class="liste__poignee"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01"/></svg></span><b>1</b><span>Statut</span><div class="btn-segmente"><button class="btn is-actif">A &rarr; Z</button><button class="btn">Z &rarr; A</button></div><button class="btn btn--icone btn--fantome btn--sm" aria-label="Retirer"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg></button></div>
  <div class="pr-tri__ligne"><span class="liste__poignee"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M8 6h13M8 12h13M8 18h13M3 6h.01M3 12h.01M3 18h.01"/></svg></span><b>2</b><span>Montant</span><div class="btn-segmente"><button class="btn">Croissant</button><button class="btn is-actif">Decroissant</button></div><button class="btn btn--icone btn--fantome btn--sm" aria-label="Retirer"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg></button></div>
  <button class="btn btn--pointille btn--dense" style="width:100%"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg> Ajouter un critere</button>
</div>
.pr-tri { width: 100%; max-width: 520px; padding: var(--sp-4); border: 1px solid var(--c-border); border-radius: var(--r-lg); background: var(--c-surface); box-shadow: var(--sh-2); }
.pr-tri__tete { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--sp-3); }
.pr-tri__tete h5 { margin: 0; font-size: 10px; font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .08em; color: var(--c-text-muted); }
.pr-tri__ligne { display: flex; align-items: center; gap: var(--sp-2); margin-bottom: var(--sp-2); }
.pr-tri__ligne b {
  display: inline-flex; align-items: center; justify-content: center;
  width: 20px; height: 20px; flex: none;
  border-radius: var(--r-full);
  background: var(--c-surface-3);
  font-size: 10px; font-weight: var(--fw-bold);
  color: var(--c-text-soft);
}
.pr-tri__ligne > span:not(.liste__poignee) { flex: 1; font-size: var(--fs-sm); font-weight: var(--fw-semi); }
.pr-tri__ligne .btn-segmente > .btn { height: 26px; padding: 0 var(--sp-2); font-size: 11px; }
chaque critere est une ligne deplacable, numerotee dans l'ordre d'application

C. Accompagnement

Visite guidee, liste de demarrage, annonce de nouveaute, fil d'activite.

Nouveau dossier
2 sur 3
Creez votre premier dossier

Tout part d'ici : le client, le chantier, l'operation. Le devis se genere ensuite en deux clics.

Visite guidee

Trois etapes maximum, et une sortie visible a chaque etape. Une visite qu'on ne peut pas quitter est vecue comme une prise d'otage, pas comme une aide.

Voir le codeMasquer le code
<div class="pr-visite-scene">
  <div class="pr-visite__cible"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M12 5v14M5 12h14"/></svg> Nouveau dossier</div>
  <div class="pr-visite">
    <div class="pr-visite__tete"><span>2 sur 3</span><button class="btn btn--fermer" aria-label="Quitter la visite"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg></button></div>
    <strong>Creez votre premier dossier</strong>
    <p>Tout part d'ici : le client, le chantier, l'operation. Le devis se genere ensuite en deux clics.</p>
    <div class="pr-visite__pied">
      <span class="pr-visite__points"><i></i><i class="c"></i><i></i></span>
      <span><button class="btn btn--fantome btn--sm">Precedent</button><button class="btn btn--plein btn--sm">Suivant</button></span>
    </div>
  </div>
</div>
.pr-visite-scene { position: relative; display: flex; flex-direction: column; align-items: center; gap: var(--sp-5); width: 100%; padding: var(--sp-6); border-radius: var(--r-md); background: var(--c-surface-2); }
.pr-visite__cible {
  display: inline-flex; align-items: center; gap: 7px;
  padding: var(--sp-2) var(--sp-4);
  border-radius: var(--r-md);
  background: var(--c-primary);
  color: var(--c-primary-text);
  font-size: var(--fs-sm); font-weight: var(--fw-semi);
  box-shadow: 0 0 0 4px color-mix(in srgb, var(--c-primary) 26%, transparent);
}
.pr-visite__cible svg { width: 15px; height: 15px; }
.pr-visite {
  position: relative;
  width: 100%; max-width: 320px;
  padding: var(--sp-4);
  border-radius: var(--r-lg);
  background: var(--c-surface);
  box-shadow: var(--sh-4);
}
/* La fleche pointe vers la cible : sans elle, le panneau flotte sans lien. */
.pr-visite::before {
  content: "";
  position: absolute;
  top: -7px; left: 50%;
  margin-left: -7px;
  border: 7px solid transparent;
  border-top: none;
  border-bottom-color: var(--c-surface);
}
.pr-visite__tete { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--sp-2); }
.pr-visite__tete span { font-size: 10px; font-weight: var(--fw-bold); text-transform: uppercase; letter-spacing: .08em; color: var(--c-text-muted); }
.pr-visite strong { display: block; font-size: var(--fs-lg); font-weight: var(--fw-bold); }
.pr-visite p { margin: 5px 0 var(--sp-4); font-size: var(--fs-sm); color: var(--c-text-soft); line-height: 1.5; }
.pr-visite__pied { display: flex; align-items: center; justify-content: space-between; gap: var(--sp-3); }
.pr-visite__pied > span:last-child { display: flex; gap: var(--sp-2); }
.pr-visite__points { display: flex; gap: 5px; }
.pr-visite__points i { width: 6px; height: 6px; border-radius: 50%; background: var(--c-border-strong); }
.pr-visite__points i.c { background: var(--c-primary); width: 18px; border-radius: 3px; }
un panneau ancre a l'element cible, avec fleche et compteur d'etapes
Prise en main3 etapes sur 5 — environ 4 minutes
  • Completer les informations de la societe
  • Ajouter votre logo
  • Creer un premier client
  • 4Emettre un devis
  • 5Inviter un collaborateur
Liste de demarrage

Les premieres actions a accomplir, avec la progression. Elle disparait definitivement une fois terminee : une liste completee qui reste affichee devient un reproche.

Voir le codeMasquer le code
<div class="pr-demarrage">
  <div class="pr-demarrage__tete">
    <div><strong>Prise en main</strong><small>3 etapes sur 5 &mdash; environ 4 minutes</small></div>
    <button class="btn btn--fantome btn--sm">Masquer</button>
  </div>
  <div class="stat__jauge"><span style="--p:60%"></span></div>
  <ul>
    <li class="f"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m20 6-11 11-5-5"/></svg><span>Completer les informations de la societe</span></li>
    <li class="f"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m20 6-11 11-5-5"/></svg><span>Ajouter votre logo</span></li>
    <li class="f"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="m20 6-11 11-5-5"/></svg><span>Creer un premier client</span></li>
    <li class="c"><i>4</i><span>Emettre un devis</span><button class="btn btn--plein btn--dense">Commencer</button></li>
    <li><i>5</i><span>Inviter un collaborateur</span></li>
  </ul>
</div>
.pr-demarrage { width: 100%; max-width: 480px; padding: var(--sp-4); border: 1px solid var(--c-border); border-radius: var(--r-lg); background: var(--c-surface); box-shadow: var(--sh-2); }
.pr-demarrage__tete { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--sp-3); margin-bottom: var(--sp-3); }
.pr-demarrage strong { display: block; font-size: var(--fs-lg); font-weight: var(--fw-bold); }
.pr-demarrage small { font-size: var(--fs-xs); color: var(--c-text-muted); }
.pr-demarrage ul { list-style: none; margin: var(--sp-4) 0 0; padding: 0; display: flex; flex-direction: column; gap: 2px; }
.pr-demarrage li {
  display: flex; align-items: center; gap: var(--sp-3);
  padding: var(--sp-2);
  border-radius: var(--r-sm);
  font-size: var(--fs-sm);
}
.pr-demarrage li > span { flex: 1; }
.pr-demarrage li svg, .pr-demarrage li i {
  display: flex; align-items: center; justify-content: center;
  width: 22px; height: 22px; flex: none;
  border-radius: 50%;
  background: var(--c-surface-3);
  color: var(--c-text-muted);
  font-style: normal; font-size: 10px; font-weight: var(--fw-bold);
}
.pr-demarrage li svg { padding: 5px; }
.pr-demarrage li.f svg { background: var(--c-success); color: #fff; }
.pr-demarrage li.f span { color: var(--c-text-muted); text-decoration: line-through; text-decoration-color: var(--c-border-strong); }
.pr-demarrage li.c { background: var(--c-primary-soft); }
.pr-demarrage li.c i { background: var(--c-primary); color: var(--c-primary-text); }
les etapes faites restent visibles et cochees : c'est la preuve du chemin parcouru
Nouveautes
Nouveau
Relances automatiques

Un courriel part seul 7 jours apres l'envoi d'un devis reste sans reponse.

6 septembre
Ameliore
Export Excel plus rapide

Les exports de plus de 500 lignes passent de 40 a 4 secondes.

2 septembre
Corrige
Dates au format francais

Les dates saisies avec des barres obliques ne s'inversent plus.

29 aout
Annonce de nouveaute

Ce qui a change depuis la derniere connexion. Datee, courte, et fermable definitivement : une pastille rouge qui ne part jamais finit par etre ignoree.

Voir le codeMasquer le code
<div class="pr-nouveau">
  <div class="pr-nouveau__tete"><strong>Nouveautes</strong><button class="btn btn--fermer" aria-label="Fermer"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M18 6 6 18M6 6l12 12"/></svg></button></div>
  <article><span class="doc-etiq doc-etiq--ok">Nouveau</span><div><strong>Relances automatiques</strong><p>Un courriel part seul 7 jours apres l'envoi d'un devis reste sans reponse.</p><small>6 septembre</small></div></article>
  <article><span class="doc-etiq doc-etiq--neutre">Ameliore</span><div><strong>Export Excel plus rapide</strong><p>Les exports de plus de 500 lignes passent de 40 a 4 secondes.</p><small>2 septembre</small></div></article>
  <article><span class="doc-etiq doc-etiq--attente">Corrige</span><div><strong>Dates au format francais</strong><p>Les dates saisies avec des barres obliques ne s'inversent plus.</p><small>29 aout</small></div></article>
</div>
.pr-nouveau { width: 100%; max-width: 420px; border: 1px solid var(--c-border); border-radius: var(--r-lg); background: var(--c-surface); box-shadow: var(--sh-3); overflow: hidden; }
.pr-nouveau__tete { display: flex; align-items: center; justify-content: space-between; padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--c-border); }
.pr-nouveau__tete strong { font-size: var(--fs-md); font-weight: var(--fw-bold); }
.pr-nouveau article { display: flex; gap: var(--sp-3); padding: var(--sp-3) var(--sp-4); border-bottom: 1px solid var(--c-border); }
.pr-nouveau article:last-child { border-bottom: none; }
.pr-nouveau article .doc-etiq { flex: none; height: fit-content; }
.pr-nouveau article strong { display: block; font-size: var(--fs-sm); font-weight: var(--fw-semi); }
.pr-nouveau article p { margin: 3px 0; font-size: var(--fs-xs); color: var(--c-text-soft); line-height: 1.5; }
.pr-nouveau article small { font-size: 10.5px; color: var(--c-text-muted); }
trois categories seulement : nouveau, ameliore, corrige
Aujourd'hui
SM

Sophie M. a change le statut de 2026-103 de Envoye a Signe

14:32
JK

Julien K. a ajoute 4 photos au dossier 2026-118

11:05
SM

Sophie M. a commente : « Prevoir une rehausse pour l'unite exterieure »

09:47
Hier
JK

Julien K. a cree le dossier 2026-121

17:48
Fil d'activite

Qui a fait quoi, dans l'ordre. Utile a plusieurs, inutile seul : ne l'afficher que si l'equipe compte au moins deux personnes.

Voir le codeMasquer le code
<div class="pr-activite">
  <div class="pr-activite__jour">Aujourd'hui</div>
  <div class="pr-act"><span class="personne__avatar">SM</span><div><p><b>Sophie M.</b> a change le statut de <a href="#">2026-103</a> de <em>Envoye</em> a <em>Signe</em></p><small>14:32</small></div></div>
  <div class="pr-act"><span class="personne__avatar personne__avatar--vert">JK</span><div><p><b>Julien K.</b> a ajoute 4 photos au dossier <a href="#">2026-118</a></p><small>11:05</small><div class="pr-act__apercu"><i></i><i></i><i></i><i></i></div></div></div>
  <div class="pr-act"><span class="personne__avatar">SM</span><div><p><b>Sophie M.</b> a commente : &laquo; Prevoir une rehausse pour l'unite exterieure &raquo;</p><small>09:47</small></div></div>
  <div class="pr-activite__jour">Hier</div>
  <div class="pr-act"><span class="personne__avatar personne__avatar--vert">JK</span><div><p><b>Julien K.</b> a cree le dossier <a href="#">2026-121</a></p><small>17:48</small></div></div>
</div>
.pr-activite { width: 100%; max-width: 540px; }
.pr-activite__jour {
  position: sticky; top: 0; z-index: 2;
  padding: var(--sp-2) 0;
  background: var(--c-bg);
  font-size: 10px; font-weight: var(--fw-bold);
  text-transform: uppercase; letter-spacing: .08em;
  color: var(--c-text-muted);
}
.pr-act { display: flex; gap: var(--sp-3); padding: var(--sp-3) 0; }
.pr-act .personne__avatar { width: 30px; height: 30px; font-size: 10.5px; flex: none; }
.pr-act p { margin: 0; font-size: var(--fs-sm); color: var(--c-text-soft); line-height: 1.5; }
.pr-act b { color: var(--c-text); font-weight: var(--fw-semi); }
.pr-act em { font-style: normal; padding: 1px 6px; border-radius: var(--r-xs); background: var(--c-surface-3); color: var(--c-text); font-size: var(--fs-xs); font-weight: var(--fw-semi); }
.pr-act a { color: var(--c-primary-ink); font-weight: var(--fw-semi); text-decoration: none; }
.pr-act small { display: block; margin-top: 2px; font-size: 10.5px; color: var(--c-text-muted); }
.pr-act__apercu { display: flex; gap: 5px; margin-top: var(--sp-2); }
.pr-act__apercu i { width: 36px; height: 28px; border-radius: var(--r-xs); background: linear-gradient(140deg, #4a6fa5, #c9d9e8); }
.pr-act__apercu i:nth-child(2) { background: linear-gradient(140deg, #a8643c, #f0d9b5); }
.pr-act__apercu i:nth-child(3) { background: linear-gradient(140deg, #3d6b4f, #c3ddc9); }
.pr-act__apercu i:nth-child(4) { background: linear-gradient(140deg, #6b4a72, #ddc9dc); }
le changement de valeur est montre en clair : de X a Y, pas « a modifie »