/* ==========================================================================
   SciRedPen, design system

   Direction : la surface d'assistant. Tout ce qui se clique porte un angle
   plein, les plans sont unis, et ce qui répond au pointeur répond par un fond
   à peine teinté plutôt que par un trait. Une ombre n'existe que sous ce qui
   flotte au-dessus de la page ; partout ailleurs, un filet d'un point suffit.

   Une seule famille, celle du système, à trois graisses : le corps à 400, le
   libellé et le bouton à 500, le titre à 600. Aucune capitale forcée, aucune
   approche élargie : la hiérarchie vient du corps, du poids et de la couleur
   du texte, jamais de la casse. Les poids sont des jetons, faute de quoi un
   seul écart de graisse se corrige en trente endroits.

   Trois encres, comme sur un bureau de correction : le crimson marque et
   alerte, le bleu d'ardoise désigne ce qui est actif, l'ambre est réservé à ce
   qui attend. Le reste est du papier.

   Un seul jeu de jetons ; le thème clair n'en est qu'une redéfinition. Les
   jetons `--ms-*` font exception : ils décrivent le manuscrit, qui reste
   blanc et marqué de crimson dans les deux thèmes.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Fontes
   L'interface se compose dans le dessin que la machine emploie déjà pour ses
   propres fenêtres : rien à télécharger avant le premier mot lisible, et un
   texte qui a l'air d'appartenir au poste plutôt qu'à une page.

   Les quatre coupes servies par l'origine restent en réserve, pour les
   plates-formes dépourvues de pile système. Elles ne sont téléchargées que
   si aucune des familles nommées avant elles n'existe.
   -------------------------------------------------------------------------- */

@font-face {
  font-family: "Lato";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/lato-latin-400-normal.woff2") format("woff2");
}

@font-face {
  font-family: "Lato";
  font-style: italic;
  font-weight: 400;
  font-display: swap;
  src: url("/fonts/lato-latin-400-italic.woff2") format("woff2");
}

@font-face {
  font-family: "Lato";
  font-style: normal;
  font-weight: 700;
  font-display: swap;
  src: url("/fonts/lato-latin-700-normal.woff2") format("woff2");
}

@font-face {
  font-family: "Lato";
  font-style: normal;
  font-weight: 900;
  font-display: swap;
  src: url("/fonts/lato-latin-900-normal.woff2") format("woff2");
}

:root {
  color-scheme: dark;

  /* Surfaces : l'ardoise d'Oxford. Ce fond n'est pas le manuscrit mais la
     coque qui l'entoure ; la page, elle, reste blanche. */
  --bg: #0f172a;
  --bg-sunken: #0b1220;
  --bg-raised: #1e293b;
  /* Le fond du plan de travail est le plus sombre de tous : c'est ce qui fait
     exister la page blanche posée dessus. */
  --bg-canvas: #020617;
  --bg-hover: rgba(234, 241, 255, 0.06);
  --bg-active: rgba(234, 241, 255, 0.1);

  --text: #eaf1ff;
  --text-muted: #94a3b8;
  --text-faint: #7d8da3;
  --text-inverse: #0f172a;

  --line: rgba(203, 213, 225, 0.16);
  --line-strong: rgba(203, 213, 225, 0.32);

  /* Bleu de méthode : ce qui est actif, validé, désigné. Distinct du crimson,
     qui ne sert qu'aux constats. */
  --accent: #bec6e0;
  --accent-soft: rgba(190, 198, 224, 0.16);
  --accent-ring: rgba(190, 198, 224, 0.34);

  /* Crimson d'éditeur : ce qui est marqué, ce qui a échoué. */
  --danger: #ffb4ac;
  --danger-soft: rgba(255, 180, 172, 0.14);
  --warn: #fbbf24;

  --solid: #eaf1ff;
  --solid-hover: #ffffff;

  /* Le manuscrit. Ces jetons ne suivent pas le thème : une page reste blanche
     et ses marques gardent leur couleur, sous la lampe comme au jour. Les
     prendre dans les jetons d'interface rendrait le crimson clair du thème
     sombre invisible sur le papier. */
  --ms-paper: #ffffff;
  --ms-ink: #0f172a;
  --ms-rule: #e2e8f0;
  --ms-mark: #991b1b;
  /* Vélin annoté : le surlignage dit « regardé ici », le crimson dit « ceci
     est faux ». Confondre les deux fait de chaque page un réquisitoire. */
  --ms-highlight: #fef08a;

  /* Une ombre ne sépare pas deux plans, elle dit qu'un objet flotte au-dessus
     de la page : elle n'est portée que par ce qui s'ouvre par-dessus le
     reste. */
  --shadow-sm: 0 1px 2px rgba(2, 6, 23, 0.32);
  --shadow-md: 0 4px 12px rgba(2, 6, 23, 0.38);
  --shadow-lg: 0 16px 40px rgba(2, 6, 23, 0.48);

  /* Angles. Le rayon croît avec la surface, et tout ce qui se clique porte le
     rayon plein : c'est la forme, et non un cadre, qui dit qu'un élément est
     un objet manipulable. */
  --r-sm: 8px;
  --r-md: 12px;
  --r-lg: 16px;
  --r-xl: 24px;
  --r-pill: 999px;

  /* Trois rôles, une seule famille. Les jetons restent séparés parce que ce
     sont les rôles qui structurent la feuille, non les dessins : titre, texte
     courant, libellé. */
  --font-ui: ui-sans-serif, -apple-system, system-ui, "Segoe UI", Helvetica, "Apple Color Emoji",
    "Lato", Arial, sans-serif, "Segoe UI Emoji", "Segoe UI Symbol";
  --font-display: var(--font-ui);
  --font-text: var(--font-ui);
  --font-meta: var(--font-ui);

  /* Graisses. Trois valeurs seulement, et resserrées : au-delà de 600, un
     titre d'interface cesse d'être un titre pour devenir une enseigne. */
  --w-text: 400;
  --w-strong: 500;
  --w-display: 600;

  --topbar-h: 56px;
  --actionbar-h: 52px;
  /* Hauteur des contrôles. Une seule, pour que la barre garde une ligne de
     fond, et une réduite pour ce qui se pose sur la visionneuse. */
  --control-h: 36px;
  --control-h-sm: 30px;
  /* Garde sous la page : la barre de pagination flotte au-dessus du bas de la
     visionneuse, et la derniere ligne du manuscrit doit pouvoir passer
     dessous. */
  --pagebar-clear: 88px;

  /* Échelle d'espacement, base 4, avec un demi-pas pour les interstices d'un
     instrument dense. Aucune valeur d'espacement hors de cette échelle :
     c'est ce qui fait qu'une barre et un panneau respirent au même rythme. */
  --s-half: 2px;
  --s-1: 4px;
  --s-2: 8px;
  --s-3: 12px;
  --s-4: 16px;
  --s-5: 20px;
  --s-6: 24px;
  --s-7: 32px;
  --s-8: 48px;
  --s-9: 64px;

  /* Approche des titres, et d'eux seuls : à partir de 15 points, un titre
     laissé à l'approche du corps de texte s'étale. Rien d'autre n'est
     approché, ni en plus ni en moins. */
  --track-title: -0.011em;

  /* Courbes. Trois, et elles ne sont pas interchangeables : ce qui entre ou
     sort décélère, ce qui se déplace à l'écran accélère puis décélère, ce qui
     ne change que de couleur suit la courbe courte. */
  --ease-out: cubic-bezier(0.23, 1, 0.32, 1);
  --ease-in-out: cubic-bezier(0.77, 0, 0.175, 1);
  --ease-hover: cubic-bezier(0.2, 0, 0, 1);
  --ease: var(--ease-hover);

  /* Durées. Un outil manipulé toute la journée reste sous 250 ms ; seule
     l'ouverture de l'atelier, vue une fois par session, s'autorise plus. */
  --t-press: 120ms;
  --t-hover: 140ms;
  --t-pop: 160ms;
  --t-panel: 240ms;
  --t-enter: 420ms;
}

[data-theme="light"] {
  color-scheme: light;

  /* Papier de manuscrit, encre d'archive : l'épreuve posée sur le bureau. */
  --bg: #f8fafc;
  --bg-sunken: #f1f5f9;
  --bg-raised: #ffffff;
  --bg-canvas: #e2e8f0;
  --bg-hover: rgba(15, 23, 42, 0.05);
  --bg-active: rgba(15, 23, 42, 0.09);

  --text: #0f172a;
  --text-muted: #475569;
  --text-faint: #64748b;
  --text-inverse: #ffffff;

  /* Le système sépare par des filets, non par des ombres : deux valeurs, la
     seconde là où la surface se manipule. */
  --line: #e2e8f0;
  --line-strong: #cbd5e1;

  --accent: #565e74;
  --accent-soft: rgba(86, 94, 116, 0.1);
  --accent-ring: rgba(86, 94, 116, 0.28);

  --danger: #991b1b;
  --danger-soft: rgba(153, 27, 27, 0.08);
  --warn: #b45309;

  --solid: #0f172a;
  --solid-hover: #1e293b;

  --shadow-sm: 0 1px 2px rgba(15, 23, 42, 0.06);
  --shadow-md: 0 4px 12px rgba(15, 23, 42, 0.1);
  --shadow-lg: 0 16px 40px rgba(15, 23, 42, 0.16);
}

* {
  box-sizing: border-box;
}

/**
 * `[hidden]` doit gagner.
 *
 * La regle du navigateur qui masque un element `hidden` est une regle
 * d'agent utilisateur : la moindre declaration d'auteur -- ici
 * `button { display: inline-flex }` -- la surclasse, et l'attribut cesse
 * silencieusement de masquer quoi que ce soit.
 */
[hidden] {
  display: none !important;
}

html,
body {
  height: 100%;
}

body {
  margin: 0;
  background-color: var(--bg);
  color: var(--text);
  font-family: var(--font-text);
  font-size: 15px;
  line-height: 1.6;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
}

h1,
h2,
h3,
p {
  margin: 0;
}

::selection {
  background: var(--danger-soft);
}

:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* Barres de défilement discrètes */
* {
  scrollbar-width: thin;
  scrollbar-color: var(--line-strong) transparent;
}

*::-webkit-scrollbar {
  width: 10px;
  height: 10px;
}

*::-webkit-scrollbar-thumb {
  border: 3px solid transparent;
  border-radius: var(--r-pill);
  background: var(--line-strong);
  background-clip: content-box;
}

*::-webkit-scrollbar-track {
  background: transparent;
}

/* --------------------------------------------------------------------------
   Contrôles
   Des pastilles : angle plein, libellé dans sa casse, et un fond qui s'allume
   sous le pointeur plutôt qu'un cadre qui s'épaissit.
   -------------------------------------------------------------------------- */

button,
input,
textarea,
select {
  font: inherit;
  color: inherit;
}

button,
.file-button span {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  height: var(--control-h);
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--text-muted);
  padding: 0 var(--s-4);
  font-family: var(--font-meta);
  font-size: 14px;
  font-weight: var(--w-strong);
  letter-spacing: normal;
  text-transform: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--t-hover) var(--ease-hover), color var(--t-hover) var(--ease-hover),
    border-color var(--t-hover) var(--ease-hover), opacity var(--t-press) var(--ease-out);
}

/* Le survol ne vaut que pour un pointeur qui survole. Une tablette déclenche
   `:hover` au toucher : sans cette porte, chaque appui laisse la ligne
   allumée derrière le doigt. */
@media (hover: hover) and (pointer: fine) {
  button:hover:not(:disabled),
  .file-button:hover span {
    background: var(--bg-hover);
    color: var(--text);
  }
}

/* L'enfoncement se voit avant le résultat, et il se voit au fond : une
   pastille qui recule d'un centième fait tressauter la barre entière. */
button:active:not(:disabled),
.file-button:active span {
  background: var(--bg-active);
}

button:disabled {
  opacity: 0.35;
  cursor: not-allowed;
}

button.active {
  background: var(--bg-active);
  color: var(--text);
}

/* Le contour d'un bouton secondaire est un filet, pas un cadre : c'est le
   fond qui répond au survol. */
.btn-outline,
.file-button span {
  border-color: var(--line);
  color: var(--text);
}

.btn-primary {
  border-color: transparent;
  background: var(--solid);
  color: var(--text-inverse);
  font-weight: var(--w-strong);
}

@media (hover: hover) and (pointer: fine) {
  .btn-primary:hover:not(:disabled) {
    background: var(--solid-hover);
    color: var(--text-inverse);
  }
}

/* Un fond translucide posé sur une pastille pleine l'éclaircit au lieu de
   l'enfoncer : elle s'atténue, et garde sa couleur. */
.btn-primary:active:not(:disabled) {
  background: var(--solid);
  opacity: 0.82;
}

.btn-danger {
  border-color: var(--danger);
  color: var(--danger);
}

@media (hover: hover) and (pointer: fine) {
  .btn-danger:hover:not(:disabled) {
    background: var(--danger);
    color: var(--text-inverse);
  }
}

/* Un bouton d'icône est un disque : hauteur de contrôle en largeur, angle
   plein, et le fond seul dit qu'il est sous le pointeur. */
.icon-btn {
  width: var(--control-h);
  padding: 0;
  justify-content: center;
}

.icon-btn svg {
  width: 16px;
  height: 16px;
}

/* --------------------------------------------------------------------------
   Charpente
   -------------------------------------------------------------------------- */

.app {
  height: 100%;
  min-height: 0;
  display: flex;
  flex-direction: column;
}

.topbar {
  height: var(--topbar-h);
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-4);
  border-bottom: 1px solid var(--line);
  background: var(--bg-sunken);
  padding: 0 var(--s-4);
}

.brand {
  display: flex;
  align-items: center;
  gap: var(--s-3);
  min-width: 0;
}

/* The artwork has dedicated light/dark variants. Stacking them avoids a flash
   of the wrong logo when the stored theme is applied before first paint. */
.brand-mark {
  width: 152px;
  height: 40px;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  color: inherit;
  text-decoration: none;
}

.visually-hidden {
  position: fixed;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.brand-logo {
  width: 100%;
  height: 100%;
  grid-area: 1 / 1;
  display: block;
  object-fit: contain;
  transition: opacity 140ms var(--ease-hover);
}

.brand-logo--light-theme {
  opacity: 0;
}

[data-theme="light"] .brand-logo--dark-theme {
  opacity: 0;
}

[data-theme="light"] .brand-logo--light-theme {
  opacity: 1;
}

.brand-text {
  display: flex;
  align-items: baseline;
  gap: var(--s-3);
  min-width: 0;
}

h1 {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: var(--w-display);
  letter-spacing: var(--track-title);
}

/* Le nom du document tient sur une ligne : c'est un titre courant, pas un
   paragraphe. La règle ne vaut que dans la barre de titre de l'atelier. */
.topbar h1 {
  white-space: nowrap;
}

#documentName {
  position: relative;
  max-width: 42ch;
  padding-left: var(--s-3);
  overflow: hidden;
  color: var(--text-faint);
  font-family: var(--font-meta);
  font-size: 13px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

#documentName::before {
  content: "";
  position: absolute;
  top: 0.15em;
  bottom: 0.15em;
  left: 0;
  width: 1px;
  background: var(--line);
}

.topbar-actions {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  flex: 0 0 auto;
}

.research-link {
  color: var(--text-muted);
  padding: 0 var(--s-2);
  font-family: var(--font-meta);
  font-size: 14px;
  text-decoration: none;
  white-space: nowrap;
  transition: color var(--t-hover) var(--ease-hover);
}

@media (hover: hover) and (pointer: fine) {
  .research-link:hover {
    color: var(--danger);
  }
}

.divider {
  width: 1px;
  height: 18px;
  margin: 0 var(--s-1);
  background: var(--line);
}

.credits-label {
  color: var(--text-muted);
  padding: 0 var(--s-2);
  font-family: var(--font-meta);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.credits-label.low {
  color: var(--danger);
}

/* Sélecteur de langue : deux états visibles à la fois, pour qu'aucun clic ne
   soit un pari sur ce qui se passera. */
.lang-switch {
  display: inline-flex;
  align-items: center;
  gap: var(--s-half);
  border: 0;
  border-radius: var(--r-pill);
  background: var(--bg-hover);
  padding: var(--s-half);
}

/* Les pages qui ont une adresse par langue portent un lien vers leur jumelle
   plutôt qu'un bouton : l'option s'affiche de la même façon dans les deux
   cas, la propriété du lien ne se voit qu'à l'adresse qu'il ouvre. */
.lang-switch button,
.lang-switch a {
  display: inline-flex;
  align-items: center;
  height: 26px;
  border: 0;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--text-faint);
  padding: 0 var(--s-3);
  font-family: var(--font-meta);
  font-size: 12px;
  font-weight: var(--w-strong);
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition: background var(--t-hover) var(--ease-hover), color var(--t-hover) var(--ease-hover);
}

/* Même porte que pour les boutons : un appui sur tablette ne doit pas laisser
   l'option allumée derrière le doigt. */
@media (hover: hover) and (pointer: fine) {
  .lang-switch a:hover {
    background: var(--bg-hover);
    color: var(--text);
  }
}

.lang-switch a:active {
  background: var(--bg-active);
}

/* La langue retenue est posée sur le creux, pas gravée dedans : une pastille
   de surface, de la couleur des panneaux. */
.lang-switch button.active,
.lang-switch a.active {
  background: var(--bg-raised);
  color: var(--text);
  box-shadow: var(--shadow-sm);
}

/* --------------------------------------------------------------------------
   Panneau de compte
   Une carte qui flotte sous la barre : angles pleins, ombre portée, et les
   réglages du poste rangés par nature plutôt qu'alignés.
   -------------------------------------------------------------------------- */

.account-menu,
.export-menu {
  position: relative;
  flex: none;
}

.account-trigger {
  gap: var(--s-2);
  height: var(--control-h);
  padding: 0 var(--s-3) 0 var(--s-1);
}

.account-trigger[aria-expanded="true"] {
  background: var(--bg-active);
  color: var(--text);
}

/* La lettrine du compte : même geste que la marque du produit, mais à l'encre.
   Le rouge reste réservé à ce qui corrige. */
.account-initial {
  width: 22px;
  height: 22px;
  flex: 0 0 auto;
  display: grid;
  place-items: center;
  border: 0;
  border-radius: 50%;
  background: var(--bg-active);
  color: var(--text);
  font-family: var(--font-display);
  font-size: 12px;
  font-weight: var(--w-display);
  line-height: 1;
}

.account-trigger-label {
  max-width: 22ch;
  overflow: hidden;
  font-size: 14px;
  text-overflow: ellipsis;
}

.account-chevron {
  width: 8px;
  height: 8px;
  flex: 0 0 auto;
  opacity: 0.55;
  transition: transform var(--t-pop) var(--ease-out);
}

[aria-expanded="true"] > .account-chevron {
  transform: rotate(180deg);
}

.account-sheet,
.export-sheet {
  position: absolute;
  top: calc(100% + var(--s-2));
  right: 0;
  z-index: 40;
  display: grid;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg-raised);
  box-shadow: var(--shadow-lg);

  /* Le feuillet se déplie depuis son cartouche, non depuis son centre :
     l'origine est le coin qui touche le déclencheur. */
  transform-origin: top right;
  transition: opacity var(--t-pop) var(--ease-out), transform var(--t-pop) var(--ease-out);
}

/* Ouverture du feuillet. `@starting-style` est le seul moyen d'animer une
   apparition depuis `display: none`, l'état dans lequel `hidden` le laisse.
   Un navigateur qui l'ignore affiche le panneau d'un coup, ce qui reste
   correct. La fermeture, elle, est instantanée : un menu qu'on quitte ne doit
   pas rester une fraction de seconde sous le doigt. */
@starting-style {
  .account-sheet,
  .export-sheet,
  .library-menu-list {
    opacity: 0;
    transform: translateY(-6px) scale(0.97);
  }
}

.account-sheet {
  min-width: 264px;
  padding: var(--s-2);
}

/* Le cartouche d'export est à gauche de sa barre : le feuillet se déplie donc
   vers la droite, depuis le coin qui le porte. */
.export-sheet {
  right: auto;
  left: 0;
  min-width: 196px;
  padding: var(--s-2);
  transform-origin: top left;
}

/* Le porteur du nom, et la porte vers le compte sous lui. */
.sheet-identity {
  display: grid;
  gap: var(--s-half);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--s-1);
  padding: var(--s-2) var(--s-3) var(--s-3);
}

.sheet-identity-name {
  overflow: hidden;
  color: var(--text);
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: var(--w-display);
  letter-spacing: var(--track-title);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.sheet-identity-link {
  color: var(--text-faint);
  font-family: var(--font-meta);
  font-size: 13px;
  text-decoration: none;
  transition: color var(--t-hover) var(--ease-hover);
}

@media (hover: hover) and (pointer: fine) {
  .sheet-identity-link:hover {
    color: var(--accent);
  }
}

/* Les sections se séparent par un filet, et non par de l'air : sur un feuillet
   étroit, un blanc se lit comme une omission. */
.sheet-section {
  display: grid;
  gap: var(--s-half);
  padding: var(--s-1) 0;
}

.sheet-section + .sheet-section {
  border-top: 1px solid var(--line);
}

/* Un intitulé de section se lit comme une phrase, en plus petit et en plus
   pâle que ce qu'il coiffe : ni capitales, ni approche élargie. */
.sheet-label {
  color: var(--text-faint);
  padding: var(--s-2) var(--s-3) var(--s-1);
  font-family: var(--font-meta);
  font-size: 12px;
  font-weight: var(--w-strong);
}

/* Une ligne de réglage : le nom à gauche, le réglage à droite, contre ce
   qu'il change. */
.sheet-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  padding-right: var(--s-2);
}

.sheet-row .sheet-label {
  padding-bottom: var(--s-1);
}

.sheet-item {
  width: 100%;
  height: auto;
  min-height: 34px;
  justify-content: flex-start;
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text);
  padding: var(--s-2) var(--s-3);
  font-family: var(--font-meta);
  font-size: 14px;
  font-weight: var(--w-text);
  text-align: left;
  text-decoration: none;
  white-space: nowrap;
}

@media (hover: hover) and (pointer: fine) {
  .sheet-item:hover:not(:disabled) {
    background: var(--bg-hover);
    color: var(--text);
  }

  .sheet-item.danger:hover:not(:disabled) {
    background: var(--danger-soft);
    color: var(--danger);
  }
}

/* Le déclencheur d'export porte le poids d'une action, pas celui d'un
   intertitre : c'est la seule sortie de l'atelier. */
.export-trigger {
  gap: var(--s-2);
  border-color: var(--line);
  color: var(--text);
}

.export-trigger[aria-expanded="true"] {
  background: var(--bg-active);
}

/* Bascules de colonne : le cadre de travail se règle au bout de la barre. */
.panel-toggles {
  display: flex;
  align-items: center;
  gap: var(--s-half);
  margin-left: auto;
  flex: none;
}

.panel-toggles .icon-btn svg {
  width: 15px;
  height: 15px;
}

.panel-toggles [aria-pressed="false"] {
  color: var(--text-faint);
}

.panel-toggles [aria-pressed="false"] svg rect:last-child {
  fill: none;
}

/* Barre d'actions */

/* La barre se replie sur deux lignes plutôt que de défiler : un conteneur de
   défilement rognerait le feuillet d'export, qui est posé en absolu sous son
   cartouche. Depuis que les exports tiennent derrière un seul bouton, la barre
   n'a plus de quoi déborder à une largeur de travail. */
.actionbar {
  min-height: var(--actionbar-h);
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: var(--s-2) var(--s-4);
  border-bottom: 1px solid var(--line);
  background: var(--bg);
  padding: var(--s-2) var(--s-4);
}

.actionbar-group {
  display: flex;
  align-items: center;
  gap: var(--s-2);
}

.upload-disclosure {
  flex: 0 0 auto;
  display: flex;
  align-items: center;
  gap: var(--s-3);
  border-bottom: 1px solid var(--line);
  background: var(--bg-sunken);
  color: var(--text-muted);
  padding: 6px var(--s-3) 6px var(--s-4);
  font-family: var(--font-meta);
  font-size: 12px;
  line-height: 1.35;
}

.upload-disclosure-copy {
  min-width: 0;
  flex: 1 1 auto;
  display: flex;
  align-items: baseline;
  flex-wrap: wrap;
  gap: 2px var(--s-2);
}

.upload-disclosure strong {
  flex: none;
  color: var(--text-muted);
  font-weight: var(--w-strong);
  white-space: nowrap;
}

.upload-disclosure a {
  flex: none;
  color: var(--text);
  text-underline-offset: 3px;
}

.upload-disclosure-close {
  width: 28px;
  height: 28px;
  flex: 0 0 28px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  border: 0;
  border-radius: 50%;
  background: transparent;
  color: var(--text-faint);
  padding: 0;
  cursor: pointer;
  transition:
    background-color 160ms ease,
    color 160ms ease,
    transform 160ms ease;
}

.upload-disclosure-close svg {
  width: 14px;
  height: 14px;
  fill: none;
  stroke: currentColor;
  stroke-linecap: round;
  stroke-width: 1.5;
}

@media (hover: hover) and (pointer: fine) {
  .upload-disclosure-close:hover {
    background: var(--bg-hover);
    color: var(--text);
  }
}

.upload-disclosure-close:active {
  transform: scale(0.92);
}

.upload-disclosure-close:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

@media (max-width: 860px) {
  .upload-disclosure {
    align-items: flex-start;
    padding: var(--s-2) var(--s-2) var(--s-2) var(--s-3);
  }
}

.file-button input {
  position: absolute;
  width: 1px;
  height: 1px;
  opacity: 0;
  pointer-events: none;
}

.file-button:focus-within span {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}

/* --------------------------------------------------------------------------
   Espace de travail
   -------------------------------------------------------------------------- */

/* La bibliothèque à gauche, où l'on choisit sur quoi travailler ; la
   visionneuse au centre, qui garde la place ; à droite un seul panneau, dont
   les onglets font alterner les commentaires numérotés et la relecture dont ils
   sont issus. Deux colonnes de lecture rognaient le document sans qu'on lise
   jamais les deux à la fois. */
.workspace {
  /* Les largeurs mémorisées restent des variables ; les états de repli ont
     chacun une grille nommée afin qu'aucune piste invisible ne survive. */
  --col-library: clamp(200px, var(--library-panel-width, 240px), 33vw);
  --col-assistant: clamp(320px, var(--assistant-panel-width, 440px), 33vw);
  --library-resizer: 7px;
  --assistant-resizer: 7px;
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  grid-template-columns:
    var(--col-library)
    var(--library-resizer)
    minmax(360px, 1fr)
    var(--assistant-resizer)
    var(--col-assistant);
  grid-template-areas: "library library-resizer viewer assistant-resizer assistant";
  /* Les pistes ne sont volontairement pas animées. Chromium peut perdre la
     peinture du canvas PDF et des panneaux adjacents pendant l'interpolation
     d'une grille avec plusieurs zones défilantes. Le repli est donc atomique :
     le document reste visible au lieu de produire une image grise transitoire. */
}

.library-panel,
.assistant-panel {
  min-width: 0;
  min-height: 0;
  overflow-y: auto;
  background: var(--bg-sunken);
  padding: var(--s-4) var(--s-3) var(--s-6);
}

.library-panel {
  grid-area: library;
}

.viewer-shell {
  grid-area: viewer;
}

[data-panel-resizer="library"] {
  grid-area: library-resizer;
}

[data-panel-resizer="assistant"] {
  grid-area: assistant-resizer;
}

.assistant-panel {
  grid-area: assistant;
}

/* Un panneau replié sort réellement de la grille. Des pistes conservées à
   zéro pixel font perdre à Chromium la peinture du canvas et des autres zones
   défilantes. Chaque état possède donc sa propre grille, sans piste fantôme. */
.app.library-collapsed .workspace {
  grid-template-columns: minmax(360px, 1fr) var(--assistant-resizer) var(--col-assistant);
  grid-template-areas: "viewer assistant-resizer assistant";
}

.app.assistant-collapsed .workspace {
  grid-template-columns: var(--col-library) var(--library-resizer) minmax(360px, 1fr);
  grid-template-areas: "library library-resizer viewer";
}

.app.library-collapsed.assistant-collapsed .workspace,
.app.library-collapsed.assistant-empty .workspace {
  grid-template-columns: minmax(360px, 1fr);
  grid-template-areas: "viewer";
}

.app.library-collapsed .library-panel,
.app.assistant-collapsed .assistant-panel,
.app.assistant-empty .assistant-panel {
  display: none;
}

/* Le panneau de droite ne porte que ce qu'une relecture produit : les
   commentaires numérotés et la relecture dont ils sont issus. Tant qu'aucune
   n'a tourné sur le manuscrit ouvert, deux onglets vides prenaient une colonne
   entière à la visionneuse. Il est donc retiré, et non réduit comme un repli :
   il n'y a rien à retrouver dedans, et à l'étroit, où la grille est refaite,
   une colonne nulle ne suffirait pas à le faire disparaître. */
.app.assistant-empty .workspace {
  grid-template-columns: var(--col-library) var(--library-resizer) minmax(360px, 1fr);
  grid-template-areas: "library library-resizer viewer";
}

.library-panel {
  border-right: 0;
}

.assistant-panel {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  border-left: 0;
}

/* Les séparateurs occupent une zone confortable sans épaissir le filet. */
.panel-resizer {
  position: relative;
  min-width: 0;
  background: var(--bg-sunken);
  cursor: col-resize;
  touch-action: none;
  user-select: none;
}

.panel-resizer::before {
  content: "";
  position: absolute;
  inset: 0 3px;
  background: var(--line);
  transition:
    inset 140ms ease,
    background-color 140ms ease;
}

@media (hover: hover) and (pointer: fine) {
  .panel-resizer:hover::before {
    inset-inline: 2px;
    background: var(--line-strong);
  }
}

.panel-resizer:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: -2px;
}

.panel-resizer[aria-disabled="true"] {
  pointer-events: none;
}

.app.panel-resizing,
.app.panel-resizing * {
  cursor: col-resize !important;
  user-select: none !important;
}

.app.panel-resizing .workspace {
  transition: none;
}

.app.library-collapsed [data-panel-resizer="library"],
.app.assistant-collapsed [data-panel-resizer="assistant"],
.app.assistant-empty [data-panel-resizer="assistant"] {
  display: none;
}

.review-pane {
  display: flex;
  flex-direction: column;
  gap: var(--s-4);
  min-height: 0;
}

/* Le titre de panneau est un filet de tête : il sépare autant qu'il nomme. */
.panel-title {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--s-3);
  border-bottom: 1px solid var(--line);
  margin-bottom: var(--s-4);
  padding-bottom: var(--s-3);
}

.panel-title h2 {
  color: var(--text-muted);
  font-family: var(--font-meta);
  font-size: 13px;
  font-weight: var(--w-strong);
}

/* L'état du modèle passe sous les onglets, sur sa propre ligne : à côté d'eux
   il était tronqué au milieu d'un mot, ce qui se lisait comme une panne
   d'affichage plutôt que comme un état. */
/* Le titre du panneau de droite porte deux lignes, non deux colonnes : les
   onglets occupent toute la mesure, l'état du modèle se lit dessous. */
.assistant-panel .panel-title {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: var(--s-2);
}

#llmState {
  overflow: hidden;
  color: var(--text-faint);
  font-family: var(--font-meta);
  font-size: 12px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* Visionneuse, la coque porte les éléments flottants, le scroll reste au
   niveau de `.viewer` pour qu'ils ne défilent pas avec la page. */

.viewer-shell {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  min-height: 0;
  overflow: hidden;
  background: var(--bg-canvas);
}

.viewer {
  flex: 1 1 auto;
  min-height: 0;
  overflow: auto;
  display: grid;
  align-items: start;
  justify-items: center;
  padding: var(--s-7) var(--s-7) var(--pagebar-clear);
}

/* Un dépôt refusé, un transfert en cours, une bibliothèque muette : l'avis se
   place au-dessus de la visionneuse et non par-dessus elle. Il pousse le
   manuscrit vers le bas au lieu de le masquer, et reste tant que sa cause
   n'est pas levée. */
.viewer-notice {
  flex: none;
  display: flex;
  align-items: center;
  gap: var(--s-4);
  border-bottom: 1px solid var(--line);
  background: var(--bg-raised);
  padding: var(--s-3) var(--s-5);
}

.viewer-notice-text {
  flex: 0 1 auto;
  min-width: 0;
  max-width: 76ch;
}

.viewer-notice strong {
  display: block;
  color: var(--text);
  font-family: var(--font-meta);
  font-size: 13px;
  font-weight: var(--w-strong);
}

.viewer-notice p {
  margin: var(--s-1) 0 0;
  color: var(--text-muted);
  font-family: var(--font-text);
  font-size: 14px;
  line-height: 1.6;
}

.viewer-notice[data-tone="error"] {
  border-bottom-color: var(--danger);
}

.viewer-notice[data-tone="error"] strong {
  color: var(--danger);
}

.viewer-notice .progress-track {
  flex: 0 0 120px;
}

.viewer-notice-actions {
  flex: none;
  display: flex;
  gap: var(--s-2);
}

.viewer-notice-actions:empty {
  display: none;
}

/* Une barre sans mesure : elle dit qu'un transfert avance, elle ne prétend pas
   savoir de combien. */
.progress-track.indeterminate .progress-bar {
  width: 40%;
  animation: transfer-sweep 1.6s var(--ease-in-out) infinite;
}

@keyframes transfer-sweep {
  0% {
    transform: translateX(-100%);
  }
  100% {
    transform: translateX(250%);
  }
}

/* Un compte sans manuscrit est un compte neuf, pas une panne : l'accueil dit
   ce qui est accepté, ce que le dépôt coûte, et porte l'action qui commence. */
.viewer-welcome {
  display: none;
  max-width: 52ch;
  margin-top: var(--s-8);
  text-align: left;
}

.app.no-document .viewer-welcome {
  display: block;
}

.viewer-welcome h2 {
  margin: 0;
  color: var(--text);
  font-family: var(--font-display);
  font-size: 24px;
  letter-spacing: var(--track-title);
}

.viewer-welcome p {
  margin: var(--s-3) 0 0;
  color: var(--text-muted);
  font-family: var(--font-text);
  font-size: 15px;
  line-height: 1.7;
}

.viewer-welcome ul {
  margin: var(--s-5) 0 var(--s-6);
  padding-left: var(--s-5);
  color: var(--text-muted);
  font-family: var(--font-text);
  font-size: 14px;
  line-height: 1.7;
}

.viewer-welcome li {
  margin-bottom: var(--s-1);
}

.viewer-status {
  position: absolute;
  top: 16px;
  left: 50%;
  z-index: 5;
  transform: translateX(-50%);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--bg-raised);
  box-shadow: var(--shadow-md);
  color: var(--text-muted);
  padding: var(--s-1) var(--s-4);
  font-family: var(--font-meta);
  font-size: 12px;
  transition: opacity var(--t-pop) var(--ease-out), transform var(--t-pop) var(--ease-out);
}

/* Le cartouche d'état se retire vers le haut, d'où il est venu : sans cela il
   disparaissait net au milieu d'un rendu, ce qui se lisait comme une panne.
   `display: none` rendrait la transition impossible, l'opacité suffit. */
.viewer-status:empty {
  opacity: 0;
  transform: translateX(-50%) translateY(-6px);
  pointer-events: none;
}

/* La page reste du papier : blanche dans les deux thèmes, et posée, pas
   incrustée. Le liseré la détache du plan de travail comme une feuille. */
.page-surface {
  position: relative;
  border-radius: 1px;
  background: var(--ms-paper);
  box-shadow: var(--shadow-lg), 0 0 0 1px rgba(15, 23, 42, 0.14);
  line-height: 0;
}

.app.no-document .page-surface,
.app.no-document .pagebar {
  display: none;
}

#pdfCanvas {
  display: block;
  border-radius: inherit;
}

.annotation-layer {
  position: absolute;
  inset: 0;
  line-height: normal;
}

/* Un surlignage : le vélin passé sur la ligne, souligné du crimson de la
   marque. Le surlignage désigne, le trait constate. */
.annotation {
  position: absolute;
  height: auto;
  border: 0;
  border-bottom: 1.5px solid var(--ms-mark);
  border-radius: 0;
  background: var(--ms-highlight);
  padding: 0;
  cursor: pointer;
}

@media (hover: hover) and (pointer: fine) {
  .annotation:hover:not(:disabled) {
    background: var(--ms-highlight);
  }
}

.annotation.selected {
  outline: 1.5px solid var(--ms-mark);
  outline-offset: 2px;
}

/* Un commentaire numéroté : le même rond rouge que sur le PDF rendu, et que
   sur la page de présentation. */
.annotation.note {
  width: 22px;
  height: 22px;
  display: grid;
  place-items: center;
  border: 1.5px solid var(--ms-mark);
  border-radius: 50%;
  background: var(--ms-paper);
  box-shadow: var(--shadow-sm);
  color: var(--ms-mark);
  font-family: var(--font-meta);
  font-size: 11px;
  font-weight: var(--w-strong);
  letter-spacing: 0;
}

@media (hover: hover) and (pointer: fine) {
  .annotation.note:hover:not(:disabled) {
    background: var(--ms-mark);
    color: var(--ms-paper);
  }
}

.annotation.note:empty::after {
  content: "";
  width: 6px;
  height: 6px;
  border-radius: var(--r-pill);
  background: currentColor;
}

/* Barre de page : une pastille posée au-dessus du manuscrit, portée par une
   ombre puisqu'elle flotte sur lui. */

.pagebar {
  position: absolute;
  bottom: 20px;
  left: 50%;
  z-index: 6;
  transform: translateX(-50%);
  display: flex;
  align-items: center;
  gap: var(--s-half);
  border: 1px solid var(--line);
  border-radius: var(--r-pill);
  background: var(--bg-raised);
  box-shadow: var(--shadow-md);
  padding: var(--s-1) var(--s-2);
}

.pagebar button {
  height: var(--control-h-sm);
  padding: 0 var(--s-3);
  font-size: 13px;
}

.pagebar .icon-btn {
  width: var(--control-h-sm);
  padding: 0;
}

.pagebar .divider {
  height: 16px;
  margin: 0 var(--s-1);
}

.page-jump {
  display: inline-flex;
  align-items: center;
  gap: var(--s-1);
  color: var(--text-muted);
  padding: 0 var(--s-half);
  font-family: var(--font-meta);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.page-jump input {
  width: 42px;
  border: 1px solid var(--line);
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text);
  outline: 0;
  padding: var(--s-1) var(--s-1);
  font-family: var(--font-meta);
  font-size: 13px;
  text-align: center;
  -moz-appearance: textfield;
}

.page-jump input::-webkit-outer-spin-button,
.page-jump input::-webkit-inner-spin-button {
  margin: 0;
  -webkit-appearance: none;
}

.page-jump input:focus {
  border-color: var(--accent);
}

.zoom-label {
  min-width: 44px;
  color: var(--text-muted);
  font-family: var(--font-meta);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
  text-align: center;
}

/* --------------------------------------------------------------------------
   Listes du panneau
   -------------------------------------------------------------------------- */

/* Onglets du panneau de droite : commentaires de la relecture ouverte, ou
   relecture elle-même. */
/* Deux colonnes égales dans un creux, et une pastille de surface qui glisse
   de l'une à l'autre. Le fond ne s'allume pas d'un côté en s'éteignant de
   l'autre : il se déplace, ce qui dit que les deux onglets sont deux vues du
   même panneau. */
.tabs {
  position: relative;
  display: grid;
  grid-template-columns: 1fr 1fr;
  align-items: center;
  border-radius: var(--r-pill);
  background: var(--bg-hover);
  padding: var(--s-half);
}

.tabs::before {
  content: "";
  position: absolute;
  top: var(--s-half);
  bottom: var(--s-half);
  left: var(--s-half);
  width: calc(50% - var(--s-half));
  border-radius: var(--r-pill);
  background: var(--bg-raised);
  box-shadow: var(--shadow-sm);
  transition: transform var(--t-pop) var(--ease-in-out);
}

.tabs[data-active="review"]::before {
  transform: translateX(100%);
}

.tab {
  position: relative;
  z-index: 1;
  height: 28px;
  justify-content: center;
  border: 0;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--text-faint);
  padding: 0 var(--s-2);
  font-size: 13px;
  transition: color var(--t-pop) var(--ease-hover);
}

/* Le libellé actif se pose sur la pastille : c'est elle qui porte le relief,
   jamais le bouton. */
.tab.active,
.tab.active:hover:not(:disabled) {
  background: transparent;
  color: var(--text);
}

.annotation-list,
.library-list {
  display: grid;
  gap: var(--s-half);
}

.library-row {
  display: flex;
  align-items: center;
  gap: var(--s-half);
}

/* Les versions restent dans leur projet : un léger retrait suffit à montrer
   la filiation sans transformer la bibliothèque en arbre technique. */
.revision-list {
  display: grid;
  gap: var(--s-half);
  margin: 0 0 var(--s-2) var(--s-4);
  padding-left: var(--s-2);
  border-left: 1px solid var(--line);
}

.revision-item {
  width: 100%;
  height: auto;
  min-height: 42px;
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: center;
  gap: 2px var(--s-2);
  border: 0;
  border-radius: var(--r-sm);
  padding: var(--s-2) var(--s-3);
  text-align: left;
}

.revision-item.active {
  background: var(--bg-active);
}

.revision-label {
  color: var(--text);
  font-family: var(--font-meta);
  font-size: 12px;
  font-weight: var(--w-strong);
}

.revision-name {
  min-width: 0;
  overflow: hidden;
  color: var(--text-faint);
  font-family: var(--font-meta);
  font-size: 12px;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.revision-item .library-status {
  grid-column: 1 / -1;
  color: var(--text-faint);
  font-size: 11px;
}

/* Une ligne de liste n'est pas une carte : un fond arrondi suffit à dire
   laquelle est survolée, laquelle est ouverte. */
.library-item,
.annotation-item {
  width: 100%;
  height: auto;
  display: grid;
  gap: var(--s-1);
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text);
  padding: var(--s-2) var(--s-3);
  font-family: var(--font-text);
  font-size: 14px;
  font-weight: var(--w-text);
  text-align: left;
  white-space: normal;
}

.library-item {
  flex: 1;
  min-width: 0;
}

.annotation-item {
  display: block;
}

@media (hover: hover) and (pointer: fine) {
  .library-item:hover:not(:disabled),
  .annotation-item:hover:not(:disabled) {
    background: var(--bg-hover);
    color: var(--text);
  }
}

.library-item.active {
  background: var(--bg-active);
}

/* Un commentaire retenu se signale en rouge : c'est une correction, pas une
   sélection de confort. */
.annotation-item.active {
  background: var(--danger-soft);
}

.library-name {
  overflow: hidden;
  font-family: var(--font-text);
  font-size: 14px;
  font-weight: var(--w-strong);
  letter-spacing: normal;
  text-overflow: ellipsis;
  white-space: nowrap;
}

/* La ligne de pied d'une entrée : état et date sur une seule ligne, quitte à
   couper la date. Deux lignes feraient de chaque entrée un pavé. */
.library-meta {
  display: flex;
  align-items: center;
  gap: var(--s-2);
  overflow: hidden;
  color: var(--text-faint);
  font-family: var(--font-meta);
  font-size: 12px;
  white-space: nowrap;
}

.library-meta > :last-child {
  overflow: hidden;
  text-overflow: ellipsis;
}

.library-status {
  display: inline-flex;
  align-items: center;
  gap: var(--s-2);
  white-space: nowrap;
}

.library-status::before {
  content: "";
  width: 6px;
  height: 6px;
  border: 1px solid var(--text-faint);
  border-radius: var(--r-pill);
}

/* Relu : le point est plein, l'affaire est close. */
.library-status.reviewed::before {
  border-color: var(--accent);
  background: var(--accent);
}

.library-status.failed::before {
  border-color: var(--danger);
  background: var(--danger);
}

/* Une relecture en cours se signale d'elle-même : le point bat. */
.library-status.running::before,
.library-status.queued::before {
  border-color: var(--warn);
  background: var(--warn);
  animation: library-pulse 1.6s ease-in-out infinite;
}

@keyframes library-pulse {
  50% {
    opacity: 0.25;
  }
}

/* Ce qu'on peut faire d'un projet dépend de ce qu'il a produit : la ligne ne
   porte donc qu'un bouton, et le menu dit ce qui est ouvert. Il ne s'offre
   qu'à la ligne survolée, et reste visible tant qu'il est déployé. */
.library-menu {
  position: relative;
  flex: none;
}

.library-menu-trigger {
  width: var(--control-h-sm);
  height: var(--control-h-sm);
  justify-content: center;
  border: 1px solid transparent;
  border-radius: var(--r-pill);
  background: transparent;
  color: var(--text-faint);
  padding: 0;
  font-size: 15px;
  line-height: 1;
  opacity: 0;
  transition: opacity var(--t-hover) var(--ease-hover), background var(--t-hover) var(--ease-hover),
    border-color var(--t-hover) var(--ease-hover), color var(--t-hover) var(--ease-hover);
}

.library-menu-trigger:focus-visible,
.library-menu-trigger[aria-expanded="true"] {
  opacity: 1;
}

/* Le menu ne se cache derrière un survol que là où un survol existe : sur un
   écran tactile il est visible en permanence, sinon il serait inatteignable. */
@media (hover: hover) and (pointer: fine) {
  .library-row:hover .library-menu-trigger {
    opacity: 1;
  }

  .library-menu-trigger:hover {
    background: var(--bg-hover);
    color: var(--text);
  }
}

@media (hover: none) {
  .library-menu-trigger {
    opacity: 1;
  }
}

.library-menu-trigger[aria-expanded="true"] {
  background: var(--bg-active);
  color: var(--text);
}

.library-menu-list {
  position: absolute;
  top: calc(100% + var(--s-1));
  right: 0;
  z-index: 20;
  display: grid;
  min-width: 168px;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg-raised);
  box-shadow: var(--shadow-lg);
  padding: var(--s-2);
  transform-origin: top right;
  transition: opacity var(--t-pop) var(--ease-out), transform var(--t-pop) var(--ease-out);
}

/* Un intertitre, non une action : les exports sont plusieurs, la suppression
   est seule, et rien ne doit les confondre. */
.library-menu-group {
  color: var(--text-faint);
  padding: var(--s-2) var(--s-3) var(--s-1);
  font-family: var(--font-meta);
  font-size: 12px;
  font-weight: var(--w-strong);
}

.library-menu-item {
  width: 100%;
  height: auto;
  min-height: 34px;
  justify-content: flex-start;
  border: 0;
  border-radius: var(--r-sm);
  background: transparent;
  color: var(--text);
  padding: var(--s-2) var(--s-3);
  font-family: var(--font-meta);
  font-size: 14px;
  font-weight: var(--w-text);
  text-align: left;
  white-space: nowrap;
}

@media (hover: hover) and (pointer: fine) {
  .library-menu-item:hover {
    background: var(--bg-hover);
    color: var(--text);
  }

  .library-menu-item.danger:hover {
    background: var(--danger-soft);
    color: var(--danger);
  }
}

.annotation-empty {
  color: var(--text-faint);
  padding: var(--s-2) var(--s-3);
  font-family: var(--font-text);
  font-size: 14px;
  line-height: 1.6;
  white-space: pre-wrap;
}

/* Une bibliothèque qui n'a pas pu être lue porte sa cause et le moyen de
   réessayer : « Chargement » indéfini se lit comme un produit en panne. */
.library-error {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: var(--s-2);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg-sunken);
  padding: var(--s-3);
}

.library-error p {
  margin: 0;
  color: var(--text-muted);
  font-family: var(--font-text);
  font-size: 13px;
  line-height: 1.6;
}

/* Le numéro du commentaire reprend celui porté dans la marge du PDF, et la
   page où il est posé. */
.annotation-item strong {
  display: block;
  margin-bottom: var(--s-1);
  color: var(--danger);
  font-family: var(--font-meta);
  font-size: 12px;
  font-weight: var(--w-strong);
}

.annotation-item p {
  color: var(--text-muted);
  font-size: 14px;
  line-height: 1.6;
  white-space: pre-wrap;
}

/* La citation qui a permis de placer la marque : elle est rapportée, donc
   posée derrière un filet. */
.annotation-evidence {
  display: block;
  margin-top: var(--s-2);
  border-left: 2px solid var(--line);
  color: var(--text-faint);
  padding-left: var(--s-3);
  font-family: var(--font-text);
  font-size: 13px;
  line-height: 1.6;
}

/* --------------------------------------------------------------------------
   Progression et sortie de revue
   -------------------------------------------------------------------------- */

.review-progress {
  display: grid;
  gap: var(--s-3);
  flex: 0 0 auto;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--bg-raised);
  padding: var(--s-4);
}

.review-progress[hidden] {
  display: none;
}

.progress-meta {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--s-3);
}

.progress-meta strong {
  font-family: var(--font-display);
  font-size: 15px;
  font-weight: var(--w-display);
  letter-spacing: var(--track-title);
}

.progress-meta span,
.review-progress p {
  color: var(--text-muted);
  font-family: var(--font-meta);
  font-size: 13px;
  font-variant-numeric: tabular-nums;
}

.review-progress p {
  color: var(--text-faint);
  line-height: 1.6;
}

/* La progression est une barre pleine, et sa pointe bat tant qu'elle avance :
   sans ce battement, une relecture longue se lit comme une barre arrêtée. */
.progress-track {
  position: relative;
  height: 4px;
  overflow: hidden;
  border-radius: var(--r-pill);
  background: var(--bg-active);
}

.progress-bar {
  position: relative;
  width: 0%;
  height: 100%;
  border-radius: var(--r-pill);
  background: var(--accent);
  /* Elle se deplace a l'ecran, elle n'entre pas : courbe de deplacement, et
     non de decelaration. */
  transition: width 500ms var(--ease-in-out);
}

.progress-bar::after {
  content: "";
  position: absolute;
  top: 0;
  right: 0;
  width: 18px;
  height: 100%;
  border-radius: var(--r-pill);
  background: var(--solid);
  opacity: 0;
}

.progress-bar.active::after {
  opacity: 0.55;
}

.progress-bar.active::after {
  animation: progress-nib 1.4s ease-in-out infinite;
}

@keyframes progress-nib {
  50% {
    opacity: 0.12;
  }
}

/* La relecture se lit comme les commentaires : une entree par section, son
   intitule au-dessus du texte, et rien autour de l'ensemble. Un seul bloc de
   Markdown, dans la meme colonne qu'une liste, se parcourait mal. */
.review-list {
  display: grid;
  gap: var(--s-half);
}

.review-item {
  display: block;
  border-radius: var(--r-sm);
  padding: var(--s-2) var(--s-3);
  color: var(--text);
  font-family: var(--font-text);
  font-size: 14px;
  text-align: left;
  overflow-wrap: anywhere;
}

/* L'intitule de section reprend la forme de celui d'un commentaire, dans la
   couleur de l'application : il nomme, il ne corrige pas. */
.review-item strong {
  display: block;
  margin-bottom: var(--s-1);
  color: var(--accent);
  font-family: var(--font-meta);
  font-size: 12px;
  font-weight: var(--w-strong);
}

.review-item p {
  color: var(--text-muted);
  font-size: 14px;
  line-height: 1.6;
  white-space: pre-wrap;
}

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

textarea {
  width: 100%;
  min-height: 96px;
  resize: vertical;
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: var(--bg-raised);
  color: var(--text);
  outline: 0;
  padding: var(--s-3) var(--s-4);
  font-family: var(--font-text);
  font-size: 15px;
  line-height: 1.6;
}

textarea::placeholder {
  color: var(--text-faint);
}

textarea:focus {
  border-color: var(--accent);
  box-shadow: 0 0 0 3px var(--accent-ring);
}

.message {
  border-radius: var(--r-md);
  background: var(--bg-hover);
  padding: var(--s-3) var(--s-4);
  font-size: 15px;
  line-height: 1.6;
  white-space: pre-wrap;
}

.message.user {
  background: var(--accent-soft);
}

.message.assistant {
  background: var(--bg-raised);
}

.ask-form {
  display: grid;
  gap: var(--s-2);
}

.ask-form textarea {
  min-height: 82px;
}

.manual-tools,
.compat-controls {
  display: none !important;
}

/* Thème : une seule icône visible à la fois. */
#themeToggle .icon-light {
  display: none;
}

[data-theme="light"] #themeToggle .icon-light {
  display: block;
}

[data-theme="light"] #themeToggle .icon-dark {
  display: none;
}

/* --------------------------------------------------------------------------
   Ouverture de l'atelier
   Une seule orchestration, courte : les trois colonnes se posent l'une après
   l'autre, le temps que la première page s'affiche. Au-delà, un outil qui
   s'anime à chaque geste fatigue.
   -------------------------------------------------------------------------- */

@keyframes panel-settle {
  from {
    opacity: 0;
    transform: translateY(6px);
  }
}

.library-panel,
.viewer-shell,
.assistant-panel {
  animation: panel-settle var(--t-enter) var(--ease-out) both;
}

.viewer-shell {
  animation-delay: 60ms;
}

.assistant-panel {
  animation-delay: 120ms;
}

/* Moins de mouvement, pas moins de retour.
   Ce qui ne fait que changer de couleur ou d'opacité continue de le faire :
   c'est ce qui rend un survol et un enfoncement lisibles. Seuls les
   déplacements et les mises à l'échelle sont retirés. Couper tout, comme le
   faisait la règle précédente, retirait aussi le battement qui signale une
   relecture en cours, c'est-à-dire une information. */
@media (prefers-reduced-motion: reduce) {
  * {
    transition-property: opacity, color, background, background-color, border-color, box-shadow, fill, stroke !important;
  }

  .library-panel,
  .viewer-shell,
  .assistant-panel {
    animation: none !important;
  }

  .account-sheet,
  .export-sheet,
  .library-menu-list,
  .modal[open] {
    transform: none !important;
  }

  /* La barre de transfert dit qu'un dépôt est en cours : elle reste pleine
     plutôt que de balayer. */
  .progress-track.indeterminate .progress-bar {
    width: 100%;
    animation: none !important;
  }

  .tabs::before,
  .workspace {
    transition: none !important;
  }

  /* Le battement d'une relecture en cours reste, ralenti : il ne décore pas,
     il dit qu'un travail avance. */
  .library-status.running::before,
  .library-status.queued::before,
  .progress-bar.active::after {
    animation-duration: 2.8s;
  }
}

/* --------------------------------------------------------------------------
   Boîte de dialogue
   -------------------------------------------------------------------------- */

/* Une suppression est irréversible : elle se décide dans une boîte modale, qui
   nomme le manuscrit concerné et laisse la sortie la plus sûre sous le doigt. */
.modal {
  max-width: 400px;
  border: 1px solid var(--line);
  border-radius: var(--r-lg);
  background: var(--bg-raised);
  color: var(--text);
  padding: 0;
  box-shadow: var(--shadow-lg);
  /* Centrée, donc mise à l'échelle depuis son centre : elle ne sort d'aucun
     bouton, et la faire naître d'un coin la rattacherait à rien. */
  transform-origin: center;
  transition: opacity var(--t-panel) var(--ease-out), transform var(--t-panel) var(--ease-out);
}

.modal::backdrop {
  background: rgba(2, 6, 23, 0.62);
  transition: opacity var(--t-panel) var(--ease-out);
}

/* La boîte arrive, elle n'est pas déjà là : elle monte de 0.97 plutôt que de
   rien, un objet n'apparaît pas d'un point. */
@starting-style {
  .modal[open] {
    opacity: 0;
    transform: scale(0.97);
  }

  .modal[open]::backdrop {
    opacity: 0;
  }
}

.modal-card {
  display: grid;
  gap: var(--s-3);
  padding: var(--s-6);
}

.modal-card h2 {
  font-family: var(--font-display);
  font-size: 19px;
  font-weight: var(--w-display);
  letter-spacing: var(--track-title);
}

.modal-card p {
  color: var(--text-muted);
  font-size: 15px;
  line-height: 1.6;
}

/* Un message peut etre long - une erreur du serveur, la reponse a une
   question : il garde ses retours a la ligne et defile dans la boite plutot
   que de l'etirer hors de l'ecran. */
.message-body {
  max-height: 46vh;
  overflow: auto;
  white-space: pre-wrap;
  overflow-wrap: anywhere;
}

.modal-actions {
  display: flex;
  justify-content: flex-end;
  gap: var(--s-2);
  margin-top: var(--s-3);
}

.revision-modal-actions {
  flex-wrap: wrap;
}

.credit-modal {
  width: min(470px, calc(100vw - 28px));
  max-width: 470px;
  border-color: var(--line-strong);
}

.credit-modal-card {
  gap: 0;
  padding: var(--s-6);
}

.credit-modal-heading {
  display: grid;
  grid-template-columns: 44px minmax(0, 1fr);
  align-items: center;
  gap: var(--s-4);
}

.credit-mark {
  display: grid;
  place-items: center;
  width: 44px;
  height: 44px;
  border: 1px solid var(--line-strong);
  border-radius: 14px;
  background: var(--bg);
  color: var(--text-muted);
  font-family: var(--font-meta);
  font-size: 15px;
  font-variant-numeric: tabular-nums;
  box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
}

.modal-card .credit-modal-kicker {
  margin-bottom: 3px;
  color: var(--text-faint);
  font-size: 11px;
  font-weight: var(--w-strong);
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.credit-modal-card h2 {
  font-size: 21px;
  letter-spacing: -0.025em;
  line-height: 1.2;
  text-wrap: balance;
}

.modal-card .credit-modal-intro {
  max-width: 42ch;
  margin-top: var(--s-5);
  line-height: 1.55;
  text-wrap: pretty;
}

.credit-options {
  display: grid;
  gap: var(--s-2);
  margin-top: var(--s-5);
}

.credit-option {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: var(--s-4);
  width: 100%;
  height: auto;
  min-width: 0;
  min-height: 76px;
  padding: 14px var(--s-4);
  border: 1px solid var(--line);
  border-radius: var(--r-md);
  background: transparent;
  color: var(--text);
  text-align: left;
  white-space: normal;
  cursor: pointer;
  transition: border-color var(--t-hover) var(--ease-hover), background var(--t-hover) var(--ease-hover),
    color var(--t-hover) var(--ease-hover), transform var(--t-press) var(--ease-out);
}

.credit-option-copy,
.credit-option-price {
  display: grid;
  gap: 2px;
  min-width: 0;
}

.credit-option-label {
  display: flex;
  align-items: baseline;
  gap: var(--s-2);
  min-width: 0;
}

.credit-option strong {
  font-size: 14px;
  font-weight: 600;
  line-height: 1.25;
}

.credit-option small {
  color: var(--text-faint);
  font-size: 12px;
  font-weight: 400;
  line-height: 1.4;
}

.credit-option-label em {
  color: inherit;
  font-size: 11px;
  font-style: normal;
  font-weight: 500;
  opacity: 0.66;
}

.credit-option-price {
  justify-items: end;
  text-align: right;
}

.credit-option-price strong {
  font-size: 18px;
  font-variant-numeric: tabular-nums;
  letter-spacing: -0.02em;
}

.credit-option.single:hover {
  border-color: var(--line-strong);
  background: var(--bg-hover);
}

.credit-option:focus-visible {
  outline: 2px solid var(--accent-ring);
  outline-offset: 2px;
}

.credit-option:active {
  transform: scale(0.99);
}

.credit-option.recommended {
  border-color: transparent;
  background: var(--solid);
  color: var(--text-inverse);
}

.credit-option.recommended small {
  color: currentColor;
  opacity: 0.66;
}

@media (hover: hover) and (pointer: fine) {
  .credit-option.recommended:hover {
    border-color: transparent;
    background: var(--solid-hover);
    color: var(--text-inverse);
  }
}

.modal-card .credit-assurance {
  margin-top: var(--s-4);
  color: var(--text-faint);
  font-size: 12px;
  text-align: center;
}

.credit-dismiss {
  justify-self: center;
  height: auto;
  margin-top: var(--s-4);
  padding: var(--s-1) var(--s-3);
  color: var(--text-muted);
  font-size: 13px;
}

@media (max-width: 520px) {
  .credit-modal-card {
    padding: var(--s-5);
  }

  .credit-modal-heading {
    grid-template-columns: 38px minmax(0, 1fr);
    gap: var(--s-3);
  }

  .credit-mark {
    width: 38px;
    height: 38px;
    border-radius: var(--r-md);
  }

  .credit-option {
    min-height: 72px;
    padding: 12px 14px;
  }

  .credit-option-label {
    display: grid;
    gap: 0;
  }
}

/* --------------------------------------------------------------------------
   Adaptatif
   -------------------------------------------------------------------------- */

/* À l'étroit, la visionneuse prend toute la largeur et les deux panneaux
   passent dessous, l'un à côté de l'autre. Elle passe en tête par `order` :
   c'est le document qui doit rester sous les yeux. */
@media (max-width: 1180px) {
  .workspace {
    grid-template-columns: minmax(200px, 0.8fr) minmax(280px, 1.4fr);
    grid-template-rows: minmax(0, 1fr) auto;
    grid-template-areas:
      "viewer viewer"
      "library assistant";
  }

  .panel-resizer {
    display: none;
  }

  .viewer-shell {
    order: initial;
  }

  .library-panel,
  .assistant-panel {
    max-height: 340px;
    border-top: 1px solid var(--line);
  }

  .library-panel {
    border-right: 0;
  }

  /* Un panneau replié, ou vide faute de relecture, est retiré ; celui qui
     reste tient la ligne entière plutôt que de laisser une demi-largeur vide. */
  .app.library-collapsed .library-panel,
  .app.assistant-collapsed .assistant-panel {
    display: none;
  }

  .app.library-collapsed .workspace {
    grid-template-columns: 1fr;
    grid-template-areas:
      "viewer"
      "assistant";
  }

  .app.assistant-collapsed .workspace,
  .app.assistant-empty .workspace {
    grid-template-columns: 1fr;
    grid-template-areas:
      "viewer"
      "library";
  }

  .app.library-collapsed.assistant-collapsed .workspace,
  .app.library-collapsed.assistant-empty .workspace {
    grid-template-columns: 1fr;
    grid-template-areas: "viewer";
  }

  .assistant-panel {
    border-left: 1px solid var(--line-strong);
  }
}

@media (max-width: 860px) {
  .topbar {
    height: auto;
    flex-wrap: wrap;
    gap: var(--s-2);
    padding: var(--s-2) var(--s-3);
  }

  .brand-text {
    flex-wrap: wrap;
  }

  .workspace {
    grid-template-columns: 1fr;
    grid-template-rows: auto;
    grid-auto-rows: min-content;
    grid-template-areas:
      "viewer"
      "library"
      "assistant";
    overflow-y: auto;
  }

  .app.library-collapsed .workspace {
    grid-template-areas:
      "viewer"
      "assistant";
  }

  .app.assistant-collapsed .workspace,
  .app.assistant-empty .workspace {
    grid-template-areas:
      "viewer"
      "library";
  }

  .app.library-collapsed.assistant-collapsed .workspace,
  .app.library-collapsed.assistant-empty .workspace {
    grid-template-areas: "viewer";
  }

  .library-panel {
    max-height: 280px;
    border-left: 0;
    border-right: 0;
    border-top: 1px solid var(--line-strong);
  }

  .viewer-shell {
    min-height: 60vh;
  }

  .viewer {
    padding: var(--s-4) var(--s-3) calc(var(--pagebar-clear) - var(--s-2));
  }

  .assistant-panel {
    max-height: none;
  }
}
