/* ══════════════════════════════════════════════════════════════════════════
   wr-shell.css — LA COQUILLE : header · sidebar · contenu · rail

   ⚠️  CE FICHIER EST LA SEULE AUTORITÉ SUR LA GRILLE.

   Il est chargé EN DERNIER. Aucune autre feuille ne doit déclarer
   `grid-template-columns` sur `.wr-shell`, ni `position` / `width` /
   `display` sur `.wr-side` ou `.wr-rail`. Les blocs correspondants de
   `wr-app.css` ont été retirés et renvoient ici.

   ══════════════════════════════════════════════════════════════════════════
   ⚠️  LE BUG QUE CE FICHIER CORRIGE — À LIRE AVANT DE TOUCHER QUOI QUE CE SOIT
   ══════════════════════════════════════════════════════════════════════════

   Symptôme : sur /city/{slug}, tout le contenu de la page était comprimé
   dans une colonne de 68 px collée à gauche, le reste de l'écran vide.
   Le bug apparaissait après avoir replié la sidebar, puis navigué.

   Cause : la grille reposait sur le PLACEMENT AUTOMATIQUE.

     .wr-shell { grid-template-columns: 264px minmax(0,1fr) 300px; }

   `<main>` n'était pas placé : il tombait dans la colonne 2 uniquement
   PARCE QUE la sidebar occupait la colonne 1 avant lui. Sur les landings,
   `.wr-shell--full` masquait la sidebar (`display:none`) — un élément
   masqué n'est plus un item de grille, donc `<main>` remontait en
   colonne 1. Et la largeur de cette colonne 1 était décidée par une
   bataille de sélecteurs :

     .wr-shell--full            (0,1,0)  → 1fr        …déclarée ligne 2847
     .wr-shell--no-rail         (0,1,0)  → 264px      …déclarée ligne 2864 → GAGNE
     .wr-shell.is-side-collapsed (0,2,0) → 68px       …spécificité + forte → GAGNE

   D'où les deux symptômes rapportés, exactement :
     · visiteur          → contenu dans 264 px  (« tout petit »)
     · connecté + replié → contenu dans 68 px   (la capture d'écran)

   ══════════════════════════════════════════════════════════════════════════
   LES DEUX RÈGLES QUI RENDENT ÇA IMPOSSIBLE À REPRODUIRE
   ══════════════════════════════════════════════════════════════════════════

   1. PLACEMENT EXPLICITE. `<main>` est en colonne 2, toujours, par
      `grid-area`. Masquer, replier ou supprimer une colonne latérale ne
      peut plus le déplacer. C'est la correction de fond.

   2. LES COLONNES LATÉRALES SE DIMENSIONNENT SUR LEUR CONTENU (`auto`),
      et c'est l'ÉLÉMENT qui porte sa largeur (`.wr-side { width }`).
      Plus aucune déclaration `grid-template-columns` concurrente : replier
      la sidebar, c'est changer UNE largeur, pas redéclarer trois colonnes.
      Une colonne masquée vaut 0 — et comme la gouttière est portée par
      l'élément (`margin`), elle disparaît avec lui : pas de gouttière
      fantôme à droite du contenu.
   ══════════════════════════════════════════════════════════════════════════ */

.wr-shell {
  /* Les seules mesures de la coquille. Tout le reste en dérive.

     ⚠️  `--wr-side-w` EST LE SEUL ENDROIT OÙ LA LARGEUR SE RÈGLE.

     C'est tout l'intérêt du refactor : les pistes latérales sont en `auto`
     et se dimensionnent sur leur contenu, donc changer cette variable
     déplace la colonne, la gouttière et le contenu d'un seul coup. Aucune
     autre feuille ne déclare `grid-template-columns` sur `.wr-shell`. */
  --wr-side-w: 314px;
  --wr-rail-w: 300px;
  --wr-shell-gap: 24px;
  --wr-shell-top: 92px;   /* header (68px) + 24px de respiration */

  display: grid;
  grid-template-columns: auto minmax(0, 1fr) auto;
  align-items: start;     /* indispensable : sans lui, pas de sticky */

  width: 100%;
  max-width: none;
  padding: 24px 32px 56px;
}

/* ── LE PLACEMENT EXPLICITE ────────────────────────────────────────────
   `> ` (enfant direct) : la coquille ne place que SES colonnes. Une
   `.wr-side` imbriquée dans une page (il n'y en a pas aujourd'hui) ne
   serait pas capturée. */
.wr-shell > .wr-side        { grid-area: 1 / 1 / 2 / 2; }
.wr-shell > .wr-shell__main { grid-area: 1 / 2 / 2 / 3; }
.wr-shell > .wr-rail        { grid-area: 1 / 3 / 2 / 4; }

/* `min-width: 0` : sans lui, un tableau ou une longue URL dans le contenu
   élargit la colonne 1fr au-delà de la grille et pousse le rail dehors. */
.wr-shell__main {
  min-width: 0;
  width: auto;
  max-width: none;
}

/* ══════════════════════════════════════════════════════════════════════
   LES DEUX COLONNES LATÉRALES

   La gouttière est un `margin` sur l'élément, pas un `gap` sur la grille :
   masquée, la colonne emporte sa gouttière avec elle.
   ══════════════════════════════════════════════════════════════════════ */

.wr-side {
  position: sticky;
  top: var(--wr-shell-top);
  display: flex;
  flex-direction: column;
  gap: 14px;

  width: var(--wr-side-w);
  margin-right: var(--wr-shell-gap);

  /* ══════════════════════════════════════════════════════════════════════
     LA SIDEBAR DEFILE QUAND ELLE DEPASSE L'ECRAN

     ⚠️  `position: sticky` NE SUFFIT PAS, ET C'ETAIT LE BUG.

     Sticky colle la colonne pendant que la page défile — mais seulement
     tant qu'elle TIENT dans la fenêtre. Plus haute que l'écran, elle se
     comporte comme un bloc normal : le bas reste inaccessible. Sur un
     portable en 800 px de haut, le compte recruteur affiche cinq cartes
     empilées ; « Mon profil » et « Déconnexion » étaient hors d'atteinte.

     `max-height` + `overflow-y` créent une zone de défilement PROPRE à la
     colonne, indépendante de celle de la page.

     ⚠️  LES DEUX VONT ENSEMBLE.

     `overflow-y: auto` sans hauteur bornée ne fait rien : sans limite, il
     n'y a jamais de débordement à faire défiler. C'est l'erreur classique.

     `100vh - top` : la hauteur visible moins ce que le header occupe. Les
     16 px de plus évitent que le dernier lien touche le bas de l'écran —
     un élément collé au bord se lit mal et se clique mal.
     ══════════════════════════════════════════════════════════════════════ */
  max-height: calc(100vh - var(--wr-shell-top) - 16px);
  overflow-y: auto;

  /* Le défilement s'arrête à la colonne : arrivé en bas de la sidebar, la
     molette ne doit pas embrayer sur la page derrière. C'est le « scroll
     chaining », et il donne l'impression que le site saute tout seul. */
  overscroll-behavior: contain;

  /* Une gouttière permanente plutôt qu'une barre qui apparaît au survol :
     sans elle, l'apparition de la barre réduit la largeur utile et décale
     tout le contenu de la colonne de quelques pixels. `stable` réserve la
     place une fois pour toutes. Ignoré par les navigateurs qui ne le
     connaissent pas — sans conséquence. */
  scrollbar-gutter: stable;

  /* On anime la LARGEUR de l'élément, pas le `grid-template-columns` de la
     grille : les pistes `auto` ne s'interpolent pas, une largeur si. La
     colonne centrale suit le mouvement, l'œil n'a pas de saut de 200 px. */
  transition: width .22s cubic-bezier(.4, 0, .2, 1);
}

/* ── La barre de défilement, discrète ──
   Une barre système à pleine opacité dans un menu attire l'œil plus que les
   liens. On la garde visible — elle signale qu'il y a du contenu plus bas —
   mais fine et pâle, et elle s'affirme au survol. */
.wr-side::-webkit-scrollbar { width: 8px; }
.wr-side::-webkit-scrollbar-track { background: transparent; }
.wr-side::-webkit-scrollbar-thumb {
  background: rgba(30, 27, 46, .14);
  border-radius: 100px;
}
.wr-side:hover::-webkit-scrollbar-thumb { background: rgba(30, 27, 46, .26); }

/* Firefox : pas de pseudo-éléments, deux propriétés dédiées. */
.wr-side {
  scrollbar-width: thin;
  scrollbar-color: rgba(30, 27, 46, .18) transparent;
}

/* ⚠️  LE MEME TRAITEMENT POUR LE RAIL.

   Il souffre exactement du même défaut : une conversation longue le rend
   plus haut que l'écran, et son bas devient inaccessible. */
.wr-rail {
  max-height: calc(100vh - var(--wr-shell-top) - 16px);
  overflow-y: auto;
  overscroll-behavior: contain;
  scrollbar-gutter: stable;
  scrollbar-width: thin;
  scrollbar-color: rgba(30, 27, 46, .18) transparent;
}

.wr-rail::-webkit-scrollbar { width: 8px; }
.wr-rail::-webkit-scrollbar-track { background: transparent; }
.wr-rail::-webkit-scrollbar-thumb {
  background: rgba(30, 27, 46, .14);
  border-radius: 100px;
}
.wr-rail:hover::-webkit-scrollbar-thumb { background: rgba(30, 27, 46, .26); }

.wr-rail {
  position: sticky;
  top: var(--wr-shell-top);
  display: flex;
  flex-direction: column;
  gap: 14px;

  width: var(--wr-rail-w);
  margin-left: var(--wr-shell-gap);
}

@media (prefers-reduced-motion: reduce) {
  .wr-side { transition: none; }
}

/* ══════════════════════════════════════════════════════════════════════
   SIDEBAR REPLIÉE — une bande d'icônes

   Une seule déclaration : la largeur. Comparer avec l'ancien code, qui
   redéclarait les trois colonnes et devait ensuite se battre contre
   `--no-rail` et `--rail-collapsed` à coups de sélecteurs doublés.
   ══════════════════════════════════════════════════════════════════════ */

.wr-shell.is-side-collapsed { --wr-side-w: 68px; }

/* ══════════════════════════════════════════════════════════════════════
   RAIL ABSENT OU RÉDUIT

   `--no-rail` : visiteur anonyme (posé côté serveur — pas de conversation).
   `--rail-collapsed` : réduction manuelle (posée par wr-rail-toggle.js).

   Il n'y a plus de largeur de colonne à corriger : `display:none` suffit,
   la piste `auto` retombe à 0 et le `margin-left` part avec le rail.
   ══════════════════════════════════════════════════════════════════════ */

.wr-shell--no-rail > .wr-rail,
.wr-shell--rail-collapsed > .wr-rail { display: none; }

/* ══════════════════════════════════════════════════════════════════════
   PLEINE LARGEUR — `fullWidth: true` côté route

   ⚠️  PLUS UTILISÉ PAR AUCUNE ROUTE (les landings ville ont la sidebar,
   comme toutes les autres pages). On garde la classe, DÉFINIE CORRECTEMENT :
   si quelqu'un repose le drapeau demain, `<main>` traverse les trois
   colonnes au lieu de se retrouver coincé dans la première.

   C'est ce `grid-area` qui manquait. Il tient en une ligne.
   ══════════════════════════════════════════════════════════════════════ */

.wr-shell--full > .wr-side,
.wr-shell--full > .wr-rail { display: none; }
.wr-shell--full > .wr-shell__main { grid-area: 1 / 1 / 2 / -1; }
.wr-shell--full { padding-inline: 0; }

/* ══════════════════════════════════════════════════════════════════════
   RESPONSIVE

   ≤1280px : le rail sort. La bulle de messagerie fait le même travail et
             elle est déjà là.
   ≤991px  : la sidebar devient un panneau glissant (drawer).
   ══════════════════════════════════════════════════════════════════════ */

@media (max-width: 1280px) {
  .wr-shell > .wr-rail { display: none; }
}

@media (max-width: 991px) {
  .wr-shell {
    grid-template-columns: minmax(0, 1fr);
    padding: 20px 16px 44px;
  }

  /* Une seule colonne : le contenu la prend en entier. Sans cette ligne,
     `grid-area: 1/2/2/3` créerait une piste implicite et laisserait la
     première vide — le bug d'origine, en miroir. */
  .wr-shell > .wr-shell__main,
  .wr-shell--full > .wr-shell__main { grid-area: 1 / 1 / 2 / -1; }

  /* ── LA SIDEBAR EN DRAWER ──
     `position: fixed` la sort du flux : elle n'est plus un item de grille,
     la piste retombe à 0 d'elle-même.

     ⚠️  ELLE N'EST PAS `display: none`.
     C'était le bug : `wr-app.css` posait `display:none` sous 991px, plus
     bas dans le fichier que les règles du drawer. Le bouton flottant
     ouvrait donc un panneau qui ne pouvait pas s'afficher. C'est
     `transform` qui la sort de l'écran, pas `display`. */
  .wr-side {
    position: fixed;
    top: 0;
    left: 0;
    bottom: 0;
    z-index: 1000;

    display: flex;
    gap: 12px;
    width: min(86vw, 340px);
    margin: 0;
    padding: 16px 14px calc(16px + env(safe-area-inset-bottom, 0px));

    background: var(--wr-bg, #FBFCFE);
    box-shadow: 0 18px 60px rgba(30, 27, 46, .28);

    /* ⚠️  `max-height` DU DESKTOP ANNULE ICI.

       En mode colonne, la sidebar est bornée à `100vh - header`. En drawer,
       elle est `fixed` de `top: 0` à `bottom: 0` : elle occupe déjà toute la
       hauteur. Garder la borne desktop lui retirerait la hauteur du header
       — un drawer qui s'arrête 92 px avant le bas de l'écran, avec du vide
       en dessous. */
    max-height: none;

    overflow-y: auto;
    -webkit-overflow-scrolling: touch;
    overscroll-behavior: contain;

    transform: translateX(-100%);

    /* Fermée, elle sort du parcours de tabulation : un menu invisible dans
       lequel le focus se perd est pire qu'un menu absent. `visibility`
       bascule à la FIN de la fermeture, sinon le panneau disparaîtrait
       avant d'avoir glissé. */
    visibility: hidden;
    transition: transform .28s cubic-bezier(.4, 0, .2, 1),
                visibility 0s linear .28s;
  }

  .wr-side.is-open {
    transform: translateX(0);
    visibility: visible;
    transition: transform .28s cubic-bezier(.4, 0, .2, 1),
                visibility 0s linear 0s;
  }

  /* En drawer, la largeur ne se règle plus par variable : on annule le
     repli, hérité du localStorage d'une session desktop. Une bande de
     68 px en plein écran serait inutilisable. */
  .wr-shell.is-side-collapsed { --wr-side-w: min(86vw, 340px); }
}

/* ══════════════════════════════════════════════════════════════════════
   L'EN-TÊTE DU DRAWER — titre + fermeture

   Masqué sur desktop : la sidebar y est une colonne, elle n'a rien à
   fermer.
   ══════════════════════════════════════════════════════════════════════ */

.wr-side__drawerhead { display: none; }

@media (max-width: 991px) {
  .wr-side__drawerhead {
    display: flex;
    align-items: center;
    justify-content: space-between;
    padding: 4px 6px 10px;
    margin-bottom: 2px;
    border-bottom: 1px solid var(--wr-line, #EEF1F7);
  }

  .wr-side__drawertitle {
    font-size: 11px;
    font-weight: 700;
    text-transform: uppercase;
    letter-spacing: .1em;
    color: var(--wr-muted-2, #9AA0AD);
  }

  .wr-side__drawerclose {
    width: 34px;
    height: 34px;
    border: none;
    background: var(--wr-bg-2, #F1F3F7);
    border-radius: 10px;
    color: var(--wr-ink, #1E1B2E);
    cursor: pointer;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }

  .wr-side__drawerclose svg { width: 18px; height: 18px; }
}

/* ══════════════════════════════════════════════════════════════════════
   LE VOILE + LE BOUTON FLOTTANT (mobile)

   Tous deux hors grille : `display:none` sur desktop, `position:fixed`
   sur mobile. Ni l'un ni l'autre ne peut donc décaler les colonnes.
   ══════════════════════════════════════════════════════════════════════ */

.wr-side-toggle,
.wr-side-backdrop { display: none; }

@media (max-width: 991px) {
  .wr-side-backdrop {
    display: block;
    position: fixed;
    inset: 0;
    z-index: 999;
    background: rgba(30, 27, 46, .42);
    opacity: 0;
    visibility: hidden;
    transition: opacity .28s ease, visibility .28s ease;
  }

  .wr-side-backdrop.is-open { opacity: 1; visibility: visible; }

  /* On respecte l'attribut `hidden` : le JS le retire à l'ouverture. Si le
     script ne tourne pas, le voile ne recouvre rien. */
  .wr-side-backdrop[hidden] { display: none; }

  .wr-side-toggle {
    display: inline-flex;
    align-items: center;
    justify-content: center;
    position: fixed;
    left: 14px;
    bottom: calc(18px + env(safe-area-inset-bottom, 0px));
    z-index: 900;

    width: 52px;
    height: 52px;
    border: none;
    border-radius: 50%;
    background: var(--wr-violet, #8A63C1);
    color: #fff;
    box-shadow: 0 8px 26px rgba(138, 99, 193, .42);
    cursor: pointer;
  }

  .wr-side-toggle svg { width: 24px; height: 24px; }
  .wr-side-toggle:active { transform: scale(.94); }

  /* Drawer ouvert : le bouton ferait doublon avec la croix. */
  body.wr-side-open .wr-side-toggle { display: none; }

  /* Le bouton « replier » n'a pas de sens sur un drawer. */
  .wr-side__toggle { display: none; }
}

/* ══════════════════════════════════════════════════════════════════════
   LE BOUTON « REPLIER » ET L'ATTRIBUT `hidden`

   Il est rendu avec `hidden` et découvert par wr-side-collapse.js : replié
   sans JavaScript, la sidebar serait un menu que rien ne peut rouvrir.

   ⚠️  `[hidden]` NE SUFFIT PAS TOUT SEUL.

   C'est une règle du NAVIGATEUR (`display: none`), et la moindre règle
   d'auteur qui pose un `display` l'emporte sur elle. `wr-app.css` déclare
   `.wr-side__toggle { display: flex }` — sans la règle ci-dessous, le
   bouton resterait visible alors que le JS l'a masqué.
   ══════════════════════════════════════════════════════════════════════ */

.wr-side__toggle[hidden] { display: none; }

/* ══════════════════════════════════════════════════════════════════════════
   LA CARTE TOOLBOX — réservée aux abonnés premium

   Une bordure violette et un liseré : la carte doit se distinguer des
   autres sans crier. C'est un espace acquis, pas une publicité.

   ⚠️  ELLE MASQUE, ELLE NE PROTÈGE PAS. Le rendu conditionnel de la barre
   latérale est du confort d'affichage ; chaque page listée doit revérifier
   le premium côté serveur.
   ══════════════════════════════════════════════════════════════════════════ */

.wr-side__card--premium {
  border: 1px solid rgba(138, 99, 193, .28);
  background: linear-gradient(180deg, rgba(138, 99, 193, .07), transparent 62%);
}

.wr-side__label--premium {
  display: flex;
  align-items: center;
  gap: 6px;
  color: var(--wr-violet, #8A63C1);
}

.wr-side__label--premium svg {
  width: 13px;
  height: 13px;
  flex: none;
}

/* Le bouton du portail de facturation doit être indiscernable d'un lien :
   même graisse, même alignement, même zone cliquable. Un <button> hérite
   des styles du navigateur, pas de ceux du lien voisin. */
.wr-side__form { margin: 0; }

.wr-side__link--btn {
  width: 100%;
  border: none;
  background: none;
  font: inherit;
  text-align: left;
  cursor: pointer;
}

/* Sidebar repliée : le formulaire ne doit pas casser l'alignement de la
   colonne d'icônes. */
.wr-side.is-collapsed .wr-side__form { display: contents; }

/* ══════════════════════════════════════════════════════════════════════════
   SIDEBAR — LES LIGNES QUI PORTENT UNE PASTILLE NE SAUTENT PLUS DE LIGNE

   « Ajouter une mission » s'affichait sur TROIS lignes. La ligne contient :
   icône (18) + gouttière (11) + libellé + pastille GRATUIT (~65) +
   gouttière (6) + icône externe (14). Dans une colonne de 264 px moins les
   marges, il restait environ 106 px au libellé, qui en réclame 120.

   Trois corrections, de la plus structurelle à la plus cosmétique.
   ══════════════════════════════════════════════════════════════════════════ */

/* ── 1. LE LIBELLÉ NE PEUT PLUS REVENIR À LA LIGNE ──
   C'est la correction de fond : quelle que soit la traduction, quelle que
   soit la largeur, cette ligne restera une ligne. Au pire elle tronque —
   « Ajouter une mis… » se lit ; un pavé de trois lignes dans un menu, non.

   `min-width: 0` est obligatoire : sans lui, un item de flex refuse de
   descendre sous la largeur de son contenu et `text-overflow` n'a jamais
   l'occasion de s'appliquer. C'est le piège classique de flexbox. */
.wr-side__linktxt {
  flex: 1 1 auto;
  min-width: 0;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}

/* ── 2. ON REND DE LA PLACE AU LIBELLÉ ──
   La pastille était dimensionnée pour être lue de loin. Dans une colonne
   étroite, elle mange le texte qu'elle est censée qualifier. On la resserre :
   elle reste parfaitement lisible et rend une douzaine de pixels. */
.wr-side__tag {
  font-size: 9.5px;
  letter-spacing: .02em;
  padding: 2px 6px;
}

.wr-side__tag + .wr-side__ext { margin-left: 5px; }

/* La gouttière de 11 px se justifie entre une icône et du texte. Sur une
   ligne qui porte trois éléments de plus, elle coûte trop cher. */
.wr-side__link:has(.wr-side__tag) { gap: 9px; }

/* ── 3. LA SIDEBAR REPLIÉE ──
   À 68 px, seules les icônes restent. Un libellé tronqué à deux caractères
   serait du bruit. */
.wr-side.is-collapsed .wr-side__linktxt { display: none; }

/* ══════════════════════════════════════════════════════════════════════════
   SIDEBAR REPLIEE — PAS DE DEFILEMENT INTERNE. C'EST UN ARBITRAGE.

   ⚠️  `overflow-y: auto` FORCE `overflow-x` A `auto` AUSSI.

   C'est une règle du CSS, pas un bug de navigateur : dès qu'un axe n'est
   plus `visible`, l'autre ne peut pas le rester. Il devient `auto`.

   Or les infobulles de la colonne repliée sont en
   `position: absolute; left: calc(100% + 10px)` — elles s'affichent À DROITE
   DE LA COLONNE, donc hors de ses limites. Avec un débordement borné, elles
   seraient ROGNÉES : à 68 px de large, on ne verrait plus que les deux ou
   trois premiers pixels du libellé.

   Une colonne d'icônes muettes, dont on ne peut plus lire le nom au survol,
   n'est plus utilisable. C'est un plus mauvais compromis que de ne pas
   pouvoir faire défiler.

   Et le risque est faible : repliée, la colonne ne montre que des icônes
   empilées — une hauteur sans commune mesure avec les cinq cartes du mode
   déplié. C'est précisément ce que le repli sert à obtenir.

   ── SI ÇA DEVAIT QUAND MÊME DÉBORDER ──
   Il faudrait sortir les infobulles du flux de la colonne (les rendre en
   `position: fixed` depuis le JS, positionnées au survol). C'est faisable,
   mais ça remplace trois lignes de CSS par un gestionnaire d'événements —
   à ne faire que si le cas se présente réellement.
   ══════════════════════════════════════════════════════════════════════════ */

.wr-side.is-collapsed {
  max-height: none;
  overflow: visible;
  scrollbar-gutter: auto;
}
