/* Design system Daddiest.
 *
 * Source de vérité : docs/daddiest-ds-preview.html.
 * Servi par CHAQUE app sous /_ds/ : mêmes octets partout, puisque c'est le
 * même fichier sur le disque (editable install).
 *
 * Le principe qui tient tout : DEUX familles, désormais SYSTÈME (2026-08-16,
 * plus de webfont self-hosted — on suit le rendu des maquettes) :
 *   - un monospace système (ui-monospace / Consolas) pour la DONNÉE, les
 *     labels et les chiffres
 *   - un sans système (Segoe UI / -apple-system) pour la prose et l'interface
 * Le mono sur des phrases sonne machine — c'est ce seul partage qui retire
 * l'effet robotique. L'héritage ASCII ne subsiste que dans le registre MARQUE
 * et dans la nav.
 *
 * Règle pour les apps : aucun CSS local hors d'un app.css explicitement scopé
 * (.collection-grid { }). Tout le reste vient d'ici.
 */

/* ------------------------------------------------------------------ fonts
 *
 * Polices SYSTÈME (2026-08-16) : le site s'aligne sur le rendu des maquettes,
 * qui ne chargeaient aucune webfont. On abandonne donc Inter et JetBrains Mono
 * self-hosted au profit des piles de l'OS — Segoe UI (Windows) / -apple-system
 * (macOS) côté prose, ui-monospace / Consolas côté données et chrome mono.
 * Plus aucun @font-face : rien à télécharger, le rendu est celui du template.
 * Les .woff2 self-hosted et le dossier static/fonts/ ont été supprimés (2026-08-20).
 */

/* ============================================================
   TOKENS
   ============================================================ */
:root{
  /* --- Couleurs : surfaces --- */
  --bg-page:      #e7edf3;
  --bg-surface:   #ffffff;
  --bg-inset:     #f2f6fa;   /* fond des champs */
  --bg-sunken:    #dfe8f0;   /* panneaux de synthèse */

  /* --- Couleurs : traits --- */
  --border:       #d5dfe8;
  --border-sunken:#e4ebf1;   /* filet des panneaux, sur fond sourd */
  --border-strong:#c3d1dd;
  --rule:         #e4ebf1;   /* filets sous les titres de section */

  /* --- Couleurs : texte --- */
  --text:         #18212a;
  --text-muted:   #47555f;
  --text-faint:   #77848f;
  --text-data:    #2a4254;   /* valeurs mono */

  /* --- Couleurs : accent & sémantique --- */
  --accent:       #3c637f;
  --accent-hover: #2d4d64;
  --accent-soft:  #dbe7f0;
  --accent-text:  #2d4d64;
  /* Texte posé SUR l'accent. Indispensable : en clair l'accent est sombre et
     porte du blanc, en nuit il est clair et porte du #0a0e10. Sans ce token,
     tous les boutons primaires deviennent illisibles en thème nuit. */
  --on-accent:    #ffffff;

  /* --- Divers --- */
  --bar-track:    #d4dce4;
  --hairline:     rgba(24,33,42,.06);
  --encart-line:  #ecdcc2;
  --caret:        #47555f;   /* chevron du select — voir la note plus bas */

  --warn:         #9a6b2f;
  --warn-soft:    #f3ede6;
  --ok:           #4a7a52;
  --ok-soft:      #e9efea;
  --danger:       #a44a44;
  --danger-hover: #863d38;
  --danger-soft:  #f4e9e9;

  /* --- Typographie --- *
   * Trois registres, trois usages. Le partage ui/data est le principe qui
   * tient tout ; `display` est un accent, pas une quatrième police.
   *
   * --font-display : plus consommé nulle part depuis le 2026-08-09 — il
   * habillait `.page-head h1`, mais la charte validée
   * (daddiest-ds-proposition.html) ne charge que Inter + JetBrains Mono et
   * n'a jamais mis de serif sur son propre h1 ; repris à tort de la charte
   * de nutrition. Le token reste défini, au cas où un vrai registre
   * display soit tranché plus tard — mais RIEN ne doit s'y raccrocher tant
   * que ce jour n'est pas venu.
   */
  --font-ui:      -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
  --font-data:    ui-monospace, 'SF Mono', 'JetBrains Mono', Consolas, 'Courier New', monospace;
  --font-display: Georgia, 'Times New Roman', serif;

  --fs-micro:  11px;   /* micro-labels */
  --fs-sm:     13px;
  --fs-base:   14px;
  --fs-md:     16px;
  --fs-lg:     20px;
  --fs-xl:     28px;
  --fs-display:40px;

  /* --- Interlettrage --- *
   * Tokenisé : la valeur était codée en dur à six endroits différents.
   *   --ls-label : micro-labels, en-têtes de tableau, badges, nav applicative
   *   --ls-title : titres de section, noms d'étape
   *   --ls-brand : registre MARQUE uniquement (wordmark, tagline, invite)
   */
  --ls-label: .1em;
  --ls-title: .14em;
  --ls-brand: .18em;

  /* --- Espacements --- */
  --sp-1: 4px;  --sp-2: 8px;  --sp-3: 12px; --sp-4: 16px;
  --sp-5: 20px; --sp-6: 24px; --sp-8: 32px; --sp-10:40px;

  /* --- Formes --- */
  --r-sm: 7px;  --r-md: 11px;  --r-pill: 999px;

  /* --- Élévation & mouvement --- */
  --shadow-card: 0 1px 2px rgba(24,33,42,.04), 0 4px 14px rgba(24,33,42,.05);
  --shadow-pop:  0 2px 6px rgba(24,33,42,.06), 0 12px 28px rgba(24,33,42,.10);
  --ease: 140ms cubic-bezier(.4,0,.2,1);

  /* --- Nav (bandeau + sidebar, refonte 2026-08-08) ---
   * Dimensions pures, indifférentes au thème : pas de contrepartie sous
   * [data-theme="dark"], contrairement aux couleurs plus haut. */
  --topbar-h: 58px;
  --side-w:   224px;
  /* Hauteur commune champs / boutons — reprise du --h-control des maquettes
     validées (login-v8 / creation-compte), 2026-08-17. */
  --h-control:34px;
}

/* ============================================================
   TEINTE (préférence de profil, users.prefs_json.tint)
   Bleu = valeurs par défaut de :root ci-dessus, pas de bloc dédié. Clair
   uniquement — le thème nuit garde sa palette unique, aucune variante de
   teinte documentée pour lui (docs/MISSION-ds-registre-applicatif.md §9).
   ============================================================ */
[data-tint="neutre"]{
  --bg-page:      #efefef;
  --bg-inset:     #f7f7f7;
  --bg-sunken:    #e6e6e6;
  --border:       #dedede;
  --rule:         #eaeaea;
}
[data-tint="bleu-sat"]{
  --bg-page:      #dbe6f0;
  --bg-inset:     #eef4fa;
  --bg-sunken:    #cfdeeb;
  --border:       #c8d7e4;
  --rule:         #dbe6ef;
}
[data-tint="blanc"]{
  --bg-page:      #ffffff;
  --bg-inset:     #f7f7f7;
  --bg-sunken:    #eeeeee;
  --border:       #e2e2e2;
  --rule:         #ececec;
}
[data-tint="vert"]{
  --bg-page:      #e3f0e6;
  --bg-inset:     #eef7f0;
  --bg-sunken:    #d7e9db;
  --border:       #c9ddcd;
  --rule:         #dcebdf;
}
[data-tint="lavande"]{
  --bg-page:      #ece5f5;
  --bg-inset:     #f5f0fa;
  --bg-sunken:    #ded2ec;
  --border:       #d2c2e6;
  --rule:         #e5dced;
}
[data-tint="peche"]{
  --bg-page:      #f6e6dc;
  --bg-inset:     #fbf1ea;
  --bg-sunken:    #efd9c9;
  --border:       #e5c7b0;
  --rule:         #f0ddd0;
}
[data-tint="rose"]{
  --bg-page:      #f6e2e8;
  --bg-inset:     #fbedf0;
  --bg-sunken:    #eecfd7;
  --border:       #e3b9c4;
  --rule:         #f0dbe1;
}

/* ============================================================
   THÈME NUIT
   Fond principal repris de la home daddiest.com (#0a0e10), accent et texte
   discret repris de la même palette (#8ba3b8 / #5c6773).
   Seules les variables changent : aucun composant n'est retouché.
   Noter l'inversion : en clair le panneau est plus SOURD que la page, en
   sombre il est plus CLAIR — la métaphore du creux ne survit pas.
   ============================================================ */
[data-theme="dark"]{
  --bg-page:      #0a0e10;
  --bg-surface:   #141b20;
  --bg-inset:     #1a232a;
  --bg-sunken:    #18212a;

  --border:       #232e36;
  --border-sunken:#2c3a44;
  --border-strong:#3a4a55;
  --rule:         #1c252c;

  --text:         #dce5e9;
  --text-muted:   #8b9ba4;
  --text-faint:   #5c6773;
  --text-data:    #a6c0cf;

  --accent:       #8ba3b8;
  --accent-hover: #a2b8ca;
  --accent-soft:  #1a2732;
  --accent-text:  #a8c0d4;
  --on-accent:    #0a0e10;

  --warn:         #d3a86d;
  --warn-soft:    #241f16;
  --ok:           #7fb08f;
  --ok-soft:      #16231a;
  --danger:       #d98a80;
  --danger-soft:  #271916;

  --bar-track:    #232e36;
  --hairline:     rgba(255,255,255,.07);
  --encart-line:  #3a3122;
  --caret:        #8b9ba4;

  --shadow-card: 0 1px 2px rgba(0,0,0,.4);
  --shadow-pop:  0 4px 14px rgba(0,0,0,.5);
}

/* ============================================================
   BASE
   ============================================================ */
*, *::before, *::after { box-sizing:border-box; }

body{
  margin:0; background:var(--bg-page); color:var(--text);
  font-family:var(--font-ui); font-size:var(--fs-base); line-height:1.55;
  -webkit-font-smoothing:antialiased;
  display:flex; flex-direction:column; min-height:100vh;
}

h1,h2,h3{ margin:0; font-weight:600; letter-spacing:-.01em; }
a{ color:var(--accent); }

/* Focus clavier — visible sur tout élément interactif, jamais supprimé.
   :focus-visible (pas :focus) : ne se déclenche qu'à la navigation clavier,
   pas au clic souris. S'ajoute au halo déjà posé sur .input/.select/.textarea
   plutôt que de le remplacer — les deux se superposent sans conflit. */
:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }

/* Le mono est réservé à la DONNÉE et aux LABELS, jamais à la prose. */
.data, .mono{ font-family:var(--font-data); color:var(--text-data); }

/* ============================================================
   REGISTRE MARQUE
   Réservé à la vitrine daddiest.com et à la nav. JAMAIS dans une app :
   c'est ce qui distingue l'univers de ses outils. Le registre applicatif
   (cartes, champs, panneaux) ne doit rien lui emprunter — et réciproquement,
   ce registre n'emprunte rien au registre applicatif.

   Couleurs FIXES, indépendantes de [data-theme] : "dark mode uniquement,
   pas de variante claire" pour la marque (docs/design-system.md) — un
   visiteur anonyme n'a pas de compte, donc pas de préférence de thème à
   suivre. Reprises telles quelles de l'ancienne page statique
   (daddiest/index.html), qui est leur source, pas une coïncidence avec le
   thème nuit de l'app.
   ============================================================ */
:root{
  --brand-bg:      #0a0e10;
  --brand-fg:      #d3d7cf;
  --brand-accent:  #8ba3b8;
  --brand-dim:     #5c6773;
  --brand-border:  #2a3138;
}

/* Posée par body_class sur la vitrine (daddiest/home.html, visiteur
   anonyme) : seule app à jamais utiliser ce registre. */
body.vitrine{ background:var(--brand-bg); color:var(--brand-fg); }

/* Wordmark ASCII. Ne JAMAIS mettre text-align:center sur le <pre> lui-même :
   ça casse l'alignement quand les lignes n'ont pas la même longueur. On centre
   le bloc entier, l'alignement interne reste intact. */
.brand-mark{
  font-family:var(--font-data);
  color:var(--brand-accent);
  text-shadow:0 0 14px rgba(139,163,184,.35);
  white-space:pre;
  text-align:left;
  width:fit-content;
  max-width:100%;
  margin:0 auto;
  line-height:1.15;
  font-size:clamp(9px, 4.6vw, 15px);
}

.brand-prefix{
  display:block; text-align:center;
  font-family:var(--font-data); font-weight:700;
  font-size:clamp(13px, 5vw, 20px);
  letter-spacing:var(--ls-brand); text-transform:lowercase;
  color:var(--brand-accent); margin-bottom:var(--sp-1);
}

/* « DADDIEST.COM · THEDADDIEST.COM » — capitales très espacées. */
.brand-tagline{
  display:block; text-align:center;
  font-family:var(--font-data);
  font-size:clamp(10px, 3.4vw, var(--fs-sm));
  letter-spacing:var(--ls-brand); text-transform:uppercase;
  color:var(--brand-dim); margin:var(--sp-4) 0;
}

/* Invite guest@daddiest:~$ avec curseur clignotant. */
.brand-prompt{
  font-family:var(--font-data); font-size:clamp(11px, 3.6vw, 14px);
  color:var(--brand-dim); text-align:center; margin-top:var(--sp-5);
}
.brand-prompt__user{ color:var(--brand-accent); }
.brand-prompt__caret{
  display:inline-block; width:.55em; height:1em;
  background:var(--brand-fg); margin-left:2px; vertical-align:-.15em;
  animation:ds-blink 1s steps(1) infinite;
}
@keyframes ds-blink{ 0%,49%{opacity:1} 50%,100%{opacity:0} }

/* Panneau "welcome" — le .box de l'ancienne page statique, à ne pas
   confondre avec .card (registre applicatif) : padding et texte bien plus
   compacts, c'est voulu. Structuré comme les maquettes login-v8 /
   creation-compte (2026-08-16) : une barre d'en-tête filetée (.brand-box__head)
   puis un corps rembourré (.brand-box__body). Le contenu DOIT donc être
   enveloppé dans .brand-box__body dans le gabarit. Aucune ombre : on ne touche
   pas aux box-shadow. */
.brand-box{
  border:1px solid var(--brand-border); border-radius:var(--r-md);
  font-size:clamp(11px, 3.6vw, 14px); line-height:1.65;
  background:rgba(255,255,255,.015); color:var(--brand-fg);
  /* Comme la maquette validée : la PROSE et les champs sont en sans, seul le
     chrome (en-tête, labels, boutons) passe en mono — chacun le déclare
     explicitement. Mettre du mono ici forcerait l'accroche en monospace, ce
     qui n'est pas le template. */
  font-family:var(--font-ui);
}
.brand-box__head{
  color:var(--brand-dim); font-family:var(--font-data);
  font-size:var(--fs-micro); letter-spacing:var(--ls-title); text-transform:uppercase;
  padding:var(--sp-3) var(--sp-4); border-bottom:1px solid var(--brand-border);
}
.brand-box__head::before{ content:"✻ "; color:var(--brand-accent); }
.brand-box__body{ padding:var(--sp-4); }
.brand-box__body p{ margin:0 0 var(--sp-4) 0; color:var(--brand-dim); font-size:12px; }

/* ============================================================
   NAV — bandeau + sidebar (refonte 2026-08-08, maquette
   daddiest-nav-v4.html validée). Remplace l'ancien bandeau noir
   unique (.topnav) : un bandeau blanc pleine largeur en haut, une
   sidebar d'apps en dessous. L'héritage ASCII (registre MARQUE,
   fond sombre) ne vit plus ici — le bandeau est blanc, le logo est
   en --accent sur --bg-surface, pas en négatif. Le registre marque
   reste réservé aux surfaces sombres (.brand-*, vitrine).
   ============================================================ */
.topbar{
  position:sticky; top:0; z-index:110; height:var(--topbar-h);
  background:var(--bg-surface); border-bottom:1px solid var(--border);
  display:flex; align-items:stretch; box-shadow:var(--shadow-card);
}
/* Largeur naturelle (burger + logo, pas --side-w) : essayé aligné sur la
   sidebar avec un filet à droite (2026-08-09), rendu confirmé mauvais à
   l'écran — un trait flottant au milieu d'un bandeau par ailleurs vide,
   sans rien à droite pour justifier une "zone" délimitée. Simple groupe
   flex, sans chercher à faire correspondre une largeur de colonne qui
   n'a de sens que plus bas, dans la sidebar elle-même. */
.topbar-brand{
  display:flex; align-items:center; gap:var(--sp-3);
  padding:0 var(--sp-4);
}
/* Un seul burger pilote la sidebar, visible dans les deux modes (desktop
   masque/affiche la colonne, mobile fait glisser un overlay) — jamais
   caché par media query, contrairement à l'ancien burger mobile-only. */
.burger{
  width:38px; height:38px; border-radius:var(--r-sm);
  border:1px solid var(--border); background:var(--bg-inset); color:var(--text-muted);
  cursor:pointer; display:flex; align-items:center; justify-content:center;
  font-size:18px; flex-shrink:0; transition:var(--ease);
}
.burger:hover{ background:var(--bg-sunken); color:var(--text); }
/* Emplacement du vrai logo ASCII — placeholder texte en attendant. */
.brand-logo{
  font-family:var(--font-data); font-weight:700; font-size:16px;
  letter-spacing:var(--ls-brand); color:var(--accent); white-space:nowrap;
  text-decoration:none;
}
.topbar-right{
  margin-left:auto; display:flex; align-items:center; gap:var(--sp-2);
  padding-right:var(--sp-4);
}
.topbar-btn{
  width:36px; height:36px; border-radius:var(--r-sm); border:1px solid var(--border);
  background:var(--bg-inset); color:var(--text-muted); cursor:pointer;
  display:flex; align-items:center; justify-content:center;
  font-family:var(--font-data); font-size:16px; transition:var(--ease);
}
.topbar-btn:hover{ background:var(--bg-sunken); color:var(--text); }

/* Menu déroulant du compte — seul menu de ce type restant : la liste des
   apps accessibles vit dans la sidebar en permanence, plus en dropdown. */
.nav-menu{
  position:absolute; top:100%; right:var(--sp-4); z-index:120; min-width:200px;
  background:var(--bg-surface); border:1px solid var(--border);
  border-radius:var(--r-md); box-shadow:var(--shadow-pop); padding:var(--sp-2);
}
.nav-menu__compte{ display:flex; flex-wrap:wrap; gap:var(--sp-3); font-size:var(--fs-sm); }
.nav-menu__compte a{ color:var(--text-muted); padding:4px 6px; }
/* Le bouton de déconnexion doit ressembler aux liens voisins, sans en être un :
   c'est une écriture, donc un POST. */
.nav-menu__logout{ display:inline; margin:0; }
.nav-menu__logout button{
  background:none; border:none; padding:4px 6px; cursor:pointer;
  font:inherit; font-size:var(--fs-sm); color:var(--text-muted);
}
.nav-menu__logout button:hover{ color:var(--accent); text-decoration:underline; }

/* ── Corps : sidebar + contenu, sous le bandeau ──
   Flexbox et non grid (contrairement à la maquette) : quand la sidebar
   n'existe pas dans le DOM (anonyme — voir _sidebar.html), .main doit
   récupérer toute la largeur sans laisser de gouttière. Une colonne grid
   réserverait l'espace même sans élément dedans ; un enfant flex absent
   ne coûte rien à ses voisins. body{display:flex;flex-direction:column}
   pousse .foot en bas de page (plus haut dans ce fichier) : .body-row
   reprend le relais de .wrap{flex:1} à ce niveau, .main doit donc être
   flex-column à son tour pour que .wrap{flex:1} garde son effet. */
.body-row{ display:flex; flex:1; min-height:0; }

/* Pas de height fixe : .body-row est flex, .side s'étire naturellement
   (align-items:stretch, par défaut) sur toute la hauteur réelle de .main
   — qui peut dépasser 100vh (page longue) ou, à l'inverse, être étirée à
   100vh par .wrap{flex:1} même sur un contenu court (pied de page collé
   en bas). Une height:calc(100vh - topbar-h) fixe ici plafonnait la
   sidebar à un écran, laissant un grand vide sans elle en dessous dès
   que .main dépassait cette hauteur (repéré sur trip, 2026-08-09).
   position:sticky reste utile : son CONTENU (nav, pied) se fixe sous le
   bandeau pendant le défilement, même si la BOÎTE fait toute la hauteur. */
.side{
  flex:0 0 var(--side-w); width:var(--side-w); overflow:hidden;
  border-right:1px solid var(--rule); background:var(--bg-page);
  position:sticky; top:var(--topbar-h);
  display:flex; flex-direction:column;
  transition:flex-basis .22s ease, width .22s ease;
}
.side-foot{
  margin-top:auto; border-top:1px solid var(--rule);
  padding:var(--sp-3) var(--sp-4);
  font-family:var(--font-data); font-size:var(--fs-micro);
  letter-spacing:var(--ls-label); color:var(--text-faint);
}
/* Masquage desktop (clic burger) : la colonne se réduit à rien plutôt
   que de disparaître du DOM — l'état n'est pas persisté (phase 7). */
.body-row.hidden-nav .side{
  flex-basis:0; width:0; border-right-color:transparent;
}

.nav{ display:flex; flex-direction:column; gap:2px; padding:var(--sp-3); flex:1; }
.nav a{
  display:flex; align-items:center; gap:var(--sp-3); padding:9px var(--sp-3);
  border-radius:var(--r-sm); color:var(--text-muted); text-decoration:none;
  font-size:var(--fs-sm); white-space:nowrap;
}
.nav a:hover{ background:var(--bg-inset); color:var(--text); }
.nav a[aria-current]{
  background:var(--bg-surface); color:var(--text); font-weight:500;
  box-shadow:var(--shadow-card);
}
.nav .ico{
  font-family:var(--font-data); font-size:13px; width:18px; text-align:center;
  color:var(--text-faint); flex-shrink:0;
}
.nav a[aria-current] .ico{ color:var(--accent); }
.nav-empty{ display:block; padding:9px var(--sp-3); color:var(--text-faint); font-size:var(--fs-sm); }

/* Sous-section repliée sous l'app active : les écrans/onglets PROPRES à
   cette app (Scan/Rafale/Liste/Réglages pour collection), jamais visible
   pour les autres apps de la liste. Indentation alignée sur le début du
   LABEL du parent (18px d'icône + son gap), pas sur l'icône elle-même. */
.nav-sub{ display:flex; flex-direction:column; gap:1px; padding:2px 0 6px 30px; }
.nav-sub a{
  display:block; padding:6px var(--sp-3); border-radius:var(--r-sm);
  color:var(--text-faint); text-decoration:none;
  font-size:var(--fs-sm); white-space:nowrap;
}
.nav-sub a:hover{ background:var(--bg-inset); color:var(--text); }
.nav-sub a[aria-current]{
  background:var(--bg-surface); color:var(--text); font-weight:500;
  box-shadow:var(--shadow-card);
}

.main{ min-width:0; flex:1; display:flex; flex-direction:column; }

/* Voile mobile derrière la sidebar en overlay. */
.scrim{
  display:none; position:fixed; inset:0; top:var(--topbar-h);
  background:rgba(10,14,16,.42); z-index:95;
}
.scrim.show{ display:block; }

@media (max-width:820px){
  .side{
    position:fixed; top:var(--topbar-h); left:0; bottom:0;
    width:min(272px,82vw); height:calc(100vh - var(--topbar-h)); z-index:100;
    transform:translateX(-100%); transition:transform .24s ease;
    box-shadow:var(--shadow-pop); border-right:1px solid var(--border);
  }
  /* Caché par défaut (translateX), ouvert = .open ; hidden-nav (mécanisme
     desktop) n'est jamais posé en mobile par le JS, mais autant ne pas
     laisser une largeur à 0 si les deux se chevauchaient un jour. */
  .body-row.hidden-nav .side{ width:min(272px,82vw); flex-basis:auto; }
  .side.open{ transform:translateX(0); }
}

/* ============================================================
   LAYOUT
   ============================================================ */
.wrap{ max-width:1080px; padding:var(--sp-8) var(--sp-6) 80px;
       width:100%; flex:1; }
/* --etroit : uniquement la vitrine anonyme (sans sidebar, .main pleine
   largeur du viewport) — reste centrée comme un encart terminal autonome.
   Le "plein" ci-dessus (connecté, à côté de la sidebar) n'en a lui jamais
   eu besoin : c'est justement son margin:auto hérité qui recentrait le
   contenu loin de la sidebar sur grand écran (2026-08-09), corrigé en le
   retirant SEULEMENT là. */
.wrap--etroit{ max-width:420px; margin:0 auto; }

/* Fil d'ariane — repris de la démo (daddiest-ds-proposition.html) et de la
   mission §7.2/annexe. Jamais implémenté avant son premier vrai consommateur
   (product_detail.html, 2026-08-08). Mono, discret : c'est un repère de
   navigation, pas du contenu. */
.crumb{ font-family:var(--font-data); font-size:var(--fs-micro); letter-spacing:var(--ls-label);
        text-transform:uppercase; color:var(--text-faint); margin-bottom:var(--sp-3); }
.crumb a{ color:var(--text-faint); text-decoration:none; }
.crumb a:hover{ color:var(--accent); text-decoration:underline; }

/* Refonte 2026-08-09 (page_head, _macros.html) : aligné sur le motif du
   mockup — ligne flex, filet du bas, plus de simple bloc empilé. Reprend
   ce que product_detail portait seul dans .fiche-page-head (retiré,
   collection/static/css/app.css) : le motif devient partagé. */
.page-head{
  display:flex; align-items:flex-end; justify-content:space-between;
  gap:var(--sp-4); flex-wrap:wrap;
  padding-bottom:var(--sp-4); border-bottom:1px solid var(--border);
  margin-bottom:var(--sp-8);
}
/* Inter, pas le serif --font-display : daddiest-ds-proposition.html (la
   charte validée) ne charge que Inter + JetBrains Mono, son propre h1
   n'a jamais porté de serif. --font-display datait d'une itération
   antérieure (charte nutrition) jamais mise à jour depuis — repéré par
   Antoine sur le h1 "Collection", 2026-08-09. */
.page-head h1{ font-family:var(--font-ui); font-size:var(--fs-xl);
               font-weight:600; letter-spacing:-0.02em; margin:0; }
.page-head p{ color:var(--text-muted); margin:var(--sp-2) 0 0; max-width:62ch; }
.page-head-actions{ display:flex; gap:var(--sp-2); flex-shrink:0; }

.spec{ margin-bottom:var(--sp-10); }
.spec-title{
  font-family:var(--font-data); font-size:var(--fs-micro);
  letter-spacing:var(--ls-title); text-transform:uppercase; color:var(--text-faint);
  padding-bottom:var(--sp-2); border-bottom:1px solid var(--border);
  margin-bottom:var(--sp-5);
}
.row{ display:flex; flex-wrap:wrap; gap:var(--sp-3); align-items:center; }
.grid2{ display:grid; grid-template-columns:1fr 1fr; gap:var(--sp-5); }
@media(max-width:720px){ .grid2{ grid-template-columns:1fr; } }

/* ============================================================
   CARTE
   ============================================================ */
.card{
  background:var(--bg-surface); border:1px solid var(--border);
  border-radius:var(--r-md); padding:var(--sp-6);
  box-shadow:var(--shadow-card); margin-bottom:var(--sp-5);
}
.card-title{
  font-size:var(--fs-md); font-weight:600;
  padding-bottom:var(--sp-3); border-bottom:1px solid var(--rule);
  margin-bottom:var(--sp-5);
  display:flex; justify-content:space-between; align-items:baseline; gap:var(--sp-4);
}
.card-caption{ font-family:var(--font-ui); font-size:var(--fs-sm);
               font-weight:400; color:var(--text-faint); }

/* ============================================================
   CHAMPS
   ============================================================ */
.field{ margin-bottom:var(--sp-5); }
.label{
  display:block; font-family:var(--font-data);
  /* 10px : valeur exacte des maquettes (hors échelle --fs-*), assumée. */
  font-size:10px; letter-spacing:var(--ls-label); text-transform:uppercase;
  color:var(--text-faint); margin-bottom:var(--sp-2);
}
.input, .select, .textarea{
  width:100%; background:var(--bg-inset);
  border:1px solid var(--border); border-radius:var(--r-sm);
  padding:6px 12px; font-family:var(--font-ui);
  /* 12px + hauteur 34px : valeurs exactes des maquettes validées. */
  font-size:12px;
  color:var(--text-data); transition:var(--ease); outline:none;
  min-height:var(--h-control);
}
.input::placeholder{ color:var(--text-faint); }
.input:hover, .select:hover, .textarea:hover{ border-color:var(--border-strong); }
.input:focus, .select:focus, .textarea:focus{
  background:var(--bg-surface); border-color:var(--accent);
  box-shadow:0 0 0 3px var(--accent-soft);
}
.textarea{ min-height:84px; resize:vertical; }

/* Le chevron est un SVG en data: URL — il échappe aux variables CSS, la
   couleur y est écrite en dur. Il DOIT donc être dupliqué pour le thème
   sombre : sans ça, le chevron reste #647876 sur fond nuit. */
.select{
  appearance:none; padding-right:32px;
  background-repeat:no-repeat; background-position:right 11px center;
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'><path d='M3 4.5L6 8l3-3.5' fill='none' stroke='%2347555f' stroke-width='1.4'/></svg>");
}
[data-theme="dark"] .select{
  background-image:url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 12 12'><path d='M3 4.5L6 8l3-3.5' fill='none' stroke='%238b9ba4' stroke-width='1.4'/></svg>");
}

.help{ font-size:var(--fs-sm); color:var(--text-faint); margin-top:var(--sp-2); }
.field.is-error .input,
.field.is-error .select,
.field.is-error .textarea{ border-color:var(--danger); background:var(--danger-soft); }
.field.is-error .help{ color:var(--danger); }

/* Sélecteur de teinte (préférence de profil) : pastilles rondes montrant la
   VRAIE couleur de chaque option, pas un <select> texte — les couleurs des
   trois options sont donc dupliquées ici des blocs [data-tint] ci-dessus
   (nécessaire : les trois s'affichent en même temps, indépendamment de la
   teinte active sur la page). Input radio visuellement masqué mais gardé
   dans le flux (focus clavier, lecteur d'écran), jamais display:none. */
.tint-picker{ display:flex; flex-wrap:wrap; gap:var(--sp-4); }
.tint-swatch{ display:flex; flex-direction:column; align-items:center; gap:var(--sp-2); cursor:pointer; }
.tint-swatch input{
  position:absolute; width:1px; height:1px; margin:-1px; padding:0;
  overflow:hidden; clip:rect(0,0,0,0); white-space:nowrap; border:0;
}
.tint-dot{
  width:26px; height:26px; border-radius:var(--r-pill);
  border:1px solid var(--border-strong); display:block;
}
.tint-dot--neutre{ background:#efefef; }
.tint-dot--bleu{ background:#e7edf3; }
.tint-dot--bleu-sat{ background:#dbe6f0; }
.tint-dot--blanc{ background:#ffffff; }
.tint-dot--vert{ background:#e3f0e6; }
.tint-dot--lavande{ background:#ece5f5; }
.tint-dot--peche{ background:#f6e6dc; }
.tint-dot--rose{ background:#f6e2e8; }
.tint-swatch input:checked + .tint-dot{
  box-shadow:0 0 0 2px var(--bg-surface), 0 0 0 4px var(--accent);
}
.tint-swatch input:focus-visible + .tint-dot{ outline:2px solid var(--accent); outline-offset:3px; }
.tint-swatch-label{ font-size:var(--fs-sm); color:var(--text-muted); }

/* ============================================================
   BOUTONS
   Fond relatif à la surface porteuse, pas une couleur en dur : blanc sur
   le fond de page, gris clair posé dans un panneau/tableau/état vide.
   Deux couleurs, une seule règle — voir --btn-bg / --btn-bg-hover ci-dessous.

   ATTENTION : ces deux lignes vont sur `body`, JAMAIS sur `:root`. Un
   var() à l'intérieur d'une déclaration de custom property est résolu LÀ
   OÙ LA DÉCLARATION VIT, pas là où la variable est utilisée. Sur :root,
   ces deux variables capteraient --bg-inset par défaut et ignoreraient
   les variantes de teinte posées sur <body> (§9) : les boutons resteraient
   bleutés en teinte neutre pendant que la nav juste au-dessus vire au gris.
   ============================================================ */
body{ --btn-bg:var(--bg-surface); --btn-bg-hover:var(--bg-inset); }
.card, .panel, .rows, table, .empty, .skel{
  --btn-bg:var(--bg-inset); --btn-bg-hover:var(--bg-sunken);
}

/* Trois variantes : par défaut (pas de modificateur), --primary et
   --danger. Un troisième niveau NEUTRE n'est probablement pas un bouton
   mais un lien sortant — mais --danger n'est pas un niveau neutre, c'est
   un registre d'alerte : une action destructive doit se signaler, sinon
   elle se confond visuellement avec « Annuler » et se clique par erreur.
   Comme --primary, elle est donc solide et fixe plutôt que relative à la
   surface porteuse : la mécanique --btn-bg sert à faire disparaître le
   bouton par défaut dans son contexte, exactement l'inverse de ce qu'il
   faut ici. */
/* Boutons repris du registre terminal des maquettes (2026-08-16) : monospace
   (système) en capitales espacées. Volontairement « robotique » — décision
   assumée qui revient sur la note « non-terminal » de design-system.md. Les
   ombres (--shadow-card) sont conservées telles quelles, on ne touche pas. */
.btn{
  font-family:var(--font-data); font-size:var(--fs-micro); font-weight:500;
  text-transform:uppercase; letter-spacing:var(--ls-label);
  padding:6px 12px; border-radius:var(--r-sm); border:1px solid var(--rule);
  cursor:pointer; transition:var(--ease); display:inline-flex;
  align-items:center; gap:var(--sp-2); line-height:1.2;
  text-decoration:none; min-height:var(--h-control); justify-content:center;
  background:var(--btn-bg); color:var(--text-muted); box-shadow:var(--shadow-card);
}
.btn:hover{ background:var(--btn-bg-hover); color:var(--text); }
.btn--primary{ background:var(--accent); border-color:var(--accent); color:var(--on-accent); }
.btn--primary:hover{ background:var(--accent-hover); border-color:var(--accent-hover); color:var(--on-accent); }
.btn--danger{ background:var(--danger); border-color:var(--danger); color:var(--on-accent); }
.btn--danger:hover{ background:var(--danger-hover); border-color:var(--danger-hover); color:var(--on-accent); }
.btn:disabled, .btn.is-disabled{ opacity:.45; cursor:not-allowed; }
/* Devenu identique à .btn depuis que la taille par défaut a été alignée
   sur l'ancienne .btn--sm (voir plus haut) : aucun effet visuel dans
   daddiest. Gardé quand même — collection appelle btn(size='sm') dans
   queue.html/scan_series.html/settings.html sans jamais redéfinir cette
   classe dans son propre app.css, contrairement à .btn/.btn-primary/etc. */
.btn--sm{ font-size:var(--fs-micro); padding:6px 12px; min-height:var(--h-control); }
/* Le CTA pleine largeur garde un corps lisible (--fs-sm) : 11px sur un bouton
   large sonnerait creux. Il hérite des capitales mono de .btn. */
.btn--block{ width:100%; padding:10px 18px; font-size:var(--fs-sm); }

/* Rangée d'actions d'un formulaire : bouton auto-largeur centré, comme le
   template login (là où .btn--block conviendrait à un CTA pleine largeur). */
.form-actions{ display:flex; justify-content:center; gap:var(--sp-2); }

/* ============================================================
   BADGES / PILULES
   ============================================================ */
.badge{
  display:inline-flex; align-items:center; gap:5px;
  font-family:var(--font-data); font-size:var(--fs-micro);
  letter-spacing:var(--ls-label); text-transform:uppercase;
  padding:3px 9px; border-radius:var(--r-pill);
  background:var(--bg-inset); color:var(--text-muted); border:1px solid var(--border);
}
.badge-accent{ background:var(--accent-soft); color:var(--accent-text); border-color:transparent; }
.badge-ok{ background:var(--ok-soft); color:var(--ok); border-color:transparent; }
.badge-warn{ background:var(--warn-soft); color:var(--warn); border-color:transparent; }
.badge-danger{ background:var(--danger-soft); color:var(--danger); border-color:transparent; }

/* ============================================================
   PANNEAU DE DONNÉES
   ============================================================ */
.panel{
  background:var(--bg-sunken); border:1px solid var(--border-sunken);
  border-radius:var(--r-md);
  padding:var(--sp-5) var(--sp-6); margin-bottom:var(--sp-5);
}
.panel-head{ display:flex; align-items:baseline; justify-content:space-between; gap:var(--sp-4); }
.kpi{ font-family:var(--font-data); font-size:var(--fs-display); font-weight:500;
      color:var(--text); letter-spacing:-.02em; line-height:1.1; }
.kpi-unit{ font-size:var(--fs-md); color:var(--text-muted); margin-left:6px; }
.kpi-note{ font-size:var(--fs-sm); color:var(--text-muted); text-align:right; }
.bar{ height:6px; background:var(--bar-track); border-radius:var(--r-pill);
      overflow:hidden; margin:var(--sp-4) 0; }
.bar > span{ display:block; height:100%; background:var(--accent); border-radius:var(--r-pill); }
.stat{ display:flex; justify-content:space-between; padding:5px 0; font-size:var(--fs-sm); }
.stat + .stat{ border-top:1px solid var(--hairline); }
.stat b{ font-family:var(--font-data); font-weight:500; color:var(--text-data); }

/* ============================================================
   BLOC DE SÉQUENCE
   Une carte par étape, la carte active portant un filet à gauche.
   ============================================================ */
.slot{
  background:var(--bg-surface); border:1px solid var(--border);
  border-radius:var(--r-md); padding:var(--sp-4) var(--sp-5);
  margin-bottom:var(--sp-3);
}
.slot-active{ border-color:var(--border-strong); border-left:3px solid var(--accent);
              box-shadow:var(--shadow-card); }
.slot-muted{ background:transparent; border-style:dashed; text-align:center; color:var(--text-faint); }
.slot-head{ display:flex; align-items:center; gap:var(--sp-2); margin-bottom:var(--sp-2); }
.slot-name{
  font-family:var(--font-data); font-size:var(--fs-sm);
  letter-spacing:var(--ls-title); text-transform:uppercase; color:var(--text-muted);
}
.slot-status{ margin-left:auto; font-size:var(--fs-sm); color:var(--text-faint); }
.slot-sub{ font-size:var(--fs-sm); color:var(--text-muted); }
.slot-val{ font-family:var(--font-data); color:var(--text-data); margin-left:auto; }

/* ============================================================
   ENCART — suggestion / rappel contextuel
   Mono pour la donnée rappelée, Inter pour la prose qui suit.
   ============================================================ */
.encart{
  background:var(--warn-soft); border:1px solid var(--encart-line);
  border-radius:var(--r-md); padding:var(--sp-3) var(--sp-4); margin-top:var(--sp-3);
}
.encart-line{ font-family:var(--font-data); font-size:var(--fs-base);
              color:var(--warn); display:flex; align-items:center; gap:var(--sp-2); }
.encart-meta{ font-family:var(--font-data); font-size:var(--fs-sm);
              color:var(--warn); opacity:.8; margin-top:3px; }
.encart-accent{ background:var(--accent-soft); border-color:var(--border-sunken); }
.encart-accent .encart-line{ color:var(--accent-text); }
.encart-accent .encart-meta{ color:var(--accent-text); opacity:.72; }
.after-note{ font-size:var(--fs-sm); color:var(--text-faint); margin-top:var(--sp-3); }

/* ============================================================
   TABLEAU
   ============================================================ */
table{ width:100%; border-collapse:collapse; font-size:var(--fs-sm); }
th{
  text-align:left; font-family:var(--font-data); font-weight:500;
  font-size:var(--fs-micro); letter-spacing:var(--ls-label); text-transform:uppercase;
  color:var(--text-muted); padding:0 var(--sp-3) var(--sp-2);
  border-bottom:1px solid var(--border);
}
td{ padding:11px var(--sp-3); border-bottom:1px solid var(--rule);
    font-family:var(--font-data); color:var(--text-data); }
td.txt{ font-family:var(--font-ui); color:var(--text); }
tbody tr:hover{ background:var(--bg-inset); }

/* ============================================================
   MESSAGES
   ============================================================ */
.note{
  border-radius:var(--r-md); padding:var(--sp-4) var(--sp-5);
  font-size:var(--fs-base); margin-bottom:var(--sp-3);
}
.note-info{ background:var(--accent-soft); color:var(--accent-text); }
.note-warn{ background:var(--warn-soft); color:var(--warn); }
.note-ok{ background:var(--ok-soft); color:var(--ok); }
.note-danger{ background:var(--danger-soft); color:var(--danger); }
.note code{ font-family:var(--font-data); font-size:.92em; }

.flash{ list-style:none; margin:0 0 var(--sp-5); padding:0; }

/* ============================================================
   ÉTAT VIDE, PAGINATION, AVATAR
   ============================================================ */
.empty{ text-align:center; padding:var(--sp-8) var(--sp-4); }
.empty-title{ font-size:var(--fs-md); font-weight:600; }
.empty-msg{ color:var(--text-muted); margin:var(--sp-2) 0 var(--sp-5); }

.pagination{ display:flex; align-items:center; justify-content:space-between;
             gap:var(--sp-4); margin-top:var(--sp-5); }
.pagination a{ text-decoration:none; }
.pagination-state{ font-family:var(--font-data); font-size:var(--fs-sm); color:var(--text-faint); }

.avatar{
  display:inline-flex; align-items:center; justify-content:center;
  border-radius:var(--r-pill); border:1px solid var(--border);
  object-fit:cover; background:var(--bg-inset);
  font-family:var(--font-data); color:var(--accent-text);
}
.avatar-sm{ width:28px; height:28px; font-size:var(--fs-micro); }
.avatar-md{ width:44px; height:44px; font-size:var(--fs-sm); }
.avatar-lg{ width:72px; height:72px; font-size:var(--fs-lg); }

/* ============================================================
   PAGES D'ERREUR
   ============================================================ */
.erreur{ text-align:center; }
.erreur-code{
  font-family:var(--font-data); color:var(--accent);
  font-size:clamp(48px, 18vw, 96px); font-weight:500;
  letter-spacing:-.02em; margin:0 0 var(--sp-5);
}

/* Micro-animations discrètes seulement : coupées si l'utilisateur les refuse. */
@media (prefers-reduced-motion: reduce){
  .brand-prompt__caret{ animation:none; }
  *{ transition:none !important; }
}

/* ============================================================
   AUTH — révélation du mot de passe, checklist, cases à cocher
   Ajouts pour login/inscription (2026-08-16). Additions only : aucun
   sélecteur existant touché, aucune couleur en dur — que des tokens.
   ============================================================ */

/* Révélation du mot de passe : le bouton se glisse DANS le champ sans en
   changer la hauteur. Le champ garde son .input ordinaire ; .input--peek
   réserve seulement la place à droite. */
.field__control{ position:relative; }
.input--peek{ padding-right:38px; }
.peek{
  position:absolute; right:6px; top:50%; transform:translateY(-50%);
  display:inline-grid; place-items:center;
  background:transparent; border:0; padding:4px; cursor:pointer;
  color:var(--text-faint); border-radius:var(--r-sm);
}
.peek:hover{ color:var(--accent); }
.peek:focus-visible{ outline:2px solid var(--accent); outline-offset:2px; }
.peek svg{ width:16px; height:16px; display:block; }

/* Checklist de robustesse : même registre que .label (mono, micro, espacé),
   chaque ligne s'allume quand la condition est remplie. Confort d'UX
   seulement — la vraie validation est côté serveur. */
.field-hint{
  list-style:none; margin:var(--sp-2) 0 0; padding:0;
  font-family:var(--font-data); font-size:var(--fs-micro);
  letter-spacing:var(--ls-label); color:var(--text-faint);
}
.field-hint li{ margin:3px 0; }
.field-hint li::before{ content:'· '; color:var(--border-strong); }
.field-hint li.is-ok{ color:var(--ok); }
.field-hint li.is-ok::before{ content:'✓ '; color:var(--ok); }

/* Case à cocher : input masqué mais gardé dans le flux (clavier, lecteur
   d'écran — jamais display:none), pastille dessinée en .check__box. Même
   logique visuelle que .input : anneau en bordure, remplissage accent coché. */
.check-group{ display:flex; flex-direction:column; gap:var(--sp-3); }
.check{
  display:flex; align-items:center; gap:var(--sp-3);
  font-family:var(--font-ui); font-size:var(--fs-sm); color:var(--text);
  cursor:pointer;
}
.check input{ position:absolute; opacity:0; width:1px; height:1px; }
.check__box{
  width:18px; height:18px; flex:0 0 18px; border-radius:5px;
  border:1px solid var(--border-strong); background:var(--bg-inset);
  display:inline-grid; place-items:center; transition:var(--ease);
}
.check__box::after{
  content:''; width:9px; height:9px; border-radius:2px;
  background:transparent; transition:var(--ease);
}
.check input:checked + .check__box{ border-color:var(--accent); }
.check input:checked + .check__box::after{ background:var(--accent); }
.check input:focus-visible + .check__box{ outline:2px solid var(--accent); outline-offset:2px; }
.check:hover .check__box{ border-color:var(--border-strong); }

/* fieldset porteur de champs : reset du chrome navigateur, la légende
   réutilise .label. */
fieldset.field{ border:0; padding:0; margin:0 0 var(--sp-5); min-inline-size:0; }
fieldset.field > legend{ padding:0; }

/* Voies secondaires sous un formulaire d'auth (créer un compte, mot de passe
   oublié, « déjà un compte ? »). */
.foot-links{
  text-align:center; margin-top:var(--sp-5);
  font-size:var(--fs-sm); color:var(--text-muted);
}
.foot-links a{ text-decoration:none; }
.foot-links a:hover{ text-decoration:underline; }
.foot-links__sep{ color:var(--border-strong); margin:0 var(--sp-2); }
