/* =============================================================================
   MystMUD — interface à onglets
   =============================================================================

   En temps normal, la page tient en trois lignes :

     +---------------------------------------------+
     |   barre d'état + bouton de rangement (⚙)     |
     +---------------------------------------------+
     |  [onglets du haut]                          |
     |        panneau du haut                      |
     +---------------------------------------------+
     |  [onglets du bas]     (s'il en reste)       |
     |        panneau du bas                       |
     +---------------------------------------------+
     |            contrôles du bas                 |
     +---------------------------------------------+

   Aucune colonne latérale : la réserve d'onglets ne paraît qu'en mode
   rangement, et par-dessus.

   ========================================================================== */

:root {
    --app-height: 100vh;
    --bas-part: 38%;

    --fond: #0d0f12;
    --fond-panneau: #14181d;
    --fond-relief: #1c2128;
    --bordure: #2a323c;
    --texte: #c8d0d8;
    --accent: #1abc9c;
}

* { box-sizing: border-box; margin: 0; padding: 0; }

body {
    background: var(--fond);
    color: var(--texte);
    font-family: 'VT323', 'Courier New', monospace;
    font-size: 20px;
    overflow: hidden;
}

.app {
    display: grid;
    grid-template-rows: auto 1fr auto;
    height: var(--app-height);
    width: 100vw;
    position: relative;
}

/* --- BARRE D'ÉTAT -------------------------------------------------------- */

.header-bar {
    display: flex;
    flex-direction: column;
    gap: 4px;
    padding: 4px 8px;
    background: var(--fond-relief);
    border-bottom: 1px solid var(--bordure);
}

.header-ligne {
    display: flex;
    align-items: center;
    gap: 10px;
}

/* La ligne de l'adversaire : absente hors combat, d'où le [hidden] qui doit
   l'emporter sur le display:flex. */
.ennemi-ligne {
    display: flex;
    align-items: center;
    gap: 8px;
}

.ennemi-ligne[hidden] { display: none; }

.ennemi-nom {
    color: #e74c3c;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 40%;
}

/* Verte, puis jaune, puis rouge : on lit l'état de l'adversaire à la couleur
   avant même d'avoir lu le chiffre. */
.fill-ennemi { background: #27ae60; }
.fill-ennemi.blesse { background: #f1c40f; }
.fill-ennemi.mourant { background: #c0392b; }

.player-name { color: var(--accent); white-space: nowrap; }
.level-badge { color: #f1c40f; white-space: nowrap; }

.vitals { display: flex; flex: 1; gap: 8px; min-width: 0; }

.gauge {
    position: relative;
    flex: 1;
    min-width: 0;
    height: 20px;
    background: #000;
    border: 1px solid var(--bordure);
    overflow: hidden;
}

.gauge-fill { height: 100%; width: 0; transition: width .25s ease; }
.fill-hp { background: #c0392b; }
.fill-mana { background: #2980b9; }
.fill-move { background: #b7950b; }

.gauge-text {
    position: absolute;
    inset: 0;
    text-align: center;
    line-height: 18px;
    color: #fff;
    text-shadow: 1px 1px 2px #000;
}

.gauge-low .gauge-fill { animation: pulse 1s infinite; }
@keyframes pulse { 50% { opacity: .45; } }
@media (prefers-reduced-motion: reduce) {
    .gauge-low .gauge-fill { animation: none; }
    .gauge-fill { transition: none; }
}

/* Les pastilles d'effets (poison, lumière, caractéristique renforcée) :
   absentes de la mise en page tant qu'aucun effet n'agit sur le personnage,
   plutôt qu'une ligne vide qui réserverait sa hauteur pour rien. */
.effets-ligne {
    display: flex;
    flex-wrap: wrap;
    gap: 4px;
}
.effets-ligne:empty { display: none; }

.effet-badge {
    font-size: 14px;
    line-height: 1.4;
    padding: 0 6px;
    border: 1px solid var(--bordure);
    border-radius: 3px;
    background: var(--fond-relief);
    white-space: nowrap;
}
.effet-poison { color: #e74c3c; border-color: #e74c3c; }
.effet-light  { color: #f1c40f; border-color: #f1c40f; }
.effet-boost  { color: #1abc9c; border-color: #1abc9c; }

.btn-editer {
    flex: 0 0 auto;
    background: #0d0f12;
    color: #7f8c8d;
    border: 1px solid var(--bordure);
    font-family: inherit;
    font-size: 19px;
    line-height: 1;
    padding: 4px 8px;
    cursor: pointer;
}
.btn-editer:hover { color: var(--accent); border-color: var(--accent); }
.app.rangement .btn-editer { color: #f1c40f; border-color: #f1c40f; }

/* --- LES PANNEAUX -------------------------------------------------------- */

.scene { display: flex; flex-direction: column; min-height: 0; }

.panneau { display: flex; flex-direction: column; min-height: 0; background: var(--fond-panneau); position: relative; }

/* Le bouton de retour en bas du fil. Il flotte au-dessus du panneau, en bas à
   droite, et ne paraît que là où il sert (voir majBoutonsBas). */
.aller-en-bas {
    display: none;
    position: absolute;
    right: 10px;
    bottom: 8px;
    z-index: 10;
    width: 34px;
    height: 34px;
    padding: 0;
    background: var(--fond-relief);
    color: var(--texte);
    border: 1px solid var(--bordure);
    border-radius: 50%;
    font-family: inherit;
    font-size: 20px;
    line-height: 1;
    cursor: pointer;
    opacity: .55;
}
.aller-en-bas.visible { display: block; }
.aller-en-bas:hover { opacity: 1; color: #fff; border-color: var(--accent); }

/* Le vide posé sous le fil pour que la barre de salle puisse monter tout en
   haut du panneau. Pur artifice d'affichage : il ne fait pas partie de
   l'historique, et se recalcule à chaque repeinture (voir poseLeDefilement). */
.souffle { pointer-events: none; }
#panneau-haut { flex: 1; }

/* Le panneau du bas n'existe que s'il lui reste un onglet ouvert. */
#panneau-bas, .separateur-h { display: none; }
.app.avec-bas #panneau-bas { display: flex; flex: 0 0 var(--bas-part); }
.app.avec-bas .separateur-h { display: block; }

.panneau-corps {
    flex: 1;
    overflow: auto;
    padding: 8px;
    white-space: pre-wrap;
    word-break: break-word;

    /* Serré, comme dans le client d'origine : l'art ASCII de la bannière et
       les cadres du serveur se lisent comme un bloc, pas comme un poème. */
    line-height: 0.85;
}

/* --- LA BARRE D'ONGLETS D'UN PANNEAU ------------------------------------- */
/*
   L'onglet actif s'écrit en toutes lettres, les autres se réduisent à leur
   emoji : on sait ce qu'on regarde, on n'a besoin de lire que ce vers quoi on
   peut aller.
*/

.panneau-barre {
    display: flex;
    align-items: stretch;
    gap: 2px;
    padding: 2px 4px;
    min-height: 28px;
    background: var(--fond-relief);
    border-bottom: 1px solid var(--bordure);
    overflow-x: auto;
    scrollbar-width: none;
}
.panneau-barre::-webkit-scrollbar { display: none; }

.mini-onglet {
    display: flex;
    align-items: center;
    gap: 5px;
    padding: 2px 8px;
    background: transparent;
    color: #7f8c8d;
    border: none;
    border-bottom: 2px solid transparent;
    font-family: inherit;
    font-size: 18px;
    line-height: 1.4;
    cursor: pointer;
    white-space: nowrap;
    touch-action: none;
}

.mini-onglet:hover { color: var(--texte); }

.mini-onglet.actif {
    color: #fff;
    border-bottom-color: var(--accent);
    letter-spacing: 1px;
    text-transform: uppercase;
}

.mini-onglet .texte { display: none; }
.mini-onglet.actif .texte { display: inline; }

.mini-onglet .pastille { color: var(--accent); font-size: 20px; line-height: 1; }
.mini-onglet.actif .pastille { visibility: hidden; }

/* La croix de fermeture n'apparaît qu'en mode rangement. */
.mini-onglet .croix { display: none; color: #e74c3c; font-size: 17px; padding-left: 2px; }
.app.rangement .mini-onglet .croix { display: inline; }
.app.rangement .mini-onglet { border: 1px dashed var(--bordure); cursor: grab; }
.app.rangement .mini-onglet.actif { border-color: var(--accent); }

/* --- SÉPARATEUR ---------------------------------------------------------- */

.separateur-h {
    height: 8px;
    cursor: row-resize;
    background: var(--bordure);
    flex: 0 0 auto;
    touch-action: none;
}
.separateur-h:hover { background: var(--accent); }

/* --- LA RÉSERVE (mode rangement) ----------------------------------------- */

.reserve {
    display: none;
    position: absolute;
    top: 0;
    right: 0;
    bottom: 0;
    width: 190px;
    z-index: 20;
    flex-direction: column;
    background: #10141a;
    border-left: 2px solid #f1c40f;
    box-shadow: -8px 0 20px rgba(0, 0, 0, .5);
}
.app.rangement .reserve { display: flex; }

.reserve-titre {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 6px;
    padding: 6px 8px;
    color: #f1c40f;
    border-bottom: 1px solid var(--bordure);
}

.reserve-titre button {
    background: #0d0f12;
    color: #7f8c8d;
    border: 1px solid var(--bordure);
    font-family: inherit;
    font-size: 17px;
    cursor: pointer;
    padding: 2px 8px;
}
.reserve-titre button:hover { color: var(--accent); border-color: var(--accent); }

.reserve-liste { flex: 1; overflow-y: auto; padding: 6px; }

.reserve-liste .mini-onglet {
    display: flex;
    width: 100%;
    margin-bottom: 4px;
    padding: 7px 8px;
    background: #0d0f12;
    border: 1px dashed var(--bordure);
    color: var(--texte);
    text-transform: none;
    letter-spacing: 0;
}
/* Dans la réserve, tous les noms se lisent : c'est un catalogue. */
.reserve-liste .mini-onglet .texte { display: inline; }
.reserve-liste .mini-onglet .croix { display: none !important; }

.reserve-aide { padding: 8px; color: #7f8c8d; font-size: 16px; line-height: 1.15; }

.reserve-options { padding: 8px; border-top: 1px solid var(--bordure); }

.option-ligne {
    display: flex;
    align-items: center;
    gap: 8px;
    color: var(--texte);
    font-size: 15px;
    line-height: 1.25;
    cursor: pointer;
}
.option-ligne input[type="checkbox"] {
    flex: 0 0 auto;
    width: 16px;
    height: 16px;
    accent-color: var(--accent);
}

/* Zone survolée pendant un glissement. */
.zone-visee { outline: 2px dashed var(--accent); outline-offset: -2px; }

/* Pendant un glissement, la barre du bas se montre MÊME VIDE : sinon un
   panneau qu'on vient de vider disparaît avec sa barre, et l'onglet qu'on tient
   n'a plus nulle part où redescendre. Seule la barre paraît — le corps du
   panneau attend d'avoir quelque chose à montrer. */
.app.glisse:not(.avec-bas) #panneau-bas { display: flex; flex: 0 0 auto; }
.app.glisse:not(.avec-bas) #panneau-bas .panneau-corps { display: none; }
.app.glisse:not(.avec-bas) #panneau-bas .panneau-barre { opacity: .75; }

/* On ne sélectionne pas le nom d'un onglet qu'on est en train de déplacer. */
.mini-onglet { user-select: none; -webkit-user-select: none; }

/* Le fantôme qui suit le doigt. */
.fantome {
    position: fixed;
    z-index: 100;
    pointer-events: none;
    padding: 4px 10px;
    background: var(--fond-relief);
    border: 1px solid var(--accent);
    color: #fff;
    font-family: inherit;
    font-size: 18px;
    opacity: .9;
}

/* --- CONTRÔLES DU BAS ---------------------------------------------------- */

.controls-panel {
    background: var(--fond-relief);
    border-top: 1px solid var(--bordure);
    padding: 6px;
    position: relative;
}

.cmd-hint { display: none; color: #f1c40f; font-size: 17px; padding: 0 2px 4px; }
.cmd-hint.visible { display: block; }

/* La barre de sorts : un bouton par FAMILLE (voir dessineBarreSorts), son
   emoji et sa couleur posés en ligne. Cachée hors combat, et quand on ne
   connaît aucun sort. Le clic ouvre #spell-family-menu, ci-dessous. */
.spell-bar { display: flex; gap: 6px; margin-bottom: 6px; }
.spell-bar[hidden] { display: none; }

.spell-btn {
    flex: 1;
    min-width: 0;
    padding: 6px 4px;
    background: #0d0f12;
    border: 1px solid currentColor;
    border-radius: 6px;
    font-family: inherit;
    font-size: 22px;
    line-height: 1.1;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.spell-btn:hover { background: var(--fond-relief); }
.spell-btn.sort-cher { opacity: .4; }
/* La famille dont le sous-menu est ouvert se signale par son cadre, comme le
   mode de saisie en cours (voir .mode-btn.courant). */
.spell-btn.courant { background: var(--fond-relief); box-shadow: 0 0 0 1px currentColor; }

.action-buttons { display: flex; gap: 6px; }

.action-btn {
    flex: 1;
    min-width: 0;
    padding: 8px 4px;
    background: #0d0f12;
    color: var(--texte);
    border: 1px solid var(--bordure);
    border-left: 3px solid var(--accent);
    font-family: inherit;
    font-size: 19px;
    cursor: pointer;
    white-space: nowrap;
    overflow: hidden;
}
.action-btn:hover { border-color: var(--accent); color: #fff; }
.btn-plus { flex: 0 0 44px; }
.btn-plus.ouvert { border-color: #f1c40f; color: #f1c40f; }

.command-tree {
    display: none;
    position: absolute;
    left: 6px;
    right: 6px;
    bottom: 100%;
    background: var(--fond-panneau);
    border: 1px solid var(--accent);
    padding: 8px;
    max-height: 55vh;
    overflow-y: auto;
    z-index: 30;
}
.command-tree.ouvert { display: block; }

.tree-titre { color: #f1c40f; padding-bottom: 6px; }
.tree-grille { display: grid; grid-template-columns: repeat(auto-fill, minmax(150px, 1fr)); gap: 6px; }

.tree-btn {
    padding: 8px;
    background: #0d0f12;
    color: var(--texte);
    border: 1px solid var(--bordure);
    border-left: 3px solid #3498db;
    font-family: inherit;
    font-size: 19px;
    cursor: pointer;
    text-align: left;
}
.tree-btn:hover { border-color: var(--accent); }
.tree-btn.categorie { color: var(--accent); }
.tree-btn.retour { color: #f1c40f; }

/* Une entrée qui informe et n'agit pas : elle se lit, elle ne se clique pas. */
.tree-btn.tree-btn-inerte { cursor: default; opacity: 0.85; }
.tree-btn.tree-btn-inerte:hover { border-color: var(--bordure); }

/* LE MENU DU MODE DE SAISIE — mêmes règles de position que l'arbre des
   commandes : posé par-dessus le jeu, ancré au-dessus du champ. Les deux
   occupent la même place et ne s'ouvrent jamais ensemble (voir ouvreMenuMode
   et ouvreArbre dans client.js). */
.mode-menu {
    display: none;
    position: absolute;
    left: 6px;
    right: 6px;
    bottom: 100%;
    background: var(--fond-panneau);
    border: 1px solid var(--accent);
    padding: 8px;
    max-height: 55vh;
    overflow-y: auto;
    z-index: 30;
}
.mode-menu.ouvert { display: block; }

.mode-liste { display: grid; grid-template-columns: repeat(auto-fill, minmax(190px, 1fr)); gap: 6px; }

/* Un mode se lit en toutes lettres ici : c'est le seul endroit où l'on
   découvre ce que fait le bouton, qui n'a plus ensuite que son emoji. */
.mode-btn {
    padding: 8px;
    background: #0d0f12;
    color: var(--texte);
    border: 1px solid var(--bordure);
    border-left: 3px solid #f1c40f;
    font-family: inherit;
    font-size: 19px;
    cursor: pointer;
    text-align: left;
}
.mode-btn:hover { border-color: var(--accent); }
/* Le mode en cours se signale par son cadre, pas par sa couleur : la couleur
   est déjà prise, elle dit de quel canal il s'agit. */
.mode-btn.courant { border-color: var(--accent); background: var(--fond-relief); }

.input-container { display: flex; gap: 6px; margin-top: 6px; }

/* Le bouton de mode ne prend que sa largeur, comme la croix : tout ce qu'il
   prendrait de plus serait retiré à la commande qu'on tape. Sa couleur est
   celle du canal (classes .color-*, posées par majBoutonMode) ; en mode
   ordinaire il reste gris, comme un bouton qui ne fait rien de particulier. */
#btn-mode {
    flex: 0 0 auto;
    padding: 8px 10px;
    background: #0d0f12;
    color: #7f8c8d;
    border: 1px solid var(--bordure);
    font-family: inherit;
    font-size: 20px;
    cursor: pointer;
}
#btn-mode:hover { border-color: var(--accent); }
/* Un canal actif se voit : le cadre prend la couleur héritée du texte, donc
   celle du canal lui-même. */
#btn-mode.actif { border-color: currentColor; }

#cmd-input {
    flex: 1;
    min-width: 0;
    padding: 8px;
    background: #000;
    color: var(--accent);
    border: 1px solid var(--bordure);
    font-family: inherit;
    font-size: 20px;
}
#cmd-input:focus { outline: none; border-color: var(--accent); }

/* La dernière commande grisée dans le champ (voir majPlaceholderHistorique) :
   même teinte que la croix inactive, pour qu'on la lise comme "posée là",
   pas comme un texte qu'on aurait tapé. */
#cmd-input::placeholder { color: #7f8c8d; opacity: 1; }

#btn-ok, #btn-clear {
    padding: 8px 16px;
    background: #0d0f12;
    color: var(--texte);
    border: 1px solid var(--bordure);
    font-family: inherit;
    font-size: 20px;
    cursor: pointer;
}

/* La croix ne prend que sa largeur, et s'efface tant qu'il n'y a rien à
   effacer : un bouton sans effet ne doit pas s'annoncer comme les autres. */
#btn-clear {
    flex: 0 0 auto;
    padding: 8px 12px;
    color: #7f8c8d;
}
#btn-clear:hover { color: #e74c3c; border-color: #e74c3c; }
#btn-clear.vide { opacity: .35; }

/* --- COULEURS DU JEU ----------------------------------------------------- */

.color-red { color: #e74c3c; }
.color-green { color: #2ecc71; }
.color-yellow { color: #f1c40f; }
.color-blue { color: #3498db; }
/* Le rose n'est employé que par ce qui m'est adressé personnellement (tell) :
   c'est ce qui le rend repérable du coin de l'œil dans un fil qui défile. */
.color-magenta { color: #e984c8; }
.color-cyan { color: #1abc9c; }
.color-white { color: #ffffff; }

/* La gamme VIVE : les mêmes couleurs poussées à fond, celles d'un terminal en
   mode « bright ». Réservée aux auras. */
.color-red-vif { color: #ff4d4d; }
.color-green-vif { color: #00ff00; }
.color-yellow-vif { color: #ffff00; }
.color-blue-vif { color: #5c5cff; }
.color-magenta-vif { color: #ff00ff; }
.color-cyan-vif { color: #00ffff; }
.color-white-vif { color: #ffffff; }

/* Sortie fermée à clé : [🔒soupirail]
   Le cadenas est posé par le JS avec le sélecteur de présentation texte ;
   font-variant-emoji le redit au navigateur, seul moyen sur certains systèmes
   d'obtenir le glyphe au trait plutôt que l'émoji en couleurs. Là où ni l'un ni
   l'autre n'est compris, le cadenas s'affiche en couleurs : c'est moins joli,
   mais ça reste un cadenas, et la porte reste lisible comme fermée. */
.exit-locked {
    color: #e74c3c;
    opacity: .75;
    text-decoration: none;
    font-variant-emoji: text;
}
.exit-locked:hover { opacity: 1; }

/* La barre qui sépare deux salles dans le fil des événements. Le nom du lieu
   posé sur un trait : on sait ce qu'on quitte, et ce qu'on lit en dessous. */
.marque-salle {
    display: flex;
    align-items: center;
    gap: 8px;
    margin: 8px 0 4px;
    color: #7f8c8d;
    font-size: 17px;
    line-height: 1;
    text-transform: uppercase;
    letter-spacing: 1px;
    white-space: nowrap;
}
.marque-salle::before,
.marque-salle::after {
    content: "";
    flex: 1;
    height: 1px;
    background: var(--bordure);
}
/* La toute première barre du fil n'a rien à séparer : elle ouvre. */
.marque-salle:first-child { margin-top: 0; }

/* La respiration entre deux rounds de combat : une VRAIE ligne vide, de la
   hauteur d'une ligne de texte, pas un demi-interligne qu'on ne remarque pas.
   C'est elle qui donne son rythme au duel — chaque tour se lit comme un
   paragraphe au lieu de se fondre dans le bloc précédent. */
.round-vide { height: 1.1em; }

/* CE QUE LA JAUGE DIT DÉJÀ (voir {(}…{)} dans couleursANSI, telnet.go).
   Le serveur écrit toujours « il lui reste 43 % » ; il n'y a qu'ici, dans le
   bandeau de combat, qu'on le retire — la barre de vie ennemie est en haut de
   l'écran, en permanence, et la répéter à chaque coup allonge chaque ligne
   pour ne rien apprendre. Le flux, les événements et le terminal le gardent :
   eux n'ont pas de jauge sous les yeux. */
.ligne-combat .detail-jauge { display: none; }

/* Les messages respirent un peu plus que l'art ASCII : ce sont des phrases. */
.message { padding: 1px 0; line-height: 1.1; }
.message-say { color: #1abc9c; }
.message-tell { color: #e984c8; }
.message-shout { color: #e74c3c; }
.message-group { color: #2ecc71; }
.message-move { color: #f1c40f; }
.message-combat { color: #e67e22; }
.message-system { color: #9b59b6; }
.message-info { color: var(--texte); }

/* L'invite du flux : discrète, mais elle rythme la lecture comme au terminal. */
.flux-invite { color: #7f8c8d; padding-bottom: 4px; }

.erreur { color: #e74c3c; text-align: center; padding: 20px; }

/* --- LE COMBAT, DANS SON ONGLET ------------------------------------------ */

/* L'onglet ne porte plus que les échanges : la vie de l'adversaire est montée
   dans la barre d'état (voir .ennemi-ligne), où on la voit sans la chercher. */
.combat-vide { color: #7f8c8d; }

/* --- ÉCRANS ÉTROITS ------------------------------------------------------ */

@media (max-width: 760px) {
    body { font-size: 17px; }
    .header-bar { gap: 6px; padding: 3px 5px; }
    .panneau-corps { padding: 6px; }
    .reserve { width: 165px; }
    .action-btn, .tree-btn, .mode-btn, #cmd-input, #btn-ok, #btn-mode { font-size: 18px; }
}
