/*
 * lequellec.xyz — landing page.
 *
 * Composition centree, colonne etroite, fond plat : nom en capitales espacees,
 * un filet, un panneau listant les depots, un lien, un selecteur de palette.
 *
 * Cinq palettes d'editeur, chacune declinee en clair et en sombre, soit dix
 * combinaisons. Toutes ont ete verifiees au ratio WCAG AA (4,5:1 pour le texte
 * courant, 3:1 pour le texte large) ; les valeurs qui echouaient a la palette
 * d'origine ont ete assombries ou eclaircies du minimum necessaire.
 *
 * Aucune ressource externe : les polices sont servies par ce meme conteneur.
 */

/* ---------- Polices ---------- */

@font-face {
  font-family: 'Manrope';
  src: url('../fonts/manrope-500.woff2') format('woff2');
  font-weight: 500;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'Manrope';
  src: url('../fonts/manrope-800.woff2') format('woff2');
  font-weight: 800;
  font-style: normal;
  font-display: swap;
}

@font-face {
  font-family: 'JetBrains Mono';
  src: url('../fonts/jetbrains-mono-400.woff2') format('woff2');
  font-weight: 400;
  font-style: normal;
  font-display: swap;
}

/* La graisse 700 est livree plutot que synthetisee : la pastille de langage est
 * le seul endroit ou du mono est demande en gras, a 0,72 em, et un gras
 * synthetique a cette taille epaissit les fûts sans redessiner les contreformes
 * — le « C » se bouchait. */
@font-face {
  font-family: 'JetBrains Mono';
  src: url('../fonts/jetbrains-mono-700.woff2') format('woff2');
  font-weight: 700;
  font-style: normal;
  font-display: swap;
}

/* ---------- Constantes non chromatiques ---------- */

:root {
  --font-sans: 'Manrope', ui-sans-serif, 'Segoe UI', Roboto, sans-serif;
  /* Le mono porte aussi le nom. Deux familles en tout : celle-ci pour tout ce
   * qui releve du systeme — nom, pied, selecteur, pastille de langage, compte
   * d'etoiles — et Manrope pour le contenu editorial. Une troisieme, reservee
   * au titre, avait ete essayee : elle donnait un nom d'une autre page que
   * celle qu'il annonce. */
  --font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  /* Largeur du panneau. Elle ne depend plus du viewport mais de la colonne :
   * `42vw` donnait au panneau 20 rem sous 762 px de large pendant que le nom
   * couvrait toute la page, soit un titre 1,4 fois plus large que le tableau
   * qu'il annonce. Les deux mesures se suivent maintenant — le panneau occupe
   * la colonne, plafonne a 46 rem, et le nom 89 % de cette meme colonne. */
  --col: min(100%, 46rem);
  /* Echelle du panneau.
   *
   * Elle depend des deux dimensions : pilotee par `vw` seul, la typographie
   * restait figee des 1440 px de large et le tableau ne pouvait plus occuper la
   * hauteur qu'en etirant ses marges.
   *
   * Le `min(..., 2.2vh)` est la contrainte qui compte : le panneau doit tenir
   * dans la hauteur restante. Sans ce plafond, une fenetre large et courte le
   * faisait grandir avec la largeur jusqu'a faire defiler la page.
   *
   * La valeur vient d'une mesure, pas d'un essai : une ligne occupe 5,3 em de
   * haut (contenu plus marges), soit 18,9 em pour le panneau entier. Sur une
   * fenetre de 600 px de haut, la place restante apres le titre, les commandes
   * et le pied est d'environ 256 px, d'ou une echelle maximale de 13,5 px, soit
   * 2,2 % de la hauteur. */
  --echelle: clamp(0.75rem, min(0.55vw + 1.1vh, 2.2vh), 3.5rem);
  /* Colonne de la page. Ramenee de 60 a 52 rem : a 60 rem le nom mesurait
   * 823 px face a un panneau de 736, et l'ecart se lisait comme un titre pose
   * sur un tableau trop petit pour lui. A 52 rem les deux tombent a une
   * quinzaine de pixels l'un de l'autre — le bloc se tient. */
  --col-wide: min(100%, 52rem);
  --dur: 180ms;
  --ease: cubic-bezier(0.2, 0.7, 0.3, 1);

  /* Pastilles du selecteur : couleurs fixes, elles designent la palette. */
  --sw-tokyo-1: #7aa2f7;
  --sw-tokyo-2: #bb9af7;
  --sw-tokyo-3: #1a1b26;
  --sw-dracula-1: #bd93f9;
  --sw-dracula-2: #ff79c6;
  --sw-dracula-3: #282a36;
  --sw-nord-1: #88c0d0;
  --sw-nord-2: #81a1c1;
  --sw-nord-3: #3b4252;
  --sw-rose-1: #c4a7e7;
  --sw-rose-2: #eb6f92;
  --sw-rose-3: #1f1d2e;
  --sw-cat-1: #cba6f7;
  --sw-cat-2: #89b4fa;
  --sw-cat-3: #1e1e2e;
}

/* ---------- Palettes ----------
 * Pour chaque palette : le bloc sombre, puis la declinaison claire, appliquee
 * soit par preference systeme (sans JavaScript), soit par choix explicite.
 */

/* Tokyo Night */
:root[data-palette='tokyo-night'] {
  color-scheme: dark;

  --bg: #16161e;
  --panel: #1a1b26;
  --fg: #c0caf5;
  --fg-strong: #e6ebff;
  --fg-muted: #8b93ba;
  --accent: #7aa2f7;
  --line: #2a2e42;
  --vif: #f7768e;
}

@media (prefers-color-scheme: light) {
  :root[data-palette='tokyo-night']:not([data-theme='dark']) {
    color-scheme: light;

    --bg: #e1e2e7;
    --panel: #d8d9df;
    --fg: #343b58;
    --fg-strong: #1c2033;
    --fg-muted: #565a6e;
    --accent: #2a54c0;
    --line: #bcbec9;
    --vif: #8c1f4f;
  }
}

:root[data-palette='tokyo-night'][data-theme='light'] {
  color-scheme: light;

  --bg: #e1e2e7;
  --panel: #d8d9df;
  --fg: #343b58;
  --fg-strong: #1c2033;
  --fg-muted: #565a6e;
  --accent: #2a54c0;
  --line: #bcbec9;
  --vif: #8c1f4f;
}

/* Dracula / Alucard */
:root[data-palette='dracula'] {
  color-scheme: dark;

  --bg: #21222c;
  --panel: #282a36;
  --fg: #f8f8f2;
  --fg-strong: #ffffff;
  --fg-muted: #a9aed0;
  --accent: #bd93f9;
  --line: #3b3d4d;
  --vif: #ff79c6;
}

@media (prefers-color-scheme: light) {
  :root[data-palette='dracula']:not([data-theme='dark']) {
    color-scheme: light;

    --bg: #fffbeb;
    --panel: #f6f0d8;
    --fg: #2a2823;
    --fg-strong: #1f1f1f;
    --fg-muted: #5f5940;
    --accent: #5a3fc0;
    --line: #ddd6bd;
    --vif: #a3144d;
  }
}

:root[data-palette='dracula'][data-theme='light'] {
  color-scheme: light;

  --bg: #fffbeb;
  --panel: #f6f0d8;
  --fg: #2a2823;
  --fg-strong: #1f1f1f;
  --fg-muted: #5f5940;
  --accent: #5a3fc0;
  --line: #ddd6bd;
  --vif: #a3144d;
}

/* Nord — Polar Night / Snow Storm. Palette par defaut, donc aussi le repli
 * applique si aucun attribut de palette n'est encore pose. */
:root,
:root[data-palette='nord'] {
  color-scheme: dark;

  --bg: #2e3440;
  --panel: #3b4252;
  --fg: #d8dee9;
  --fg-strong: #eceff4;
  --fg-muted: #a9b4c6;
  --accent: #88c0d0;
  --line: #4c566a;
  --vif: #c9a3c4;
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme='dark']),
  :root[data-palette='nord']:not([data-theme='dark']) {
    color-scheme: light;

    --bg: #eceff4;
    --panel: #e5e9f0;
    --fg: #3b4252;
    --fg-strong: #2e3440;
    --fg-muted: #4c566a;
    --accent: #2f5f88;
    --line: #d0d6e0;
    --vif: #94357f;
  }
}

:root[data-palette='nord'][data-theme='light'] {
  color-scheme: light;

  --bg: #eceff4;
  --panel: #e5e9f0;
  --fg: #3b4252;
  --fg-strong: #2e3440;
  --fg-muted: #4c566a;
  --accent: #2f5f88;
  --line: #d0d6e0;
  --vif: #94357f;
}

/* Rose Pine / Rose Pine Dawn */
:root[data-palette='rose-pine'] {
  color-scheme: dark;

  --bg: #191724;
  --panel: #1f1d2e;
  --fg: #e0def4;
  --fg-strong: #f2f0ff;
  --fg-muted: #a9a4c9;
  --accent: #c4a7e7;
  --line: #302c48;
  --vif: #eb6f92;
}

@media (prefers-color-scheme: light) {
  :root[data-palette='rose-pine']:not([data-theme='dark']) {
    color-scheme: light;

    --bg: #faf4ed;
    --panel: #f2e9e1;
    --fg: #575279;
    --fg-strong: #3d3a55;
    --fg-muted: #68647a;
    --accent: #7a4d94;
    --line: #dfd6cd;
    --vif: #a03a58;
  }
}

:root[data-palette='rose-pine'][data-theme='light'] {
  color-scheme: light;

  --bg: #faf4ed;
  --panel: #f2e9e1;
  --fg: #575279;
  --fg-strong: #3d3a55;
  --fg-muted: #68647a;
  --accent: #7a4d94;
  --line: #dfd6cd;
  --vif: #a03a58;
}

/* Catppuccin — Mocha / Latte */
:root[data-palette='catppuccin'] {
  color-scheme: dark;

  --bg: #181825;
  --panel: #1e1e2e;
  --fg: #cdd6f4;
  --fg-strong: #eff1f5;
  --fg-muted: #a6adc8;
  --accent: #cba6f7;
  --line: #313244;
  --vif: #f38ba8;
}

@media (prefers-color-scheme: light) {
  :root[data-palette='catppuccin']:not([data-theme='dark']) {
    color-scheme: light;

    --bg: #eff1f5;
    --panel: #e6e9ef;
    --fg: #4c4f69;
    --fg-strong: #3a3c52;
    --fg-muted: #5c5f77;
    --accent: #7c2fd4;
    --line: #ccd0da;
    --vif: #a02a45;
  }
}

:root[data-palette='catppuccin'][data-theme='light'] {
  color-scheme: light;

  --bg: #eff1f5;
  --panel: #e6e9ef;
  --fg: #4c4f69;
  --fg-strong: #3a3c52;
  --fg-muted: #5c5f77;
  --accent: #7c2fd4;
  --line: #ccd0da;
  --vif: #a02a45;
}

/* ---------- Base ---------- */

*,
*::before,
*::after {
  box-sizing: border-box;
}

body {
  /* Le contenu est ancre en haut : le titre doit se trouver au meme endroit
   * quelle que soit la hauteur de l'ecran. Le pied suit le contenu a distance
   * bornee, plutot que d'etre plaque en bas — une grille `1fr auto` creusait
   * plusieurs centaines de pixels entre les deux sur un ecran haut, au point
   * qu'il se lisait comme absent. */
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-start;
  min-height: 100svh;
  margin: 0;
  padding: clamp(1.5rem, 7vh, 5rem) 1.25rem clamp(1.5rem, 4vh, 3rem);
  background-color: var(--bg);
  color: var(--fg);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.55;
  -webkit-font-smoothing: antialiased;
  transition:
    background-color var(--dur) var(--ease),
    color var(--dur) var(--ease);
}

a {
  color: inherit;
  text-decoration: none;
}

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

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

.skip-link {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 3;
  padding: 0.6rem 1rem;
  background-color: var(--fg);
  color: var(--bg);
  font-size: 0.8125rem;
  transform: translateY(-150%);
}

.skip-link:focus-visible {
  transform: translateY(0);
}

/* ---------- Colonne centrale ---------- */

.identite {
  /* Un seul bloc, pour que le nom et son filet restent solidaires quand la
   * mise en page repartit les blocs sur la hauteur.
   *
   * Conteneur de requete : le nom se dimensionne sur la largeur de SA colonne,
   * pas sur celle de l'ecran. Une taille en `vw` ignorait qu'en deux colonnes
   * la place disponible est une fraction du viewport — d'ou un nom casse en
   * deux des que la fenetre n'etait pas une des tailles que j'avais testees. */
  container-type: inline-size;
  display: block;
  width: 100%;
}

main {
  /* `main` prend la hauteur restante et le panneau en absorbe la part : sans
   * cela, la moitie basse d'un grand ecran restait vide, le contenu etant de
   * taille fixe et ancre en haut. */
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  align-items: center;
  /* Rythme vertical unique.
   *
   * Quatre marges automatiques — sous le selecteur, sous le panneau, sous le
   * lien, et celle que le selecteur porte au-dessus de lui — se partagent tout
   * l'espace libre a parts egales. Les quatre intervalles de la page valent
   * donc la meme chose, quelle que soit la hauteur de l'ecran : nom, selecteur,
   * panneau, lien, pied se succedent a pas constant.
   *
   * Les repartitions inegales essayees avant donnaient toutes le meme defaut,
   * sous une forme ou une autre : deux blocs colles et un troisieme suspendu
   * dans un vide deux fois plus grand. Un intervalle qui se repete est ce qui
   * fait tenir une colonne ; il n'y a rien ici qui justifie de le rompre. */
  justify-content: flex-start;
  width: 100%;
  max-width: var(--col-wide);
  margin: 0 auto;
}

.name {
  max-width: 100%;
  margin: 0;
  color: var(--fg-strong);
  /* Mesure : « JEAN LE QUELLEC » occupe 10,49 em de large avec ce crenage. La
   * ligne tient donc tant que la taille reste sous 100/10,14 = 9,87 % de la
   * largeur du conteneur. La mesure est a refaire a chaque changement de police
   * — elle valait 10,49 em du temps de Manrope. En chasse fixe elle se retrouve
   * par le calcul : quinze signes de 0,6 em plus quinze fois 0,08 em
   * d'interlettrage, moins l'ajustement des deux espaces.
   * La valeur retenue, 8,6 %, n'est pas le maximum mais celui qui laisse au nom
   * une marge de 6 % de chaque cote — au maximum il touchait les bords de sa
   * colonne et se lisait comme deborde. Le minimum est bas a dessein — un
   * plancher trop haut reimposerait le retour a la ligne dans une colonne
   * etroite, ce que la valeur relative sert precisement a eviter. */
  font-size: min(clamp(0.75rem, 8.6cqi, 6.5rem), 13vh);
  font-family: var(--font-mono);
  font-weight: 400;
  line-height: 1.2;
  /* Une chasse fixe espace deja les lettres d'elle-meme : l'interlettrage
   * tombe de 0,16 a 0,08 em. A la valeur de la didone, le nom se disloquait en
   * quinze signes independants. */
  letter-spacing: 0.08em;
  /* L'interlettrage s'ajoute aussi a l'espace mot : on rend au mot la moitie
   * de ce qui lui a ete ajoute. */
  word-spacing: -0.04em;
  text-align: center;
  text-indent: 0.16em; /* compense l'espace ajoute apres la derniere lettre */
  text-transform: uppercase;
  transition: color var(--dur) var(--ease);
}

.rule {
  /* Proportionnel au nom : une largeur fixe de 3 rem paraissait un residu sous
   * un titre de 900 px. */
  width: clamp(3rem, 14cqi, 10rem);
  height: 1px;
  /* Rythme proportionnel a la hauteur disponible : sur un petit ecran, des
   * marges fixes faisaient defiler la page. `margin-inline: auto` est
   * necessaire depuis que le filet vit dans un bloc et non plus directement
   * dans le conteneur flex qui le centrait.
   *
   * Aucune marge basse : elle est comprise dans la hauteur du bloc d'identite
   * et venait donc s'ajouter au premier intervalle de la page, qui mesurait
   * 112 px quand les trois autres en mesuraient 76. L'espace sous le filet est
   * desormais celui que la repartition automatique lui donne, ni plus ni
   * moins — les quatre intervalles sont egaux. */
  margin: clamp(1rem, 3vh, 1.75rem) auto 0;
  border: 0;
  background-color: var(--line);
}

/* ---------- Panneau des depots ---------- */

.panel {
  display: flex;
  flex-direction: column;
  width: 100%;
  max-width: var(--col);
  padding: 0.5rem 0.25rem;
  border: 1px solid var(--line);
  border-radius: 0.75rem;
  background-color: var(--panel);
  /* Deuxieme des trois marges automatiques qui se partagent l'espace libre.
   * Voir `.pills`. */
  margin-bottom: auto;
  transition:
    background-color var(--dur) var(--ease),
    border-color var(--dur) var(--ease);
}

.repos {
  display: flex;
  flex: 1 1 auto;
  flex-direction: column;
  margin: 0;
  padding: 0;
  list-style: none;
}

/* Les lignes ne s'etirent plus : leur hauteur vient de leur propre echelle
 * typographique. Marges en `em` : elles suivent la taille du texte, donc la
 * ligne grandit d'un bloc au lieu d'etre etiree. */
.repo {
  position: relative;
  display: flex;
  flex-direction: column;
  justify-content: center;
  padding: 1em 1.15em 1.1em;
  border-top: 1px solid var(--line);
  font-size: var(--echelle);
}

.repo:first-child {
  border-top: 0;
}

/* Marque de survol : un filet d'accent contre le bord gauche de la ligne, qui
 * se deploie du centre. Seul le nom changeait de couleur, ce qui ne signalait
 * rien tant que le curseur n'etait pas exactement dessus alors que la ligne
 * entiere est cliquable. Un fond de survol aurait demande un onzieme jeton par
 * palette ; un filet se contente de l'accent existant. */
.repo::before {
  content: '';
  position: absolute;
  top: 0.55em;
  bottom: 0.55em;
  left: 0;
  width: 2px;
  border-radius: 999px;
  background-color: var(--accent);
  transform: scaleY(0);
  transition: transform var(--dur) var(--ease);
}

.repo:hover::before,
.repo:focus-within::before {
  transform: scaleY(1);
}

.repo__link {
  /* Centrage et non alignement sur la ligne de base : la pastille de langage
   * est desormais une capsule de hauteur fixe. Alignee par sa base, elle
   * pendait sous le nom d'une fraction de cadratin. */
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  min-width: 0;
}

.repo__name {
  /* Le nom tient sur une ligne et se tronque au besoin : le laisser passer a la
   * ligne faisait grandir le panneau jusqu'a faire defiler la page sur une
   * fenetre etroite. */
  overflow: hidden;
  min-width: 0;
  font-size: 1.08em;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-weight: 800;
  letter-spacing: -0.01em;
  transition: color var(--dur) var(--ease);
}

.repo__link:hover .repo__name,
.repo__link:focus-visible .repo__name {
  color: var(--accent);
}

.repo__stars {
  /* Largeur minimale : sans elle, le compteur dictait la position du badge de
   * langage, qui se decalait d'une ligne a l'autre selon le nombre d'etoiles et
   * dessinait une diagonale.
   *
   * La couleur ne vient plus d'un jeton `--star` dore : cet or etait la seule
   * teinte de la page a n'appartenir a aucune des cinq palettes, et il jurait
   * avec quatre d'entre elles. L'etoile prend `--vif`, la couleur vive que
   * chaque palette possede deja ; le compte reste dans la couleur du texte
   * courant, pour que le chiffre se lise et que la couleur signale. */
  flex: none;
  min-width: 3.4em;
  color: var(--fg);
  font-family: var(--font-mono);
  font-size: 0.82em;
  font-variant-numeric: tabular-nums;
  text-align: right;
}

.repo__stars > span {
  color: var(--vif);
}

/* Langage et etoiles forment un seul groupe a droite du nom : le badge de
 * langage se retrouvait seul sur une deuxieme ligne des qu'un depot n'avait pas
 * de description, et flottait dans le vide. */
.repo__aside {
  display: flex;
  flex: none;
  gap: 0.7em;
  align-items: center;
}

.repo__lang {
  /* Capsule cerclee et ecrite dans `--vif`.
   *
   * Le contour d'un pixel en `--line` sur du texte `--fg` donnait une etiquette
   * de la meme valeur que la description posee juste dessous : deux gris
   * voisins, la pastille se lisait comme un fragment de prose encadre. Ce n'est
   * pas la forme qui manquait mais la teinte — c'est la couleur vive de la
   * palette qui separe l'etiquette de la prose, pas un cadre de plus.
   *
   * La geometrie est ce qui la rendait bancale : un remplissage asymetrique
   * (0,15em en haut, 0,2em en bas) sur une boite dont la hauteur dependait de
   * l'interlignage. Sur une seule lettre — le cas le plus frequent, « C », « GO »
   * — la capsule sortait ecrasee et de travers. Hauteur fixe, remplissage
   * horizontal seul, largeur minimale : une lettre ou quatre donnent la meme
   * forme. */
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  min-width: 2.6em;
  height: 1.75em;
  padding: 0 0.65em;
  border: 1px solid var(--accent);
  border-radius: 999px;
  color: var(--accent);
  font-family: var(--font-mono);
  font-size: 0.72em;
  font-weight: 700;
  line-height: 1;
  letter-spacing: 0.1em;
  text-indent: 0.1em; /* compense l'espace ajoute apres la derniere lettre */
  text-transform: uppercase;
  transition:
    color var(--dur) var(--ease),
    border-color var(--dur) var(--ease);
}

.repo__desc {
  overflow: hidden;
  margin: 0.4em 0 0;
  color: var(--fg-muted);
  font-size: 0.92em;
  text-overflow: ellipsis;
  white-space: nowrap;
}


/* ---------- Lien sortant ----------
 * Action de contenu : c'est le seul lien de la page, il doit peser plus que le
 * selecteur de theme, qui n'est qu'une preference d'affichage.
 */

.pills {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
  justify-content: center;
  /* Trois marges automatiques se partagent l'espace libre — apres le nom, apres
   * le panneau, apres le lien. Deux suffisaient a la composition mais pas a la
   * page : sur un ecran de 1440 px de haut, deux intervalles absorbent 320 px
   * chacun, soit 22 % de la hauteur, et le lien GitHub se retrouve suspendu au
   * milieu d'un vide. A trois, le meme espace donne 15 %, et le rythme reste le
   * meme d'un ecran a l'autre. */
  margin-top: 0;
  margin-bottom: auto;
}

.pill {
  display: inline-flex;
  align-items: center;
  gap: 0.6rem;
  min-height: 3rem;
  padding: 0 1.6rem;
  /* Repos neutre : un contour d'accent permanent faisait lire le bouton comme
   * selectionne ou focalise, et ne laissait rien a changer au survol. La
   * hierarchie vient de la taille et du fond, pas d'une couleur d'etat. */
  border: 1px solid var(--line);
  border-radius: 999px;
  background-color: var(--panel);
  font-size: 0.9375rem;
  font-weight: 800;
  transition:
    color var(--dur) var(--ease),
    border-color var(--dur) var(--ease);
}

.pill:hover,
.pill:focus-visible {
  color: var(--accent);
  border-color: var(--accent);
}

.pill__icon {
  flex: none;
}

/* ---------- Selecteur de palette ---------- */

.themes {
  /* Entre le nom et le tableau. Ni sous le panneau — il l'y separait du lien
   * GitHub, seul lien de la page, qu'il repoussait loin de la liste dont il est
   * la source — ni en coin superieur droit, ou six commandes alignees pesaient
   * autant que le titre qu'elles surplombaient.
   *
   * Sa largeur n'est pas bornee a celle du panneau : le conteneur de requete
   * ci-dessous se mesure sur elle, et la limiter a `--col` (20 rem sous 762 px
   * de fenetre) aurait masque les libelles bien avant que la place manque. La
   * rangee, elle, reste centree sur l'axe du panneau.
   *
   * Conteneur de requete : le selecteur decide d'afficher ou non ses libelles
   * d'apres SA largeur disponible, pas d'apres celle de l'ecran. Sa largeur
   * doit donc venir du parent — une requete de conteneur sur un element
   * dimensionne par son contenu est circulaire, et le navigateur repond alors
   * avec la largeur maximale, si bien que la requete ne declenche jamais. */
  container-type: inline-size;
  width: 100%;
  /* Les deux marges sont automatiques : le selecteur se place exactement au
   * milieu entre le filet du nom et le bord du panneau. Colle sous le panneau,
   * puis colle au-dessus, il se lisait chaque fois comme un appendice de
   * celui-ci ; a mi-distance il devient une station du rythme, au meme titre
   * que les autres. */
  margin-block: auto;
}

.themes__row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.3rem;
  align-items: center;
  justify-content: center;
}

.swatch {
  display: inline-flex;
  align-items: center;
  gap: 0.35rem;
  min-height: 2.25rem;
  /* Remplissage reduit de 0,6 a 0,4 rem : c'est ce qui fait entrer la rangee
   * complete sous les 32 rem, donc reapparaitre les libelles des 560 px de
   * fenetre au lieu de 620. Le contour ayant disparu, ce remplissage ne
   * separait plus rien — il n'ecartait que les libelles les uns des autres. */
  padding: 0 0.4rem;
  /* Le fond d'un bouton de ce selecteur ne doit JAMAIS valoir `--bg` : pose sur
   * le fond de la page, un bouton de la couleur du fond n'est plus un bouton,
   * c'est un libelle flottant, et rien n'indique ou l'on peut cliquer. Il porte
   * donc `--panel`, la seule autre surface de la page, comme le lien GitHub. La
   * hierarchie entre les deux vient de la taille et de la graisse du texte, pas
   * de l'effacement de l'un des deux. */
  border: 1px solid var(--line);
  border-radius: 999px;
  background-color: var(--panel);
  color: var(--fg-muted);
  font-family: var(--font-mono);
  font-size: 0.65rem;
  letter-spacing: 0.03em;
  white-space: nowrap;
  cursor: pointer;
  transition:
    color var(--dur) var(--ease),
    background-color var(--dur) var(--ease),
    border-color var(--dur) var(--ease);
}


/* Au survol et une fois choisie, chaque pastille s'exprime dans la couleur
 * d'accent de la palette qu'elle designe. Les 50 combinaisons (5 accents x 10
 * fonds) ont ete verifiees : le pire ratio est de 4,89:1, donc au-dessus du
 * seuil AA. */
.swatch:hover,
.swatch[aria-pressed='true'] {
  color: var(--sw-accent, var(--fg));
  border-color: var(--sw-accent, var(--fg-muted));
}

.swatch--tokyo {
  --sw-accent: #7aa2f7;
}

.swatch--dracula {
  --sw-accent: #bd93f9;
}

.swatch--nord {
  --sw-accent: #88c0d0;
}

.swatch--rose {
  --sw-accent: #c4a7e7;
}

.swatch--cat {
  --sw-accent: #cba6f7;
}

/* En clair, chaque accent bascule sur sa variante foncee. */
:root[data-theme='light'] .swatch--tokyo {
  --sw-accent: #2a54c0;
}

:root[data-theme='light'] .swatch--dracula {
  --sw-accent: #5a3fc0;
}

:root[data-theme='light'] .swatch--nord {
  --sw-accent: #2f5f88;
}

:root[data-theme='light'] .swatch--rose {
  --sw-accent: #7a4d94;
}

:root[data-theme='light'] .swatch--cat {
  --sw-accent: #7c2fd4;
}

@media (prefers-color-scheme: light) {
  :root:not([data-theme='dark']) .swatch--tokyo {
    --sw-accent: #2a54c0;
  }

  :root:not([data-theme='dark']) .swatch--dracula {
    --sw-accent: #5a3fc0;
  }

  :root:not([data-theme='dark']) .swatch--nord {
    --sw-accent: #2f5f88;
  }

  :root:not([data-theme='dark']) .swatch--rose {
    --sw-accent: #7a4d94;
  }

  :root:not([data-theme='dark']) .swatch--cat {
    --sw-accent: #7c2fd4;
  }
}

.swatch--mode:hover,
.swatch--mode[aria-pressed='true'] {
  color: var(--fg-strong);
  border-color: var(--fg-muted);
}

/* La pastille montre les couleurs de la palette qu'elle designe : elles sont
 * donc fixes, independantes de la palette active. */
.swatch__chip {
  flex: none;
  width: 1.1rem;
  height: 0.45rem;
  border-radius: 999px;
}

.swatch--tokyo .swatch__chip {
  background-image: linear-gradient(
    90deg,
    var(--sw-tokyo-1) 0 33%,
    var(--sw-tokyo-2) 33% 66%,
    var(--sw-tokyo-3) 66% 100%
  );
}

.swatch--dracula .swatch__chip {
  background-image: linear-gradient(
    90deg,
    var(--sw-dracula-1) 0 33%,
    var(--sw-dracula-2) 33% 66%,
    var(--sw-dracula-3) 66% 100%
  );
}

.swatch--nord .swatch__chip {
  background-image: linear-gradient(
    90deg,
    var(--sw-nord-1) 0 33%,
    var(--sw-nord-2) 33% 66%,
    var(--sw-nord-3) 66% 100%
  );
}

.swatch--rose .swatch__chip {
  background-image: linear-gradient(
    90deg,
    var(--sw-rose-1) 0 33%,
    var(--sw-rose-2) 33% 66%,
    var(--sw-rose-3) 66% 100%
  );
}

.swatch--cat .swatch__chip {
  background-image: linear-gradient(
    90deg,
    var(--sw-cat-1) 0 33%,
    var(--sw-cat-2) 33% 66%,
    var(--sw-cat-3) 66% 100%
  );
}

/* Le bouton clair/sombre n'est pas une sixieme palette : un ecart le detache
 * des cinq, sans quoi la rangee se lisait comme six choix exclusifs. Un filet
 * de separation en plus des contours aurait fait un trait de trop. */
.swatch--mode {
  margin-left: 0.6rem;
  padding: 0 0.6rem;
}

.theme-glyph {
  flex: none;
  width: 0.75rem;
  height: 0.75rem;
  border: 1px solid currentcolor;
  border-radius: 50%;
  background-image: linear-gradient(to right, currentcolor 50%, transparent 50%);
}

/* ---------- Pied ---------- */

.foot {
  margin-top: 0;
  color: var(--fg-muted);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.24em;
  text-align: center;
  text-indent: 0.24em;
  text-transform: uppercase;
}

/* ---------- Entree en scene ----------
 * Une seule orchestration breve au chargement, en CSS pur : la page s'affiche
 * donc aussi sans JavaScript. Rien ne bouge ensuite.
 */

@keyframes rise {
  from {
    opacity: 0;
    transform: translateY(0.6rem);
  }

  to {
    opacity: 1;
    transform: none;
  }
}

.name,
.rule,
.panel,
.pills,
.themes,
.foot {
  animation: rise 500ms var(--ease) both;
}

.rule {
  animation-delay: 80ms;
}

.panel {
  animation-delay: 140ms;
}

.pills {
  animation-delay: 210ms;
}

.themes {
  animation-delay: 280ms;
}

.foot {
  animation-delay: 340ms;
}

@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    animation: none !important;
    transition: none !important;
  }
}

/* ---------- Ecran bas : deux colonnes ----------
 * En paysage sur telephone, ou dans une fenetre de bureau ecrasee, la pile
 * verticale ne tient pas dans la hauteur — et la page ne doit jamais defiler.
 * Le contenu se reorganise donc en deux colonnes : identite et lien a gauche,
 * panneau des depots a droite. Le selecteur reste en rail lateral.
 */

@media (max-height: 34rem) and (orientation: landscape) {
  body {
    padding-top: 1rem;
    padding-bottom: 1rem;
  }

  main {
    display: grid;
    /* Le selecteur court sur les deux colonnes : confine dans la colonne
     * gauche, il passait sur deux lignes des 640 px de large. */
    grid-template-areas:
      'identite panneau'
      'liens    panneau'
      'themes   themes';
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.15fr);
    /* La rangee du milieu s'etire : le panneau, qui la couvre, occupe donc
     * toute la hauteur, tandis que le lien reste cale sous le titre par son
     * `align-self: start`. Avec des rangees toutes automatiques, le panneau
     * s'arretait a mi-hauteur et laissait la moitie basse vide.
     *
     * Le selecteur occupe la derniere rangee et non sa place du flux vertical :
     * la hauteur est ici la ressource rare, et l'intercaler entre le titre et le
     * panneau aurait coute une rangee a chacun. Il court sur les deux colonnes —
     * confine dans la gauche, il passait sur deux lignes des 640 px de large. */
    grid-template-rows: auto 1fr auto;
    align-content: stretch;
    column-gap: clamp(1.5rem, 4vw, 3rem);
    max-width: min(100%, 56rem);
  }

  .identite {
    grid-area: identite;
  }

  .name {
    text-align: left;
    text-indent: 0;
  }

  .rule {
    margin: 0.75rem 0;
    margin-inline: 0;
  }

  .panel {
    /* Le panneau s'etire sur la hauteur de la grille : il occupe l'espace que
     * l'ancrage haut libere sous le titre. La marge automatique de la mise en
     * page en colonne doit etre annulee — sur une piste de grille elle
     * l'emporte sur `align-self: stretch` et recollerait le panneau en haut. */
    grid-area: panneau;
    align-self: stretch;
    max-width: none;
    margin-bottom: 0;
  }

  .pills {
    grid-area: liens;
    align-self: start;
    justify-content: flex-start;
    margin-top: 0.75rem;
    margin-bottom: 0;
  }

  .themes {
    grid-area: themes;
    justify-self: stretch;
    margin-top: 0.75rem;
    margin-bottom: 0;
  }

  .foot {
    margin-top: 0.75rem;
  }

  /* Une description longue ferait grandir le panneau au-dela de la hauteur
   * disponible : elle passe sur la meme ligne que le langage, tronquee.
   *
   * Les lignes se partagent la hauteur, contrairement a la mise en page en
   * colonne ou elles gardent celle de leur texte. C'est le seul cas ou le
   * panneau a une hauteur imposee de l'exterieur — il doit couvrir la colonne
   * de droite — et les lignes serrees en haut y laissaient la moitie basse
   * vide, une boite a moitie remplie. Elles ne sont pas etirees par choix
   * typographique mais parce que la place est deja prise. */
  .repo {
    flex: 1 1 auto;
    padding-block: 0.5rem 0.6rem;
  }

  .repo__desc {
    overflow: hidden;
    white-space: nowrap;
    text-overflow: ellipsis;
  }
}

/* Telephone en portrait.
 *
 * Flux vertical simple, tout centre sur l'axe de l'ecran. Le selecteur reste
 * en bas, en une seule ligne : les libelles cedent la place aux seules
 * pastilles de couleur, ce qui suffit a le faire tenir sur la largeur.
 */
/* Le selecteur bascule en pastilles seules quand son propre conteneur ne peut
 * plus afficher les libelles. Le seuil n'est pas choisi, il est mesure : la
 * rangee complete occupait 568 px, soit 35,5 rem, et le seuil valait 35 rem —
 * les libelles ne revenaient donc qu'a partir d'environ 620 px de fenetre.
 * Remplissage, ecart et pastilles resserres, elle occupe 515 px, soit 32,2 rem.
 * Le seuil descend a 32,5 rem, ce qui ramene les libelles des 560 px de
 * fenetre. Requete de conteneur et non de viewport : en deux colonnes, la place
 * disponible n'a rien a voir avec la largeur de l'ecran. */
@container (max-width: 32.5rem) {
  .themes__row {
    gap: 0.25rem;
  }

  .swatch {
    justify-content: center;
    width: 2.5rem;
    min-height: 2.5rem;
    padding: 0;
  }

  .swatch > span:not(.swatch__chip):not(.theme-glyph) {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
    border: 0;
  }

  .swatch__chip {
    width: 1.2rem;
    height: 0.55rem;
  }

  .theme-glyph {
    width: 0.95rem;
    height: 0.95rem;
    color: var(--fg);
  }
}

/* Fenetre courte : on resserre le rythme vertical. Sans cela, la page depassait
 * de quelques pixels seulement — assez pour faire apparaitre une barre de
 * defilement, ce que la page ne doit jamais faire. */
@media (max-height: 34rem) {
  body {
    padding-block: 1rem;
  }

  .rule {
    margin-block: 0.6rem;
  }

  .pills,
  .foot {
    margin-top: 0.6rem;
  }
}
