/* Crystal — app grand public Yumi (/app). Direction artistique « Verre & Prisme » :
   l'interface est taillée dans le verre et la lumière. Fond nuit profonde traversé
   d'une aura prismatique ; panneaux en verre dépoli (.glass) ; chaque assistant est
   une gemme à monogramme (.gem, teinte dérivée du nom). ZÉRO emoji dans l'UI.
   Corps DM Sans + chiffres JetBrains Mono servis par /admin/assets/fonts/fonts.css ;
   titres Space Grotesk vendorisé À PLAT ci-dessous (woff2, licence OFL, aucun CDN). */

/* Space Grotesk — © Florian Karsten, SIL Open Font License 1.1 (OFL).
   Fichier variable (axe poids 300→700) vendorisé À PLAT, aucun CDN. */
@font-face{
  font-family:"Space Grotesk";font-style:normal;font-weight:300 700;font-display:swap;
  src:url("/app/assets/space-grotesk-latin.woff2") format("woff2");
  unicode-range:U+0000-00FF,U+0131,U+0152-0153,U+02BB-02BC,U+02C6,U+02DA,U+02DC,U+0304,U+0308,U+0329,U+2000-206F,U+20AC,U+2122,U+2191,U+2193,U+2212,U+2215,U+FEFF,U+FFFD;
}
@font-face{
  font-family:"Space Grotesk";font-style:normal;font-weight:300 700;font-display:swap;
  src:url("/app/assets/space-grotesk-latin-ext.woff2") format("woff2");
  unicode-range:U+0100-02BA,U+02BD-02C5,U+02C7-02CC,U+02CE-02D7,U+02DD-02FF,U+0304,U+0308,U+0329,U+1D00-1DBF,U+1E00-1E9F,U+1EF2-1EFF,U+2020,U+20A0-20AB,U+20AD-20C0,U+2113,U+2C60-2C7F,U+A720-A7FF;
}

:root{
  /* Cristal clair (light) */
  --bg:#f2f2f7; --card:#ffffff; --card2:#f6f6fb;
  --border:rgba(20,16,40,.10); --hairline:rgba(20,16,40,.06);
  --txt:#12101c; --muted:#615f72;
  --accent:#6b4dff; --accent-soft:rgba(107,77,255,.12);
  --ink:#12101c; --ink-txt:#ffffff;
  --danger:#d70015; --ok:#0a8a3d; --warn:#b45400;
  --prism:linear-gradient(135deg,#7c5cff 0%,#2ad4ff 55%,#ff5c8a 110%);
  /* Verre dépoli (light : vitre blanche translucide) */
  --glass:rgba(255,255,255,.62); --glass-solid:#ffffff;
  --glass-brd:rgba(20,16,40,.10); --glass-brd2:rgba(107,77,255,.32);
  --glass-hi:rgba(255,255,255,.9); --glass-hi2:rgba(255,255,255,1);
  --glass-bd:saturate(1.6) blur(18px);
  --halo:0 8px 30px rgba(124,92,255,.28);
  /* Aura prismatique (pastel discret en clair) */
  --aura1:rgba(124,92,255,.14); --aura2:rgba(42,212,255,.10); --aura3:rgba(255,92,138,.10);
  --aura-blur:48px;
  --radius:18px; --radius-lg:22px; --radius-pill:999px;
  --shadow-card:0 2px 8px rgba(20,16,40,.05),0 12px 32px rgba(20,16,40,.09);
  --shadow-pop:0 20px 56px rgba(20,16,40,.18);
  --ring:0 0 0 4px var(--accent-soft);
  --ease:cubic-bezier(.4,0,.2,1); --dur:.22s;
  --topbar-h:56px;
  /* ---- Ordre d'EMPILEMENT (une seule adresse) ----
     Un panneau (`.modal`) peut ouvrir un menu « … », qui peut demander une
     confirmation : chacun doit passer AU-DESSUS de celui qui l'a appelé, sinon
     il se peint derrière (ordre du document) et le geste paraît sans effet. */
  --z-panel:60;
  --z-menu:70;
  --z-ask:80;
  /* ---- Ancrages COLLANTS (C1a) — UNE seule source ----
     `--topbar-top` = hauteur à laquelle flotte la pilule du haut (et la
     respiration au-dessus d'elle : même valeur, une seule ligne à changer).
     `--stick-top` = ligne où se colle TOUT ce qui vient juste sous la topbar
     (en-tête magnétique du chat). `--head-h` = hauteur de cette barre de nom ;
     `--stick-top2` = ligne des volets latéraux, qui se collent SOUS l'en-tête
     au lieu de glisser derrière lui. `--chat-gap` = l'écart du fil, partagé par
     la colonne, les volets et ces calculs (pas trois fois « 14px »). */
  --topbar-top:12px;
  --chat-gap:14px;
  --head-h:60px;
  --stick-top:calc(var(--topbar-top) + var(--topbar-h) + 4px);
  --stick-top2:calc(var(--stick-top) + var(--head-h) + var(--chat-gap));
  /* Hauteur qu'un écran occupe au minimum : la fenêtre moins la barre du haut
     et les marges du document. Une seule ligne pour `section[data-screen]` et
     pour le fil, qui la lisaient tous les deux en la recopiant. */
  --screen-min:calc(100dvh - var(--topbar-h) - 96px);
  /* ---- Largeurs de la coquille (G1) — UNE seule source ----
     `--shell-max` = largeur utile de l'app (barre du haut + `main#app`) : l'app
     prend TOUT l'espace disponible, bornée seulement pour ne pas se déformer sur
     un écran mural. `--shell-gutter` = respiration de la pilule de verre du haut.
     `--read-w` = colonne de LECTURE (conversation) : la coquille s'élargit, la
     ligne de texte non — c'est l'ancien plafond de 1080 px, qui n'était pas une
     largeur d'app mais une largeur de lecture. */
  --shell-max:2200px;
  --shell-gutter:12px;
  --read-w:1080px;
  /* ---- Cartes (G1, correction) — UNE seule source ----
     Une carte a une taille NORMALE et BORNÉE : elle ne s'étire jamais pour
     remplir l'écran. Quand la fenêtre grandit, la grille ajoute des COLONNES,
     elle n'agrandit pas les cartes (`minmax(min,max)`, jamais `1fr`).
     `--card-*` = cartes d'assistants ; `--pick-*` = cartes de choix (wizard,
     réglages), plus petites. `--dur-move` = durée du reflow de grille. */
  --card-min:240px;
  --card-max:300px;
  --card-gap:20px;
  --pick-min:130px;
  --pick-max:180px;
  /* `--cfg-card-*` = cartes de la page de configuration : mêmes règles (bornées,
     jamais `1fr`), mais plus larges — elles portent des saisies et des listes,
     pas une vignette. Changer la densité de cet écran = changer CES deux lignes. */
  --cfg-card-min:340px;
  --cfg-card-max:460px;
  /* `--side-w` = largeur d'un VOLET latéral du fil (zone de travail, panneau de
     validation) : les deux volets se ressemblent parce qu'ils lisent la même
     ligne, pas parce qu'on a recopié la valeur.
     G2 : la valeur d'avant (`min(340px,36vw)`) était taillée pour une coquille
     plafonnée à 1080 px — dans un shell large, un volet DÉPLIÉ en permanence a
     droit à de la vraie place. Comme une carte, il est BORNÉ des deux côtés :
     il grandit avec l'écran (`24vw`) sans jamais devenir une seconde page.
     `--read-min` = ce qu'on refuse de descendre en dessous pour la conversation :
     les volets cèdent AVANT le fil (cf. `.chat-main`), sinon deux volets ouverts
     sur un écran moyen le réduiraient à une gouttière. */
  --side-min:280px;
  --side-max:420px;
  --side-w:clamp(var(--side-min),24vw,var(--side-max));
  --read-min:420px;
  /* Un cran d'indentation de l'arborescence du dossier de travail (G2). */
  --ws-step:15px;
  --dur-move:.26s;
  --sans:"DM Sans",-apple-system,BlinkMacSystemFont,"Segoe UI","PingFang SC","Microsoft YaHei",sans-serif;
  --font-display:"Space Grotesk",var(--sans);
}
:root[data-theme="dark"]{
  /* Nuit profonde (dark-first) */
  --bg:#05050a; --card:#13131f; --card2:#0e0e18;
  --border:rgba(255,255,255,.11); --hairline:rgba(255,255,255,.06);
  --txt:#f3f3fb; --muted:#a0a0b8;
  --accent:#8f74ff; --accent-soft:rgba(143,116,255,.20);
  --ink:#f3f3fb; --ink-txt:#0a0a12;
  --danger:#ff5c7a; --ok:#3ddc84; --warn:#ffb454;
  /* Verre dépoli (dark : vitre posée sur l'aura) */
  --glass:rgba(255,255,255,.055); --glass-solid:#161622;
  --glass-brd:rgba(255,255,255,.14); --glass-brd2:rgba(143,116,255,.5);
  --glass-hi:rgba(255,255,255,.18); --glass-hi2:rgba(255,255,255,.28);
  --halo:0 8px 34px rgba(143,116,255,.4);
  --aura1:rgba(124,92,255,.20); --aura2:rgba(42,212,255,.14); --aura3:rgba(255,92,138,.16);
  --shadow-card:0 2px 8px rgba(0,0,0,.4),0 14px 36px rgba(0,0,0,.55);
  --shadow-pop:0 24px 60px rgba(0,0,0,.65);
}

*{box-sizing:border-box;margin:0;padding:0}
/* L'attribut [hidden] doit toujours gagner sur un display: explicite
   (.hero=flex, .chat-send=grid…) — sinon un bloc masqué reste affiché. */
[hidden]{display:none!important}
html{-webkit-text-size-adjust:100%;background:var(--bg)}
body{
  font-family:var(--sans);background:transparent;color:var(--txt);
  min-height:100dvh;line-height:1.5;
  -webkit-font-smoothing:antialiased;text-rendering:optimizeLegibility;
}
button{font:inherit;color:inherit;background:none;border:0;cursor:pointer}
a{color:inherit;text-decoration:none}
:focus-visible{outline:none;box-shadow:var(--ring);border-radius:8px}
/* Titres en Space Grotesk (display), interlettrage resserré. */
h1,h2,h3,.brand-name{font-family:var(--font-display);letter-spacing:-.03em}

/* ---------- Aura prismatique (fond auroral) ----------
   Nappes radiales STATIQUES posées derrière toute l'UI, flou appliqué au gradient.
   AUCUNE animation : l'état est statique (règle design maison « zéro animation
   décorative »). La dérive `auroraDrift` a été retirée — sur un écran large elle
   gardait ce calque flouté (blur 48px) perpétuellement « sale » sous will-change,
   forçant le compositeur à re-flouter le fond derrière CHAQUE vitre backdrop-filter
   à chaque frame de scroll (repaint en boucle = scroll saccadé). Un fond figé se
   met en cache : le scroll redevient fluide. */
body::before{
  content:"";position:fixed;inset:-15vmax;z-index:-1;pointer-events:none;
  background:
    radial-gradient(42% 38% at 18% 12%, var(--aura1), transparent 70%),
    radial-gradient(40% 36% at 84% 20%, var(--aura2), transparent 72%),
    radial-gradient(50% 46% at 62% 96%, var(--aura3), transparent 74%);
  filter:blur(var(--aura-blur));
}

/* ---------- Verre dépoli (utilitaires) ---------- */
.glass{
  background:var(--glass);border:1px solid var(--glass-brd);border-radius:var(--radius-lg);
  box-shadow:inset 0 1px 0 var(--glass-hi),var(--shadow-card);
  -webkit-backdrop-filter:var(--glass-bd);backdrop-filter:var(--glass-bd);
}
/* Fallback net (opaque) quand backdrop-filter n'est pas supporté. */
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .glass{background:var(--glass-solid)}
}
.glass-hover{transition:transform var(--dur) var(--ease),box-shadow var(--dur) var(--ease),border-color var(--dur) var(--ease)}
.glass-hover:hover{
  transform:translateY(-3px);border-color:var(--glass-brd2);
  box-shadow:inset 0 1px 0 var(--glass-hi2),var(--shadow-pop);
}

/* ---------- Gemme à monogramme (chaque assistant) ----------
   Squircle au dégradé conique UNIQUE (2 teintes dérivées du nom, posées inline
   via --h1/--h2), anneau prismatique, relief inset, initiales Space Grotesk.
   Remplace tout emoji d'assistant dans l'UI. */
.gem{
  position:relative;display:inline-grid;place-items:center;flex:none;
  width:var(--gem-sz,72px);height:var(--gem-sz,72px);border-radius:28%;
  background:conic-gradient(from 210deg,
    hsl(var(--h1,265) 85% 62%),hsl(var(--h2,190) 85% 60%),hsl(var(--h1,265) 85% 62%));
  color:#fff;font-family:var(--font-display);font-weight:600;line-height:1;
  box-shadow:
    inset 0 1px 1px rgba(255,255,255,.5),inset 0 -6px 14px rgba(0,0,0,.22),
    0 6px 18px rgba(0,0,0,.28),0 0 0 1px rgba(255,255,255,.12);
}
.gem::after{
  content:"";position:absolute;inset:-1.5px;border-radius:inherit;padding:1.5px;
  background:conic-gradient(from 0deg,
    hsl(var(--h1,265) 92% 66%),hsl(var(--h2,190) 92% 66%),hsl(var(--h1,265) 92% 66%));
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;mask-composite:exclude;opacity:.65;pointer-events:none;
}
.gem-txt{position:relative;z-index:1;font-size:calc(var(--gem-sz,72px)*.38);letter-spacing:0}
/* Icône de marque monochrome (connecteurs) : hérite de la couleur du contexte. */
.brandico{flex:none;color:currentColor}

/* ---------- Barre du haut (verre flottant) ----------
   Pilule de verre dépoli posée sur l'aura, détachée des bords ; liseré lumineux
   en haut, ombre douce. Fallback opaque net si backdrop-filter absent. */
.topbar{
  position:sticky;top:var(--topbar-top);z-index:20;height:var(--topbar-h);
  width:min(var(--shell-max),calc(100% - var(--shell-gutter)*2));
  margin:var(--topbar-top) auto 0;
  display:flex;align-items:center;justify-content:space-between;
  padding:0 8px 0 18px;
  background:var(--glass);border:1px solid var(--glass-brd);
  border-radius:var(--radius-pill);
  box-shadow:inset 0 1px 0 var(--glass-hi),var(--shadow-card);
  -webkit-backdrop-filter:var(--glass-bd);backdrop-filter:var(--glass-bd);
}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .topbar{background:var(--glass-solid)}
}
.brand{display:flex;align-items:center;gap:10px;font-weight:700;font-size:17px;letter-spacing:-.01em}
.brand-gem{
  display:grid;place-items:center;width:30px;height:30px;border-radius:10px;
  color:#fff;background:var(--prism);
  box-shadow:0 2px 10px rgba(94,92,230,.35);
}
.topbar-actions{display:flex;align-items:center;gap:10px}
.langsw{display:flex;background:var(--card);border:1px solid var(--border);border-radius:var(--radius-pill);padding:2px;position:relative}
.langsw button{
  flex:1;position:relative;z-index:1;text-align:center;
  padding:4px 12px;border-radius:var(--radius-pill);font-size:12.5px;font-weight:600;color:var(--muted);
  white-space:nowrap;writing-mode:horizontal-tb;   /* B7 : « 中文 » sur une ligne */
  transition:color var(--dur) var(--ease);
}
.langsw button.active{color:var(--ink-txt)}
.iconbtn{
  display:grid;place-items:center;width:34px;height:34px;border-radius:var(--radius-pill);
  background:var(--card);border:1px solid var(--border);color:var(--muted);
  transition:color var(--dur) var(--ease),transform var(--dur) var(--ease);
}
.iconbtn:hover{color:var(--txt);transform:translateY(-1px)}
:root[data-theme="light"] .ico-sun{display:none}
:root[data-theme="dark"] .ico-moon{display:none}

/* ---------- Coquille ----------
   G1 : plus de plafond à 1080 px — la coquille s'étend sur tout l'espace
   (`--shell-max`, cf. :root). Les `max-width` INTERNES de lisibilité restent :
   bulles (`.msg`), réglages (`.set-body`, `.cfg`), rendez-vous (`.sched`). */
main#app{
  max-width:var(--shell-max);margin:0 auto;
  padding:32px max(20px,env(safe-area-inset-left)) 64px max(20px,env(safe-area-inset-right));
}
section[data-screen]{min-height:var(--screen-min)}

/* La boîte blanche plate `.card` est MORTE (DA « Verre & Prisme ») : tous les
   panneaux sont désormais des vitres (.glass) — cartes, modales, menu contextuel.
   Le token de couleur --card sert encore de base aux verres semi-opaques (bulles,
   chips…) mais aucun élément ne porte plus la classe .card. */

/* ---------- Héros (état vide) ---------- */
.hero{
  display:flex;flex-direction:column;align-items:center;justify-content:center;text-align:center;
  min-height:60dvh;gap:8px;padding:24px;
}
.hero-gem{
  font-size:64px;line-height:1;margin-bottom:16px;color:var(--accent);
  filter:drop-shadow(0 12px 24px rgba(94,92,230,.25));
}
.hero-gem svg{width:64px;height:64px}
/* État vide de la galerie : gemme GÉANTE prismatique (squircle relief + halo),
   au lieu d'une icône plate. */
.gem-hero{
  display:grid;place-items:center;width:112px;height:112px;border-radius:30%;
  margin-bottom:20px;color:#fff;background:var(--prism);filter:none;
  box-shadow:
    inset 0 2px 2px rgba(255,255,255,.5),inset 0 -10px 22px rgba(0,0,0,.25),
    0 0 0 1px rgba(255,255,255,.14),var(--halo);
}
.gem-hero svg{width:52px;height:52px}
.hero h1{font-size:clamp(28px,5vw,40px);font-weight:700;letter-spacing:-.02em}
.hero-sub{font-size:17px;color:var(--muted);max-width:420px}
/* État d'erreur réseau habillé : panneau de verre teinté danger posé sur l'aura,
   avec une gemme d'alerte (relief + halo). Le .hero reste le contexte de centrage. */
.err-card{
  display:flex;flex-direction:column;align-items:center;text-align:center;gap:8px;
  padding:32px 28px;max-width:400px;
  border-color:color-mix(in srgb,var(--danger) 34%,var(--glass-brd));
  box-shadow:inset 0 1px 0 var(--glass-hi),var(--shadow-card);
}
.err-card .cta{margin-top:16px}
.err-gem{
  display:grid;place-items:center;width:64px;height:64px;border-radius:20px;margin-bottom:8px;
  color:#fff;background:linear-gradient(135deg,var(--danger),var(--warn));
  box-shadow:
    inset 0 2px 2px rgba(255,255,255,.4),inset 0 -8px 18px rgba(0,0,0,.18),
    0 8px 24px color-mix(in srgb,var(--danger) 40%,transparent);
}
.err-gem svg{width:34px;height:34px}

/* ---------- CTA pilule ---------- */
.cta{
  margin-top:24px;padding:14px 32px;border-radius:var(--radius-pill);
  background:var(--ink);color:var(--ink-txt);font-size:16px;font-weight:600;
  transition:transform var(--dur) var(--ease),box-shadow var(--dur) var(--ease),opacity var(--dur) var(--ease);
  box-shadow:0 4px 16px rgba(0,0,0,.12);
}
.cta:hover{transform:translateY(-2px);box-shadow:0 8px 24px rgba(0,0,0,.18)}
.cta:active{transform:translateY(0) scale(.98)}
.cta[disabled]{opacity:.4;pointer-events:none}
.cta.secondary{background:var(--card);color:var(--txt);border:1px solid var(--border);box-shadow:none}

/* ---------- Verrou (vitre centrale posée sur l'aura) ---------- */
.lock{
  position:fixed;inset:0;z-index:40;display:grid;place-items:center;
  background:color-mix(in srgb,var(--bg) 62%,transparent);padding:20px;
}
.lock-card{
  width:min(400px,100%);padding:40px 32px;text-align:center;
  border-radius:var(--radius-lg);
  display:flex;flex-direction:column;align-items:center;gap:8px;
}
.lock-gem{
  display:grid;place-items:center;width:56px;height:56px;border-radius:18px;
  color:#fff;background:var(--prism);margin-bottom:12px;
  box-shadow:0 8px 24px rgba(94,92,230,.35);
}
.lock-card h1{font-size:24px;font-weight:700;letter-spacing:-.02em}
.lock-sub{color:var(--muted);font-size:15px;margin-bottom:12px}
.lock-card form{display:flex;flex-direction:column;gap:10px;width:100%}
.field{
  width:100%;padding:13px 16px;border-radius:14px;font:inherit;font-size:15px;
  background:var(--card2);border:1px solid var(--border);color:var(--txt);
  transition:border-color var(--dur) var(--ease),box-shadow var(--dur) var(--ease);
}
.field::placeholder{color:var(--muted)}
.field:focus{outline:none;border-color:var(--accent);box-shadow:var(--ring)}
.lock-cta{margin-top:8px;width:100%}
.lock-hint{color:var(--muted);font-size:13px;margin-top:8px}
/* Message d'erreur inline (verrou / réglages / modale connecteur) = pastille de
   verre teinté danger (liseré + halo intérieur), plus un texte rouge nu. */
.lock-err{
  color:var(--danger);font-size:14px;font-weight:500;margin-top:8px;
  padding:9px 13px;border-radius:12px;
  background:color-mix(in srgb,var(--danger) 12%,transparent);
  border:1px solid color-mix(in srgb,var(--danger) 30%,transparent);
  box-shadow:inset 0 1px 0 var(--glass-hi);
}
@keyframes shake{20%,60%{transform:translateX(-6px)}40%,80%{transform:translateX(6px)}}
.lock-card.shake{animation:shake .4s var(--ease)}

/* ---------- Placeholders écrans à venir ---------- */
.placeholder{
  display:grid;place-items:center;min-height:40dvh;color:var(--muted);font-size:15px;
  margin-top:24px;
}

/* ---------- Galerie d'assistants ---------- */
.home-head{
  display:flex;align-items:center;justify-content:space-between;gap:16px;
  margin:8px 0 24px;flex-wrap:wrap;
}
.home-head h1{font-size:clamp(24px,4vw,32px);font-weight:700;letter-spacing:-.02em}
.cta.small{margin-top:0;padding:10px 20px;font-size:14px}

/* ---------- Jauge d'usage (G4b) ----------
   Information SECONDAIRE : deux lignes fines posées entre le titre et le bouton,
   pas une carte à elle seule. Chaque ligne = une fenêtre glissante annoncée par
   le serveur (profondeur + total + plafond) ; le nombre de lignes suit la
   réponse, le CSS n'en connaît aucune en particulier.
   ÉTAT STATIQUE : la barre est peinte à sa largeur, elle ne s'anime pas (une
   jauge qui « pousse » à chaque retour sur l'accueil serait décoratif).
   La barre SATURE à 100 % (`.over`) — rien n'est bloqué, l'usage continue de
   compter au-delà (voir `ratelimit.UsageWindow`). */
.usage{
  --usage-bar-w:96px;
  display:flex;flex-direction:column;gap:5px;margin-left:auto;
  font-size:12px;color:var(--muted);
}
.usage-win{
  display:grid;grid-template-columns:auto var(--usage-bar-w) auto;
  align-items:center;gap:8px;
}
.usage-lbl{font-variant-numeric:tabular-nums;white-space:nowrap}
.usage-bar{height:4px;border-radius:var(--radius-pill);background:var(--hairline);overflow:hidden}
.usage-fill{display:block;height:100%;border-radius:inherit;background:var(--accent)}
/* Au-delà du plafond graphique : la barre est pleine et change de teinte — elle
   dit « c'est passé au-dessus », elle n'empêche rien. */
.usage-fill.over{background:var(--warn)}
.usage-val{
  font-family:ui-monospace,monospace;font-variant-numeric:tabular-nums;
  color:var(--txt);white-space:nowrap;
}
/* (Écran étroit : la jauge se range SOUS le titre — règle dans la section Mobile,
   il n'y a qu'UN bloc @media 640px dans ce fichier.) */
/* La place gagnée par la coquille pleine largeur se remplit en AJOUTANT des
   colonnes : les pistes sont bornées à `--card-max`, jamais `1fr`. Les cartes
   se rangent à la queue leu leu depuis la gauche (alignées sur le titre de la
   page), le reliquat de largeur reste vide plutôt que d'être avalé par une
   carte démesurée. */
.agent-grid{
  display:grid;gap:var(--card-gap);justify-content:start;
  grid-template-columns:repeat(auto-fill,minmax(var(--card-min),var(--card-max)));
}
/* (Une carte qui part laisse un trou que les autres viennent combler en
   glissant : le reflow est défini plus bas, juste après `.reveal`, qu'il doit
   neutraliser — voir « Reflow de grille ».) */
/* Chaque carte est une VITRE (pas une boîte plate) : gemme monogramme en héros,
   nom, description, action. Survol = élévation + liseré (via .glass-hover). */
.agent-card{
  position:relative;display:flex;flex-direction:column;align-items:center;text-align:center;
  gap:10px;padding:30px 22px 22px;border-radius:var(--radius-lg);
}
.agent-card.off{opacity:.62}
.agent-gem{margin-bottom:4px;line-height:0}
.agent-body{display:flex;flex-direction:column;align-items:center;gap:6px;width:100%}
.agent-card h3{font-size:18px;font-weight:700;letter-spacing:-.01em}
.agent-desc{
  color:var(--muted);font-size:14px;min-height:42px;
  display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden;
}
.agent-foot{margin-top:auto;padding-top:14px}
/* (La vitre LARGE du 1er assistant, qui prenait la rangée entière, a été
   retirée : une carte ne s'étire jamais sur toute la largeur. Toutes les cartes
   ont la même taille normale et se rangent côte à côte.) */
.agent-menu-btn{
  position:absolute;top:12px;right:12px;display:grid;place-items:center;
  width:32px;height:32px;border-radius:var(--radius-pill);color:var(--muted);
  transition:background var(--dur) var(--ease),color var(--dur) var(--ease);
}
.agent-menu-btn:hover{background:var(--accent-soft);color:var(--txt)}
.agent-card.new{
  justify-content:center;align-items:center;gap:10px;
  border-style:dashed;cursor:pointer;color:var(--muted);min-height:190px;
}
.agent-card.new:hover{color:var(--accent)}
.agent-add-ico{
  display:grid;place-items:center;width:52px;height:52px;border-radius:16px;
  border:1px solid var(--glass-brd);color:inherit;
}
.agent-new-lbl{font-size:15px;font-weight:600}
.chip{
  display:inline-block;padding:3px 10px;border-radius:var(--radius-pill);
  font-size:12px;font-weight:600;background:var(--accent-soft);color:var(--accent);
}
.chip[data-chip="paused"]{background:rgba(192,76,0,.12);color:var(--warn)}

/* ---------- Clés nues promouvables (section discrète sous la galerie) ---------- */
.other-keys{margin-top:44px}
.other-keys h2{font-size:16px;font-weight:700;letter-spacing:-.01em}
.other-keys-sub{color:var(--muted);font-size:14px;margin-top:4px}
.other-keys-list{display:flex;flex-direction:column;gap:10px;margin-top:16px}
.other-key{
  display:flex;align-items:center;gap:14px;padding:12px 16px;
  border-radius:var(--radius-lg);
}
.other-key-gem{line-height:0}
.other-key-body{flex:1;min-width:0}
.other-key-name{font-size:15px;font-weight:600}
.other-key-prefix{color:var(--muted);font-size:13px;font-family:ui-monospace,monospace}
.other-key-btn{flex:none}
@media (max-width:520px){
  .other-key{flex-wrap:wrap}
  .other-key-btn{width:100%}
}

/* Squelettes de chargement (vitres inertes) */
.agent-card.skeleton{min-height:200px;pointer-events:none;overflow:hidden}
.agent-card.skeleton::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(100deg,transparent 30%,var(--accent-soft) 50%,transparent 70%);
  animation:shimmer 1.4s infinite;opacity:.5;
}
@keyframes shimmer{from{transform:translateX(-100%)}to{transform:translateX(100%)}}

/* ---------- Menu contextuel (vitre flottante) ---------- */
.popmenu{
  position:absolute;z-index:var(--z-menu);min-width:180px;padding:6px;border-radius:14px;
  box-shadow:inset 0 1px 0 var(--glass-hi),var(--shadow-pop);
}
/* Un item porte son libellé À GAUCHE et, quand c'est un CHOIX actif, une coche à
   DROITE : d'où la ligne flex plutôt qu'un bloc de texte. */
.popmenu-item{
  display:flex;align-items:center;gap:10px;width:100%;text-align:left;padding:9px 12px;border-radius:9px;
  font-size:14px;font-weight:500;
  transition:background var(--dur) var(--ease);
}
.popmenu-lbl{flex:1;min-width:0}
.popmenu-item:hover{background:var(--accent-soft)}
.popmenu-item.danger{color:var(--danger)}
/* Choix actif : teinte d'accent + coche SVG. Aucun aplat plein — la ligne reste
   sobre, c'est la coche qui dit « c'est celui-là ». */
.popmenu-item.on{color:var(--accent)}
.popmenu-tick{flex:none;line-height:0}
/* Intertitre d'un groupe de choix (Mode, Effort) : ce n'est pas un bouton. */
.popmenu-sect{
  padding:9px 12px 4px;font-size:11.5px;font-weight:700;letter-spacing:.04em;
  text-transform:uppercase;color:var(--muted);
}

/* ---------- Modale de confirmation (vitre posée sur scrim auroral) ---------- */
.modal{position:fixed;inset:0;z-index:var(--z-panel);display:grid;place-items:center;padding:20px}
/* La confirmation est le DERNIER mot : elle est appelée depuis les autres
   panneaux (historique, aperçu de fichier), qui la suivent dans le document. */
#modal{z-index:var(--z-ask)}
.modal-scrim{position:absolute;inset:0;background:rgba(0,0,0,.4);-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}
/* La carte de modale est une VITRE (.glass en markup) : le pop shadow ici prime
   sur l'ombre de carte du .glass pour la faire flotter au-dessus du scrim. */
.modal-card{
  position:relative;width:min(400px,100%);padding:32px 28px;text-align:center;
  border-radius:var(--radius-lg);display:flex;flex-direction:column;align-items:center;gap:8px;
  box-shadow:inset 0 1px 0 var(--glass-hi),var(--shadow-pop);
  animation:rise .3s var(--ease) both;
}
/* En-tête de modale : plus d'emoji — gemme monogramme ou icône de marque. */
.modal-emoji{display:grid;place-items:center;line-height:1;margin-bottom:8px;color:var(--txt)}
.modal-emoji .brandico{width:52px;height:52px}
.modal-card h2{font-size:20px;font-weight:700;letter-spacing:-.01em}
.modal-sub{color:var(--muted);font-size:14.5px}
.modal-actions{display:flex;gap:10px;margin-top:16px;width:100%}
.modal-actions .cta{flex:1;margin-top:0;padding:12px 16px;font-size:15px}
.cta.danger{background:var(--danger);color:#fff}

/* ---------- Wizard ---------- */
.wiz{max-width:640px;margin:0 auto;display:flex;flex-direction:column}
.wiz-top{display:flex;align-items:center;justify-content:space-between;margin-bottom:24px}
.wiz-top-spacer{width:34px}
.wiz-steps{display:flex;gap:8px}
/* Stepper prismatique : les étapes atteintes deviennent des gemmes de lumière. */
.wiz-steps i{
  width:8px;height:8px;border-radius:50%;background:var(--glass-brd);
  transition:background var(--dur) var(--ease),transform var(--dur) var(--ease),box-shadow var(--dur) var(--ease);
}
.wiz-steps i.on{background:var(--prism);transform:scale(1.4);box-shadow:0 2px 10px rgba(124,92,255,.55)}
.wiz-pane{display:flex;flex-direction:column;align-items:center;text-align:center;gap:10px;animation:rise .3s var(--ease) both}
.wiz-pane h1{font-size:clamp(24px,4.5vw,32px);font-weight:700;letter-spacing:-.02em}
.wiz-sub{color:var(--muted);font-size:16px;margin-bottom:8px}
.wiz-h2{font-size:19px;font-weight:700;letter-spacing:-.01em;margin-top:24px}
#wizBriefBlock{display:flex;flex-direction:column;align-items:center;gap:12px;width:100%}
.wiz-brief{max-width:520px;font-size:16px;resize:vertical;min-height:88px;text-align:center}
.linkbtn{color:var(--accent);font-size:14px;font-weight:500;background:none}
.linkbtn:hover{text-decoration:underline}
.banner{
  display:flex;flex-direction:column;align-items:center;gap:6px;width:100%;max-width:520px;
  padding:14px 18px;border-radius:14px;font-size:14.5px;
  background:rgba(192,76,0,.1);color:var(--warn);border:1px solid rgba(192,76,0,.2);
}

/* Carte persona (aperçu éditable) */
.persona-card{
  width:100%;max-width:440px;padding:32px 28px;margin-top:8px;border-radius:20px;
  display:flex;flex-direction:column;align-items:center;gap:8px;
}
.persona-card.skeleton{min-height:260px;position:relative;overflow:hidden;pointer-events:none}
.persona-card.skeleton::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(100deg,transparent 30%,var(--accent-soft) 50%,transparent 70%);
  animation:shimmer 1.4s infinite;opacity:.5;
}
/* Aperçu du persona = gemme à monogramme (plus d'emoji, plus de sélecteur). */
.persona-gem{display:grid;place-items:center;margin-bottom:4px}
.persona-name{font-size:20px;font-weight:700;letter-spacing:-.01em;min-width:60px;outline:none;border-radius:8px;padding:2px 8px}
.persona-desc{color:var(--muted);font-size:14.5px;outline:none;border-radius:8px;padding:2px 8px;min-width:120px}
.persona-name:focus,.persona-desc:focus{background:var(--accent-soft)}
.persona-name:empty::before,.persona-desc:empty::before{content:attr(data-ph);color:var(--muted);opacity:.6}
.persona-instr-lbl{font-size:12.5px;font-weight:600;color:var(--muted);text-transform:uppercase;letter-spacing:.06em;margin-top:14px;align-self:flex-start}
.persona-instr{font-size:13.5px;resize:vertical;text-align:left}
.persona-card.pop>*{animation:rise .4s var(--ease) both}
.persona-card.pop>*:nth-child(2){animation-delay:.08s}
.persona-card.pop>*:nth-child(3){animation-delay:.16s}
.persona-card.pop>*:nth-child(4){animation-delay:.24s}
.persona-card.pop>*:nth-child(5){animation-delay:.3s}
/* Moment magique : quand le persona est généré, la GEMME apparaît en pop. */
.persona-card.pop .persona-gem{animation:popIn .5s var(--ease) both}
@keyframes popIn{from{opacity:0;transform:scale(.5)}60%{transform:scale(1.12)}to{opacity:1;transform:scale(1)}}

/* Chips de retouche */
/* Chips de retouche = pilules de verre (translucides sur l'aura, sans blur). */
.chiprow{display:flex;flex-wrap:wrap;gap:8px;justify-content:center;margin-top:6px}
.chipbtn{
  padding:7px 14px;border-radius:var(--radius-pill);font-size:13.5px;font-weight:500;
  background:var(--glass);border:1px solid var(--glass-brd);
  box-shadow:inset 0 1px 0 var(--glass-hi);
  transition:border-color var(--dur) var(--ease),background var(--dur) var(--ease);
}
.chipbtn:hover{border-color:var(--glass-brd2);background:var(--accent-soft)}
.wiz-next{margin-top:28px;min-width:200px}

/* Cartes radio (cerveau, liberté) = vitres translucides sur l'aura (pas de blur
   empilé — perf pad) : survol = élévation + liseré ; sélection = liseré
   PRISMATIQUE (bordure conique masquée, à la manière des gemmes) + halo. */
/* Mêmes règles que la galerie : pistes bornées (`--pick-*`), jamais `1fr` — à
   deux options, on veut deux cartes normales côte à côte, pas deux demi-écrans.
   Centrées, car le wizard est une colonne centrée. */
.pick-grid{
  display:grid;gap:12px;width:100%;justify-content:center;
  grid-template-columns:repeat(auto-fill,minmax(var(--pick-min),var(--pick-max)));
}
.pick-card{
  position:relative;display:flex;flex-direction:column;align-items:center;gap:5px;
  padding:18px 14px;border-radius:16px;background:var(--glass);
  border:1px solid var(--glass-brd);box-shadow:inset 0 1px 0 var(--glass-hi),var(--shadow-card);
  transition:border-color var(--dur) var(--ease),transform var(--dur) var(--ease),box-shadow var(--dur) var(--ease);
}
.pick-card:hover{transform:translateY(-3px);border-color:var(--glass-brd2);box-shadow:inset 0 1px 0 var(--glass-hi2),var(--shadow-pop)}
.pick-card.sel{border-color:transparent;background:var(--accent-soft);box-shadow:inset 0 1px 0 var(--glass-hi),var(--halo)}
.pick-card.sel::before{
  content:"";position:absolute;inset:0;border-radius:inherit;padding:1.5px;
  background:var(--prism);
  -webkit-mask:linear-gradient(#000 0 0) content-box,linear-gradient(#000 0 0);
  -webkit-mask-composite:xor;mask-composite:exclude;pointer-events:none;
}
.pick-card strong{font-size:15px;font-weight:700}
.pick-ico{color:var(--accent);line-height:0;margin-bottom:2px}
.pick-sub{font-size:12.5px;color:var(--muted);word-break:break-all}
.checkline{
  display:flex;align-items:center;gap:8px;font-size:14px;color:var(--muted);
  margin-top:10px;cursor:pointer;
}
.checkline input{width:16px;height:16px;accent-color:var(--accent)}
.wiz-hint{font-size:13.5px;color:var(--muted);margin-top:6px}
.conn-list{display:flex;flex-direction:column;gap:2px;margin-top:8px}
.conn-line{align-items:center}
/* Rangée : icône de marque (ou mini-gemme) + libellé, plus d'emoji. */
.conn-line>span{display:flex;align-items:center;gap:9px;flex:1;min-width:0;color:var(--ink)}
.conn-ico{flex:none;display:inline-flex;line-height:0;color:var(--muted)}
.conn-txt{display:flex;flex-direction:column;gap:1px;min-width:0}
.conn-sub{font-size:12.5px;color:var(--muted)}

/* Écran « C'est prêt » : la gemme du nouvel assistant + un checkmark lumineux
   (badge vert en relief, coche tracée). */
.done-figure{position:relative;display:inline-grid;place-items:center;margin-bottom:16px;animation:popIn .5s var(--ease) both}
.done-gem{line-height:0}
.done-check{
  position:absolute;right:-4px;bottom:-4px;display:grid;place-items:center;
  width:38px;height:38px;border-radius:50%;color:#fff;background:var(--ok);
  box-shadow:0 6px 18px rgba(10,138,61,.5),0 0 0 4px var(--bg);
}
.dc-tick{stroke-dasharray:32;stroke-dashoffset:32;animation:draw .45s var(--ease) .35s forwards}
@keyframes draw{to{stroke-dashoffset:0}}
/* Récap : chips à picto SVG (cerveau, liberté) alignés — plus d'emoji. */
#wizRecapChips .chip{display:inline-flex;align-items:center;gap:4px}
.techdetails{margin-top:28px;max-width:520px;width:100%;text-align:left}
.techdetails summary{color:var(--muted);font-size:13px;cursor:pointer}
.techdetails pre{
  margin-top:10px;padding:14px;border-radius:12px;font-size:12px;overflow-x:auto;
  background:var(--card2);border:1px solid var(--hairline);
  font-family:"JetBrains Mono",ui-monospace,monospace;white-space:pre-wrap;word-break:break-all;
}

/* ---------- Boutique (Store) ---------- */
.navbtn{
  display:flex;align-items:center;gap:7px;padding:6px 14px 6px 11px;border-radius:var(--radius-pill);
  background:var(--card);border:1px solid var(--border);color:var(--txt);
  font-size:13.5px;font-weight:600;
  transition:color var(--dur) var(--ease),border-color var(--dur) var(--ease),transform var(--dur) var(--ease);
}
.navbtn:hover{border-color:var(--accent);transform:translateY(-1px)}
.navbtn svg{color:var(--muted)}
.navbtn:hover svg{color:var(--accent)}
.store-head{margin:8px 0 24px}
.store-head h1{font-size:clamp(24px,4vw,32px);font-weight:700;letter-spacing:-.02em}
.store-sub{color:var(--muted);font-size:16px;margin-top:4px}
/* La LISTE elle-même (groupes, rangées, instances, badges) et le formulaire de
   secret de la modale sont habillés par la feuille PARTAGÉE avec /admin :
   ai_gateway/web/shared/store.css, chargée par crystal.html juste avant celle-ci
   (même markup des deux côtés ⇒ une seule feuille). Ne reste ici que ce qui est
   propre à Crystal : l'en-tête d'écran, le squelette de chargement animé et la
   modale de connexion. */
.store-row.skeleton{pointer-events:none;overflow:hidden}
.store-row.skeleton::after{
  content:"";position:absolute;inset:0;
  background:linear-gradient(100deg,transparent 30%,var(--accent-soft) 50%,transparent 70%);
  animation:shimmer 1.4s infinite;opacity:.5;
}

/* Modale quick-connect / rattachement */
.store-modal{text-align:left;align-items:stretch}
.store-modal .modal-emoji,.store-modal h2,.store-modal .modal-sub{align-self:center;text-align:center}
.store-modal .linkbtn{align-self:center;margin-top:2px}
.sm-fields{display:flex;flex-direction:column;gap:12px;width:100%;margin-top:16px;max-height:46dvh;overflow-y:auto}
.sm-lbl .field{margin-top:2px}       /* champs propres à Crystal (compte, boîte mail) */
/* Erreur boîte mail : ligne humaine (héritée de .lock-err) + détail serveur brut,
   discret, en dessous. */
.sm-err-msg{display:block}
.sm-err-detail{display:block;margin-top:6px;font-size:12.5px;font-weight:500;opacity:.82;word-break:break-word;overflow-wrap:anywhere}
/* Toast discret (message transitoire bas de l'écran) — s'efface seul, sans emoji. */
.cr-toast{
  position:fixed;left:50%;bottom:24px;transform:translate(-50%,16px);
  z-index:60;max-width:min(92vw,420px);padding:12px 18px;border-radius:14px;
  font-size:14px;font-weight:600;text-align:center;
  background:var(--card2);color:var(--txt);border:1px solid var(--hairline);
  box-shadow:0 8px 30px rgba(0,0,0,.28);
  opacity:0;pointer-events:none;transition:opacity .22s ease,transform .22s ease;
}
.cr-toast.show{opacity:1;transform:translate(-50%,0)}
/* Bloc « Autre » (serveur IMAP libre + port/SSL) de la modale boîte mail. */
.sm-autre{display:flex;flex-direction:column;gap:12px}
.sm-check-row{display:flex;flex-direction:row;align-items:center;gap:8px;font-size:13px;font-weight:600;color:var(--muted)}
.sm-check-row input{flex:none}
/* Récap adresse / serveur IMAP de la modale d'approbation d'une boîte mail. */
.sm-kv{
  display:flex;align-items:baseline;justify-content:space-between;gap:12px;
  padding:10px 12px;border-radius:12px;background:var(--card2);
  border:1px solid var(--hairline);font-size:14px;
}
.sm-kv-k{font-size:12px;font-weight:600;color:var(--muted);flex:none}
.sm-kv-v{font-weight:600;text-align:right;word-break:break-all;overflow-wrap:anywhere}
/* Hôte IMAP inattendu (imposé par l'agent ≠ hôte déduit du domaine) : en garde. */
.sm-kv.warn{
  background:color-mix(in srgb,var(--danger) 12%,transparent);
  border-color:color-mix(in srgb,var(--danger) 34%,var(--hairline));
}
.sm-kv.warn .sm-kv-v{color:var(--danger)}
.sm-warn{
  font-size:13px;line-height:1.45;font-weight:500;color:var(--danger);
  padding:10px 12px;border-radius:12px;
  background:color-mix(in srgb,var(--danger) 12%,transparent);
  border:1px solid color-mix(in srgb,var(--danger) 30%,transparent);
}
.sm-check{
  display:flex;align-items:center;gap:10px;padding:10px 12px;border-radius:12px;
  background:var(--card2);border:1px solid var(--hairline);cursor:pointer;font-size:14px;
}
.sm-check input{width:18px;height:18px;accent-color:var(--accent);flex:none}
.sm-check input:disabled{opacity:.5}
/* Nom de l'assistant précédé de sa gemme monogramme (zéro emoji). */
.sm-check-name{display:flex;align-items:center;gap:8px;min-width:0}
.sm-check-name .gem{--gem-sz:22px;flex:none}
.sm-check-name>span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
/* Rangée « rattacher » : assistant + bouton Configurer (renvoie vers sa page). */
.sm-attach-row{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:6px 0}
.sm-attach-row .sm-check-name{flex:1}

/* ---------- Bandeau guard (demandes de connexion des assistants) ----------
   Vitre d'alerte (.glass) à liseré ambré : gemme monogramme du DEMANDEUR à
   gauche, message avec puce icône de marque du connecteur. Zéro emoji. */
#guardBanner{display:flex;flex-direction:column;gap:12px;margin-bottom:18px}
.guard-card{
  display:flex;align-items:center;gap:14px;padding:14px 16px;flex-wrap:wrap;
  max-width:100%;
  border-color:rgba(192,76,0,.34);
  box-shadow:inset 3px 0 0 var(--warn),inset 0 1px 0 var(--glass-hi),var(--shadow-card);
}
.guard-gem{flex:none;align-self:flex-start}
.guard-gem .gem{--gem-sz:40px}
.guard-body{flex:1 1 220px;min-width:0}
.guard-msg{margin:0;font-size:15px;line-height:1.5}
.guard-msg b{font-weight:700}
.guard-conn{
  display:inline-flex;align-items:center;gap:5px;vertical-align:middle;
  padding:1px 9px 1px 5px;border-radius:var(--radius-pill);
  background:var(--card2);border:1px solid var(--hairline);font-weight:600;
}
.guard-conn .brandico{width:15px;height:15px;flex:none}
.guard-conn .gem{--gem-sz:16px;flex:none}
.guard-reason{display:block;margin-top:4px;font-size:13px;color:var(--muted);overflow-wrap:anywhere}
/* Demande de LIEN réseau : sélecteur du sens DANS la carte (mêmes pilules que
   les réglages, et la MÊME règle compacte que .cfg-net-seg — voir plus bas, elle
   doit rester APRÈS la base .set-seg-btn : la carte du bandeau est étroite et ne
   doit jamais déborder, même à 375 px). */
.guard-net-seg{width:100%;margin-top:8px}
.guard-err{display:block;margin:6px 0 0;font-size:13px;color:var(--danger,#c0392b);overflow-wrap:anywhere}
.guard-actions{display:flex;gap:8px;flex:none;min-width:0}
@media (max-width:480px){
  /* Mobile 375px : carte en colonne, boutons pleine largeur, cible tactile ≥44px,
     aucun débordement horizontal (enfants flex autorisés à rétrécir). */
  .guard-card{flex-direction:column;align-items:stretch}
  .guard-body{flex:1 1 auto;min-width:0}
  .guard-actions{width:100%}
  .guard-actions .cta{flex:1;min-width:0;min-height:44px}
}

/* ---------- Carte ALERTE DE SÉCURITÉ (injection, secret retenu — lot P5) ----
   Même vitre que le guard (structure guardShell réutilisée) mais liseré DANGER,
   pas ambré : ce n'est pas une demande à trancher, c'est un incident à savoir.
   Posée au-dessus des cartes guard, hors zone scrollée : toujours visible.
   Zéro emoji (bouclier SVG monochrome). */
#alertInline{display:flex;flex-direction:column;gap:10px;margin:10px 0 4px}
.guard-card.alert-card{
  border-color:color-mix(in srgb,var(--danger) 30%,var(--glass-brd));
  box-shadow:inset 3px 0 0 var(--danger),inset 0 1px 0 var(--glass-hi),var(--shadow-card);
}
.alert-card .guard-gem{color:var(--danger);align-self:flex-start;display:flex}
/* Extrait du contenu hostile : monospace, replié, jamais débordant (une seule
   ligne côté serveur, mais un mot très long ne doit pas pousser la carte). */
.alert-excerpt{
  margin:6px 0 0;padding:6px 9px;border-radius:10px;
  background:var(--card2);border:1px solid var(--hairline);
  font-family:"JetBrains Mono",ui-monospace,monospace;font-size:12px;line-height:1.45;
  color:var(--muted);overflow-wrap:anywhere;max-width:100%;
}
/* La phrase de fin dit ce que la gateway A FAIT : elle rassure, elle n'alarme
   pas une seconde fois — donc encre normale, pas la teinte discrète des motifs. */
.alert-done{color:var(--txt)}
.alert-count{
  display:inline-block;margin-top:6px;padding:1px 9px;border-radius:var(--radius-pill);
  background:var(--card2);border:1px solid var(--hairline);
  font-size:12px;font-weight:600;color:var(--muted);
}

/* ---------- Carte QUESTION (ask_user) dans le fil du chat ----------
   Vitre à liseré accent (≠ liseré ambré du guard) posée dans .chat-log :
   qui pose + question + boutons de choix + champ libre optionnel. Une fois
   résolue (.resolved), les choix disparaissent et un accusé s'affiche. */
.ask-card{
  align-self:stretch;max-width:100%;display:flex;gap:12px;padding:13px 15px;
  border-color:var(--accent-soft);
  box-shadow:inset 3px 0 0 var(--accent),inset 0 1px 0 var(--glass-hi),var(--shadow-card);
}
.ask-gem{flex:none;align-self:flex-start}
.ask-gem .gem{--gem-sz:34px}
.ask-body{flex:1 1 auto;min-width:0}
.ask-who{margin:0;font-size:13px;color:var(--muted)}
.ask-who b{font-weight:700;color:var(--txt)}
.ask-q{margin:3px 0 10px;font-size:15px;line-height:1.5;overflow-wrap:anywhere}
.ask-opts{display:flex;flex-wrap:wrap;gap:8px}
.ask-opt{min-width:0}
.ask-free{display:flex;gap:8px;margin-top:10px}
.ask-free-input{
  flex:1;min-width:0;padding:9px 12px;border-radius:var(--radius-pill);
  border:1px solid var(--hairline);background:var(--card2);color:var(--txt);font-size:14px;
}
.ask-free-input:focus{outline:none;border-color:var(--accent);box-shadow:var(--ring)}
.ask-free-send{flex:none}
.ask-err{margin:8px 0 0;font-size:13px;color:var(--danger);overflow-wrap:anywhere}
.ask-done{margin:2px 0 0;font-size:14px;color:var(--ok);overflow-wrap:anywhere}
.ask-done b{font-weight:700}
.ask-expired{color:var(--muted)}
@media (max-width:480px){
  .ask-opts .cta{flex:1 1 auto;min-height:44px}
  .ask-free{flex-direction:column}
  .ask-free-send{width:100%;min-height:44px}
}

/* ---------- Chat avec un assistant ---------- */
.chat{
  display:flex;flex-direction:column;gap:var(--chat-gap);
  min-height:var(--screen-min);
}
/* En-tête = barre de verre : gemme monogramme de l'agent + nom (blur autorisé).
   C1a — barre MAGNÉTIQUE : elle se colle juste sous la pilule du haut
   (`--stick-top`) et ne quitte plus l'écran. On sait toujours À QUI on parle,
   et les gestes de la conversation (calendrier, historique, nouvelle
   conversation) restent sous le doigt au lieu de partir en haut du document.
   Le fil défile DERRIÈRE elle : le verre est déjà flouté (`.glass`), rien à
   ajouter. `z-index` sous celui de la topbar (20) — la barre du haut reste la
   couche la plus haute ; au-dessus des volets, qui viennent après dans le
   document et passeraient sinon par-dessus à z-index égal.
   Hauteur FIXE (`--head-h`) : c'est elle qui donne aux volets la ligne où se
   coller à leur tour (`--stick-top2`) ; une hauteur devinée les ferait glisser
   sous l'en-tête. Elle vaut la cible tactile (44px) + les marges de la barre. */
.chat-head{
  position:sticky;top:var(--stick-top);z-index:15;
  display:flex;align-items:center;gap:12px;padding:8px 12px;min-height:var(--head-h)
}
.chat-id{flex:1;display:flex;align-items:center;gap:11px;min-width:0}
/* Même rayon que la gemme qu'elle contient : l'anneau « au travail »
   (shared/agent_activity.css) épouse ainsi sa forme au lieu d'un rectangle. */
.chat-gem{flex:none;display:flex;border-radius:28%}
.chat-head h1{font-size:20px;font-weight:700;letter-spacing:-.01em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* G3a : les deux entrées NOMMÉES de l'historique (conversations précédentes /
   nouvelle conversation) réutilisent la pilule `.navbtn` de la topbar — donc
   aussi son repli à 640 px (`.navbtn span{display:none}`) : le TEXTE se rabat,
   l'icône reste sur sa ligne, la barre ne change pas de hauteur. `flex:none` +
   `nowrap` : c'est le NOM de l'assistant qui cède la place (il a déjà son
   ellipse), jamais le libellé — sans quoi il passerait à la ligne et ferait
   grandir une barre dont la hauteur est fixe (`--head-h`). */
.chat-head .navbtn{flex:none;white-space:nowrap}
/* U7 : conversation + zone de travail côte à côte. La conversation garde
   `flex:1` et `min-width:0` — zone fermée, elle occupe TOUTE la largeur ; zone
   ouverte, elle se resserre sans jamais devenir une colonne « ascenseur ».
   `position:relative` porte l'annonce de dépôt (.chat-drophint). */
.chat-body{flex:1;display:flex;align-items:stretch;gap:var(--chat-gap);min-height:0}
/* G2 : la conversation a un PLANCHER de lisibilité (`--read-min`). Sans lui, un
   écran moyen avec les deux volets ouverts la comprimait en gouttière. Le
   `min(...,100%)` garde la règle inoffensive sur un téléphone : le plancher ne
   peut jamais dépasser la place réellement disponible. */
.chat-main{
  flex:1;position:relative;display:flex;flex-direction:column;gap:12px;
  min-width:min(var(--read-min),100%);min-height:0;
}
/* G1 : la coquille prend tout l'écran, la CONVERSATION garde sa colonne de
   lecture (`--read-w`) et se centre. Sans ça, sur un grand écran les bulles
   partiraient se coller aux deux bords opposés : la place gagnée doit aller au
   shell et à la zone de travail, pas à la ligne de texte. Le voile de dépôt est
   exclu : il annonce la conversation ENTIÈRE, il doit la couvrir entière. */
.chat-main > *:not(.chat-drophint){width:100%;max-width:var(--read-w);margin-inline:auto}
.chat-log{
  flex:1;display:flex;flex-direction:column;gap:14px;overflow-y:auto;
  padding:6px 2px;min-height:220px;-webkit-overflow-scrolling:touch;
}
.chat-hollow{
  margin:auto;text-align:center;color:var(--muted);font-size:14px;padding:40px 12px;max-width:340px;
}
.msg{max-width:min(680px,92%);display:flex;flex-direction:column;gap:6px}
.msg.user{align-self:flex-end}
.msg.bot{align-self:flex-start}
/* Bulles = verre semi-opaque SANS backdrop-filter (le blur reste réservé à
   l'en-tête + composer — perf pad). Utilisateur = verre teinté prismatique,
   assistant = verre neutre. */
.msg .body{
  padding:11px 15px;border-radius:16px;font-size:15px;line-height:1.55;
  word-break:break-word;overflow-wrap:anywhere;
}
.msg.user .body{
  color:#fff;border-bottom-right-radius:5px;
  background:linear-gradient(135deg,
    color-mix(in srgb,var(--accent) 82%,#7c5cff),
    color-mix(in srgb,var(--accent) 64%,#2ad4ff));
  border:1px solid var(--glass-brd2);
  box-shadow:inset 0 1px 0 rgba(255,255,255,.28),0 6px 20px rgba(124,92,255,.28);
}
.msg.bot .body{
  border-bottom-left-radius:5px;
  background:color-mix(in srgb,var(--card) 82%,transparent);
  border:1px solid var(--glass-brd);
  box-shadow:inset 0 1px 0 var(--glass-hi);
}
.msg .body.waiting{
  color:var(--muted);font-style:italic;
  background:color-mix(in srgb,var(--card) 68%,transparent);border:1px solid var(--glass-brd);
}
.msg .meta{font-size:11.5px;color:var(--muted);padding:0 4px}
/* NOTE du fil (W10) : un événement de la mécanique du tour — une consigne
   d'orientation — jamais une parole. Centrée, discrète, bord tireté : on doit
   voir d'un coup d'œil que ce n'est ni l'utilisateur (bulle prismatique à
   droite) ni l'assistant (bulle de verre à gauche). */
.msg.note{align-self:center;max-width:min(560px,96%);text-align:center}
.msg.note .body{
  padding:8px 14px;border-radius:12px;font-size:13.5px;
  color:var(--muted);background:color-mix(in srgb,var(--card) 55%,transparent);
  border:1px dashed var(--glass-brd);
}
.msg.note .meta{text-align:center;padding:0 6px}
/* Sortie proposée par une bulle d'erreur (E1) : un bouton à la taille de son
   texte, jamais une bande pleine largeur — et jamais une navigation subie. */
.msg-act{align-self:flex-start}
/* Bannière « aucun cerveau sur ce serveur » : même vitre que le wizard, posée
   en tête de la vue chat sans manger la hauteur du fil. */
.chat-banner{align-self:center;flex:none}
/* Markdown minimal dans les bulles */
.mdwrap>div{min-height:1px}
.mdwrap .mdgap{height:8px}
.mdwrap .mdh{font-weight:700;margin:6px 0 2px}
.mdwrap ul,.mdwrap ol{margin:4px 0 4px 20px}
.mdwrap code{
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:.9em;
  background:var(--card2);border:1px solid var(--hairline);border-radius:5px;padding:1px 5px;
}
.mdwrap a{color:var(--accent);text-decoration:underline}
.mdcode{
  background:var(--card2);border:1px solid var(--hairline);border-radius:12px;
  padding:12px 14px;margin:8px 0;overflow-x:auto;
}
.mdcode code{background:none;border:0;padding:0;font-size:13px;line-height:1.5;white-space:pre}
/* Bloc « Réflexion » repliable = verre neutre (pas de blur) */
.think{
  align-self:flex-start;max-width:100%;font-size:13px;color:var(--muted);
  background:color-mix(in srgb,var(--card) 70%,transparent);
  border:1px solid var(--glass-brd);border-radius:14px;padding:4px 12px;
  box-shadow:inset 0 1px 0 var(--glass-hi);
}
.think summary{cursor:pointer;font-weight:600;padding:4px 0;list-style:none}
.think summary::-webkit-details-marker{display:none}
.think summary::before{content:"›";display:inline-block;margin-right:6px;transition:transform var(--dur) var(--ease)}
.think[open] summary::before{transform:rotate(90deg)}
.think-body{white-space:pre-wrap;padding:4px 0 8px;line-height:1.5;opacity:.9}
/* Chips outils = pastilles verre monochrome */
.tchip{
  display:inline-flex;align-items:center;gap:6px;align-self:flex-start;max-width:100%;
  font-size:12.5px;color:var(--muted);
  background:color-mix(in srgb,var(--card) 66%,transparent);
  border:1px solid var(--glass-brd);border-radius:var(--radius-pill);padding:4px 11px;
  box-shadow:inset 0 1px 0 var(--glass-hi);
}
.tchip span{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.tchip.ok{color:var(--ok)}
.tchip.err{color:var(--danger)}
/* ---- Bas de colonne : UN SEUL bloc collant ----
   Réglages (Mode/Effort), ouverture de la zone de travail et champ de saisie
   descendent ensemble. Avant, seul `.chat-composer` était `sticky` : dès que la
   colonne dépassait la hauteur de la fenêtre — c'est le cas quand la zone de
   travail s'ouvre et resserre la conversation — le champ remontait au bas de
   l'écran tandis que la barre Mode/Effort restait à sa place, plus bas : les
   deux se chevauchaient et la barre était coupée par le bas de la fenêtre.
   Collant en bloc, ils gardent leur ordre de flux (réglages AU-DESSUS du champ,
   jamais par-dessus) et le bloc entier tient dans la fenêtre. */
.chat-bottom{
  position:sticky;bottom:max(10px,env(safe-area-inset-bottom));
  display:flex;flex-direction:column;gap:12px;min-width:0;
}
/* Zone de saisie = barre de verre FLOTTANTE (blur autorisé ici), safe-area. */
.chat-composer{
  display:flex;gap:10px;align-items:flex-end;margin-top:8px;padding:7px 7px 7px 6px;
  background:var(--glass);border:1px solid var(--glass-brd);border-radius:26px;
  box-shadow:inset 0 1px 0 var(--glass-hi),var(--shadow-card);
  -webkit-backdrop-filter:var(--glass-bd);backdrop-filter:var(--glass-bd);
  transition:border-color var(--dur) var(--ease),box-shadow var(--dur) var(--ease);
}
@supports not ((backdrop-filter:blur(1px)) or (-webkit-backdrop-filter:blur(1px))){
  .chat-composer{background:var(--glass-solid)}
}
.chat-composer:focus-within{border-color:var(--glass-brd2);box-shadow:inset 0 1px 0 var(--glass-hi2),var(--halo)}
/* Le champ épouse la barre : transparent, sans bord ni anneau propre. */
/* `min-width:0` : sans lui, la taille minimale AUTOMATIQUE d'un `<textarea>`
   (dérivée de ses colonnes) l'empêche de rétrécir, et la barre déborde dès
   qu'elle porte trois boutons — le cas d'un tour en vol à 390 px (Orienter +
   Arrêter + dictée). Le champ doit céder, pas la barre. */
.chat-input{
  flex:1;min-width:0;resize:none;max-height:180px;line-height:1.45;overflow-y:auto;
  background:transparent;border:0;padding:11px 8px;min-height:44px;
}
.chat-input:focus{border:0;box-shadow:none}
/* Bouton envoi = gemme bouton (dégradé prismatique, relief, halo au survol). */
.chat-send{
  flex:none;display:grid;place-items:center;width:44px;height:44px;border-radius:15px;
  background:var(--prism);color:#fff;
  transition:transform var(--dur) var(--ease),box-shadow var(--dur) var(--ease),opacity var(--dur) var(--ease);
  box-shadow:inset 0 1px 1px rgba(255,255,255,.42),0 4px 14px rgba(124,92,255,.4);
}
.chat-send:hover{transform:translateY(-1px);box-shadow:inset 0 1px 1px rgba(255,255,255,.42),0 8px 22px rgba(124,92,255,.55)}
.chat-send.stop{background:var(--danger);color:#fff;box-shadow:0 4px 14px rgba(0,0,0,.2)}
/* Orienter (W10) : même gabarit tactile (44 px) que l'envoi, mais PAS la gemme
   — elle reste l'action « envoyer un message ». Orienter recadre un tour déjà
   parti : c'est un geste secondaire, contourné d'accent, il se lit comme tel. */
.chat-send.steer{
  background:none;color:var(--accent);border:1px solid var(--accent);box-shadow:none;
}
.chat-send.steer:hover{
  transform:translateY(-1px);box-shadow:none;
  background:color-mix(in srgb,var(--accent) 12%,transparent);
}
/* Dictée (U8) : bouton DISCRET à côté de l'envoi — même gabarit tactile (44 px,
   utilisable au doigt) mais pas la gemme, réservée à l'action d'envoyer : dicter
   remplit le champ, ça n'envoie rien. À l'écoute il s'allume et respire — l'état
   se voit sans ajouter un mot dans la barre. */
.chat-mic{
  flex:none;display:grid;place-items:center;width:44px;height:44px;border-radius:15px;
  color:var(--muted);background:color-mix(in srgb,var(--card) 68%,transparent);
  border:1px solid var(--glass-brd);
  transition:color var(--dur) var(--ease),border-color var(--dur) var(--ease),background var(--dur) var(--ease);
}
.chat-mic:hover{color:var(--accent);border-color:var(--accent)}
/* Le battement s'éteint tout seul si l'utilisateur refuse les animations : le
   bloc global @media (prefers-reduced-motion:reduce) plus bas coupe déjà TOUTE
   animation — inutile d'en rouvrir un ici (et un 2e bloc masquerait le premier). */
.chat-mic.on{color:#fff;background:var(--danger);border-color:transparent;animation:micPulse 1.7s var(--ease) infinite}
@keyframes micPulse{
  0%,100%{box-shadow:0 0 0 0 color-mix(in srgb,var(--danger) 55%,transparent)}
  50%{box-shadow:0 0 0 6px color-mix(in srgb,var(--danger) 0%,transparent)}
}
/* Bouton d'ouverture : en bas à droite, juste AU-DESSUS du champ de texte. */
.chat-workbar{display:flex;justify-content:flex-end;margin:0 4px -2px}
.work-toggle{
  display:inline-flex;align-items:center;gap:7px;min-height:34px;padding:6px 13px;
  font-size:12.5px;font-weight:600;color:var(--muted);
  background:color-mix(in srgb,var(--card) 68%,transparent);
  border:1px solid var(--glass-brd);border-radius:var(--radius-pill);
  transition:color var(--dur) var(--ease),border-color var(--dur) var(--ease);
}
.work-toggle:hover{color:var(--accent);border-color:var(--accent)}
.work-toggle[aria-expanded="true"]{color:var(--accent);border-color:var(--accent);background:var(--accent-soft)}
/* Zone fermée + nouveautés en attente : un point, pas un chiffre — le compte
   exact vit dans la tête de la zone, qu'on ouvre d'un clic. */
.work-toggle.has-new::after{
  content:"";width:7px;height:7px;border-radius:50%;background:var(--ok);flex:none;
}
/* Annonce de dépôt DANS la conversation : inerte au pointeur, sinon elle
   volerait l'événement de dépôt qu'elle annonce. */
.chat-drophint{
  position:absolute;inset:0;z-index:3;pointer-events:none;
  display:flex;align-items:center;justify-content:center;padding:20px;
  border:2px dashed var(--accent);border-radius:var(--radius-lg);
  background:color-mix(in srgb,var(--accent) 10%,transparent);
  font-size:14px;font-weight:600;color:var(--accent);text-align:center;
}
/* ---- Zone de travail : volet latéral droit (U7) ----
   Fermée elle ne prend AUCUNE place (display:none) : la conversation reprend
   toute la largeur. [hidden] (aucun dossier de travail) reste prioritaire. */
.chat-work{
  /* `0 1` : le volet ne pousse jamais, mais il SE RESSERRE quand la
     conversation réclame son plancher (`--read-min`) — c'est lui qui cède, pas
     le fil. */
  flex:0 1 var(--side-w);width:var(--side-w);min-width:0;display:none;
  align-self:flex-start;position:sticky;top:var(--stick-top2);
  max-height:calc(100dvh - var(--stick-top2) - var(--chat-gap));overflow-y:auto;
  -webkit-overflow-scrolling:touch;
}
.chat-work.open{display:block}
.chat-work.drop .chat-files{border-color:var(--accent);background:var(--accent-soft)}
.chat-work.drop .ws-send-hint{color:var(--accent)}
/* ---- Panneau « En attente de validation » (V1) : le second volet droit ----
   Il partage la MISE EN VOLET de la zone de travail (même largeur `--side-w`,
   même ancrage collant) : ce sont deux panneaux du même meuble, pas deux
   inventions. Il n'a pas d'état « fermé » : il apparaît quand il a quelque
   chose à faire valider et disparaît quand la file est vide (`[hidden]` posé
   par pendRender) — un panneau vide serait un meuble mort. */
.chat-pend{
  flex:0 1 var(--side-w);width:var(--side-w);min-width:0;
  align-self:flex-start;position:sticky;top:var(--stick-top2);
  max-height:calc(100dvh - var(--stick-top2) - var(--chat-gap));overflow-y:auto;
  -webkit-overflow-scrolling:touch;
}
/* Les cartes de demande gardent leur structure (mêmes cartes que le bandeau,
   mêmes gestes) mais se RESSERRENT dans le volet : le panneau est un mur de
   petites cartes, pas une pile de bannières. */
.pend-list{display:flex;flex-direction:column;gap:8px;padding:2px 10px 12px}
.pend-list > *{width:100%}
.pend-list .guard-card,.pend-list .ask-card{padding:11px 12px;gap:9px;font-size:13px}
.pend-list .guard-gem,.pend-list .ask-gem{width:28px;height:28px}
.pend-list .guard-gem svg,.pend-list .ask-gem svg{width:28px;height:28px}
.pend-list .guard-actions,.pend-list .ask-opts{flex-wrap:wrap;gap:6px}
/* Panneau fichiers (contenu de la zone) + boîte du panneau de validation =
   même vitre neutre : une seule règle, deux hôtes. */
.chat-files,.pend-box{
  border:1px solid var(--glass-brd);border-radius:16px;overflow:hidden;
  background:color-mix(in srgb,var(--card) 68%,transparent);
  box-shadow:inset 0 1px 0 var(--glass-hi);
  transition:border-color var(--dur) var(--ease),background var(--dur) var(--ease);
}
.chat-files-head{
  display:flex;align-items:center;gap:8px;width:100%;padding:9px 13px;
  font-size:13.5px;font-weight:600;color:var(--muted);
}
.ws-close{
  margin-left:auto;flex:none;display:inline-flex;align-items:center;justify-content:center;
  width:28px;height:28px;border-radius:9px;color:var(--muted);
}
.ws-close:hover{background:var(--accent-soft);color:var(--accent)}
.chat-files-head .cnt{
  font-size:11px;background:var(--accent-soft);color:var(--accent);
  border-radius:var(--radius-pill);padding:1px 8px;
}
/* Nouveautés (U5) : ce que l'assistant vient d'écrire se signale de lui-même —
   pastille sur la tête tant que le panneau est replié, mention par ligne
   ensuite. Texte, jamais d'emoji. */
.chat-files-head .cnt.new{background:color-mix(in srgb,var(--ok) 16%,transparent);color:var(--ok)}
.chat-files-list{display:flex;flex-direction:column;gap:8px;padding:2px 10px 12px}
/* Tri de l'arbre : une icône dans la tête, pas une barre — on trie rarement. */
.ws-sort{
  flex:none;display:inline-flex;align-items:center;justify-content:center;
  width:28px;height:28px;border-radius:9px;color:var(--muted);margin-left:auto;
}
.ws-sort:hover,.ws-sort[aria-expanded="true"]{background:var(--accent-soft);color:var(--accent)}
/* Le bouton de fermeture suivait le tri : il n'est plus le premier à droite. */
.ws-sort ~ .ws-close{margin-left:0}
/* `position:relative` : le lasso (.ws-band) se pose DANS la liste, ses
   coordonnées sont donc celles de la liste. `user-select:none` : glisser sur le
   fond trace un rectangle, ça ne surligne pas des noms de fichiers. */
/* `min-height` : le lasso part du VIDE — sans un peu de fond sous les lignes,
   un dossier de deux fichiers n'offrirait nulle part où commencer le geste. */
.ws-rows{
  display:flex;flex-direction:column;gap:4px;position:relative;
  user-select:none;min-height:120px;
}
.ws-row{
  display:flex;align-items:center;gap:4px;border-radius:11px;
  border:1px solid transparent;transition:border-color var(--dur) var(--ease),background var(--dur) var(--ease);
}
.ws-row:hover{border-color:var(--glass-brd);background:color-mix(in srgb,var(--card) 72%,transparent)}
/* Ligne CHOISIE (G2) : l'état se voit d'un coup d'œil, sans rien ajouter à la
   ligne — c'est la sélection qui porte l'action, plus une corbeille par item. */
.ws-row.sel,.ws-row.sel:hover{
  background:var(--accent-soft);border-color:color-mix(in srgb,var(--accent) 38%,transparent);
}
.ws-row.sel .ws-name{color:var(--accent);font-weight:600}
/* Le rectangle du lasso : dessiné pendant le glisser, retiré au relâchement.
   Il ne reçoit aucun clic — c'est un tracé, pas une cible. */
.ws-band{
  position:absolute;pointer-events:none;border-radius:6px;
  border:1px solid color-mix(in srgb,var(--accent) 55%,transparent);
  background:color-mix(in srgb,var(--accent) 12%,transparent);
}
/* ARBORESCENCE (G2) : la PROFONDEUR est un cran de décalage à gauche, posé par
   la variable `--ws-d` que le rendu écrit sur la ligne. Un seul pas ici — le JS
   ne calcule aucune marge. */
.ws-main{
  flex:1;min-width:0;display:flex;align-items:center;gap:8px;
  padding:7px 9px 7px calc(9px + var(--ws-d,0) * var(--ws-step));
  font-size:13px;color:var(--txt);text-align:left;
}
/* Chevron d'ouverture : présent sur toute ligne (vide pour un fichier) pour que
   les noms restent alignés. Il PIVOTE quand la branche s'ouvre — mouvement
   fonctionnel (l'état du dépliage), pas une décoration. */
.ws-chev{
  flex:none;display:inline-flex;align-items:center;justify-content:center;
  width:14px;height:14px;color:var(--muted);
  transition:transform var(--dur) var(--ease);
}
.ws-row.open > .ws-main > .ws-chev{transform:rotate(90deg)}
.ws-ico{flex:none;display:inline-flex;align-items:center;justify-content:center}
.ws-name{flex:1;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ws-meta{flex:none;font-size:11.5px;color:var(--muted);font-variant-numeric:tabular-nums}
.ws-new{
  flex:none;font-size:10.5px;font-weight:700;letter-spacing:.02em;
  text-transform:uppercase;color:var(--ok);
  background:color-mix(in srgb,var(--ok) 14%,transparent);
  border-radius:var(--radius-pill);padding:1px 7px;
}
.ws-row.fresh{border-color:color-mix(in srgb,var(--ok) 32%,transparent)}
.ws-main:hover .ws-name{color:var(--accent)}
.ws-act{
  flex:none;display:inline-flex;align-items:center;justify-content:center;
  width:32px;height:32px;border-radius:9px;color:var(--muted);
}
.ws-act:hover{background:var(--accent-soft);color:var(--accent)}
.ws-del:hover{background:color-mix(in srgb,var(--danger) 14%,transparent);color:var(--danger)}
/* Envoi : bouton (doigt compris) + zone de dépôt + progression réelle. */
.ws-send{display:flex;flex-wrap:wrap;align-items:center;gap:4px 10px;padding-top:2px}
.ws-send-btn{
  display:inline-flex;align-items:center;gap:7px;font-size:13px;font-weight:600;
  color:var(--accent);background:var(--accent-soft);
  border:1px solid transparent;border-radius:11px;padding:9px 14px;min-height:40px;
}
.ws-send-btn:hover{border-color:var(--accent)}
.ws-send-hint{font-size:12px;color:var(--muted)}
.ws-up{display:flex;align-items:center;gap:9px;padding:2px 0}
.ws-up-track{
  flex:1;height:5px;border-radius:var(--radius-pill);overflow:hidden;
  background:color-mix(in srgb,var(--muted) 22%,transparent);
}
.ws-up-fill{display:block;height:100%;width:0;background:var(--accent);transition:width .18s linear}
.ws-up-txt{flex:none;font-size:11.5px;color:var(--muted);font-variant-numeric:tabular-nums}
.ws-empty{padding:14px 10px;text-align:center}
.ws-empty-t{font-size:13.5px;font-weight:600;color:var(--txt)}
.ws-empty-s{font-size:12.5px;color:var(--muted);margin-top:3px}
/* Écran étroit : la zone de travail ne PARTAGE plus la largeur — elle se replie
   hors champ à droite et s'ouvre PAR-DESSUS la conversation, qui garde donc
   toute sa place tant qu'elle est fermée. Au-dessus du contenu et de la topbar
   (20), mais SOUS le menu (50) et les modales (60) : une confirmation de
   collision ou de suppression reste toujours au premier plan. */
@media (max-width:900px){
  .chat-work{
    /* Marque LUE par le JS (wsIsOverlay) : en tiroir, la zone ne s'ouvre pas
       d'elle-même — elle couvrirait la conversation sans qu'on l'ait demandé.
       Le seuil ne vit QU'ICI : une media query ne sait pas lire une variable,
       alors c'est elle qui la pose. */
    --ws-overlay:1;
    position:fixed;top:0;right:0;bottom:0;width:min(360px,90vw);max-height:none;
    z-index:30;padding:14px 12px calc(14px + env(safe-area-inset-bottom));
    background:var(--glass-solid);border-left:1px solid var(--glass-brd);
    box-shadow:var(--shadow-pop);
    overflow-y:auto;
  }
  /* Le panneau de validation, lui, ne part PAS en tiroir : une décision en
     attente qu'il faut aller chercher derrière un bouton est une décision
     oubliée. Il repasse simplement en pleine largeur, AU-DESSUS de la
     conversation (`order`), et redevient une bande normale du flux. */
  .chat-body{flex-wrap:wrap}
  /* `flex-basis` prime sur `width` pour un enfant flex : redevenir une bande
     pleine largeur demande de reprendre la BASE, pas seulement la largeur. */
  .chat-pend{width:100%;order:-1;position:static;max-height:none;overflow:visible;flex-basis:100%}
}
/* Téléphone (390 px) : la date passe sous le nom, les actions restent au doigt. */
@media (max-width:430px){
  .ws-main{flex-wrap:wrap;gap:3px 8px}
  .ws-name{flex:1 0 100%}
  .ws-meta{margin-left:23px}
  /* La mention « nouveau » passe sous le nom, alignée sur la date. */
  .ws-new{margin-left:23px}
  .ws-row.fresh .ws-meta{margin-left:0}
  .ws-crumb{max-width:44vw}
  .ws-send-btn{flex:1;justify-content:center}
  .ws-send-hint{flex:1 0 100%;text-align:center}
}
/* Modale d'aperçu de fichier */
.file-modal{width:min(720px,100%);max-height:82dvh;display:flex;flex-direction:column;padding:0}
.file-modal-head{
  display:flex;align-items:center;gap:10px;padding:14px 18px;border-bottom:1px solid var(--hairline);
}
.file-modal-name{
  flex:1;font-size:13.5px;font-weight:600;color:var(--muted);
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.file-modal-body{
  margin:0;padding:16px 18px;overflow:auto;white-space:pre-wrap;word-break:break-word;
  font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:12.5px;line-height:1.55;
}
/* Modale des conversations précédentes (même châssis que l'aperçu de fichier) */
.convs-modal{width:min(560px,100%);max-height:82dvh;display:flex;flex-direction:column;padding:0}
.convs-modal-name{flex:1;font-size:15px;font-weight:650;color:var(--txt)}
.convs-busy{margin:0;padding:12px 18px 0;color:var(--muted);font-size:13px}
.convs-list{display:flex;flex-direction:column;gap:6px;padding:12px;overflow:auto}
.convs-empty{margin:0;padding:14px 6px;color:var(--muted);font-size:14px;text-align:center}
/* Une ligne = la conversation (elle s'ouvre) + son « … » (gérer). Le cadre
   reste porté par la ligne : le bouton d'ouverture n'a ni bord ni fond, il n'y
   a donc toujours qu'UNE seule boîte visible par conversation. */
.conv-row{
  display:flex;align-items:center;gap:6px;
  background:color-mix(in srgb,var(--card) 72%,transparent);
  border:1px solid var(--glass-brd);border-radius:12px;padding:10px 12px;
  transition:border-color var(--dur) var(--ease),color var(--dur) var(--ease);
}
.conv-row:hover:has(.conv-open:not(:disabled)){border-color:var(--accent)}
.conv-row.on{border-color:var(--accent)}
.conv-open{
  flex:1;min-width:0;display:flex;flex-direction:column;gap:3px;text-align:left;
  background:none;border:0;padding:0;color:inherit;
}
.conv-open:disabled{opacity:.5;cursor:default}
.conv-title{
  font-size:14.5px;font-weight:600;color:var(--txt);
  white-space:nowrap;overflow:hidden;text-overflow:ellipsis;
}
.conv-meta{font-size:12.5px;color:var(--muted)}
/* Le « … » ne se remarque qu'au besoin : muet au repos (comme toute icône
   secondaire), net au survol de sa ligne ou au focus clavier. */
.conv-menu-btn{flex:none;border:0;background:none;opacity:.45}
.conv-row:hover .conv-menu-btn,.conv-menu-btn:focus-visible{opacity:1}
.conv-menu-btn:disabled{opacity:.2;cursor:default}
/* Renommage sur place : le champ prend EXACTEMENT la place du titre (`order`
   le remet en tête, la ligne ne se réorganise pas autour de lui). */
.conv-row.renaming .conv-open{display:none}
.conv-rename{
  order:-1;flex:1;min-width:0;font-size:14.5px;font-weight:600;color:var(--txt);
  background:var(--card);border:1px solid var(--accent);border-radius:8px;padding:4px 8px;
}

/* ---------- Apparition orchestrée ---------- */
@keyframes rise{from{opacity:0;transform:translateY(14px)}to{opacity:1;transform:none}}
.reveal{animation:rise .5s var(--ease) both}
.reveal>*{animation:rise .5s var(--ease) both}
.reveal>*:nth-child(2){animation-delay:.06s}
.reveal>*:nth-child(3){animation-delay:.12s}
.reveal>*:nth-child(4){animation-delay:.18s}
@media (prefers-reduced-motion:reduce){
  *,*::before,*::after{animation:none!important;transition:none!important}
}

/* ---------- Reflow de grille (cartes) ----------
   Une carte qui part (supprimée, mise en pause) laisse un trou : les autres
   viennent le combler EN GLISSANT (technique FLIP, cf. `gridReflow`). C'est le
   SEUL mouvement voulu — fonctionnel, jamais décoratif.
   Corollaire : pendant ce re-rendu, la grille ne rejoue PAS son entrée `rise`.
   Une liste qui se rafraîchit ne doit pas re-surgir, et l'animation écraserait
   de toute façon le `transform` du FLIP (une animation bat le style en ligne).
   D'où ce bloc placé APRÈS `.reveal` : à spécificité égale, c'est le dernier
   qui gagne. `prefers-reduced-motion` coupe déjà tout (bloc ci-dessus). */
.grid-reflow>*{animation:none}
.grid-flip{transition:transform var(--dur-move) var(--ease)}

/* ---------- Réglages ---------- */
.set-head{margin:8px 0 24px}
.set-head h1{font-size:clamp(24px,4vw,32px);font-weight:700;letter-spacing:-.02em}
.set-body{display:flex;flex-direction:column;gap:16px;max-width:540px}
.set-card{padding:20px 22px;display:flex;flex-direction:column;gap:14px}
.set-card-title{font-size:16px;font-weight:700;letter-spacing:-.01em}
.set-row{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}
.set-label{font-size:15px;color:var(--txt)}
.set-sub{font-size:14px;color:var(--muted);line-height:1.5}
/* Segmented control = verre : piste translucide à liseré, segment actif en
   pilule PRISMATIQUE (DA « Verre & Prisme »). Pas de backdrop propre (la piste
   vit déjà dans une vitre — évite un empilement de flous). */
.set-seg{
  display:flex;background:var(--glass);border:1px solid var(--glass-brd);
  border-radius:var(--radius-pill);padding:2px;box-shadow:inset 0 1px 0 var(--glass-hi);
  position:relative;
}
.set-seg-btn{
  flex:1;text-align:center;position:relative;z-index:1;
  padding:8px 14px;border-radius:var(--radius-pill);font-size:13.5px;font-weight:600;
  color:var(--muted);min-height:36px;
  /* B7 : libellés sur UNE ligne dans les 3 langues — le chinois (« 列表 », « 月 »,
     types « Quand ») se coupait entre idéogrammes et empilait les caractères
     (segment ~57px de haut). nowrap + écriture horizontale forcée l'interdisent. */
  white-space:nowrap;writing-mode:horizontal-tb;
  transition:color var(--dur) var(--ease);
}
.set-seg-btn.active{color:#fff}
/* Pilule active = indicateur UNIQUE qui GLISSE d'un segment à l'autre (« gros
   toggle ») : positionné par index (--seg-i / --seg-n), animé en transform et
   respectant prefers-reduced-motion (bloc global *{transition:none}). Piste
   partagée par le segmented des réglages (.set-seg) et le sélecteur de langue
   (.langsw) : plus aucun aplat par bouton qui SAUTE. */
.set-seg-ind,.langsw-ind{
  position:absolute;top:2px;left:2px;bottom:2px;width:calc((100% - 4px)/var(--seg-n,2));
  border-radius:var(--radius-pill);transform:translateX(calc(var(--seg-i,0) * 100%));
  transition:transform var(--dur) var(--ease);pointer-events:none;z-index:0;
}
.set-seg-ind{background:var(--prism);box-shadow:inset 0 1px 0 var(--glass-hi2),0 2px 10px rgba(124,92,255,.4)}
.langsw-ind{background:var(--ink)}
/* Réglages du tour (C1b) : mode ET effort tiennent dans UN bouton du composer,
   à droite du champ, qui déplie le menu partagé (.popmenu). Il remplace la
   barre de deux segmented (.chat-modebar) posée au-dessus du champ : elle
   occupait une ligne entière en permanence et, à 390 px, ses six niveaux
   d'effort devaient défiler dans leur propre conteneur — beaucoup de meuble
   pour des réglages qu'on touche rarement.
   Même gabarit tactile que la dictée et l'envoi (44 px, utilisable au doigt),
   mais pas la gemme : elle reste l'action « envoyer un message ». */
.chat-modebtn{
  flex:none;display:inline-flex;align-items:center;gap:7px;min-height:44px;padding:0 13px;
  border-radius:var(--radius-pill);font-size:13px;font-weight:600;color:var(--muted);
  border:1px solid var(--glass-brd);background:color-mix(in srgb,var(--card) 55%,transparent);
  transition:color var(--dur) var(--ease),border-color var(--dur) var(--ease);
}
.chat-modebtn:hover{color:var(--txt);border-color:var(--glass-brd2)}
/* Mode écarté du défaut : le bouton s'allume — l'état se lit sans rien ouvrir. */
.chat-modebtn.on{color:var(--accent);border-color:color-mix(in srgb,var(--accent) 34%,var(--glass-brd))}
.chat-modebtn>svg{flex:none}
/* Écran étroit : le LIBELLÉ se rabat, l'icône reste EN PLACE (même ligne, aucun
   reflux) — le réglage ne disparaît pas, il se resserre. */
@media (max-width:520px){
  .chat-modebtn{padding:0 12px}
  .chat-modebtn>span{display:none}
}
.set-form{display:flex;flex-direction:column;gap:10px;margin-top:2px}
.set-cta{margin-top:4px;width:100%;min-height:44px}
.set-err{margin-top:0}
.set-ok{font-size:14px;color:var(--ok);font-weight:600}
.set-health-state{display:flex;align-items:center;gap:10px}
.set-dot{width:9px;height:9px;border-radius:50%;background:var(--muted);flex:none}
/* Pastille d'état système : halo teinté doux (verre lumineux) selon santé. */
.set-dot.ok{background:var(--ok);box-shadow:0 0 0 4px color-mix(in srgb,var(--ok) 22%,transparent)}
.set-dot.ko{background:var(--danger);box-shadow:0 0 0 4px color-mix(in srgb,var(--danger) 22%,transparent)}
.set-mono{font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:13.5px;color:var(--muted)}
.set-advanced{display:flex;justify-content:center;padding:8px 0 4px}
.set-advanced-link{font-size:13px;color:var(--muted);text-decoration:underline;text-underline-offset:3px}
.set-advanced-link:hover{color:var(--accent)}

/* ---------- Calendrier de réveils (heartbeats) ----------
   « Verre & Prisme » : en-tête gemme, vitres liste, grille mois à pastilles
   prismatiques, segmented control partagé (.set-seg). Zéro emoji. */
.sched{max-width:680px;margin:0 auto;display:flex;flex-direction:column;gap:16px}
.sched-head{display:flex;align-items:center;gap:14px;padding:16px 18px}
.sched-gem{flex:none;display:inline-flex}
.sched-id{flex:1;min-width:0}
.sched-id h1{font-size:20px;font-weight:700;letter-spacing:-.02em;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.sched-sub{font-size:13px;color:var(--muted);margin-top:2px}
.sched-toolbar{display:flex;justify-content:center}
.sched-body{display:flex;flex-direction:column;gap:14px}
.sched-listwrap{display:flex;flex-direction:column;gap:12px}
.sched-hollow{padding:32px 20px;text-align:center;color:var(--muted);font-size:15px}
/* Une vitre par réveil. */
.sched-card{padding:16px 18px;display:flex;flex-direction:column;gap:12px}
.sched-card.off{opacity:.62}
.sched-card-head{display:flex;align-items:center;justify-content:space-between;gap:10px}
.sched-card-title{font-size:16px;font-weight:700;letter-spacing:-.01em}
.sched-badge{flex:none}
.sched-badge.on{background:color-mix(in srgb,var(--ok) 16%,transparent);color:var(--ok)}
.sched-badge.off{background:var(--accent-soft);color:var(--muted)}
.sched-meta{display:flex;flex-wrap:wrap;gap:8px}
.sched-pill{
  font-size:12.5px;font-weight:600;padding:5px 11px;border-radius:var(--radius-pill);
  background:var(--glass);border:1px solid var(--glass-brd);color:var(--txt);
  box-shadow:inset 0 1px 0 var(--glass-hi);
}
.sched-pill.next{color:var(--accent);border-color:color-mix(in srgb,var(--accent) 26%,var(--glass-brd))}
.sched-pill.status.ok{color:var(--ok)}
.sched-pill.status.err{color:var(--danger)}
.sched-pill.status.skip{color:var(--warn)}
.sched-pill.status.never{color:var(--muted)}
.sched-past-hint{margin:6px 0 0;font-size:12.5px;color:var(--warn)}
.sched-actions{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap}
.sched-switch-wrap{display:flex;align-items:center;gap:10px}
.sched-switch-lbl{font-size:13.5px;color:var(--muted)}
.sched-switch{
  width:46px;height:28px;border-radius:var(--radius-pill);position:relative;flex:none;padding:0;
  background:var(--glass);border:1px solid var(--glass-brd);box-shadow:inset 0 1px 0 var(--glass-hi);
  transition:background var(--dur) var(--ease),border-color var(--dur) var(--ease);
}
/* Cible tactile ≥44px sans agrandir le visuel (l'interrupteur reste 46×28). */
.sched-switch::before{content:"";position:absolute;inset:-8px -6px}
.sched-switch.on{background:var(--prism);border-color:transparent}
.sched-switch-dot{
  position:absolute;top:3px;left:3px;width:20px;height:20px;border-radius:50%;background:#fff;
  box-shadow:0 1px 4px rgba(0,0,0,.35);transition:transform var(--dur) var(--ease);
}
.sched-switch.on .sched-switch-dot{transform:translateX(18px)}
.sched-act-btn{
  padding:9px 16px;border-radius:var(--radius-pill);font-size:13.5px;font-weight:600;min-height:40px;
  background:var(--glass);border:1px solid var(--glass-brd);color:var(--txt);
}
.sched-act-btn.danger{color:var(--danger);border-color:color-mix(in srgb,var(--danger) 30%,var(--glass-brd))}
.sched-act-btn:hover{background:var(--accent-soft)}
.sched-act-btn.danger:hover{background:color-mix(in srgb,var(--danger) 12%,transparent)}
/* Historique repliable. */
.sched-hist{border-top:1px solid var(--glass-brd);padding-top:10px}
.sched-hist-sum{font-size:13.5px;font-weight:600;color:var(--muted);cursor:pointer;list-style:none}
.sched-hist-sum::-webkit-details-marker{display:none}
.sched-hist-body{display:flex;flex-direction:column;gap:6px;margin-top:10px}
.sched-runs-empty,.sched-runs-load{font-size:13px;color:var(--muted)}
.sched-run{display:flex;align-items:center;gap:8px;font-size:13px}
.sched-run-dot{width:8px;height:8px;border-radius:50%;flex:none;background:var(--muted)}
.sched-run-dot.ok{background:var(--ok)}
.sched-run-dot.err{background:var(--danger)}
.sched-run-dot.skip{background:var(--warn)}
.sched-run-when{color:var(--txt);font-weight:600}
.sched-run-detail{color:var(--muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
/* Vue mois : navigation + grille scrollable + pastilles prismatiques. */
.sched-monthwrap{display:flex;flex-direction:column;gap:12px}
.sched-monthnav{display:flex;align-items:center;justify-content:center;gap:16px}
.sched-month-title{font-size:16px;font-weight:700;letter-spacing:-.01em;min-width:140px;text-align:center;text-transform:capitalize}
.sched-monthscroll{overflow-x:auto;-webkit-overflow-scrolling:touch}
.sched-grid{
  display:grid;grid-template-columns:repeat(7,1fr);gap:4px;padding:12px;min-width:322px;
}
.sched-wd{text-align:center;font-size:11px;font-weight:700;color:var(--muted);padding:4px 0;text-transform:uppercase;letter-spacing:.03em}
.sched-day{
  position:relative;aspect-ratio:1;min-height:44px;border-radius:12px;padding:6px;
  display:flex;flex-direction:column;align-items:flex-start;gap:2px;
  background:transparent;border:1px solid transparent;transition:background var(--dur) var(--ease);
}
.sched-day:not(.empty):hover{background:var(--accent-soft)}
.sched-day.empty{pointer-events:none}
.sched-day-num{font-size:13px;font-weight:600;color:var(--txt)}
.sched-day.today{border-color:color-mix(in srgb,var(--accent) 40%,var(--glass-brd))}
.sched-day.today .sched-day-num{color:var(--accent)}
.sched-day.sel{background:var(--accent-soft);border-color:var(--accent)}
.sched-dots{display:flex;gap:3px;margin-top:auto;align-self:center;flex-wrap:wrap;justify-content:center}
.sched-dot{width:6px;height:6px;border-radius:50%;background:var(--prism);box-shadow:0 1px 3px rgba(124,92,255,.4)}
.sched-daydetail{padding:14px 16px;display:flex;flex-direction:column;gap:8px}
.sched-daydetail-title{font-size:15px;font-weight:700;text-transform:capitalize}
.sched-daydetail-none{font-size:14px;color:var(--muted)}
.sched-daydetail-row{display:flex;align-items:baseline;justify-content:space-between;gap:12px;flex-wrap:wrap}
.sched-daydetail-name{font-size:14px;font-weight:600}
.sched-daydetail-recur{font-size:12.5px;color:var(--muted)}
/* Modale de création manuelle : formulaire aligné à gauche dans la vitre. */
.sched-modal{align-items:stretch;text-align:left;max-width:440px;width:100%}
.sched-modal h2{text-align:left}
.sched-form{display:flex;flex-direction:column;gap:14px;margin:6px 0 4px}
.sched-fld{display:flex;flex-direction:column;gap:6px}
.sched-fld-lbl{font-size:13.5px;font-weight:600;color:var(--muted)}
.sched-ta{resize:vertical;min-height:72px;line-height:1.45}
.sched-kind-seg{flex-wrap:wrap}
.sched-spec{display:flex;flex-direction:column;gap:14px}
/* Modale ponctuelle : mini-calendrier prismatique (grille mois réutilisée) + heure. */
.sched-oncecal{display:flex;flex-direction:column;gap:10px;overflow-x:auto;-webkit-overflow-scrolling:touch}
.sched-oncecal .sched-grid{min-width:280px}
.sched-day.past{opacity:.32;cursor:default}
.sched-day.past:hover{background:transparent}
.sched-once-tz{font-size:12px;color:var(--muted)}
.sched-once-sum{font-size:13.5px;font-weight:600;color:var(--accent)}
select.field{appearance:none;-webkit-appearance:none;cursor:pointer}

/* ---------- Mobile ---------- */
@media (max-width:640px){
  /* La topbar est en flux (position:sticky) : elle RÉSERVE sa hauteur, le contenu
     coule dessous — le padding-top du main est donc un simple espace de respiration,
     pas une compensation d'un élément flottant (pas de zone morte sous la barre). */
  main#app{padding-top:16px}
  /* Jauge d'usage : elle passe SOUS le titre et le bouton (`order`) au lieu de
     s'intercaler entre eux — deux lignes propres, jamais trois. Les barres
     prennent alors la largeur restante. */
  .usage{--usage-bar-w:1fr;order:1;margin-left:0;width:100%}
  .brand-name{font-size:16px}
  .hero-gem{font-size:56px}
  .hero-gem svg{width:56px;height:56px}
  .navbtn span{display:none}
  .navbtn{padding:8px 10px}
  /* Topbar compacte : gaps resserrés + paddings réduits pour que tout tienne dans
     la pilule sans wrap ni débordement (hauteur stable = --topbar-h). */
  .topbar{padding:0 6px 0 12px}
  .topbar-actions{gap:8px}
  .langsw button{padding:6px 11px}
  /* Perf pad/mobile : flou de l'aura réduit ; blur du verre allégé sur les
     vitres visibles (topbar comprise). L'aura est déjà statique partout. */
  body::before{--aura-blur:30px}
  .glass,.topbar{--glass-bd:saturate(1.5) blur(10px)}
  .topbar{-webkit-backdrop-filter:var(--glass-bd);backdrop-filter:var(--glass-bd)}
}
@media (max-width:480px){
  /* Liste boutique : rangées un peu plus compactes (le bouton reste ≥44px). */
  .store-row{padding:10px 12px;gap:12px}
  .agent-grid,.cfg-body{grid-template-columns:1fr}
  /* Cibles tactiles ≥44px (topbar + segmented control des réglages).
     G3a : à cette largeur le libellé des pilules nommées de l'en-tête chat est
     rabattu — elles redeviennent des carrés et PARTAGENT la règle des icônes,
     au lieu de reporter la même taille une seconde fois. Deux cibles de tailles
     différentes sur une même ligne se verraient au premier coup d'œil. */
  .iconbtn,.chat-head .navbtn{width:44px;height:44px;padding:0;justify-content:center}
  /* Quatre boutons dans l'en-tête du chat depuis l'accès direct au dossier :
     on resserre les écarts pour que le nom garde de la place avant l'ellipse. */
  .chat-head{gap:7px;padding:8px 4px}
  .langsw button{padding:8px 9px;min-height:44px;font-size:12px;white-space:nowrap}
  .set-seg-btn{flex:1;min-height:44px;text-align:center}
  .set-card{padding:18px 16px}
  /* Calendrier : cibles tactiles ≥44px, grille scrollable horizontalement. */
  .sched-act-btn{min-height:44px}
  .sched-day{min-height:46px}
  /* Cible 375px : la marque se réduit au monogramme (le lien garde aria-label
     « Yumi »), la topbar se resserre encore — brand + actions tiennent largement
     dans la pilule (aucun contrôle ne déborde ni ne wrappe : topbar.right ≤ vw). */
  .topbar{padding:0 5px 0 10px}
  .topbar-actions{gap:6px}
  .brand-name{display:none}
  .brand-gem{width:28px;height:28px}
  .navbtn{padding:8px 9px}
  .cfg-head{flex-wrap:wrap}
  .cfg-head-state{flex-direction:row;align-items:center}
  .cfg-danger-actions{flex-direction:column}
  .cfg-danger-actions .cta{width:100%;min-height:44px}
}

/* ---------- Page de configuration d'un assistant (roue dentee) ---------- */
/* La page n'est PLUS une colonne de 640px qui empile tout : elle prend la largeur
   de l'écran (comme la coquille, G1) et ce sont les CARTES qui sont bornées. */
.cfg{padding:8px 0 40px;display:flex;flex-direction:column;gap:16px}
.cfg-top{
  display:flex;align-items:center;gap:12px;padding:10px 14px;
  border-radius:var(--radius-lg);position:sticky;top:8px;z-index:2;
}
.cfg-top-title{font-size:16px;font-weight:700;letter-spacing:-.01em;flex:1}
/* Indicateur discret « Enregistré » (aucune interruption de flux) */
.cfg-saved{font-size:12.5px;font-weight:600;color:var(--muted);transition:color var(--dur) var(--ease)}
.cfg-saved[data-state="saved"]{color:var(--ok)}
.cfg-saved[data-state="error"]{color:var(--danger)}
/* Grille de cartes indépendantes : mêmes règles que la galerie d'assistants —
   `auto-fill` + piste BORNÉE (jamais `1fr`), donc la place en trop devient une
   colonne de plus, jamais une carte étirée. `align-items:start` : chaque carte
   garde sa hauteur naturelle (une carte dépliée n'étire pas ses voisines). */
.cfg-body{
  display:grid;gap:var(--card-gap);justify-content:start;align-items:start;
  grid-template-columns:repeat(auto-fill,minmax(var(--cfg-card-min),var(--cfg-card-max)));
}

/* En-tête : gemme + identité éditable + état */
/* Carte d'identité : elle vit dans la grille comme les autres, donc elle wrappe
   d'office (la gemme + le nom + l'état ne tiennent pas toujours sur une ligne). */
.cfg-head{display:flex;align-items:center;gap:14px;padding:18px 20px;flex-wrap:wrap}
.cfg-head-gem{flex:none}
.cfg-head-id{flex:1;min-width:0;display:flex;flex-direction:column;gap:4px}
.cfg-name{font-size:22px;font-weight:700;letter-spacing:-.01em;outline:none;border-radius:8px;padding:2px 8px;min-width:60px}
.cfg-desc{color:var(--muted);font-size:14.5px;outline:none;border-radius:8px;padding:2px 8px;min-width:120px}
.cfg-name:focus,.cfg-desc:focus{background:var(--accent-soft)}
.cfg-name:empty::before,.cfg-desc:empty::before{content:attr(data-ph);color:var(--muted);opacity:.6}
.cfg-head-state{display:flex;flex-direction:column;align-items:flex-end;gap:10px;flex:none}
.chip[data-chip="active"]{background:color-mix(in srgb,var(--ok) 14%,transparent);color:var(--ok)}

/* Sections (réutilisent .set-card) : sous-titres, pitch, sous-libellés */
.cfg-instr{width:100%;resize:vertical;min-height:120px}
.cfg-chips{justify-content:flex-start;margin-top:2px}
.cfg-regen.busy{opacity:.6;pointer-events:none}
.cfg-model-sub{font-size:12.5px;color:var(--muted);font-family:ui-monospace,SFMono-Regular,Menlo,monospace}
.cfg-subh{font-size:14px;font-weight:700;letter-spacing:-.01em;margin-top:6px}
.cfg-pitch{font-size:13.5px;color:var(--muted)}
.cfg-card-sub{font-size:13.5px;color:var(--muted)}
.cfg-cal-btn{align-self:flex-start}
.cfg-switch-row{display:flex;align-items:center;justify-content:space-between;gap:12px}
.cfg-switch-lbl{font-size:15px;color:var(--txt)}
/* ---- Carte de CAPACITÉ (motif unique de la page) --------------------------
   Une carte = [icône · libellé · interrupteur], et sous elle ses sous-items qui
   se déplient. Le dépliage anime `grid-template-rows` de 0fr à 1fr : la hauteur
   réelle du contenu n'a donc jamais à être écrite en dur, et la grille de la
   page se réorganise d'elle-même pendant que la carte grandit. Transition
   COURTE (`--dur`, la même que le reste de l'app) : fonctionnelle, pas décorative
   — `prefers-reduced-motion` la neutralise via la règle globale. */
.cfg-cap{padding:0;overflow:hidden}
.cfg-cap-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:16px 18px}
.cfg-cap-body{display:grid;grid-template-rows:0fr;transition:grid-template-rows var(--dur) var(--ease)}
.cfg-cap.open .cfg-cap-body{grid-template-rows:1fr}
.cfg-cap-inner{overflow:hidden;min-height:0}
.cfg-cap-pad{padding:0 18px 16px}
/* Ce que le serveur ne sait pas donner par item, la carte le DIT (jamais un faux
   interrupteur) : note discrète en bas des sous-items. */
.cfg-cap-note{font-size:12.5px;color:var(--muted);margin-top:8px}
/* Ses connexions : lignes [icône · label · toggle glissant] (réutilise .conn-ico
   / .conn-txt / .conn-sub + .sched-switch). */
.cfg-conn-list{display:flex;flex-direction:column;margin:8px 0 10px}
.cfg-conn-row{display:flex;align-items:center;justify-content:space-between;gap:12px;
  padding:10px 0;border-bottom:1px solid var(--glass-brd)}
.cfg-conn-row:last-child{border-bottom:0}
.cfg-conn-txt{display:flex;align-items:center;gap:10px;min-width:0;flex:1;color:var(--txt)}
.cfg-conn-empty{font-size:13.5px;color:var(--muted);padding:8px 0}
.cfg-conn-link{align-self:flex-start;margin-top:2px}
/* Son réseau (V4) : une ligne par autre assistant — en-tête [gemme · nom ·
   description] PUIS le sélecteur 3 positions en pleine largeur (en colonne, pour
   rester lisible sur un téléphone où 3 segments se partagent déjà la ligne).
   Réutilise .set-seg (pilule glissante) et .conn-txt / .conn-sub. */
.cfg-net-list{display:flex;flex-direction:column;margin:8px 0 10px}
.cfg-net-row{display:flex;flex-direction:column;gap:8px;padding:12px 0;
  border-bottom:1px solid var(--glass-brd)}
.cfg-net-row:last-child{border-bottom:0}
.cfg-net-row.off{opacity:.55}
.cfg-net-head{display:flex;align-items:center;gap:10px;min-width:0;color:var(--txt)}
.cfg-net-seg{width:100%}
/* Libellés plus compacts que le segmented des réglages (3 colonnes de texte, pas
   3 mots) + ellipse de sécurité : jamais de débordement hors de la vitre. Règle
   PARTAGÉE avec la carte de demande de lien du guard (.guard-net-seg, V7) : même
   contrainte d'étroitesse, une seule source de vérité. */
.cfg-net-seg .set-seg-btn,.guard-net-seg .set-seg-btn{padding:6px 8px;
  font-size:12.5px;min-width:0;overflow:hidden;text-overflow:ellipsis}
.cfg-net-note{font-size:12.5px;color:var(--muted)}
.cfg-net-sum,.cfg-skill-sum{font-size:13.5px;color:var(--muted)}
/* Ligne de réglage avec puce d'origine (« Ses compétences ») : réutilise
   .cfg-conn-list / .cfg-conn-row / .conn-*. Le libellé et la puce partagent la
   1re ligne et REPASSENT à la ligne plutôt que de pousser le toggle hors de la
   vitre (libellé long à 390 px). */
.cfg-row-head{display:flex;align-items:center;gap:6px;min-width:0;flex-wrap:wrap}
.cfg-row-tag{flex:none}
/* Bouton d'ajout aligné à gauche — partagé par « Ses boîtes mail » et « Son
   coffre » (+ le bouton « Copier » de la révélation du mot de passe maître). */
.cfg-mail-add,.cfg-vault-add{align-self:flex-start;margin-top:2px}
/* Mot de passe maître du coffre, montré UNE fois : lecture seule, en chasse fixe
   pour se relire/copier sans ambiguïté. */
.cfg-vault-master{font-family:"JetBrains Mono",ui-monospace,monospace;margin-bottom:8px}
/* Journal des accès (modale) : liste défilante réutilisant .cfg-conn-list. */
.cfg-audit-scroll{max-height:44vh;overflow-y:auto;margin:4px 0 0}
/* Réglage du mot de passe maître GLOBAL : section séparée sous la liste du coffre,
   état + boutons d'action (créer / refuser / déverrouiller) qui repassent à la ligne. */
.cfg-vault-sec{border-top:1px solid var(--glass-brd);margin-top:10px;padding-top:10px}
.cfg-vault-state{font-size:14px;color:var(--txt);margin:6px 0 0}
.cfg-vault-btns{display:flex;flex-wrap:wrap;gap:8px;margin-top:8px}
.cfg-tech-pre{
  margin-top:10px;padding:14px;border-radius:12px;font-size:12px;overflow-x:auto;
  background:var(--card2);border:1px solid var(--hairline);
  font-family:"JetBrains Mono",ui-monospace,monospace;white-space:pre-wrap;word-break:break-all;
}
.cfg-danger .set-card-title{color:var(--danger)}
.cfg-danger-actions{display:flex;gap:10px;flex-wrap:wrap}
