/*
 * La SDR Quest v2 (ECL-21) — les écrans.
 *
 * Cette feuille ne contient AUCUNE couleur, aucune police, aucun rayon, aucune
 * durée en dur : tout vient des tokens d'un thème (`public/css/quest-themes/`,
 * contrat dans `src/lib/quest-theme.js`, garde `check-quest-themes`). C'est ce
 * qui permet de livrer un autre métier avec une autre esthétique sans rouvrir
 * `public/js/pages/quest.js`.
 *
 * Trois règles tenues ligne par ligne :
 *  - aucun `!important` : tout se joue à la spécificité (`check-css`) ;
 *  - tout est jouable au doigt — cible minimale 44 px, glisser-déposer avec
 *    repli au clic, une seule colonne sous 900 px ;
 *  - `prefers-reduced-motion` neutralise TOUTES les transitions et animations
 *    ici, une fois pour toutes : un thème n'a pas à y penser.
 *
 * Le jaune `--q-ai` désigne les moments IA (le [AI] du logo, le juge, la
 * manager, l'action principale d'un écran). Il ne décore jamais.
 */

/* La display des titres de journée. Self-hostée : la CSP n'autorise aucune
   origine externe pour une police (src/lib/security-headers.js). */
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url('/fonts/bricolage-grotesque-latin-600-normal.woff2') format('woff2');
}
@font-face {
  font-family: 'Bricolage Grotesque';
  font-style: normal;
  font-weight: 800;
  font-display: swap;
  src: url('/fonts/bricolage-grotesque-latin-800-normal.woff2') format('woff2');
}

/* --- La scène ------------------------------------------------------------ */

.quest-v2 {
  position: relative;
  display: flex;
  flex-direction: column;
  gap: var(--q-gap);
  /* ECL-77 — la scene prend la FENETRE. Elle bordait a bord par une marge
     negative qui annulait le retrait lateral de `.main` ; la coquille etant
     repliee (`body[data-immersive]`, dashboard.css), `.main` n'a plus de
     retrait a annuler et la marge a disparu avec lui. Ce qui reste est plus
     simple et plus juste : la scene occupe la hauteur de la fenetre, fond du
     theme et trame de points d'un bord a l'autre.

     `dvh` plutot que `vh` : sur un telephone, la barre d'adresse se retracte
     et `100vh` depasse alors l'ecran — on gagnait un defilement de 60 px qui
     ne menait nulle part. */
  min-height: 100dvh;
  padding: var(--q-pad);
  /* Deux étages de fond : la TRAME du thème (scanlines, halo — `none` chez
     ceux qui n'en veulent pas) posée sur le dégradé de la scène. Une couche
     d'image ne tient pas dans un arrêt de dégradé, d'où un token à elle
     (`--q-bg-texture`, ECL-51) plutôt qu'une trame écrite ici, qui
     s'appliquerait aux trois thèmes. */
  background:
    var(--q-bg-texture),
    radial-gradient(120% 90% at 30% 0%, var(--q-bg-1) 0%, var(--q-bg-2) 55%, var(--q-bg-3) 100%);
  color: var(--q-text);
  font-family: var(--q-font-body);
}

/* Le décor du thème : purement décoratif, aucune information n'y vit.

   Il reste DERRIÈRE le contenu. Ce n'est pas un détail d'esthétique : sans
   `z-index`, le décor est le seul élément POSITIONNÉ de la carte, et l'ordre
   de peinture met les positionnés au-dessus des frères qui sont dans le flux
   — même déclaré en premier dans le DOM. Résultat vu en production : on lisait
   le texte du panneau à travers les colonnes, et le bouton « commencer lundi »
   était barré par elles. */
.q-decor {
  position: absolute;
  inset: auto 0 0;
  z-index: 0;
  height: 260px;
  background-position: bottom center;
  background-repeat: no-repeat;
  background-size: cover;
  opacity: 0.5;
  /* Et il ne capte aucun clic : ce qui ne porte pas d'information ne prend
     pas la main. */
  pointer-events: none;
}

.q-scene {
  position: relative;
  /* Le calque du décor appartient à CETTE carte : `isolation` en fait un
     contexte d'empilement, donc le décor ne peut ni remonter par-dessus le
     panneau de leçon ni glisser sous le fond de la scène. */
  isolation: isolate;
  overflow: hidden;
  border-radius: var(--q-radius);
}

/* Le contenu passe devant le décor — tout le contenu, y compris ce qu'un
   écran futur ajoutera : la règle vise « tout sauf le décor » plutôt que la
   liste des blocs d'aujourd'hui, qui serait fausse au premier ajout.
   `position: relative` sans décalage ne déplace rien ; il donne seulement le
   droit d'avoir un `z-index`. */
.q-scene > :not(.q-decor) {
  position: relative;
  z-index: 1;
}

.q-title {
  margin: 0;
  /* Une display de caractère peut être monospacée (la pixel d'`arcade`) : un
     mot long doit alors pouvoir se couper plutôt que sortir de la colonne. */
  overflow-wrap: break-word;
  font-family: var(--q-font-display);
  font-size: var(--q-display-size);
  font-weight: var(--q-display-weight);
  letter-spacing: var(--q-display-tracking);
  line-height: 1.1;
}

.q-lead { margin: 0; color: var(--q-text-muted); }
.q-dim { color: var(--q-text-dim); font-size: 0.85rem; }
.q-muted { color: var(--q-text-muted); }

/* --- La barre du haut ---------------------------------------------------- */

/* ECL-77 — UNE ligne, a toute largeur.
 *
 * Elle en faisait trois a 390 px (le logo, les jours, les compteurs) : la
 * barre etait une rangee qui se plie, donc sa mise en page dependait de la
 * longueur des libelles. Elle porte maintenant ce qui se COMMANDE — la
 * sortie, la langue, le theme, le son, la boite, le plein ecran — et ce qui
 * s'INFORME (les jours, les compteurs) est descendu d'une rangee
 * (`.q-status`). `flex-wrap: nowrap` est la promesse ; ce qui la tient, c'est
 * que chaque outil se resserre sous 900 px (`.q-bar-label`, `.q-logo`). */
.q-top {
  display: flex;
  flex-wrap: nowrap;
  gap: var(--q-gap-sm);
  align-items: center;
  padding: var(--q-pad-sm) var(--q-pad);
  border: var(--q-border-width) solid var(--q-border);
  border-radius: var(--q-radius);
  background: var(--q-surface);
}

/* Les outils, colles a droite. Rien ici ne les laisse se serrer (voir la
   regle suivante) : c'est le smoke qui mesure qu'ils tiennent, a 390 px et
   a 901 px — juste au-dessus du point ou les libelles reviennent — dans la
   locale la plus longue (es). */
.q-top-tools {
  display: flex;
  flex-wrap: nowrap;
  gap: var(--q-gap-sm);
  align-items: center;
  margin-left: auto;
}

/* Aucun outil ne se resserre : un bouton rogne n'est pas plus lisible qu'un
   bouton absent, et un selecteur de langue qui coupe « Francais » est
   justement la panne du 11/09. Ce qui tient la ligne, ce sont les
   resserrements DECIDES du bloc mobile, pas un ecrasement subi. */
.q-top > *,
.q-top-tools > * { flex: 0 0 auto; }

.q-bar-glyph { font-size: 1rem; line-height: 1; }
.q-bar-label { white-space: nowrap; }

/* Une invitation, pas une injonction : le plein ecran se PROPOSE tant que le
   joueur n'a pas repondu (ECL-77). Il a dit oui ou non une fois — dans un sens
   ou dans l'autre — et le bouton redevient un bouton. */
.q-fullscreen[data-suggest='true'] { border-color: var(--q-ai-ink); color: var(--q-ai-ink); }

/* Le selecteur de langue de la coquille, peau du theme : la meme liste, au
   meme endroit, sans quitter le jeu. */
.q-select {
  min-height: 36px;
  max-width: 100%;
  padding: 0 var(--q-gap-sm);
  border: var(--q-border-width) solid var(--q-border);
  border-radius: var(--q-radius-sm);
  background: var(--q-surface-2);
  color: var(--q-text);
  font-family: inherit;
  font-size: 0.8rem;
  cursor: pointer;
}

.q-select:focus-visible { border-color: var(--q-ai-ink); outline: none; }

/* La ligne d'etat : les cinq jours, et ce qu'on a gagne. Elle, elle a le
   droit de se plier — ce sont deux informations, pas deux commandes. */
.q-status {
  display: flex;
  flex-wrap: wrap;
  gap: var(--q-gap-sm);
  align-items: center;
  justify-content: space-between;
}

/* La marque porte une PASTILLE quand son thème en a besoin.
   ADR-0004 réserve le jaune au `[AI]` ; sur un thème dont la page EST jaune
   (direction C), le `[AI]` ne se voit plus. Le fond de la pastille et l'encre
   du reste du mot sont donc des tokens : `transparent` et la couleur du texte
   chez les thèmes sombres — rien ne bouge — un aplat navy à texte blanc ici. */
.q-logo {
  padding: 2px var(--q-gap-sm);
  border-radius: var(--q-radius-sm);
  background: var(--q-brand-bg);
  box-shadow: var(--q-shadow-sm);
  color: var(--q-brand-ink);
  font-family: var(--q-font-display);
  font-size: 1.15rem;
  font-weight: var(--q-display-weight);
  letter-spacing: var(--q-display-tracking);
}

/* Le seul endroit où le jaune touche le logo : le [AI]. Et c'est le jaune
   BRUT — celui qui remplit — parce que c'est la marque, pas un accent. */
.q-logo-ai { color: var(--q-ai); }

.q-days {
  display: flex;
  flex: 1 1 260px;
  gap: var(--q-gap-sm);
  /* `min-width: 0` : sans lui, une piste qui deborde POUSSE ses voisins hors
     de l'ecran au lieu de defiler dans son propre cadre. */
  min-width: 0;
  overflow-x: auto;
  padding-bottom: 2px;
}

.q-day {
  display: inline-flex;
  flex: 0 0 auto;
  gap: var(--q-gap-sm);
  align-items: center;
  min-height: 44px;
  padding: 0 var(--q-pad-sm);
  border: var(--q-border-width) solid var(--q-border);
  border-radius: var(--q-radius-pill);
  background: var(--q-surface);
  box-shadow: var(--q-shadow-sm);
  color: var(--q-text-muted);
  /* Les jours sont une ENSEIGNE : ils portent la display du thème. */
  font-family: var(--q-font-display);
  font-size: 0.85rem;
  font-weight: 500;
  cursor: pointer;
  transition: border-color var(--q-motion-fast) var(--q-ease), color var(--q-motion-fast) var(--q-ease);
}

.q-day:hover { border-color: var(--q-border-strong); }
/* Un jour verrouillé se dit par son TRAIT, pas seulement par son gris :
   pointillé, on voit qu'il n'est pas encore là. */
.q-day[disabled] { cursor: not-allowed; opacity: 0.6; border-style: dashed; box-shadow: none; }
.q-day[data-state='done'] { border-color: var(--q-good); color: var(--q-good); }

/* Le jour EN COURS porte la pastille de l'actif : un aplat et son encre chez
   un thème qui en a une, la bordure et le halo chez les autres (leur
   `--q-on-bg` vaut `transparent` et leur `--q-on-ink` l'accent). */
.q-day[data-state='current'] {
  border-color: var(--q-on-ink);
  background: var(--q-on-bg);
  box-shadow: var(--q-glow);
  color: var(--q-on-ink);
  font-weight: 700;
}

.q-day-score { font-variant-numeric: tabular-nums; }

.q-scores {
  display: flex;
  flex-wrap: wrap;
  gap: var(--q-gap);
  align-items: center;
  justify-content: flex-end;
}

/* Un COMPTEUR (ECL-51) : le temps gagne, le total de la partie, le total de
   la semaine. Il se lit de loin — donc il porte la display du theme, comme le
   chiffre du bilan — et il ROULE quand il monte : un total qui saute de 3 a 6
   entre deux rendus ne se voit pas.

   L'etoile est un GLYPHE separe : une display de caractere (la pixel
   d'`arcade`) ne la porte pas, et le nombre qui roule reste un nombre. */
.q-score {
  display: inline-flex;
  gap: 6px;
  align-items: baseline;
  color: var(--q-ai-ink);
  font-weight: 700;
}

.q-score-value {
  font-family: var(--q-font-display);
  font-weight: var(--q-display-weight);
  letter-spacing: var(--q-display-tracking);
  /* Des chiffres de meme chasse : sinon le compteur SAUTE a chaque image, et
     ce qui devait se lire devient un tremblement. */
  font-variant-numeric: tabular-nums;
}

.q-stars { display: inline-flex; gap: 2px; }
.q-star { color: var(--q-border-strong); font-size: 1.05rem; line-height: 1; }
.q-star[data-filled='true'] { color: var(--q-ai-ink); }

/* Une etoile qui s'allume le dit d'un a-coup, une seule fois : `data-lit` est
   pose au CHANGEMENT, pas a chaque image. */
.q-star[data-lit='true'] { animation: q-star-pop var(--q-motion-fast) var(--q-ease) both; }

@keyframes q-star-pop {
  from { transform: scale(0.55); }
  60% { transform: scale(1.3); }
  to { transform: none; }
}

/* Au bilan, les etoiles et le total de la semaine sur une ligne : ils disent
   la meme chose et se lisent ensemble. */
.q-score-line { align-items: baseline; }
.q-score-total { color: var(--q-text-muted); font-weight: 600; }

/* --- La colonne de gauche et la scène ------------------------------------ */

.q-body {
  display: grid;
  grid-template-columns: minmax(240px, 300px) minmax(0, 1fr) minmax(220px, 280px);
  gap: var(--q-gap);
  align-items: start;
}

.q-body[data-columns='2'] { grid-template-columns: minmax(240px, 300px) minmax(0, 1fr); }

.q-col { display: flex; flex-direction: column; gap: var(--q-gap); }

/* --- Mardi : le PLATEAU (ECL-51) ------------------------------------------
 *
 * Le jour se jouait en colonne : le titre, la narration, la consigne, puis la
 * matrice — a 1280x720 la premiere case tombait a 1352 px du haut. On devait
 * faire defiler ENTRE la carte qu'on prend et la case ou on la pose, et le
 * glisser a la souris ne tenait pas (ECL-43 l'avait vu rouge et avait sorti
 * la pioche a cote ; le vrai remede etait ici).
 *
 * La consigne ne passe plus au-dessus du plateau, elle passe A COTE. Le reste
 * — le pipeline, la manager, le rituel, « ton bureau » — tient sur une ligne
 * SOUS le pli : rien du geste ne demande de defiler, et ce qui s'y trouve
 * s'atteint en defilant, apres.
 *
 * `align-items: start` (herite de `.q-body`) fait que la hauteur de la
 * consigne ne pousse jamais la matrice vers le bas : la ligne s'allonge, le
 * plateau reste en haut. Et quand le joueur PREND une carte, la consigne se
 * replie (ECL-43) : la ligne se resserre et « ton bureau » remonte.
 */
.q-under {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
  gap: var(--q-gap);
  align-items: start;
}

@media (min-width: 901px) {
  .q-body[data-layout='board'] {
    /* La pioche se resserre et la consigne tient sa largeur de lecture : ce
       qui reste va au plateau, qui gagne au passage ~40 px sur la mise en
       page d'avant (la matrice vivait dans la colonne du milieu). */
    grid-template-columns: minmax(260px, 300px) minmax(0, 1fr) minmax(210px, 250px);
    grid-template-areas:
      'title title title'
      'brief board hand'
      'under under under';
  }

  /* La matrice se resserre sur le plateau : quatre cases de 150 px debordaient
     de 80 px sous le titre du jour. 104 px tiennent ce qu'une case VIDE doit
     montrer — son etiquette et, des qu'une carte est prise, le bouton
     « deposer ici » (36 px de cible, ses marges) — et une case qui recoit une
     carte grandit d'elle-meme, apres le geste. Sous 900 px la regle mobile
     reprend la main (120 px, une seule colonne). */
  .q-body[data-layout='board'] .q-matrix { grid-auto-rows: minmax(104px, auto); }

  .q-board-title { grid-area: title; }
  .q-board-head { grid-area: brief; }
  .q-board-plate { grid-area: board; }
  .q-board-hand { grid-area: hand; }
  .q-body[data-layout='board'] .q-under { grid-area: under; }

  /* La pioche montre la description ENTIERE d'une carte (ECL-81) : c'est le
     RAIL qui borne la hauteur du plateau, pas le texte qu'on coupe. */
  .q-body[data-layout='board'] .q-hand-rail { max-height: 30vh; overflow-y: auto; }
}

.q-card {
  display: flex;
  flex-direction: column;
  gap: var(--q-gap-sm);
  padding: var(--q-pad);
  border: var(--q-border-width) solid var(--q-border);
  border-radius: var(--q-radius);
  background: var(--q-surface);
  box-shadow: var(--q-shadow);
}

.q-card-title {
  margin: 0;
  font-family: var(--q-font-title);
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: var(--q-display-tracking);
}

/* --- Le pipeline --------------------------------------------------------- */

.q-pipe-row { display: flex; flex-direction: column; gap: 4px; }

.q-pipe-head {
  display: flex;
  justify-content: space-between;
  font-size: 0.85rem;
}

.q-pipe-value { font-weight: 700; font-variant-numeric: tabular-nums; }
/* La barre porte le TRAIT du theme : sur la direction C, un pipeline est une
   jauge decoupee, pas un filet. */
.q-pipe-track {
  height: 10px;
  border: var(--q-border-width) solid var(--q-border);
  border-radius: var(--q-radius-pill);
  background: var(--q-surface-2);
}

.q-pipe-fill {
  width: 0;
  height: 100%;
  border-radius: var(--q-radius-pill);
  background: var(--q-primary);
  transition: width var(--q-motion-slow) var(--q-ease);
}

.q-pipe-row[data-kind='meetings'] .q-pipe-fill { background: var(--q-good); }
.q-pipe-row[data-kind='oppositions'] .q-pipe-fill { background: var(--q-bad); }
.q-pipe-row[data-kind='oppositions'] .q-pipe-value { color: var(--q-bad-ink); }
.q-pipe-row[data-kind='meetings'] .q-pipe-value { color: var(--q-good); }

/* --- La manager et les collègues ----------------------------------------- */

.q-person { display: flex; gap: var(--q-gap-sm); align-items: flex-start; }

.q-portrait {
  flex: 0 0 auto;
  width: 64px;
  height: 64px;
  border: var(--q-border-width) solid var(--q-border-strong);
  border-radius: var(--q-radius-sm);
}

.q-person-body { display: flex; flex-direction: column; gap: 4px; min-width: 0; }
.q-person-name { font-weight: 700; }
.q-person-role { color: var(--q-text-dim); font-size: 0.8rem; }

.q-quote {
  margin: 0;
  padding-left: var(--q-pad-sm);
  border-left: 3px solid var(--q-ai-ink);
  color: var(--q-text-muted);
  font-size: 0.9rem;
}

/* --- Boutons ------------------------------------------------------------- */

.q-btn {
  display: inline-flex;
  gap: var(--q-gap-sm);
  align-items: center;
  justify-content: center;
  min-height: 44px;
  padding: 0 var(--q-pad);
  border: var(--q-border-width) solid var(--q-border-strong);
  border-radius: var(--q-radius-pill);
  background: transparent;
  color: var(--q-text);
  box-shadow: var(--q-shadow-sm);
  font: inherit;
  font-weight: 600;
  text-align: center;
  cursor: pointer;
  transition: transform var(--q-motion-fast) var(--q-ease), border-color var(--q-motion-fast) var(--q-ease);
}

.q-btn:hover { border-color: var(--q-ai-ink); }
.q-btn:active { transform: translateY(1px); }
/* Un bouton `aria-disabled` se PEINT comme un bouton grisé, mais il reçoit le
   clic : c'est ce qui lui permet de répéter sa raison (ECL-81, mardi). */
.q-btn[disabled],
.q-btn[aria-disabled='true'] { cursor: not-allowed; opacity: 0.45; }

/* La raison sous « Valider » : pourquoi il ne part pas encore. */
.q-blocker { flex: 1 1 100%; margin: 0; color: var(--q-text-muted); font-size: 0.8rem; }

/* L'action principale d'un écran est un moment IA : elle porte le jaune —
   celui qui REMPLIT. Ce qui s'écrit dessus est un token à lui : sur un thème
   dont la page est déjà jaune, le fond de page ne peut pas servir d'encre. */
.q-btn-main {
  border-color: var(--q-ai-ink);
  background: var(--q-ai);
  color: var(--q-ai-on);
}

.q-btn-main:hover { box-shadow: var(--q-glow); }

.q-btn-ghost { border-color: var(--q-border); color: var(--q-text-muted); }
/* ECL-59 : `aria-pressed` porte l'ETAT de la bascule du son — enfoncee = le
   son est allume. La peau ne rend visible que le contraire, le son COUPE (le
   defaut) : le trait du theme en pointilles, comme un jour verrouille. Aucune
   couleur posee ici. */
.q-btn-ghost[aria-pressed='false'] { border-style: dashed; }
.q-btn-sm { min-height: 36px; padding: 0 var(--q-pad-sm); font-size: 0.8rem; font-weight: 500; }
.q-actions { display: flex; flex-wrap: wrap; gap: var(--q-gap-sm); align-items: center; }
/* Trois chronos sur une ligne : « avant », « apres », « fois par semaine » se
   lisent ensemble ou ne se lisent pas. */
.q-actions .q-field { flex: 1 1 130px; }

/* --- L'intro (ECL-78), jouée avant « Commencer » -------------------------- */
.q-intro { display: flex; flex-direction: column; gap: var(--q-gap-sm); margin: var(--q-gap-sm) 0; }
.q-intro-video {
  width: 100%;
  max-width: 640px;
  border-radius: var(--q-radius);
  border: var(--q-border-width) solid var(--q-border);
}

/* --- Lundi : les trois collègues ----------------------------------------- */

.q-people {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(230px, 1fr));
  gap: var(--q-gap);
}

.q-people .q-card { height: 100%; }
.q-card[data-chosen='true'] { border-color: var(--q-good); }

/* --- Mardi : la matrice -------------------------------------------------- */

.q-matrix-wrap { display: flex; gap: var(--q-gap-sm); }

.q-axis-y {
  display: flex;
  flex: 0 0 auto;
  align-items: center;
  justify-content: center;
  color: var(--q-text-dim);
  font-size: 0.75rem;
  writing-mode: vertical-rl;
  transform: rotate(180deg);
}

.q-matrix {
  display: grid;
  flex: 1 1 auto;
  grid-template-columns: 1fr 1fr;
  grid-auto-rows: minmax(150px, auto);
  gap: var(--q-gap-sm);
}

.q-cell {
  display: flex;
  flex-direction: column;
  gap: var(--q-gap-sm);
  padding: var(--q-pad-sm);
  border: var(--q-border-width) dashed var(--q-border);
  border-radius: var(--q-radius-sm);
  background: var(--q-surface);
  transition: border-color var(--q-motion-fast) var(--q-ease), background var(--q-motion-fast) var(--q-ease);
}

.q-cell[data-over='true'],
.q-cell[data-open='true'] {
  border-color: var(--q-ai-ink);
  border-style: solid;
  background: var(--q-ai-soft);
}

/* La case qui LANCE, tant qu'elle n'a pas ses trois cartes (ECL-81). Le
   liseré est une OMBRE, pas une bordure : la bordure change quand une carte
   est prise (`data-open`), et la case qui décide ne doit pas se perdre à ce
   moment-là — c'est justement le moment où l'on cherche où poser. */
.q-cell[data-launch='true'] { border-style: solid; box-shadow: var(--q-glow); }

.q-cell-label { color: var(--q-text-dim); font-size: 0.72rem; text-transform: uppercase; }
.q-cell-launch {
  color: var(--q-ai-ink);
  font-size: 0.68rem;
  font-weight: 600;
  /* Serre : le libellé s'ajoute DANS la case, et le plateau tient à
     1280x720 au pixel près (mesuré par le smoke d'ECL-51). */
  line-height: 1.2;
}
.q-axis-x { color: var(--q-text-dim); font-size: 0.75rem; text-align: center; }

.q-hand {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(220px, 1fr));
  gap: var(--q-gap-sm);
  align-items: start;
  padding-top: var(--q-gap-sm);
  border-top: var(--q-border-width) solid var(--q-border);
}

.q-hand > .q-label { grid-column: 1 / -1; }

.q-tile {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-height: 44px;
  padding: var(--q-pad-sm);
  border: var(--q-border-width) solid var(--q-border-strong);
  border-radius: var(--q-radius-sm);
  background: var(--q-surface-2);
  color: var(--q-text);
  font: inherit;
  text-align: left;
  cursor: grab;
  transition: transform var(--q-motion-fast) var(--q-ease), border-color var(--q-motion-fast) var(--q-ease);
}

.q-tile:hover { border-color: var(--q-ai-ink); }
.q-tile[data-picked='true'] { border-color: var(--q-ai-ink); box-shadow: var(--q-glow); }
/* Une carte POSÉE prend la surface de l'état « rangé » — un lavis chez les
   thèmes sombres, un aplat sur la direction C — et son encre avec. Elle
   s'incline un peu : `--q-tilt` vaut `0deg` quand un thème ne joue pas à ça,
   et une case sur deux penche de l'autre côté pour que ça reste un tas de
   cartes et pas un motif. */
.q-tile[data-placed='true'] {
  border-color: var(--q-primary);
  background: var(--q-primary-soft);
  box-shadow: var(--q-shadow-sm);
  color: var(--q-primary-ink);
  transform: rotate(var(--q-tilt));
  cursor: pointer;
}

.q-cell:nth-child(even) .q-tile[data-placed='true'] { transform: rotate(calc(-1 * var(--q-tilt))); }

/* Sur un thème dont la surface « rangée » est un APLAT, la note de la carte et
   son « retirer » ne peuvent plus emprunter la couleur de texte faible du
   thème — bleu pâle sur bleu plein ne se lit pas. Ils suivent l'encre de la
   surface, en retrait. */
.q-tile[data-placed='true'] .q-tile-note { color: inherit; opacity: 0.78; }
.q-tile[data-trap='revealed'] { border-color: var(--q-bad); }
.q-tile-title { font-weight: 600; font-size: 0.85rem; }
.q-tile-head { display: flex; flex-wrap: wrap; gap: var(--q-gap-sm); align-items: baseline; }

/* La FAMILLE d'un bloc du jeudi (ECL-81) : une information, sur les neuf
   blocs ou sur aucun. Pastille neutre — elle nomme, elle ne recommande pas. */
.q-tile-kind {
  padding: 1px var(--q-pad-sm);
  border: var(--q-border-width) solid var(--q-border-strong);
  border-radius: var(--q-radius-pill);
  color: var(--q-text-muted);
  font-size: 0.68rem;
  white-space: nowrap;
}
/* Sur l'établi (surface « rangée » en APLAT), même règle que la note : la
   pastille suit l'encre de la surface — gris faible sur bleu plein ne se lit
   pas (relecture ECL-81, mesuré ≈ 1,5:1 sur arcade). */
.q-tile[data-placed='true'] .q-tile-kind { color: inherit; border-color: currentcolor; opacity: 0.78; }

/* La description d'un cas d'usage est un PARAGRAPHE dans le scenario.
   Elle se lisait sur TROIS lignes, le reste dans un `title` natif : invisible
   au doigt, une infobulle grise a la souris (capture 3 du 19/09). Dans la
   pioche, elle se lit ENTIERE — c'est le rail qui defile qui borne la
   hauteur. POSEE dans une case, la carte n'en montre qu'une ligne, et
   « lire » deplie le reste SUR PLACE : la matrice reste une matrice, et rien
   n'est hors de portee. */
.q-tile-note { margin: 0; color: var(--q-text-dim); font-size: 0.72rem; }

.q-tile-note[data-open='false'] {
  display: -webkit-box;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 1;
  line-clamp: 1;
}

.q-tile-acts { display: flex; flex-wrap: wrap; gap: var(--q-gap-sm); align-items: center; }

/* Deux commandes sur une carte posee — « lire », « retirer ». Des LIENS, pas
   des boutons pleins : dans une case de matrice, deux pastilles de 44 px
   chasseraient le texte qu'on vient de rendre lisible. Meme patron que
   `.q-lesson-link`. */
.q-tile-link {
  padding: 4px 0;
  border: 0;
  border-bottom: 1px dashed currentcolor;
  background: transparent;
  color: inherit;
  font: inherit;
  font-size: 0.72rem;
  cursor: pointer;
}

.q-tile-link:hover { border-bottom-style: solid; }

.q-alert {
  padding: var(--q-pad-sm);
  border: var(--q-border-width) solid var(--q-bad);
  border-radius: var(--q-radius-sm);
  color: var(--q-bad-ink);
  font-size: 0.85rem;
}

.q-ok {
  padding: var(--q-pad-sm);
  border: var(--q-border-width) solid var(--q-good);
  border-radius: var(--q-radius-sm);
  color: var(--q-good);
  font-size: 0.85rem;
}

/* --- Mercredi : le Prompt Lab -------------------------------------------- */

.q-split {
  display: grid;
  grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
  gap: var(--q-gap);
  align-items: start;
}

.q-field { display: flex; flex-direction: column; gap: 4px; }
.q-pillars { display: grid; grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); gap: var(--q-gap); }
.q-label { color: var(--q-text-muted); font-size: 0.78rem; }

.q-input,
.q-textarea {
  width: 100%;
  min-height: 44px;
  padding: var(--q-pad-sm);
  border: var(--q-border-width) solid var(--q-border-strong);
  border-radius: var(--q-radius-sm);
  background: var(--q-surface-2);
  color: var(--q-text);
  font: inherit;
}

.q-textarea { min-height: 180px; resize: vertical; }
.q-input:focus-visible,
.q-textarea:focus-visible { border-color: var(--q-ai-ink); outline: none; }

.q-example { border-left: 3px solid var(--q-ai-ink); padding-left: var(--q-pad-sm); }
.q-example-text { margin: 0; font-size: 0.92rem; line-height: 1.55; }
.q-note-quote { color: var(--q-ai-ink); font-weight: 600; }
.q-note-why { color: var(--q-text-muted); }

.q-annotated { display: flex; flex-direction: column; gap: 6px; }
.q-annot { font-size: 0.82rem; }

.q-verdict-text {
  margin: 0;
  padding: var(--q-pad-sm);
  border: var(--q-border-width) solid var(--q-border);
  border-radius: var(--q-radius-sm);
  background: var(--q-surface-2);
  font-size: 0.9rem;
  line-height: 1.6;
  white-space: pre-wrap;
}

/* La citation du juge, surlignée DANS le texte : c'est ça, « attaquer ». */
.q-fault {
  border-bottom: 2px solid var(--q-bad);
  background: var(--q-ai-soft);
  color: var(--q-text);
}

.q-fault-list { display: flex; flex-direction: column; gap: var(--q-gap-sm); margin: 0; padding: 0; list-style: none; }

.q-fault-item {
  padding-left: var(--q-pad-sm);
  border-left: 3px solid var(--q-bad);
  font-size: 0.85rem;
}

.q-fault-item[data-severity='minor'] { border-left-color: var(--q-warn); }
.q-fault-kind { color: var(--q-bad-ink); font-weight: 600; }
.q-fact { display: flex; flex-direction: column; gap: 2px; padding: var(--q-pad-sm) 0; }
.q-fact + .q-fact { border-top: 1px solid var(--q-border); }
.q-fact[data-planted='true'] { border-left: 3px solid var(--q-bad); padding-left: var(--q-pad-sm); }
.q-fact-source { color: var(--q-text-dim); font-size: 0.75rem; word-break: break-all; }

.q-pii {
  padding: var(--q-pad-sm);
  border: 1px dashed var(--q-warn);
  border-radius: var(--q-radius-sm);
  color: var(--q-warn);
  font-size: 0.78rem;
}

/* --- Jeudi : l'établi et la trace ---------------------------------------- */

.q-bench {
  display: flex;
  flex-direction: column;
  gap: var(--q-gap-sm);
  min-height: 180px;
  padding: var(--q-pad-sm);
  border: 1px dashed var(--q-border);
  border-radius: var(--q-radius-sm);
}

.q-bench[data-over='true'] { border-color: var(--q-ai-ink); border-style: solid; background: var(--q-ai-soft); }
.q-bench-empty { color: var(--q-text-dim); font-size: 0.85rem; text-align: center; }

.q-slot { display: flex; gap: var(--q-gap-sm); align-items: center; }
.q-slot-arrow { color: var(--q-text-dim); }
.q-slot .q-tile { flex: 1 1 auto; }

.q-budget { display: flex; flex-direction: column; gap: 4px; }
.q-budget-track { height: 10px; border-radius: var(--q-radius-pill); background: var(--q-surface-2); }
.q-budget-fill { width: 0; height: 100%; border-radius: var(--q-radius-pill); background: var(--q-primary); transition: width var(--q-motion-slow) var(--q-ease); }
.q-budget[data-over='true'] .q-budget-fill { background: var(--q-bad); }
.q-budget[data-over='true'] .q-budget-value { color: var(--q-bad-ink); }
.q-budget-value { font-weight: 700; font-variant-numeric: tabular-nums; }

.q-trace {
  display: flex;
  flex-direction: column;
  gap: 2px;
  max-height: 340px;
  overflow-y: auto;
  padding: var(--q-pad-sm);
  border: var(--q-border-width) solid var(--q-border);
  border-radius: var(--q-radius-sm);
  background: var(--q-bg-3);
  font-family: ui-monospace, 'SFMono-Regular', 'Menlo', 'Consolas', monospace;
  font-size: 0.78rem;
}

.q-trace-line { display: flex; gap: var(--q-gap-sm); padding: 2px 0; color: var(--q-text-muted); }
.q-trace-line[data-status='stopped'] { color: var(--q-warn); }
.q-trace-line[data-status='skipped'] { color: var(--q-text-dim); }
.q-trace-line[data-kind='silent'] { color: var(--q-bad-ink); }
.q-trace-line[data-kind='caught'] { color: var(--q-good); }
.q-trace-i { flex: 0 0 2.4em; color: var(--q-text-dim); text-align: right; }

.q-anim-line { animation: q-line var(--q-motion-slow) var(--q-ease) both; }

@keyframes q-line {
  from { opacity: 0; transform: translateX(-6px); }
  to { opacity: 1; transform: none; }
}

/* --- Vendredi : le bilan ------------------------------------------------- */

.q-kpis { display: grid; grid-template-columns: repeat(auto-fit, minmax(160px, 1fr)); gap: var(--q-gap); }
.q-kpi { display: flex; flex-direction: column; gap: 2px; }
/* Le chiffre du bilan est un compteur de MARQUISE : il suit la display du
   thème, et sa taille en DÉCOULE (`--q-display-size`) au lieu d'être fixée
   ici — une pixel monospacée à 2,2 rem sortait de sa tuile de 160 px. */
.q-kpi-value {
  font-family: var(--q-font-display);
  font-size: calc(var(--q-display-size) * 1.1);
  font-weight: var(--q-display-weight);
  line-height: 1.1;
  overflow-wrap: break-word;
}
.q-kpi[data-tone='good'] .q-kpi-value { color: var(--q-good); }
.q-kpi[data-tone='ai'] .q-kpi-value { color: var(--q-ai-ink); }
.q-kpi[data-tone='bad'] .q-kpi-value { color: var(--q-bad-ink); }
.q-kpi-label { font-weight: 600; font-size: 0.85rem; }
.q-chart { width: 100%; height: auto; }
.q-badges { display: flex; flex-wrap: wrap; gap: var(--q-gap-sm); }

.q-badge {
  padding: 4px var(--q-pad-sm);
  border: var(--q-border-width) solid var(--q-ai-ink);
  border-radius: var(--q-radius-pill);
  box-shadow: var(--q-shadow-sm);
  color: var(--q-ai-ink);
  font-size: 0.75rem;
}

.q-rank { display: flex; flex-direction: column; gap: 4px; margin: 0; padding: 0; list-style: none; }
.q-rank-row { display: flex; gap: var(--q-gap-sm); align-items: baseline; font-size: 0.85rem; }
.q-rank-row[data-me='true'] { color: var(--q-ai-ink); font-weight: 700; }
.q-rank-n { flex: 0 0 1.6em; color: var(--q-text-dim); }
.q-rank-name { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.q-rank-score { font-variant-numeric: tabular-nums; }

/* --- Le questionnaire ---------------------------------------------------- */

.q-quiz { display: flex; flex-direction: column; gap: var(--q-gap); }
.q-quiz-options { display: flex; flex-direction: column; gap: var(--q-gap-sm); }

.q-option {
  min-height: 44px;
  padding: var(--q-pad-sm);
  border: var(--q-border-width) solid var(--q-border);
  border-radius: var(--q-radius-sm);
  background: var(--q-surface-2);
  color: var(--q-text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.q-option[aria-pressed='true'] { border-color: var(--q-ai-ink); background: var(--q-ai-soft); }
.q-option[data-verdict='right'] { border-color: var(--q-good); }
.q-option[data-verdict='wrong'] { border-color: var(--q-bad); }

/* --- Le panneau de leçon (exigence 4 : un clic, sans quitter la partie) --- */

.q-panel {
  position: fixed;
  inset: 0 0 0 auto;
  z-index: 40;
  display: flex;
  flex-direction: column;
  gap: var(--q-gap-sm);
  width: min(480px, 100%);
  overflow-y: auto;
  padding: var(--q-pad);
  border-left: var(--q-border-width) solid var(--q-border-strong);
  background: var(--q-bg-2);
  box-shadow: var(--q-shadow);
  animation: q-slide var(--q-motion-fast) var(--q-ease) both;
}

@keyframes q-slide {
  from { transform: translateX(24px); opacity: 0; }
  to { transform: none; opacity: 1; }
}

.q-panel-head { display: flex; gap: var(--q-gap-sm); align-items: center; justify-content: space-between; }
.q-panel-body { display: flex; flex-direction: column; gap: var(--q-gap-sm); font-size: 0.9rem; line-height: 1.6; }
.q-panel-body h3 { margin: var(--q-gap-sm) 0 0; font-family: var(--q-font-title); font-size: 1rem; }
.q-panel-body ul { margin: 0; padding-left: 1.2em; }

.q-lesson-link {
  align-self: flex-start;
  padding: 2px 0;
  border: 0;
  border-bottom: 1px dashed var(--q-ai-ink);
  background: transparent;
  color: var(--q-ai-ink);
  font: inherit;
  font-size: 0.8rem;
  cursor: pointer;
}

/* --- Le rituel ----------------------------------------------------------- */

.q-weeks { display: flex; flex-wrap: wrap; gap: var(--q-gap-sm); }

.q-week {
  display: flex;
  flex-direction: column;
  gap: 2px;
  min-width: 160px;
  min-height: 44px;
  padding: var(--q-pad-sm);
  border: var(--q-border-width) solid var(--q-border);
  border-radius: var(--q-radius-sm);
  background: transparent;
  color: var(--q-text);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.q-week[data-state='done'] { border-color: var(--q-good); }
.q-week[data-state='current'] { border-color: var(--q-on-ink); background: var(--q-on-bg); color: var(--q-on-ink); box-shadow: var(--q-glow); }
.q-week[disabled] { cursor: not-allowed; opacity: 0.55; }

/* --- ECL-80 : le message recu — il ARRIVE, il ne trone pas ---------------
 *
 * La carte « Ta manager » etait un meuble : portrait, role, replique et
 * lecteur audio, sur tous les ecrans, des l'accueil. Ce qui la remplace tient
 * en deux pieces : une NOTIFICATION (coin haut droit, sous la barre) et UNE
 * fenetre de message — un DM ou un vocal, jamais les deux.
 *
 * Aucune couleur ici : uniquement les jetons du theme (check-quest-themes).
 */

/* Posee dans le FLUX, juste sous la barre du haut — ni `fixed` (elle mordait
   la barre de la coquille, la panne du 11/09), ni `absolute` a un multiple de
   `--q-pad` (elle recouvrait la boite et le son sur `marche`, et la barre
   entiere quand elle se plie sur trois lignes au telephone — relecture
   ECL-80). Dans le flux, elle ne recouvre rien, sur aucun theme, a aucune
   largeur : elle pousse. */
.q-notif {
  display: flex;
  justify-content: flex-end;
  margin-top: var(--q-gap-sm);
}

.q-notif-card {
  display: flex;
  gap: var(--q-gap-sm);
  align-items: center;
  width: min(320px, 100%);
  min-height: 44px;
  padding: var(--q-pad-sm);
  border: var(--q-border-width) solid var(--q-border-strong);
  border-radius: var(--q-radius);
  background: var(--q-surface-2);
  color: var(--q-text);
  font: inherit;
  text-align: left;
  box-shadow: var(--q-shadow);
  cursor: pointer;
  animation: q-drop var(--q-motion-fast) var(--q-ease) both;
}

.q-notif-card:hover { border-color: var(--q-ai-ink); }
.q-notif-card .q-portrait { width: 40px; height: 40px; }
.q-notif-body { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.q-notif-dim { color: var(--q-text-muted); font-size: 0.8rem; }

.q-notif-dot {
  flex: 0 0 auto;
  width: 10px;
  height: 10px;
  margin-left: auto;
  border-radius: 50%;
  background: var(--q-ai);
}

@keyframes q-drop {
  from { transform: translateY(-12px); opacity: 0; }
  to { transform: none; opacity: 1; }
}

/* La boite de la barre du haut : elle ROUVRE le message, discretement. */
.q-inbox[data-unread='true'] { border-color: var(--q-ai-ink); color: var(--q-ai-ink); }

.q-dm-back { position: fixed; inset: 0; z-index: 48; background: var(--q-bg-1); opacity: 0.6; }

.q-dm {
  position: fixed;
  z-index: 49;
  top: 50%;
  left: 50%;
  display: flex;
  flex-direction: column;
  gap: var(--q-gap-sm);
  width: min(460px, calc(100vw - 2 * var(--q-pad)));
  max-height: 80vh;
  overflow-y: auto;
  padding: var(--q-pad);
  border: var(--q-border-width) solid var(--q-border-strong);
  border-radius: var(--q-radius);
  background: var(--q-surface);
  box-shadow: var(--q-shadow);
  transform: translate(-50%, -50%);
  animation: q-dm-drop var(--q-motion-fast) var(--q-ease) both;
}

/* Une propriete ANIMEE l'emporte sur la declaration, et `both` garde la
   derniere image : avec `q-drop` (`to { transform: none }`) la fenetre finissait
   son coin haut gauche a (50vw, 50vh) — hors ecran sous 920 px, invisible au
   smoke en 1280x720 (relecture ECL-80). Le centrage voyage donc DANS les
   images. */
@keyframes q-dm-drop {
  from { transform: translate(-50%, calc(-50% - 12px)); opacity: 0; }
  to { transform: translate(-50%, -50%); opacity: 1; }
}

.q-dm-head { display: flex; gap: var(--q-gap-sm); align-items: center; }
.q-dm-who { display: flex; flex-direction: column; gap: 2px; min-width: 0; margin-right: auto; }
.q-dm-stamp { color: var(--q-text-dim); font-size: 0.75rem; }
.q-dm-to { margin: 0; color: var(--q-text-muted); font-size: 0.8rem; }

.q-dm-bubble {
  margin: 0;
  padding: var(--q-pad-sm);
  border: var(--q-border-width) solid var(--q-border);
  border-radius: var(--q-radius);
  background: var(--q-surface-2);
  line-height: 1.6;
}

.q-dm-seen { margin: 0; align-self: flex-end; color: var(--q-text-dim); font-size: 0.75rem; }

/* Le vocal : une barre, une duree, la transcription REPLIEE. */
.q-dm-voice { display: flex; flex-direction: column; gap: var(--q-gap-sm); }
.q-dm-row { display: flex; gap: var(--q-gap-sm); align-items: center; }
.q-dm-time { font-variant-numeric: tabular-nums; font-size: 0.8rem; }
.q-dm-audio { display: none; }

.q-dm-bar {
  flex: 1 1 auto;
  width: 100%;
  height: 8px;
  border: 0;
  border-radius: var(--q-radius-pill);
  background: var(--q-surface-2);
  appearance: none;
}

.q-dm-bar::-webkit-progress-bar { border-radius: var(--q-radius-pill); background: var(--q-surface-2); }
.q-dm-bar::-webkit-progress-value { border-radius: var(--q-radius-pill); background: var(--q-ai); }
.q-dm-bar::-moz-progress-bar { border-radius: var(--q-radius-pill); background: var(--q-ai); }

.q-dm-summary { color: var(--q-ai-ink); font-size: 0.85rem; cursor: pointer; }
.q-dm-fold[open] .q-dm-summary { margin-bottom: var(--q-gap-sm); }

/* --- Divers -------------------------------------------------------------- */

.q-error { padding: var(--q-pad); border: var(--q-border-width) solid var(--q-bad); border-radius: var(--q-radius-sm); color: var(--q-bad-ink); }
.q-empty { color: var(--q-text-muted); }

/* --- ECL-43 : la consigne du jour, et l'invitation a agir ----------------
 *
 * Meme composant que Pratiquer (`window.ECLAIR_BRIEF`), peau de la Quest :
 * aucune couleur ici, uniquement les jetons du theme (check-quest-themes).
 * La consigne s'ouvre en tete de journee et se replie au premier geste ; le
 * premier element a toucher porte `data-first` tant que rien n'a ete fait.
 */

.q-brief {
  display: flex;
  flex-direction: column;
  gap: var(--q-gap-sm);
  padding: var(--q-pad);
  border: var(--q-border-width) solid var(--q-border);
  border-left: 3px solid var(--q-ai-ink);
  border-radius: var(--q-radius);
  background: var(--q-surface-2);
  color: var(--q-text);
}

.q-brief-head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--q-gap-sm);
  flex-wrap: wrap;
}

.q-brief-title {
  margin: 0;
  /* Un titre de consigne se LIT : il suit `--q-font-title`, jamais la display
     de marquise, et porte son propre gras — `--q-display-weight` vaut 400 sur
     un thème dont la display n'a qu'une graisse (ECL-51). */
  font-family: var(--q-font-title);
  font-weight: 600;
  font-size: 1.1rem;
}

.q-brief-toggle {
  border: 0;
  background: none;
  color: var(--q-ai-ink);
  font: inherit;
  font-size: 0.85rem;
  cursor: pointer;
  text-decoration: underline;
  padding: var(--q-gap-sm) 0;
}

.q-brief-body { display: grid; gap: var(--q-gap-sm); }
.q-brief[data-open='false'] .q-brief-body { display: none; }

.q-brief-line, .q-brief-why { margin: 0; line-height: 1.55; }
.q-brief-label { font-weight: 600; color: var(--q-text); }
.q-brief-why { color: var(--q-text-muted); }

.q-brief-steps { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--q-gap-sm); }
.q-brief-step { display: flex; gap: var(--q-gap-sm); align-items: baseline; }

/* Le numero est un NOEUD : c'est un ordre a lire, pas une puce. */
.q-brief-step-num {
  flex: 0 0 auto;
  width: 22px;
  height: 22px;
  border-radius: var(--q-radius-pill);
  background: var(--q-ai);
  color: var(--q-ai-on);
  font-size: 0.78rem;
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
}

.q-brief-step-text { line-height: 1.5; }

/* L'invitation : le premier endroit ou agir, tant que rien n'a ete fait.
   L'`outline` est REPOSE ici : la regle commune de `practice.css` en pose un
   en `--primary` (design system), et sans cette ligne la premiere tuile
   portait un anneau bleu au milieu d'un halo jaune sur le theme arcade. Dans
   la Quest, une couleur ne vient que du theme. */
.quest-v2 [data-first='true'] {
  border-color: var(--q-ai-ink);
  box-shadow: var(--q-glow);
  outline: 2px solid var(--q-ai-ink);
  outline-offset: 3px;
  animation: q-invite var(--q-motion-slow) ease-in-out infinite;
}

@keyframes q-invite {
  from { box-shadow: 0 0 0 2px var(--q-ai-soft); }
  50% { box-shadow: 0 0 0 7px var(--q-ai-soft); }
  to { box-shadow: 0 0 0 2px var(--q-ai-soft); }
}

/* --- Ce qu'on refait, a cote du verdict ---------------------------------- */

.q-redo {
  display: grid;
  gap: var(--q-gap-sm);
  padding: var(--q-pad-sm);
  border: var(--q-border-width) solid var(--q-border);
  border-left: 3px solid var(--q-ai-ink);
  border-radius: var(--q-radius-sm);
  background: var(--q-surface-2);
}

.q-redo-none { margin: 0; color: var(--q-text-muted); }
.q-redo-list { list-style: none; margin: 0; padding: 0; display: grid; gap: var(--q-gap-sm); }
.q-redo-move { line-height: 1.5; }
.q-redo-verb { font-weight: 600; }
.q-redo-quote { font-style: italic; }
.q-redo-move[data-severity='zero'] .q-redo-verb { color: var(--q-bad-ink); }
.q-redo-move[data-severity='blocking'] .q-redo-verb { color: var(--q-warn); }

/* La pioche du mardi en COLONNE (ECL-43) : une carte par ligne, pas de trait
   de separation (elle a son titre de carte), et rien a faire defiler entre la
   carte qu'on prend et la case ou on la pose. */

.q-hand-rail {
  grid-template-columns: minmax(0, 1fr);
  padding-top: 0;
  border-top: 0;
}

/* --- Mobile : 390 px, jouable au doigt ----------------------------------- */

@media (max-width: 900px) {
  .quest-v2 { padding: var(--q-pad-sm); }
  .q-body,
  .q-body[data-columns='2'] { grid-template-columns: minmax(0, 1fr); }
  .q-split { grid-template-columns: minmax(0, 1fr); }
  .q-matrix { grid-auto-rows: minmax(120px, auto); }
  .q-panel { inset: auto 0 0 0; width: 100%; max-height: 82vh; border-left: 0; border-top: var(--q-border-width) solid var(--q-border-strong); }
  .q-title { font-size: calc(var(--q-display-size) * 0.8); }

  /* ECL-77 — a 390 px la barre tient sur UNE ligne, et le smoke le mesure.
     Trois resserrements, et pas un de plus :
      - le libelle d'un outil devient hors-ecran, jamais `display: none` : le
        bouton garde son nom pour un lecteur d'ecran, et son `title` a la
        souris ;
      - la marque s'efface — l'ecran porte deja le titre du jeu, et 85 px de
        logo, c'est le bouton « quitter » qui sort de l'ecran ;
      - le selecteur de langue se serre sur son texte.
     Ce qui reste visible : la sortie, la langue, le son, la boite, le plein
     ecran — cinq cibles de 36 px. */
  .q-top .q-bar-label {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .q-top .q-logo { display: none; }
  .q-select { padding: 0 4px; font-size: 0.75rem; }
  .q-days { flex: 1 1 100%; }
  .q-scores { flex: 1 1 auto; }
  /* Le glisser au doigt est fragile : sur petit écran on joue au TOUCHER,
     et les tuiles le disent (« touche une tuile, puis une case »). */
  .q-tile { cursor: pointer; }
}

/* --- ECL-84 : le fil ecrit d'un collegue --------------------------------
   Il vit DANS la carte du personnage — la saisie s'ouvre la ou elle se range.
   Il ne connait que les jetons du theme (`check-quest-themes`) : aucune
   couleur en dur, aucun `!important`. */

.q-chat {
  display: flex;
  flex-direction: column;
  gap: var(--q-gap-sm);
  margin-top: var(--q-gap-sm);
  padding-top: var(--q-gap-sm);
  border-top: var(--q-border-width) solid var(--q-border);
}

.q-chat-title {
  margin: 0;
  color: var(--q-text-muted);
  font-family: var(--q-font-display);
  font-size: 0.85rem;
  letter-spacing: var(--q-display-tracking);
  text-transform: uppercase;
}

/* Ce que le joueur a ecrit, et ce que le collegue repond : deux bulles, deux
   bords. Le collegue porte le liseré des moments IA — c'est un modele qui
   parle, et l'ecran ne le cache pas. */
.q-chat-me,
.q-chat-them {
  margin: 0;
  padding: var(--q-pad-sm);
  border-radius: var(--q-radius-sm);
  font-size: 0.9rem;
  line-height: 1.5;
}

.q-chat-me {
  align-self: flex-end;
  max-width: 85%;
  border: var(--q-border-width) solid var(--q-border);
  background: var(--q-surface-2);
  color: var(--q-text);
}

.q-chat-them {
  align-self: flex-start;
  max-width: 95%;
  border-left: 3px solid var(--q-ai-ink);
  background: var(--q-surface-2);
  color: var(--q-text-muted);
}

/* Une question, pas un dossier : la zone est courte, et elle grandit si le
   joueur le demande. */
.q-chat-area { min-height: 72px; }

/* --- Mouvement : jamais sans information, et jamais imposé --------------- */

@media (prefers-reduced-motion: reduce) {
  .quest-v2 *,
  .quest-v2 *::before,
  .quest-v2 *::after {
    animation-duration: 1ms;
    animation-iteration-count: 1;
    transition-duration: 1ms;
  }

  /* L'invitation d'ECL-43 se coupe ICI, et pas par la regle ci-dessus :
     `.quest-v2 *` pese (0,1,0) quand `.quest-v2 [data-first='true']` pese
     (0,2,0) — la plus specifique gagnait, et le bouton pulsait a l'infini chez
     un joueur qui a demande moins d'animations. L'anneau, lui, RESTE : une
     invitation ne depend pas du mouvement. Prouve par
     `e2e/quest-v2.spec.js` (emulateMedia reduced-motion). */
  .quest-v2 [data-first='true'] { animation: none; }

  /* Meme piege, meme remede pour l'a-coup d'une etoile qui s'allume (ECL-51) :
     `.q-star[data-lit='true']` pese (0,2,0). Aujourd'hui `data-lit` n'est
     JAMAIS pose sous reduced-motion — le compteur ne part pas — mais une regle
     de specificite ne se relit pas a l'oeil, et un chemin futur qui poserait
     l'attribut autrement rallumerait l'animation sans que rien ne le dise. */
  .quest-v2 .q-star[data-lit='true'] { animation: none; }
}
