/* Drive Forever — tableau de bord et commandes.
   Le jeu lui-même est dessiné sur le canvas ; tout ce qui est ici est l'habillage
   autour : compteurs, jauges, état des pièces, commandes tactiles.
   Univers volontairement sombre et unique, donc les couleurs sont fixées. */

   :root {
    color-scheme: dark;
    --panel: rgba(16, 20, 18, 0.62);
    --text: #f2efe6;
    --accent: #ffd27a;
    --warn: #ff9a6c;
    /* La taille de l'habillage, réglée dans le menu de la roue crantée. */
    --ui: 1;
  }
  
  /* Le zoom de l'interface. `zoom` plutôt qu'une mise à l'échelle : il refait la
     mise en page au lieu d'étirer une image, donc le texte reste net, les
     panneaux gardent leurs coins et les boutons gardent leur vraie surface
     tactile. Il se pose sur chaque calque de l'habillage, jamais sur `body` :
     le canvas du jeu doit garder un pixel pour un pixel d'écran, sinon le monde
     serait peint trop petit puis étiré, et deviendrait flou.
     Les manches tactiles en sont exclus exprès : ils naissent à l'endroit exact
     du contact, donc leurs coordonnées sont celles de l'écran. */
  #hud,
  #corner,
  #action-hint,
  #help,
  #tip,
  #touch-buttons,
  #gameover,
  #inventory { zoom: var(--ui); }
  
  * { box-sizing: border-box; }
  
  html, body {
    margin: 0;
    height: 100%;
    overflow: hidden;
    background: #223425;
    color: var(--text);
    font-family: ui-sans-serif, system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
    -webkit-user-select: none;
    user-select: none;
    -webkit-tap-highlight-color: transparent;
  }
  
  #game {
    position: fixed;
    inset: 0;
    display: block;
    width: 100%;
    height: 100%;
    touch-action: none;
  }
  
  /* --- Tableau de bord --- */
  /* Colonne de gauche : compteurs, état de surface, puis les jauges. */
  #hud {
    position: fixed;
    top: max(12px, env(safe-area-inset-top));
    left: max(12px, env(safe-area-inset-left));
    display: flex;
    flex-direction: column;
    align-items: flex-start;
    gap: 8px;
    pointer-events: none;
  }
  
  #tiles { display: flex; gap: 8px; }
  
  .tile {
    background: var(--panel);
    backdrop-filter: blur(6px);
    border-radius: 10px;
    padding: 8px 12px;
    line-height: 1.15;
  }
  
  .tile .label {
    display: block;
    font-size: 10px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    opacity: 0.65;
  }
  
  .tile .value {
    font-variant-numeric: tabular-nums;
    font-size: 22px;
    font-weight: 600;
  }
  
  .tile .unit {
    font-size: 11px;
    opacity: 0.7;
    margin-left: 2px;
  }
  
  .tile.hidden { display: none; }
  
  #pills { display: flex; gap: 6px; flex-wrap: wrap; }
  
  #surface, #biome, #weather {
    font-size: 12px;
    padding: 6px 10px;
    border-radius: 999px;
    background: var(--panel);
    color: var(--accent);
  }
  
  #surface.warn, #weather.warn { color: var(--warn); }
  
  /* La flèche du vent tourne, donc elle a besoin d'être un bloc à elle. Et
     `display: flex` l'emporterait sur l'attribut `hidden` : par temps clair, la
     pastille doit disparaître pour de bon. */
  #weather { display: flex; align-items: center; gap: 6px; }
  #weather[hidden] { display: none; }
  
  #wind-arrow {
    display: inline-block;
    line-height: 1;
    transition: transform 220ms linear;
  }
  
  /* Un souffle ne mérite pas qu'on le montre ; une bourrasque, si. */
  #weather[data-wind="calme"] #wind-arrow { opacity: 0.35; }
  #weather[data-wind="fort"] #wind-arrow { font-weight: 700; }
  
  /* Le temps se reconnaît à sa couleur avant de se lire, comme le pays. */
  #weather[data-kind="rain"] { color: #9ec4e0; }
  #weather[data-kind="snowfall"] { color: #e7f1f7; }
  #weather[data-kind="fog"] { color: #c3cbd2; }
  #weather[data-kind="sand"] { color: #e0b878; }
  
  /* Le pays se reconnaît à sa couleur avant de se lire. */
  #biome[data-kind="snow"] { color: #cfe3ee; }
  #biome[data-kind="desert"] { color: #e8c279; }
  #biome[data-kind="plain"] { color: #9dc48f; }
  
  /* --- Jauges, en deux groupes --- */
  #gauges { display: flex; flex-direction: column; gap: 8px; }
  
  .gauge-group {
    background: var(--panel);
    backdrop-filter: blur(6px);
    border-radius: 10px;
    padding: 8px 10px 9px;
    display: flex;
    flex-direction: column;
    gap: 5px;
    width: 172px;
  }
  
  .group-title {
    margin: 0 0 1px;
    font-size: 9px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    opacity: 0.55;
  }
  
  .gauge { display: flex; align-items: center; gap: 8px; }
  
  .gauge-label {
    font-size: 10px;
    width: 58px;
    flex: none;
    opacity: 0.8;
  }
  
  .track {
    flex: 1;
    min-width: 0;
    height: 7px;
    border-radius: 999px;
    background: rgba(242, 239, 230, 0.14);
    overflow: hidden;
    display: flex;
  }
  
  .fill {
    height: 100%;
    width: 0;
    transition: width 0.25s ease;
    background: var(--tone, #7fb48a);
  }
  
  /* Le chiffre à droite d'une jauge : l'autonomie, la température. */
  .gauge-read {
    flex: none;
    width: 40px;
    text-align: right;
    font-size: 9px;
    opacity: 0.75;
    font-variant-numeric: tabular-nums;
  }
  
  /* Zone rouge : le moteur peut casser net à chaque seconde, la jauge clignote
     tant que ça dure. */
  .gauge.danger .gauge-label,
  .gauge.danger .gauge-read { color: var(--warn); opacity: 1; }
  .gauge.danger .track { animation: tempFlash 0.8s infinite; }
  
  @keyframes tempFlash {
    50% { box-shadow: 0 0 0 1px var(--warn) inset; background: rgba(255, 154, 108, 0.4); }
  }
  
  /* La couleur de chaque jauge est posée par le script : la liste des teintes
     vit dans src/items.js, avec les objets. */
  
  /* Une jauge basse se repère sans lire son nom. */
  .gauge[data-level="worn"] .gauge-label { opacity: 1; color: var(--accent); }
  .gauge[data-level="critical"] .gauge-label { opacity: 1; color: var(--warn); }
  .gauge[data-level="critical"] .track { box-shadow: 0 0 0 1px var(--warn) inset; }
  
  /* --- Le coin haut-droit : pièces du véhicule, puis réglages à leur droite --- */
  /* Les deux vivent sur la même ligne, la roue crantée dans le coin : elle ne
     bouge donc pas quand les pièces se rangent, à pied. */
  #corner {
    position: fixed;
    top: max(12px, env(safe-area-inset-top));
    right: max(12px, env(safe-area-inset-right));
    display: flex;
    flex-direction: row;
    align-items: flex-start;
    gap: 6px;
  }
  
  #settings {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 6px;
    /* Le panneau tombe sous la roue crantée sans écarter la ligne du coin. */
    position: relative;
  }
  
  #settings-panel { position: absolute; top: 40px; right: 0; }
  
  #settings-toggle {
    display: flex;
    align-items: center;
    justify-content: center;
    width: 34px;
    height: 34px;
    border: 0;
    border-radius: 999px;
    padding: 0;
    background: var(--panel);
    color: var(--text);
    cursor: pointer;
  }
  
  #settings-toggle svg {
    width: 20px;
    height: 20px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
    transition: color 0.15s ease;
  }
  #settings-toggle:hover svg,
  #settings.open #settings-toggle svg { color: var(--accent); }
  
  #settings-panel {
    width: 268px;
    /* Au plus gros zoom, le panneau ne doit pas déborder par la gauche : la
       largeur est divisée par le zoom pour que son résultat à l'écran tienne. */
    max-width: calc(92vw / var(--ui));
    background: var(--panel);
    backdrop-filter: blur(6px);
    border-radius: 10px;
    padding: 10px 12px;
  }
  
  .settings-title {
    margin: 0 0 6px;
    font-size: 10px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    opacity: 0.65;
  }
  
  .settings-soon {
    margin: 9px 0 0;
    font-size: 12px;
    line-height: 1.35;
    opacity: 0.7;
  }
  
  /* Un réglage : son nom, puis la liste et le bouton qui valide. Rien ne change
     tant qu'on n'a pas validé, pour qu'on puisse parcourir la liste sans voir
     l'écran sauter à chaque cran. */
  .settings-row {
    display: block;
    margin: 0 0 5px;
    font-size: 12px;
    opacity: 0.85;
  }
  
  .settings-act { display: flex; gap: 6px; align-items: stretch; }
  
  .settings-act select {
    flex: 1;
    min-width: 0;
    height: 30px;
    border: 1px solid rgba(242, 239, 230, 0.22);
    border-radius: 8px;
    padding: 0 6px;
    background: rgba(8, 11, 9, 0.5);
    color: var(--text);
    font: inherit;
    font-size: 13px;
  }
  
  .settings-act button {
    border: 0;
    border-radius: 8px;
    padding: 0 11px;
    background: rgba(255, 210, 122, 0.22);
    color: var(--accent);
    font: inherit;
    font-size: 13px;
    cursor: pointer;
  }
  
  .settings-act button:active { background: rgba(255, 210, 122, 0.36); }
  
  .settings-note {
    margin: 7px 0 0;
    font-size: 11px;
    line-height: 1.35;
    opacity: 0.55;
  }
  
  .settings-note:empty { display: none; }
  
  /* Le second réglage se détache du premier par un filet : deux listes collées
     se liraient comme une seule. */
  .settings-note + .settings-row {
    margin-top: 11px;
    padding-top: 10px;
    border-top: 1px solid rgba(242, 239, 230, 0.12);
  }
  
  /* --- Le repère de l'inclinaison --- */
  /* Une mécanique et son indicateur arrivent ensemble : sans cette barre, on ne
     saurait pas si le téléphone répond, ni où est son zéro. */
  #drive-tilt {
    display: flex;
    align-items: center;
    gap: 8px;
    margin-top: 8px;
  }
  
  #drive-tilt[hidden] { display: none; }
  
  #tilt-meter {
    position: relative;
    flex: 1;
    height: 14px;
    border-radius: 999px;
    background: rgba(8, 11, 9, 0.5);
    overflow: hidden;
  }
  
  /* Le trait du milieu : c'est le tout droit. */
  #tilt-meter::before {
    content: '';
    position: absolute;
    left: 50%;
    top: 2px;
    bottom: 2px;
    width: 1px;
    background: rgba(242, 239, 230, 0.3);
  }
  
  #tilt-needle {
    position: absolute;
    top: 2px;
    left: calc(50% - 5px);
    width: 10px;
    height: 10px;
    border-radius: 999px;
    background: var(--accent);
  }
  
  #tilt-zero {
    border: 1px solid rgba(242, 239, 230, 0.22);
    border-radius: 8px;
    padding: 4px 9px;
    background: transparent;
    color: var(--text);
    font: inherit;
    font-size: 11.5px;
    cursor: pointer;
    white-space: nowrap;
  }
  
  #parts {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 6px;
  }
  
  #parts.hidden { display: none; }
  
  #parts-toggle {
    display: none;
    align-items: center;
    gap: 6px;
    border: 0;
    border-radius: 999px;
    padding: 7px 12px;
    background: var(--panel);
    color: var(--text);
    font: inherit;
    font-size: 12px;
    cursor: pointer;
  }
  
  /* La charge se voit sur le compteur de poids : ambre quand la voiture traîne,
     rouge quand elle est bourrée. */
  #weight-tile[data-level="worn"] .value { color: var(--accent); }
  #weight-tile[data-level="critical"] .value { color: var(--warn); }
  
  #parts-toggle[data-level="worn"] { color: var(--accent); }
  #parts-toggle[data-level="critical"] { color: var(--warn); }
  
  #parts-panel {
    display: flex;
    gap: 4px;
    background: var(--panel);
    backdrop-filter: blur(6px);
    border-radius: 10px;
    padding: 8px 10px;
    /* Dix pièces sur un rang tiennent à l'écran d'origine ; grossies d'un cran
       de trop, elles sortiraient par la gauche. Elles passent alors à la ligne,
       dans ce qui reste de largeur une fois le zoom appliqué. */
    flex-wrap: wrap;
    justify-content: flex-end;
    max-width: calc(94vw / var(--ui));
  }
  
  .part {
    width: 42px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 2px;
  }
  
  .part svg {
    width: 30px;
    height: 30px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
    color: #7fb48a;
  }
  
  .part[data-level="worn"] svg { color: var(--accent); }
  .part[data-level="critical"] svg { color: var(--warn); }
  
  .part .ring-bg { stroke: rgba(242, 239, 230, 0.16); stroke-width: 2.2; }
  .part .ring { stroke-width: 2.2; transition: stroke-dashoffset 0.25s ease; }
  .part .glyph { opacity: 0.9; }
  
  .part-name {
    font-size: 8px;
    letter-spacing: 0.04em;
    opacity: 0.6;
    white-space: nowrap;
  }
  
  /* Indication d'action, centrée bas : apparaît quand une action est possible. */
  #action-hint {
    position: fixed;
    left: 50%;
    bottom: calc(54px + env(safe-area-inset-bottom));
    transform: translateX(-50%);
    padding: 8px 16px;
    border-radius: 999px;
    background: var(--panel);
    color: var(--accent);
    font-size: 13px;
    white-space: nowrap;
    opacity: 0;
    transition: opacity 0.18s ease;
    pointer-events: none;
  }
  
  #action-hint.visible { opacity: 1; }
  
  /* --- La bulle d'information au doigt --- */
  /* Ce que la souris lit en survolant, le doigt l'ouvre en touchant. Elle se
     place en pixels d'écran depuis src/tips.js, au-dessus de tout le reste —
     y compris l'inventaire et le double qu'on traîne. */
  #tip {
    position: fixed;
    left: 0;
    top: 0;
    z-index: 50;
    max-width: calc(min(320px, 86vw) / var(--ui));
    padding: 7px 10px;
    border-radius: 9px;
    background: rgba(18, 23, 20, 0.95);
    box-shadow: 0 8px 22px rgba(0, 0, 0, 0.45);
    pointer-events: none;
  }
  
  #tip[hidden] { display: none; }
  
  #tip-text {
    margin: 0;
    font-size: 12.5px;
    line-height: 1.35;
    color: var(--text);
  }
  
  /* Le tableau de bord laisse passer les doigts, pour que le pouce puisse
     conduire à travers lui. Ce qui porte une phrase, lui, doit l'attraper :
     c'est la seule façon de lire au doigt ce que la souris lit au survol. */
  #hud [title] { pointer-events: auto; }
  
  /* Le rappel des commandes : clavier par défaut, une ligne au doigt, et plus
     rien dès que le joueur a touché l'écran — il a compris. */
  #help .pad { display: none; }
  body.touching #help { display: none; }
  
  #help {
    position: fixed;
    bottom: max(12px, env(safe-area-inset-bottom));
    left: max(12px, env(safe-area-inset-left));
    font-size: 12px;
    opacity: 0.6;
    pointer-events: none;
  }
  
  /* --- Commandes tactiles --- */
  /* Rien n'occupe l'écran au repos : les manches n'existent que sous le doigt,
     et les quatre pastilles tiennent sur une seule ligne dans le coin. */
  #touch-controls {
    position: fixed;
    inset: 0;
    pointer-events: none;
  }
  
  /* Un manche flottant. L'élément est posé à l'endroit du contact par une
     translation, ses deux formes sont centrées dessus par leur position.
     Le manche libre est rond ; celui de la direction est une barre couchée et
     celui des pédales une barre debout, pour que la forme dise elle-même dans
     quel sens le pouce a le droit d'aller. */
  .stick {
    position: absolute;
    left: 0;
    top: 0;
    opacity: 0;
    transition: opacity 0.12s ease;
  }
  
  .stick.on { opacity: 1; }
  
  .stick-base,
  .stick-knob {
    position: absolute;
    border-radius: 999px;
  }
  
  .stick-base {
    left: -56px;
    top: -56px;
    width: 112px;
    height: 112px;
    background: rgba(242, 239, 230, 0.12);
    border: 1px solid rgba(242, 239, 230, 0.3);
  }
  
  .stick-knob {
    left: -24px;
    top: -24px;
    width: 48px;
    height: 48px;
    background: rgba(242, 239, 230, 0.3);
    border: 1px solid rgba(242, 239, 230, 0.4);
  }
  
  /* La direction : une barre couchée, le pouce ne va que de gauche à droite. */
  .stick.axis-x > .stick-base {
    top: -27px;
    height: 54px;
  }
  
  /* Les pédales : une barre debout, gaz vers le haut, frein vers le bas. */
  .stick.axis-y > .stick-base {
    left: -27px;
    width: 54px;
  }
  
  #touch-buttons {
    position: fixed;
    right: max(12px, env(safe-area-inset-right));
    bottom: max(12px, env(safe-area-inset-bottom));
    display: none;
    /* Quatre pastilles depuis le frein à main : elles doivent tenir dans le coin
       sans manger la place où naissent les manches. */
    gap: 7px;
  }
  
  #touch-controls.visible #touch-buttons { display: flex; }
  
  #touch-controls button {
    pointer-events: auto;
    height: 42px;
    padding: 0 13px;
    border: 0;
    border-radius: 999px;
    background: rgba(242, 239, 230, 0.16);
    color: var(--text);
    font-size: 14px;
    touch-action: none;
  }
  
  #touch-controls button:active { background: rgba(242, 239, 230, 0.34); }
  
  /* Le frein à main se tient : il reste allumé tant que le doigt est dessus. */
  #touch-controls button[data-hold].held {
    background: rgba(255, 210, 122, 0.3);
    color: var(--accent);
  }
  
  /* Le bouton d'action s'allume quand il y a vraiment quelque chose à faire. */
  #touch-controls button[data-action="action"] { opacity: 0.45; }
  
  #touch-controls button[data-action="action"].ready {
    opacity: 1;
    background: rgba(255, 210, 122, 0.26);
    color: var(--accent);
  }
  
  @media (max-width: 520px) {
    /* Au doigt, la seule chose à savoir est quel pouce fait quoi. */
    #help .keys { display: none; }
    #help .pad { display: inline; }
    /* Les deux coins du bas appartiennent aux pouces : les pastilles remontent
       le long du bord droit, à portée de l'index, pour ne pas se retrouver
       sous la paume au moment d'accélérer. */
    #touch-buttons {
      flex-direction: column;
      align-items: flex-end;
      bottom: calc(150px + env(safe-area-inset-bottom));
    }
    #action-hint { bottom: calc(62px + env(safe-area-inset-bottom)); }
    .tile { padding: 6px 9px; }
    .tile .value { font-size: 16px; }
    .gauge-group { width: 150px; }
    .gauge-label { width: 50px; }
  
    /* L'écran est trop étroit pour neuf pièces en ligne : on les range
       dans un panneau que l'on ouvre. */
    #parts-toggle { display: flex; }
    #parts-panel { display: none; flex-wrap: wrap; width: 224px; }
    /* La ligne du coin doit tenir à droite du poids : le mot saute, le
       pourcentage reste, et le panneau dit le reste quand on l'ouvre. */
    .parts-word { display: none; }
    .part { width: 40px; }
    .part-name { font-size: 7.5px; }
    #parts.open #parts-panel { display: flex; }
  }
  
  /* Une roue qui ne fait pas la taille des autres : on la signale, parce que
     c'est elle qui explique le tirage, le frein et l'usure accélérée. */
  .part[data-odd] .ring-bg { stroke: var(--accent); stroke-dasharray: 2 2; }
  .part[data-odd] .part-name { color: var(--accent); opacity: 1; }
  .part[data-odd] .part-name::after { content: ' ≠'; }
  
  /* --- Pièce absente --- */
  /* Une pièce démontée se lit autrement qu'une pièce très abîmée : l'anneau de
     fond devient pointillé et la case s'éteint. */
  .part[data-missing] svg { opacity: 0.3; }
  .part[data-missing] .ring-bg { stroke-dasharray: 3 3; }
  .part[data-missing] .part-name { opacity: 0.4; text-decoration: line-through; }
  
  /* --- Inventaire --- */
  /* Des cases carrées, un objet occupe un rectangle. À gauche le sac du
     personnage, à droite le véhicule vu du dessus quand on est dedans. */
  #inventory {
    position: fixed;
    inset: 0;
    z-index: 10;
    display: flex;
    align-items: center;
    justify-content: center;
    padding: 14px;
    background: rgba(8, 12, 10, 0.6);
    backdrop-filter: blur(3px);
  }
  
  #inventory[hidden] { display: none; }
  
  #inv-sheet {
    --cell: 36px;
    --line: rgba(242, 239, 230, 0.1);
    --slot: rgba(8, 11, 9, 0.4);
    --good: #7fb48a;
    background: rgba(18, 23, 20, 0.96);
    border-radius: 14px;
    box-shadow: 0 18px 48px rgba(0, 0, 0, 0.5);
    padding: 13px 16px 11px;
    max-height: 100%;
    overflow: auto;
    touch-action: none;
  }
  
  .inv-head {
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 20px;
    margin-bottom: 10px;
  }
  
  .inv-head h2 {
    margin: 0;
    font-size: 12px;
    font-weight: 600;
    letter-spacing: 0.16em;
    text-transform: uppercase;
    opacity: 0.7;
  }
  
  #inv-close {
    border: 0;
    border-radius: 999px;
    padding: 6px 13px;
    background: rgba(242, 239, 230, 0.14);
    color: var(--text);
    font: inherit;
    font-size: 12px;
    cursor: pointer;
  }
  
  #inv-close:hover { background: rgba(242, 239, 230, 0.24); }
  
  .inv-cols { display: flex; gap: 22px; align-items: flex-start; }
  
  #inv-vehicle[hidden] { display: none; }
  
  .inv-title {
    display: flex;
    justify-content: space-between;
    gap: 12px;
    margin: 0 0 6px;
    font-size: 9px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    opacity: 0.55;
  }
  
  .inv-load { letter-spacing: 0; opacity: 0.85; }
  
  .inv-hint {
    margin: 11px 0 0;
    font-size: 10px;
    opacity: 0.45;
  }
  
  /* Le quadrillage est un fond, pas des éléments : une case par objet suffit. */
  .inv-grid {
    display: grid;
    grid-template-columns: repeat(var(--cols), var(--cell));
    grid-template-rows: repeat(var(--rows), var(--cell));
    border-radius: 4px;
    background-color: var(--slot);
    background-image:
      linear-gradient(to right, var(--line) 1px, transparent 1px),
      linear-gradient(to bottom, var(--line) 1px, transparent 1px);
    background-size: var(--cell) var(--cell);
    box-shadow: inset 0 0 0 1px rgba(242, 239, 230, 0.16);
  }
  
  .inv-item {
    position: relative;
    margin: 2px;
    border-radius: 5px;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 1px;
    overflow: hidden;
    background: rgba(242, 239, 230, 0.1);
    box-shadow: inset 0 0 0 1px rgba(242, 239, 230, 0.18);
    color: var(--tone, #cdd6cb);
    cursor: grab;
    touch-action: none;
  }
  
  .inv-item svg {
    width: 22px;
    height: 22px;
    flex: none;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
  }
  
  .inv-item em {
    display: block;
    position: relative;
    font-style: normal;
    /* Le texte suit la taille des cases : il reste lisible sur un grand écran
       et ne déborde pas des 30 px d'un téléphone. */
    font-size: calc(var(--cell, 36px) * 0.2);
    max-width: 100%;
    color: var(--text);
    opacity: 0.65;
    white-space: nowrap;
  }
  
  /* Une case unique n'a pas la place d'un grand dessin et d'un texte : le dessin
     rétrécit, parce que c'est la variante (« 15" », « 1,2 L ») qui fait choisir. */
  .inv-item.tiny svg { width: 16px; height: 16px; }
  
  /* Le dessin passe par-dessus le niveau de remplissage. */
  .inv-item svg { position: relative; }
  
  /* Ce que contient un récipient : le liquide monte depuis le bas de la case. */
  .inv-fill {
    position: absolute;
    left: 0;
    right: 0;
    bottom: 0;
    opacity: 0.32;
  }
  
  /* État d'une pièce usée, en bas de sa case. */
  .inv-cond {
    position: absolute;
    left: 0;
    bottom: 0;
    height: 2px;
    background: var(--warn);
  }
  
  /* À zéro, la barre n'a plus rien à montrer : une pièce morte ressemblait donc
     à une pièce neuve. Elle se teinte de rouge, le fond comme le dessin, pour
     qu'on voie d'un coup d'œil laquelle est le souci. */
  .inv-item[data-cond="dead"] {
    background: rgba(214, 92, 76, 0.26);
    box-shadow: inset 0 0 0 1px rgba(236, 124, 106, 0.6);
    color: #f0a394;
  }
  
  .inv-item[data-cond="dead"] em { color: #f0a394; opacity: 0.8; }
  
  /* Sorti du cadre, l'objet va tomber : il se détache et s'incline. */
  .inv-item.dragging.falling {
    opacity: 0.8;
    box-shadow: 0 14px 28px rgba(0, 0, 0, 0.55), inset 0 0 0 1px var(--warn);
  }
  
  #inv-drop-hint {
    position: fixed;
    left: 50%;
    bottom: 22px;
    transform: translateX(-50%);
    margin: 0;
    padding: 5px 11px;
    border-radius: 999px;
    font-size: 11px;
    color: var(--text);
    background: rgba(18, 23, 19, 0.88);
    box-shadow: inset 0 0 0 1px var(--warn);
    pointer-events: none;
    z-index: 41;
  }
  
  /* L'objet saisi reste à sa place en transparence, un double suit le doigt. */
  .inv-item.held { opacity: 0.22; }
  
  .inv-item.dragging {
    position: fixed;
    left: 0;
    top: 0;
    z-index: 40;
    margin: 0;
    pointer-events: none;
    cursor: grabbing;
    background: rgba(30, 38, 32, 0.96);
    box-shadow: 0 10px 24px rgba(0, 0, 0, 0.5), inset 0 0 0 1px rgba(242, 239, 230, 0.32);
  }
  
  /* Où l'objet atterrirait, et si c'est permis. L'aperçu est volontairement plus
     large que l'objet : le double qui suit le doigt le recouvrirait sinon, et on
     ne verrait plus la couleur qui dit oui ou non. */
  .inv-preview { border-radius: 6px; pointer-events: none; }
  .inv-preview.ok { background: rgba(127, 180, 138, 0.22); box-shadow: inset 0 0 0 2px var(--good); }
  .inv-preview.bad { background: rgba(255, 154, 108, 0.16); box-shadow: inset 0 0 0 2px var(--warn); }
  
  /* --- Le véhicule vu du dessus --- */
  #inv-rig {
    display: grid;
    grid-template-columns: repeat(var(--cols), var(--cell));
    grid-template-rows: repeat(var(--rows), var(--cell));
  }
  
  /* `display: grid` l'emporterait sur le `hidden` du navigateur : pendant la
     personnalisation, la grille du véhicule doit vraiment disparaître. */
  #inv-rig[hidden] { display: none; }
  
  /* La carrosserie, derrière les emplacements : les roues dépassent de chaque
     côté, le coffre est à l'arrière. */
  #inv-chassis {
    border-radius: 28px 28px 12px 12px;
    background: rgba(242, 239, 230, 0.09);
    box-shadow: inset 0 0 0 1px rgba(242, 239, 230, 0.2);
  }
  
  /* Une carcasse se montre dans la même grille que la voiture, mais sa tôle est
     rouillée : on ne confond pas son épave avec son propre véhicule. */
  #inv-vehicle.wrecked #inv-chassis {
    background: rgba(122, 90, 74, 0.16);
    box-shadow: inset 0 0 0 1px rgba(122, 90, 74, 0.45);
  }
  
  #inv-vehicle.wrecked .inv-title {
    opacity: 0.8;
    color: #c0906f;
  }
  
  /* --- Personnaliser ---
     Le bouton vit dans le titre de la colonne, et l'écran qu'il ouvre occupe
     exactement la place de la grille du véhicule : la feuille ne change pas de
     taille quand on passe de l'une à l'autre. */
  #inv-tune-toggle {
    margin-left: auto;
    border: 0;
    border-radius: 999px;
    padding: 3px 9px;
    background: rgba(242, 239, 230, 0.14);
    color: var(--text);
    font: inherit;
    font-size: 9px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    cursor: pointer;
  }
  
  #inv-tune-toggle:hover { background: rgba(242, 239, 230, 0.26); }
  #inv-tune-toggle[hidden] { display: none; }
  
  #inv-tune {
    width: calc(var(--cols) * var(--cell));
    min-height: calc(var(--rows) * var(--cell));
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
  }
  
  #inv-tune[hidden] { display: none; }
  
  /* La voiture en grand : c'est elle qu'on repeint, et c'est aussi la cible où
     l'on peut lâcher une bombe. */
  #tune-car {
    width: calc(var(--cell) * 2.6);
    padding: 4px;
    border-radius: 10px;
  }
  
  #tune-car svg { display: block; width: 100%; height: auto; }
  #tune-car.ok { background: rgba(127, 180, 138, 0.22); box-shadow: inset 0 0 0 2px var(--good); }
  #tune-car.bad { background: rgba(255, 154, 108, 0.16); box-shadow: inset 0 0 0 2px var(--warn); }
  
  #tune-read {
    margin: 0;
    font-size: 10px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    opacity: 0.6;
  }
  
  #tune-read strong { letter-spacing: 0; opacity: 0.95; }
  
  /* Les bombes qu'on a sous la main, chacune de sa couleur. */
  #tune-sprays {
    display: flex;
    flex-wrap: wrap;
    justify-content: center;
    gap: 6px;
  }
  
  .tune-spray {
    width: calc(var(--cell) * 1.15);
    border: 0;
    border-radius: 7px;
    padding: 5px 2px 4px;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 3px;
    background: var(--slot);
    box-shadow: inset 0 0 0 1px rgba(242, 239, 230, 0.16);
    color: var(--text);
    font: inherit;
    cursor: pointer;
  }
  
  .tune-spray:hover:not(:disabled) {
    background: rgba(242, 239, 230, 0.14);
    box-shadow: inset 0 0 0 1px rgba(242, 239, 230, 0.4);
  }
  
  /* Une bombe vide, ou de la couleur déjà posée, se montre tout de même : la
     voir barrée vaut mieux que la chercher. */
  .tune-spray:disabled { opacity: 0.4; cursor: default; }
  
  .tune-spray i {
    width: 14px;
    height: 14px;
    border-radius: 50%;
    background: var(--paint);
    box-shadow: inset 0 0 0 1px rgba(10, 12, 10, 0.45);
  }
  
  .tune-spray em { font-size: 8px; font-style: normal; opacity: 0.9; }
  .tune-spray small { font-size: 7px; opacity: 0.45; }
  
  #tune-hint {
    margin: 0;
    max-width: calc(var(--cols) * var(--cell));
    text-align: center;
    font-size: 9px;
    line-height: 1.4;
    opacity: 0.45;
  }
  
  .inv-slot {
    position: relative;
    margin: 2px;
    border-radius: 6px;
    display: flex;
    align-items: center;
    justify-content: center;
    background: var(--slot);
    box-shadow: inset 0 0 0 1px rgba(242, 239, 230, 0.16);
  }
  
  .inv-slot > .inv-item { position: absolute; inset: 0; margin: 0; }
  
  /* --- La fin du voyage --- */
  /* Sobre et au centre : la cause, la distance atteinte, et comment repartir. Le
     décor reste visible derrière, parce que c'est là qu'on s'est arrêté. */
  #gameover {
    position: fixed;
    inset: 0;
    z-index: 30;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 6px;
    background: rgba(14, 16, 20, 0.72);
    color: #f2efe9;
    text-align: center;
    padding: 0 16px;
  }
  
  /* Comme l'inventaire : donner un display à un élément caché le ferait
     réapparaître, et il couvrirait tout l'écran. */
  #gameover[hidden] { display: none; }
  
  #gameover .over-cause {
    margin: 0;
    font-size: 26px;
    letter-spacing: 0.04em;
    color: var(--warn);
  }
  
  #gameover .over-score { margin: 0; font-size: 18px; }
  
  #gameover .over-again {
    margin: 10px 0 0;
    font-size: 12px;
    letter-spacing: 0.12em;
    text-transform: uppercase;
    opacity: 0.6;
  }
  
  /* --- La bouche et la vidange --- */
  /* Deux destinations qui ne sont pas des cases : on y glisse un objet pour le
     consommer ou pour le jeter. Elles se partagent la rangée sous le sac. */
  /* Le sac à dos : la case qui le porte, et à côté les cases qu'il ouvre. Sans
     sac, il n'y a rien à montrer que la case vide et la raison. */
  .inv-pack {
    margin-top: 8px;
    display: flex;
    gap: 8px;
    align-items: flex-start;
  }
  
  /* L'emplacement a la forme du sac qu'il attend — deux cases sur deux — pour
     qu'un sac saisi là garde ses proportions, comme une pièce du véhicule. */
  #inv-pack-slot {
    flex: none;
    width: calc(var(--cell) * 2);
    height: calc(var(--cell) * 2);
  }
  
  /* Dans une rangée souple, une grille se laisserait rétrécir : ses cases doivent
     garder la taille de celles des poches. */
  #inv-pack { flex: none; }
  
  /* Les grilles du personnage ne font que la largeur de leurs colonnes : sans
     quoi, la rangée du sac étant plus large, les poches s'étireraient et
     montreraient des cases qui n'existent pas. */
  #inv-bag, #inv-pack { width: max-content; }
  
  #inv-pack-hint {
    margin: 0;
    align-self: center;
    font-size: 10px;
    opacity: 0.4;
  }
  
  #inv-pack[hidden], #inv-pack-hint[hidden] { display: none; }
  
  .inv-sinks {
    margin-top: 8px;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 8px;
  }
  
  #inv-mouth,
  #inv-drain {
    height: calc(var(--cell) * 1.1);
    border-radius: 8px;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 7px;
    background: var(--slot);
    cursor: default;
  }
  
  /* La vidange : ce qui y tombe est perdu, d'où le rouge. */
  #inv-drain {
    box-shadow: inset 0 0 0 1px rgba(255, 154, 108, 0.3);
    color: var(--warn);
  }
  
  #inv-mouth svg,
  #inv-drain svg {
    width: 15px;
    height: 15px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
  }
  
  #inv-mouth em,
  #inv-drain em {
    font-style: normal;
    font-size: 10px;
    letter-spacing: 0.1em;
    text-transform: uppercase;
    opacity: 0.75;
  }
  
  #inv-mouth.ok,
  #inv-drain.ok { outline: 2px solid var(--good); outline-offset: 1px; }
  #inv-mouth.bad,
  #inv-drain.bad { outline: 2px solid var(--warn); outline-offset: 1px; }
  
  /* La bouche : on y boit et on y mange, d'où la teinte d'eau. */
  #inv-mouth {
    box-shadow: inset 0 0 0 1px rgba(122, 185, 214, 0.32);
    color: #8ec6de;
  }
  
  /* Un objet posé en travers : le dessin suit, sinon une roue couchée aurait
     toujours l'air debout. */
  .inv-item.turned svg { transform: rotate(90deg); }
  
  /* --- Les réservoirs de la voiture --- */
  /* On n'y range rien, on y verse : d'où la forme ronde, qui ne ressemble pas à
     une case d'emplacement. */
  .inv-res {
    position: relative;
    margin: 3px;
    border-radius: 50%;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    gap: 0;
    background: var(--slot);
    box-shadow: inset 0 0 0 1px rgba(242, 239, 230, 0.22);
    color: var(--tone, #cdd6cb);
  }
  
  .inv-res svg {
    position: relative;
    width: 13px;
    height: 13px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linejoin: round;
  }
  
  .inv-res em {
    position: relative;
    font-style: normal;
    font-size: calc(var(--cell, 36px) * 0.18);
    color: var(--text);
    opacity: 0.7;
  }
  
  /* Pièce manquante : le réservoir ne sert à rien tant qu'elle n'est pas montée. */
  .inv-res.off { opacity: 0.3; }
  .inv-res.ok { outline: 2px solid var(--good); outline-offset: 1px; }
  .inv-res.bad { outline: 2px solid var(--warn); outline-offset: 1px; }
  
  /* La cible d'un transvasement s'allume, elle, en bleu : ce n'est ni un refus
     ni un déplacement. */
  .inv-item.pour { outline: 2px solid #5fa8d3; outline-offset: 1px; }
  .inv-item.bad { outline: 2px solid var(--warn); outline-offset: 1px; }
  
  /* Une jauge dont la pièce manque ne veut plus rien dire. */
  .gauge.off { opacity: 0.4; }
  
  /* --- Le panneau de transvasement --- */
  #inv-pour {
    position: absolute;
    left: 50%;
    top: 50%;
    transform: translate(-50%, -50%);
    z-index: 3;
    width: min(300px, 86%);
    padding: 13px 15px 12px;
    border-radius: 10px;
    background: rgba(22, 28, 24, 0.97);
    box-shadow: 0 16px 40px rgba(0, 0, 0, 0.55), inset 0 0 0 1px rgba(242, 239, 230, 0.2);
    text-align: center;
  }
  
  #pour-title {
    margin: 0 0 9px;
    font-size: 11px;
    letter-spacing: 0.14em;
    text-transform: uppercase;
    opacity: 0.55;
  }
  
  #pour-sides {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 8px;
    font-size: 12px;
  }
  
  #pour-swap {
    flex: none;
    width: 26px;
    height: 22px;
    border: 0;
    border-radius: 6px;
    background: rgba(242, 239, 230, 0.12);
    color: var(--text);
    font: inherit;
    cursor: pointer;
  }
  
  /* Chaque bout du transvasement tient en trois lignes : le nom, ce qu'il y a
     dedans, les litres avant et après. */
  .pour-side {
    flex: 1;
    display: flex;
    flex-direction: column;
    gap: 2px;
    line-height: 1.3;
  }
  
  .pour-name { opacity: 0.85; }
  
  .pour-what {
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    gap: 3px;
    font-size: 11px;
    opacity: 0.95;
  }
  
  .pour-what i {
    width: 7px;
    height: 7px;
    border-radius: 50%;
    display: inline-block;
  }
  
  .pour-what em { font-style: normal; opacity: 0.5; }
  .pour-empty { opacity: 0.45; font-style: italic; }
  .pour-move { font-size: 11px; opacity: 0.6; font-variant-numeric: tabular-nums; }
  
  #pour-warn {
    margin: -7px 0 9px;
    font-size: 11px;
    color: var(--warn);
  }
  
  #pour-amount {
    width: 100%;
    margin: 11px 0 4px;
    accent-color: var(--good);
  }
  
  #pour-read {
    margin: 0 0 11px;
    font-size: 13px;
    font-weight: 600;
    min-height: 16px;
  }
  
  #pour-acts { display: flex; gap: 8px; }
  
  #pour-acts button {
    flex: 1;
    padding: 6px 0;
    border: 0;
    border-radius: 6px;
    font: inherit;
    font-size: 12px;
    cursor: pointer;
    background: rgba(242, 239, 230, 0.12);
    color: var(--text);
  }
  
  #pour-ok { background: rgba(127, 180, 138, 0.3); }
  #pour-ok:disabled { opacity: 0.4; cursor: default; }
  
  /* Ce qui va dans l'emplacement, en filigrane tant qu'il est vide. */
  .inv-ghost {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1px;
    opacity: 0.32;
    pointer-events: none;
  }
  
  .inv-ghost svg {
    width: 20px;
    height: 20px;
    fill: none;
    stroke: currentColor;
    stroke-width: 1.6;
    stroke-linecap: round;
    stroke-linejoin: round;
  }
  
  .inv-ghost em {
    font-style: normal;
    font-size: 7px;
    letter-spacing: 0.04em;
    white-space: nowrap;
  }
  
  /* Un emplacement vide se voit au premier coup d'œil : trait pointillé, et le
     dessin de la pièce qui y va en filigrane. */
  .inv-slot:not(.filled) {
    box-shadow: none;
    outline: 1px dashed rgba(242, 239, 230, 0.26);
    outline-offset: -1px;
  }
  
  .inv-slot.filled .inv-ghost { display: none; }
  .inv-slot.ok, .inv-slot.bad { outline-offset: 1px; outline-style: solid; outline-width: 2px; }
  .inv-slot.ok { background: rgba(127, 180, 138, 0.18); outline-color: var(--good); }
  .inv-slot.bad { background: rgba(255, 154, 108, 0.14); outline-color: var(--warn); }
  
  @media (max-width: 520px) {
    #touch-controls button { height: 38px; padding: 0 11px; font-size: 13px; }
  }
  
  @media (max-width: 520px) {
    #inv-sheet { --cell: 30px; padding: 11px 13px 10px; }
    .inv-cols { flex-direction: column; gap: 12px; align-items: center; }
    .inv-box { width: fit-content; }
    .inv-item svg { width: 19px; height: 19px; }
    .inv-item.tiny svg { width: 14px; height: 14px; }
    .inv-ghost svg { width: 17px; height: 17px; }
  }
  