:root {
  color-scheme: light;
  --bg: #ffffff;
  --panel: #f4f5f7;
  --panel-alt: #e9ebef;
  --border: #d5d8de;
  --text: #1d1f26;
  --text-dim: #5b6270;
  --accent: #3a5fd9;
  --accent-text: #ffffff;
}

* {
  box-sizing: border-box;
}

html, body {
  height: 100%;
  margin: 0;
}

body {
  /* Motif a 0.2 d'opacite sur fond blanc : superposition d'un calque blanc a
     0.8 (1 - 0.2) sur l'image, plutot qu'un opacity CSS qui affecterait aussi
     le texte/contenu de la page. */
  background-color: var(--bg);
  background-image: linear-gradient(rgba(255, 255, 255, 0.8), rgba(255, 255, 255, 0.8)), url("/assets/background.jpg");
  background-repeat: repeat;
  /* Image source en 1800x1800 : reduite pour un motif plus petit/dense. */
  background-size: 400px 400px;
  color: var(--text);
  font-family: system-ui, -apple-system, "Segoe UI", Roboto, sans-serif;
}

.app {
  display: flex;
  flex-direction: column;
  height: 100vh;
}

.app-header {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.75rem 1.25rem;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
  flex-wrap: wrap;
}

.app-header h1 {
  font-size: 1.15rem;
  margin: 0;
  white-space: nowrap;
}

.home-link {
  color: inherit;
  text-decoration: none;
  display: inline-flex;
  align-items: center;
  gap: 0.4rem;
}

.header-icon {
  width: 24px;
  height: 24px;
}

.home-link:hover {
  opacity: 0.8;
}

/* Single nav entry point for every page (picker/favorites/library/admin),
   replacing what used to be one-off links (e.g. "Change console") scattered
   across each header. */
.burger-menu {
  position: relative;
  display: flex;
  /* Always the rightmost item in .app-header, on every page - pushes itself
     (not its siblings) to the far edge regardless of whether an earlier
     sibling like #search already has flex:1. justify-content keeps the
     button pinned right even on mobile, where .app-header switches to a
     column layout and align-items:stretch would otherwise widen this box
     to the full row and left-align the button inside it. */
  margin-left: auto;
  justify-content: flex-end;
}

.burger-btn {
  background: none;
  border: 1px solid var(--border);
  border-radius: 6px;
  color: var(--text);
  font-size: 1.1rem;
  line-height: 1;
  padding: 0.4rem 0.65rem;
  cursor: pointer;
}

.burger-btn:hover {
  background: var(--panel-alt);
}

.burger-dropdown {
  position: absolute;
  top: calc(100% + 0.4rem);
  /* Anchored to its right edge, not left: the button now sits at the far
     right of .app-header (see .burger-menu's margin-left:auto), so a
     left:0 dropdown of min-width 180px would overflow past the viewport
     edge instead of opening back over the page. */
  right: 0;
  display: flex;
  flex-direction: column;
  min-width: 180px;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  box-shadow: 0 6px 20px rgba(0, 0, 0, 0.15);
  padding: 0.35rem;
  z-index: 20;
}

.burger-dropdown a {
  color: var(--text);
  text-decoration: none;
  padding: 0.5rem 0.65rem;
  border-radius: 6px;
  font-size: 0.9rem;
  white-space: nowrap;
}

.burger-dropdown a:hover {
  background: var(--panel-alt);
}

#search {
  flex: 1;
  min-width: 180px;
  padding: 0.5rem 0.75rem;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--panel-alt);
  color: var(--text);
  font-size: 0.95rem;
}

#search:focus {
  outline: 2px solid var(--accent);
  outline-offset: 1px;
}

.count {
  color: var(--text-dim);
  font-size: 0.85rem;
  white-space: nowrap;
}

.app-main {
  flex: 1;
  display: flex;
  min-height: 0;
}

.game-list {
  list-style: none;
  margin: 0;
  padding: 0.5rem;
  width: 380px;
  flex-shrink: 0;
  overflow-y: auto;
  border-right: 1px solid var(--border);
}

.game-row {
  display: flex;
  align-items: center;
  gap: 0.15rem;
}

.game-row .favorite-toggle {
  flex-shrink: 0;
}

.game-item {
  display: flex;
  align-items: center;
  gap: 0.6rem;
  padding: 0.4rem 0.5rem;
  border-radius: 6px;
  cursor: pointer;
  color: var(--text);
  background: transparent;
  border: 1px solid transparent;
  flex: 1;
  min-width: 0;
  text-align: left;
  font-size: 0.85rem;
}

.game-item:hover {
  background: var(--panel-alt);
}

.game-item.selected {
  background: var(--accent);
  color: var(--accent-text);
  border-color: var(--accent);
}

.game-item .thumb {
  width: 40px;
  height: 40px;
  object-fit: contain;
  border-radius: 4px;
  flex-shrink: 0;
}

.game-item .name {
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.game-list .empty {
  color: var(--text-dim);
  padding: 1rem;
  text-align: center;
}

.details {
  flex: 1;
  overflow-y: auto;
  padding: 1.5rem;
}

.details-placeholder {
  color: var(--text-dim);
}

.details h2 {
  margin-top: 0;
}

.details-title-row {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.details-title-row h2 {
  margin: 0;
}

.details-title-row .favorite-toggle {
  font-size: 1.4rem;
}

.media-row {
  display: flex;
  align-items: flex-start;
  gap: 1.5rem;
  flex-wrap: wrap;
  margin: 1rem 0;
}

.media-video-col {
  flex: 0 1 480px;
  min-width: 280px;
}

.media-video-col video {
  display: block;
  max-width: 480px;
  width: 100%;
  border-radius: 8px;
  background: #000;
}

/* Marquee (logo) empile au-dessus de la jaquette (thumb), a droite de la video. */
.media-side-col {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  width: 240px;
  max-width: 100%;
  flex-shrink: 0;
}

.marquee-img,
.thumb-img {
  width: 100%;
  height: auto;
  border-radius: 8px;
  object-fit: contain;
}

.titre-img {
  display: block;
  max-width: 480px;
  width: 100%;
  border-radius: 8px;
}

.media-missing {
  color: var(--text-dim);
  font-style: italic;
}

.details-links-row {
  display: flex;
  flex-wrap: wrap;
  gap: 0.75rem;
}

.download-link {
  display: inline-block;
  margin-top: 0.5rem;
  padding: 0.5rem 1rem;
  background: var(--accent);
  color: var(--accent-text);
  border-radius: 6px;
  text-decoration: none;
  font-weight: 600;
}

.download-link:hover {
  opacity: 0.9;
}

.manual-link {
  background: var(--panel-alt);
  color: var(--text);
  border: none;
  cursor: pointer;
  font: inherit;
}

.play-link {
  background: #e8791a;
  color: #ffffff;
  border: none;
  cursor: pointer;
  font: inherit;
}

/* --- Visionneuse de manuel (modale PDF) --- */

.manual-viewer-dialog {
  width: 90vw;
  max-width: 900px;
  height: 85vh;
  padding: 0;
  border: none;
  border-radius: 10px;
  overflow: hidden;
  background: var(--panel);
  color: var(--text);
}

/* display doit rester conditionne a [open] : sinon la regle s'applique
   meme apres dialog.close() (qui retire cet attribut), et la boite reste
   visible/en flux normal malgre une fermeture reussie cote JS. */
.manual-viewer-dialog[open] {
  display: flex;
  flex-direction: column;
}

.manual-viewer-dialog::backdrop {
  background: rgba(0, 0, 0, 0.6);
}

.manual-viewer-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.manual-viewer-header span {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.manual-viewer-body {
  flex: 1;
  min-height: 0;
  overflow: auto;
  background: #525659;
  display: flex;
  justify-content: center;
  padding: 1rem;
}

.manual-viewer-body canvas {
  max-width: 100%;
  height: fit-content;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
}

.manual-viewer-controls {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 1rem;
  padding: 0.6rem 1rem;
  border-top: 1px solid var(--border);
  flex-shrink: 0;
}

.manual-viewer-controls span {
  font-size: 0.85rem;
  color: var(--text-dim);
  min-width: 6rem;
  text-align: center;
}

.play-dialog {
  width: 90vw;
  max-width: 900px;
  height: 85vh;
  padding: 0;
  border: none;
  border-radius: 10px;
  overflow: hidden;
  background: var(--panel);
  color: var(--text);
}

/* display doit rester conditionne a [open] : sinon la regle s'applique
   meme apres dialog.close() (qui retire cet attribut), et la boite reste
   visible/en flux normal malgre une fermeture reussie cote JS. */
.play-dialog[open] {
  display: flex;
  flex-direction: column;
}

.play-dialog::backdrop {
  background: rgba(0, 0, 0, 0.6);
}

.play-dialog-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 1rem;
  padding: 0.75rem 1rem;
  border-bottom: 1px solid var(--border);
  flex-shrink: 0;
}

.play-dialog-header span {
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.play-dialog-body {
  flex: 1;
  min-height: 0;
  overflow: auto;
  background: #525659;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  padding: 1rem;
  gap: 1rem;
}

/* WasmBoy fixe lui-meme width/height/style (dont image-rendering) sur ce
   canvas a l'initialisation - la regle ci-dessous est une redondance
   volontaire (filet de securite si une future version arretait de le
   faire), pas la source de verite du dimensionnement interne (160x144). */
.play-dialog-body canvas {
  width: min(80vw, 640px);
  height: auto;
  aspect-ratio: 160 / 144;
  image-rendering: pixelated;
  box-shadow: 0 2px 12px rgba(0, 0, 0, 0.4);
}

.play-dialog-error {
  color: var(--text-dim);
}

.play-dialog-controls {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 0.3rem;
  padding: 0.6rem 1rem;
  border-top: 1px solid var(--border);
  flex-shrink: 0;
}

.play-dialog-controls span {
  font-size: 0.85rem;
  color: var(--text-dim);
  text-align: center;
}

.play-dialog-controls .play-gamepad-status {
  color: var(--accent);
}

.gamepad-status {
  font-size: 0.85rem;
  color: var(--accent);
}

/* Configurateur de manette (app.js, controller-wizard-dialog) - meme gabarit
   que manual-viewer-dialog/play-dialog ci-dessus, mais plus petit : c'est un
   formulaire, pas un lecteur media. */
.controller-wizard-dialog {
  width: 90vw;
  max-width: 520px;
  padding: 0;
  border: none;
  border-radius: 10px;
  overflow: hidden;
  background: var(--panel);
  color: var(--text);
}

.controller-wizard-dialog[open] {
  display: flex;
  flex-direction: column;
}

.controller-wizard-dialog::backdrop {
  background: rgba(0, 0, 0, 0.6);
}

.controller-wizard-body {
  padding: 1rem;
  overflow: auto;
  max-height: 70vh;
}

.controller-wizard-dpad-mode {
  border: none;
  padding: 0;
  margin: 0 0 0.75rem;
  display: flex;
  gap: 1rem;
}

.controller-wizard-dpad-mode legend {
  font-size: 0.85rem;
  color: var(--text-dim);
  padding: 0;
}

.controller-wizard-actions {
  display: flex;
  justify-content: flex-end;
  gap: 0.6rem;
  padding: 0.75rem 1rem;
  border-top: 1px solid var(--border);
}

/* --- Metadonnees ScreenScraper (panneau detail) --- */

.details-meta {
  margin: 0.5rem 0 1rem;
}

.details-meta-line {
  color: var(--text-dim);
  font-size: 0.85rem;
  margin: 0 0 0.5rem;
}

.details-synopsis {
  line-height: 1.5;
  margin: 0;
}

/* --- Action admin (recherche ScreenScraper) dans le panneau detail --- */

.details-admin-row {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  margin-top: 1rem;
  padding-top: 1rem;
  border-top: 1px dashed var(--border);
}

.details-admin-status {
  font-size: 0.85rem;
  color: var(--text-dim);
}

.details-admin-status.error {
  color: #ff9fa8;
}

/* --- Filtres avances (bibliotheque) --- */

.advanced-filters {
  margin: 0;
  padding: 0 1.25rem;
  border-bottom: 1px solid var(--border);
  background: var(--panel);
}

.advanced-filters summary {
  cursor: pointer;
  padding: 0.6rem 0;
  font-size: 0.85rem;
  color: var(--text-dim);
  list-style: none;
}

.advanced-filters[open] summary {
  color: var(--text);
}

.advanced-filters-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(160px, 1fr));
  gap: 0.75rem;
  padding: 0 0 0.9rem;
}

.advanced-filters-grid label {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.8rem;
  color: var(--text-dim);
}

.advanced-filters-grid select {
  padding: 0.4rem 0.5rem;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--panel-alt);
  color: var(--text);
  font-size: 0.85rem;
}

.filter-region-group {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.8rem;
  color: var(--text-dim);
  /* Plusieurs cases a cocher : plus large qu'une simple colonne de select. */
  grid-column: span 2;
}

.filter-region-label {
  display: block;
}

.filter-region-options {
  display: flex;
  flex-wrap: wrap;
  gap: 0.4rem 0.9rem;
}

/* Bouton-drapeau tri-etat (region filter) : Indifferent (niveaux de gris,
   opacite 1) -> Avec (couleur, opacite 1) -> Sans (couleur, opacite 0.2) au
   clic, voir app.js buildRegionGroups/REGION_STATE_CYCLE. */
.region-flag-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 2.1rem;
  height: 2.1rem;
  padding: 0;
  border: 1px solid var(--border);
  border-radius: 6px;
  background: var(--panel-alt);
  cursor: pointer;
  transition: opacity 0.15s ease, filter 0.15s ease, border-color 0.15s ease;
}

.region-flag-btn:hover {
  border-color: var(--accent);
}

.region-flag-icon {
  font-size: 1.2rem;
  line-height: 1;
}

.region-flag-btn[data-state='neutral'] {
  filter: grayscale(1);
  opacity: 1;
}

.region-flag-btn[data-state='with'] {
  filter: none;
  opacity: 1;
  border-color: var(--accent);
}

.region-flag-btn[data-state='without'] {
  filter: none;
  opacity: 0.2;
}

/* Contenu reserve aux lecteurs d'ecran (ex. libelle textuel d'un bouton
   iconographique) : retire visuellement sans toucher a l'accessibilite. */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  padding: 0;
  margin: -1px;
  overflow: hidden;
  clip: rect(0, 0, 0, 0);
  white-space: nowrap;
  border: 0;
}

.back-btn {
  display: none;
  margin-bottom: 1rem;
  padding: 0.5rem 0.9rem;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--panel-alt);
  color: var(--text);
  font-size: 0.95rem;
  cursor: pointer;
}

.back-btn:hover {
  background: var(--panel);
}

/* --- Connexion --- */

.auth-page {
  min-height: 100vh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 1rem;
}

.auth-card {
  width: 100%;
  max-width: 340px;
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  padding: 1.75rem;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
}

.auth-card h1 {
  margin: 0 0 0.25rem;
  font-size: 1.2rem;
  text-align: center;
}

.auth-card label {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.85rem;
  color: var(--text-dim);
}

.auth-card input[type="text"],
.auth-card input[type="password"] {
  font-size: 16px;
  padding: 0.55rem 0.7rem;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--panel-alt);
  color: var(--text);
}

.auth-card button,
.create-user-form button,
.keymap-form-actions button {
  padding: 0.6rem 1rem;
  border: none;
  border-radius: 6px;
  background: var(--accent);
  color: var(--accent-text);
  font-weight: 600;
  cursor: pointer;
}

.auth-card button:hover,
.create-user-form button:hover,
.keymap-form-actions button:hover {
  opacity: 0.9;
}

.flash {
  margin: 0;
  padding: 0.5rem 0.7rem;
  border-radius: 6px;
  font-size: 0.85rem;
}

.flash-error {
  background: #3a1d22;
  color: #ff9fa8;
  border: 1px solid #5c2933;
}

.flash-success {
  background: #1d3a26;
  color: #8fe0ab;
  border: 1px solid #295c3a;
}

/* --- Back-office admin --- */

.admin-page {
  max-width: 960px;
  margin: 0 auto;
  padding: 1.5rem;
}

.admin-page-wide {
  max-width: none;
  width: 100%;
  box-sizing: border-box;
}

.admin-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 0.75rem;
  margin-bottom: 1rem;
}

.admin-header h1 {
  font-size: 1.3rem;
  margin: 0;
}

.admin-nav {
  display: flex;
  align-items: center;
  gap: 1rem;
}

.admin-nav a {
  color: var(--text-dim);
  text-decoration: none;
}

.admin-nav a:hover {
  color: var(--text);
}

.users-table,
.games-table {
  width: 100%;
  border-collapse: collapse;
  margin: 1rem 0 2rem;
  font-size: 0.85rem;
}

.users-table th,
.users-table td,
.games-table th,
.games-table td {
  padding: 0.6rem 0.6rem;
  text-align: left;
  border-bottom: 1px solid var(--border);
  vertical-align: middle;
}

.you-tag {
  color: var(--text-dim);
  font-size: 0.75rem;
}

.actions-cell {
  display: flex;
  flex-wrap: wrap;
  gap: 0.5rem;
  align-items: center;
}

/* Sur /admin/games, seulement 2 boutons icone (recherche + masquer) : on les
   garde toujours cote a cote plutot que de les laisser passer a la ligne
   (contrairement a la table des utilisateurs, dont les actions sont plus
   nombreuses/larges et beneficient du retour a la ligne sur petit ecran). */
.games-table .actions-cell {
  flex-wrap: nowrap;
}

.inline-form {
  display: inline-flex;
  gap: 0.35rem;
  align-items: center;
  margin: 0;
}

.inline-form input[type="password"] {
  width: 150px;
  padding: 0.35rem 0.5rem;
  border-radius: 5px;
  border: 1px solid var(--border);
  background: var(--panel-alt);
  color: var(--text);
  font-size: 0.8rem;
}

.btn-small {
  padding: 0.35rem 0.6rem;
  border-radius: 5px;
  border: 1px solid var(--border);
  background: var(--panel-alt);
  color: var(--text);
  font-size: 0.8rem;
  cursor: pointer;
}

.btn-small:hover {
  background: var(--panel);
}

.btn-danger {
  border-color: #5c2933;
  color: #ff9fa8;
}

.btn-danger:hover {
  background: #3a1d22;
}

.btn-icon {
  padding: 0.35rem 0.5rem;
  font-size: 1rem;
  line-height: 1;
}

.btn-icon:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

.btn-icon-active {
  border-color: #8fe0ab;
  color: #8fe0ab;
}

.emulator-help {
  color: var(--text-dim);
  font-size: 0.85rem;
  max-width: 640px;
}

.emulator-keymap {
  padding: 1.25rem;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
  margin-bottom: 1.5rem;
}

.emulator-keymap h2 {
  margin-top: 0;
  font-size: 1rem;
}

.emulator-keymap h3 {
  font-size: 0.9rem;
  color: var(--text-dim);
  margin: 1.5rem 0 0.5rem;
}

.options-form {
  display: flex;
  flex-direction: column;
  gap: 0.9rem;
  margin: 0.5rem 0 1rem;
}

.option-field select {
  margin-left: 0.5rem;
  padding: 0.3rem 0.5rem;
  border-radius: 5px;
  border: 1px solid var(--border);
  background: var(--panel-alt);
  color: var(--text);
}

.option-help {
  margin: 0.25rem 0 0;
  font-size: 0.8rem;
  color: var(--text-dim);
}

.keymap-table {
  margin: 0.5rem 0 1rem;
}

.keymap-key-cell {
  display: flex;
  align-items: center;
  gap: 0.6rem;
}

.key-code-display,
.gamepad-button-display,
.gamepad-axis-display {
  font-family: monospace;
  background: var(--panel-alt);
  border: 1px solid var(--border);
  border-radius: 5px;
  padding: 0.2rem 0.5rem;
  min-width: 8rem;
  display: inline-block;
}

/* Une carte par manette du registre (voir views.js:controllerCard) - meme
   look que .emulator-keymap mais imbriquee dedans, d'ou un fond legerement
   different pour rester lisible. */
.controller-card {
  padding: 1rem;
  margin: 0.75rem 0;
  background: var(--panel-alt);
  border: 1px solid var(--border);
  border-radius: 8px;
}

.controller-card h3 {
  margin-top: 0;
  font-size: 0.95rem;
}

.keymap-form-actions {
  display: flex;
  justify-content: flex-end;
}

.create-user {
  padding: 1.25rem;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 10px;
}

.create-user h2 {
  margin-top: 0;
  font-size: 1rem;
}

.create-user-form {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: end;
}

.create-user-form label {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.85rem;
  color: var(--text-dim);
}

.create-user-form input[type="text"],
.create-user-form input[type="password"] {
  font-size: 16px;
  padding: 0.5rem 0.6rem;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--panel-alt);
  color: var(--text);
}

.checkbox-label {
  flex-direction: row !important;
  align-items: center;
  gap: 0.4rem !important;
}

.filter-form {
  display: flex;
  flex-wrap: wrap;
  gap: 1rem;
  align-items: end;
  margin-bottom: 1rem;
}

.filter-form label {
  display: flex;
  flex-direction: column;
  gap: 0.3rem;
  font-size: 0.85rem;
  color: var(--text-dim);
}

.media-yes {
  color: #8fe0ab;
}

.media-no {
  color: var(--text-dim);
}

.status-found,
.status-not-found,
.status-error,
.status-pending {
  font-size: 1rem;
  cursor: help;
}

.status-found {
  color: #8fe0ab;
}

.status-not-found {
  color: var(--text-dim);
}

.status-error {
  color: #ff9fa8;
}

.status-pending {
  color: var(--text-dim);
}

.table-scroll {
  overflow-x: auto;
}

.genre-badge {
  white-space: nowrap;
}

.meta-missing {
  color: var(--text-dim);
}

.row-hidden {
  opacity: 0.55;
}

.hidden-tag {
  font-size: 0.7rem;
  color: var(--text-dim);
  border: 1px solid var(--border);
  border-radius: 4px;
  padding: 0.05rem 0.35rem;
}

.console-badge {
  display: inline-block;
  font-size: 0.7rem;
  font-weight: 600;
  color: var(--accent-text);
  background: var(--accent);
  border-radius: 4px;
  padding: 0.05rem 0.4rem;
  white-space: nowrap;
}

/* Contrairement a .row-hidden (qui estompe), un jeu manquant doit ressortir
   clairement dans la liste. */
.row-missing {
  background: rgba(255, 90, 90, 0.08);
}

.missing-tag {
  font-size: 0.7rem;
  color: #ff9fa8;
  border: 1px solid #ff9fa8;
  border-radius: 4px;
  padding: 0.05rem 0.35rem;
}

.status-missing {
  font-size: 1rem;
  cursor: help;
  color: #ff9fa8;
}

/* --- Barre utilisateur au-dessus de la bibliotheque --- */

.user-bar {
  display: flex;
  align-items: center;
  gap: 0.75rem;
  font-size: 0.85rem;
  color: var(--text-dim);
  white-space: nowrap;
}

.user-bar a {
  color: var(--text-dim);
  text-decoration: none;
}

.user-bar a:hover {
  color: var(--text);
}

.user-bar form {
  margin: 0;
}

.favorite-toggle {
  background: none;
  border: none;
  cursor: pointer;
  font-size: 1.1rem;
  line-height: 1;
  color: var(--text-dim);
  padding: 0.2rem;
  flex-shrink: 0;
}

.favorite-toggle.active {
  color: #ffd257;
}

.favorite-toggle:disabled {
  cursor: default;
}

.favorite-toggle.readonly.active {
  color: #a68a3c;
}

.favorites-filter {
  display: flex;
  align-items: center;
  gap: 0.35rem;
  font-size: 0.85rem;
  color: var(--text-dim);
  white-space: nowrap;
}

/* Favoriting requires an account (see CLAUDE.md, app.js): hidden entirely
   for anonymous visitors via the [hidden] attribute. Needs its own
   [hidden] override since .favorites-filter's display:flex above has the
   same specificity as the UA stylesheet's [hidden] rule, and author rules
   win ties over UA rules regardless of source order. */
.favorites-filter[hidden] {
  display: none;
}

.favorites-filter select {
  padding: 0.35rem 0.5rem;
  border-radius: 6px;
  border: 1px solid var(--border);
  background: var(--panel-alt);
  color: var(--text);
  font-size: 0.85rem;
}

/* Mobile : navigation "liste <-> détail" plein écran, vidéo prioritaire. */
@media (max-width: 700px) {
  .app-header {
    flex-direction: column;
    align-items: stretch;
    padding: 0.6rem 0.8rem;
    gap: 0.5rem;
  }

  .advanced-filters {
    padding: 0 0.8rem;
  }

  .manual-viewer-dialog {
    width: 100vw;
    max-width: none;
    height: 100vh;
    border-radius: 0;
  }

  .app-header h1 {
    font-size: 1rem;
    width: 100%;
  }

  #search {
    font-size: 16px; /* evite le zoom auto au focus sur iOS */
    min-width: 0;
    width: 100%;
  }

  .favorites-filter,
  .count,
  .user-bar {
    width: 100%;
  }

  /* .app-header switches to column above: without this, align-items:stretch
     would size .burger-menu to the header's full width, and the dropdown's
     right:0 (relative to that stretched box) would then align with the
     *screen* edge instead of sitting just past the small burger button -
     still not an overflow, but worth pinning explicitly rather than relying
     on the auto-margin/stretch interaction being resolved the same way
     everywhere. */
  .burger-menu {
    align-self: flex-end;
  }

  .app-main {
    flex-direction: column;
  }

  .game-list {
    width: 100%;
    border-right: none;
  }

  .game-item {
    padding: 0.65rem 0.5rem;
    font-size: 0.95rem;
  }

  .game-item .thumb {
    width: 48px;
    height: 48px;
  }

  .back-btn {
    display: inline-block;
  }

  .details {
    padding: 1rem;
  }

  .media-video-col video,
  .titre-img {
    max-width: none;
  }

  .media-side-col {
    width: 200px;
  }

  /* Mode détail : la liste disparait, seul le panneau détail (vidéo) est visible. */
  .app-main:not(.detail-open) .details {
    display: none;
  }

  .app-main.detail-open .game-list {
    display: none;
  }

  .carousel-item {
    width: 110px;
  }

  .carousel-item img {
    width: 110px;
  }
}

/* Dialogue de jeu plein ecran sur mobile, portrait ET paysage - une simple
   max-width ne suffit pas : un telephone en paysage peut largement depasser
   700px de large tout en restant un petit ecran tactile, d'ou la seconde
   condition sur max-height+orientation. Legende clavier masquee : sur
   mobile seule la manette est pertinente. */
@media (max-width: 700px), (max-height: 500px) and (orientation: landscape) {
  .play-dialog {
    width: 100vw;
    max-width: none;
    height: 100vh;
    height: 100dvh;
    border-radius: 0;
  }

  .play-dialog-body {
    padding: 0.4rem;
  }

  .play-dialog-body canvas {
    width: 100%;
    height: 100%;
    max-width: 100%;
    max-height: 100%;
    aspect-ratio: 160 / 144;
    object-fit: contain;
  }

  .play-dialog-controls {
    padding: 0.4rem 0.6rem;
  }

  .play-keyboard-legend {
    display: none;
  }
}

/* --- Page d'accueil --- */

.home {
  max-width: 900px;
  margin: 0 auto;
}

.home-main {
  display: flex;
  flex-direction: column;
  gap: 2rem;
  padding: 1.5rem;
}

.home-actions {
  display: flex;
  align-items: center;
  align-self: flex-start;
  gap: 1rem;
  flex-wrap: wrap;
}

.library-link {
  align-self: flex-start;
  padding: 0.75rem 1.5rem;
  background: var(--accent);
  color: var(--accent-text);
  border: none;
  border-radius: 8px;
  text-decoration: none;
  font-family: inherit;
  font-weight: 600;
  font-size: 1.05rem;
  cursor: pointer;
}

.library-link:hover {
  opacity: 0.9;
}

.library-link:disabled {
  opacity: 0.5;
  cursor: not-allowed;
}

/* --- Page de choix de console (picker.html) --- */

.picker {
  max-width: 900px;
  margin: 0 auto;
}

.picker-main {
  padding: 2rem 1.5rem;
}

.picker-grid {
  display: flex;
  flex-wrap: wrap;
  gap: 1.5rem;
  justify-content: center;
}

.picker-card {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.75rem;
  width: 260px;
  padding: 1.5rem;
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 12px;
  text-decoration: none;
  color: inherit;
  transition: transform 0.15s ease, border-color 0.15s ease;
}

.picker-card:hover {
  transform: translateY(-2px);
  border-color: var(--accent);
}

/* Hauteur max plutot qu'un ratio fige, au cas ou une console future n'ait pas
   une photo parfaitement carree - evite de deformer/rogner l'image. Les slots
   ont la meme hauteur fixe que l'ancien max-height, statique ou en crossfade,
   pour que les 2 cas restent visuellement identiques au pixel pres. */
/* width/height explicites + align-items: stretch : un enfant .picker-crossfade
   n'a aucune taille intrinseque (ses seules images sont en position absolute,
   retirees du flux) donc il a besoin d'une largeur ET d'une hauteur deja
   resolues (100%) pour que ses images s'affichent. Ca ne change rien au rendu
   de l'image statique seule : elle garde sa propre largeur intrinseque et son
   max-height egal a celui du slot. */
.picker-photo-slot {
  display: flex;
  align-items: stretch;
  justify-content: center;
  width: 100%;
  height: 220px;
}

.picker-logo-slot {
  display: flex;
  align-items: stretch;
  justify-content: center;
  width: 100%;
  height: 60px;
}

.picker-photo {
  max-width: 100%;
  max-height: 220px;
  object-fit: contain;
}

.picker-logo {
  max-width: 80%;
  max-height: 60px;
  object-fit: contain;
}

/* Fondu enchaine en boucle entre 2 identites visuelles regionales d'une meme
   console (ex. NES/Famicom - voir picker.js's appendCrossfadeImage et
   screenscraper.js's fetchSystemAssets). Technique classique 2-images :
   superposees en absolute, meme animation, la 2e demarre a mi-cycle
   (animation-delay negatif) pour etre en opposition de phase avec la 1ere. */
.picker-crossfade {
  position: relative;
  width: 100%;
  height: 100%;
}

.picker-crossfade img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  max-width: 100%;
  object-fit: contain;
  animation: picker-crossfade 8s ease-in-out infinite;
}

.picker-crossfade img:nth-child(2) {
  animation-delay: -4s;
}

@keyframes picker-crossfade {
  0%, 40% { opacity: 1; }
  50%, 90% { opacity: 0; }
  100% { opacity: 1; }
}

@media (prefers-reduced-motion: reduce) {
  .picker-crossfade img {
    animation: none;
  }
  .picker-crossfade img:nth-child(2) {
    display: none;
  }
}

.picker-label {
  font-weight: 600;
  font-size: 1.1rem;
  text-align: center;
}

#favorites-sections {
  display: flex;
  flex-direction: column;
  gap: 2rem;
}

.favorites-section h2 {
  margin: 0 0 1rem;
  font-size: 1.1rem;
  color: var(--text-dim);
  font-weight: 600;
}

.carousel {
  display: flex;
  align-items: flex-end;
  gap: 1rem;
  overflow-x: auto;
  scroll-snap-type: x mandatory;
  padding-bottom: 0.5rem;
  -webkit-overflow-scrolling: touch;
}

.carousel-item {
  scroll-snap-align: start;
  flex: 0 0 auto;
  width: 140px;
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  text-decoration: none;
  color: var(--text);
}

/* Hauteur libre (pas de crop/deformation) : les jaquettes japonaises
   (~325x600) n'ont pas le meme format que USA/Europe (~494x640). */
.carousel-item img {
  width: 140px;
  height: auto;
  border-radius: 8px;
}

.carousel-item:hover img {
  outline: 2px solid var(--accent);
}

.carousel-item span {
  font-size: 0.8rem;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.carousel-empty {
  color: var(--text-dim);
}

.carousel-empty a {
  color: var(--accent);
}

/* --- Popup de telechargement des favoris (zip) --- */

.favorites-download-dialog {
  background: var(--panel);
  color: var(--text);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 1.5rem;
  max-width: 420px;
  width: 90vw;
}

.favorites-download-dialog::backdrop {
  background: rgba(0, 0, 0, 0.6);
}

.favorites-download-dialog h2 {
  margin: 0 0 1rem;
  font-size: 1.1rem;
}

.dialog-actions-row {
  display: flex;
  gap: 0.5rem;
}

.favorites-download-users {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  max-height: 40vh;
  overflow-y: auto;
  margin: 0.75rem 0;
}

.dialog-buttons {
  display: flex;
  gap: 0.5rem;
  justify-content: flex-end;
  margin-top: 1rem;
}

.dialog-buttons .library-link {
  font-size: 0.95rem;
  padding: 0.5rem 1rem;
}

.download-organize {
  display: flex;
  flex-direction: column;
  gap: 0.4rem;
  margin: 0.75rem 0;
  padding: 0.6rem 0.75rem;
  border: 1px solid var(--border);
  border-radius: 8px;
}

.download-organize legend {
  padding: 0 0.3rem;
  font-size: 0.85rem;
  color: var(--text-muted, var(--text));
}

.radio-label {
  display: flex;
  flex-direction: row;
  align-items: center;
  gap: 0.4rem;
}

.download-per-folder-label {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 0.5rem;
  margin: 0.75rem 0;
}

.download-per-folder-label input[type='number'] {
  width: 5rem;
}

.download-per-folder-label input:disabled {
  opacity: 0.5;
}

/* Section "Historique" de la page d'accueil (picker.html/picker.js) : deux
   onglets, Comparaison (radar materiel) et Historique (frise chronologique
   des modeles), qui partagent une meme palette de 8 slots de couleur fixes
   par console (son rang chronologique, pas son ordre de coche/decoche ou
   d'affichage - la couleur suit l'entite, jamais le rang, skill dataviz) :
   slot 1 = accent du site deja utilise partout ailleurs, slots 2-8 = les
   teintes categorielles restantes de la palette de reference, dans cet ordre
   precis. Cet ordre (et pas un autre, ex. aqua en slot 2) est celui qui passe
   la validation CVD avec l'accent du site en slot 1 - voir
   scripts/validate_palette.js du skill dataviz ; ne pas reordonner sans
   re-valider. */
.console-history {
  --series-1: var(--accent);
  --series-2: #008300;
  --series-3: #e87ba4;
  --series-4: #eda100;
  --series-5: #1baf7a;
  --series-6: #eb6834;
  --series-7: #4a3aa7;
  --series-8: #e34948;
  margin-top: 2.5rem;
  padding-top: 2rem;
  border-top: 1px solid var(--border);
}

.history-tabs {
  display: flex;
  justify-content: center;
  gap: 0.5rem;
  margin-bottom: 1.5rem;
}

.history-tab {
  padding: 0.5rem 1.1rem;
  border-radius: 999px;
  border: 1px solid var(--border);
  background: var(--panel-alt);
  color: var(--text-dim);
  font-size: 0.9rem;
  cursor: pointer;
}

.history-tab.active {
  background: var(--accent);
  border-color: var(--accent);
  color: var(--accent-text);
}

.history-panel h2 {
  text-align: center;
  font-size: 1.1rem;
  margin: 0 0 1rem;
}

.console-compare-hint {
  text-align: center;
  font-size: 0.85rem;
  color: var(--text-dim);
  margin: -0.5rem 0 1rem;
}

.console-compare-checkboxes {
  display: flex;
  justify-content: center;
  gap: 1.25rem;
  flex-wrap: wrap;
  margin-bottom: 1rem;
}

.console-compare-checkbox-label {
  display: flex;
  align-items: center;
  gap: 0.4rem;
  cursor: pointer;
}

.compare-swatch {
  width: 12px;
  height: 12px;
  border-radius: 50%;
  flex: none;
}

.console-compare-chart {
  display: flex;
  justify-content: center;
}

.compare-chart-svg {
  width: 100%;
  max-width: 360px;
  height: auto;
  /* Les etiquettes d'axes depassent legerement le viewBox (ex. "Couleurs" a
     gauche) - sans ca, le clip par defaut du SVG les tronque. */
  overflow: visible;
}

.compare-grid-ring {
  fill: none;
  stroke: var(--border);
  stroke-width: 1;
}

.compare-grid-axis {
  stroke: var(--border);
  stroke-width: 1;
}

.compare-axis-label {
  fill: var(--text-dim);
  font-size: 11px;
}

.compare-series-shape {
  fill-opacity: 0.12;
  stroke-width: 2;
}

.compare-series-1 {
  fill: var(--series-1);
  stroke: var(--series-1);
}

.compare-series-2 {
  fill: var(--series-2);
  stroke: var(--series-2);
}

.compare-series-3 {
  fill: var(--series-3);
  stroke: var(--series-3);
}

.compare-series-4 {
  fill: var(--series-4);
  stroke: var(--series-4);
}

.compare-series-5 {
  fill: var(--series-5);
  stroke: var(--series-5);
}

.compare-series-6 {
  fill: var(--series-6);
  stroke: var(--series-6);
}

.compare-series-7 {
  fill: var(--series-7);
  stroke: var(--series-7);
}

.compare-series-8 {
  fill: var(--series-8);
  stroke: var(--series-8);
}

/* Le swatch de legende (case a cocher) et les barres de la frise
   chronologique reutilisent les memes slots de couleur que les series du
   radar - background plutot que fill/stroke. */
.compare-swatch.compare-series-1,
.timeline-bar.compare-series-1 {
  background: var(--series-1);
}

.compare-swatch.compare-series-2,
.timeline-bar.compare-series-2 {
  background: var(--series-2);
}

.compare-swatch.compare-series-3,
.timeline-bar.compare-series-3 {
  background: var(--series-3);
}

.compare-swatch.compare-series-4,
.timeline-bar.compare-series-4 {
  background: var(--series-4);
}

.compare-swatch.compare-series-5,
.timeline-bar.compare-series-5 {
  background: var(--series-5);
}

.compare-swatch.compare-series-6,
.timeline-bar.compare-series-6 {
  background: var(--series-6);
}

.compare-swatch.compare-series-7,
.timeline-bar.compare-series-7 {
  background: var(--series-7);
}

.compare-swatch.compare-series-8,
.timeline-bar.compare-series-8 {
  background: var(--series-8);
}

.compare-series-dot {
  /* Anneau dans la couleur de fond (technique "surface ring" : le point
     reste lisible meme superpose a l'autre serie ou a un axe). */
  stroke: var(--bg);
  stroke-width: 2;
}

.console-compare-table {
  display: flex;
  justify-content: center;
  margin-top: 1.5rem;
  overflow-x: auto;
}

/* Le radar normalise chaque axe sur son propre maximum : ce tableau porte les
   vraies valeurs (MHz/Ko/pixels/couleurs), seule facon fiable de comparer des
   unites aussi differentes - voir le commentaire dans picker.js. */
.compare-values-table {
  border-collapse: collapse;
  font-size: 0.85rem;
}

.compare-values-table th,
.compare-values-table td {
  padding: 0.5rem 1rem;
  text-align: left;
  border-bottom: 1px solid var(--border);
}

.compare-values-table thead th {
  color: var(--text-dim);
  font-weight: 600;
}

.compare-values-table tbody th {
  color: var(--text-dim);
  font-weight: 500;
}

/* Frise chronologique (onglet "Historique") : une rangee par modele materiel,
   regroupees par console (consoles.js's hardwareHistory), avec la meme
   couleur par console que le radar de l'onglet Comparaison - voir le
   commentaire sur .console-history plus haut. */
.timeline-scroll {
  overflow-x: auto;
}

.timeline-chart {
  min-width: 560px;
  padding-top: 0.5rem;
}

.timeline-axis {
  position: relative;
  height: 1.4rem;
  margin-left: 170px;
  border-bottom: 1px solid var(--border);
}

.timeline-axis-tick {
  position: absolute;
  top: 0;
  transform: translateX(-50%);
  font-size: 0.75rem;
  color: var(--text-dim);
}

.timeline-plot-area {
  position: relative;
}

.timeline-gridlines {
  position: absolute;
  inset: 0;
  margin-left: 170px;
  pointer-events: none;
  z-index: 0;
}

.timeline-gridline {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 1px;
  background: var(--border);
  opacity: 0.6;
}

.timeline-group {
  position: relative;
  z-index: 1;
}

.timeline-group-title {
  font-size: 0.75rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.03em;
  color: var(--text-dim);
  margin: 1.2rem 0 0.3rem 170px;
}

.timeline-row {
  display: flex;
  align-items: center;
  min-height: 2.5rem;
}

.timeline-row-label {
  width: 170px;
  flex: none;
  padding-right: 0.75rem;
  text-align: right;
  font-size: 0.8rem;
  line-height: 1.25;
}

.timeline-model-name {
  display: block;
  color: var(--text);
}

.timeline-model-code {
  display: block;
  color: var(--text-dim);
  font-size: 0.7rem;
  font-variant-numeric: tabular-nums;
}

.timeline-row-track {
  position: relative;
  flex: 1;
  height: 100%;
}

.timeline-bar {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  height: 18px;
  border-radius: 9px;
  opacity: 0.85;
  outline-offset: 2px;
}

.timeline-bar:hover,
.timeline-bar:focus-visible {
  opacity: 1;
}

.timeline-bar-label {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  font-size: 0.72rem;
  color: var(--text-dim);
  white-space: nowrap;
  font-variant-numeric: tabular-nums;
}

.timeline-bar-label.start { right: calc(100% + 6px); }
.timeline-bar-label.end   { left: calc(100% + 6px); }

.timeline-bar-label.inside-start,
.timeline-bar-label.inside-end {
  color: var(--accent-text);
  font-weight: 600;
}

.timeline-bar-label.inside-start { left: 8px; }
.timeline-bar-label.inside-end   { right: 8px; }

.timeline-tooltip {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  transform: translateX(-50%) translateY(4px);
  background: var(--panel);
  border: 1px solid var(--border);
  border-radius: 8px;
  padding: 0.5rem 0.65rem;
  font-size: 0.78rem;
  line-height: 1.4;
  color: var(--text);
  white-space: nowrap;
  box-shadow: 0 4px 14px rgba(0, 0, 0, 0.18);
  opacity: 0;
  pointer-events: none;
  transition: opacity 0.12s ease, transform 0.12s ease;
  z-index: 5;
}

.timeline-bar:hover .timeline-tooltip,
.timeline-bar:focus-visible .timeline-tooltip {
  opacity: 1;
  transform: translateX(-50%) translateY(0);
}

.timeline-tooltip strong { display: block; margin-bottom: 0.15rem; }
.timeline-tooltip-dim { color: var(--text-dim); }

.timeline-table {
  margin-top: 2rem;
  overflow-x: auto;
}

.timeline-data-table {
  border-collapse: collapse;
  font-size: 0.85rem;
  width: 100%;
  min-width: 480px;
}

.timeline-data-table th,
.timeline-data-table td {
  padding: 0.5rem 0.75rem;
  text-align: left;
  border-bottom: 1px solid var(--border);
}

.timeline-data-table thead th {
  color: var(--text-dim);
  font-weight: 600;
}

.timeline-data-table tr.corrected td:last-child {
  color: var(--text);
  font-weight: 600;
}

.timeline-footnotes {
  margin-top: 1rem;
  padding: 0.75rem 1rem;
  background: var(--panel-alt);
  border-radius: 8px;
  font-size: 0.8rem;
  color: var(--text-dim);
  line-height: 1.5;
}

.timeline-footnotes p {
  margin: 0 0 0.4rem;
}

.timeline-footnotes p:last-child {
  margin-bottom: 0;
}
