/* =========================================================================
   HARDBASS.FR — Панелька
   -------------------------------------------------------------------------
   La refonte : béton, contours épais, ombres franches, étiquettes en
   cyrillique, et le bloc de la page d'accueil. Claire, sombre, ou au gré de
   l'appareil.

   Cette feuille se pose PAR-DESSUS hardbass.css, qui reste chargée : tout ce
   qu'elle ne redessine pas garde l'allure d'origine au lieu de tomber sans
   style. Le serveur ne l'envoie qu'aux visiteurs qui ont gardé Панелька ;
   l'ancienne allure ne la télécharge pas.

   Aucune couche ici, et c'est voulu : une règle hors couche
   l'emporte sur toutes celles qui en ont une, quelle que soit sa spécificité.
   La feuille d'origine range ses composants en couches, mais garde aussi des
   règles hors couche en fin de fichier ; venir après elle, à spécificité
   égale, suffit à les recouvrir.

   Polices : Unbounded, Golos Text et IBM Plex Mono, licence SIL OFL 1.1,
   servies par le site (paquets Fontsource 5.3.0, sous-ensembles latin et
   cyrillique). Aucun appel à un tiers : la politique de sécurité n'admet que
   l'origine, et un appel distant exposerait l'adresse de chaque visiteur.

   Mouvement réduit : le garde-fou de hardbass.css vise « * », « ::before » et
   « ::after » avec !important — durées et retards ramenés à rien. Il couvre
   donc tout ce qui s'anime ici. Ne restent en fin de feuille que les états
   figés qu'un mouvement abrégé ne suffit pas à rendre lisibles : le spectre
   de la une, les anneaux des touches de lecture.
   ========================================================================= */

/* ------------------------------------------------------------------ polices */

/*
  Deux fichiers par famille, découpés par « unicode-range » : le navigateur ne
  télécharge le cyrillique que si la page en contient. Unbounded et Golos Text
  sont des polices variables — un seul fichier couvre toutes les graisses.

  Les adresses portent l'empreinte que la publication donne à chaque fichier :
  servie sous ce nom, une police se garde un an sans jamais être redemandée.
  Sous son nom nu, elle revenait se faire revalider toutes les heures — huit
  allers-retours par chargement complet, avant que le texte ne prenne sa
  police. La feuille ne suit pas l'empreinte d'elle-même : elle est écrite
  ici, et une épreuve vérifie que chaque adresse sert bien la police d'origine,
  gardée un an. Changer une police change son empreinte — l'épreuve le dit.
*/
@font-face {
  font-family: "Unbounded";
  font-style: normal;
  font-weight: 200 900;
  font-display: swap;
  src: url("../fonts/unbounded-latin-wght.62ps5tmq76.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Unbounded";
  font-style: normal;
  font-weight: 200 900;
  font-display: swap;
  src: url("../fonts/unbounded-cyrillic-wght.ra6ouu4eh4.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "Golos Text";
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url("../fonts/golos-text-latin-wght.e36bytcrrr.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}

@font-face {
  font-family: "Golos Text";
  font-style: normal;
  font-weight: 400 900;
  font-display: swap;
  src: url("../fonts/golos-text-cyrillic-wght.p0ptohxg14.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/ibm-plex-mono-latin-400.cn3ilp54rs.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/ibm-plex-mono-latin-600.lmeovgkbnd.woff2") format("woff2");
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC,
    U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215,
    U+FEFF, U+FFFD;
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 400;
  font-display: swap;
  src: url("../fonts/ibm-plex-mono-cyrillic-400.ebrhqbopo3.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

@font-face {
  font-family: "IBM Plex Mono";
  font-style: normal;
  font-weight: 600;
  font-display: swap;
  src: url("../fonts/ibm-plex-mono-cyrillic-600.54wx6dk2ae.woff2") format("woff2");
  unicode-range: U+0301, U+0400-045F, U+0490-0491, U+04B0-04B1, U+2116;
}

/* ------------------------------------------------------------------ jetons */

/*
  Deux jeux de couleurs, un seul jeu de composants : le sombre ne redéfinit
  que des variables. Le clair est posé sur la racine ; « sombre » le remplace,
  et « auto » ne le remplace que si l'appareil le demande.

  L'accent orange n'est jamais une couleur de texte courant. Sur le béton
  clair il plafonne à 2,8:1 — sous le seuil de lecture. Le texte qui doit
  porter l'accent prend « --pk-accent-encre », une teinte assombrie ou
  éclaircie selon l'éclairage : 4,7:1 sur le béton, 5,4 sur les panneaux,
  4,9 sur une ligne survolée. La précédente annonçait 5:1 et en donnait 4,41
  sur le béton ; un test recalcule désormais ces rapports sur chaque fond.
*/
:root {
  color-scheme: light;

  --pk-bg: #e4e2dd;
  --pk-panel: #f4f2ed;
  --pk-champ: #ffffff;
  --pk-encre: #111111;
  --pk-doux: #33363b;
  --pk-discret: #5c5a55;
  --pk-trait: #111111;
  --pk-fin: #cfcbc3;
  --pk-ombre: #111111;
  --pk-plein: #111111;
  --pk-sur-plein: #f4f2ed;
  --pk-survol: #e9e6df;
  --pk-accent: #ff5a1f;
  --pk-accent-encre: #ad3d0a;
  --pk-sur-accent: #111111;
  --pk-ok: #1a7035;
  --pk-grave: #b3121c;
  --pk-info: #1f45d6;
  --pk-papier: #ffffff;

  /* Le bloc, de jour. */
  --bk-ciel-haut: #c3cdd4;
  --bk-ciel-bas: #e4e2dd;
  --bk-etoile: transparent;
  --bk-lune: transparent;
  --bk-lune-ombre: transparent;
  --bk-panneau-1: #cfcac0;
  --bk-panneau-2: #c7c2b7;
  --bk-panneau-3: #d9d4cb;
  --bk-joint: #8c877d;
  --bk-vitre: #95a3ac;
  --bk-cadre: rgb(25 25 28 / 0.55);
  --bk-escalier: #a7b3b8;
  --bk-pignon: #b9b4aa;
  --bk-pignon-chiffre: #f4f2ed;
  --bk-soubassement: #6e6a63;
  --bk-trottoir: #8f8b83;
  --bk-bordure: #a9a59d;
  --bk-feuillage: #5f7f4f;
  --bk-metal: #3a3b3f;
  --bk-halo: transparent;
  --bk-ampoule: #cfcbc3;
  --bk-lueur: transparent;
}

:root[data-theme="sombre"] {
  color-scheme: dark;

  --pk-bg: #1f2023;
  --pk-panel: #151618;
  --pk-champ: #0e0f10;
  --pk-encre: #e9e6df;
  --pk-doux: #c9c6bf;
  --pk-discret: #a9a6a0;
  --pk-trait: #e9e6df;
  --pk-fin: #3a3b3f;
  --pk-ombre: #000000;
  --pk-plein: #e9e6df;
  --pk-sur-plein: #0a0a0b;
  --pk-survol: #1c1d20;
  --pk-accent-encre: #ff8a5c;
  --pk-ok: #7bd389;
  --pk-grave: #ff6b6b;
  --pk-info: #8fa8ff;
  --pk-papier: #e9e6df;

  /* Le bloc, de nuit. */
  --bk-ciel-haut: #0d1017;
  --bk-ciel-bas: #262932;
  --bk-etoile: rgb(255 250 235 / 0.85);
  --bk-lune: #efe7cf;
  --bk-lune-ombre: rgb(0 0 0 / 0.14);
  --bk-panneau-1: #3b3e44;
  --bk-panneau-2: #35383e;
  --bk-panneau-3: #43464c;
  --bk-joint: #1c1e22;
  --bk-vitre: #1a1c21;
  --bk-cadre: rgb(8 8 10 / 0.7);
  --bk-escalier: #c8cd8e;
  --bk-pignon: #2d3035;
  --bk-pignon-chiffre: #6e737b;
  --bk-soubassement: #18191c;
  --bk-trottoir: #26272b;
  --bk-bordure: #34353a;
  --bk-feuillage: #1d2f1e;
  --bk-metal: #0f1012;
  --bk-halo: rgb(255 176 80 / 0.42);
  --bk-ampoule: #ffd58a;
  --bk-lueur: rgb(255 190 110 / 0.7);
}

@media (prefers-color-scheme: dark) {
  :root[data-theme="auto"] {
    color-scheme: dark;

    --pk-bg: #1f2023;
    --pk-panel: #151618;
    --pk-champ: #0e0f10;
    --pk-encre: #e9e6df;
    --pk-doux: #c9c6bf;
    --pk-discret: #a9a6a0;
    --pk-trait: #e9e6df;
    --pk-fin: #3a3b3f;
    --pk-ombre: #000000;
    --pk-plein: #e9e6df;
    --pk-sur-plein: #0a0a0b;
    --pk-survol: #1c1d20;
    --pk-accent-encre: #ff8a5c;
    --pk-ok: #7bd389;
    --pk-grave: #ff6b6b;
    --pk-info: #8fa8ff;
    --pk-papier: #e9e6df;

    --bk-ciel-haut: #0d1017;
    --bk-ciel-bas: #262932;
    --bk-etoile: rgb(255 250 235 / 0.85);
    --bk-lune: #efe7cf;
    --bk-lune-ombre: rgb(0 0 0 / 0.14);
    --bk-panneau-1: #3b3e44;
    --bk-panneau-2: #35383e;
    --bk-panneau-3: #43464c;
    --bk-joint: #1c1e22;
    --bk-vitre: #1a1c21;
    --bk-cadre: rgb(8 8 10 / 0.7);
    --bk-escalier: #c8cd8e;
    --bk-pignon: #2d3035;
    --bk-pignon-chiffre: #6e737b;
    --bk-soubassement: #18191c;
    --bk-trottoir: #26272b;
    --bk-bordure: #34353a;
    --bk-feuillage: #1d2f1e;
    --bk-metal: #0f1012;
    --bk-halo: rgb(255 176 80 / 0.42);
    --bk-ampoule: #ffd58a;
    --bk-lueur: rgb(255 190 110 / 0.7);
  }
}

/*
  Les variables de la feuille d'origine, rebranchées sur celles d'ici.

  C'est ce qui fait l'essentiel de la bascule : chaque composant de
  hardbass.css lit ses couleurs dans ces noms, il change donc d'allure sans
  être réécrit. Les règles plus bas ne reprennent que ce qu'un jeu de couleurs
  ne suffit pas à changer — contours, ombres, typographie.
*/
:root {
  --ink-950: var(--pk-bg);
  --ink-900: var(--pk-panel);
  --ink-850: var(--pk-champ);
  --ink-800: var(--pk-survol);
  --ink-700: var(--pk-fin);
  --ink-600: var(--pk-discret);

  --chalk: var(--pk-encre);
  --smoke: var(--pk-doux);
  --smoke-dim: var(--pk-discret);

  --red: var(--pk-accent);
  --red-hot: var(--pk-accent-encre);
  --red-dim: color-mix(in oklab, var(--pk-accent) 55%, var(--pk-panel));

  --ice: var(--pk-info);
  --ice-dim: color-mix(in oklab, var(--pk-info) 60%, var(--pk-panel));

  --surface: var(--pk-panel);
  --surface-raised: var(--pk-champ);
  --line: var(--pk-fin);
  --line-strong: var(--pk-trait);

  --radius: 0;
  --shadow-panel: 6px 6px 0 var(--pk-ombre);

  --font-display: "Unbounded", "Arial Black", system-ui, sans-serif;
  --font-body: "Golos Text", ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
  --font-mono: "IBM Plex Mono", ui-monospace, "SF Mono", "Cascadia Mono", Menlo, monospace;

  --pk-ressort: cubic-bezier(0.3, 1.6, 0.5, 1);
}

/*
  Défilement vers un élément — lien d'évitement, ancre, focus au clavier :
  il s'arrête sous l'en-tête collant et au-dessus du lecteur, au lieu de
  poser l'élément dessous. Le haut couvre l'en-tête sur une ligne ; ses
  variantes plus hautes ajustent la valeur plus bas.
*/
html {
  scroll-padding-block: 5.5rem calc(var(--dock-height) + 1rem + env(safe-area-inset-bottom));
}

/* -------------------------------------------------------------------- base */

/*
  Le passage d'un éclairage à l'autre se fond plutôt que de couper. Le choix
  se fait sans recharger la page : sans transition, tout le site changerait
  de couleur d'un coup sec sous le doigt.
*/
body,
.site-header,
.site-footer,
.panel,
.dock {
  transition:
    background-color 350ms ease,
    color 350ms ease,
    border-color 350ms ease;
}

body {
  background-color: var(--pk-bg);
  color: var(--pk-encre);
  font-family: var(--font-body);
}

/* Les trois barres et le grain de l'ancienne allure n'ont rien à faire sur du
   béton. Le lecteur règle encore l'opacité des barres au rythme des basses :
   cachées, elles ne coûtent qu'une écriture ignorée. */
body::before,
.stripes {
  display: none;
}

h1,
h2,
h3 {
  font-family: var(--font-display);
  font-weight: 900;
  letter-spacing: -0.02em;
}

a:hover {
  color: var(--pk-accent-encre);
}

::selection {
  background: var(--pk-accent);
  color: var(--pk-sur-accent);
}

:focus-visible {
  outline: 3px solid var(--pk-info);
  outline-offset: 2px;
}

/*
  Le lien d'évitement, en plaque orange à l'encre noire dans les deux
  éclairages. La feuille d'origine l'écrit à la craie : sur l'orange, de
  nuit, 2,5:1 — et le survol général y posait l'accent assombri, 1,3:1.
*/
.skip-link,
.skip-link:hover {
  background: var(--pk-accent);
  color: var(--pk-sur-accent);
  border: 2px solid var(--pk-ombre);
}

time {
  font-family: var(--font-mono);
  color: var(--pk-discret);
}

.muted {
  color: var(--pk-discret);
}

/* ---------------------------------------------------------- en-tête et pied */

.site-header {
  background: var(--pk-panel);
  backdrop-filter: none;
  border-block-end: 2px solid var(--pk-trait);
}

.site-footer {
  background: var(--pk-panel);
  border-block-start: 2px solid var(--pk-trait);
  color: var(--pk-discret);
}

.site-footer > .shell > p:first-child {
  font-family: var(--font-display);
  font-weight: 900;
  text-transform: uppercase;
  color: var(--pk-encre);
}

.brand {
  flex: none;
  margin-inline-end: 0;
  font-family: var(--font-display);
  font-weight: 900;
  letter-spacing: -0.02em;
}

/* Les trois barres de l'ancienne marque : la plaque « .FR » suffit à signer. */
.brand__mark {
  display: none;
}

/* « .FR » devient une plaque : l'accent plein, et le contour du béton. */
.brand__tld {
  margin-inline-start: 0.35rem;
  padding: 0.05rem 0.35rem;
  background: var(--pk-accent);
  color: var(--pk-sur-accent);
  border: 2px solid var(--pk-ombre);
  font-size: 0.8em;
}

/*
  Les liens de navigation deviennent des touches, chacune doublée de son nom
  russe. Le nom vient de la feuille, accroché à l'adresse du lien : la page
  n'a pas à changer pour l'ancienne allure, qui ne le montre pas.

  Le texte de remplacement vide après la barre oblique tait l'étiquette aux
  lecteurs d'écran, qui liraient sinon « ЭФИР Antenne ». La première
  déclaration sert aux navigateurs qui ignorent cette syntaxe : ils montrent
  l'étiquette, et la lisent.
*/
.nav a {
  display: inline-flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 0;
  min-height: 3rem;
  padding: 0.3rem 0.75rem;
  border: 2px solid var(--pk-trait);
  background: var(--pk-champ);
  color: var(--pk-encre);
  font-family: var(--font-body);
  font-size: 0.9rem;
  font-weight: 700;
  letter-spacing: 0;
  line-height: 1.15;
  text-transform: none;
  transition:
    translate 180ms var(--ease-out),
    box-shadow 180ms var(--ease-out),
    background-color 200ms ease,
    color 200ms ease;
}

.nav a::after {
  display: none;
}

.nav a::before {
  font-family: var(--font-mono);
  font-size: 0.6rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  opacity: 0.75;
}

.nav a[href="/"]::before {
  content: "ЭФИР";
  content: "ЭФИР" / "";
}

.nav a[href="/programme"]::before {
  content: "ПРОГРАММА";
  content: "ПРОГРАММА" / "";
}

.nav a[href="/historique"]::before {
  content: "ИСТОРИЯ";
  content: "ИСТОРИЯ" / "";
}

.nav a[href="/journal"]::before {
  content: "ЖУРНАЛ";
  content: "ЖУРНАЛ" / "";
}

.nav a[href="/studio"]::before {
  content: "СТУДИЯ";
  content: "СТУДИЯ" / "";
}

.nav a[href="/admin"]::before {
  content: "УПРАВДОМ";
  content: "УПРАВДОМ" / "";
}

.nav a:hover {
  translate: -2px -2px;
  box-shadow: 4px 4px 0 var(--pk-ombre);
  color: var(--pk-encre);
}

.nav a[aria-current="page"],
.nav a.active {
  background: var(--pk-plein);
  color: var(--pk-sur-plein);
}

.pseudo {
  font-family: var(--font-body);
  font-weight: 700;
  letter-spacing: 0;
  text-transform: none;
  color: var(--pk-encre);
}

/*
  L'en-tête de la maquette : la marque, la navigation tout contre elle, et le
  compte poussé à droite — éclairage, langue, membre, sortie.

  Une seule rangée tant que tout y tient, et le droit de passer à la ligne
  sinon. L'en-tête refusait de le faire : la navigation se serrait dans ce qui
  restait entre la marque et le compte, une destination par ligne, et un
  administrateur obtenait à 800 pixels un en-tête collant de 300 pixels —
  un tiers de l'écran, sur toutes les pages.
*/
.site-header__inner {
  flex-wrap: wrap;
  gap: 0.5rem 1rem;
  padding-block: 0.625rem;
}

.site-header .nav:not(.nav--account) {
  flex: 0 1 auto;
  min-width: 0;
}

.nav--account {
  flex: 0 1 auto;
  margin-inline-start: auto;
  gap: 0.5rem;
}

/*
  Entre le téléphone et le grand écran, un membre a de quatre à six
  destinations : la navigation prend alors sa propre ligne, sous la marque et
  le compte, et ne s'y replie plus. Jusqu'à 1 120 pixels pour quatre ou plus,
  1 280 pour cinq ou plus — mesuré en français, c'est là que tout tient sur
  une rangée. Le visiteur anonyme n'en a que deux, qui tiennent à côté de la
  marque.

  L'ordre du balisage ne change pas — marque, navigation, compte — : c'est
  celui du clavier et des lecteurs d'écran. Seule la disposition remonte le
  compte sur la première ligne.
*/
@media (min-width: 47.5rem) and (max-width: 69.99rem) {
  .site-header__inner:has(> .nav:not(.nav--account) > :nth-child(3)) > .nav:not(.nav--account) {
    order: 1;
    flex-basis: 100%;
  }
}

@media (min-width: 70rem) and (max-width: 79.99rem) {
  .site-header__inner:has(> .nav:not(.nav--account) > :nth-child(5)) > .nav:not(.nav--account) {
    order: 1;
    flex-basis: 100%;
  }
}

/* L'en-tête sur deux rangées : le défilement s'arrête sous la seconde. */
@media (min-width: 47.5rem) and (max-width: 79.99rem) {
  html {
    scroll-padding-block-start: 8.5rem;
  }
}

/*
  Un écran très bas — téléphone couché, zoom fort — : l'en-tête ne colle
  plus. Collé, il mangeait la moitié de la hauteur disponible.
*/
@media (max-height: 30rem) {
  .site-header {
    position: static;
  }

  html {
    scroll-padding-block-start: 1rem;
  }
}

.nav--account .btn {
  min-height: 3rem;
}

/* Le membre : sa vignette, puis son pseudo dans sa couleur. */
.nav--account .pseudo {
  position: relative;
  flex-direction: row;
  align-items: center;
  gap: 0.625rem;
  padding: 0.25rem 0.875rem 0.25rem 0.25rem;
}

.pseudo__vignette {
  display: block;
  width: 2.25rem;
  height: 2.25rem;
  border: 2px solid var(--pk-ombre);
  border-radius: 0;
}

/*
  La bascule d'éclairage : un seul de ses trois boutons paraît, celui de
  l'éclairage en cours, que l'attribut du document désigne.
*/
.bascule {
  display: flex;
  margin: 0;
}

.bascule__theme {
  display: none;
}

.bascule .bascule__theme {
  align-items: center;
  gap: 0.375rem;
  min-height: 3rem;
  padding: 0 0.75rem;
  border: 2px solid var(--pk-trait);
  background: var(--pk-champ);
  color: var(--pk-encre);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 700;
  cursor: pointer;
  transition:
    translate 180ms var(--ease-out),
    box-shadow 180ms var(--ease-out);
}

.bascule .bascule__theme:hover {
  translate: -2px -2px;
  box-shadow: 4px 4px 0 var(--pk-ombre);
}

:root[data-theme="auto"] .bascule__theme--auto,
:root[data-theme="clair"] .bascule__theme--clair,
:root[data-theme="sombre"] .bascule__theme--sombre {
  display: inline-flex;
}

/* FR / EN, deux touches accolées ; la langue servie est la touche pleine. */
.langues-courtes {
  display: flex;
  border: 2px solid var(--pk-trait);
}

.langues-courtes .inline-form {
  display: flex;
}

.langues-courtes > * + * {
  border-inline-start: 2px solid var(--pk-trait);
}

.langues-courtes__choix {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  min-width: 2.75rem;
  min-height: 2.75rem;
  padding: 0 0.5rem;
  border: 0;
  background: var(--pk-champ);
  color: var(--pk-encre);
  font: inherit;
  font-size: 0.8125rem;
  font-weight: 700;
  cursor: pointer;
}

.langues-courtes__choix[aria-current] {
  background: var(--pk-plein);
  color: var(--pk-sur-plein);
  cursor: default;
}

/* ------------------------------------------------------------------ boutons */

/*
  Le bouton se soulève au survol — l'ombre grandit — et s'enfonce au clic.
  Le déplacement passe par « translate », comme dans la feuille d'origine :
  une transformation posée ailleurs ne le défait pas.
*/
.btn {
  --btn-bg: var(--pk-champ);
  --btn-fg: var(--pk-encre);
  --btn-line: var(--pk-trait);

  border-width: 2px;
  font-family: var(--font-body);
  font-weight: 700;
  letter-spacing: 0;
  text-transform: none;
  transition:
    translate 180ms var(--ease-out),
    box-shadow 180ms var(--ease-out),
    background-color 200ms ease,
    border-color 200ms ease,
    color 200ms ease;
}

.btn:hover {
  translate: -2px -2px;
  border-color: var(--btn-line);
  color: var(--btn-fg);
  box-shadow: 4px 4px 0 var(--pk-ombre);
}

.btn:active {
  translate: 2px 2px;
  box-shadow: 0 0 0 var(--pk-ombre);
  transition-duration: 60ms;
}

.btn--accent,
.btn--accent:hover {
  --btn-bg: var(--pk-accent);
  --btn-line: var(--pk-ombre);
  --btn-fg: var(--pk-sur-accent);
}

.btn--accent {
  box-shadow: 3px 3px 0 var(--pk-ombre);
}

.btn--danger,
.btn--danger:hover {
  --btn-line: var(--pk-grave);
  --btn-fg: var(--pk-grave);
}

.btn--ghost {
  --btn-bg: transparent;
}

/*
  La petite taille garde une cible de quarante-quatre pixels : c'est elle que
  portent la cloche du programme et les actions de l'administration et du
  Studio, qui se touchent du doigt comme les autres. Elle en faisait 35.
*/
.btn--sm {
  min-height: 2.75rem;
}

.btn-icon {
  border: 2px solid var(--pk-trait);
  border-radius: 0;
  color: var(--pk-encre);
}

.btn-icon:hover {
  color: var(--pk-encre);
  border-color: var(--pk-trait);
}

.btn-icon[aria-pressed="true"] {
  color: var(--pk-accent-encre);
  border-color: var(--pk-trait);
  animation: pk-rebond 400ms var(--pk-ressort);
}

/* ------------------------------------------------------------------ panneaux */

/*
  Le panneau arrive comme un tampon : il part de la place de son ombre et se
  pose. Jamais depuis l'invisible — la feuille d'origine l'a mesuré, un fondu
  depuis zéro se lit comme un chargement.
*/
.panel {
  background: var(--pk-panel);
  border: 2px solid var(--pk-trait);
  border-radius: 0;
  box-shadow: 6px 6px 0 var(--pk-ombre);
  animation: pk-tampon 420ms var(--ease-out) both;
}

.direct__scene > :nth-child(2),
.grid > :nth-child(2) {
  animation-delay: 60ms;
}

.direct__scene > :nth-child(3),
.grid > :nth-child(3) {
  animation-delay: 120ms;
}

.direct__scene > :nth-child(n + 4),
.grid > :nth-child(n + 4) {
  animation-delay: 180ms;
}

.direct__chat > .panel {
  animation-delay: 90ms;
}

.panel__title {
  align-items: center;
  font-family: var(--font-display);
  font-weight: 900;
  letter-spacing: -0.01em;
  border-block-end: 2px solid var(--pk-trait);
}

/*
  Étiquette russe devant le titre des panneaux qui en ont une. Le nom est
  porté par l'identifiant du titre, déjà unique : rien à ajouter au balisage,
  et l'ancienne allure n'en sait rien.

  Le texte de remplacement vide la tait aux lecteurs d'écran, comme celles
  de la navigation. Mais pas par deux déclarations successives, comme
  là-bas : une valeur qui contient « var() » passe toujours l'analyse, la
  seconde l'emporterait donc partout, et un navigateur qui ignore la syntaxe
  du remplacement la rejetterait au calcul — sans retomber sur la première.
  L'étiquette disparaîtrait au lieu d'être lue. La forme tue n'est posée que
  là où « @supports » la sait comprise.
*/
.panel__title::before {
  content: var(--pk-ru, none);
  flex: none;
  padding: 0.1rem 0.45rem;
  background: var(--pk-plein);
  color: var(--pk-sur-plein);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.12em;
}

@supports (content: "" / "") {
  .panel__title::before {
    content: var(--pk-ru, none) / "";
  }
}

/*
  « ИСТОРИЯ », « ЖУРНАЛ » et « СТУДИЯ » n'ont pas d'étiquette ici : elles
  sont montées au titre de la page, ou sur le bandeau du panneau.
*/
#titre-recent { --pk-ru: "ТРЕКЛИСТ"; }
#titre-chat { --pk-ru: "ЛАВОЧКА У ПОДЪЕЗДА"; }
#titre-vote { --pk-ru: "ГОЛОСУЕМ, ПАЦАНЫ"; }
#titre-blindtest { --pk-ru: "УГАДАЙ МЕЛОДИЮ"; }
#titre-identite { --pk-ru: "КВ. 37"; }
#titre-favoris { --pk-ru: "ИЗБРАННОЕ"; }
#titre-amis { --pk-ru: "ДРУЗЬЯ"; }
#titre-mes-codes { --pk-ru: "ПРИГЛАШЕНИЯ"; }
#titre-membres { --pk-ru: "ЖИЛЬЦЫ"; }
#titre-design { --pk-ru: "ДИЗАЙН"; }
#titre-theme { --pk-ru: "СВЕТ"; }
#titre-grille { --pk-ru: "СЕТКА ВЕЩАНИЯ"; }
#titre-mes-rappels { --pk-ru: "НАПОМИНАНИЯ"; }
#titre-hors-direct { --pk-ru: "АВТОПИЛОТ"; }
#titre-prochain-direct { --pk-ru: "СКОРО В ЭФИРЕ"; }
#titre-proposer { --pk-ru: "ЗАЯВКА"; }
#titre-mes-creneaux { --pk-ru: "МОИ ЭФИРЫ"; }
#titre-creneaux-a-valider { --pk-ru: "НА УТВЕРЖДЕНИЕ"; }
#titre-insignes { --pk-ru: "ЗНАЧКИ"; }
#titre-membre-insignes { --pk-ru: "ЗНАЧКИ"; }

.panel__hint {
  font-family: var(--font-body);
  color: var(--pk-discret);
}

.panel__next,
.panel__more {
  border-block-start: 2px solid var(--pk-trait);
  color: var(--pk-doux);
}

.panel--grave {
  border-color: var(--pk-grave);
  box-shadow: 6px 6px 0 var(--pk-grave);
}

.panel--grave .panel__title {
  color: var(--pk-grave);
  border-block-end-color: var(--pk-grave);
}

.page-title {
  font-size: clamp(2rem, 1.2rem + 3vw, 4rem);
  line-height: 0.95;
  letter-spacing: -0.04em;
  animation: pk-montee 480ms var(--ease-out) both;
}

/*
  Dans un panneau de formulaire, le titre se mesure au panneau. « CONNEXION »
  est un seul mot, qui ne peut pas passer à la ligne : à la taille d'une page,
  il débordait d'un panneau de trente rems.
*/
.panel--form .page-title {
  margin-block-end: 1.1rem;
  font-size: clamp(1.6rem, 9cqi, 2.8rem);
}

/* ------------------------------------------------------------- page d'accueil */

/*
  Sous Панелька, l'accueil s'ouvre sur la « une » : le titre de l'ancienne
  allure et son panneau « À l'antenne » restent dans la page, pour elle, et
  s'effacent ici. Les réactions qu'il portait ont leur double dans la une.
*/
.hero,
.panel--now {
  display: none;
}

/* ------------------------------------------------------------- la une */

/*
  Le bloc vient de la mise en page, la une de la page : ils n'ont en commun
  que leur parent, « main », dont le bloc est le premier enfant et la une le
  suivant. La grille est donc posée sur lui, et la une en épouse les lignes
  et les colonnes par « subgrid » : tête, corps, une ligne pour le bloc quand
  il passe dessous, pied. Le bloc se pose ainsi exactement là où le corps lui
  laisse la place — à droite sur grand écran, sous lui ailleurs.

  Sans bloc — le temps qu'une allure change sans recharger —, rien de tout
  cela ne s'applique et la une se tient seule, sur une colonne.

  Aucune « container-type » sur la une : un confinement de mise en page ferait
  retomber « subgrid » à « none », et le bloc ne trouverait plus sa case.
*/
.site-main:has(> .immeuble) {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  gap: 0;
}

.site-main:has(> .immeuble) > * {
  grid-column: 1 / -1;
}

.site-main:has(> .immeuble) > .une {
  grid-row: 1 / span 4;
  grid-template-columns: subgrid;
  grid-template-rows: subgrid;
}

/*
  La bordure de la une n'est pas dans la grille de « main » : le bloc la
  recouvrirait. Il s'en écarte d'autant.
*/
.site-main:has(> .immeuble) > .immeuble {
  grid-row: 3;
  margin-inline: 2px;
}

.site-main:has(> .immeuble) > .une ~ * {
  margin-block-start: 1.75rem;
}

/*
  Ni l'un ni l'autre n'entre en scène. La une est refaite quand la page
  devient interactive, le bloc non : animés, ils se décaleraient l'un de
  l'autre le temps du mouvement.
*/
.site-main:has(> .immeuble) > :is(.une, .immeuble) {
  animation: none;
}

/*
  Côte à côte dès que la une dispose de 1 080 pixels : 560 pour le morceau,
  520 pour le bloc, comme dans la maquette.
*/
@media (min-width: 71.25rem) {
  .site-main:has(> .immeuble) {
    grid-template-columns: minmax(0, 1fr) 32.5rem;
  }

  .site-main:has(> .immeuble) > .immeuble {
    grid-column: 2;
    grid-row: 2;
    margin-inline: 0 2px;
  }
}

/*
  Sans « subgrid » — Safari avant la 16, Chrome avant la 117 —, la une ne
  reprend pas les lignes de « main » : elle en couvre quatre d'un seul tenant,
  et le bloc, rangé dans la troisième, se peignait par-dessus son texte.
  Chacun prend alors sa propre case : la une, puis le bloc dessous, ou à côté
  sur grand écran — hors du cadre de la une, mais jamais dessus.
*/
@supports not (grid-template-rows: subgrid) {
  .site-main:has(> .immeuble) > .une {
    grid-row: 1;
  }

  .site-main:has(> .immeuble) > .immeuble {
    grid-row: 2;
    margin-inline: 0;
  }

  @media (min-width: 71.25rem) {
    .site-main:has(> .immeuble) > .une {
      grid-column: 1;
    }

    .site-main:has(> .immeuble) > .immeuble {
      grid-row: 1;
    }
  }
}

/*
  La une elle-même : une tête inversée, le corps, et un pied séparé d'un trait.
  Chaque bloc porte sa colonne et sa ligne : sous « subgrid » elles sont celles
  de « main », sans lui celles de la une seule — la même place dans les deux
  cas.
*/
.une {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  border: 2px solid var(--pk-trait);
  background: var(--pk-panel);
  box-shadow: 6px 6px 0 var(--pk-ombre);
}

.une__tete {
  grid-column: 1 / -1;
  grid-row: 1;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem 0.75rem;
  padding: 0.75rem 1.125rem;
  border-block-end: 2px solid var(--pk-trait);
  background: var(--pk-plein);
  color: var(--pk-sur-plein);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.une__titre {
  margin: 0;
  font: inherit;
  letter-spacing: inherit;
}

.une__etat {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem 1.125rem;
  margin: 0;
  letter-spacing: 0.1em;
}

/*
  Le carré de l'antenne, qui pulse quand on l'écoute. Au repos, il reste
  allumé sans bouger.

  L'onde est un second carré posé dessus, qui grandit et s'efface. Elle était
  une ombre animée : repeinte à chaque image, elle coûtait à elle seule 162 ms
  de fil principal par seconde de lecture, 695 sur une machine quatre fois plus
  lente. Une échelle et une opacité se composent sans rien repeindre. Même
  dessin : de 9 à 23 pixels de côté — l'ombre s'étendait de 7 pixels de chaque
  côté —, de la couleur pleine à rien, et la part qui recouvre le carré est de
  sa couleur.

  Un élément et non un pseudo-élément de « une__direct » : l'onde doit se
  caler exactement sur le carré, posé sur la ligne de base du texte, et seul un
  parent commun le permet sans deviner où tombe cette ligne.
*/
.une__voyant {
  position: relative;
  display: inline-block;
  width: 9px;
  height: 9px;
  margin-inline-end: 0.5rem;
  background: var(--pk-accent);
}

.une__voyant::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--pk-accent);
  opacity: 0;
}

body:has(.dock[data-state="playing"]) .une__voyant::after {
  animation: une-emission 1.6s cubic-bezier(0, 0, 0.2, 1) infinite;
}

/*
  Un seul mot pour le mode, choisi d'après ce que la page montre : les panneaux
  du vote et du blind test n'existent que pendant un tour.
*/
.une__mode {
  display: none;
}

.site-main:has(.vote) .une__mode--vote,
.site-main:has(.blindtest) .une__mode--blind,
.site-main:not(:has(.vote, .blindtest)) .une__mode--aucun {
  display: inline;
}

.une__corps {
  grid-column: 1;
  grid-row: 2;
  display: flex;
  flex-direction: column;
  gap: 1.375rem;
  min-width: 0;
  padding: clamp(1.125rem, 3vw, 2rem);
}

.une__morceau {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 1.5rem;
}

/*
  La pochette : un carré au contour franc, son ombre posée de biais. Jamais
  plus large que la une : texte agrandi sur un téléphone, ses 11,5 rems
  dépassaient l'écran.
*/
.une__pochette {
  position: relative;
  flex: none;
  width: min(11.5rem, 100%);
  height: auto;
  aspect-ratio: 1;
  border: 2px solid var(--pk-ombre);
  background: var(--pk-accent);
  box-shadow: 5px 5px 0 var(--pk-ombre);
}

.une__pochette .track__pochette {
  width: 100%;
  height: 100%;
}

.une__pochette .track__art {
  border: 0;
}

/* Le tampon du direct, posé de travers sur la photo du DJ. */
.une__live {
  position: absolute;
  left: -10px;
  bottom: 14px;
  z-index: 1;
  padding: 2px 10px;
  rotate: -6deg;
  border: 2px solid #111111;
  background: var(--pk-accent);
  color: #111111;
  font-family: var(--font-mono);
  font-size: 0.8125rem;
  font-weight: 600;
  letter-spacing: 0.14em;
}

/* Pendant un blind test : une case vide en pointillés, et la question. */
.une__pochette--masquee {
  display: grid;
  place-items: center;
  border: 2px dashed var(--pk-trait);
  background: var(--pk-champ);
  box-shadow: none;
}

.une__pochette--masquee .track__pochette {
  display: none;
}

.une__pochette--masquee::after {
  content: "?";
  color: var(--pk-encre);
  font-family: var(--font-display);
  font-size: 6rem;
  font-weight: 900;
  line-height: 1;
}

.une__texte {
  flex: 1 1 17.5rem;
  min-width: 0;
}

.une__surtitre {
  margin: 0;
  color: var(--pk-discret);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.une__nom {
  margin: 0.5rem 0 0;
  font-family: var(--font-display);
  font-size: clamp(1.875rem, 4.4vw, 3.5rem);
  font-weight: 900;
  line-height: 0.98;
  letter-spacing: -0.03em;
  text-transform: uppercase;
  overflow-wrap: anywhere;
}

.une__artiste {
  margin: 0.625rem 0 0;
  color: var(--pk-doux);
  font-size: 1.25rem;
  font-weight: 600;
}

.une__puces {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin: 0.875rem 0 0;
}

/*
  La puce passe à la ligne plutôt que de sortir de la une : le nom d'une
  playlist n'a pas de longueur bornée, et un mot seul plus large que la
  colonne se coupe où il peut.
*/
.une__puce {
  display: inline-flex;
  align-items: center;
  max-width: 100%;
  padding: 1px 9px;
  border: 2px solid var(--pk-trait);
  font-size: 0.8125rem;
  font-weight: 600;
  white-space: normal;
  overflow-wrap: anywhere;
}

.une__puce--mono {
  font-family: var(--font-mono);
}

/* ---- les actions : écouter, favori, ДАВАЙ ---- */

.une__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: 0.75rem;
}

.une__ecoute,
.une__favori,
.une__connexion {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 0.75rem;
  min-height: 3.75rem;
  padding: 0 1.625rem 0 1.25rem;
  border: 2px solid var(--pk-ombre);
  font: inherit;
  font-size: 1.0625rem;
  font-weight: 700;
  line-height: 1.2;
  text-decoration: none;
  cursor: pointer;
  transition:
    translate 180ms var(--ease-out),
    box-shadow 180ms var(--ease-out);
}

/* La seule touche pleine : le favori et le lien de connexion prennent le fond du champ. */
.une__ecoute {
  background: var(--pk-accent);
  color: var(--pk-sur-accent);
  box-shadow: 3px 3px 0 var(--pk-ombre);
}

.une__ecoute:hover,
.une__connexion:hover,
.une__favori:hover {
  translate: -2px -2px;
  box-shadow: 4px 4px 0 var(--pk-ombre);
}

.une__ecoute:hover {
  color: var(--pk-sur-accent);
}

.une__ecoute:active,
.une__connexion:active,
.une__favori:active {
  translate: 2px 2px;
  box-shadow: 0 0 0 var(--pk-ombre);
  transition-duration: 60ms;
}

/* Le triangle de lecture, dessiné comme celui du lecteur. */
.une__ecoute::before {
  content: "";
  flex: none;
  width: 0;
  height: 0;
  border-block: 0.55rem solid transparent;
  border-inline-start: 0.9rem solid currentColor;
}

.une__cri {
  font-family: var(--font-display);
  font-weight: 900;
}

.une__couper {
  display: none;
}

/*
  Le libellé suit le lecteur, qui seul sait s'il joue : « data-state » sur son
  bandeau, le même indice que celui qui allume les fenêtres du bloc.
*/
body:has(.dock[data-state="playing"]) .une__lancer {
  display: none;
}

body:has(.dock[data-state="playing"]) .une__couper {
  display: inline;
}

body:has(.dock[data-state="playing"]) .une__ecoute::before {
  width: 0.85rem;
  height: 1.05rem;
  border: 0;
  background: linear-gradient(90deg, currentColor 0 34%, transparent 34% 66%, currentColor 66% 100%);
}

/*
  L'anneau qui bat au tempo, comme sur la touche du lecteur. La touche est
  large et basse : l'anneau s'élargit moins qu'il ne monte, pour s'écarter
  d'autant de chaque côté.
*/
body:has(.dock[data-state="playing"]) .une__ecoute::after {
  content: "";
  position: absolute;
  inset: -2px;
  border: 3px solid var(--pk-trait);
  pointer-events: none;
  animation: pk-anneau-large 400ms var(--ease-out) infinite;
}

/* Le lecteur n'est pas encore prêt : la touche le dit, sans rien promettre. */
body:has(.dock__play:disabled) .une__ecoute {
  cursor: progress;
}

/*
  L'écoute fermée à ce visiteur : le lecteur montre un lien de connexion à la
  place de son bouton, la une fait de même.
*/
.une__connexion {
  display: none;
  padding-inline: 1.25rem;
  border-color: var(--pk-trait);
  background: var(--pk-champ);
  color: var(--pk-encre);
  box-shadow: none;
}

body:has(.dock__connexion) .une__connexion {
  display: inline-flex;
}

body:has(.dock__connexion) .une__ecoute {
  display: none;
}

.une__favori {
  gap: 0.5rem;
  padding-inline: 1.125rem;
  border-color: var(--pk-trait);
  background: var(--pk-champ);
  color: var(--pk-encre);
  box-shadow: none;
  font-size: 0.9375rem;
}

.une__connexion:hover,
.une__favori:hover {
  color: var(--pk-encre);
}

.une__favori::before {
  content: "☆";
  content: "☆" / "";
  font-size: 1.25rem;
  line-height: 1;
}

.une__retirer {
  display: none;
}

body:has(.dock__favori[aria-pressed="true"]) .une__favori::before {
  content: "★";
  content: "★" / "";
  color: var(--pk-accent-encre);
}

body:has(.dock__favori[aria-pressed="true"]) .une__ajouter {
  display: none;
}

body:has(.dock__favori[aria-pressed="true"]) .une__retirer {
  display: inline;
}

/*
  Rien à écouter ou à mettre en favori, ou la page pas encore interactive :
  la touche s'efface sans disparaître, et reste lisible. L'opacité qu'elle
  prenait faisait tomber le libellé à 4,3:1 ; ici seuls le contour, en
  pointillés, et le curseur changent — le texte garde 6,9:1 sur le champ
  clair. Le lecteur peut être désactivé quand la une ne l'est pas encore,
  d'où la seconde condition.
*/
.une__ecoute:disabled,
.une__favori:disabled,
body:has(.dock__favori:disabled) .une__favori {
  border-style: dashed;
  border-color: var(--pk-discret);
  background: var(--pk-champ);
  color: var(--pk-discret);
  box-shadow: none;
  translate: 0 0;
  cursor: not-allowed;
}

/*
  ДАВАЙ dans la une : une touche blanche à côté de la touche orange — deux
  accents côte à côte se disputeraient le regard —, et son compte à côté.
*/
.une .davai__bouton {
  min-height: 3.75rem;
  justify-content: center;
  border-color: var(--pk-trait);
  background: var(--pk-champ);
  color: var(--pk-encre);
  box-shadow: none;
}

.une .davai__bouton:hover {
  background: var(--pk-champ);
  box-shadow: 4px 4px 0 var(--pk-ombre);
}

.une .davai__sous-titre {
  color: var(--pk-discret);
}

.une .davai__total {
  font-size: 1.25rem;
}

/* ---- la progression ---- */

.une__temps {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 600;
}

.une__piste {
  flex: 1;
  height: 12px;
  border: 2px solid var(--pk-trait);
  background: var(--pk-champ);
}

/* La durée en chiffres de compteur : elle ne bouge pas d'un morceau à l'autre. */
.une__duree {
  font-variant-numeric: tabular-nums;
}

/* Pleine et réduite par une échelle, comme celle du lecteur : voir la feuille d'origine. */
.une__barre {
  display: block;
  width: 100%;
  height: 100%;
  background: var(--pk-accent);
  transform: scaleX(0);
  transform-origin: 0 50%;
  transition: transform 900ms linear;
}

/* ---- le pied : spectre, la suite, КОЛБАСИТ ---- */

.une__pied {
  grid-column: 1 / -1;
  grid-row: 4;
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: space-between;
  gap: 0.875rem 1.75rem;
  padding: 1rem clamp(1.125rem, 3vw, 2rem) 1.125rem;
  border-block-start: 2px solid var(--pk-trait);
}

/*
  Un spectre de décor, pas une mesure : celui du lecteur lit le son, celui-ci
  bat au tempo. Arrêté tant que rien ne joue — chaque barre figée à une hauteur
  différente par le retard négatif de son animation.
*/
.une__spectre {
  flex: 1 1 100%;
  display: flex;
  align-items: flex-end;
  gap: 4px;
  height: 3.5rem;
  margin: 0;
}

.une__spectre i {
  flex: 1;
  height: 62%;
  background: var(--pk-encre);
  transform-origin: 50% 100%;
  animation: une-egaliseur 550ms cubic-bezier(0.4, 0, 0.6, 1) infinite alternate;
  animation-play-state: paused;
}

.une__spectre i:nth-child(5n + 1) { height: 38%; }
.une__spectre i:nth-child(5n + 2) { height: 86%; }
.une__spectre i:nth-child(5n + 3) { height: 54%; }
.une__spectre i:nth-child(5n + 4) { height: 100%; }
.une__spectre i:nth-child(3n + 1) { scale: 1 0.72; animation-duration: 640ms; }
.une__spectre i:nth-child(3n + 2) { animation-duration: 470ms; animation-delay: -0.31s; }
.une__spectre i:nth-child(4n + 3) { animation-delay: -0.12s; }
.une__spectre i:nth-child(4n) { animation-delay: -0.44s; }
.une__spectre i:nth-child(7n + 4) { background: var(--pk-accent); }

body:has(.dock[data-state="playing"]) .une__spectre i {
  animation-play-state: running;
}

.une__ensuite {
  flex: 1 1 18rem;
  margin: 0;
  color: var(--pk-doux);
  font-size: 0.9375rem;
}

.une__ensuite strong {
  color: var(--pk-encre);
}

/*
  КОЛБАСИТ sur une ligne : le nom, la jauge, la valeur. Le titre de la jauge
  s'efface en tant que boîte pour que ses mots se rangent autour d'elle ; le
  « ça secoue » reste dit par le libellé de la jauge.
*/
.une .kolbasit {
  flex: 0 1 23.75rem;
  grid-template-columns: auto minmax(6rem, 1fr) auto;
  align-items: center;
  gap: 0.625rem;
  min-width: 0;
}

.une .kolbasit__titre {
  display: contents;
}

.une .kolbasit__sous-titre {
  display: none;
}

.une .kolbasit__nom {
  grid-column: 1;
  grid-row: 1;
}

.une .kolbasit__jauge {
  grid-column: 2;
  grid-row: 1;
  height: 12px;
  box-shadow: none;
}

.une .kolbasit__valeur {
  grid-column: 3;
  grid-row: 1;
  margin: 0;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 600;
  white-space: nowrap;
}

/* ---------------------------------------------------------- à l'antenne */

.track__art {
  border: 2px solid var(--pk-ombre);
  border-radius: 0;
}

.track__art--empty {
  background: var(--pk-accent);
}

.track__artist {
  font-family: var(--font-mono);
  font-weight: 600;
  letter-spacing: 0.08em;
  color: var(--pk-accent-encre);
}

.track__title {
  font-family: var(--font-display);
  font-weight: 900;
  letter-spacing: -0.02em;
  text-transform: uppercase;
}

.tag,
.badge {
  border: 2px solid var(--pk-trait);
  border-radius: 0;
  color: var(--pk-encre);
  font-weight: 600;
}

.badge--live {
  background: var(--pk-accent);
  border-color: var(--pk-ombre);
  color: var(--pk-sur-accent);
}

.tag--role {
  border-color: var(--pk-info);
  color: var(--pk-info);
}

.tag--disponible {
  border-color: var(--pk-ok);
  color: var(--pk-ok);
}

.tag--utilise {
  border-color: var(--pk-fin);
  color: var(--pk-discret);
}

.tag--expire,
.tag--masque {
  border-color: var(--pk-grave);
  color: var(--pk-grave);
}

.chart__count {
  font-family: var(--font-display);
  font-weight: 900;
  color: var(--pk-accent-encre);
}

.playlist__row,
.chart__row,
.favori,
.blindtest__rang {
  border-block-end-color: var(--pk-fin);
}

.vignette,
.avatar {
  border-radius: 0;
}

.vignette {
  border: 2px solid var(--pk-ombre);
}

.notice {
  border: 2px solid var(--pk-info);
  border-radius: 0;
  background: color-mix(in oklab, var(--pk-info) 8%, var(--pk-panel));
  color: var(--pk-encre);
}

.error-code {
  display: inline-block;
  padding: 0 0.12em;
  background: var(--pk-accent);
  color: var(--pk-sur-accent);
  border: 3px solid var(--pk-ombre);
  box-shadow: 6px 6px 0 var(--pk-ombre);
  font-weight: 900;
  letter-spacing: -0.06em;
}

/* ------------------------------------------------------------ jeux du direct */

.vote__candidat,
.blindtest__proposition {
  border: 2px solid var(--pk-trait);
  border-radius: 0;
  background: var(--pk-champ);
  color: var(--pk-encre);
}

.vote__candidat:hover:not(:disabled):not(.vote__candidat--inerte),
.vote__candidat:focus-visible,
.blindtest__proposition:hover:not(:disabled),
.blindtest__proposition:focus-visible {
  border-color: var(--pk-trait);
  background: var(--pk-champ);
  translate: -2px -2px;
  box-shadow: 4px 4px 0 var(--pk-ombre);
}

.vote__candidat--choisi {
  border-color: var(--pk-trait);
  background: var(--pk-champ);
  box-shadow: 4px 4px 0 var(--pk-accent);
}

.vote__voix,
.blindtest__points {
  color: var(--pk-encre);
}

.vote__candidat--choisi .vote__voix {
  color: var(--pk-accent-encre);
}

.vote__annonce,
.blindtest__annonce {
  border-radius: 0;
  border-inline-start-width: 4px;
  color: var(--pk-encre);
}

.blindtest__rang:first-child .blindtest__joueur,
.blindtest__rang:first-child .blindtest__points {
  color: var(--pk-accent-encre);
}

/*
  Le titre des deux jeux se lit comme une affiche : l'étiquette russe en
  surtitre, sans plaque, puis le titre en grand.
*/
.vote > .panel__title,
.blindtest > .panel__title {
  flex-direction: column;
  align-items: flex-start;
  gap: 0.5rem;
  margin-block-end: 0.5rem;
  padding: 0;
  border: 0;
  font-size: clamp(1.375rem, 2.6vw, 1.875rem);
  line-height: 1.1;
  text-transform: uppercase;
}

.vote > .panel__title::before,
.blindtest > .panel__title::before {
  padding: 0;
  background: none;
  color: var(--pk-discret);
  font-size: 0.75rem;
  letter-spacing: 0.1em;
}

/*
  Le vote en bulletins numérotés : le rang dans sa case, le titre, la part des
  voix et sa jauge. Le rang tient lieu de pochette — trois carrés d'images
  côte à côte se disputaient le regard avec la une.
*/
.vote__candidats {
  gap: 0.75rem;
}

.vote__candidat {
  display: grid;
  grid-template-columns: 3.5rem minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.5rem 0;
  min-height: 4rem;
  padding: 0;
  font-size: 1rem;
}

.vote__rang {
  display: flex;
  grid-row: 1 / span 2;
  grid-column: 1;
  align-self: stretch;
  align-items: center;
  justify-content: center;
  border-inline-end: 2px solid var(--pk-trait);
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: 900;
}

.vote__candidat .vignette,
.vote__voix {
  display: none;
}

.vote__libelle {
  grid-row: 1;
  grid-column: 2;
  padding: 0.625rem 0.875rem 0;
}

.vote__libelle strong {
  font-weight: 700;
}

.vote__part {
  display: block;
  grid-row: 1;
  grid-column: 3;
  padding: 0.625rem 0.875rem 0 0;
  font-family: var(--font-mono);
  font-size: 0.875rem;
  font-weight: 600;
  white-space: nowrap;
}

/*
  Un « meter » : la valeur est un attribut, la politique de sécurité n'a rien
  à redire. Une règle par moteur, comme pour КОЛБАСИТ — un sélecteur inconnu
  ferait tomber toute une liste.
*/
.vote__jauge {
  display: block;
  grid-row: 2;
  grid-column: 2 / -1;
  appearance: none;
  width: calc(100% - 1.75rem);
  height: 8px;
  margin: 0 0.875rem 0.625rem;
  border: 2px solid var(--pk-trait);
  background: var(--pk-bg);
}

.vote__jauge::-webkit-meter-bar {
  height: 100%;
  border: 0;
  border-radius: 0;
  background: var(--pk-bg);
}

.vote__jauge::-webkit-meter-optimum-value {
  background: var(--pk-encre);
}

.vote__jauge::-moz-meter-bar {
  background: var(--pk-encre);
}

.vote__candidat--choisi .vote__rang {
  background: var(--pk-accent);
  color: var(--pk-sur-accent);
}

.vote__candidat--choisi .vote__jauge::-webkit-meter-optimum-value {
  background: var(--pk-accent);
}

.vote__candidat--choisi .vote__jauge::-moz-meter-bar {
  background: var(--pk-accent);
}

/* Le blind test porte son ombre en accent : c'est le jeu qui presse. */
.blindtest {
  box-shadow: 6px 6px 0 var(--pk-accent);
}

/* Le classement dans un encart, sous sa plaque. */
.blindtest__sous-titre {
  margin-block: 1.1rem 0;
  padding: 0.5rem 0.75rem;
  border: 0;
  background: var(--pk-plein);
  color: var(--pk-sur-plein);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.1em;
}

.blindtest__classement {
  border: 2px solid var(--pk-trait);
  border-block-start: 0;
  background: var(--pk-champ);
}

.blindtest__rang {
  padding: 0.5rem 0.75rem;
}

/* ------------------------------------------------------------------- chat */

/*
  Les messages deviennent des cartes posées sur le banc. La vignette reste en
  marge, dans le retrait que la feuille d'origine lui réserve — décalée ici de
  la valeur du nouveau rembourrage.
*/
.chat__message {
  padding: 0.45rem 0.6rem 0.45rem calc(28px + 1.1rem);
  min-block-size: calc(28px + 0.9rem);
  background: var(--pk-champ);
  border: 1px solid var(--pk-fin);
}

.chat__avatar {
  inset-inline-start: 0.5rem;
  inset-block-start: 0.45rem;
}

.chat__fil {
  gap: 0.45rem;
}

.chat__auteur,
.chat__auteur--cliquable {
  color: var(--pk-encre);
  font-weight: 700;
}

.chat__pastille[popover] {
  background: var(--pk-panel);
  color: var(--pk-encre);
  border: 2px solid var(--pk-trait);
  border-radius: 0;
  box-shadow: 6px 6px 0 var(--pk-accent);
}

.chat__action {
  border-radius: 0;
  color: var(--pk-encre);
}

.chat__action:hover,
.chat__action:focus-visible {
  background: var(--pk-survol);
}

.chat__action--grave {
  color: var(--pk-grave);
}

/*
  Le chat de l'accueil : la tête inversée du banc, la bande des présents,
  des cartes, et la saisie séparée d'un trait. Le panneau perd son
  rembourrage pour que la tête et les traits aillent d'un bord à l'autre ;
  chaque partie reprend le sien.
*/
.direct__chat .chat {
  padding: 0;
}

.chat > .panel__title {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto auto;
  align-items: end;
  gap: 0.25rem 0.75rem;
  margin: 0;
  padding: 0.75rem 1.125rem;
  background: var(--pk-plein);
  color: var(--pk-sur-plein);
  font-size: 1.25rem;
}

.chat > .panel__title::before {
  grid-column: 1 / -1;
  padding: 0;
  background: none;
  color: inherit;
}

.chat > .panel__title .panel__hint {
  color: inherit;
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  letter-spacing: 0.06em;
}

/* Trois barres penchées, la signature du site, au bout de la tête. */
.chat > .panel__title::after {
  content: "";
  width: 23px;
  height: 22px;
  align-self: center;
  background: linear-gradient(90deg, currentColor 0 5px, transparent 5px 9px, currentColor 9px 14px, transparent 14px 18px, currentColor 18px);
  transform: skewX(-20deg);
}

/* ---- qui est sur le banc ---- */

.presents {
  display: block;
  margin: 0;
  border-block-end: 1px solid var(--pk-fin);
  font-size: 0.875rem;
  font-weight: 600;
}

.presents.presents__compte {
  padding: 0.75rem 1.125rem;
}

.presents__resume {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  min-height: 3.25rem;
  padding: 0.375rem 1.125rem;
  list-style: none;
  cursor: pointer;
}

.presents__resume::-webkit-details-marker {
  display: none;
}

.presents__resume::after {
  content: "▼";
  content: "▼" / "";
  margin-inline-start: auto;
  font-size: 0.7rem;
}

.presents[open] > .presents__resume::after {
  content: "▲";
  content: "▲" / "";
}

.presents__visages {
  display: flex;
  padding-inline-start: 8px;
}

.presents__visage {
  width: 28px;
  height: 28px;
  margin-inline-start: -8px;
  border: 2px solid var(--pk-ombre);
  border-radius: 0;
}

.presents__liste {
  display: flex;
  flex-wrap: wrap;
  gap: 6px;
  margin: 0;
  padding: 0.625rem 1.125rem 0.75rem;
  list-style: none;
  border-block-start: 1px solid var(--pk-fin);
}

.presents__pseudo {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  padding: 0 0.75rem;
  border: 2px solid var(--pk-trait);
  background: var(--pk-champ);
  color: var(--pk-encre);
  font-size: 0.8125rem;
  font-weight: 600;
  text-decoration: none;
}

.presents__pseudo:hover {
  color: var(--pk-encre);
  box-shadow: 3px 3px 0 var(--pk-ombre);
}

/* ---- les messages en cartes ---- */

/*
  La vignette sort de la carte et se pose à côté, comme une tête au-dessus
  d'un banc : la carte est peinte derrière le message, décalée d'autant. Le
  pseudo passe avant l'heure — on lit qui parle, puis quand.
*/
.chat .chat__corps {
  margin: 0;
  padding: 0.875rem;
}

.chat__corps .chat__fil {
  gap: 0.625rem;
  margin: 0;
}

.chat__corps .chat__message {
  display: grid;
  grid-template-columns: auto minmax(0, 1fr);
  align-items: baseline;
  column-gap: 0.5rem;
  isolation: isolate;
  min-block-size: 34px;
  padding: 0.5rem 0.625rem 0.5rem calc(34px + 1.25rem);
  border: 0;
  background: none;
}

.chat__corps .chat__message::before {
  content: "";
  position: absolute;
  inset: 0 0 0 calc(34px + 0.625rem);
  z-index: -1;
  border: 1px solid var(--pk-fin);
  background: var(--pk-champ);
}

.chat__corps .chat__avatar {
  width: 34px;
  height: 34px;
  inset-block-start: 0;
  inset-inline-start: 0;
  border: 2px solid var(--pk-ombre);
}

.chat__corps .chat__auteur {
  grid-row: 1;
  grid-column: 1;
  margin: 0;
  font-size: 0.875rem;
}

.chat__corps .chat__heure {
  grid-row: 1;
  grid-column: 2;
  margin: 0;
  font-size: 0.6875rem;
}

.chat__corps .chat__texte {
  grid-row: 2;
  grid-column: 1 / -1;
  font-size: 0.9375rem;
}

.chat > .chat__envoi,
.chat > .empty {
  margin: 0;
  padding: 0.875rem;
  border-block-start: 2px solid var(--pk-trait);
}

.chat > .chat__erreur {
  margin: 0;
  padding: 0 0.875rem 0.875rem;
}

/* ------------------------------------------------------- champs et listes */

.field input,
.field select,
.field textarea,
.recherche__champ,
.champ-compact,
.journal__formulaire textarea,
.journal__formulaire input,
select {
  background: var(--pk-champ);
  border: 2px solid var(--pk-trait);
  border-radius: 0;
  color: var(--pk-encre);
}

.field input:hover,
select:hover {
  border-color: var(--pk-trait);
}

.field input:focus-visible,
select:focus-visible,
.recherche__champ:focus-visible {
  border-color: var(--pk-info);
  outline: 3px solid var(--pk-info);
  outline-offset: 0;
}

.field label,
form label {
  font-family: var(--font-body);
  font-weight: 700;
  letter-spacing: 0;
  text-transform: none;
  color: var(--pk-encre);
}

.checkbox,
.checkbox input {
  accent-color: var(--pk-accent);
}

select::picker(select) {
  border: 2px solid var(--pk-trait);
  border-radius: 0;
  background: var(--pk-panel);
  box-shadow: 6px 6px 0 var(--pk-ombre);
}

select option {
  border-radius: 0;
}

select option:hover {
  background: var(--pk-survol);
}

.form-errors:not(:empty) {
  border: 2px solid var(--pk-grave);
  border-radius: 0;
  color: var(--pk-grave);
}

.field__error:not(:empty) {
  color: var(--pk-grave);
}

.codes__valeur,
.diffusion__secret {
  background: var(--pk-champ);
  border: 2px solid var(--pk-trait);
  border-radius: 0;
  color: var(--pk-encre);
  font-family: var(--font-mono);
}

.repli,
.console {
  border: 2px solid var(--pk-trait);
  border-radius: 0;
}

.console {
  background: var(--pk-champ);
}

.champ-fichier::file-selector-button {
  border: 2px solid var(--pk-trait);
  border-radius: 0;
  background: var(--pk-champ);
  color: var(--pk-encre);
  font-weight: 700;
}

/* --------------------------------------------- onglets, filtres, pastilles */

.onglets {
  gap: 0.5rem;
  border-block-end: 0;
}

.onglets__lien {
  padding: 0.55rem 1rem;
  margin-block-end: 0;
  border: 2px solid var(--pk-trait);
  background: var(--pk-champ);
  color: var(--pk-encre);
  font-family: var(--font-body);
  font-weight: 700;
  letter-spacing: 0;
  text-transform: none;
  transition:
    translate 180ms var(--ease-out),
    box-shadow 180ms var(--ease-out),
    background-color 200ms ease,
    color 200ms ease;
}

.onglets__lien:hover {
  translate: -2px -2px;
  box-shadow: 4px 4px 0 var(--pk-ombre);
  color: var(--pk-encre);
}

.onglets__lien--actif,
.onglets__lien--actif:hover {
  background: var(--pk-plein);
  color: var(--pk-sur-plein);
  border-color: var(--pk-trait);
}

.filtres__choix {
  border: 2px dashed var(--pk-trait);
  border-radius: 0;
  color: var(--pk-encre);
  font-weight: 700;
}

.filtres__choix:hover,
.filtres__choix:focus-visible {
  color: var(--pk-encre);
  border-color: var(--pk-trait);
}

/*
  Le choix actif garde son encre claire au survol et au focus : la règle
  ci-dessus, plus spécifique, peignait sinon l'encre sur le plein — noir sur
  noir, 1:1.
*/
.filtres__choix--actif,
.filtres__choix--actif:is(:hover, :focus-visible) {
  background: var(--pk-plein);
  color: var(--pk-sur-plein);
  border-style: solid;
}

.pastille-role {
  border: 2px solid var(--pk-fin);
  border-radius: 0;
  color: var(--pk-discret);
  font-weight: 700;
}

/*
  Même piège, venu de la feuille d'origine : son survol, hors couche et plus
  spécifique, reposait le gris du texte sur la pastille pleine (1,6:1).
*/
.pastille-role--porte,
.pastille-role--porte:is(:hover, :focus-visible) {
  background: var(--pk-plein);
  border-color: var(--pk-trait);
  color: var(--pk-sur-plein);
}

.etat__point,
.presence {
  border-radius: 0;
}

.etat__point--actif,
.presence--en-ligne {
  background: var(--pk-ok);
  box-shadow: none;
}

.etat__point--ferme {
  background: var(--pk-grave);
}

.datalist dt {
  font-family: var(--font-mono);
  letter-spacing: 0.06em;
  text-transform: none;
}

/* ---------------------------------------------------------------- tableaux */

.table th {
  padding-inline: 0.75rem;
  background: var(--pk-plein);
  color: var(--pk-sur-plein);
  font-family: var(--font-mono);
  border-block-end: 0;
}

.table td {
  padding-inline: 0.75rem;
  border-block-end-color: var(--pk-fin);
}

.table tbody tr:hover td {
  background: var(--pk-survol);
}

@media (min-width: 60rem) {
  .table__pseudo {
    background: var(--pk-panel);
  }

  .table tbody tr:hover td.table__pseudo {
    background: var(--pk-survol);
  }
}

/* ----------------------------------------------------------------- journal */

/*
  Chaque entrée devient un avis collé au mur du bloc : une feuille de papier,
  son contour, son ombre, et sa nature tamponnée de travers dans le coin.
  Autant de colonnes que la largeur en tient, une seule sur un téléphone.

  Le papier reste clair de nuit, comme une affiche sous un lampadaire. Il
  redéfinit donc ses encres — et les noms de la feuille d'origine qui en
  dérivent : ceux-là sont résolus une fois pour toutes sur la racine, et
  garderaient sinon les teintes de la nuit, de la craie sur du blanc.
*/
section[aria-labelledby="titre-entrees"] {
  padding: 0;
  border: 0;
  background: none;
  box-shadow: none;
  animation: none;
}

/* Le compte des entrées, en ligne de légende : le titre de page l'a coiffé. */
#titre-entrees {
  margin: 0 0 1.5rem;
  padding: 0;
  border: 0;
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

#titre-entrees::before {
  content: none;
}

/*
  Chaque avis garde sa longueur. Égaliser une rangée creusait des pans de
  papier blanc sous les avis courts : les entrées réelles vont d'une phrase à
  cinq paragraphes, et la plus longue donnait sa hauteur aux deux autres.
*/
.journal {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(min(100%, 22.5rem), 1fr));
  align-items: start;
  gap: 1.5rem;
}

.journal__item,
.journal__item:first-child {
  --pk-encre: #111111;
  --pk-doux: #33363b;
  --pk-discret: #5c5a55;
  --pk-trait: #111111;
  --pk-fin: #cfcbc3;
  --pk-info: #1f45d6;
  --pk-accent-encre: #ad3d0a;
  --chalk: var(--pk-encre);
  --smoke: var(--pk-doux);
  --smoke-dim: var(--pk-discret);
  --ice: var(--pk-info);
  --ice-dim: var(--pk-info);
  --line: var(--pk-fin);
  --line-strong: var(--pk-trait);

  display: flex;
  flex-direction: column;
  padding: 1.375rem;
  border: 2px solid var(--pk-ombre);
  background: var(--pk-papier);
  color: var(--pk-encre);
  box-shadow: 6px 6px 0 var(--pk-ombre);
  color-scheme: light;
  animation: pk-tampon 420ms var(--ease-out) both;
}

.journal__item:nth-child(2) {
  animation-delay: 60ms;
}

.journal__item:nth-child(3) {
  animation-delay: 120ms;
}

.journal__item:nth-child(n + 4) {
  animation-delay: 180ms;
}

.journal__entete {
  justify-content: space-between;
  gap: 0.5rem 0.75rem;
  margin: 0;
  font-size: 0.75rem;
  color: var(--pk-encre);
}

.journal__entete time {
  order: -1;
  font-weight: 600;
  color: var(--pk-encre);
}

/* La nature, au tampon : de travers, à l'encre de sa couleur. */
.journal__entete .tag {
  order: 1;
  margin-inline-start: auto;
  rotate: -4deg;
  padding: 0.125rem 0.625rem;
  border: 2px solid currentColor;
  background: none;
  color: var(--pk-encre);
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

/*
  Cinq encres de tampon, lisibles sur le papier de jour comme de nuit : 5:1
  au moins. Le vert du site restait sous ce seuil sur le papier de nuit,
  d'où le sien, plus sombre.
*/
.journal__entete [data-nature="nouveaute"] {
  color: #1f45d6;
}

.journal__entete [data-nature="performance"] {
  color: #1a6e35;
}

.journal__entete [data-nature="correctif"] {
  color: #a3410b;
}

.journal__entete [data-nature="securite"] {
  color: #b3121c;
}

.journal__entete [data-nature="interne"] {
  color: #7a2bb5;
}

.journal__titre {
  margin: 1rem 0 0;
  font-size: 1.25rem;
  text-transform: none;
  font-weight: 700;
  line-height: 1.15;
  letter-spacing: -0.02em;
  color: var(--pk-encre);
}

.journal__item > .journal__texte {
  max-width: none;
  margin-block-start: 0.625rem;
  line-height: 1.6;
  color: var(--pk-doux);
}

.journal__technique {
  margin-block-start: 0.875rem;
  border-inline-start: 2px solid var(--pk-fin);
}

/* Le repli s'ouvre au doigt : la ligne fait quarante-quatre pixels. */
.journal__technique > summary {
  padding-block: 0.8rem;
  color: var(--pk-info);
}

/* « Modifier », en touche au pied de l'avis. */
.journal__lien-edition {
  display: inline-flex;
  align-items: center;
  align-self: flex-start;
  min-height: 2.75rem;
  padding: 0 0.75rem;
  border: 2px solid var(--pk-trait);
  color: var(--pk-encre);
  font-size: 0.875rem;
  font-weight: 700;
  text-decoration: none;
  transition:
    translate 180ms var(--ease-out),
    box-shadow 180ms var(--ease-out);
}

.journal__lien-edition:hover,
.journal__lien-edition:focus-visible {
  translate: -2px -2px;
  box-shadow: 3px 3px 0 var(--pk-ombre);
  color: var(--pk-encre);
}

.journal__item:has(> .journal__lien-edition) > :nth-last-child(2) {
  margin-block-end: 1rem;
}

/* Les formulaires du propriétaire gardent une ligne lisible. */
section:is(
    [aria-labelledby="titre-ajout"],
    [aria-labelledby="titre-visibilite"],
    [aria-labelledby="titre-edition"]
  ) {
  max-width: 48.75rem;
}

/* ------------------------------------------------------ fenêtre de modération */

.fenetre {
  background: var(--pk-panel);
  color: var(--pk-encre);
  border: 2px solid var(--pk-trait);
  border-radius: 0;
  box-shadow: 8px 8px 0 var(--pk-accent);
}

.fenetre__entete {
  border-block-end: 2px solid var(--pk-trait);
}

.fenetre__titre,
.fenetre__section-titre {
  font-family: var(--font-display);
  font-weight: 900;
}

/* --------------------------------------------------------------- gabarits */

.squelette__ligne {
  border-radius: 0;
  background: linear-gradient(90deg, var(--pk-survol) 0%, var(--pk-fin) 50%, var(--pk-survol) 100%);
  background-size: 300% 100%;
}

/* ---------------------------------------------------------- pseudos colorés */

/*
  Les couleurs de pseudo sont validées par le domaine contre le fond presque
  noir de l'ancienne allure : 4,5:1 au moins, sur ce noir-là. Sur le béton
  clair, elles deviennent illisibles — un jaune pâle sur du gris clair. Sur
  le béton de nuit aussi, plus discrètement : ses panneaux sont moins noirs
  que l'ancien fond, et une couleur acceptée de justesse n'y avait plus que
  3,6 à 4,2:1.

  Le pseudo se pose donc sur une plaque noire, comme un nom sur une boîte aux
  lettres, dans les trois éclairages. Noire et non gris très sombre : la
  plaque d'avant, #151618, ramenait la couleur la plus sombre que le domaine
  accepte à 4,0:1 ; le noir la tient à 4,6. Le domaine n'a pas à changer.

  « :where » ôte toute spécificité à la racine : la règle reste à égalité
  avec celle de la feuille des couleurs, qui vient après dans le document et
  garde le dernier mot sur la teinte.
*/
:where(:root[data-theme]) [data-membre] {
  padding: 0 0.3em;
  background: #000000;
  color: #e9e6df;
  box-decoration-break: clone;
}

/*
  L'aperçu de la couleur, sur le profil, prend la même plaque : il montre la
  teinte sur le fond pour lequel elle est faite. Le blanc proposé par défaut
  s'y écrivait sinon en blanc sur le béton — un aperçu de rien. Le script y
  pose la teinte choisie, qui garde le dernier mot sur celle d'ici.
*/
:where(:root[data-theme]) [data-couleur-apercu] {
  padding: 0 0.3em;
  background: #000000;
  color: #e9e6df;
}

/* --------------------------------------------------------------- le lecteur */

/*
  Le lecteur reste sombre dans les deux éclairages : c'est le meuble de la
  radio, posé sous la page. Il redéfinit donc ses propres teintes, et le
  spectre — que le lecteur peint en lisant ces variables à côté de lui — les
  suit sans savoir quel éclairage la page a pris.

  Les deux jeux, et pas un seul. Les noms de la feuille d'origine sont résolus
  une fois pour toutes sur la racine : les redéfinir ici ne suffit pas à ce
  qui lit les jetons d'ici. Le lecteur et les onglets du bas, en clair,
  gardaient l'anneau de focus bleu foncé (2,7:1 sur le noir), le gris des
  « auditeurs » (2,9:1) et une pastille « +N » blanche (2,4:1).
*/
.dock,
.onglets-bas {
  color-scheme: dark;

  --pk-encre: #e9e6df;
  --pk-doux: #c9c6bf;
  --pk-discret: #a9a6a0;
  --pk-trait: #e9e6df;
  --pk-fin: #3a3b3f;
  --pk-champ: #0e0f10;
  --pk-survol: #1c1d20;
  --pk-accent-encre: #ff8a5c;
  --pk-info: #8fa8ff;
  --surface-raised: #0e0f10;
}

.dock {
  --chalk: #e9e6df;
  --smoke: #c9c6bf;
  --smoke-dim: #a9a6a0;
  --red-hot: var(--pk-accent);
  --ink-950: #0a0a0b;
  --ink-700: #3a3b3f;
  --line: #3a3b3f;
  --line-strong: #e9e6df;

  background: #0a0a0b;
  color: #e9e6df;
  backdrop-filter: none;
  border-block-start: 2px solid #e9e6df;
}

/* Le bouton de lecture est la touche orange de la façade. */
.dock__play {
  position: relative;
  border: 2px solid #e9e6df;
  border-radius: 0;
  background: var(--pk-accent);
}

.dock__play:hover {
  background: var(--pk-accent);
  scale: 1;
  translate: -2px -2px;
  box-shadow: 4px 4px 0 #e9e6df;
}

.dock__play-icon {
  border-inline-start-color: #111111;
}

.dock[data-state="playing"] .dock__play-icon {
  background: linear-gradient(90deg, #111111 0 34%, transparent 34% 66%, #111111 66% 100%);
}

/* Un anneau s'en échappe à chaque temps, au tempo du hardbass (150 BPM). */
.dock[data-state="playing"] .dock__play::after {
  content: "";
  position: absolute;
  inset: -2px;
  border: 3px solid #e9e6df;
  pointer-events: none;
  animation: pk-anneau 400ms var(--ease-out) infinite;
}

/*
  Le survol garde l'encre noire sur l'orange. La règle générale des liens au
  survol, plus spécifique, posait l'accent assombri sur l'accent : 1,8:1 en
  clair, 1,3:1 en sombre.
*/
.dock__connexion,
.dock__connexion:is(:hover, :focus-visible) {
  border: 2px solid #e9e6df;
  border-radius: 0;
  background: var(--pk-accent);
  color: #111111;
}

.dock__label {
  font-family: var(--font-mono);
  font-weight: 600;
  letter-spacing: 0.12em;
}

.dock__track {
  font-family: var(--font-body);
  font-weight: 700;
}

.dock__progress {
  height: 6px;
  background: #3a3b3f;
}

.dock__progress-bar {
  background: var(--pk-accent);
}

.dock__listeners {
  font-family: var(--font-mono);
  font-weight: 600;
}

.dock .btn-icon {
  width: 2.75rem;
  height: 2.75rem;
  border-color: #e9e6df;
  color: #e9e6df;
}

.dock .btn-icon[aria-pressed="true"] {
  color: var(--pk-accent);
}

.dock .volume input {
  accent-color: var(--pk-accent);
}

.dock__present {
  border-radius: 0;
  border-color: #0a0a0b;
}

/*
  La minuterie de veille, en caractères de compteur : c'est un chiffre qu'on
  lit en passant, comme sur un radio-réveil. Rien ici ne touche à « display » —
  la feuille d'origine cache le bouton sur les écrans étroits, et une règle
  hors couche venue après l'emporterait sur ce masquage.
*/
.dock__veille {
  font-family: var(--font-mono);
  font-weight: 600;
  letter-spacing: 0.04em;
}

.dock__veille:disabled {
  opacity: 0.35;
}

/*
  Le surtitre du lecteur, comme dans la maquette : « ЭФИР · Antenne ». Le point
  qui pulsait devant n'y figure plus — la touche orange bat déjà au tempo.
*/
.dock .live-dot {
  display: none;
}

.dock__label::before {
  content: "ЭФИР ·";
  content: "ЭФИР ·" / "";
}

/* Le spectre du lecteur reste une mesure, à la taille d'un vumètre de façade. */
.dock__spectrum {
  width: 9.375rem;
  height: 2.25rem;
}

/* La veille en pointillés : une commande à part, qui ne joue rien. */
.dock .dock__veille {
  width: auto;
  border-style: dashed;
}

/*
  Armée, elle prend l'accent, comme le favori posé. Par sa classe et non par
  « aria-pressed » : son nom dit déjà l'état — « veille dans 30 minutes » —,
  et un bouton à quatre crans n'est pas une case qu'on coche.
*/
.dock .dock__veille--armee {
  color: var(--pk-accent);
  animation: pk-rebond 400ms var(--pk-ressort);
}

/* ------------------------------------------- réactions : ДАВАЙ, КОЛБАСИТ */

/*
  Le bouton est la touche orange du panneau, comme la lecture est celle du
  lecteur : il s'enfonce sous le doigt et laisse son ombre derrière lui.
*/
.davai__bouton {
  border: 2px solid var(--pk-trait);
  border-radius: 0;
  background: var(--pk-accent);
  color: var(--pk-sur-accent);
  box-shadow: 4px 4px 0 var(--pk-ombre);
  transition:
    translate 120ms var(--pk-ressort),
    box-shadow 120ms var(--pk-ressort);
}

.davai__bouton:hover {
  background: var(--pk-accent);
  translate: -2px -2px;
  box-shadow: 6px 6px 0 var(--pk-ombre);
}

.davai__bouton:active {
  translate: 2px 2px;
  box-shadow: 0 0 0 var(--pk-ombre);
  transition-duration: 60ms;
}

.davai__bouton:disabled,
.davai__bouton[aria-disabled="true"],
.davai__bouton[aria-disabled="true"]:hover {
  border-color: var(--pk-fin);
  background: var(--pk-panel);
  color: var(--pk-discret);
  translate: 0 0;
  box-shadow: 4px 4px 0 var(--pk-fin);
}

/* L'invitation reste une touche, mais blanche : rien ne s'allume encore. */
.davai__bouton--invite,
.davai__bouton--invite:hover {
  border-color: var(--pk-trait);
  background: var(--pk-champ);
  color: var(--pk-encre);
}

.davai__cri {
  font-family: var(--font-display);
  font-weight: 900;
  letter-spacing: -0.01em;
}

.davai__sous-titre {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: inherit;
}

.davai__envol {
  font-family: var(--font-display);
  font-size: var(--step-1);
  font-weight: 900;
  color: var(--pk-accent-encre);
}

.davai__total {
  font-family: var(--font-display);
  font-weight: 900;
  letter-spacing: -0.02em;
  color: var(--pk-encre);
}

.davai__legende {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--pk-discret);
}

.davai__avis {
  font-weight: 600;
  color: var(--pk-accent-encre);
}

/* Le nom de la jauge en plaque, comme les étiquettes russes des panneaux. */
.kolbasit__nom {
  padding: 0.1rem 0.45rem;
  background: var(--pk-plein);
  color: var(--pk-sur-plein);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.12em;
}

.kolbasit__sous-titre {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  color: var(--pk-discret);
}

.kolbasit__valeur {
  font-family: var(--font-display);
  font-weight: 900;
  color: var(--pk-encre);
}

/*
  Un vumètre de façade : des segments plutôt qu'un dégradé, un contour épais et
  une ombre franche. Chaque moteur a sa règle, pour la raison donnée dans la
  feuille d'origine.
*/
.kolbasit__jauge {
  height: 1rem;
  border: 2px solid var(--pk-trait);
  border-radius: 0;
  background: var(--pk-champ);
  box-shadow: 3px 3px 0 var(--pk-ombre);
}

.kolbasit__jauge::-webkit-meter-bar {
  background: var(--pk-champ);
}

.kolbasit__jauge::-webkit-meter-optimum-value,
.kolbasit__jauge::-webkit-meter-suboptimum-value,
.kolbasit__jauge::-webkit-meter-even-less-good-value {
  background: repeating-linear-gradient(90deg, var(--pk-accent) 0 8px, transparent 8px 11px);
}

.kolbasit__jauge::-moz-meter-bar {
  background: repeating-linear-gradient(90deg, var(--pk-accent) 0 8px, transparent 8px 11px);
}

/* ----------------------------------------------------------------- insignes */

/*
  Des épinglettes en émail, comme celles qu'on piquait sur un revers : un rond
  orange, deux anneaux noirs séparés d'un liseré de la couleur du panneau, une
  étoile et l'étiquette russe. L'ombre est franche, comme celle des panneaux —
  elle reste noire de nuit, l'émail ne change pas d'éclairage.
*/
.pastille-insigne {
  gap: 0.4rem;
  padding: 0.2rem 0.6rem;
  border: 2px solid var(--pk-trait);
  border-radius: 0;
  background: var(--pk-accent);
  color: var(--pk-sur-accent);
  box-shadow: 3px 3px 0 var(--pk-ombre);
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 600;
  letter-spacing: 0.1em;
}

.pastille-insigne__etoile {
  color: var(--pk-sur-accent);
}

.insignes-entete__lien {
  font-weight: 700;
  color: var(--pk-accent-encre);
  text-decoration: underline 2px;
  text-underline-offset: 3px;
}

.insignes-entete__lien:hover {
  color: var(--pk-encre);
}

.chiffres-insignes__case {
  border: 2px solid var(--pk-trait);
  border-radius: 0;
  background: var(--pk-champ);
  box-shadow: 4px 4px 0 var(--pk-ombre);
}

.chiffres-insignes__case dt {
  font-family: var(--font-mono);
  font-size: 0.7rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
  color: var(--pk-discret);
}

.chiffres-insignes__case dd {
  font-family: var(--font-display);
  font-weight: 900;
  letter-spacing: -0.02em;
  color: var(--pk-encre);
}

.insigne__epinglette {
  width: 6.25rem;
  border: 2px solid var(--pk-trait);
  background: radial-gradient(
    circle at 35% 30%,
    color-mix(in oklab, var(--pk-accent) 55%, #ffffff),
    var(--pk-accent) 58%,
    color-mix(in oklab, var(--pk-accent) 82%, #000000)
  );
  box-shadow:
    inset 0 0 0 4px var(--pk-panel),
    inset 0 0 0 6px var(--pk-trait),
    5px 5px 0 var(--pk-ombre);
}

.insigne__etoile {
  font-size: 1.5rem;
  color: var(--pk-sur-accent);
}

.insigne__ru {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  color: var(--pk-sur-accent);
}

.insigne__nom {
  font-family: var(--font-display);
  font-weight: 900;
  letter-spacing: -0.01em;
  color: var(--pk-encre);
}

.insigne__condition {
  color: var(--pk-doux);
}

/* L'état en plaque, comme les étiquettes russes des panneaux. */
.insigne__etat {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--pk-discret);
}

.insigne--obtenu .insigne__etat {
  padding: 0.1rem 0.45rem;
  background: var(--pk-plein);
  color: var(--pk-sur-plein);
}

/*
  À venir : le même rond, en béton, cerné de pointillés. Ni opacité ni
  filtre — le nom et la condition dessous gardent tout leur contraste.
*/
.insigne--a-venir .insigne__epinglette {
  border: 2px dashed var(--pk-discret);
  background: var(--pk-champ);
  box-shadow:
    inset 0 0 0 4px var(--pk-champ),
    inset 0 0 0 6px var(--pk-fin),
    5px 5px 0 var(--pk-fin);
}

.insigne--a-venir .insigne__etoile,
.insigne--a-venir .insigne__ru {
  color: var(--pk-discret);
}

.insigne--a-venir .insigne__nom {
  color: var(--pk-doux);
}

/* La progression en vumètre, segments et ombre franche, comme КОЛБАСИТ. */
.insigne__progression {
  height: 0.9rem;
  border: 2px solid var(--pk-trait);
  border-radius: 0;
  background: var(--pk-champ);
  box-shadow: 3px 3px 0 var(--pk-ombre);
}

.insigne__progression::-webkit-progress-bar {
  background: var(--pk-champ);
}

.insigne__progression::-webkit-progress-value {
  background: repeating-linear-gradient(90deg, var(--pk-accent) 0 8px, transparent 8px 11px);
}

.insigne__progression::-moz-progress-bar {
  background: repeating-linear-gradient(90deg, var(--pk-accent) 0 8px, transparent 8px 11px);
}

.insigne__chiffres {
  font-family: var(--font-mono);
  font-weight: 600;
  color: var(--pk-encre);
}

/* -------------------------------------------------- programme des directs */

/*
  Chaque jour devient une touche : l'abréviation en plaque, la date en gros,
  le nombre de directs dessous. Un jour sans direct garde sa touche, en
  pointillés — on peut y aller, il n'y a simplement rien à y annoncer.
*/
.programme__jour {
  padding: 0.45rem 0.8rem;
}

.programme__nom {
  font-family: var(--font-mono);
  font-size: 0.66rem;
  font-weight: 600;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.programme__date {
  font-family: var(--font-display);
  font-size: 1.35rem;
  font-weight: 900;
  color: inherit;
}

.programme__compte {
  font-family: var(--font-mono);
  font-size: 0.62rem;
  color: inherit;
}

.programme__jour--vide {
  border-style: dashed;
  color: var(--pk-discret);
}

.programme__jour--vide .programme__date {
  color: inherit;
}

.programme__jour--vide.onglets__lien--actif {
  border-style: solid;
  color: var(--pk-sur-plein);
}

/*
  La grille d'une journée : chaque direct en carte, comme sur la maquette —
  l'horaire dans une colonne pleine à gauche, le set à côté, l'échéance et la
  cloche au bout. Sur un téléphone, l'horaire passe en bandeau au-dessus.
*/
.programme__liste {
  gap: 1.125rem;
  margin: 0;
  padding: 0;
}

.direct-prevu,
.direct-prevu:last-child {
  grid-template-columns: 6.75rem minmax(0, 1fr) auto;
  align-items: center;
  gap: 0.75rem 1rem;
  padding: 0 1rem 0 0;
  border: 2px solid var(--pk-trait);
  background: var(--pk-champ);
  box-shadow: 4px 4px 0 var(--pk-ombre);
}

.direct-prevu__horaire {
  align-self: stretch;
  display: flex;
  align-items: center;
  padding: 1rem 0.875rem;
  border-inline-end: 2px solid var(--pk-trait);
  background: var(--pk-plein);
  color: var(--pk-sur-plein);
  font-family: var(--font-display);
  font-size: 1.125rem;
  font-weight: 900;
  line-height: 1.15;
  white-space: normal;
}

/* La suite d'un direct de la veille, sous Панелька. */
.direct-prevu__suite {
  color: var(--pk-discret);
}

.direct-prevu__corps {
  padding-block: 1rem;
}

.direct-prevu__etat {
  padding-block: 1rem;
}

@media (max-width: 40rem) {
  .direct-prevu,
  .direct-prevu:last-child {
    grid-template-columns: minmax(0, 1fr);
    padding: 0;
  }

  .direct-prevu__horaire {
    padding: 0.5rem 1rem;
    border-inline-end: 0;
    border-block-end: 2px solid var(--pk-trait);
    font-size: 1rem;
  }

  .direct-prevu__corps,
  .direct-prevu__etat {
    padding: 0 1rem;
  }

  .direct-prevu__etat {
    padding-block-end: 1rem;
  }
}

.direct-prevu__titre {
  font-family: var(--font-display);
  font-weight: 900;
  letter-spacing: -0.01em;
  text-transform: uppercase;
  color: var(--pk-encre);
}

.direct-prevu__dj {
  color: var(--pk-doux);
}

/*
  Le pseudo du DJ est un lien vers sa page : souligné, sinon rien ne le
  distingue du texte qui l'entoure que sa plaque, que portent aussi les
  pseudos qui ne mènent nulle part. Le trait est posé sur le pseudo et non
  sur le lien, pour prendre sa couleur : celle du lien, sombre, disparaîtrait
  sur la plaque noire.
*/
.direct-prevu__dj a [data-membre] {
  text-decoration: underline;
  text-decoration-thickness: 2px;
  text-underline-offset: 0.2em;
}

.direct-prevu--passe {
  box-shadow: none;
}

.direct-prevu--passe .direct-prevu__horaire {
  background: var(--pk-survol);
  color: var(--pk-discret);
}

.direct-prevu--passe .direct-prevu__titre {
  color: var(--pk-discret);
}

/* Le direct en cours prend l'accent : c'est lui qui est à l'antenne. */
.direct-prevu--en-cours {
  box-shadow: 6px 6px 0 var(--pk-accent);
}

.direct-prevu--en-cours .direct-prevu__horaire {
  background: var(--pk-accent);
  color: var(--pk-sur-accent);
}

.echeance {
  border: 2px solid var(--pk-trait);
  border-radius: 0;
  background: var(--pk-champ);
  color: var(--pk-encre);
  font-family: var(--font-mono);
  font-weight: 600;
  letter-spacing: 0.04em;
}

.echeance--direct {
  background: var(--pk-accent);
  border-color: var(--pk-ombre);
  color: var(--pk-sur-accent);
  box-shadow: 3px 3px 0 var(--pk-ombre);
}

.echeance--bientot {
  border-color: var(--pk-info);
  color: var(--pk-info);
}

.echeance--passe {
  border-color: var(--pk-fin);
  background: transparent;
  color: var(--pk-discret);
}

.etiquette {
  border: 2px solid var(--pk-trait);
  border-radius: 0;
  background: var(--pk-champ);
  color: var(--pk-encre);
  font-weight: 600;
}

/* Le dièse, comme sur une affiche : décor seulement, les lecteurs d'écran le taisent. */
.etiquette::before {
  content: "#";
  content: "#" / "";
  color: var(--pk-accent-encre);
}

/*
  La cloche posée, en touche pleine. Les variables ne suffisent pas : la
  feuille d'origine pose sa couleur à elle, hors couche, sur la même classe
  — le bleu d'information sur le plein, 2,6:1. On la reprend donc ici.
*/
.cloche--posee,
.cloche--posee:hover {
  --btn-bg: var(--pk-plein);
  --btn-fg: var(--pk-sur-plein);
  --btn-line: var(--pk-trait);

  border-color: var(--btn-line);
  color: var(--btn-fg);
}

.rappels__ligne {
  padding: 0.5rem 0.6rem;
  border: 2px solid var(--pk-trait);
  background: var(--pk-champ);
  box-shadow: 4px 4px 0 var(--pk-ombre);
}

.rappels__quand {
  font-weight: 600;
  color: var(--pk-accent-encre);
}

.rappels__titre {
  font-weight: 700;
  color: var(--pk-encre);
}

/* L'annonce de l'accueil porte son ombre en accent : elle appelle à revenir. */
.prochain {
  box-shadow: 6px 6px 0 var(--pk-accent);
}

.prochain__horaire {
  color: var(--pk-doux);
}

.prochain__titre {
  font-weight: 900;
  letter-spacing: -0.02em;
  text-transform: uppercase;
  color: var(--pk-encre);
}

.prochain__dj {
  color: var(--pk-doux);
}

.creneaux__ligne {
  border-block-end: 2px solid var(--pk-fin);
}

.creneaux__quand {
  font-weight: 600;
  color: var(--pk-accent-encre);
}

.creneaux__titre {
  font-family: var(--font-display);
  font-weight: 700;
  color: var(--pk-encre);
}

.creneaux__dj {
  color: var(--pk-doux);
}

.tag--attente {
  border-style: dashed;
  border-color: var(--pk-info);
  color: var(--pk-info);
}

.tag--valide {
  background: var(--pk-ok);
  border-color: var(--pk-ombre);
  color: var(--pk-sur-plein);
}

.tag--refuse {
  border-color: var(--pk-grave);
  color: var(--pk-grave);
}

.tag--retire,
.tag--annule,
.tag--echu {
  border-color: var(--pk-fin);
  color: var(--pk-discret);
}

/* --------------------------------------------------------- choix d'allure */

.affichage {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 0.6rem 1.4rem;
  margin-block-start: 0.9rem;
}

/*
  Le groupe passe à la ligne plutôt que de déborder du pied de page : en
  anglais, ou le texte agrandi, l'étiquette et ses trois choix dépassaient
  la largeur d'un téléphone.
*/
.affichage__groupe {
  display: inline-flex;
  flex-wrap: wrap;
  align-items: stretch;
  max-width: 100%;
  border: 2px solid var(--pk-trait);
}

/*
  L'étiquette reste sans fond : pleine, elle prenait la teinte du choix pressé
  qui la suit, et les deux se lisaient comme un seul bloc.
*/
.affichage__titre {
  display: inline-flex;
  align-items: center;
  padding: 0 0.6rem;
  color: var(--pk-discret);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.affichage__choix {
  min-height: 2.75rem;
  padding: 0 0.75rem;
  border: 0;
  border-inline-start: 2px solid var(--pk-trait);
  background: var(--pk-champ);
  color: var(--pk-encre);
  font: inherit;
  font-size: 0.85rem;
  font-weight: 700;
  text-decoration: none;
  cursor: pointer;
  transition:
    background-color 200ms ease,
    color 200ms ease;
}

.affichage__choix[aria-current="true"] {
  background: var(--pk-plein);
  color: var(--pk-sur-plein);
}

.affichage__aide {
  margin-block-end: 1rem;
}

.affichage--complet {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 11rem), 1fr));
  gap: 0.8rem;
  margin: 0;
}

.affichage__carte {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 0.3rem;
  padding: 0.9rem 1rem;
  border: 2px solid var(--pk-trait);
  background: var(--pk-champ);
  color: var(--pk-encre);
  font: inherit;
  text-align: start;
  cursor: pointer;
  transition:
    translate 180ms var(--ease-out),
    box-shadow 180ms var(--ease-out),
    background-color 200ms ease,
    color 200ms ease;
}

.affichage__carte:hover {
  translate: -2px -2px;
  box-shadow: 4px 4px 0 var(--pk-ombre);
}

.affichage__carte[aria-current="true"] {
  background: var(--pk-plein);
  color: var(--pk-sur-plein);
  box-shadow: 4px 4px 0 var(--pk-accent);
}

.affichage__nom {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 1.05rem;
  text-transform: uppercase;
}

/*
  La description suit l'encre de sa carte. La feuille d'origine lui donne sa
  propre couleur, le gris doux : sur la carte choisie, pleine, elle tombait à
  1,4:1.
*/
.affichage__description {
  color: inherit;
  font-size: 0.85rem;
  opacity: 0.85;
}

/* ------------------------------------------------- le téléphone : onglets */

/*
  Sous 760 pixels, la navigation descend sous le pouce : quatre onglets et
  « Plus », le lecteur posé juste au-dessus. L'en-tête ne garde que la marque
  et le compte — la vignette du membre, ou « Rejoindre ».

  Hauteur de la barre : une touche de 56 pixels, son rembourrage, son filet.
  L'encoche du bas s'y ajoute, et seulement à elle : le lecteur se pose sur la
  barre, pas sur l'encoche.
*/
:root {
  --onglets: 4.125rem;
}

.onglets-bas {
  display: none;
  position: fixed;
  inset-inline: 0;
  bottom: 0;
  z-index: 40;
  justify-content: space-around;
  gap: 2px;
  padding: 4px 4px calc(4px + env(safe-area-inset-bottom));
  background: #0a0a0b;
  border-block-start: 2px solid #3a3b3f;
}

.onglets-bas__lien {
  flex: 1;
  min-width: 0;
  min-height: 3.5rem;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 3px;
  padding: 0 2px;
  border: 0;
  background: transparent;
  color: #c9c6bf;
  font: inherit;
  font-size: 0.6875rem;
  font-weight: 700;
  line-height: 1.2;
  text-decoration: none;
  white-space: nowrap;
  cursor: pointer;
  transition:
    background-color 200ms ease,
    color 200ms ease;
}

.onglets-bas__lien:hover {
  color: #e9e6df;
}

/*
  L'anneau se pose à l'intérieur de l'onglet, collé au bord de l'écran. Sa
  couleur est celle de la barre, sombre : « --pk-info » y est redéfini plus
  haut. Sur l'onglet actif, orange, il passe au noir — le bleu clair n'y
  avait que 1,4:1.
*/
.onglets-bas__lien:focus-visible {
  outline-offset: -3px;
}

.onglets-bas__lien.active,
.onglets-bas__lien[aria-current="page"] {
  background: var(--pk-accent);
  color: #111111;
}

/*
  La feuille ouverte, c'est « Plus » qui est l'onglet en cours. Chaque forme
  dans sa propre règle : là où « :popover-open » est inconnu — précisément
  les navigateurs du repli —, une liste qui le contient tombe tout entière,
  et l'onglet actif n'était plus surligné.
*/
body:has(.feuille:popover-open) .onglets-bas__lien[popovertarget] {
  background: var(--pk-accent);
  color: #111111;
}

body:has(.feuille[data-ouverte]) .onglets-bas__lien[popovertarget] {
  background: var(--pk-accent);
  color: #111111;
}

body:has(.feuille:popover-open) .onglets-bas__lien:not([popovertarget]) {
  background: transparent;
  color: #c9c6bf;
}

body:has(.feuille[data-ouverte]) .onglets-bas__lien:not([popovertarget]) {
  background: transparent;
  color: #c9c6bf;
}

.onglets-bas__lien:is(.active, [aria-current="page"]):focus-visible {
  outline-color: #111111;
}

body:has(.feuille:popover-open) .onglets-bas__lien[popovertarget]:focus-visible {
  outline-color: #111111;
}

body:has(.feuille[data-ouverte]) .onglets-bas__lien[popovertarget]:focus-visible {
  outline-color: #111111;
}

.onglets-bas__ru,
.onglets-bas__nom {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}

.onglets-bas__ru {
  font-family: var(--font-mono);
  font-size: 0.5625rem;
  font-weight: 600;
  letter-spacing: 0.04em;
}

/*
  La feuille « Plus » : posée au-dessus du lecteur, deux colonnes de touches.
  Un « popover » natif vit dans la couche supérieure : il passe devant le
  lecteur sans qu'aucun « z-index » s'en mêle.

  Sans l'API — Safari et iOS avant la 17, Firefox avant la 125 —, le script
  du site ouvre la feuille par un attribut, « data-ouverte ». Elle n'est
  alors plus dans la couche supérieure : un « z-index » la passe devant le
  lecteur et les onglets. Sans ce repli, la moitié des destinations du
  téléphone — journal, studio, administration, éclairage, langue, sortie —
  restaient hors d'atteinte sur un iPhone de 2022.

  La géométrie est sur la feuille même, fermée ou non ; seule l'ouverture
  change, par deux règles distinctes pour la raison dite plus haut.
*/
.feuille {
  display: none;
  position: fixed;
  inset: auto 0.5rem calc(var(--dock-height) + var(--onglets) + 0.75rem + env(safe-area-inset-bottom));
  width: auto;
  max-height: calc(100dvh - var(--dock-height) - var(--onglets) - 2rem);
  margin: 0;
  padding: 0.875rem;
  overflow: auto;
  border: 2px solid var(--pk-trait);
  background: var(--pk-panel);
  color: var(--pk-encre);
  box-shadow: 6px 6px 0 var(--pk-ombre);
}

.feuille:popover-open {
  display: block;
}

.feuille[data-ouverte] {
  display: block;
  z-index: 50;
}

/* Fermer, au-dessus des touches : Échap et le toucher à côté ne se voient pas. */
.feuille__fermer {
  display: flex;
  align-items: center;
  gap: 0.375rem;
  min-height: 2.75rem;
  margin: 0 0 0.625rem auto;
  padding: 0 0.875rem;
  border: 2px solid var(--pk-trait);
  background: var(--pk-champ);
  color: var(--pk-encre);
  font: inherit;
  font-size: 0.875rem;
  font-weight: 700;
  cursor: pointer;
}

.feuille__fermer:hover {
  box-shadow: 4px 4px 0 var(--pk-ombre);
}

.feuille__grille {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  gap: 0.5rem;
}

.feuille__lien {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  min-height: 3.625rem;
  padding: 0.375rem 0.75rem;
  border: 2px solid var(--pk-trait);
  background: var(--pk-champ);
  color: var(--pk-encre);
  font: inherit;
  font-size: 0.875rem;
  font-weight: 700;
  line-height: 1.2;
  text-align: start;
  text-decoration: none;
  cursor: pointer;
}

.feuille__lien:hover {
  color: var(--pk-encre);
  box-shadow: 4px 4px 0 var(--pk-ombre);
}

.feuille__lien[aria-current="page"] {
  background: var(--pk-plein);
  color: var(--pk-sur-plein);
}

.feuille__lien[aria-current="page"] .feuille__ru {
  color: inherit;
}

.feuille__ru {
  color: var(--pk-discret);
  font-family: var(--font-mono);
  font-size: 0.625rem;
  font-weight: 600;
  letter-spacing: 0.1em;
}

.feuille .bascule__theme {
  display: none;
}

:root[data-theme="auto"] .feuille .bascule__theme--auto,
:root[data-theme="clair"] .feuille .bascule__theme--clair,
:root[data-theme="sombre"] .feuille .bascule__theme--sombre {
  display: flex;
}

@media (max-width: 47.5rem) {
  /*
    Le lecteur se resserre : la barre d'onglets prend déjà sa part du bas de
    l'écran. La variable sert aussi au rembourrage du corps, recalculé dessous.
  */
  :root {
    --dock-height: 4.75rem;
  }

  body:has(.onglets-bas) {
    padding-block-end: calc(var(--dock-height) + var(--onglets) + 2rem + env(safe-area-inset-bottom));
  }

  /* Le défilement s'arrête aussi au-dessus de la barre d'onglets. */
  html:has(.onglets-bas) {
    scroll-padding-block-end: calc(var(--dock-height) + var(--onglets) + 1rem + env(safe-area-inset-bottom));
  }

  .onglets-bas {
    display: flex;
  }

  body:has(.onglets-bas) .dock {
    bottom: calc(var(--onglets) + env(safe-area-inset-bottom));
    padding-block-end: 0;
  }

  /*
    La marque et le compte ; le second passe sous la première plutôt que de
    sortir de l'écran quand le texte est agrandi.
  */
  .site-header__inner {
    flex-wrap: wrap;
    justify-content: space-between;
  }

  .brand {
    width: auto;
    min-width: 0;
    justify-content: flex-start;
  }

  /*
    Texte agrandi, la plaque « .FR » passe sous « HARDBASS » plutôt que de
    sortir de l'écran : à 200 % sur 320 pixels, la marque seule en faisait 344.
  */
  .brand__text {
    display: inline-flex;
    flex-wrap: wrap;
    align-items: center;
    row-gap: 0.25rem;
  }

  .site-header .nav:not(.nav--account),
  .bascule,
  .langues-courtes,
  .nav--account .inline-form,
  .nav--account a[href="/compte/connexion"],
  .dock__listeners {
    display: none;
  }

  /* La vignette seule ; le pseudo reste dit, pour les lecteurs d'écran. */
  .nav--account .pseudo {
    padding: 0.25rem;
  }

  .nav--account .pseudo [data-membre] {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
}

/* ================================================================ le bloc */

/*
  L'immeuble de la page d'accueil. Tout s'y mesure en fraction de la largeur
  du bâtiment (« cqw ») : le dessin garde ses proportions du téléphone au
  grand écran, sans un seul point de rupture.
*/
.immeuble {
  position: relative;
  display: flex;
  flex-direction: column;
  min-width: 0;
  padding-block-start: 1rem;
  overflow: hidden;
  background-color: var(--bk-ciel-bas);
  background-image: linear-gradient(180deg, var(--bk-ciel-haut), var(--bk-ciel-bas));
}

/*
  La couture : le ciel se fond dans le panneau du côté où il le touche — à
  gauche quand le bloc est à côté du morceau, en haut quand il passe dessous.
  Peinte avant l'immeuble, qui garde ses arêtes nettes par-dessus.
*/
.immeuble::before {
  content: "";
  position: absolute;
  inset: 0 0 auto;
  height: 4.5rem;
  background-image: linear-gradient(180deg, var(--pk-panel), transparent);
  pointer-events: none;
}

@media (min-width: 71.25rem) {
  .immeuble::before {
    inset: 0 auto 0 0;
    width: 6rem;
    height: auto;
    background-image: linear-gradient(90deg, var(--pk-panel), transparent);
  }
}

.immeuble__lune {
  position: absolute;
  top: 1.6rem;
  right: 8%;
  width: 2.1rem;
  height: 2.1rem;
  border-radius: 50%;
  background: var(--bk-lune);
  box-shadow:
    inset -8px -3px 0 var(--bk-lune-ombre),
    0 0 30px var(--bk-lune);
}

.immeuble__etoile {
  position: absolute;
  width: 2px;
  height: 2px;
  border-radius: 50%;
  background: var(--bk-etoile);
}

.immeuble__etoile:nth-of-type(3n) {
  width: 3px;
  height: 3px;
}

.immeuble__etoile:nth-of-type(2) { left: 5%; top: 6%; }
.immeuble__etoile:nth-of-type(3) { left: 18%; top: 14%; }
.immeuble__etoile:nth-of-type(4) { left: 27%; top: 4%; }
.immeuble__etoile:nth-of-type(5) { left: 39%; top: 11%; }
.immeuble__etoile:nth-of-type(6) { left: 48%; top: 3%; }
.immeuble__etoile:nth-of-type(7) { left: 57%; top: 16%; }
.immeuble__etoile:nth-of-type(8) { left: 66%; top: 7%; }
.immeuble__etoile:nth-of-type(9) { left: 74%; top: 18%; }
.immeuble__etoile:nth-of-type(10) { left: 83%; top: 12%; }
.immeuble__etoile:nth-of-type(11) { left: 12%; top: 20%; }
.immeuble__etoile:nth-of-type(12) { left: 33%; top: 19%; }
.immeuble__etoile:nth-of-type(13) { left: 95%; top: 5%; }

.immeuble__adresse {
  position: relative;
  display: flex;
  justify-content: space-between;
  padding-inline: 1.1rem;
  font-family: var(--font-mono);
  font-size: 0.7rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  color: var(--pk-discret);
}

.immeuble__batiment {
  position: relative;
  container-type: inline-size;
  width: calc(100% - 2.2rem);
  margin: auto auto 0;
  padding-block-start: 0.6rem;
}

/*
  Sous la une, entre la tablette et le grand écran, le bloc prenait toute la
  largeur, et sa hauteur avec : 850 pixels à 1 000 de large, plus que l'écran.
  Le bâtiment s'y borne et se centre ; le ciel, lui, garde toute la largeur.
*/
@media (min-width: 47.5rem) and (max-width: 71.24rem) {
  .immeuble__batiment {
    max-width: 36rem;
  }
}

/* ---- le toit : machineries, antennes, et le slogan sur son treillis ---- */

.immeuble__toit {
  position: relative;
  display: grid;
  grid-template-columns: repeat(14, minmax(0, 1fr));
  align-items: end;
  height: 10cqw;
  margin-inline-end: 11%;
}

.immeuble__machinerie {
  position: relative;
  height: 4.6cqw;
  background-color: var(--bk-panneau-2);
  border: 1px solid var(--bk-joint);
  border-block-end: 0;
}

.immeuble__machinerie:nth-of-type(1) { grid-column: 4; }
.immeuble__machinerie:nth-of-type(2) { grid-column: 11; }

.immeuble__machinerie::after {
  content: "";
  position: absolute;
  left: 30%;
  width: 40%;
  bottom: 0;
  height: 55%;
  background: var(--bk-joint);
}

.immeuble__antenne {
  position: absolute;
  bottom: 0;
  width: 1.5px;
  background: var(--bk-joint);
}

.immeuble__antenne::before,
.immeuble__antenne::after {
  content: "";
  position: absolute;
  height: 1.5px;
  background: var(--bk-joint);
}

.immeuble__antenne::before { top: 8%; left: -1.4cqw; width: 2.8cqw; }
.immeuble__antenne::after { top: 26%; left: -0.9cqw; width: 1.8cqw; }

.immeuble__antenne:nth-of-type(3) { left: 3%; height: 6cqw; }
.immeuble__antenne:nth-of-type(4) { left: 9%; height: 8.5cqw; }
.immeuble__antenne:nth-of-type(5) { left: 80%; height: 9cqw; }
.immeuble__antenne:nth-of-type(6) { left: 86%; height: 5.5cqw; }

.immeuble__enseigne {
  position: absolute;
  left: 12%;
  right: 12%;
  bottom: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
}

/*
  Le slogan en lettres de toit. La nuit il brille comme un néon ; le jour, une
  ombre portée le détache du ciel. Une lettre grésille, comme sur tous les
  toits qui en portent un.
*/
.immeuble__lettres {
  font-family: var(--font-display);
  font-weight: 900;
  font-size: 4.4cqw;
  line-height: 1;
  letter-spacing: 0.02em;
  white-space: nowrap;
  color: var(--pk-accent);
  text-shadow: 0.15cqw 0.15cqw 0 rgb(0 0 0 / 0.35);
}

:root[data-theme="sombre"] .immeuble__lettres {
  text-shadow:
    0 0 1.2cqw currentColor,
    0 0 0.3cqw currentColor;
}

@media (prefers-color-scheme: dark) {
  :root[data-theme="auto"] .immeuble__lettres {
    text-shadow:
      0 0 1.2cqw currentColor,
      0 0 0.3cqw currentColor;
  }
}

.immeuble__panne {
  animation: bk-neon 4s steps(1) infinite;
}

.immeuble__treillis {
  align-self: stretch;
  height: 2.4cqw;
  border-block: 2px solid var(--bk-joint);
  background-image:
    repeating-linear-gradient(45deg, var(--bk-joint) 0 1px, transparent 1px 7px),
    repeating-linear-gradient(-45deg, var(--bk-joint) 0 1px, transparent 1px 7px);
}

/* ---- le corps : façade, rez-de-chaussée, pignon ---- */

.immeuble__corps {
  display: flex;
  align-items: stretch;
}

.immeuble__faces {
  flex: 1;
  min-width: 0;
}

.immeuble__parapet {
  display: block;
  height: 1.4cqw;
  background-color: var(--bk-panneau-3);
  border-block: 2px solid var(--bk-joint);
}

.immeuble__facade {
  display: grid;
  grid-template-columns: repeat(14, minmax(0, 1fr));
  border-inline-start: 1px solid var(--bk-joint);
}

/* Un panneau préfabriqué : chacun d'un gris à peine différent, joints apparents. */
.c {
  position: relative;
  aspect-ratio: 1 / 1.06;
  border-inline-end: 1px solid var(--bk-joint);
  border-block-end: 1px solid var(--bk-joint);
}

.c--t1 { background-color: var(--bk-panneau-1); }
.c--t2 { background-color: var(--bk-panneau-2); }
.c--t3 { background-color: var(--bk-panneau-3); }

/* La fenêtre et son châssis : un meneau, et l'imposte d'un seul côté. */
.f {
  position: absolute;
  inset: 20% 20% 24%;
  border: 1.5px solid var(--bk-cadre);
}

.f::before {
  content: "";
  position: absolute;
  left: 50%;
  top: 0;
  bottom: 0;
  width: 1.5px;
  margin-left: -0.75px;
  background: var(--bk-cadre);
}

.f::after {
  content: "";
  position: absolute;
  left: 50%;
  right: 0;
  top: 30%;
  height: 1.5px;
  background: var(--bk-cadre);
}

/* Porte-fenêtre de loggia : plus haute, décalée vers le fond. */
.f--porte {
  inset: 10% 12% 34% 30%;
}

.f--rideau {
  background-image: linear-gradient(90deg, rgb(255 255 255 / 0.3) 0 40%, transparent 40%);
}

/* Les teintes : éteinte, et les cinq lumières des fenêtres. */
.t-n { background-color: var(--bk-vitre); }
.t-a { background-color: var(--pk-accent); }
.t-j { background-color: #f4e27a; }
.t-b { background-color: #8fb8de; }
.t-o { background-color: #f2a65a; }
.t-r { background-color: #e4c2f0; }

/* Cage d'escalier en briques de verre, éclairée au néon la nuit. */
.escalier {
  position: absolute;
  inset: 6% 34%;
  border: 1.5px solid var(--bk-cadre);
  background-color: var(--bk-escalier);
  background-image:
    linear-gradient(var(--bk-cadre) 1px, transparent 1px),
    linear-gradient(90deg, var(--bk-cadre) 1px, transparent 1px);
  background-size: 100% 16%, 50% 100%;
}

/* La loggia et son habillage, tel que chaque famille l'a posé. */
.l {
  position: absolute;
  inset: auto 4% 4%;
  height: 40%;
  z-index: 1;
  border: 1.5px solid var(--bk-cadre);
  box-shadow: 0 0.4cqw 0 rgb(0 0 0 / 0.25);
}

.l--tole-rouge,
.l--tole-bleue,
.l--tole-beige,
.l--tole-verte {
  background-image: repeating-linear-gradient(90deg, rgb(0 0 0 / 0.24) 0 1px, transparent 1px 3px);
}

.l--tole-rouge { background-color: #c8553d; }
.l--tole-bleue { background-color: #3e6e8e; }
.l--tole-beige { background-color: #d9c27a; }
.l--tole-verte { background-color: #7a8b5a; }

.l--nue {
  background-color: var(--bk-panneau-3);
  background-image:
    repeating-linear-gradient(90deg, var(--bk-cadre) 0 1px, transparent 1px 5px),
    linear-gradient(180deg, transparent 55%, rgb(0 0 0 / 0.12) 55%);
}

/* Vitrée jusqu'en haut : la loggia prend la teinte de la pièce derrière. */
.l--vitree {
  top: 6%;
  height: auto;
  background-image:
    linear-gradient(90deg, var(--bk-cadre) 1.5px, transparent 1.5px),
    linear-gradient(180deg, transparent 44%, var(--bk-cadre) 44% calc(44% + 1.5px), transparent calc(44% + 1.5px));
  background-size: 25% 100%, 100% 100%;
}

.linge {
  position: absolute;
  inset: 40% 10% auto;
  height: 13%;
  z-index: 1;
  border-block-start: 1px solid var(--bk-cadre);
  background-image: linear-gradient(
    90deg,
    #e4c2f0 0 28%,
    transparent 28% 36%,
    #f2f2ee 36% 64%,
    transparent 64% 72%,
    #8fb8de 72%
  );
}

.parabole {
  position: absolute;
  right: 5%;
  top: 14%;
  z-index: 2;
  width: 24%;
  aspect-ratio: 1;
  border-radius: 50%;
  background: #e9e6df;
  border: 1.5px solid var(--bk-cadre);
  transform: rotate(-25deg) scaleX(0.75);
}

.clim {
  position: absolute;
  left: 24%;
  width: 30%;
  bottom: 5%;
  height: 14%;
  z-index: 2;
  background: #dad7d0;
  border: 1px solid var(--bk-cadre);
}

/* ---- le rez-de-chaussée ---- */

.immeuble__rdc {
  position: relative;
  display: grid;
  grid-template-columns: repeat(14, minmax(0, 1fr));
  background-color: var(--bk-panneau-2);
  border-block-start: 0.5cqw solid var(--bk-joint);
  border-inline-start: 1px solid var(--bk-joint);
}

.rdc {
  position: relative;
  aspect-ratio: 1 / 1.3;
  border-inline-end: 1px solid var(--bk-joint);
}

.rdc--magasin {
  grid-column: 1 / span 3;
  aspect-ratio: auto;
}

.rdc__vitre {
  position: absolute;
  inset: 32% 20% 20%;
  border: 1.5px solid var(--bk-cadre);
}

/* Les barreaux du rez-de-chaussée, posés par-dessus la vitre. */
.rdc__vitre::after {
  content: "";
  position: absolute;
  inset: 0;
  background-image:
    repeating-linear-gradient(90deg, #2a2b2e 0 1.5px, transparent 1.5px 22%),
    linear-gradient(180deg, transparent 46%, #2a2b2e 46% 54%, transparent 54%);
}

.rdc__enseigne {
  position: absolute;
  inset: 7% 5% auto;
  height: 22%;
  display: flex;
  align-items: center;
  justify-content: center;
  overflow: hidden;
  background: #10241a;
  border: 1.5px solid var(--bk-cadre);
  color: #7cf2a0;
  font-family: var(--font-mono);
  font-size: 1.7cqw;
  font-weight: 600;
  letter-spacing: 0.12em;
  white-space: nowrap;
}

:root[data-theme="sombre"] .rdc__enseigne {
  text-shadow: 0 0 0.8cqw #7cf2a0;
}

@media (prefers-color-scheme: dark) {
  :root[data-theme="auto"] .rdc__enseigne {
    text-shadow: 0 0 0.8cqw #7cf2a0;
  }
}

.rdc__vitrine {
  position: absolute;
  inset: 36% 5% 10%;
  background-color: #f2d58a;
  border: 1.5px solid var(--bk-cadre);
  background-image:
    repeating-linear-gradient(180deg, transparent 0 0.9cqw, rgb(60 40 10 / 0.35) 0.9cqw 1.2cqw),
    linear-gradient(90deg, transparent 49.5%, var(--bk-cadre) 49.5% 50.5%, transparent 50.5%);
}

.rdc__numero {
  position: absolute;
  left: 50%;
  top: 5%;
  z-index: 3;
  translate: -50% 0;
  padding: 0.25cqw 0.5cqw;
  background: #1e4e9c;
  color: #f4f2ed;
  border: 1px solid #f4f2ed;
  font-family: var(--font-mono);
  font-size: 1.4cqw;
  font-weight: 600;
  line-height: 1;
}

.rdc__auvent {
  position: absolute;
  inset: 22% -22% auto;
  height: 7%;
  z-index: 2;
  background-color: var(--bk-panneau-3);
  border: 1px solid var(--bk-joint);
  box-shadow: 0 0.5cqw 0 rgb(0 0 0 / 0.28);
}

.rdc__ampoule {
  position: absolute;
  left: 50%;
  top: 30%;
  z-index: 2;
  width: 1.1cqw;
  height: 1.1cqw;
  margin-left: -0.55cqw;
  border-radius: 50%;
  background: var(--bk-ampoule);
  box-shadow: 0 0 1.8cqw 0.6cqw var(--bk-lueur);
}

.rdc__porte {
  position: absolute;
  inset: 34% 16% 0;
  background-color: #2f5a4c;
  border: 1.5px solid var(--bk-cadre);
  border-block-end: 0;
}

.rdc__porte::after {
  content: "";
  position: absolute;
  inset: 12% 25% auto;
  height: 20%;
  background-color: var(--bk-escalier);
  border: 1px solid var(--bk-cadre);
}

.rdc__interphone {
  position: absolute;
  right: 3%;
  top: 52%;
  z-index: 2;
  width: 10%;
  height: 14%;
  background: #b9b6ae;
  border: 1px solid var(--bk-cadre);
}

.rdc__tag {
  position: absolute;
  left: 47%;
  top: 3%;
  z-index: 3;
  rotate: -7deg;
  color: var(--pk-accent);
  font-family: var(--font-display);
  font-size: 2.6cqw;
  font-weight: 900;
  letter-spacing: -0.02em;
  opacity: 0.9;
  text-shadow: 0.12cqw 0.12cqw 0 rgb(0 0 0 / 0.45);
}

.immeuble__soubassement {
  display: block;
  height: 1.8cqw;
  background-color: var(--bk-soubassement);
  border-block-start: 1px solid var(--bk-joint);
  background-image: repeating-linear-gradient(90deg, transparent 0 6cqw, rgb(0 0 0 / 0.5) 6cqw 7.2cqw);
  background-size: 100% 40%;
  background-position: 0 50%;
  background-repeat: no-repeat;
}

/* Le pignon et son numéro peint, la plaque de rue bleue. */
.immeuble__pignon {
  flex: none;
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 11%;
  padding-block-start: 4cqw;
  border-inline-start: 1px solid var(--bk-joint);
  background-color: var(--bk-pignon);
  background-image: linear-gradient(180deg, transparent calc(100% - 1px), var(--bk-joint) calc(100% - 1px));
  background-size: 100% 9.5%;
  clip-path: polygon(0 0, 100% 2.5%, 100% 100%, 0 100%);
}

.immeuble__numero {
  font-family: var(--font-display);
  font-size: 6cqw;
  font-weight: 900;
  line-height: 0.95;
  text-align: center;
  color: var(--bk-pignon-chiffre);
}

.immeuble__plaque {
  margin-block: auto 9cqw;
  padding: 0.3cqw 0.4cqw;
  background: #1e4e9c;
  color: #f4f2ed;
  border: 1px solid #f4f2ed;
  font-family: var(--font-mono);
  font-size: 0.95cqw;
  font-weight: 600;
  line-height: 1.2;
  text-align: center;
}

/* ---- la rue ---- */

.immeuble__rue {
  position: relative;
  height: 7cqw;
  background-color: var(--bk-trottoir);
  border-block-start: 0.4cqw solid var(--bk-joint);
}

.immeuble__rue::after {
  content: "";
  position: absolute;
  inset: auto 0 0;
  height: 1.4cqw;
  background: var(--bk-bordure);
}

.rue__objet {
  position: absolute;
  bottom: 1.6cqw;
  z-index: 4;
  height: auto;
  overflow: visible;
}

.rue__lampadaire { left: 40%; width: 7cqw; }
.rue__banc { left: 23%; width: 12cqw; }
.rue__chat { left: 30%; width: 2.6cqw; bottom: 4.3cqw; }
.rue__gopnik { left: 51%; width: 10cqw; bottom: 1.1cqw; }
.rue__gopnik--miroir { left: 71%; transform: scaleX(-1); }
.rue__bouleau { left: 89%; width: 10cqw; bottom: 1.2cqw; }

.rue__metal { fill: var(--bk-metal); }
.rue__metal-trait { stroke: var(--bk-metal); }
.rue__ampoule { fill: var(--bk-ampoule); }
.rue__feuillage { fill: var(--bk-feuillage); }

/* Le halo du lampadaire : un dégradé CSS, sans référence « #id » à résoudre. */
.rue__halo {
  position: absolute;
  left: calc(40% + 1.5cqw);
  bottom: 13cqw;
  z-index: 3;
  width: 18cqw;
  aspect-ratio: 1;
  translate: -50% 50%;
  border-radius: 50%;
  background: radial-gradient(circle, var(--bk-halo) 0, transparent 70%);
  pointer-events: none;
}

/* Des pelures de graines de tournesol, là où l'on s'accroupit. */
.rue__graine {
  position: absolute;
  bottom: 1.7cqw;
  z-index: 4;
  width: 0.5cqw;
  height: 0.3cqw;
  border-radius: 50%;
  background: #cfc8b4;
}

.rue__graine:nth-of-type(2) { left: 61.5%; }
.rue__graine:nth-of-type(3) { left: 63%; }
.rue__graine:nth-of-type(4) { left: 64.6%; }
.rue__graine:nth-of-type(5) { left: 69.5%; }

/* ---- le bloc vit avec la musique ---- */

/*
  Quand la lecture part, des fenêtres éteintes s'allument en vague, colonne
  après colonne, et les télévisions se mettent à clignoter. L'état vient du
  lecteur lui-même — « data-state » sur le dock — et ne demande donc aucun
  script : le bloc ne sait rien du lecteur, il le regarde.
*/
.f--e {
  transition: background-color 500ms ease;
}

body:has(.dock[data-state="playing"]) .f--e1 { background-color: #f4e27a; }
body:has(.dock[data-state="playing"]) .f--e2 { background-color: #ff9b73; }
body:has(.dock[data-state="playing"]) .f--e3 { background-color: #8fb8de; }

.immeuble__facade > :nth-child(14n + 1) .f--e { transition-delay: 0ms; }
.immeuble__facade > :nth-child(14n + 2) .f--e { transition-delay: 50ms; }
.immeuble__facade > :nth-child(14n + 3) .f--e { transition-delay: 100ms; }
.immeuble__facade > :nth-child(14n + 4) .f--e { transition-delay: 150ms; }
.immeuble__facade > :nth-child(14n + 5) .f--e { transition-delay: 200ms; }
.immeuble__facade > :nth-child(14n + 6) .f--e { transition-delay: 250ms; }
.immeuble__facade > :nth-child(14n + 7) .f--e { transition-delay: 300ms; }
.immeuble__facade > :nth-child(14n + 8) .f--e { transition-delay: 350ms; }
.immeuble__facade > :nth-child(14n + 9) .f--e { transition-delay: 400ms; }
.immeuble__facade > :nth-child(14n + 10) .f--e { transition-delay: 450ms; }
.immeuble__facade > :nth-child(14n + 11) .f--e { transition-delay: 500ms; }
.immeuble__facade > :nth-child(14n + 12) .f--e { transition-delay: 550ms; }
.immeuble__facade > :nth-child(14n + 13) .f--e { transition-delay: 600ms; }
.immeuble__facade > :nth-child(14n) .f--e { transition-delay: 650ms; }

.f--tv {
  animation: bk-tele 1.8s steps(1) infinite;
  animation-play-state: paused;
}

.immeuble__facade > :nth-child(3n) .f--tv { animation-delay: -0.6s; }
.immeuble__facade > :nth-child(3n + 1) .f--tv { animation-delay: -1.2s; }

body:has(.dock[data-state="playing"]) .f--tv {
  animation-play-state: running;
}

/* ================================================================ les pages */

/*
  Les pages autres que l'accueil, telles que la maquette les dessine. La
  plupart n'ont reçu aucun balisage : tout s'accroche à ce que chacune porte
  déjà d'unique — l'identifiant d'un panneau, ses onglets. Ce qui n'existait
  pas — la fiche d'un membre, l'entrée des pages de compte, l'argot des
  erreurs — n'est rendu que sous Панелька.
*/

/* ---- tête de page : l'étiquette russe en plaque, le titre en très grand ---- */

.site-main > .page-title {
  margin-block-start: clamp(0.5rem, 3vw, 2rem);
  font-size: clamp(2.125rem, 6.5vw, 5.5rem);
  line-height: 0.94;
  letter-spacing: -0.04em;
  overflow-wrap: anywhere;
  hyphens: auto;
}

/*
  L'étiquette vient de la feuille et se tait aux lecteurs d'écran, comme
  celles des panneaux et de la navigation : elle ne dit rien que le titre ne
  dise, en russe. Tue sous « @supports » seulement, pour la raison dite à
  l'étiquette des panneaux : avec « var() », la forme de repli ne servirait
  jamais.
*/
.site-main > .page-title::before {
  content: var(--pk-page-ru, none);
  display: table;
  margin-block-end: 0.875rem;
  padding: 0.125rem 0.5rem;
  background: var(--pk-plein);
  color: var(--pk-sur-plein);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.6;
  letter-spacing: 0.1em;
  hyphens: manual;
}

@supports (content: "" / "") {
  .site-main > .page-title::before {
    content: var(--pk-page-ru, none) / "";
  }
}

.site-main:has(#titre-passages) {
  --pk-page-ru: "ИСТОРИЯ";
}

.site-main:has(:is(#titre-entrees, #titre-ajout, #titre-visibilite, #titre-edition)) {
  --pk-page-ru: "ЖУРНАЛ";
}

.site-main:has(> .programme) {
  --pk-page-ru: "ПРОГРАММА";
}

.site-main:has(#titre-etat) {
  --pk-page-ru: "СТУДИЯ";
}

.site-main:has(> .onglets [href^="/admin"]) {
  --pk-page-ru: "УПРАВДОМ";
}

/*
  La même plaque, posée dans le balisage là où la page la rend elle-même :
  fiche d'un membre, entrée des pages de compte, pages d'erreur. Le russe y
  est tu aux lecteurs d'écran ; ce qui le suit, en clair, ne l'est pas.
*/
.surtitre {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.375rem 0.75rem;
  margin: 0;
  color: var(--pk-encre);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.6;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.surtitre__ru {
  padding: 0.125rem 0.5rem;
  background: var(--pk-plein);
  color: var(--pk-sur-plein);
}

/* ------------------------------------------------------------- historique */

/*
  Le titre à gauche, la recherche à droite sur sa ligne de base, la liste
  dessous sur toute la largeur. Une colonne sur un téléphone.
*/
@media (min-width: 60rem) {
  .site-main:has(#titre-passages) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 30rem);
    align-items: end;
    column-gap: 1.5rem;
  }

  .site-main:has(#titre-passages) > :not(.page-title, .recherche) {
    grid-column: 1 / -1;
  }
}

.site-main:has(#titre-passages) > .recherche {
  margin: 0;
  flex-wrap: nowrap;
}

.site-main:has(#titre-passages) .recherche__champ {
  min-height: 3.375rem;
  padding: 0 0.75rem;
  font-size: 1rem;
  box-shadow: 4px 4px 0 var(--pk-ombre);
}

.site-main:has(#titre-passages) .recherche__effacer {
  min-height: 3.375rem;
}

/* Le panneau s'ouvre sur sa plaque noire, d'un bord à l'autre. */
section[aria-labelledby="titre-passages"] {
  padding: 0;
}

#titre-passages {
  display: block;
  margin: 0;
  padding: 0.75rem 1.25rem;
  border: 0;
  background: var(--pk-plein);
  color: var(--pk-sur-plein);
  font-family: var(--font-mono);
  font-size: 0.75rem;
  font-weight: 600;
  line-height: 1.5;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

/* L'étiquette « ИСТОРИЯ » est montée au titre de la page. */
#titre-passages::before {
  content: none;
}

/*
  Une ligne par passage : l'heure en chiffres de compteur, la pochette en
  carré franc, le titre au-dessus de l'artiste, et la playlist en pastille au
  bout. L'heure passe devant la pochette : c'est l'ordre de la maquette, et
  l'ordre du balisage reste celui que lisent les lecteurs d'écran.
*/
#titre-passages ~ .playlist .playlist__row {
  align-items: center;
  gap: 1rem;
  padding: 0.625rem 0.75rem 0.625rem 1.25rem;
  border-block-end: 1px solid var(--pk-fin);
  font-size: 1rem;
  transition: background-color 150ms ease;
}

#titre-passages ~ .playlist .playlist__row:hover {
  background: var(--pk-bg);
}

#titre-passages ~ .playlist .playlist__row > time {
  order: -1;
  flex: none;
  min-width: 6.25rem;
  font-size: 0.8125rem;
  font-weight: 600;
}

#titre-passages ~ .playlist .vignette {
  --vignette: 2.75rem;
}

#titre-passages ~ .playlist .playlist__song {
  flex: 1;
  flex-direction: column;
  flex-wrap: nowrap;
  align-items: stretch;
  gap: 0;
}

#titre-passages ~ .playlist .playlist__song > * {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

#titre-passages ~ .playlist .playlist__song strong {
  font-size: 1.0625rem;
  font-weight: 700;
}

#titre-passages ~ .playlist .playlist__song .muted {
  font-size: 0.875rem;
}

#titre-passages ~ .playlist .tag {
  flex: none;
  padding: 0.0625rem 0.5625rem;
  font-size: 0.8125rem;
  letter-spacing: 0;
  white-space: nowrap;
}

#titre-passages ~ .empty {
  margin: 0;
  padding: 1.75rem 1.25rem;
  color: var(--pk-encre);
  font-size: 1.0625rem;
  font-style: normal;
}

/* Le téléphone garde l'heure, la pochette et le morceau. */
@media (max-width: 47.5rem) {
  #titre-passages ~ .playlist .playlist__row {
    gap: 0.75rem;
    padding-inline: 1rem 0.75rem;
  }

  #titre-passages ~ .playlist .playlist__row > time {
    min-width: 0;
    max-width: 3.25rem;
    font-size: 0.75rem;
    line-height: 1.3;
  }

  #titre-passages ~ .playlist .tag {
    display: none;
  }
}

/* ------------------------------------------------- fiche d'un membre */

/*
  En tête du profil et de la page d'un membre : la photo en grand carré, son
  étiquette, le pseudo en très grand, ce qui le distingue, et ses insignes
  sous un filet. Le même panneau que les autres — contour, ombre franche.
*/
.fiche {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 1.5rem;
  margin-block-start: clamp(0.5rem, 3vw, 2rem);
  padding: clamp(1.125rem, 3vw, 1.75rem);
  border: 2px solid var(--pk-trait);
  background: var(--pk-panel);
  box-shadow: 6px 6px 0 var(--pk-ombre);
  animation: pk-tampon 420ms var(--ease-out) both;
}

.fiche__avatar {
  display: block;
  width: 7.5rem;
  height: 7.5rem;
  border: 2px solid var(--pk-ombre);
  box-shadow: 4px 4px 0 var(--pk-ombre);
  background: var(--pk-champ);
}

.fiche__identite {
  flex: 1 1 13.75rem;
  min-width: 0;
}

.fiche__pseudo {
  margin: 0.375rem 0 0;
  font-size: clamp(1.875rem, 5vw, 3.5rem);
  line-height: 1;
  letter-spacing: -0.03em;
  text-transform: none;
  overflow-wrap: anywhere;
}

.fiche__pastilles,
.fiche .table__actions {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.5rem;
  margin-block-start: 0.75rem;
}

.fiche__pastille {
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
  padding: 0.0625rem 0.5625rem;
  border: 2px solid var(--pk-trait);
  font-size: 0.8125rem;
  font-weight: 600;
  white-space: nowrap;
}

.fiche__insignes {
  flex: 1 1 100%;
  padding-block-start: 1rem;
  border-block-start: 1px solid var(--pk-fin);
}

.fiche .insignes-entete {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 0.625rem;
  margin: 0;
}

/* Les insignes en épinglettes de revers : un rond d'émail, et leur nom. */
.fiche .pastille-insigne {
  gap: 0.5rem;
  padding: 0.125rem 0.75rem 0.125rem 0.25rem;
  border-radius: 999px;
  background: var(--pk-panel);
  color: var(--pk-encre);
  box-shadow: none;
}

.fiche .pastille-insigne__etoile {
  display: inline-block;
  width: 1.375rem;
  height: 1.375rem;
  border: 2px solid var(--pk-ombre);
  border-radius: 50%;
  background: var(--pk-accent);
  color: transparent;
  font-size: 0;
}

.fiche .insignes-entete__lien {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
}

/*
  L'onglet « Identité » du profil : l'identité et le mot de passe en large à
  gauche, la couleur du pseudo dans la colonne étroite. Sans le panneau de
  couleur — un public que le propriétaire n'a pas ouvert —, la grille garde
  ses colonnes d'origine.
*/
@media (min-width: 60rem) {
  .grid--profile:has(> [aria-labelledby="titre-identite"]):has(> [aria-labelledby="titre-couleur"]) {
    grid-template-columns: minmax(0, 1.6fr) minmax(0, 1fr);
    align-items: start;
  }

  .grid--profile > [aria-labelledby="titre-identite"],
  .grid--profile > [aria-labelledby="titre-mot-de-passe"] {
    grid-column: 1;
  }

  .grid--profile:has(> [aria-labelledby="titre-couleur"]) > [aria-labelledby="titre-couleur"] {
    grid-column: 2;
    grid-row: 1 / span 2;
  }
}

/* La page d'un membre : ses favoris, puis ses insignes, sur toute la largeur. */
.fiche ~ .grid--profile:has(> [aria-labelledby="titre-membre-favoris"]) {
  grid-template-columns: minmax(0, 1fr);
}

/* ----------------------------------------------------------------- studio */

/*
  Deux colonnes : l'état de l'antenne et les créneaux à gauche, ce qu'il faut
  pour prendre l'antenne à droite, en large. L'ordre du balisage ne change pas
  — on lit l'état, puis les réglages, puis les créneaux.
*/
@media (min-width: 60rem) {
  .site-main:has(#titre-etat) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1.45fr);
    align-items: start;
  }

  .site-main:has(#titre-etat) > :is(.page-title, .notice) {
    grid-column: 1 / -1;
  }

  .site-main:has(#titre-etat) > section {
    grid-column: 1;
  }

  .site-main:has(#titre-etat) > [aria-labelledby="titre-diffusion"] {
    grid-column: 2;
    grid-row: span 3;
  }
}

/* « Prendre l'antenne » s'annonce sur un bandeau orange, d'un bord à l'autre. */
section[aria-labelledby="titre-diffusion"] {
  --pk-marge: clamp(1rem, 0.8rem + 1vw, 1.6rem);
}

#titre-diffusion {
  margin: calc(-1 * var(--pk-marge)) calc(-1 * var(--pk-marge)) 1.125rem;
  padding: 0.75rem var(--pk-marge);
  border-block-end: 2px solid var(--pk-trait);
  background: var(--pk-accent);
  color: var(--pk-sur-accent);
}

#titre-diffusion::before {
  content: none;
}

/* Les réglages à recopier, en fiche technique : une ligne par paramètre. */
.diffusion__reglages {
  gap: 0;
  margin-block-start: 1rem;
  border: 2px solid var(--pk-trait);
  background: var(--pk-champ);
  font-size: 0.9375rem;
}

.diffusion__reglages > :is(dt, dd) {
  margin: 0;
  padding: 0.625rem 0.75rem;
  border-block-end: 1px solid var(--pk-fin);
  overflow-wrap: anywhere;
}

.diffusion__reglages > :is(dt, dd):nth-last-child(-n + 2) {
  border-block-end: 0;
}

.diffusion__reglages dt {
  font-family: var(--font-body);
  font-size: 0.8125rem;
  letter-spacing: 0;
  text-transform: none;
}

.diffusion__reglages code {
  font-family: var(--font-mono);
}

/* ---------------------------------------------------------- administration */

/* Les compteurs en cases, comme ceux de la maquette. */
.site-main > .hero__stats--compact {
  display: inline-grid;
  grid-auto-flow: column;
  grid-auto-columns: minmax(8rem, 1fr);
  align-self: flex-start;
  gap: 0;
  width: fit-content;
  max-width: 100%;
  margin: 0;
  border: 2px solid var(--pk-trait);
  background: var(--pk-panel);
  box-shadow: 4px 4px 0 var(--pk-ombre);
}

.site-main > .hero__stats--compact > div {
  padding: 0.75rem 0.875rem;
  text-align: start;
}

.site-main > .hero__stats--compact > div + div {
  border-inline-start: 2px solid var(--pk-trait);
}

.site-main > .hero__stats--compact dt {
  font-family: var(--font-mono);
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.1em;
  color: var(--pk-discret);
}

.site-main > .hero__stats--compact dd {
  margin: 0.25rem 0 0;
  font-size: 1.375rem;
  font-weight: 900;
  overflow-wrap: anywhere;
}

/*
  Les panneaux à tableau : le titre et sa recherche sur la même ligne, puis le
  tableau d'un bord à l'autre, sous son en-tête noir.
*/
.site-main:has(> .onglets [href^="/admin"]) .panel {
  --pk-marge: clamp(1rem, 0.8rem + 1vw, 1.6rem);
}

@media (min-width: 60rem) {
  section:is([aria-labelledby="titre-membres"], [aria-labelledby="titre-codes"]) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 22.5rem);
    align-items: center;
    column-gap: 1rem;
  }

  section:is([aria-labelledby="titre-membres"], [aria-labelledby="titre-codes"]) > :not(.panel__title, .recherche) {
    grid-column: 1 / -1;
  }

  section:is([aria-labelledby="titre-membres"], [aria-labelledby="titre-codes"]) > .panel__title {
    margin: 0;
    border: 0;
  }

  section:is([aria-labelledby="titre-membres"], [aria-labelledby="titre-codes"]) > .recherche {
    margin: 0;
    flex-wrap: nowrap;
  }

  section[aria-labelledby="titre-codes"] > .filtres {
    margin-block-start: 1rem;
  }

  /*
    Les invitations : les trois réglages lourds du propriétaire côte à côte,
    puis la distribution et l'historique en large. L'ordre reste celui du
    balisage, celui où l'on parcourt la page au clavier.
  */
  .site-main:has(#titre-codes) {
    display: grid;
    grid-template-columns: repeat(3, minmax(0, 1fr));
  }

  .site-main:has(#titre-codes) > :not(.panel--grave) {
    grid-column: 1 / -1;
  }
}

/* Distribuer : les trois champs sur une rangée, le bouton dessous. */
section[aria-labelledby="titre-distribuer"] > .pile-de-champs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(100%, 13rem), 1fr));
  align-items: start;
  gap: 1rem;
}

section[aria-labelledby="titre-distribuer"] > .pile-de-champs > .btn {
  grid-column: 1 / -1;
  justify-self: start;
}

.site-main:has(> .onglets [href^="/admin"]) .recherche__champ {
  min-height: 2.875rem;
  padding: 0 0.75rem;
  font-size: 1rem;
}

.site-main:has(> .onglets [href^="/admin"]) :is(.table-scroll, .panel > .table) {
  margin-inline: calc(-1 * var(--pk-marge));
}

.site-main:has(> .onglets [href^="/admin"]) section[aria-labelledby="titre-membres"] > .table-scroll {
  margin-block-start: 1.25rem;
}

.site-main:has(> .onglets [href^="/admin"]) .panel > :is(.table-scroll, .table):last-child {
  margin-block-end: calc(-1 * var(--pk-marge));
}

.site-main:has(> .onglets [href^="/admin"]) .panel > .table {
  width: calc(100% + 2 * var(--pk-marge));
}

.site-main:has(> .onglets [href^="/admin"]) .table :is(th, td):first-child {
  padding-inline-start: var(--pk-marge);
}

.site-main:has(> .onglets [href^="/admin"]) .table :is(th, td):last-child {
  padding-inline-end: var(--pk-marge);
}

.site-main:has(> .onglets [href^="/admin"]) .table th {
  padding-block: 0.625rem;
  font-size: 0.6875rem;
  font-weight: 600;
  letter-spacing: 0.1em;
}

/*
  Sous 760 pixels, chaque ligne devient une carte : plus de défilement de
  côté pour lire la colonne d'à côté. Les cellules gardent leur ordre, donc
  leur sens ; l'en-tête reste dans la page pour les lecteurs d'écran, et
  chaque cellule ambiguë rappelle le nom de sa colonne — un attribut que
  seule Панелька reçoit. Rien n'est dupliqué : c'est le même tableau.

  Un tableau changé d'affichage perd sa nature de tableau aux yeux de
  WebKit : le balisage porte donc ses rôles en toutes lettres. Et le rappel
  de colonne se tait aux lecteurs d'écran, qui ont déjà l'en-tête — il ne
  ferait que le répéter devant chaque valeur.
*/
@media (max-width: 47.5rem) {
  .site-main:has(> .onglets [href^="/admin"]) .table-scroll {
    overflow: visible;
  }

  .site-main:has(> .onglets [href^="/admin"]) :is(.table, .table tbody) {
    display: block;
    width: auto;
    min-width: 0;
  }

  .site-main:has(> .onglets [href^="/admin"]) .table thead {
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }

  .site-main:has(> .onglets [href^="/admin"]) .table tr {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.5rem 0.75rem;
    padding: 0.875rem var(--pk-marge);
    border-block-end: 1px solid var(--pk-fin);
  }

  .site-main:has(> .onglets [href^="/admin"]) .table td {
    display: block;
    flex: 1 1 100%;
    min-width: 0;
    max-width: none;
    padding: 0;
    border: 0;
    background: none;
    overflow-wrap: anywhere;
    white-space: normal;
  }

  .site-main:has(> .onglets [href^="/admin"]) .table td.table__email,
  .site-main:has(> .onglets [href^="/admin"]) .table td.table__email + td {
    flex: 0 1 auto;
    font-size: 0.8125rem;
  }

  .site-main:has(> .onglets [href^="/admin"]) .table td[data-libelle]::before {
    content: attr(data-libelle) "\00a0·\00a0";
    content: attr(data-libelle) "\00a0·\00a0" / "";
    color: var(--pk-discret);
    font-family: var(--font-mono);
    font-size: 0.6875rem;
    font-weight: 600;
    letter-spacing: 0.08em;
    text-transform: uppercase;
  }

  .site-main:has(> .onglets [href^="/admin"]) .table td[data-libelle] {
    flex: 1 1 auto;
  }
}

/* ------------------------------------------------- l'entrée des comptes */

/*
  Connexion, inscription, mot de passe oublié : ce qu'on gagne à entrer à
  gauche, le formulaire à droite. Sur un téléphone, l'accroche passe dessus.
*/
.site-main:has(> .acces) {
  padding-block: clamp(2rem, 7vw, 5rem);
}

@media (min-width: 60rem) {
  .site-main:has(> .acces) {
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 30rem);
    align-items: center;
    column-gap: clamp(1.75rem, 6vw, 4.5rem);
  }
}

.site-main:has(> .acces) > .panel--form {
  margin-inline: 0;
  box-shadow: 8px 8px 0 var(--pk-ombre);
}

.acces {
  display: block;
  min-width: 0;
}

.acces__titre {
  margin: 1rem 0 0;
  font-family: var(--font-display);
  font-size: clamp(2.375rem, 6.5vw, 5.5rem);
  font-weight: 900;
  line-height: 0.94;
  letter-spacing: -0.04em;
  text-transform: uppercase;
  overflow-wrap: anywhere;
}

/* Le point final, à l'accent : un décor, que personne ne lit. */
.acces__titre::after {
  content: ".";
  content: "." / "";
  color: var(--pk-accent);
}

.acces__atouts {
  display: flex;
  flex-direction: column;
  gap: 0.625rem;
  margin: 1.75rem 0 0;
  padding: 0;
  list-style: none;
  font-size: 1.0625rem;
  font-weight: 600;
}

.acces__atouts li {
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.acces__numero {
  display: inline-flex;
  flex: none;
  align-items: center;
  justify-content: center;
  width: 2.125rem;
  height: 2.125rem;
  border: 2px solid var(--pk-ombre);
  background: var(--pk-accent);
  color: var(--pk-sur-accent);
  font-family: var(--font-display);
  font-size: 0.75rem;
  font-weight: 900;
}

/*
  Connexion ou inscription, deux touches accolées en tête du formulaire. La
  touche pleine est la page en cours : son titre, que la touche répète, ne
  reste que pour les lecteurs d'écran.
*/
.acces__bascule {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  margin: calc(-1 * clamp(1rem, 0.8rem + 1vw, 1.6rem)) calc(-1 * clamp(1rem, 0.8rem + 1vw, 1.6rem)) 1.5rem;
  border-block-end: 2px solid var(--pk-trait);
}

.acces__choix {
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 3.25rem;
  padding: 0 0.75rem;
  background: var(--pk-champ);
  color: var(--pk-encre);
  font-weight: 700;
  text-align: center;
  text-decoration: none;
  transition: background-color 200ms ease, color 200ms ease;
}

.acces__choix + .acces__choix {
  border-inline-start: 2px solid var(--pk-trait);
}

.acces__choix:hover {
  color: var(--pk-encre);
  background: var(--pk-survol);
}

.acces__choix[aria-current="page"] {
  background: var(--pk-plein);
  color: var(--pk-sur-plein);
}

.acces ~ .panel--form > p.muted:has(> a) {
  margin: 0.75rem 0 0;
  font-size: 0.875rem;
}

.acces ~ .panel--form > p.muted > a {
  display: inline-flex;
  align-items: center;
  min-height: 2.75rem;
  color: var(--pk-encre);
  font-weight: 700;
  text-decoration: underline;
  text-underline-offset: 3px;
}

.acces__bascule ~ .page-title {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

/* --------------------------------------------------------- pages d'erreur */

/*
  Le code en très grand dans sa plaque orange, et à côté : l'argot en
  étiquette, le titre, ce qu'il faut savoir, le retour. Une seule colonne sur
  un téléphone.
*/
.panel--form:has(> .error-code) {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  align-items: center;
  gap: 0.875rem 3rem;
  max-width: none;
  margin-block-start: clamp(1rem, 4vw, 2.5rem);
  padding: clamp(1.25rem, 4vw, 2.75rem);
  box-shadow: 8px 8px 0 var(--pk-ombre);
}

/*
  Sur grand écran, le texte se centre à hauteur du code : deux rangées
  souples l'encadrent, et chaque élément y prend la sienne.
*/
@media (min-width: 60rem) {
  .panel--form:has(> .error-code) {
    grid-template-columns: auto minmax(0, 1fr);
    grid-template-rows: 1fr repeat(4, auto) 1fr;
  }

  .panel--form:has(> .error-code) > .error-code {
    grid-row: 1 / -1;
    margin-block-end: 0;
  }

  .panel--form:has(> .error-code) > .surtitre {
    grid-row: 2;
  }

  .panel--form:has(> .error-code) > .page-title {
    grid-row: 3;
  }

  .panel--form:has(> .error-code) > .page-title + p {
    grid-row: 4;
  }

  .panel--form:has(> .error-code) > p:last-child {
    grid-row: 5;
  }

  .panel--form:has(> .error-code) > :not(.error-code) {
    grid-column: 2;
  }
}

.panel--form > .error-code {
  display: inline-block;
  justify-self: start;
  margin: 0 0 1rem;
  font-family: var(--font-display);
  font-size: clamp(5.5rem, 18vw, 13.75rem);
  line-height: 1;
}

.panel--form:has(> .error-code) > .page-title {
  margin: 0;
  font-size: clamp(1.75rem, 4vw, 3.25rem);
  line-height: 1;
  letter-spacing: -0.03em;
}

.panel--form:has(> .error-code) > p:not(.error-code, .surtitre) {
  max-width: 48ch;
  margin: 0;
  color: var(--pk-doux);
  font-size: 1.125rem;
}

.panel--form:has(> .error-code) > p:last-child {
  margin-block-start: 0.75rem;
}

.panel--form:has(> .error-code) .btn {
  min-height: 3.375rem;
}

/* ======================================================= mouvement réduit */

/*
  Le garde-fou de hardbass.css abrège chaque mouvement, ce qui ne suffit pas
  à tout : un mouvement abrégé finit sur son état de départ ou d'arrivée, et
  pour ces deux-là, aucun n'est lisible.

  Le spectre décoratif de la une, en pause, se figeait sur la première image
  de son animation — toutes ses barres à 15 % —, ou sur la dernière selon le
  retard de chacune. Sans animation du tout, chaque barre garde la hauteur
  que lui donne la feuille : un relief de spectre, immobile.

  Les anneaux des touches de lecture, abrégés, restaient posés autour de la
  touche comme un second contour. Ils disparaissent : la touche dit déjà, par
  son libellé et son icône, que la lecture est en cours. L'onde du carré de
  l'antenne aussi, pour la même raison.
*/
@media (prefers-reduced-motion: reduce) {
  .une__spectre i {
    animation: none;
  }

  .dock__play::after,
  .une__ecoute::after,
  .une__voyant::after {
    display: none;
  }
}

/* =================================================== contraste élevé */

/*
  En contraste élevé — Windows, ses thèmes à fort contraste —, le navigateur
  remplace les couleurs par celles du système, et retire fonds en dégradé et
  ombres portées. Tout ce qui ne se distinguait que par un fond plein
  disparaissait : l'onglet en cours, le filtre choisi, le rôle attribué, la
  cloche posée, le choix d'allure ; les barres de progression et l'icône de
  pause, dessinées par un fond, s'effaçaient tout à fait.

  Les états reprennent ici les couleurs système de la sélection, que le
  navigateur respecte. Les barres et la touche de lecture gardent leurs
  propres couleurs — rien dans le thème du système ne dirait mieux qu'elles
  où en est le morceau.
*/
@media (forced-colors: active) {
  .nav a[aria-current="page"],
  .onglets__lien--actif,
  .onglets-bas__lien[aria-current="page"],
  .onglets-bas__lien.active,
  .feuille__lien[aria-current="page"],
  .acces__choix[aria-current="page"],
  .langues-courtes__choix[aria-current],
  .filtres__choix--actif,
  .pastille-role--porte,
  .cloche--posee,
  .affichage__choix[aria-current="true"],
  .affichage__carte[aria-current="true"],
  .vote__candidat--choisi .vote__rang {
    background: Highlight;
    color: HighlightText;
    border-color: Highlight;
  }

  .btn-icon[aria-pressed="true"],
  .dock .dock__veille--armee {
    color: Highlight;
    border-color: Highlight;
  }

  .vote__candidat--choisi {
    border-color: Highlight;
  }

  .une__barre,
  .dock__progress-bar,
  .dock__play,
  .une__ecoute {
    forced-color-adjust: none;
  }

  /*
    Les jauges reprennent leur dessin natif, que le système sait colorer : le
    leur passe par des pseudo-éléments en dégradé, retirés en contraste élevé.
  */
  .kolbasit__jauge,
  .vote__jauge,
  .insigne__progression {
    appearance: auto;
  }
}

/* ============================================================ impression */

/*
  Une page imprimée garde le texte : ce qui se joue, l'historique, le
  journal. Le lecteur, les onglets, la navigation, les réglages et le décor
  n'ont aucun sens sur papier, et les fonds pleins n'y sortent pas — un
  texte clair posé sur un fond plein s'imprimait blanc sur blanc. Les
  jetons passent donc à l'encre noire sur fond transparent.
*/
@media print {
  :root,
  :root[data-theme] {
    color-scheme: light;

    --pk-bg: transparent;
    --pk-panel: transparent;
    --pk-champ: transparent;
    --pk-survol: transparent;
    --pk-plein: transparent;
    --pk-papier: transparent;
    --pk-encre: #000000;
    --pk-doux: #000000;
    --pk-discret: #333333;
    --pk-trait: #000000;
    --pk-fin: #999999;
    --pk-sur-plein: #000000;
    --pk-sur-accent: #000000;
    --pk-accent-encre: #000000;
  }

  *,
  *::before,
  *::after {
    box-shadow: none !important;
    text-shadow: none !important;
  }

  body {
    padding-block-end: 0;
  }

  .site-header {
    position: static;
  }

  .dock,
  .onglets-bas,
  .feuille,
  .immeuble,
  .une__spectre,
  .une__actions,
  .site-header .nav,
  .bascule,
  .langues-courtes,
  .skip-link,
  .site-footer .affichage,
  .site-footer .langues {
    display: none;
  }

  /* Les couleurs de pseudo sont faites pour la plaque noire, qui ne s'imprime pas. */
  body [data-membre] {
    padding: 0;
    background: none;
    color: #000000;
  }
}

/* ============================================================ mouvements */

@keyframes pk-tampon {
  from {
    opacity: 0.35;
    translate: 5px 5px;
  }
}

@keyframes pk-montee {
  from {
    opacity: 0.35;
    translate: 0 10px;
  }
}

@keyframes pk-rebond {
  0% {
    scale: 0.7;
  }

  60% {
    scale: 1.2;
  }

  100% {
    scale: 1;
  }
}

/*
  L'anneau grandit par « scale » et non par « inset » : il bat tant que la
  musique joue, et un « inset » animé refaisait la mise en page à chaque
  image, pendant des heures. Une mise à l'échelle reste au compositeur. Deux
  formes : la touche du lecteur est carrée, celle de la une large et basse —
  la même échelle partout l'écarterait de 90 pixels sur ses côtés.
*/
@keyframes pk-anneau {
  from {
    opacity: 0.7;
    scale: 1;
  }

  to {
    opacity: 0;
    scale: 1.35;
  }
}

@keyframes pk-anneau-large {
  from {
    opacity: 0.7;
    scale: 1;
  }

  to {
    opacity: 0;
    scale: 1.07 1.33;
  }
}

@keyframes une-egaliseur {
  from {
    transform: scaleY(0.15);
  }

  to {
    transform: scaleY(1);
  }
}

@keyframes une-emission {
  from {
    opacity: 1;
    transform: scale(1);
  }

  to {
    opacity: 0;
    transform: scale(calc(23 / 9));
  }
}

@keyframes bk-neon {
  0%,
  100% {
    opacity: 1;
  }

  42% {
    opacity: 0.25;
  }

  44% {
    opacity: 1;
  }

  47% {
    opacity: 0.3;
  }

  49% {
    opacity: 1;
  }
}

@keyframes bk-tele {
  0% {
    opacity: 1;
  }

  50% {
    opacity: 0.25;
  }
}
