:root {
    --parchment: #efe3c8;
    --parchment-dark: #e2d3ac;
    --wood-dark: #5a3418;
    --wood: #6b3e22;
    --wood-light: #a66a33;
    --crimson: #8b2a2a;
    --gold: #c9a227;
    --ink: #3b2a1a;
    --forest: #3f6b2f;
    --panel-radius: 22px;
  }

  * { box-sizing: border-box; }

  body {
    margin: 0;
    min-height: 100vh;
    font-family: "Nunito", sans-serif;
    color: var(--ink);
    background:
      radial-gradient(ellipse at top, #f7edd4 0%, var(--parchment) 45%, var(--parchment-dark) 100%);
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 2.5rem 1.25rem 4rem;
  }
  /* « Cot-cot ! » (Poule de combat, renderCotCot) : gros bouton flottant
     au-dessus de la main, qui pulse le temps de la fenêtre de réaction. */
  .cot-cot-button {
    position: fixed;
    left: 50%;
    bottom: 42%;
    transform: translateX(-50%);
    z-index: 900;
    padding: 0.9rem 1.8rem;
    border-radius: 999px;
    border: 4px solid #fff6e2;
    background: linear-gradient(180deg, #f7c843, #e08a1e);
    color: var(--wood-dark);
    font-family: "Fraunces", serif;
    font-weight: 800;
    font-size: 1.6rem;
    white-space: nowrap;
    box-shadow: 0 5px 0 #8a5a12, 0 12px 30px rgba(0, 0, 0, 0.35);
    animation: cot-cot-pulse 0.6s ease-in-out infinite alternate;
  }
  .cot-cot-button[hidden] { display: none; }
  /* Jauge qui se vide pendant la seconde accordée (--cot-cot-left : le temps
     restant à l'apparition du bouton). */
  .cot-cot-button { overflow: hidden; }
  .cot-cot-button.is-counting::after {
    content: "";
    position: absolute;
    left: 0;
    bottom: 0;
    height: 5px;
    width: 100%;
    background: var(--crimson);
    transform-origin: left center;
    animation: cot-cot-gauge var(--cot-cot-left, 1000ms) linear forwards;
  }
  @keyframes cot-cot-gauge {
    from { transform: scaleX(1); }
    to { transform: scaleX(0); }
  }
  .cot-cot-button:active { transform: translateX(-50%) translateY(3px); box-shadow: 0 2px 0 #8a5a12; }
  @keyframes cot-cot-pulse {
    from { transform: translateX(-50%) scale(1); }
    to { transform: translateX(-50%) scale(1.08); }
  }
  @media (prefers-reduced-motion: reduce) {
    .cot-cot-button { animation: none; }
  }

  /* Message d'erreur (showError dans app.js) : bannière en haut de l'écran,
     au-dessus de tout (fenêtres comprises), qui glisse en place. */
  .error-toast {
    position: fixed;
    top: calc(0.8rem + env(safe-area-inset-top, 0px));
    left: 50%;
    transform: translateX(-50%);
    z-index: 2500;
    display: flex;
    align-items: center;
    gap: 0.55rem;
    width: max-content;
    max-width: min(92vw, 560px);
    padding: 0.6rem 0.6rem 0.6rem 0.9rem;
    border: 3px solid var(--crimson);
    border-radius: 14px;
    background: #fff6ea;
    color: var(--ink);
    font-weight: 700;
    box-shadow: 0 10px 26px rgba(0, 0, 0, 0.3);
  }
  .error-toast[hidden] { display: none; }
  .error-toast.is-shown { animation: toast-in 0.25s ease-out; }
  @keyframes toast-in {
    from { opacity: 0; transform: translate(-50%, -12px); }
    to { opacity: 1; transform: translate(-50%, 0); }
  }
  .error-toast-text { flex: 1; }
  .error-toast-close {
    flex: none;
    width: 1.8rem;
    height: 1.8rem;
    padding: 0;
    line-height: 1;
    border-radius: 50%;
    background: var(--crimson);
    box-shadow: none;
  }
  @media (prefers-reduced-motion: reduce) {
    .error-toast.is-shown { animation: none; }
  }

  /* Pied de page de l'accueil (copyright) : poussé en bas de la fenêtre
     quand le contenu est court (body est une colonne flex de 100vh),
     masqué dès qu'une salle est rejointe. */
  .site-footer {
    margin-top: auto;
    padding-top: 2.5rem;
    text-align: center;
    font-size: 0.8rem;
    color: var(--wood); /* --wood-light serait trop pâle pour un petit texte */
  }
  .site-footer p { margin: 0; }
  body.has-room .site-footer { display: none; }


  h1, h2, h3 { font-family: "Fraunces", serif; margin: 0; }

  .brand {
    text-align: center;
    margin-bottom: 1.5rem;
  }
  .brand h1 {
    /* Styles du texte de secours, visibles seulement si l'image ne charge pas */
    font-size: clamp(2.4rem, 6vw, 3.4rem);
    font-weight: 700;
    color: var(--crimson);
    line-height: 1;
  }
  /* Logo cliquable : retour à l'accueil (voir homeLink dans app.js). */
  .brand-home {
    display: block;
    border-radius: 12px;
    transition: transform 0.15s ease, filter 0.15s ease;
  }
  .brand-home:hover { filter: brightness(1.06); transform: scale(1.02); }
  .brand-home:focus-visible { outline: 3px solid var(--gold); outline-offset: 4px; }
  @media (prefers-reduced-motion: reduce) {
    .brand-home { transition: none; }
    .brand-home:hover { transform: none; }
  }
  .brand h1 img {
    display: block;
    margin: 0 auto;
    width: min(360px, 66vw);
    max-height: 140px;
    height: auto;
    object-fit: contain;
  }
  .brand .tagline {
    font-style: italic;
    font-family: "Fraunces", serif;
    color: var(--wood);
    margin-top: 0.35rem;
    font-size: 1.05rem;
  }
  /* Code de la salle dans l'en-tête : seulement en jeu (voir body.in-game). */
  .brand-room { display: none; }

  .panel {
    width: 100%;
    max-width: 480px;
    background: var(--parchment);
    border: 6px solid var(--wood);
    border-radius: var(--panel-radius);
    box-shadow:
      inset 0 0 0 2px var(--wood-light),
      0 10px 24px rgba(59, 42, 26, 0.25);
    padding: 1.75rem 1.75rem 2rem;
    margin-bottom: 1.5rem;
    animation: rise 0.35s ease-out;
  }
  @keyframes rise {
    from { opacity: 0; transform: translateY(10px); }
    to { opacity: 1; transform: translateY(0); }
  }

  .panel h2 {
    font-size: 1.4rem;
    color: var(--wood-dark);
    margin-bottom: 1rem;
  }

  label {
    display: block;
    font-weight: 700;
    font-size: 0.85rem;
    color: var(--wood-dark);
    margin: 0.9rem 0 0.3rem;
  }

  input {
    width: 100%;
    font-family: "Nunito", sans-serif;
    font-size: 1rem;
    padding: 0.6rem 0.8rem;
    border: 2px solid var(--wood-light);
    border-radius: 10px;
    background: #fffaf0;
    color: var(--ink);
  }
  input:focus { outline: 3px solid var(--gold); outline-offset: 1px; }

  button {
    font-family: "Nunito", sans-serif;
    font-weight: 800;
    font-size: 0.95rem;
    cursor: pointer;
    border: none;
    border-radius: 12px;
    padding: 0.7rem 1.2rem;
    background: linear-gradient(180deg, var(--wood-light), var(--wood));
    color: #fff6e2;
    box-shadow: 0 3px 0 var(--wood-dark);
    transition: transform 0.08s ease;
  }
  button:hover:not(:disabled) { filter: brightness(1.08); }
  button:active:not(:disabled) { transform: translateY(2px); box-shadow: 0 1px 0 var(--wood-dark); }
  button:disabled { opacity: 0.45; cursor: not-allowed; box-shadow: none; }

  .btn-primary {
    width: 100%;
    margin-top: 1.1rem;
    background: linear-gradient(180deg, #d94b4b, var(--crimson));
    box-shadow: 0 3px 0 #5c1c1c;
  }

  .room-code {
    display: inline-block;
    font-family: "Fraunces", serif;
    font-weight: 700;
    font-size: 1.6rem;
    letter-spacing: 0.15em;
    background: var(--wood-dark);
    color: #ffe9b0;
    padding: 0.25rem 0.9rem;
    border-radius: 10px;
  }
  .room-header { display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 0.6rem; margin-bottom: 1.2rem; }
  .room-header .hint { font-size: 0.85rem; color: var(--wood); }

  .hero-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 0.7rem;
  }
  .hero-tile {
    border: 3px solid var(--wood-light);
    border-radius: 14px;
    background: #fff9ea;
    padding: 0.4rem;
    text-align: center;
    cursor: pointer;
    transition: transform 0.1s ease, box-shadow 0.1s ease;
  }
  .hero-tile:hover:not(.taken) { transform: translateY(-3px); box-shadow: 0 6px 12px rgba(59,42,26,0.2); }
  .hero-tile.mine { border-color: var(--gold); box-shadow: 0 0 0 3px rgba(201,162,39,0.4); }
  .hero-tile.taken { opacity: 0.4; cursor: not-allowed; filter: grayscale(0.6); }
  .hero-tile .portrait {
    width: 100%;
    aspect-ratio: 5/7;
    border-radius: 10px;
    overflow: hidden;
    background: linear-gradient(160deg, var(--wood-light), var(--wood));
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 0.35rem;
  }
  .hero-tile .portrait img { width: 100%; height: 100%; object-fit: cover; display: block; }
  .hero-tile .portrait .fallback {
    display: none;
    font-family: "Fraunces", serif;
    font-size: 1.8rem;
    font-weight: 700;
    color: #fff6e2;
  }
  .hero-tile .name { font-weight: 800; font-size: 0.85rem; }
  .hero-tile .name .check { display: none; color: var(--forest); }
  .hero-tile.mine .name .check { display: inline; }

  .player-list { list-style: none; margin: 0.8rem 0 0; padding: 0; }
  .player-list li {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 0.45rem 0.2rem;
    border-bottom: 1px dashed var(--wood-light);
    font-weight: 700;
  }
  .player-list li:last-child { border-bottom: none; }
  .player-list .status { font-weight: 400; font-style: italic; color: var(--wood); }
  .player-list li.me { color: var(--crimson); }
  /* Nom, pastilles (🤖 IA, 👑 hôte) et croix de retrait d'une IA, à gauche ;
     le héros à droite. */
  .player-list .player-who { display: inline-flex; align-items: center; flex-wrap: wrap; gap: 0.35rem; min-width: 0; }
  .player-list .bot-badge[hidden], .player-list .bot-remove[hidden] { display: none; }
  .player-list .bot-remove {
    width: 1.5rem;
    height: 1.5rem;
    padding: 0;
    line-height: 1;
    font-size: 0.75rem;
    border-radius: 50%;
    background: var(--wood-light);
    box-shadow: none;
  }
  .player-list .bot-remove:hover { background: var(--crimson); }
  .add-bot { display: block; margin: 0.7rem 0 0.2rem; }
  .add-bot[hidden] { display: none; }
  /* Tuile d'un joueur IA en jeu : 🤖 après le nom. */
  .player-status-bar > li.is-bot .player-name::after { content: " 🤖"; }

  .waiting-note { font-size: 0.85rem; color: var(--wood); margin-top: 0.6rem; }

  /* ---- Hiérarchie des boutons (point 7) ----
     Par défaut, un bouton est en bois (style `button` plus haut) : c'est
     l'action standard, comme « Passer mon tour » ou « Jouer ». */
  #ingame { width: 100%; }

  /* Action secondaire : parchemin clair, même famille que « Règles du jeu ». */
  .btn-secondary {
    background: linear-gradient(180deg, #fff9ea, #fdeccb);
    color: var(--wood-dark);
    box-shadow: 0 3px 0 var(--wood-light);
  }
  /* Action irréversible. */
  .btn-danger {
    background: linear-gradient(180deg, #d94b4b, var(--crimson));
    color: #fff6e2;
    box-shadow: 0 3px 0 #5c1c1c;
  }
  /* L'action qui gagne la partie : dorée, comme les fragments. */
  .btn-victory {
    background: linear-gradient(180deg, #f6d86a, var(--gold));
    color: var(--wood-dark);
    box-shadow: 0 3px 0 #8a6a12;
  }
  /* Réaction Réflex : jaune vif, pour se démarquer de « Jouer ». */
  .btn-reflex {
    background: linear-gradient(180deg, #ffe46b, #f2c200);
    color: var(--wood-dark);
    box-shadow: 0 3px 0 #9a7a00;
  }
  /* Défausse : secondaire, texte rouge pour rappeler qu'on perd la carte. */
  .btn-discard {
    background: linear-gradient(180deg, #fff9ea, #fdeccb);
    color: var(--crimson);
    box-shadow: 0 3px 0 var(--wood-light);
  }
  /* Cartes de la main (point 6). --chest-color donne la bordure et la
     gemme ; --fan-rotate / --fan-lift (posés par app.js) dessinent
     l'éventail. Au survol, la carte se redresse et se soulève. */
  .hand-card {
    --chest-color: var(--wood-light);
    position: relative;
    /* Largeur et écart calculés par layoutHand() (app.js). */
    flex: none;
    width: var(--hand-card-w, 170px);
    display: flex;
    flex-direction: column;
    align-items: stretch;
    gap: 0.35rem;
    padding: 0.45rem 0.45rem 0.6rem;
    margin: 0;
    background: #fff9ea;
    border: 3px solid var(--chest-color);
    border-radius: 14px;
    box-shadow: 0 6px 14px rgba(59, 42, 26, 0.22);
    text-align: center;
    transform: translateY(var(--fan-lift, 0px)) rotate(var(--fan-rotate, 0deg));
    transform-origin: 50% 120%;
    transition: transform 0.15s ease, box-shadow 0.15s ease;
  }
  .hand-card:hover,
  .hand-card:focus-within {
    transform: translateY(-12px) rotate(0deg);
    box-shadow: 0 14px 26px rgba(59, 42, 26, 0.32);
    z-index: 2;
  }
  /* Carte Réflex perdue mais encore jouable (visibleLostReflexCards dans
     app.js) : bordure dorée en pointillés, halo qui pulse et pastille
     « Encore jouable », le temps de la fenêtre de réaction. */
  #hand .hand-card.is-lost {
    border-style: dashed;
    border-color: var(--gold);
    background: #fff6d8;
    animation: lost-reflex-pulse 0.8s ease-in-out infinite alternate;
  }
  @keyframes lost-reflex-pulse {
    from { box-shadow: 0 0 0 2px rgba(201, 162, 39, 0.4), 0 6px 14px rgba(59, 42, 26, 0.22); }
    to { box-shadow: 0 0 0 5px rgba(201, 162, 39, 0.75), 0 0 22px 6px rgba(246, 216, 106, 0.7); }
  }
  #hand .hand-card.is-lost .card-portrait { opacity: 0.75; }
  #hand .hand-card.is-lost::after {
    content: "⚡ Encore jouable";
    position: absolute;
    top: -0.85rem;
    left: 50%;
    transform: translateX(-50%);
    white-space: nowrap;
    padding: 0.1rem 0.6rem;
    border-radius: 999px;
    background: linear-gradient(180deg, #fbe58a, var(--gold));
    color: var(--wood-dark);
    font-weight: 800;
    font-size: 0.72rem;
    box-shadow: 0 2px 0 #8a6a12;
    pointer-events: none;
    z-index: 1;
  }
  @media (prefers-reduced-motion: reduce) {
    #hand .hand-card.is-lost { animation: none; box-shadow: 0 0 0 4px rgba(201, 162, 39, 0.7); }
  }

  /* Eclaireur (renderReorderPicker) : les cartes en entier dans le panneau
     du centre, sur le fond de bois des cartes révélées ; pastille de rang
     une fois placée. */
  .target-picker .reorder-cards { margin: 0.6rem 0 0.8rem; padding: 1.1rem 0.8rem 0.9rem; }
  .target-picker .reorder-card { width: 120px; }
  .reorder-card .reorder-pick { margin: 0.25rem 0 0; padding: 0.35rem 0.5rem; font-size: 0.8rem; width: 100%; }
  .reorder-card.is-placed { opacity: 0.85; }
  .reorder-rank {
    position: absolute;
    top: -0.6rem;
    left: -0.6rem;
    z-index: 1;
    width: 1.7rem;
    height: 1.7rem;
    border-radius: 50%;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--crimson);
    color: #fff6e2;
    font-family: "Fraunces", serif;
    font-weight: 800;
    font-size: 0.95rem;
    box-shadow: 0 2px 0 #5a1a1a;
  }
  .reorder-rank[hidden] { display: none; }

  /* Choix d'une carte de ma main (makeHandCardSelectable dans app.js) : la
     carte entière est le bouton. Choisissable : contour rouge et pastille
     avec le verbe (data-verb : « Défausser », « Donner »…) ; sinon ternie.
     Même langage visuel que le choix d'un joueur sur sa tuile. */
  #hand.is-choosing .hand-card-actions { display: none; }
  #hand .hand-card.is-choice {
    cursor: pointer;
    outline: 3px solid rgba(139, 42, 42, 0.35);
    outline-offset: 2px;
  }
  #hand .hand-card.is-choice .card-portrait { cursor: pointer; }
  #hand .hand-card.is-choice:hover,
  #hand .hand-card.is-choice:focus-visible { outline-color: var(--crimson); }
  #hand .hand-card.is-choice:focus-visible { outline: 3px solid var(--gold); }
  #hand .hand-card.is-choice::after {
    content: attr(data-verb);
    position: absolute;
    bottom: -0.8rem;
    left: 50%;
    transform: translateX(-50%);
    white-space: nowrap;
    padding: 0.12rem 0.7rem;
    border-radius: 999px;
    background: var(--crimson);
    color: #fff6e2;
    font-weight: 800;
    font-size: 0.78rem;
    box-shadow: 0 2px 0 #5a1a1a;
    pointer-events: none;
  }
  #hand .hand-card.is-not-choice {
    opacity: 0.45;
    filter: grayscale(0.7);
    cursor: not-allowed;
  }
  #hand .hand-card.is-not-choice .card-portrait { cursor: not-allowed; }
  /* Laisse la place aux pastilles sous les cartes. */
  #hand.is-choosing { padding-bottom: 1rem; }
  /* Défausse imposée (makeImposedDiscardSelectable) : même visuel, en deux
     temps. La carte sélectionnée se soulève, cerclée d'or, avec son bouton
     « ✓ Défausser » (les boutons restent visibles : Réflex, confirmation). */
  #hand.is-imposed { padding-bottom: 1rem; }
  #hand .hand-card.is-chosen {
    outline: 3px solid var(--gold);
    outline-offset: 2px;
    transform: translateY(-14px);
  }
  #hand .hand-card.is-chosen::after { background: var(--gold); color: var(--wood-dark); box-shadow: 0 2px 0 #8a6a12; }
  #hand.is-imposed .hand-card.is-choice::after { bottom: auto; top: -0.85rem; }

  /* .reveal-card (cartes révélées, #revealModal) partage l'habillage des
     cartes de la main : couleur du coffre, gemme, portrait, liseré doré. */
  .hand-card.chest-red, .reveal-card.chest-red, .flying-card.chest-red, .pile-button[data-chest="red"] { --chest-color: #b8332f; }
  .hand-card.chest-blue, .reveal-card.chest-blue, .flying-card.chest-blue, .pile-button[data-chest="blue"] { --chest-color: #2f62b8; }
  .hand-card.chest-green, .reveal-card.chest-green, .flying-card.chest-green, .pile-button[data-chest="green"] { --chest-color: #3f8a3a; }

  /* Gemme du coffre, à cheval sur le bord supérieur. */
  .hand-card .chest-gem,
  .reveal-card .chest-gem {
    position: absolute;
    top: -0.6rem;
    left: 50%;
    width: 1rem;
    height: 1rem;
    transform: translateX(-50%) rotate(45deg);
    border-radius: 3px;
    border: 2px solid #fff6e2;
    background:
      radial-gradient(circle at 30% 30%, rgba(255, 255, 255, 0.7) 0, transparent 45%),
      var(--chest-color);
    box-shadow: 0 1px 3px rgba(0, 0, 0, 0.35);
    z-index: 1;
  }

  /* Fragment du trésor : liseré et reflet dorés, en plus de sa couleur de coffre. */
  .hand-card.is-fragment,
  .reveal-card.is-fragment {
    border-color: var(--gold);
    background: linear-gradient(180deg, #fff6d8, #fdeab0);
    box-shadow:
      0 0 0 2px rgba(201, 162, 39, 0.5),
      0 0 16px 3px rgba(201, 162, 39, 0.45),
      0 6px 14px rgba(59, 42, 26, 0.22);
  }
  .hand-card .card-portrait,
  .reveal-card .card-portrait {
    width: 100%;
    aspect-ratio: 5/7;
    border-radius: 8px;
    overflow: hidden;
    background: linear-gradient(160deg, var(--wood-light), var(--wood));
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .hand-card .card-portrait:focus-visible,
  .reveal-card .card-portrait:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; }
  .hand-card .card-portrait img,
  .reveal-card .card-portrait img { width: 100%; height: 100%; object-fit: cover; display: block; }
  .hand-card .card-fallback,
  .reveal-card .card-fallback {
    display: none;
    flex-direction: column;
    justify-content: center;
    height: 100%;
    padding: 0.5rem;
    color: #fff6e2;
    font-family: "Fraunces", serif;
  }
  .hand-card .card-fallback strong,
  .reveal-card .card-fallback strong { font-size: 0.95rem; margin-bottom: 0.3rem; }
  .hand-card .card-fallback p,
  .reveal-card .card-fallback p { font-size: 0.75rem; font-style: italic; margin: 0; }
  /* Masqué visuellement, lu par les lecteurs d'écran (fragments seulement). */
  .hand-card .fragment-note,
  .reveal-card .fragment-note {
    display: none;
    position: absolute;
    width: 1px;
    height: 1px;
    overflow: hidden;
    clip-path: inset(50%);
    white-space: nowrap;
  }
  .hand-card.is-fragment .fragment-note,
  .reveal-card.is-fragment .fragment-note { display: block; }

  /* Barre d'état des joueurs, en jeu : portrait, statut normal/blessé, main.
     Le joueur dont c'est le tour a son nom en gras et son portrait agrandi ;
     un joueur blessé a son portrait tourné à l'horizontale (comme la carte
     Héros physique inclinée dans les vraies règles). */
  .player-status-bar {
    list-style: none;
    display: flex;
    flex-wrap: wrap;
    gap: 0.7rem;
    margin: 0;
    padding: 0;
  }
  .player-status-bar > li {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.5rem;
    background: #fff9ea;
    border: 2px solid var(--wood-light);
    border-radius: 16px;
    padding: 0.7rem 0.8rem 0.6rem;
  }
  .player-status-bar > li { position: relative; }
  .player-status-bar > li.me { border-color: var(--crimson); }
  /* Point 3 : le joueur dont c'est le tour a un halo doré qui pulse
     lentement, et une étiquette « Son tour » / « Ton tour » au-dessus.
     Durée du cycle : doit rester égale à GLOW_PERIOD_MS dans app.js.
     --glow-delay (posé par app.js à chaque rendu) cale la pulsation sur
     l'horloge : comme render() recrée ces éléments chaque seconde pendant
     un minuteur, sans ce décalage l'animation repartirait de zéro à chaque
     fois et le halo « sauterait ». */
  .player-status-bar > li.turn {
    border-color: var(--gold);
    background: #fff3d6;
    animation: turn-glow 3.2s ease-in-out infinite;
    animation-delay: var(--glow-delay, 0s);
  }
  @keyframes turn-glow {
    0%, 100% { box-shadow: 0 0 0 2px var(--gold), 0 0 10px 2px rgba(201, 162, 39, 0.45); }
    50% { box-shadow: 0 0 0 3px var(--gold), 0 0 24px 8px rgba(201, 162, 39, 0.6); }
  }
  /* Tuile cliquable pour agrandir le héros (openHeroZoom dans app.js). */
  .player-status-bar > li.is-zoomable { cursor: zoom-in; }
  .player-status-bar > li.is-zoomable:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; }

  /* ---- Animations d'attaque (playAttackAnimation dans app.js) ----
     Durées : doivent rester égales à HIT_DURATION_MS et ARROW_* dans
     app.js. --hit-delay (négatif) est posé par app.js quand la tuile est
     recréée en pleine animation, pour qu'elle continue sans sauter. */
  .player-status-bar > li.hit-attack {
    animation: hit-shake 0.5s ease-in-out, hit-flash 0.75s ease-out;
    animation-delay: var(--hit-delay, 0ms);
  }
  .player-status-bar > li.hit-ko {
    animation: hit-shake-hard 0.7s ease-in-out, hit-flash-ko 1.3s ease-out;
    animation-delay: var(--hit-delay, 0ms);
    z-index: 3; /* le flash déborde sur les tuiles voisines */
  }
  @keyframes hit-shake {
    0%, 100% { transform: translateX(0); }
    15% { transform: translateX(-7px) rotate(-1.5deg); }
    30% { transform: translateX(6px) rotate(1.5deg); }
    45% { transform: translateX(-5px) rotate(-1deg); }
    60% { transform: translateX(4px); }
    80% { transform: translateX(-2px); }
  }
  @keyframes hit-shake-hard {
    0%, 100% { transform: translate(0, 0) scale(1); }
    10% { transform: translate(-11px, -2px) rotate(-4deg) scale(1.06); }
    22% { transform: translate(10px, 2px) rotate(4deg) scale(1.06); }
    34% { transform: translate(-9px, 1px) rotate(-3deg) scale(1.04); }
    46% { transform: translate(8px, -1px) rotate(3deg) scale(1.03); }
    60% { transform: translate(-5px, 0) rotate(-1.5deg); }
    75% { transform: translate(3px, 0); }
  }
  @keyframes hit-flash {
    0% { background-color: #f3b7ab; border-color: var(--crimson); box-shadow: 0 0 0 3px rgba(139, 42, 42, 0.55); }
    100% { box-shadow: 0 0 0 0 rgba(139, 42, 42, 0); }
  }
  @keyframes hit-flash-ko {
    0% { background-color: #fff; border-color: #fff; box-shadow: 0 0 0 0 rgba(255, 255, 255, 0.9), 0 0 40px 18px rgba(255, 220, 160, 0.9); }
    12% { background-color: #e9806c; border-color: var(--crimson); box-shadow: 0 0 0 6px var(--crimson), 0 0 36px 14px rgba(139, 42, 42, 0.65); }
    70% { background-color: #f3c3b8; box-shadow: 0 0 0 3px var(--crimson), 0 0 18px 6px rgba(139, 42, 42, 0.3); }
    100% { box-shadow: 0 0 0 0 rgba(139, 42, 42, 0); }
  }
  /* Étiquette « K.O. » qui jaillit au-dessus du portrait. */
  .player-status-bar > li.hit-ko::after {
    content: "💥 K.O.";
    position: absolute;
    top: 30%;
    left: 50%;
    padding: 0.2rem 0.6rem;
    border-radius: 999px;
    background: var(--crimson);
    color: #fff6e2;
    font-family: "Fraunces", serif;
    font-weight: 800;
    font-size: 1rem;
    white-space: nowrap;
    box-shadow: 0 3px 0 #5a1a1a, 0 6px 14px rgba(0, 0, 0, 0.35);
    pointer-events: none;
    opacity: 0;
    animation: ko-pop 1.3s ease-out;
    animation-delay: var(--hit-delay, 0ms);
  }
  @keyframes ko-pop {
    0% { opacity: 0; transform: translate(-50%, 0) scale(0.3) rotate(-12deg); }
    15% { opacity: 1; transform: translate(-50%, -6px) scale(1.25) rotate(-6deg); }
    30% { transform: translate(-50%, -8px) scale(1) rotate(-6deg); }
    80% { opacity: 1; transform: translate(-50%, -12px) scale(1) rotate(-6deg); }
    100% { opacity: 0; transform: translate(-50%, -20px) scale(0.95) rotate(-6deg); }
  }

  /* ---- Réflex (playReflexAnimation) : flash doré et « ⚡ Réflex ! » sur
     celui qui le joue ; éclair vers le joueur contré, tamponné « Contré ! »
     (data-stamp). Durées : = REFLEX_* et COUNTERED_MS dans app.js. ---- */
  .player-status-bar > li.reflex-flash,
  .player-status-bar > li.cotcot-flash {
    animation: reflex-flash 0.9s ease-out;
    animation-delay: var(--reflex-delay, 0ms);
    z-index: 3;
  }
  @keyframes reflex-flash {
    0% { background-color: #fffdf2; border-color: #fff; box-shadow: 0 0 0 0 rgba(246, 216, 106, 0.9), 0 0 0 0 rgba(246, 216, 106, 0.9); }
    18% { background-color: #fff3c4; border-color: var(--gold); box-shadow: 0 0 0 5px var(--gold), 0 0 34px 14px rgba(246, 216, 106, 0.85); }
    100% { box-shadow: 0 0 0 10px rgba(246, 216, 106, 0), 0 0 0 0 rgba(246, 216, 106, 0); }
  }
  .player-status-bar > li.reflex-flash::after,
  .player-status-bar > li.cotcot-flash::after {
    content: "⚡ Réflex !";
    position: absolute;
    top: 30%;
    left: 50%;
    padding: 0.2rem 0.6rem;
    border-radius: 999px;
    background: linear-gradient(180deg, #fbe58a, var(--gold));
    color: var(--wood-dark);
    font-family: "Fraunces", serif;
    font-weight: 800;
    font-size: 0.95rem;
    white-space: nowrap;
    box-shadow: 0 3px 0 #8a6a12, 0 6px 14px rgba(0, 0, 0, 0.3);
    pointer-events: none;
    opacity: 0;
    animation: ko-pop 0.9s ease-out;
    animation-delay: var(--reflex-delay, 0ms);
  }  /* Le « Cot-cot ! » de Poule de combat : même animation, autre étiquette. */
  .player-status-bar > li.cotcot-flash::after { content: "🐔 Cot-cot !"; }

  .player-status-bar > li.countered {
    animation: countered-bump 0.9s ease-out;
    animation-delay: var(--countered-delay, 0ms);
    z-index: 3;
  }
  @keyframes countered-bump {
    0% { transform: translateY(0); box-shadow: 0 0 0 0 rgba(246, 216, 106, 0); }
    15% { transform: translateY(-5px) scale(1.04); box-shadow: 0 0 0 4px var(--gold), 0 0 18px 6px rgba(246, 216, 106, 0.7); }
    35% { transform: translateY(2px) scale(0.98); }
    55% { transform: translateY(0) scale(1); }
    100% { box-shadow: 0 0 0 0 rgba(246, 216, 106, 0); }
  }
  /* Tampon « Contré ! » / « Bloqué ! », incliné comme un coup de tampon. */
  .player-status-bar > li.countered::after {
    content: attr(data-stamp);
    position: absolute;
    top: 30%;
    left: 50%;
    padding: 0.15rem 0.55rem;
    border: 3px solid var(--gold);
    border-radius: 8px;
    background: #fffdf2;
    color: var(--wood-dark);
    font-family: "Fraunces", serif;
    font-weight: 800;
    font-size: 0.95rem;
    white-space: nowrap;
    box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
    pointer-events: none;
    opacity: 0;
    animation: stamp-in 0.9s ease-out;
    animation-delay: var(--countered-delay, 0ms);
  }
  @keyframes stamp-in {
    0% { opacity: 0; transform: translate(-50%, 0) scale(1.8) rotate(-14deg); }
    18% { opacity: 1; transform: translate(-50%, 0) scale(0.95) rotate(-10deg); }
    28% { transform: translate(-50%, 0) scale(1) rotate(-10deg); }
    80% { opacity: 1; transform: translate(-50%, 0) scale(1) rotate(-10deg); }
    100% { opacity: 0; transform: translate(-50%, -6px) scale(1) rotate(-10deg); }
  }
  .reflex-bolt {
    position: fixed;
    inset: 0;
    width: 100vw;
    height: 100vh;
    z-index: 655;
    pointer-events: none;
    overflow: visible;
    animation: reflex-bolt-life 0.85s linear forwards;
  }
  .reflex-bolt path {
    fill: none;
    stroke-linecap: round;
    stroke-linejoin: round;
    stroke-dasharray: var(--bolt-length, 1000);
    stroke-dashoffset: var(--bolt-length, 1000);
    animation: reflex-bolt-draw 0.25s ease-out forwards;
  }
  .reflex-bolt-path { stroke: #fff6c8; stroke-width: 3; }
  .reflex-bolt-glow { stroke: var(--gold); stroke-width: 9; opacity: 0.75; filter: blur(2px); }
  @keyframes reflex-bolt-draw {
    to { stroke-dashoffset: 0; }
  }
  /* Scintille deux fois avant de s'éteindre, comme un éclair. */
  @keyframes reflex-bolt-life {
    0%, 40% { opacity: 1; }
    48% { opacity: 0.35; }
    56% { opacity: 1; }
    64% { opacity: 0.5; }
    72% { opacity: 1; }
    100% { opacity: 0; }
  }

  /* ---- Pioche (playDrawAnimation) : coffre qui s'illumine, carte qui
     vole jusqu'au joueur, tuile entourée de la couleur du coffre ----
     Durées : = PILE_GLOW_MS, DRAW_FLIGHT_MS (le vol est animé en JS) et
     LAND_MS dans app.js. */
  #pileButtons .pile-button.pile-drawn .pile-portrait {
    animation: pile-drawn 0.8s ease-out;
    animation-delay: var(--pile-delay, 0ms);
  }
  /* Le coffre d'un autre joueur est désactivé (terne) : on le ravive le
     temps de l'effet, pour qu'on voie bien lequel a servi. */
  #pileButtons .pile-button.pile-drawn:disabled { opacity: 1; filter: none; }
  @keyframes pile-drawn {
    0% { transform: translateY(0) scale(1); box-shadow: 0 0 0 0 transparent; }
    20% { transform: translateY(-6px) scale(1.06); box-shadow: 0 0 0 4px var(--chest-color), 0 0 26px 10px var(--chest-color); }
    100% { transform: translateY(0) scale(1); box-shadow: 0 0 0 0 transparent; }
  }
  .flying-card {
    /* Sans classe chest-… (carte qui change de main, face cachée) : dos
       neutre, en bois clair. */
    --chest-color: var(--wood-light);
    position: fixed;
    left: 0;
    top: 0;
    width: 46px;
    height: 64px;
    z-index: 660;
    pointer-events: none;
    border: 3px solid var(--chest-color, var(--wood-light));
    border-radius: 8px;
    background:
      repeating-linear-gradient(45deg, rgba(255, 246, 226, 0.12) 0 4px, transparent 4px 9px),
      linear-gradient(160deg, var(--wood-light), var(--wood));
    box-shadow: 0 8px 18px rgba(0, 0, 0, 0.35);
    will-change: transform;
  }
  .flying-card .chest-gem {
    position: absolute;
    top: 50%;
    left: 50%;
    width: 14px;
    height: 14px;
    transform: translate(-50%, -50%) rotate(45deg);
    background: var(--chest-color);
    border: 2px solid #fff6e2;
    border-radius: 3px;
  }
  .player-status-bar > li.land-red { --land-color: #b8332f; }
  .player-status-bar > li.land-blue { --land-color: #2f62b8; }
  .player-status-bar > li.land-green { --land-color: #3f8a3a; }
  .player-status-bar > li.land-red,
  .player-status-bar > li.land-blue,
  .player-status-bar > li.land-green {
    animation: land-ring 0.7s ease-out;
    animation-delay: var(--land-delay, 0ms);
  }
  @keyframes land-ring {
    0% { box-shadow: 0 0 0 0 var(--land-color); }
    25% { box-shadow: 0 0 0 5px var(--land-color), 0 0 20px 6px var(--land-color); }
    100% { box-shadow: 0 0 0 12px transparent; }
  }

  /* ---- Compteur de cartes en main : pulse et « +1 » / « −2 » qui
     s'envole (data-delta, posé par app.js). = COUNT_PULSE_MS. ---- */
  .badge-cards { position: relative; }
  .badge-cards.count-up,
  .badge-cards.count-down {
    animation: count-pulse 1s ease-out;
    animation-delay: var(--count-delay, 0ms);
  }
  .badge-cards.count-up { --count-color: #2e7d32; --count-bg: #d7f0d3; }
  .badge-cards.count-down { --count-color: var(--crimson); --count-bg: #f6d3cc; }
  @keyframes count-pulse {
    0% { transform: scale(1); }
    18% { transform: scale(1.4); background: var(--count-bg); border-color: var(--count-color); color: var(--count-color); }
    45% { transform: scale(1); background: var(--count-bg); border-color: var(--count-color); color: var(--count-color); }
    100% { transform: scale(1); }
  }
  .badge-cards.count-up::after,
  .badge-cards.count-down::after {
    content: attr(data-delta);
    position: absolute;
    left: 50%;
    bottom: 100%;
    padding: 0 0.35rem;
    border-radius: 999px;
    background: var(--count-color);
    color: #fff;
    font-weight: 800;
    font-size: 0.78rem;
    line-height: 1.4;
    white-space: nowrap;
    pointer-events: none;
    opacity: 0;
    animation: count-delta 1s ease-out;
    animation-delay: var(--count-delay, 0ms);
  }
  @keyframes count-delta {
    0% { opacity: 0; transform: translate(-50%, 6px) scale(0.6); }
    15% { opacity: 1; transform: translate(-50%, -2px) scale(1.1); }
    75% { opacity: 1; transform: translate(-50%, -14px) scale(1); }
    100% { opacity: 0; transform: translate(-50%, -22px) scale(1); }
  }

  /* Flèche de l'attaquant vers sa cible : un calque plein écran (tracé en
     coordonnées de la fenêtre), au-dessus du plateau et du panneau latéral
     (500) mais sous le popup d'action et les fenêtres (1000 et plus). */
  .attack-arrow {
    position: fixed;
    inset: 0;
    width: 100vw;
    height: 100vh;
    z-index: 650;
    pointer-events: none;
    overflow: visible;
    color: var(--crimson);
    animation: attack-arrow-life 1.15s ease-out forwards;
  }
  .attack-arrow.is-ko { color: #6e1414; }
  .attack-arrow-path {
    fill: none;
    stroke: currentColor;
    stroke-width: 5;
    stroke-linecap: round;
    filter: drop-shadow(0 2px 3px rgba(59, 42, 26, 0.45));
    stroke-dasharray: var(--arrow-length, 1000);
    stroke-dashoffset: var(--arrow-length, 1000);
    animation: attack-arrow-draw 0.38s cubic-bezier(0.3, 0.7, 0.4, 1) forwards;
  }
  .attack-arrow.is-ko .attack-arrow-path { stroke-width: 7; }
  .attack-arrow-head {
    fill: currentColor;
    filter: drop-shadow(0 2px 3px rgba(59, 42, 26, 0.45));
    opacity: 0;
    animation: attack-arrow-head-in 0.12s ease-out 0.34s forwards;
  }
  @keyframes attack-arrow-head-in {
    to { opacity: 1; }
  }
  @keyframes attack-arrow-draw {
    to { stroke-dashoffset: 0; }
  }
  @keyframes attack-arrow-life {
    0%, 60% { opacity: 1; }
    100% { opacity: 0; }
  }

  /* Mouvement réduit (réglage du système) : ni tremblement ni tracé, juste
     le flash de la tuile et la flèche qui apparaît puis s'efface. */
  @media (prefers-reduced-motion: reduce) {
    .player-status-bar > li.hit-attack { animation: hit-flash 0.75s ease-out; animation-delay: var(--hit-delay, 0ms); }
    .player-status-bar > li.hit-ko { animation: hit-flash-ko 1.3s ease-out; animation-delay: var(--hit-delay, 0ms); }
    .player-status-bar > li.hit-ko::after { animation: ko-fade 1.3s ease-out; animation-delay: var(--hit-delay, 0ms); }
    .attack-arrow-path { animation: none; stroke-dashoffset: 0; }
    .attack-arrow-head { animation: none; opacity: 1; }
    .player-status-bar > li.countered { animation: none; }
    .player-status-bar > li.reflex-flash::after,
    .player-status-bar > li.cotcot-flash::after,
    .player-status-bar > li.countered::after { animation: ko-fade 0.9s ease-out; }
    .reflex-bolt { animation: attack-arrow-life 0.85s ease-out forwards; }
    .reflex-bolt path { animation: none; stroke-dashoffset: 0; }
    #pileButtons .pile-button.pile-drawn .pile-portrait { animation: pile-drawn-still 0.8s ease-out; animation-delay: var(--pile-delay, 0ms); }
    .badge-cards.count-up,
    .badge-cards.count-down { animation: count-flash 1s ease-out; animation-delay: var(--count-delay, 0ms); }
    .badge-cards.count-up::after,
    .badge-cards.count-down::after { animation: count-delta-still 1s ease-out; animation-delay: var(--count-delay, 0ms); }
  }
  @keyframes pile-drawn-still {
    0%, 60% { box-shadow: 0 0 0 4px var(--chest-color), 0 0 20px 6px var(--chest-color); }
    100% { box-shadow: 0 0 0 0 transparent; }
  }
  @keyframes count-flash {
    0%, 60% { background: var(--count-bg); border-color: var(--count-color); color: var(--count-color); }
  }
  @keyframes count-delta-still {
    0%, 80% { opacity: 1; transform: translate(-50%, -6px); }
    100% { opacity: 0; transform: translate(-50%, -6px); }
  }
  @keyframes ko-fade {
    0%, 80% { opacity: 1; transform: translate(-50%, -8px); }
    100% { opacity: 0; transform: translate(-50%, -8px); }
  }

  .player-status-bar .turn-flag {
    display: none;
    position: absolute;
    top: -0.8rem;
    left: 50%;
    transform: translateX(-50%);
    white-space: nowrap;
    padding: 0.15rem 0.7rem;
    border-radius: 999px;
    background: linear-gradient(180deg, #f6d86a, var(--gold));
    color: var(--wood-dark);
    font-weight: 800;
    font-size: 0.75rem;
    box-shadow: 0 2px 0 #8a6a12;
    z-index: 1;
  }
  .player-status-bar > li.turn .turn-flag { display: block; }

  /* Anneau du minuteur autour du portrait : `--progress` (1 -> 0) est posé
     par app.js à chaque seconde. Sans minuteur, l'anneau est invisible. */
  .player-status-bar .portrait-ring {
    padding: 5px;
    border-radius: 19px;
  }
  .player-status-bar > li.timed .portrait-ring {
    --ring-color: var(--gold);
    background: conic-gradient(
      var(--ring-color) calc(var(--progress, 1) * 360deg),
      rgba(107, 62, 34, 0.18) 0
    );
  }
  .player-status-bar > li.timed.low-time .portrait-ring { --ring-color: var(--crimson); }
  /* Portrait 3x plus grand que le format d'origine (40px -> 120px, 56px ->
     168px pour le tour en cours), noms et statut affichés dessous. */
  .player-status-bar .player-portrait {
    position: relative;
    width: 120px;
    height: 120px;
    min-width: 120px;
    border-radius: 14px;
    overflow: hidden;
    background: linear-gradient(160deg, var(--wood-light), var(--wood));
    display: flex;
    align-items: center;
    justify-content: center;
    transition: width 0.15s ease, height 0.15s ease, transform 0.15s ease;
  }
  .player-status-bar > li.turn .player-portrait { width: 168px; height: 168px; min-width: 168px; }
  /* Joueur déconnecté : portrait teinté d'un rouge transparent, par-dessus
     l'image ou le repli, quel que soit celui affiché. */
  .player-status-bar > li.disconnected .player-portrait::after {
    content: "";
    position: absolute;
    inset: 0;
    background: rgba(139, 42, 42, 0.45);
  }
  .player-status-bar > li.wounded .player-portrait { transform: rotate(90deg); }
  .player-status-bar .player-portrait img { width: 100%; height: 100%; object-fit: contain; display: block; }
  .player-status-bar .player-portrait .fallback {
    display: none;
    font-family: "Fraunces", serif;
    font-weight: 700;
    font-size: 2.4rem;
    color: #fff6e2;
  }
  .player-status-bar .player-details {
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
    min-width: 0;
  }
  .player-status-bar .player-name { font-weight: 700; font-size: 0.9rem; }
  .player-status-bar > li.turn .player-name { font-weight: 900; color: var(--wood-dark); }

  /* Pastilles d'état (point 4) : une par information, lisibles d'un coup
     d'œil ; le détail est dans l'infobulle (title). */
  .status-badges {
    list-style: none;
    margin: 0.35rem 0 0;
    padding: 0;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.3rem;
    max-width: 180px;
  }
  .badge {
    display: inline-flex;
    align-items: center;
    gap: 0.3rem;
    padding: 0.12rem 0.5rem;
    border: 1.5px solid;
    border-radius: 999px;
    font-size: 0.74rem;
    font-weight: 800;
    line-height: 1.35;
    white-space: nowrap;
    cursor: default;
  }

  /* Santé : pastille colorée + mot, vert / orangé / rouge. */
  .badge-health::before {
    content: "";
    width: 0.5rem;
    height: 0.5rem;
    border-radius: 50%;
    background: currentColor;
  }
  .badge-health.is-normal { color: var(--forest); background: #e6efd9; border-color: #9dbb87; }
  .badge-health.is-wounded { color: #8a4a0c; background: #fbe3c2; border-color: #d9964a; }
  .badge-health.is-ko { color: #fff6e2; background: var(--crimson); border-color: #5c1c1c; }

  /* Cartes en main : petit paquet de deux cartes dessiné en CSS + nombre. */
  .badge-cards { color: var(--wood-dark); background: #fff3d6; border-color: var(--wood-light); }
  .mini-deck {
    position: relative;
    width: 0.75rem;
    height: 0.85rem;
  }
  .mini-deck::before,
  .mini-deck::after {
    content: "";
    position: absolute;
    width: 0.5rem;
    height: 0.7rem;
    border: 1.5px solid currentColor;
    border-radius: 2px;
    background: #fff9ea;
  }
  .mini-deck::before { left: 0; top: 0.1rem; transform: rotate(-10deg); }
  .mini-deck::after { left: 0.22rem; top: 0; transform: rotate(8deg); }

  /* États rares : icône + mot court. */
  .badge-hidden { color: #35506b; background: #e1e8ee; border-color: #8aa1b6; }
  .badge-skip { color: var(--wood); background: #f1e6cf; border-color: var(--wood-light); }
  .badge-offline { color: var(--crimson); background: #fbe6de; border-color: #d98b7a; }

  .target-picker {
    background: #fff3d6;
    border: 3px solid var(--gold);
    border-radius: 12px;
    padding: 0.8rem 1rem;
    margin: 0;
    width: 100%;
    max-width: 640px;
  }
  .target-picker p { margin: 0 0 0.6rem; font-family: "Fraunces", serif; }
  .target-picker button { margin: 3px; padding: 0.5rem 0.9rem; font-size: 0.88rem; }
  .target-picker .target-picker-instruction { font-weight: 700; color: var(--crimson); }
  .target-picker .target-picker-hint { font-family: inherit; font-style: italic; font-size: 0.88rem; color: var(--wood); }

  /* Choix d'un joueur (carte à cible, don, Flip) : les tuiles des
     adversaires deviennent les boutons. Celles qu'on peut choisir sont
     cerclées de rouge avec une pastille « Choisir » ; les autres (cachées,
     interdites par la carte) sont ternies. outline plutôt que box-shadow,
     pour ne pas écraser le halo du joueur dont c'est le tour. */
  .player-status-bar > li.is-target {
    cursor: pointer;
    border-color: var(--crimson);
    outline: 3px solid rgba(139, 42, 42, 0.35);
    outline-offset: 2px;
    transition: transform 0.12s ease, outline-color 0.12s ease, background-color 0.12s ease;
  }
  .player-status-bar > li.is-target:hover,
  .player-status-bar > li.is-target:focus-visible {
    transform: translateY(-4px);
    background-color: #fff;
    outline-color: var(--crimson);
  }
  .player-status-bar > li.is-target:focus-visible { outline: 3px solid var(--gold); }
  .player-status-bar > li.is-target:active { transform: translateY(-1px); }
  .player-status-bar > li.is-target::after {
    content: "Choisir";
    position: absolute;
    bottom: -0.75rem;
    left: 50%;
    transform: translateX(-50%);
    white-space: nowrap;
    padding: 0.12rem 0.7rem;
    border-radius: 999px;
    background: var(--crimson);
    color: #fff6e2;
    font-weight: 800;
    font-size: 0.75rem;
    box-shadow: 0 2px 0 #5a1a1a;
    z-index: 1;
  }
  .player-status-bar > li.is-not-target {
    opacity: 0.45;
    filter: grayscale(0.7);
    cursor: not-allowed;
  }
  /* Laisse la place aux pastilles « Choisir » sous la rangée. */
  .player-status-bar.is-choosing { padding-bottom: 0.8rem; }

  /* Races libres (Flip) : petites cartes de héros cliquables. */
  .free-heroes { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.6rem; margin-bottom: 0.4rem; }
  .target-picker .free-hero {
    margin: 0;
    padding: 0.4rem 0.4rem 0.35rem;
    width: 88px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.3rem;
    background: #fff9ea;
    color: var(--ink);
    border: 2px solid var(--crimson);
    border-radius: 12px;
    box-shadow: 0 3px 0 var(--wood-light);
  }
  .target-picker .free-hero:hover { background: #fff; transform: translateY(-3px); }
  .free-hero-portrait {
    width: 72px;
    height: 72px;
    border-radius: 9px;
    overflow: hidden;
    background: linear-gradient(160deg, var(--wood-light), var(--wood));
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .free-hero-portrait img { width: 100%; height: 100%; object-fit: contain; display: block; }
  .free-hero-portrait .fallback {
    display: none;
    font-family: "Fraunces", serif;
    font-weight: 700;
    font-size: 1.8rem;
    color: #fff6e2;
  }
  .free-hero-name { font-weight: 700; font-size: 0.82rem; }
  @media (prefers-reduced-motion: reduce) {
    .player-status-bar > li.is-target,
    .target-picker .free-hero { transition: none; }
    .player-status-bar > li.is-target:hover,
    .player-status-bar > li.is-target:focus-visible,
    .target-picker .free-hero:hover { transform: none; }
  }

  /* Popup d'action : une notification éphémère par carte jouée avec succès
     (points 2/3/4 du README), diffusée à tout le monde. Empilée en haut de
     l'écran, une carte à la fois (voir queueActionPopup dans app.js). */
  .action-popup {
    position: fixed;
    top: 1rem;
    left: 50%;
    transform: translateX(-50%);
    z-index: 1000;
    display: flex;
    flex-direction: column;
    align-items: center;
    pointer-events: none;
  }
  .action-popup-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.4rem;
    background: var(--parchment);
    border: 3px solid var(--gold);
    border-radius: 14px;
    box-shadow: 0 8px 20px rgba(59, 42, 26, 0.3);
    padding: 0.7rem 1.4rem;
    max-width: 90vw;
    text-align: center;
    opacity: 0;
    transform: translateY(-12px);
    transition: opacity 0.2s ease, transform 0.2s ease;
  }
  .action-popup-card.visible { opacity: 1; transform: translateY(0); }
  .action-popup-portrait {
    width: 64px;
    height: 90px;
    border-radius: 8px;
    overflow: hidden;
    background: linear-gradient(160deg, var(--wood-light), var(--wood));
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .action-popup-image { width: 100%; height: 100%; object-fit: cover; display: block; }
  .action-popup-fallback {
    display: none;
    font-family: "Fraunces", serif;
    font-weight: 700;
    font-size: 1.3rem;
    color: #fff6e2;
  }
  .action-popup-message {
    margin: 0;
    font-family: "Fraunces", serif;
    font-weight: 600;
    color: var(--wood-dark);
    font-size: 1rem;
  }


  /* Zoom sur une carte (point 1 du README) : recouvre tout l'écran, la carte
     s'affiche en grand et centrée. Fermeture au clic en dehors de
     .card-zoom-content ou sur la croix (voir openCardZoom/closeCardZoom
     dans app.js). */
  .card-zoom-overlay {
    position: fixed;
    inset: 0;
    background: rgba(59, 42, 26, 0.72);
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 1rem;
    padding: 2rem 1rem;
  }
  /* Flèches de part et d'autre de la carte zoomée. */
  .card-zoom-nav {
    flex: none;
    width: 3rem;
    height: 3rem;
    padding: 0;
    border-radius: 50%;
    background: linear-gradient(180deg, #fff9ea, #fdeccb);
    color: var(--wood-dark);
    box-shadow: 0 3px 0 var(--wood-light), 0 6px 14px rgba(0, 0, 0, 0.3);
    font-size: 2rem;
    line-height: 1;
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .card-zoom-nav:disabled { opacity: 0.3; cursor: default; }
  .card-zoom-nav:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; }
  .card-zoom-content {
    position: relative;
    background: var(--parchment);
    border: 6px solid var(--wood);
    border-radius: var(--panel-radius);
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.4);
    padding: 1.6rem;
    /* Laisse la place aux deux flèches sur les petits écrans. */
    max-width: min(calc(100vw - 10rem), 420px);
    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
  }
  .card-zoom-close {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    width: 2rem;
    height: 2rem;
    padding: 0;
    line-height: 1;
    border-radius: 50%;
    background: var(--wood);
    box-shadow: none;
  }
  .card-zoom-portrait {
    width: 100%;
    aspect-ratio: 5/7;
    border-radius: 14px;
    overflow: hidden;
    background: linear-gradient(160deg, var(--wood-light), var(--wood));
    display: flex;
    align-items: center;
    justify-content: center;
    margin-bottom: 1rem;
  }
  .card-zoom-portrait img { width: 100%; height: 100%; object-fit: contain; display: block; }
  .card-zoom-fallback {
    font-family: "Fraunces", serif;
    font-weight: 700;
    font-size: 2.2rem;
    color: #fff6e2;
    padding: 1rem;
  }
  .card-zoom-name { font-family: "Fraunces", serif; font-size: 1.3rem; font-weight: 700; margin: 0 0 0.4rem; }
  .card-zoom-text { margin: 0; color: var(--wood-dark); font-style: italic; }
  /* Zoom sur un héros en jeu : nom du joueur, « Son tour », pastilles et
     minuteur, comme sur sa tuile. */
  .card-zoom-player { margin: 0 0 0.6rem; }
  .card-zoom-player[hidden] { display: none; }
  .card-zoom-player-line {
    margin: 0 0 0.4rem;
    display: flex;
    justify-content: center;
    align-items: center;
    flex-wrap: wrap;
    gap: 0.4rem;
    font-weight: 800;
    color: var(--ink);
  }
  .card-zoom-turn {
    padding: 0.05rem 0.55rem;
    border-radius: 999px;
    background: var(--gold);
    color: var(--wood-dark);
    font-size: 0.75rem;
    font-weight: 800;
  }
  .card-zoom-turn[hidden] { display: none; }
  .card-zoom-badges { justify-content: center; margin: 0; }
  .card-zoom-timer { margin: 0.4rem 0 0; font-weight: 700; color: var(--crimson); }
  .card-zoom-timer[hidden] { display: none; }
  .card-zoom-actions { display: flex; justify-content: center; flex-wrap: wrap; gap: 0.5rem; margin-top: 1rem; }
  .card-zoom-actions:empty { display: none; }
  .card-zoom-position { margin: 0.8rem 0 0; font-size: 0.8rem; font-weight: 700; color: var(--wood); }

  /* Indique que la carte est cliquable pour l'afficher en grand. */
  .hand-card .card-portrait,
  .reveal-card .card-portrait { cursor: zoom-in; }

  /* Cartes révélées (Omniscience, Petit curieux…) : fenêtre parchemin comme
     les règles, cartes alignées sur la table. z-index sous #cardZoom (2000)
     pour que le zoom s'ouvre par-dessus et que le fermer ramène ici. */
  .reveal-overlay {
    position: fixed;
    inset: 0;
    background: rgba(59, 42, 26, 0.72);
    z-index: 1900;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem 1rem;
  }
  .reveal-content {
    position: relative;
    background: var(--parchment);
    border: 6px solid var(--wood);
    border-radius: var(--panel-radius);
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.4);
    padding: 1.6rem 1.8rem 1.4rem;
    width: min(92vw, 820px);
    max-height: 88vh;
    overflow-y: auto;
    text-align: center;
  }
  /* Une seule carte (Petit curieux) : fenêtre resserrée autour d'elle. */
  .reveal-overlay.is-single .reveal-content { width: min(92vw, 360px); }
  .reveal-close {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    width: 2rem;
    height: 2rem;
    padding: 0;
    line-height: 1;
    border-radius: 50%;
    background: var(--wood);
    box-shadow: none;
  }
  .reveal-title {
    font-size: 1.45rem;
    color: var(--crimson);
    margin: 0 2rem 0.3rem;
  }
  .reveal-hint {
    margin: 0 0 1.3rem;
    font-size: 0.9rem;
    font-style: italic;
    color: var(--wood);
  }
  /* Les cartes posées sur un bout de table en bois, pour rappeler qu'elles
     sont « montrées » par un autre joueur. */
  .reveal-cards {
    list-style: none;
    margin: 0;
    padding: 1.4rem 1rem 1.1rem;
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 1.3rem 0.9rem;
    border-radius: 16px;
    background:
      repeating-linear-gradient(90deg, rgba(0, 0, 0, 0.04) 0 2px, transparent 2px 38px),
      linear-gradient(180deg, var(--wood-light), var(--wood));
    box-shadow: inset 0 3px 10px rgba(0, 0, 0, 0.35);
  }
  .reveal-card {
    --chest-color: var(--wood-light);
    position: relative;
    flex: none;
    width: 128px;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    padding: 0.4rem 0.4rem 0.45rem;
    background: #fff9ea;
    border: 3px solid var(--chest-color);
    border-radius: 12px;
    box-shadow: 0 6px 14px rgba(0, 0, 0, 0.3);
    transition: transform 0.15s ease, box-shadow 0.15s ease;
  }
  .reveal-card:hover,
  .reveal-card:focus-within {
    transform: translateY(-6px);
    box-shadow: 0 12px 22px rgba(0, 0, 0, 0.38);
  }
  .reveal-overlay.is-single .reveal-card { width: 170px; }
  .reveal-card-name {
    margin: 0;
    font-family: "Fraunces", serif;
    font-weight: 700;
    font-size: 0.85rem;
    line-height: 1.15;
    color: var(--ink);
    overflow-wrap: anywhere;
  }
  /* Image absente : le nom est déjà sous la carte, le repli n'en garde que le texte. */
  .reveal-card .card-fallback strong { display: none; }
  .reveal-empty { margin: 0.5rem 0 0; font-style: italic; color: var(--wood); }
  .reveal-actions { display: flex; justify-content: center; margin-top: 1.2rem; }
  @media (prefers-reduced-motion: reduce) {
    .reveal-card { transition: none; }
    .reveal-card:hover,
    .reveal-card:focus-within { transform: none; }
  }
  /* Téléphone : cartes plus petites (3 par ligne sur 360px), fenêtre quasi
     plein écran. */
  @media (max-width: 600px) {
    .reveal-overlay { padding: 0.75rem 0.5rem; }
    .reveal-content { width: 100%; max-height: 92vh; padding: 1.2rem 0.9rem 1rem; }
    .reveal-title { font-size: 1.2rem; }
    .reveal-hint { font-size: 0.82rem; margin-bottom: 1rem; }
    .reveal-cards { padding: 1rem 0.5rem 0.8rem; gap: 1rem 0.5rem; }
    .reveal-card { width: 92px; padding: 0.3rem; border-radius: 10px; }
    .reveal-card .chest-gem { width: 0.8rem; height: 0.8rem; top: -0.5rem; }
    .reveal-card .card-fallback p { display: none; }
    .reveal-card-name { font-size: 0.75rem; }
    .reveal-overlay.is-single .reveal-card { width: 150px; }
  }


  /* Boutons de pioche (point 7 du README) : l'image du coffre remplace le
     bouton en bois par défaut. Le nombre de cartes restantes est une
     pastille posée dans le coin bas-droit de l'image. Point 5 de la refonte :
     coffres agrandis, centre visuel de la table. */
  #pileButtons { display: flex; justify-content: center; gap: 1.6rem; margin: 0; }
  #pileButtons .pile-button {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.3rem;
    background: none;
    box-shadow: none;
    border-radius: 14px;
    padding: 0.3rem;
    margin: 0;
    font-family: "Nunito", sans-serif;
  }
  /* Hors de son tour, les coffres restent lisibles (ils font partie de la
     table) ; seulement un peu ternis pour signaler qu'on ne peut pas piocher. */
  #pileButtons .pile-button:disabled { opacity: 0.8; filter: saturate(0.6); }
  #pileButtons .pile-portrait {
    position: relative;
    width: 132px;
    aspect-ratio: 5/7;
    border-radius: 14px;
    overflow: hidden;
    background: linear-gradient(160deg, var(--wood-light), var(--wood));
    display: flex;
    align-items: center;
    justify-content: center;
    border: 3px solid var(--wood-light);
    box-shadow: 0 6px 14px rgba(59, 42, 26, 0.28);
    transition: transform 0.12s ease, box-shadow 0.12s ease;
  }
  #pileButtons .pile-button:hover:not(:disabled) .pile-portrait {
    transform: translateY(-5px);
    box-shadow: 0 10px 18px rgba(59, 42, 26, 0.32);
  }
  #pileButtons .pile-portrait img { width: 100%; height: 100%; object-fit: contain; display: block; }
  #pileButtons .pile-fallback {
    display: none;
    font-family: "Fraunces", serif;
    font-weight: 700;
    font-size: 1.1rem;
    color: #fff6e2;
    text-align: center;
    padding: 0.4rem;
  }
  /* Dans le coin (et non à cheval sur le bord) : .pile-portrait coupe tout
     ce qui dépasse (overflow: hidden), la pastille était donc rognée. */
  #pileButtons .pile-count {
    position: absolute;
    right: 0.35rem;
    bottom: 0.35rem;
    min-width: 1.9rem;
    height: 1.9rem;
    padding: 0 0.4rem;
    border-radius: 999px;
    background: var(--wood-dark);
    color: #ffe9b0;
    font-weight: 800;
    font-size: 0.95rem;
    display: flex;
    align-items: center;
    justify-content: center;
    border: 2px solid var(--parchment);
    box-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
  }




  /* ---- Lobby : nom, parties ouvertes, création, code ---- */
  .lobby-error {
    margin: 0.9rem 0 0;
    padding: 0.55rem 0.8rem;
    border-radius: 10px;
    border: 2px solid var(--crimson);
    background: #fbe3dc;
    color: var(--crimson);
    font-weight: 700;
    font-size: 0.9rem;
  }
  .lobby-error[hidden] { display: none; }

  /* Masqué à l'écran, lu par les lecteurs d'écran. */
  .visually-hidden {
    position: absolute;
    width: 1px;
    height: 1px;
    margin: -1px;
    padding: 0;
    overflow: hidden;
    clip: rect(0 0 0 0);
    white-space: nowrap;
    border: 0;
  }

  /* ---- Bandeau « Partie en cours » (haut du lobby) ---- */
  .resume-banner {
    display: flex;
    align-items: center;
    gap: 1rem;
    margin-bottom: 1.3rem;
    padding: 0.85rem 0.9rem 0.85rem 1.1rem;
    background: linear-gradient(180deg, #fff3cf, #fbe3a4);
    border: 2px solid var(--gold);
    border-left-width: 6px;
    border-radius: 12px;
    box-shadow: 0 2px 0 rgba(166, 106, 51, 0.25);
  }
  .resume-banner[hidden] { display: none; }
  .resume-text { flex: 1; min-width: 0; }
  .resume-text p { margin: 0; }
  .resume-kicker {
    font-size: 0.72rem;
    font-weight: 800;
    letter-spacing: 0.08em;
    text-transform: uppercase;
    color: var(--wood);
  }
  .resume-name {
    font-family: "Fraunces", serif;
    font-weight: 700;
    font-size: 1.1rem;
    color: var(--wood-dark);
    overflow-wrap: anywhere;
  }
  .resume-code {
    display: inline-block;
    margin-left: 0.3rem;
    padding: 0 0.45rem;
    border-radius: 6px;
    background: var(--wood-dark);
    color: #ffe9b0;
    font-size: 0.85rem;
    letter-spacing: 0.12em;
    vertical-align: 0.1em;
  }
  .resume-detail {
    font-size: 0.82rem;
    color: var(--wood);
    text-wrap: pretty;
  }
  .resume-button { flex-shrink: 0; }
  .resume-dismiss {
    flex-shrink: 0;
    align-self: flex-start;
    width: 1.8rem;
    height: 1.8rem;
    padding: 0;
    border: none;
    background: transparent;
    box-shadow: none;
    color: var(--wood);
    font-size: 0.95rem;
    line-height: 1;
    border-radius: 50%;
  }
  .resume-dismiss:hover:not(:disabled) { background: rgba(166, 106, 51, 0.15); filter: none; }
  .resume-dismiss:active:not(:disabled) { transform: none; box-shadow: none; }
  .resume-dismiss:focus-visible { outline: 3px solid var(--gold); outline-offset: 1px; }

  @media (max-width: 600px) {
    .resume-banner {
      flex-wrap: wrap;
      gap: 0.6rem;
      position: relative;
      padding-right: 2.4rem;
    }
    .resume-button { width: 100%; }
    .resume-dismiss { position: absolute; top: 0.4rem; right: 0.4rem; }
  }

  /* Carte du lobby plus large que les autres panneaux : deux colonnes. */
  #lobby { max-width: 880px; }

  .lobby-name { max-width: 22rem; }
  .lobby-name label { margin-top: 0; }

  .lobby-section-title {
    font-size: 1.15rem;
    color: var(--wood-dark);
    margin: 0 0 0.6rem;
  }
  /* .panel h2 met une marge plus grande : on garde celle ci-dessus. */
  .panel .lobby-section-title { margin-bottom: 0.6rem; font-size: 1.15rem; }

  .lobby-columns {
    display: grid;
    grid-template-columns: minmax(0, 1.35fr) minmax(0, 1fr);
    margin-top: 1.4rem;
    padding-top: 1.4rem;
    border-top: 2px solid rgba(166, 106, 51, 0.3);
  }
  .lobby-rooms {
    display: flex;
    flex-direction: column;
    min-height: 15rem;
    padding-right: 1.6rem;
  }
  .lobby-actions {
    display: flex;
    flex-direction: column;
    padding-left: 1.6rem;
    border-left: 2px solid rgba(166, 106, 51, 0.3);
  }
  .lobby-join {
    margin-top: 1.4rem;
    padding-top: 1.2rem;
    border-top: 2px solid rgba(166, 106, 51, 0.3);
  }
  #lobby .btn-primary { margin-top: 0; }

  /* État vide de la liste : centré dans la colonne, coffre en filigrane. */
  .public-rooms-empty {
    flex: 1;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0.6rem;
    padding: 1.2rem 1rem;
    border: 2px dashed rgba(166, 106, 51, 0.45);
    border-radius: 14px;
    text-align: center;
  }
  .public-rooms-empty[hidden] { display: none; }
  .public-rooms-empty img {
    width: 72px;
    height: auto;
    opacity: 0.75;
  }
  .public-rooms-empty p {
    margin: 0;
    font-family: "Fraunces", serif;
    font-style: italic;
    line-height: 1.5;
    color: var(--wood);
  }

  /* ---- Options de création (repliées) ---- */
  .create-options { margin-top: 0.8rem; }
  .create-options summary {
    display: flex;
    align-items: baseline;
    gap: 0.5rem;
    width: fit-content;
    cursor: pointer;
    font-weight: 800;
    font-size: 0.88rem;
    color: var(--wood-dark);
    list-style: none;
    border-radius: 6px;
  }
  .create-options summary::-webkit-details-marker { display: none; }
  .create-options summary::before {
    content: "▸";
    display: inline-block;
    transition: transform 0.15s ease;
  }
  .create-options[open] summary::before { transform: rotate(90deg); }
  .create-options summary:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; }
  .create-options-summary { font-weight: 600; color: var(--wood); }
  .create-options[open] .create-options-summary { display: none; }
  .create-options label[for="roomName"] { margin-top: 0.8rem; }

  .option-group {
    border: none;
    margin: 0.9rem 0 0;
    padding: 0;
    min-width: 0;
  }
  .option-group legend {
    padding: 0;
    font-weight: 700;
    font-size: 0.85rem;
    color: var(--wood-dark);
    margin-bottom: 0.3rem;
  }
  .option-hint {
    margin: 0.35rem 0 0;
    text-wrap: pretty;
    font-size: 0.8rem;
    color: var(--wood);
  }
  /* Une seule explication de visibilité à la fois. */
  .option-group .hint-private,
  .option-group:has(input[value="private"]:checked) .hint-public { display: none; }
  .option-group:has(input[value="private"]:checked) .hint-private { display: block; }

  /* Sélecteur segmenté : boutons radio accolés, l'option choisie en bois. */
  .segmented {
    display: flex;
    border: 2px solid var(--wood-light);
    border-radius: 10px;
    overflow: hidden;
    background: #fffaf0;
  }
  .segmented label {
    flex: 1;
    margin: 0;
    position: relative;
    cursor: pointer;
  }
  .segmented label + label { border-left: 2px solid var(--wood-light); }
  .segmented input {
    position: absolute;
    opacity: 0;
    width: 100%;
    height: 100%;
    margin: 0;
    cursor: pointer;
  }
  .segmented span {
    display: block;
    padding: 0.45rem 0.5rem;
    text-align: center;
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--wood-dark);
  }
  .segmented input:checked + span {
    background: linear-gradient(180deg, var(--wood-light), var(--wood));
    color: #fff6e2;
  }
  .segmented label:has(input:focus-visible) { outline: 3px solid var(--gold); outline-offset: -3px; z-index: 1; }

  /* Interrupteur du minuteur (case à cocher restylée). */
  .switch {
    display: flex;
    align-items: center;
    gap: 0.6rem;
    margin: 0;
    cursor: pointer;
    font-size: 0.85rem;
  }
  .switch input {
    position: absolute;
    opacity: 0;
    width: 1px;
    height: 1px;
  }
  .switch-track {
    flex-shrink: 0;
    position: relative;
    width: 2.4rem;
    height: 1.35rem;
    border-radius: 999px;
    background: var(--parchment-dark);
    border: 2px solid var(--wood-light);
    transition: background 0.15s ease;
  }
  .switch-track::after {
    content: "";
    position: absolute;
    top: 1px;
    left: 1px;
    width: calc(1.35rem - 6px);
    height: calc(1.35rem - 6px);
    border-radius: 50%;
    background: #fffaf0;
    box-shadow: 0 1px 2px rgba(59, 42, 26, 0.35);
    transition: transform 0.15s ease;
  }
  .switch input:checked + .switch-track { background: var(--wood-light); }
  .switch input:checked + .switch-track::after { transform: translateX(1.05rem); }
  .switch input:focus-visible + .switch-track { outline: 3px solid var(--gold); outline-offset: 2px; }

  .timer-minutes { display: none; margin-top: 0.6rem; }
  .timer-option:has(#turnTimerEnabled:checked) .timer-minutes { display: block; }
  .timer-minutes-label {
    display: block;
    font-weight: 700;
    font-size: 0.8rem;
    color: var(--wood-dark);
    margin-bottom: 0.3rem;
  }
  .segmented-compact { max-width: 15rem; }
  .segmented-compact span { padding: 0.3rem 0; }

  /* ---- Rejoindre avec un code : champ et bouton sur une ligne ---- */
  .join-row {
    display: flex;
    gap: 0.5rem;
  }
  .join-row input {
    flex: 1;
    min-width: 0;
    font-family: "Fraunces", serif;
    font-weight: 700;
    font-size: 1.3rem;
    letter-spacing: 0.3em;
    /* Compense l'espace ajouté après la dernière lettre, pour bien centrer. */
    text-indent: 0.3em;
    text-transform: uppercase;
    text-align: center;
    padding: 0.4rem 0.5rem;
  }
  .join-row input::placeholder { color: rgba(166, 106, 51, 0.45); }
  .join-row button { flex-shrink: 0; }

  /* Une colonne sous 760px : code, création, puis la liste. */
  @media (max-width: 760px) {
    .lobby-name { max-width: none; }
    .lobby-columns {
      display: flex;
      flex-direction: column;
    }
    .lobby-actions {
      order: -1;
      padding-left: 0;
      border-left: none;
    }
    .lobby-join {
      order: -1;
      margin: 0 0 1.4rem;
      padding: 0 0 1.2rem;
      border-top: none;
      border-bottom: 2px solid rgba(166, 106, 51, 0.3);
    }
    .lobby-rooms {
      min-height: 0;
      padding-right: 0;
      margin-top: 1.4rem;
      padding-top: 1.2rem;
      border-top: 2px solid rgba(166, 106, 51, 0.3);
    }
    .public-rooms-empty { padding: 1rem; }
    .public-rooms-empty img { width: 56px; }
  }

  @media (prefers-reduced-motion: reduce) {
    .create-options summary::before,
    .switch-track,
    .switch-track::after { transition: none; }
  }

  .public-rooms-status {
    margin: 0 0 0.5rem;
    font-family: "Fraunces", serif;
    font-style: italic;
    color: var(--wood);
  }
  .public-rooms-status[hidden] { display: none; }
  .public-rooms {
    list-style: none;
    margin: 0;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0.5rem;
    /* Au-delà de quelques parties, la liste défile seule : le reste du lobby
       (création, code) reste à portée de main. */
    max-height: 19rem;
    overflow-y: auto;
  }
  .public-room {
    display: flex;
    align-items: center;
    gap: 0.8rem;
    padding: 0.6rem 0.7rem 0.6rem 0.9rem;
    border: 2px solid var(--wood-light);
    border-left-width: 6px;
    border-radius: 12px;
    background: #fff9ea;
  }
  .public-room-info {
    flex: 1;
    min-width: 0;
    display: flex;
    flex-direction: column;
    gap: 0.25rem;
  }
  .public-room-name {
    font-family: "Fraunces", serif;
    font-weight: 700;
    font-size: 1.02rem;
    color: var(--wood-dark);
    overflow-wrap: anywhere;
  }
  .public-room-details {
    display: flex;
    flex-wrap: wrap;
    gap: 0.2rem 0.8rem;
    font-size: 0.82rem;
    color: var(--wood);
  }
  .public-room-count { font-weight: 800; }
  .public-room-heroes {
    list-style: none;
    margin: 0.1rem 0 0;
    padding: 0;
    display: flex;
    gap: 0.25rem;
  }
  .public-room-hero {
    width: 26px;
    height: 26px;
    border-radius: 50%;
    overflow: hidden;
    border: 2px solid var(--wood-light);
    background: linear-gradient(160deg, var(--wood-light), var(--wood));
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .public-room-hero img { width: 100%; height: 100%; object-fit: cover; display: block; }
  .public-room-hero .fallback {
    display: none;
    font-family: "Fraunces", serif;
    font-weight: 700;
    font-size: 0.75rem;
    color: #fff6e2;
  }
  .public-room-hero.no-image img { display: none; }
  .public-room-hero.no-image .fallback { display: block; }
  .public-room-join { flex-shrink: 0; padding: 0.55rem 0.95rem; }
  /* « Parties en cours » (renderPublicRooms) : pour information, plus
     discret que les parties ouvertes, une étiquette à la place du bouton. */
  .running-rooms { margin-top: 1.1rem; }
  .running-rooms[hidden] { display: none; }
  .running-rooms-title {
    margin: 0 0 0.5rem;
    font-size: 1rem;
    color: var(--wood-dark);
  }
  .public-room.is-running { background: #f6efdc; border-color: rgba(166, 106, 51, 0.45); }
  .public-room-badge {
    flex-shrink: 0;
    padding: 0.2rem 0.65rem;
    border-radius: 999px;
    background: var(--wood);
    color: #fff6e2;
    font-weight: 800;
    font-size: 0.75rem;
  }

  /* ---- Choix du héros : nom, visibilité, hôte ---- */
  .room-header-info { text-align: right; }
  .room-title {
    font-family: "Fraunces", serif;
    font-weight: 700;
    font-size: 1.1rem;
    color: var(--wood-dark);
    overflow-wrap: anywhere;
  }
  .room-header-info .hint { display: flex; justify-content: flex-end; gap: 0.7rem; }
  .player-list .host-badge {
    margin-right: auto;
    margin-left: 0.5rem;
    font-size: 0.75rem;
    font-weight: 800;
    color: var(--wood-dark);
    background: #f6e3a6;
    border: 1px solid var(--gold);
    border-radius: 999px;
    padding: 0.05rem 0.5rem;
    align-self: center;
  }
  .player-list .host-badge[hidden] { display: none; }

  /* Compte à rebours du tour en cours, sous le nom (complète l'anneau). */
  .player-status-bar .turn-timer {
    margin-top: 0.2rem;
    font-weight: 800;
    font-size: 0.8rem;
    color: var(--wood-dark);
    font-variant-numeric: tabular-nums;
  }
  .player-status-bar > li.low-time .turn-timer { color: var(--crimson); }

  /* Bandeau visible de tous pendant un choix imposé en attente (L'incapable,
     Eclaireur) avec minuteur activé. */
  .choice-timer-banner {
    background: #fff3d6;
    border: 2px solid var(--gold);
    border-radius: 10px;
    padding: 0.5rem 0.8rem;
    margin: 0;
    font-weight: 700;
    color: var(--wood-dark);
    font-size: 0.9rem;
  }


  /* Panneau latéral Journal + Chat (points 8 et 12 du README). Colonne de
     droite pleine hauteur dès qu'une salle est rejointe : au choix du héros
     (onglet Chat seul, voir « Choix du héros » plus bas) comme en jeu (voir
     la section body.in-game). Sous 1000px : tiroir (bloc mobile). */
  .side-panel {
    position: fixed;
    top: 1.5rem;
    right: 1.5rem;
    width: 300px;
    max-height: calc(100vh - 3rem);
    background: var(--parchment);
    border: 4px solid var(--wood);
    border-radius: 16px;
    box-shadow: 0 8px 20px rgba(59, 42, 26, 0.25);
    display: flex;
    flex-direction: column;
    overflow: hidden;
    z-index: 500;
  }

  .side-tabs {
    display: flex;
    align-items: stretch;
    border-bottom: 2px solid var(--wood-light);
    flex: none;
  }
  .side-tab {
    flex: 1;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 0.35rem;
    background: none;
    box-shadow: none;
    border-radius: 0;
    border-bottom: 3px solid transparent;
    margin-bottom: -2px;
    padding: 0.65rem 0.5rem 0.55rem;
    font-family: "Fraunces", serif;
    font-weight: 700;
    font-size: 0.95rem;
    color: var(--wood-light);
  }
  .side-tab[hidden] { display: none; }
  .side-tab[aria-selected="true"] { color: var(--wood-dark); border-bottom-color: var(--crimson); }
  .side-tab:focus-visible { outline: 3px solid var(--gold); outline-offset: -3px; }
  .side-panel.collapsed .side-tab[aria-selected="true"] { border-bottom-color: transparent; }
  .side-panel.collapsed .side-tabs { border-bottom: none; }

  .unread-badge {
    min-width: 1.25rem;
    height: 1.25rem;
    padding: 0 0.3rem;
    border-radius: 999px;
    background: var(--crimson);
    color: #fff6e2;
    font-family: "Nunito", sans-serif;
    font-size: 0.72rem;
    font-weight: 800;
    display: inline-flex;
    align-items: center;
    justify-content: center;
  }
  .unread-badge[hidden] { display: none; }

  .side-collapse {
    flex: none;
    background: none;
    box-shadow: none;
    padding: 0 0.7rem;
    font-size: 1rem;
    line-height: 1;
    color: var(--wood-dark);
  }

  .side-pane {
    display: none;
    flex-direction: column;
    flex: 1;
    min-height: 0;
  }
  .side-pane.active { display: flex; }
  .side-panel.collapsed .side-pane { display: none; }

  /* Journal (renderLog) : un groupe par tour, le plus récent en bas. Chaque
     groupe a un en-tête (portrait + joueur + numéro du tour), puis ses
     lignes, mises en forme selon leur type (classes log-kind-…) ; les
     conséquences d'une carte (is-detail) sont en retrait sous elle. */
  .log-list {
    list-style: none;
    margin: 0;
    padding: 0.5rem 0.6rem 0.8rem;
    overflow-y: auto;
    flex: 1;
    min-height: 120px;
    font-size: 0.85rem;
    line-height: 1.4;
  }
  .log-turn { margin: 0 0 0.7rem; }
  .log-turn-header {
    display: flex;
    align-items: center;
    gap: 0.45rem;
    padding: 0.25rem 0.45rem;
    border-radius: 8px;
    background: rgba(166, 106, 51, 0.12);
    font-family: "Fraunces", serif;
    font-weight: 700;
    font-size: 0.86rem;
    color: var(--wood-dark);
  }
  .log-turn.is-mine .log-turn-header { background: rgba(139, 42, 42, 0.1); }
  /* Le tour en cours ressort, pour savoir où on en est d'un coup d'œil. */
  .log-turn.is-current .log-turn-header {
    background: #fdeab0;
    box-shadow: inset 0 0 0 2px var(--gold);
  }
  .log-turn.is-setup .log-turn-header { background: none; padding-left: 0.2rem; color: var(--wood-light); font-size: 0.8rem; }
  .log-turn-portrait {
    flex: none;
    width: 1.6rem;
    height: 1.6rem;
    border-radius: 6px;
    overflow: hidden;
    background: linear-gradient(160deg, var(--wood-light), var(--wood));
    display: flex;
    align-items: center;
    justify-content: center;
  }
  .log-turn-portrait img { width: 100%; height: 100%; object-fit: contain; display: block; }
  .log-turn-portrait .fallback { display: none; color: #fff6e2; font-size: 0.8rem; }
  .log-turn-title { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
  .log-turn-number { flex: none; font-family: "Nunito", sans-serif; font-size: 0.7rem; font-weight: 800; color: var(--wood-light); }

  .log-turn-entries { list-style: none; margin: 0.2rem 0 0; padding: 0; }
  .log-entry {
    position: relative;
    margin: 0.12rem 0;
    padding: 0.18rem 0.4rem 0.18rem 0.55rem;
    border-left: 3px solid transparent;
    border-radius: 0 6px 6px 0;
  }
  /* Conséquences d'une carte : en retrait, avec une flèche. */
  .log-entry.is-detail { margin-left: 0.9rem; padding-left: 1.1rem; }
  .log-entry.is-detail::before {
    content: "↳";
    position: absolute;
    left: 0.25rem;
    top: 0.16rem;
    color: var(--wood-light);
  }
  /* Ce qu'on fait sans carte : discret. */
  .log-kind-draw,
  .log-kind-pass,
  .log-kind-system { color: var(--wood); font-size: 0.8rem; }
  /* Une carte jouée : la ligne principale du tour. */
  .log-kind-play { border-left-color: var(--wood); background: rgba(255, 249, 234, 0.7); font-weight: 600; }
  .log-kind-reflex { border-left-color: var(--gold); background: #fff3c4; font-weight: 600; }
  .log-kind-reflex::before { content: "⚡ "; }
  .log-kind-reflex.is-cotcot::before { content: "🐔 "; }
  /* Conséquences, par couleur. */
  .log-kind-attack { color: var(--crimson); }
  .log-kind-ko { color: var(--crimson); font-weight: 700; background: #fbe6de; }
  .log-kind-cards { color: #2c4f86; }
  .log-kind-cancel { color: #7a5a0a; font-style: italic; }
  .log-kind-victory { color: var(--crimson); font-family: "Fraunces", serif; font-weight: 700; }
  /* Lignes privées (moi seul) : teinte violette et cadenas. */
  .log-entry.is-private { background: #efe6f7; color: #4a3566; }
  .log-entry.is-private::after { content: " 🔒"; font-size: 0.7rem; }
  /* Conséquences annulées par un Réflex : barrées et estompées. */
  .log-entry.is-cancelled { text-decoration: line-through; text-decoration-color: rgba(139, 42, 42, 0.7); opacity: 0.6; }
  .log-entry.is-cancelled .log-card { text-decoration: line-through; }
  /* Une carte contrée, et le Réflex qui la contre, reliés par la même
     couleur dorée (bordure et étiquette). */
  .log-entry.is-countered { border-left-color: var(--gold); border-left-style: dashed; }
  .log-entry.is-reaction { margin-left: 0.9rem; }
  .log-tag {
    display: inline-block;
    padding: 0 0.45rem;
    border-radius: 999px;
    font-size: 0.72rem;
    font-weight: 700;
    font-style: normal;
    line-height: 1.5;
    text-decoration: none;
    white-space: normal;
  }
  .log-tag-countered { background: #f6d86a; color: var(--wood-dark); }
  .log-tag-reaction { background: rgba(201, 162, 39, 0.25); color: #6b4f05; }
  .log-tag .log-name { color: inherit; }

  .log-list > li.log-win {
    margin-top: 0.4rem;
    font-family: "Fraunces", serif;
    font-weight: 700;
    font-size: 1rem;
    color: var(--crimson);
  }

  .log-name { font-weight: 800; color: var(--ink); }
  .log-kind-attack .log-name,
  .log-kind-ko .log-name { color: inherit; }
  .log-name.is-me { color: var(--crimson); }
  /* Nom de carte cliquable : un lien discret qui ouvre le zoom. */
  .log-list .log-card {
    display: inline;
    padding: 0;
    border: none;
    border-radius: 0;
    background: none;
    box-shadow: none;
    color: inherit;
    font: inherit;
    font-weight: 700;
    text-decoration: underline dotted;
    text-underline-offset: 2px;
    cursor: zoom-in;
  }
  .log-list .log-card:hover { color: var(--crimson); filter: none; }
  .log-list .log-card:active { transform: none; box-shadow: none; }
  .log-list .log-card:focus-visible { outline: 2px solid var(--gold); outline-offset: 1px; border-radius: 3px; }

  /* Zoom d'une carte seule (journal) : ni flèches ni position. */
  .card-zoom-overlay.is-single .card-zoom-nav { visibility: hidden; }

  .side-panel .chat-messages {
    flex: 1;
    overflow-y: auto;
    padding: 0.5rem 0.7rem;
    display: flex;
    flex-direction: column;
    gap: 0.4rem;
    min-height: 120px;
    max-height: 45vh;
  }
  .chat-message {
    background: #fff9ea;
    border-radius: 10px;
    padding: 0.35rem 0.6rem;
    font-size: 0.85rem;
    word-wrap: break-word;
  }
  .chat-message.me { background: #fdeccb; align-self: flex-end; }
  .chat-message-author {
    display: block;
    font-weight: 800;
    font-size: 0.75rem;
    color: var(--crimson);
  }
  .chat-message-text { color: var(--ink); }
  .side-panel .chat-form {
    display: flex;
    gap: 0.4rem;
    padding: 0.6rem;
    border-top: 2px solid var(--wood-light);
    flex: none;
  }
  .side-panel .chat-form input {
    flex: 1;
    font-size: 0.85rem;
    padding: 0.4rem 0.6rem;
  }
  .side-panel .chat-form button {
    padding: 0.4rem 0.7rem;
    font-size: 0.85rem;
  }


  /* ---- Mise en page en jeu (points 1 et 2) ----
     body.in-game (posé par app.js dès que la partie commence) transforme la
     page en application plein écran : barre d'en-tête fine en haut, plateau
     à gauche (défilement propre si besoin), panneau Journal/Chat à droite. */
  body.in-game {
    display: grid;
    grid-template-columns: minmax(0, 1fr) auto;
    grid-template-rows: auto minmax(0, 1fr);
    grid-template-areas:
      "top  top"
      "board side";
    /* Fixé sur la zone réellement visible, plutôt que height: 100vh : sur
       mobile, 100vh compte aussi la place des barres du navigateur, et le
       min-height: 100vh du body (lobby) rendait la page plus haute que
       l'écran. La page devenait alors défilable et l'en-tête pouvait glisser
       sous la barre d'adresse. Fixé, le body ne peut plus défiler du tout :
       seuls le plateau et le panneau latéral défilent, chacun chez lui. */
    position: fixed;
    inset: 0;
    min-height: 0;
    padding: 0;
    overflow: hidden;
    align-items: stretch;
  }

  body.in-game .brand {
    grid-area: top;
    display: flex;
    align-items: center;
    gap: 1.2rem;
    margin: 0;
    padding: 0.4rem 1.25rem;
    text-align: left;
    background: linear-gradient(180deg, #f7edd4, var(--parchment));
    border-bottom: 4px solid var(--wood);
    box-shadow: 0 3px 10px rgba(59, 42, 26, 0.18);
    position: relative;
    /* Au-dessus du panneau latéral (500), pour que le menu déroulant passe
       par-dessus ; sous les popups et fenêtres (1000, 2000). */
    z-index: 700;
  }
  body.in-game .brand h1 img {
    width: auto;
    height: 52px;
    max-height: none;
    margin: 0;
  }
  body.in-game .brand .tagline { display: none; }
  body.in-game .brand-room {
    display: flex;
    align-items: center;
    gap: 0.5rem;
    font-size: 0.85rem;
    font-weight: 700;
    color: var(--wood);
  }
  body.in-game .brand-room .room-code { font-size: 1.1rem; padding: 0.15rem 0.6rem; }
  /* Chronomètre de la partie, à côté du code de salle (en jeu seulement). */
  .game-clock { display: none; }
  body.in-game .game-clock:not([hidden]) {
    display: inline-flex;
    align-items: center;
    padding: 0.15rem 0.55rem;
    border-radius: 999px;
    background: rgba(166, 106, 51, 0.12);
    color: var(--wood-dark);
    font-weight: 800;
    font-size: 0.85rem;
    font-variant-numeric: tabular-nums;
    white-space: nowrap;
  }
  body.in-game .rules-button { margin: 0 0 0 auto; }
  body.in-game .game-menu { margin-left: -0.6rem; }

  body.in-game #ingame {
    grid-area: board;
    overflow-y: auto;
    padding: 1.25rem 1.5rem 1.5rem;
  }
  body.in-game .side-panel {
    grid-area: side;
    position: static;
    width: 320px;
    max-height: none;
    border: none;
    border-left: 4px solid var(--wood);
    border-radius: 0;
    box-shadow: none;
  }
  body.in-game .side-panel .chat-messages { max-height: none; }
  /* Réduit en jeu : la colonne se rétrécit à la seule barre d'onglets,
     empilée verticalement le long du bord droit. */
  body.in-game .side-panel.collapsed { width: auto; }
  body.in-game .side-panel.collapsed .side-tabs {
    flex-direction: column;
    height: 100%;
    justify-content: flex-start;
  }
  body.in-game .side-panel.collapsed .side-collapse { order: -1; padding: 0.8rem 0; }
  body.in-game .side-panel.collapsed .side-tab {
    flex: none;
    writing-mode: vertical-rl;
    padding: 0.9rem 0.55rem;
    border-bottom: none;
    margin: 0;
  }

  /* ---- Choix du héros (avant la partie) : même colonne qu'en jeu ----
     body.has-room sans .in-game = salle rejointe, partie pas lancée. Le
     panneau est collé au bord droit sur toute la hauteur, et la page garde
     sa mise en page centrée dans la place restante (padding-right du body,
     égal à la largeur de la colonne). Réservé au bureau : sous 1000px, le
     panneau est un tiroir (le complément exact de MOBILE_QUERY, pour que
     les deux blocs ne se chevauchent jamais). */
  @media not all and (max-width: 1000px) {
    body.has-room:not(.in-game) {
      --side-column-w: 320px;
      padding-right: calc(var(--side-column-w) + 1.25rem);
    }
    /* Réduit, la colonne prend la largeur de sa barre d'onglets (≈ 40px,
       comme en jeu) : 2.5rem suffit pour que rien ne passe dessous. */
    body.has-room:not(.in-game):has(#chatPanel.collapsed) { --side-column-w: 2.5rem; }
    body.has-room:not(.in-game) .side-panel {
      top: 0;
      right: 0;
      bottom: 0;
      width: var(--side-column-w);
      max-height: none;
      border: none;
      border-left: 4px solid var(--wood);
      border-radius: 0;
      box-shadow: -4px 0 14px rgba(59, 42, 26, 0.12);
    }
    body.has-room:not(.in-game) .side-panel .chat-messages { max-height: none; }
    body.has-room:not(.in-game) .side-panel.collapsed { width: auto; }
    /* Réduit : barre d'onglets verticale le long du bord, comme en jeu. */
    body.has-room:not(.in-game) .side-panel.collapsed .side-tabs {
      flex-direction: column;
      height: 100%;
      justify-content: flex-start;
    }
    body.has-room:not(.in-game) .side-panel.collapsed .side-collapse { order: -1; padding: 0.8rem 0; }
    body.has-room:not(.in-game) .side-panel.collapsed .side-tab {
      flex: none;
      writing-mode: vertical-rl;
      padding: 0.9rem 0.55rem;
      border-bottom: none;
      margin: 0;
    }
  }

  /* Le plateau : la table (adversaires + coffres) puis ma zone. */
  .board {
    max-width: 1200px;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    gap: 1.2rem;
  }
  .table-zone {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.4rem;
    padding: 1.2rem 1.2rem 1.6rem;
    background: radial-gradient(ellipse at center, #fbf2dc 0%, var(--parchment) 55%, var(--parchment-dark) 100%);
    border: 6px solid var(--wood);
    border-radius: var(--panel-radius);
    box-shadow:
      inset 0 0 0 2px var(--wood-light),
      inset 0 0 40px rgba(107, 62, 34, 0.18),
      0 10px 24px rgba(59, 42, 26, 0.25);
  }
  .opponents { justify-content: center; align-items: flex-end; }
  .table-center {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 0.9rem;
    width: 100%;
  }

  .me-zone {
    display: flex;
    align-items: flex-start;
    gap: 1.2rem;
  }
  .me-status { flex: none; }
  .me-hand { flex: 1; min-width: 0; }
  /* Toujours une seule rangée, jamais de défilement : layoutHand() (app.js)
     rétrécit puis fait se chevaucher les cartes si la main est trop longue.
     En hauteur, la main prend la place dont elle a besoin. Marges pour la
     gemme, le soulèvement au survol et les cartes inclinées des bords. */
  #hand {
    display: flex;
    flex-wrap: nowrap;
    padding: 1.2rem 1.8rem 0.8rem;
  }
  #hand > .hand-card + .hand-card { margin-left: var(--hand-card-gap, 12px); }
  #hand > p { flex-basis: 100%; margin: 0; }
  /* Actions de tour : Révéler et Passer à gauche, Donner une carte (action
     secondaire, possible à tout moment) poussée à droite. */
  .hand-actions {
    display: flex;
    flex-wrap: wrap;
    align-items: center;
    gap: 0.6rem;
    margin-top: 1rem;
  }
  .hand-actions #giveCard { margin-left: auto; }
  .hand-card-actions {
    margin-top: auto;
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.3rem;
  }
  .hand-card-actions button { padding: 0.4rem 0.9rem; font-size: 0.85rem; }

  /* Bandeau de tour (point 3), au-dessus de la main. */
  .turn-banner {
    margin-bottom: 0.8rem;
    padding: 0.6rem 1rem;
    border: 2px solid var(--wood-light);
    border-radius: 12px;
    background: #fff9ea;
    color: var(--wood);
    font-weight: 700;
  }
  .turn-banner.is-mine,
  .turn-banner.is-win {
    border-color: var(--gold);
    background: linear-gradient(180deg, #fff3d6, #fde6ae);
    color: var(--wood-dark);
    font-family: "Fraunces", serif;
    font-size: 1.1rem;
    box-shadow: 0 0 0 2px rgba(201, 162, 39, 0.35);
  }
  .turn-banner.is-alert {
    border-color: var(--crimson);
    background: #fbe6de;
    color: var(--crimson);
  }
  .turn-banner.is-waiting { font-style: italic; }

  /* Coffres : ils brillent quand piocher est l'action attendue. */
  #pileButtons.can-draw .pile-button:not(.discard-pile) .pile-portrait {
    border-color: var(--gold);
    animation: chest-glow 3.2s ease-in-out infinite;
    animation-delay: var(--glow-delay, 0s);
  }
  @keyframes chest-glow {
    0%, 100% { box-shadow: 0 0 0 2px var(--gold), 0 0 8px 2px rgba(201, 162, 39, 0.4); }
    50% { box-shadow: 0 0 0 3px var(--gold), 0 0 20px 6px rgba(201, 162, 39, 0.6); }
  }

  @media (prefers-reduced-motion: reduce) {
    .player-status-bar > li.turn { animation: none; box-shadow: 0 0 0 3px var(--gold), 0 0 16px 4px rgba(201, 162, 39, 0.5); }
    .hand-card { transition: none; }
    #pileButtons.can-draw .pile-button:not(.discard-pile) .pile-portrait { animation: none; box-shadow: 0 0 0 3px var(--gold), 0 0 14px 4px rgba(201, 162, 39, 0.5); }
  }

  /* Menu de la partie (point 7) : dès qu'une salle est rejointe. Au choix du
     héros, à côté de « Règles du jeu » ; en jeu, dans la barre d'en-tête. */
  .game-menu { display: none; position: relative; }
  body.has-room:not(.in-game) .game-menu { display: inline-block; vertical-align: top; margin-left: 0.5rem; }
  body.in-game .game-menu { display: block; }
  body.has-room:not(.in-game) .game-menu-button { margin-top: 0.8rem; }
  .game-menu-button {
    background: linear-gradient(180deg, #fff9ea, #fdeccb);
    color: var(--wood-dark);
    box-shadow: 0 3px 0 var(--wood-light);
    padding: 0.5rem 0.8rem;
    font-size: 1rem;
    line-height: 1;
  }
  .game-menu-list {
    position: absolute;
    top: calc(100% + 0.5rem);
    right: 0;
    min-width: 230px;
    padding: 0.35rem;
    background: var(--parchment);
    border: 3px solid var(--wood);
    border-radius: 12px;
    box-shadow: 0 8px 20px rgba(59, 42, 26, 0.3);
    z-index: 600;
  }
  .game-menu-list[hidden] { display: none; }
  .game-menu-item {
    width: 100%;
    text-align: left;
    background: none;
    box-shadow: none;
    color: var(--ink);
    border-radius: 8px;
    padding: 0.55rem 0.7rem;
    font-size: 0.9rem;
  }
  .game-menu-item:hover:not(:disabled),
  .game-menu-item:focus-visible { background: #fdeccb; filter: none; outline: none; }
  .game-menu-item:active:not(:disabled) { transform: none; box-shadow: none; }
  .game-menu-item.is-danger { color: var(--crimson); }

  /* Confirmation d'abandon : même fond que les règles, petite fenêtre. */
  .confirm-overlay {
    position: fixed;
    inset: 0;
    background: rgba(59, 42, 26, 0.72);
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1rem;
  }
  .confirm-content {
    background: var(--parchment);
    border: 6px solid var(--wood);
    border-radius: var(--panel-radius);
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.4);
    padding: 1.6rem 1.8rem;
    max-width: min(92vw, 420px);
    text-align: center;
  }
  .confirm-content h2 { font-size: 1.35rem; color: var(--crimson); margin-bottom: 0.6rem; }
  .confirm-content p { margin: 0 0 1.2rem; line-height: 1.45; }
  .confirm-actions { display: flex; justify-content: center; flex-wrap: wrap; gap: 0.6rem; }

  .debug-panel { font-size: 0.85rem; }
  .debug-panel pre { max-height: 300px; overflow: auto; background: #fff9ea; padding: 0.6rem; border-radius: 8px; }

  /* Éléments propres au mobile, masqués par défaut (voir le bloc mobile). */
  .side-panel-button,
  .side-drawer-close,
  .side-backdrop { display: none; }

  /* ---- Mobile et petites tablettes (point 9), sous 1000px ----
     Hors partie : le chat passe sous le reste de la page.
     En jeu : écran plein, table qui défile en haut, ma zone (bandeau, main,
     actions) fixée en bas, Journal / Chat dans un tiroir ouvert depuis
     l'en-tête. Même seuil que MOBILE_QUERY dans app.js. */
  @media (max-width: 1000px) {
    .side-panel {
      position: static;
      order: 10;
      width: 100%;
      max-width: 480px;
      max-height: none;
      margin: 0 auto 1.5rem;
    }
    .side-panel .chat-messages { max-height: 220px; }

    /* En-tête : une seule ligne, icônes seules pour Règles. */
    body.in-game .brand { padding: 0.35rem 0.6rem; gap: 0.45rem; }
    body.in-game .brand h1 img { height: 34px; }
    body.in-game .brand-room { font-size: 0.75rem; gap: 0.35rem; }
    body.in-game .brand-room .room-code { font-size: 0.95rem; padding: 0.1rem 0.45rem; }
    /* L'en-tête doit tenir sur une ligne : « Salle » masqué, chronomètre
       sous le code. */
    body.in-game .brand-room-label { display: none; }
    body.in-game .brand-room { flex-direction: column; align-items: center; gap: 0.1rem; }
    body.in-game .game-clock:not([hidden]) { font-size: 0.68rem; padding: 0 0.35rem; background: none; }
    body.in-game .label-long { display: none; }
    body.in-game .rules-button,
    body.in-game .side-panel-button,
    body.in-game .game-menu-button {
      padding: 0.45rem 0.6rem;
      font-size: 1rem;
      line-height: 1;
    }
    body.in-game .game-menu { margin-left: 0; }
    body.has-room .side-panel-button {
      display: inline-flex;
      align-items: center;
      gap: 0.2rem;
      background: linear-gradient(180deg, #fff9ea, #fdeccb);
      color: var(--wood-dark);
      box-shadow: 0 3px 0 var(--wood-light);
    }

    /* Grille : en-tête / plateau. Le plateau lui-même se découpe en une
       table qui défile et ma zone qui reste en bas. */
    body.in-game {
      grid-template-columns: minmax(0, 1fr);
      grid-template-areas:
        "top"
        "board";
    }
    body.in-game #ingame { padding: 0; overflow: hidden; }
    body.in-game .board {
      height: 100%;
      max-width: none;
      gap: 0;
    }
    body.in-game .table-zone {
      flex: 1;
      min-height: 0;
      overflow-y: auto;
      overscroll-behavior: contain;
      gap: 0.9rem;
      margin: 0.5rem 0.5rem 0;
      padding: 1.1rem 0.6rem 0.9rem;
      border-width: 4px;
      justify-content: flex-start;
    }
    body.in-game .debug-panel { display: none; }

    /* Adversaires : tuiles compactes, sur une ou deux lignes. */
    body.in-game .opponents { gap: 0.9rem 0.5rem; }
    body.in-game .opponents > li { width: 86px; padding: 0.35rem 0.25rem; }
    body.in-game .player-status-bar .player-portrait,
    body.in-game .player-status-bar > li.turn .player-portrait { width: 48px; height: 48px; min-width: 48px; }
    body.in-game .player-status-bar .portrait-ring { padding: 3px; border-radius: 13px; }
    body.in-game .player-status-bar .player-name {
      font-size: 0.8rem;
      max-width: 100%;
      overflow: hidden;
      text-overflow: ellipsis;
      white-space: nowrap;
    }
    body.in-game .status-badges { gap: 0.2rem; }
    body.in-game .badge { font-size: 0.68rem; padding: 0.08rem 0.35rem; gap: 0.2rem; }
    /* États rares : icône seule (le mot est dans title / aria-label). */
    body.in-game .badge-hidden .badge-label,
    body.in-game .badge-skip .badge-label,
    body.in-game .badge-offline .badge-label { display: none; }
    /* Dans le zoom d'un héros, la place ne manque pas : les mots reviennent. */
    body.in-game .card-zoom-badges .badge-label { display: inline; }
    body.in-game .player-status-bar .turn-flag { font-size: 0.65rem; padding: 0.1rem 0.5rem; top: -0.7rem; }
    body.in-game .player-status-bar > li.is-target::after { font-size: 0.65rem; padding: 0.1rem 0.5rem; bottom: -0.65rem; }
    /* Étiquettes des animations (K.O., Réflex, Contré) : à la taille des
       petites tuiles. */
    body.in-game .player-status-bar > li.hit-ko::after,
    body.in-game .player-status-bar > li.reflex-flash::after,
    body.in-game .player-status-bar > li.countered::after { font-size: 0.72rem; padding: 0.1rem 0.4rem; }
    body.in-game .player-status-bar > li.countered::after { border-width: 2px; }
    body.in-game .player-status-bar .turn-timer { font-size: 0.72rem; }

    /* Coffres. */
    /* Trois coffres et la défausse sur 360px de large. */
    #pileButtons { gap: 0.45rem; }
    #pileButtons .pile-portrait { width: 70px; }
    #pileButtons .pile-label { font-size: 0.7rem; }
    #pileButtons .pile-count { min-width: 1.5rem; height: 1.5rem; font-size: 0.8rem; right: 0.25rem; bottom: 0.25rem; }

    /* Ma zone, fixée en bas : ma tuile + bandeau, main, puis actions. */
    body.in-game .me-zone {
      flex: none;
      display: grid;
      grid-template-columns: auto minmax(0, 1fr);
      grid-template-areas:
        "me banner"
        "hand hand"
        "actions actions";
      align-items: center;
      gap: 0.4rem 0.6rem;
      padding: 0.5rem 0.6rem max(0.6rem, env(safe-area-inset-bottom));
      background: linear-gradient(180deg, var(--parchment), #f7edd4);
      border-top: 4px solid var(--wood);
      box-shadow: 0 -4px 12px rgba(59, 42, 26, 0.18);
    }
    body.in-game .me-hand { display: contents; }
    body.in-game #turnBanner {
      grid-area: banner;
      margin: 0;
      padding: 0.4rem 0.7rem;
      font-size: 0.85rem;
    }
    body.in-game #turnBanner.is-mine,
    body.in-game #turnBanner.is-win { font-size: 0.95rem; }

    /* Main : rangée qu'on fait défiler au doigt (cartes à taille fixe,
       posée par layoutHand), sans éventail. */
    body.in-game #hand {
      grid-area: hand;
      overflow-x: auto;
      overscroll-behavior-x: contain;
      scroll-snap-type: x proximity;
      padding: 0.8rem 0.2rem 0.4rem;
      scrollbar-width: thin;
    }
    body.in-game .hand-card {
      transform: none;
      scroll-snap-align: start;
      padding: 0.3rem 0.3rem 0.45rem;
      border-width: 2px;
      border-radius: 11px;
      gap: 0.3rem;
      box-shadow: 0 3px 8px rgba(59, 42, 26, 0.2);
    }
    body.in-game .hand-card:hover,
    body.in-game .hand-card:focus-within { transform: none; box-shadow: 0 3px 8px rgba(59, 42, 26, 0.2); }
    body.in-game .hand-card .chest-gem { width: 0.8rem; height: 0.8rem; top: -0.5rem; }
    body.in-game .hand-card-actions button { padding: 0.35rem 0.6rem; font-size: 0.78rem; }
    body.in-game .hand-card .card-fallback strong { font-size: 0.8rem; }
    body.in-game .hand-card .card-fallback p { display: none; }
    body.in-game #hand .hand-card.is-choice::after { font-size: 0.68rem; padding: 0.1rem 0.5rem; bottom: -0.7rem; }
    /* La main défile (overflow-x) et rogne ce qui dépasse : place pour le
       contour et la pastille pendant le choix. */
    body.in-game #hand.is-choosing { padding: 0.8rem 0.5rem 1.1rem; }
    /* Défausse imposée : la carte choisie se soulève, sa pastille est en haut. */
    body.in-game #hand.is-imposed { padding: 1.3rem 0.5rem 0.6rem; }
    /* Plus précis que la pastille du choix ci-dessus : en haut, pas en bas
       (sinon, haut ET bas fixés, elle s'étire sur toute la carte). */
    body.in-game #hand.is-imposed .hand-card.is-choice::after { top: -0.7rem; bottom: auto; }
    /* Flip : coffres masqués le temps du choix (on ne peut pas piocher), les
       races libres remontent sous les tuiles des joueurs. */
    .table-center.is-hero-choice #pileButtons { display: none; }
    body.in-game .target-picker .reorder-card { width: 92px; }
    body.in-game .target-picker .reorder-cards { gap: 0.9rem 0.45rem; padding: 0.9rem 0.4rem 0.7rem; }
    body.in-game #hand .hand-card.is-lost::after { font-size: 0.62rem; padding: 0.08rem 0.4rem; top: -0.7rem; }

    /* Ma tuile : une ligne compacte (portrait + pastilles). */
    body.in-game .me-status { grid-area: me; }
    body.in-game .me-status > li {
      flex-direction: row;
      align-items: center;
      gap: 0.4rem;
      width: auto;
      padding: 0.25rem 0.5rem 0.25rem 0.3rem;
    }
    body.in-game .me-status .player-portrait,
    body.in-game .me-status > li.turn .player-portrait { width: 40px; height: 40px; min-width: 40px; }
    body.in-game .me-status .portrait-ring { padding: 2px; border-radius: 10px; }
    body.in-game .me-status .player-name { display: none; }
    body.in-game .me-status .status-badges { margin: 0; flex-direction: column; align-items: flex-start; flex-wrap: nowrap; }
    body.in-game .me-status .turn-timer { margin: 0; }

    body.in-game .hand-actions {
      grid-area: actions;
      margin: 0;
      gap: 0.4rem;
      flex-wrap: nowrap;
    }
    body.in-game .hand-actions button { flex: 1; padding: 0.55rem 0.5rem; font-size: 0.85rem; }
    body.in-game .hand-actions #giveCard { margin-left: 0; }

    /* Journal / Chat : tiroir qui glisse depuis la droite, dès qu'une
       salle est rejointe (body.has-room : choix du héros compris). */
    body.has-room .side-panel,
    body.has-room .side-panel.collapsed {
      position: fixed;
      top: 0;
      right: 0;
      bottom: 0;
      width: min(88vw, 360px);
      max-width: none;
      height: auto;
      margin: 0;
      border: none;
      border-left: 4px solid var(--wood);
      border-radius: 0;
      box-shadow: -8px 0 24px rgba(0, 0, 0, 0.3);
      z-index: 1500;
      transform: translateX(105%);
      visibility: hidden;
      transition: transform 0.25s ease, visibility 0s linear 0.25s;
    }
    body.has-room.drawer-open .side-panel {
      transform: none;
      visibility: visible;
      transition: transform 0.25s ease;
    }
    /* Dans le tiroir, pas de réduction : la croix ferme le tiroir. */
    body.has-room .side-collapse { display: none; }
    body.has-room .side-drawer-close {
      display: block;
      flex: none;
      background: none;
      box-shadow: none;
      padding: 0 0.9rem;
      font-size: 1.1rem;
      color: var(--wood-dark);
    }
    body.has-room .side-panel.collapsed .side-pane.active { display: flex; }
    body.has-room .side-panel.collapsed .side-tabs { flex-direction: row; height: auto; border-bottom: 2px solid var(--wood-light); }
    body.has-room .side-panel.collapsed .side-tab { flex: 1; writing-mode: horizontal-tb; padding: 0.65rem 0.5rem 0.55rem; border-bottom: 3px solid transparent; margin-bottom: -2px; }
    body.has-room .side-panel.collapsed .side-tab[aria-selected="true"] { border-bottom-color: var(--crimson); }
    body.has-room .side-panel .chat-messages,
    body.has-room .log-list { max-height: none; }
    body.has-room .side-backdrop:not([hidden]) {
      display: block;
      position: fixed;
      inset: 0;
      background: rgba(59, 42, 26, 0.55);
      z-index: 1400;
    }

    /* Champ du chat à 16px minimum : en dessous, iOS zoome toute la page
       quand on touche le champ. */
    .side-panel .chat-form input { font-size: 16px; }

    /* Zoom : flèches plus petites pour laisser la place à la carte. */
    .card-zoom-overlay { gap: 0.4rem; padding: 1rem 0.4rem; }
    .card-zoom-nav { width: 2.4rem; height: 2.4rem; font-size: 1.6rem; }
    .card-zoom-content { max-width: min(calc(100vw - 6.5rem), 420px); padding: 1.2rem; }
  }

  /* Téléphone à l'horizontale : trop peu de hauteur pour fixer ma zone en
     bas (la table n'aurait plus que quelques pixels). Tout le plateau
     défile alors d'un bloc, ma zone à la suite de la table. */
  /* ---- Lobby et choix du héros sur téléphone ---- */
  @media (max-width: 600px) {
    body { padding: 1rem 0.75rem 2rem; }
    .brand { margin-bottom: 1rem; }
    .brand h1 img { width: min(340px, 82vw); max-height: 120px; }
    .brand .tagline { font-size: 0.9rem; margin-top: 0.2rem; }
    .rules-button,
    body.has-room:not(.in-game) .side-panel-button { margin-top: 0.6rem; }

    .panel {
      padding: 1.2rem 1rem 1.4rem;
      border-width: 4px;
      margin-bottom: 1rem;
    }
    /* Plus précis que les règles générales, placées plus loin dans le fichier. */
    body #lobby { margin-top: 2rem; }
    #lobby .lobby-tab { margin-bottom: 4px; font-size: 0.95rem; padding: 0.35rem 1.1rem 0.3rem; }
    .panel h2 { font-size: 1.2rem; margin-bottom: 0.7rem; }
    label { margin-top: 0.75rem; }

    .room-header { margin-bottom: 0.9rem; }
    .room-code { font-size: 1.3rem; }
    .hero-grid { gap: 0.45rem; }
    .hero-tile { padding: 0.3rem; border-width: 2px; border-radius: 12px; }
    .hero-tile .portrait { border-radius: 8px; margin-bottom: 0.25rem; }
    .hero-tile .name { font-size: 0.78rem; }
    /* Nom et état peuvent passer sur deux lignes avec un nom long. */
    .player-list li { flex-wrap: wrap; gap: 0.1rem 0.8rem; }
    .player-list .status { margin-left: auto; text-align: right; }
    .room-header-info { text-align: left; }
    .room-header-info .hint { justify-content: flex-start; }
    .public-rooms { max-height: 15rem; }
    .public-room { padding: 0.5rem 0.55rem 0.5rem 0.7rem; gap: 0.55rem; }

    /* Règles : presque plein écran. */
    .rules-overlay { padding: 0.75rem 0.5rem; }
    .rules-content {
      max-width: 100%;
      max-height: calc(100dvh - 1.5rem);
      padding: 1.3rem 1.1rem;
      border-width: 4px;
    }
    .rules-content h2 { font-size: 1.25rem; padding: 0 1.8rem; }
  }

  /* Écran tactile : pas d'effet de survol qui « colle » après un toucher. */
  @media (hover: none) {
    .hero-tile:hover:not(.taken) { transform: none; box-shadow: none; }
    .hero-tile.mine:hover { box-shadow: 0 0 0 3px rgba(201, 162, 39, 0.4); }
  }

  @media (max-width: 1000px) and (max-height: 520px) {
    body.in-game #ingame { overflow-y: auto; }
    body.in-game .board { height: auto; }
    body.in-game .table-zone { flex: none; overflow: visible; }
  }

  @media (max-width: 1000px) and (prefers-reduced-motion: reduce) {
    body.has-room .side-panel,
    body.has-room.drawer-open .side-panel { transition: none; }
  }

  /* ---- Liste de cartes : catalogue (accueil) et défausse (en partie) ----
     Fenêtre #cardsModal, sur la base de la fenêtre des cartes révélées
     (.reveal-overlay / .reveal-content / .reveal-card). */
  .cards-overlay .cards-content { width: min(94vw, 1000px); }
  .cards-filters {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 0.4rem;
    margin: 0 0 1rem;
  }
  .cards-filters[hidden] { display: none; }
  .cards-filter {
    padding: 0.3rem 0.85rem;
    border-radius: 999px;
    font-size: 0.85rem;
    background: #fff9ea;
    color: var(--wood-dark);
    box-shadow: 0 2px 0 var(--wood-light);
  }
  .cards-filter[aria-pressed="true"] { background: var(--wood); color: #fff6e2; box-shadow: 0 2px 0 var(--wood-dark); }
  .cards-empty[hidden] { display: none; }
  .list-card-meta {
    margin: 0;
    font-size: 0.72rem;
    line-height: 1.25;
    color: var(--wood);
  }
  .list-card-meta[hidden] { display: none; }
  /* Carte dont les exemplaires sont dans plusieurs coffres (catalogue) :
     bordure dorée, gemme aux trois couleurs. */
  .reveal-card.chest-multi { --chest-color: var(--gold); }
  .reveal-card.chest-multi .chest-gem { background: conic-gradient(#b8332f 0 120deg, #2f62b8 0 240deg, #3f8a3a 0); }
  .card-zoom-meta { margin: 0.6rem 0 0; font-size: 0.85rem; font-weight: 700; color: var(--wood); }
  .card-zoom-meta[hidden] { display: none; }

  /* Défausse sur la table : 4e pile à côté des coffres. La dernière carte
     défaussée, posée sur une pile (ombres décalées), ou un emplacement vide
     en pointillés ; jamais grisée (on peut la consulter à tout moment). */
  #pileButtons .discard-pile .pile-portrait {
    border: 3px solid var(--chest-color, var(--wood-light));
    border-radius: 12px;
    background: #fff9ea;
    box-shadow: 3px 3px 0 #e8d6b0, 6px 6px 0 #d8c093, 0 8px 14px rgba(59, 42, 26, 0.25);
    cursor: zoom-in;
  }
  #pileButtons .discard-pile.chest-red { --chest-color: #b8332f; }
  #pileButtons .discard-pile.chest-blue { --chest-color: #2f62b8; }
  #pileButtons .discard-pile.chest-green { --chest-color: #3f8a3a; }
  #pileButtons .discard-pile.is-empty .pile-portrait {
    border: 3px dashed var(--wood-light);
    background: rgba(255, 249, 234, 0.5);
    box-shadow: none;
  }
  #pileButtons .discard-pile .pile-portrait img { object-fit: cover; border-radius: 8px; }
  #pileButtons .discard-pile .pile-fallback { color: var(--wood-dark); font-size: 0.8rem; padding: 0.3rem; text-align: center; }
  #pileButtons .discard-pile.is-empty .pile-fallback { color: var(--wood-light); font-style: italic; }
  .pile-label { font-size: 0.78rem; font-weight: 800; color: var(--wood-dark); }

  /* Bouton "Règles du jeu" : dans .brand, donc visible sur tous les écrans
     (lobby, choix du héros, en jeu) sans logique de visibilité à gérer. */
  .rules-button {
    margin-top: 0.8rem;
    background: linear-gradient(180deg, #fff9ea, #fdeccb);
    color: var(--wood-dark);
    box-shadow: 0 3px 0 var(--wood-light);
    font-size: 0.85rem;
  }

  /* Bouton Contact : même style que « Règles du jeu », à côté de lui ;
     seulement sur l'accueil. */
  /* Boutons de l'accueil seulement (Cartes, Feuille éditeur, Contact) : à côté de « Règles
     du jeu », masqués dès qu'une salle est rejointe. */
  .home-only { margin-left: 0.5rem; }
  body.has-room .home-only { display: none; }

  /* Fenêtre Contact (#contactModal) : même principe que les autres
     fenêtres (fond sombre, parchemin, croix). */
  .contact-overlay {
    position: fixed;
    inset: 0;
    background: rgba(59, 42, 26, 0.72);
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem 1rem;
  }
  .contact-content {
    position: relative;
    width: min(92vw, 440px);
    background: var(--parchment);
    border: 6px solid var(--wood);
    border-radius: var(--panel-radius);
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.4);
    padding: 1.6rem 1.6rem 1.3rem;
    text-align: center;
  }
  .contact-content h2 { color: var(--crimson); font-size: 1.4rem; margin: 0 2rem 0.6rem; }
  .contact-close {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    width: 2rem;
    height: 2rem;
    padding: 0;
    line-height: 1;
    border-radius: 50%;
    background: var(--wood);
    box-shadow: none;
  }
  .contact-intro { margin: 0 0 1.1rem; color: var(--wood-dark); }
  .contact-row {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.6rem;
  }
  .contact-email {
    font-family: "Fraunces", serif;
    font-weight: 700;
    font-size: 1.1rem;
    color: var(--crimson);
    overflow-wrap: anywhere;
  }
  .contact-email:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; border-radius: 4px; }
  .contact-copy { padding: 0.45rem 1rem; font-size: 0.9rem; }
  .contact-copied { min-height: 1.2em; margin: 0.7rem 0 0; font-size: 0.82rem; color: var(--wood); }

  /* Fenêtre Feuille éditeur (#publisherModal) : même principe que Contact,
     plus large pour l'image A4 paysage ; défile si l'écran est trop bas. */
  .publisher-overlay {
    position: fixed;
    inset: 0;
    background: rgba(59, 42, 26, 0.72);
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem 1rem;
    overflow-y: auto;
  }
  .publisher-content {
    position: relative;
    /* Largeur limitée aussi par la hauteur de l'écran (image A4 : 1,414 de
       large pour 1 de haut ; ~18rem pour le titre, les boutons et les
       marges), pour que les boutons restent visibles sans défiler. */
    width: min(94vw, 920px, max(480px, calc((100vh - 18rem) * 1.414 + 3.6rem)));
    max-height: 100%;
    overflow-y: auto;
    background: var(--parchment);
    border: 6px solid var(--wood);
    border-radius: var(--panel-radius);
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.4);
    padding: 1.6rem 1.6rem 1.3rem;
    text-align: center;
  }
  .publisher-content h2 { color: var(--crimson); font-size: 1.4rem; margin: 0 2rem 0.4rem; }
  .publisher-close {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    width: 2rem;
    height: 2rem;
    padding: 0;
    line-height: 1;
    border-radius: 50%;
    background: var(--wood);
    box-shadow: none;
  }
  .publisher-intro { margin: 0 0 1rem; color: var(--wood-dark); }
  /* L'image : cliquable (agrandir dans un onglet). */
  .publisher-preview {
    display: block;
    border: 3px solid var(--wood-light);
    border-radius: 10px;
    overflow: hidden;
    background: #fff9ea;
    box-shadow: 0 4px 12px rgba(59, 42, 26, 0.25);
    cursor: zoom-in;
  }
  .publisher-preview img { display: block; width: 100%; height: auto; }
  .publisher-preview:focus-visible { outline: 3px solid var(--gold); outline-offset: 3px; }
  .publisher-actions {
    display: flex;
    justify-content: center;
    flex-wrap: wrap;
    gap: 0.7rem;
    margin-top: 1.1rem;
  }
  /* Des liens <a> (téléchargement, onglet) habillés comme les boutons. */
  .publisher-button {
    display: inline-block;
    font-family: "Nunito", sans-serif;
    font-weight: 800;
    font-size: 0.95rem;
    text-decoration: none;
    border-radius: 12px;
    padding: 0.7rem 1.2rem;
    background: linear-gradient(180deg, #d94b4b, var(--crimson));
    color: #fff6e2;
    box-shadow: 0 3px 0 #5c1c1c;
    transition: transform 0.08s ease;
  }
  .publisher-button.is-secondary {
    background: linear-gradient(180deg, #fff9ea, #fdeccb);
    color: var(--wood-dark);
    box-shadow: 0 3px 0 var(--wood-light);
  }
  .publisher-button:hover { filter: brightness(1.08); }
  .publisher-button:active { transform: translateY(2px); box-shadow: 0 1px 0 #5c1c1c; }
  .publisher-button.is-secondary:active { box-shadow: 0 1px 0 var(--wood-light); }
  .publisher-button:focus-visible { outline: 3px solid var(--gold); outline-offset: 2px; }
  .publisher-contact { margin: 0.9rem 0 0; font-size: 0.85rem; color: var(--wood); }
  .publisher-contact a { color: var(--crimson); font-weight: 700; }
  @media (max-width: 600px) {
    .publisher-overlay { padding: 1rem 0.5rem; }
    .publisher-content { padding: 1.3rem 0.9rem 1rem; border-width: 4px; }
    .publisher-content h2 { font-size: 1.2rem; }
    .publisher-actions { flex-direction: column; align-items: stretch; }
  }

  /* Avis de fin de partie (#feedbackModal) : même principe que les autres
     fenêtres (fond sombre, parchemin, croix), en tête le message de
     victoire du plateau. */
  .feedback-overlay {
    position: fixed;
    inset: 0;
    background: rgba(59, 42, 26, 0.72);
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 1.5rem 1rem;
  }
  .feedback-content {
    position: relative;
    width: min(94vw, 560px);
    max-height: 92vh;
    overflow-y: auto;
    background: var(--parchment);
    border: 6px solid var(--wood);
    border-radius: var(--panel-radius);
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.4);
    padding: 1.5rem 1.5rem 1.2rem;
  }
  .feedback-close {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    width: 2rem;
    height: 2rem;
    padding: 0;
    line-height: 1;
    border-radius: 50%;
    background: var(--wood);
    box-shadow: none;
  }
  .feedback-victory {
    margin: 0 2rem 0.8rem;
    text-align: center;
    color: var(--crimson);
    font-size: 1.45rem;
  }
  .feedback-intro { margin: 0 0 1rem; text-align: center; color: var(--wood-dark); font-style: italic; }
  .feedback-form[hidden], .feedback-thanks[hidden] { display: none; }
  .feedback-field { display: block; margin: 0 0 0.8rem; }
  .feedback-field > span { display: block; margin: 0 0 0.25rem; font-weight: 800; color: var(--wood-dark); }
  .feedback-field textarea {
    width: 100%;
    box-sizing: border-box;
    min-height: 3.6rem;
    resize: vertical;
    padding: 0.5rem 0.65rem;
    border: 2px solid var(--wood-light);
    border-radius: 10px;
    background: #fffaf0;
    color: var(--ink);
    font: inherit;
  }
  .feedback-field textarea:focus-visible { outline: 3px solid var(--gold); outline-offset: 1px; }
  .feedback-choice {
    margin: 0.2rem 0 0.6rem;
    padding: 0.6rem 0.8rem 0.7rem;
    border: 2px solid var(--wood-light);
    border-radius: 10px;
  }
  .feedback-choice legend { padding: 0 0.3rem; font-weight: 800; color: var(--wood-dark); }
  .feedback-choice label { display: inline-flex; align-items: center; gap: 0.3rem; margin: 0.3rem 1.1rem 0 0; cursor: pointer; }
  .feedback-choice input { accent-color: var(--crimson); width: 1.1rem; height: 1.1rem; }
  .feedback-status { min-height: 1.2em; margin: 0.2rem 0 0.4rem; color: var(--crimson); font-weight: 700; font-size: 0.9rem; }
  .feedback-actions { display: flex; justify-content: flex-end; flex-wrap: wrap; gap: 0.6rem; }
  .feedback-thanks { text-align: center; padding: 0.8rem 0 0.4rem; }
  .feedback-thanks p { font-size: 1.15rem; font-weight: 800; color: var(--wood-dark); margin: 0 0 1rem; }

  /* Onglet « Jouer au prototype » posé sur le bord supérieur du cadre des
     parties (#lobby), comme l'onglet d'un classeur : même bois que la
     bordure, collé à elle (bottom: 100% + l'épaisseur de la bordure), pour
     qu'on lise qu'il désigne ce cadre. Dans #lobby, il disparaît avec lui. */
  #lobby { position: relative; margin-top: 2.2rem; }
  .lobby-tab {
    position: absolute;
    left: 50%;
    bottom: 100%;
    margin: 0 0 6px; /* = épaisseur de la bordure de .panel */
    transform: translateX(-50%);
    padding: 0.4rem 1.3rem 0.35rem;
    border-radius: 14px 14px 0 0;
    background: var(--wood);
    color: #fff6e2;
    font-family: "Fraunces", serif;
    font-weight: 700;
    font-size: 1.05rem;
    white-space: nowrap;
    box-shadow: inset 0 2px 0 rgba(255, 246, 226, 0.18), 0 -4px 10px rgba(59, 42, 26, 0.12);
  }

  /* Overlay des règles : même principe que le zoom sur une carte (voir
     .card-zoom-overlay), plus large et scrollable pour du texte long. */
  .rules-overlay {
    position: fixed;
    inset: 0;
    background: rgba(59, 42, 26, 0.72);
    z-index: 2000;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 2rem 1rem;
  }
  .rules-content {
    position: relative;
    background: var(--parchment);
    border: 6px solid var(--wood);
    border-radius: var(--panel-radius);
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.4);
    padding: 1.8rem 2rem;
    max-width: min(90vw, 560px);
    max-height: 85vh;
    overflow-y: auto;
    text-align: left;
  }
  .rules-content h2 {
    font-size: 1.5rem;
    color: var(--crimson);
    margin: 0 0 1rem;
    text-align: center;
  }
  .rules-content h3 {
    font-size: 1.05rem;
    color: var(--wood-dark);
    margin: 1.1rem 0 0.3rem;
  }
  .rules-content p, .rules-content ul { margin: 0.3rem 0; line-height: 1.45; }
  .rules-content ul { padding-left: 1.2rem; }
  .rules-close {
    position: absolute;
    top: 0.5rem;
    right: 0.5rem;
    width: 2rem;
    height: 2rem;
    padding: 0;
    line-height: 1;
    border-radius: 50%;
    background: var(--wood);
    box-shadow: none;
  }


  /* Cercle de domination, dans le popup des règles : l'image remplace
     l'ancien schéma en flèches, avec ce texte en repli si elle ne charge pas
     (voir setupRulesDominationImage dans app.js). */
  .rules-image { text-align: center; margin: 0.6rem 0; }
  .rules-image img { max-width: 100%; border-radius: 10px; }
  /* Plusieurs images d'une même section côte à côte (ex. les 3 coffres),
     chacune prenant un tiers de la largeur plutôt que de s'empiler. */
  .rules-image-row { display: flex; justify-content: center; gap: 0.6rem; }
  .rules-image-row img { max-width: calc(33.33% - 0.4rem); }