@charset "UTF-8";
/* ==========================================================================
   sport-theme.css — Système de thème RPG du module Sport (§4.1 / §4.1bis)

   Se charge APRÈS theme.css (variables globales du site : --r-md, --shadow-*,
   --font, --ease). Tout est scopé sous .sport-app pour ne jamais fuiter sur
   le reste du site — le module reste sombre par défaut quel que soit le
   thème clair/sombre global choisi ailleurs sur Abonator (data-theme sur
   <html> ne pilote QUE le reste du site).

   Changer d'accent = changer data-sport-theme sur .sport-app. Ajouter un
   thème = ajouter un bloc [data-sport-theme="..."] ci-dessous, rien d'autre
   à toucher dans les composants.
   ========================================================================== */

.sport-app {
  --sp-bg: #05070c;
  --sp-surface: #0d1119;
  --sp-surface-2: #131a26;
  --sp-border: #1f2937;
  --sp-text: #e8ecf4;
  --sp-text-2: #93a0b4;
  --sp-text-3: #5b6779;

  /* Accent par défaut : Bleu électrique */
  --accent: #00A8FF;
  --accent-2: #7B2FFF;
  --glow: color-mix(in srgb, var(--accent) 45%, transparent);

  --sp-radius: var(--r-md, 14px);
  --sp-radius-lg: var(--r-lg, 18px);
  --sp-shadow: 0 10px 30px rgba(0,0,0,.45);
  --sp-ease-bounce: cubic-bezier(0.34, 1.56, 0.64, 1);
  --sp-ease-out: ease-out;
  --sp-dur-fast: 150ms;

  /* Le fond suit désormais le thème choisi, pas seulement les accents ponctuels (rang, barre d'XP,
     bordures) : même schéma que la tuile dashboard (home.css, .tile::after) — un voile radial doux
     dans le coin haut-droit, posé sur le fond sombre/clair de base. Demande explicite répétée
     ("le fond n'a pas changé de couleur alors que j'ai choisi le thème rose"). */
  background:
    radial-gradient(120% 90% at 100% 0%, color-mix(in srgb, var(--accent) 14%, transparent), transparent 60%),
    var(--sp-bg);
  color: var(--sp-text);
  font-family: var(--font, 'Inter', system-ui, sans-serif);
  min-height: 100vh;
}

/* --- Palettes d'accent (§4.1) --------------------------------------- */
.sport-app[data-sport-theme="bleuElectrique"] { --accent: #00A8FF; --accent-2: #7B2FFF; }
.sport-app[data-sport-theme="roseNeon"]       { --accent: #FF2E88; --accent-2: #FF6EC7; }
.sport-app[data-sport-theme="violetMonarque"] { --accent: #8B5CF6; --accent-2: #C084FC; }
.sport-app[data-sport-theme="ambre"]          { --accent: #FFB020; --accent-2: #FF7A00; }
.sport-app[data-sport-theme="vertToxique"]    { --accent: #39FF14; --accent-2: #00E5A0; }
.sport-app[data-sport-theme="rougeSang"]      { --accent: #FF3B3B; --accent-2: #FF8A3D; }
.sport-app[data-sport-theme="cyanGlacial"]    { --accent: #22E4E4; --accent-2: #5EEAD4; }

.sport-app { transition: background 300ms var(--sp-ease-out); }
.sport-app * { transition: border-color 300ms var(--sp-ease-out), box-shadow 300ms var(--sp-ease-out); }

/* --- Mode clair, accessibilité obligatoire (§4.1) -------------------- */
.sport-app[data-sport-mode="clair"] {
  --sp-bg: #f6f7f9;
  --sp-surface: #ffffff;
  --sp-surface-2: #f0f2f6;
  --sp-border: #dde2ea;
  --sp-text: #0d1220;
  --sp-text-2: #4b5670;
  --sp-text-3: #7a8499;
  --sp-shadow: 0 4px 16px rgba(13,18,32,.08);
}

/* --- Thèmes déblocables par progression (ex : Rouge sang dès rang A) --- */
.sport-theme-locked { filter: grayscale(1); opacity: .4; pointer-events: none; position: relative; }
.sport-theme-locked::after {
  content: attr(data-unlock-hint);
  position: absolute; inset: auto 0 -18px 0; text-align: center;
  font-size: .65rem; color: var(--sp-text-3);
  /* "Rang A" retombait à la ligne dans les 32px de la pastille et débordait sur la ligne de
     pastilles suivante (gap trop faible côté conteneur, corrigé aussi dans sport/index.html) —
     white-space:nowrap règle le retour à la ligne, le row-gap élargi règle le chevauchement. */
  white-space: nowrap;
}

/* --- prefers-reduced-motion (§7, obligatoire) ------------------------ */
@media (prefers-reduced-motion: reduce) {
  .sport-app *, .sport-app *::before, .sport-app *::after {
    animation-duration: .001ms !important;
    animation-iteration-count: 1 !important;
    transition-duration: .001ms !important;
    scroll-behavior: auto !important;
  }
}
.sport-app[data-reduced-motion="true"] * {
  animation-duration: .001ms !important;
  transition-duration: .001ms !important;
}

/* ==========================================================================
   Composants de base
   ========================================================================== */

.sp-card {
  background: var(--sp-surface);
  border: 1px solid var(--sp-border);
  border-radius: var(--sp-radius);
  padding: 18px;
  box-shadow: var(--sp-shadow);
}

.sp-gate { max-width: 420px; margin: 15vh auto; text-align: center; padding: 32px 24px; }
.sp-muted { color: var(--sp-text-2); font-size: .9rem; }

.sp-btn {
  display: inline-flex; align-items: center; justify-content: center; gap: 8px;
  padding: 12px 20px; border-radius: var(--sp-radius); border: 1px solid transparent;
  font-weight: 600; font-size: .95rem; cursor: pointer;
  transition: transform var(--sp-dur-fast) var(--sp-ease-bounce), box-shadow var(--sp-dur-fast);
}
.sp-btn:active { transform: scale(.97); }
.sp-btn-primary { background: linear-gradient(135deg, var(--accent), var(--accent-2)); color: #05070c; }
.sp-btn-primary:hover { box-shadow: 0 0 0 4px var(--glow); }
.sp-btn-ghost { background: transparent; border-color: var(--sp-border); color: var(--sp-text); }
.sp-btn-danger-soft { background: transparent; border-color: var(--sp-border); color: var(--sp-text-2); font-size: .85rem; }

/* --- Photo de profil dans l'onboarding (même patron que .avatar-row/.avatar-preview de hub.css) */
.sp-onboarding-avatar { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; margin: 16px 0 20px; }
.sp-onboarding-avatar__preview {
  width: 56px; height: 56px; border-radius: 50%; flex-shrink: 0;
  background: var(--sp-surface-2) center/cover no-repeat;
  border: 1px solid var(--sp-border);
  display: flex; align-items: center; justify-content: center;
  font-size: 1.4rem; color: var(--sp-text-2);
}

/* --- Fenêtre système (notifications [SYSTÈME] / [NOTIFICATION]) ------ */
.sp-window {
  background: var(--sp-surface-2);
  border: 1px solid var(--sp-border);
  border-radius: var(--sp-radius);
  padding: 14px 16px;
  position: relative;
  overflow: hidden;
  animation: sp-window-in 320ms var(--sp-ease-out);
}
.sp-window::before {
  content: ''; position: absolute; inset: 0 0 auto 0; height: 2px;
  background: linear-gradient(90deg, transparent, var(--accent), transparent);
  animation: sp-sweep 900ms var(--sp-ease-out);
}
.sp-window__tag { color: var(--accent); font-weight: 700; font-size: .72rem; letter-spacing: .06em; text-transform: uppercase; }
.sp-window__body { margin-top: 4px; font-size: .9rem; color: var(--sp-text); }

@keyframes sp-window-in {
  from { opacity: 0; transform: scale(.95); }
  to   { opacity: 1; transform: scale(1); }
}
@keyframes sp-sweep {
  from { transform: translateX(-100%); }
  to   { transform: translateX(100%); }
}

/* --- Panneau de statut du chasseur / barre XP ------------------------ */
.sp-status {
  display: flex; flex-direction: column; gap: 14px;
}
.sp-status__top { display: flex; justify-content: space-between; align-items: center; gap: 12px; }

/* Identité (photo + pseudo + niveau) à gauche, rang mis en valeur à droite (demande explicite). */
.sp-status__identity { display: flex; align-items: center; gap: 12px; min-width: 0; }
.sp-status__avatar {
  flex: none; width: 44px; height: 44px; border-radius: 50%;
  background: var(--sp-surface-2) center/cover no-repeat;
  border: 2px solid var(--accent);
  display: flex; align-items: center; justify-content: center;
  font-size: 1.3rem; overflow: hidden;
}
.sp-status__who { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.sp-status__pseudo {
  font-size: .85rem; font-weight: 600; color: var(--sp-text-2, inherit);
  white-space: nowrap; overflow: hidden; text-overflow: ellipsis;
}
.sp-level { font-size: 1.6rem; font-weight: 800; line-height: 1.1; }

.sp-rank {
  flex: none; font-size: 1.5rem; font-weight: 800; letter-spacing: .04em;
  color: var(--accent); border: 2px solid var(--accent); border-radius: var(--r-full, 999px);
  padding: 6px 18px;
  text-shadow: 0 0 12px var(--glow);
  box-shadow: 0 0 16px var(--glow);
}

.sp-xpbar { position: relative; height: 14px; border-radius: var(--r-full, 999px);
  background: var(--sp-surface-2); border: 1px solid var(--sp-border); overflow: hidden; }
.sp-xpbar__fill {
  position: absolute; inset: 0 auto 0 0; height: 100%; width: 0%;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  border-radius: inherit;
  transition: width 700ms var(--sp-ease-bounce);
}
.sp-xpbar__fill.is-filling { box-shadow: 0 0 12px var(--glow); }

/* --- Aura du multiplicateur ------------------------------------------ */
.sp-multiplier {
  display: flex; align-items: center; gap: 10px; padding: 10px 14px;
  border-radius: var(--sp-radius); border: 1px solid var(--sp-border);
  background: radial-gradient(120px 60px at 0% 50%, var(--glow), transparent);
}
.sp-multiplier__value { font-size: 1.3rem; font-weight: 800; color: var(--accent); }
.sp-multiplier--pulse { animation: sp-pulse 1.8s ease-in-out infinite; }
.sp-multiplier--danger { animation: sp-flicker 1.4s ease-in-out infinite; }

@keyframes sp-pulse {
  0%, 100% { box-shadow: 0 0 0 0 var(--glow); }
  50%      { box-shadow: 0 0 20px 4px var(--glow); }
}
@keyframes sp-flicker {
  0%, 100% { opacity: 1; }
  45%      { opacity: .55; }
  55%      { opacity: .85; }
}

/* --- Gain d'XP flottant (§4.1bis) ------------------------------------ */
.sp-xp-float {
  position: fixed; pointer-events: none; z-index: 999;
  font-weight: 800; font-size: 1.1rem; color: var(--accent);
  animation: sp-xp-float 600ms var(--sp-ease-out) forwards;
}
@keyframes sp-xp-float {
  0%   { opacity: 0; transform: translateY(0) scale(.8); }
  20%  { opacity: 1; transform: translateY(-10px) scale(1.15); }
  100% { opacity: 0; transform: translateY(-40px) scale(1); }
}

/* --- Anneaux (calories / macros / hydratation) ------------------------
   Agrandis (84px → 132px) et remontés juste sous la barre de niveau (cf. index.html) : à cette
   taille et cette place, ils se lisent d'un coup d'œil au lieu de se noyer plus bas dans la page. */
.sp-rings { display: flex; gap: 16px; justify-content: space-around; flex-wrap: wrap; }
.sp-ring { --pct: 0; width: 84px; height: 84px; border-radius: 50%; position: relative;
  background: conic-gradient(var(--accent) calc(var(--pct) * 1%), var(--sp-surface-2) 0);
  display: flex; align-items: center; justify-content: center;
  transition: background 500ms var(--sp-ease-bounce);
}
.sp-ring::before { content: ''; position: absolute; inset: 8px; border-radius: 50%; background: var(--sp-surface); }
.sp-ring__label { position: relative; font-size: .78rem; font-weight: 700; text-align: center; }

.sp-rings--lg .sp-ring { width: 132px; height: 132px; }
.sp-rings--lg .sp-ring::before { inset: 12px; }
.sp-rings--lg .sp-ring__label { font-size: 1rem; }
@media (max-width: 420px) {
  .sp-rings--lg .sp-ring { width: 96px; height: 96px; }
  .sp-rings--lg .sp-ring__label { font-size: .85rem; }
}

/* --- Quêtes ------------------------------------------------------------ */
.sp-quest { display: flex; align-items: center; gap: 10px; padding: 10px 12px;
  border-radius: var(--sp-radius); border: 1px solid var(--sp-border); background: var(--sp-surface-2);
  transition: transform 180ms var(--sp-ease-bounce), background 180ms var(--sp-ease-out), opacity 300ms var(--sp-ease-out); }
.sp-quest:hover { transform: translateY(-1px); background: color-mix(in srgb, var(--sp-surface-2) 80%, var(--accent) 6%); }
.sp-quest.is-done { opacity: .55; text-decoration: line-through; }
.sp-quest__progress { flex: 1; height: 6px; border-radius: 4px; background: var(--sp-border); overflow: hidden; }
/* La barre passait d'une largeur à l'autre d'un coup (aucune transition déclarée) : c'est ce qui
   donnait l'impression qu'elle « sautait » de vide à remplie. Même courbe que la barre d'XP. */
.sp-quest__progress > span {
  display: block; height: 100%;
  background: linear-gradient(90deg, var(--accent), var(--accent-2));
  border-radius: inherit;
  transition: width 700ms var(--sp-ease-bounce);
}

/* --- Badges -------------------------------------------------------------*/
.sp-badge { width: 56px; height: 56px; border-radius: 12px; display: flex; align-items: center;
  justify-content: center; background: var(--sp-surface-2); border: 1px solid var(--sp-border); font-size: 1.4rem; }
.sp-badge--bronze { border-color: #cd7f32; }
.sp-badge--argent { border-color: #c0c0c0; }
.sp-badge--or      { border-color: #ffd700; }
.sp-badge--platine  { border-color: #e5e4e2; }
/* Badge verrouillé : même traitement visuel que les séances du Grimoire pas encore débloquées
   (grisé + opacité réduite), pour rester cohérent avec un pattern déjà connu de l'utilisateur. */
.sp-badge.is-locked { filter: grayscale(1); opacity: .4; }

/* --- Catalogue complet des badges (20 familles × 4 paliers), onglet Profil --------------------
   Avant, seuls les badges débloqués étaient affichés : un compte neuf voyait une grille vide.
   Maintenant chaque famille est une ligne : nom + les 4 paliers (verrouillés grisés). */
.sp-badges-grid { display: flex; flex-direction: column; gap: 16px; }
.sp-badge-famille { display: flex; align-items: center; gap: 16px; flex-wrap: wrap; }
.sp-badge-famille__entete { display: flex; align-items: center; gap: 8px; flex: 0 0 190px; min-width: 150px; }
.sp-badge-famille__icone { font-size: 1.3rem; }
.sp-badge-famille__nom { font-size: .88rem; color: var(--sp-text-2); }
.sp-badge-famille__paliers { display: flex; gap: 10px; flex-wrap: wrap; }

/* --- Boss : barre de vie ------------------------------------------------ */
.sp-boss-hp { height: 20px; border-radius: var(--r-full, 999px); background: var(--sp-surface-2);
  border: 1px solid var(--sp-border); overflow: hidden; position: relative; }
.sp-boss-hp__fill { height: 100%; background: linear-gradient(90deg, #ef4444, #f59e0b); transition: width 500ms var(--sp-ease-out); }

/* --- Overlay plein écran (level up, rang, bilan de cycle) -------------- */
.sp-overlay {
  position: fixed; inset: 0; z-index: 1000; display: flex; align-items: center; justify-content: center;
  background: rgba(2,4,8,.82); backdrop-filter: blur(2px);
  animation: sp-overlay-in 250ms var(--sp-ease-out);
}
.sp-overlay[hidden] { display: none; }
.sp-overlay__panel { max-width: 480px; width: min(92vw, 480px); text-align: center; }
@keyframes sp-overlay-in { from { opacity: 0; } to { opacity: 1; } }

/* --- Onglets (réutilise le vocabulaire .hub-tab/.hub-panel du site) --- */
.sp-tabs { display: flex; gap: 6px; overflow-x: auto; padding-bottom: 4px; }
.sp-tab { flex: none; padding: 8px 14px; border-radius: var(--r-full, 999px); border: 1px solid var(--sp-border);
  background: transparent; color: var(--sp-text-2); font-size: .85rem; cursor: pointer; }
.sp-tab.is-active { background: var(--sp-surface-2); color: var(--sp-text); border-color: var(--accent); }
.sp-panel { display: none; }
/* Les cartes d'un panneau étaient collées les unes aux autres : le `gap` de .sp-main ne s'applique
   qu'à ses enfants directs (onglets + panneaux), jamais aux .sp-card imbriquées dans un panneau
   affiché en `display:block`. On repasse chaque panneau en colonne flex avec son propre gap. */
.sp-panel.is-active { display: flex; flex-direction: column; gap: 16px; }

/* --- Layout général ----------------------------------------------------- */
.sp-main { max-width: 720px; margin: 0 auto; padding: 16px 16px 100px; display: flex; flex-direction: column; gap: 16px; }

/* --- Onboarding : plein écran façon tableau de bord sur grand écran ------
   .sp-main plafonnait tout (onboarding compris) à 720px quelle que soit la largeur d'écran : sur
   desktop, la création de profil restait une colonne étroite perdue au milieu d'un écran vide,
   alors que le reste d'Abonator (accueil, hub) occupe tout l'espace disponible en grille. On sort
   l'onboarding de ce plafond et on éclate ses 3 blocs (Profil physique / Activité & objectif /
   Premier cycle) en vraies colonnes côte à côte au lieu d'un empilement vertical unique. */
@media (min-width: 900px) {
  #onboardingScreen.sp-main {
    max-width: 1320px;
    padding: 40px clamp(24px, 4vw, 64px) 64px;
  }
  #onboardingScreen .sp-card {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px;
    align-items: start;
  }
  #onboardingScreen .sp-card > * { margin-top: 0; } /* neutralise .sp-card > * + * (empilement vertical) */
  #onboardingScreen .sp-card > h1,
  #onboardingScreen .sp-card > p.sp-muted {
    grid-column: 1 / -1;
  }
  #onboardingScreen form#onboardingForm {
    grid-column: 1 / -1;
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 20px;
    /* align-items par défaut (stretch) : les 3 fieldsets s'alignent à hauteur égale, comme des
       tuiles de tableau de bord, plutôt que de suivre chacun la hauteur de son propre contenu. */
  }
  #onboardingScreen form#onboardingForm > p.sp-muted,
  #onboardingScreen form#onboardingForm > button {
    grid-column: 1 / -1;
  }
}

/* --- App principale : même traitement grand écran que l'onboarding -------
   Idem que ci-dessus mais pour #appMain : chaque onglet (Profil compris) restait une colonne unique
   plafonnée à 720px, avec un grand vide de part et d'autre sur un écran large — visible notamment
   sur l'onglet Profil, où la carte Pesée se retrouvait décentrée dans tout cet espace inutilisé. Les
   cartes de l'onglet actif passent en grille façon tableau de bord ; en dessous de 900px, l'empilement
   mobile d'origine est inchangé. */
@media (min-width: 900px) {
  #appMain.sp-main {
    max-width: 1320px;
    padding: 24px clamp(24px, 4vw, 64px) 100px;
  }
  #appMain .sp-panel.is-active {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(360px, 1fr));
    align-items: start;
    gap: 20px;
  }
  /* Carte qui doit occuper toute la largeur de la grille (ex : Badges, "les badge prenne toute la
     largeurs" demandé explicitement) au lieu de rester limitée à une seule colonne de ~360px. */
  #appMain .sp-panel.is-active .sp-card--full { grid-column: 1 / -1; }
}

/* --- Regroupement de cartes qui doivent rester empilées dans une même colonne du dashboard -----
   .sp-panel.is-active en grille flotte les cartes ligne par ligne : pour garder "recap joueur" et
   "anneaux du jour" toujours l'un sous l'autre (demande explicite), on les enveloppe dans un seul
   item de grille qui gère lui-même son empilement vertical. */
.sp-dash-left { display: flex; flex-direction: column; gap: 16px; }

/* --- Carte mise en avant (ex : "Aujourd'hui" en tête de l'onglet Planning) --------------------- */
.sp-card--accent { border-color: var(--accent); box-shadow: 0 0 0 1px var(--accent) inset, var(--sp-shadow); }

/* --- Champs de saisie « chiffre clé » (poids, masse grasse) --------------
   Un input numérique isolé qui affiche une valeur centrale (le poids qu'on suit chaque semaine)
   se lisait comme n'importe quel champ de formulaire, aligné à gauche — recentré et mis en avant
   pour qu'il se distingue des champs de configuration classiques. */
.sp-input-centre { text-align: center; font-size: 1.2rem; font-weight: 700; }

/* --- Groupes : carte de membre (niveau, rang, XP et séances du jour) -----
   cacheStats était écrit une fois à zéro et jamais mis à jour : l'onglet Groupes n'affichait que le
   nom du groupe. Pensé dès maintenant pour être repris tel quel dans le futur widget plein écran du
   mode display (écran dual-profil compét en couple, cf. sport-page.js `renderMembresGroupe`). */
.sp-group-membres { display: flex; flex-direction: column; gap: 8px; }
.sp-group-membre {
  display: flex; align-items: center; gap: 12px; padding: 10px 12px;
  border-radius: var(--sp-radius); border: 1px solid var(--sp-border); background: var(--sp-surface-2);
}
.sp-group-membre.is-me { border-color: var(--accent); box-shadow: 0 0 0 1px color-mix(in srgb, var(--accent) 40%, transparent); }
/* Couleur de thème personnelle du membre (Profil > Thème, republiée via cacheStats.couleurAccent) :
   remplace l'accent générique par sa propre couleur, visible même en dehors de sa carte "moi". */
.sp-group-membre[style*="--accent-membre"] { border-color: var(--accent-membre); }
.sp-group-membre[style*="--accent-membre"] .sp-group-membre__niveau { color: var(--accent-membre); }
.sp-group-membre__avatar {
  width: 42px; height: 42px; border-radius: 50%; flex-shrink: 0;
  background: var(--sp-surface-3, var(--sp-surface-2)) center/cover no-repeat;
  border: 1px solid var(--sp-border);
  display: flex; align-items: center; justify-content: center;
  font-size: 1.15rem;
}
.sp-group-membre__avatar--vide { color: var(--sp-text-2); }
.sp-group-membre__corps { display: flex; flex-direction: column; gap: 4px; flex: 1; min-width: 0; }
.sp-group-membre__head { display: flex; align-items: center; gap: 8px; min-width: 0; flex: 1; }
.sp-group-membre__nom { font-weight: 700; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.sp-group-membre__niveau { font-weight: 800; font-size: 1.05rem; color: var(--accent); white-space: nowrap; }
.sp-group-membre__stats { display: flex; flex-direction: column; gap: 2px; font-size: .78rem; color: var(--sp-text-2); text-align: right; white-space: nowrap; }

/* --- Grimoire : encart "à débloquer" (teaser, non dépliable) et pied de carte "Valider" ---------
   Avant correctif, une séance verrouillée utilisait le même <details> complet qu'une séance
   débloquée, juste grisé : le contenu (quête, échauffement, corps, coach, objectif) restait
   présent et dépliable au clic. `.sp-grimoire-teaser` est un simple encart, jamais un <details>. */
.sp-grimoire-teaser {
  display: flex; align-items: center; justify-content: space-between; gap: 10px;
  opacity: .6;
}
.sp-grimoire-teaser__nom { font-weight: 700; }
.sp-grimoire-valider { display: flex; justify-content: flex-end; padding-top: 4px; border-top: 1px solid var(--sp-border); }

/* --- Rythme vertical interne des cartes et formulaires -------------------
   Sans ça, titres, paragraphes, champs et boutons se touchaient : le module n'avait aucune
   règle d'espacement sur ses propres éléments de formulaire (seul le layout externe était géré). */
.sp-card > * + * { margin-top: 12px; }
.sp-card > h2, .sp-card > h3 { margin: 0; font-size: 1.05rem; letter-spacing: .01em; }
.sp-card > h2 + p, .sp-card > h3 + p { margin-top: 6px; }

.sp-card form { display: flex; flex-direction: column; gap: 12px; }
.sp-card form > * { margin-top: 0; }

.sp-card label { display: block; font-size: .9rem; color: var(--sp-text-2); }
.sp-card label > input:not([type="checkbox"]),
.sp-card label > select {
  display: block; width: 100%; margin-top: 6px; padding: 10px 12px;
  border-radius: var(--sp-radius); border: 1px solid var(--sp-border);
  background: var(--sp-surface-2); color: var(--sp-text); font-size: .95rem;
  transition: border-color var(--sp-dur-fast);
}
.sp-card label > input:focus, .sp-card label > select:focus {
  outline: none; border-color: var(--accent); box-shadow: 0 0 0 3px var(--glow);
}
.sp-card label > input[type="checkbox"] { margin-right: 8px; accent-color: var(--accent); }

.sp-card fieldset {
  border: 1px solid var(--sp-border); border-radius: var(--sp-radius);
  padding: 16px; margin: 0; display: flex; flex-direction: column; gap: 12px;
}
.sp-card legend { padding: 0 8px; font-weight: 600; color: var(--sp-text); font-size: .92rem; }

/* Espacement des listes rendues dynamiquement (quêtes, séances, groupes, records...) */
.sp-quest + .sp-quest { margin-top: 8px; }

/* --- Conteneurs de graphiques ------------------------------------------
   Chart.js en mode responsive s'étire à la hauteur de son parent : sans conteneur borné, le radar
   débordait sur toute la page et ses graduations s'empilaient en colonne. */
.sp-chart { position: relative; height: 220px; width: 100%; }
.sp-chart--carre { height: 300px; max-width: 340px; margin: 0 auto; }
.sp-chart canvas { position: absolute; inset: 0; }

/* --- Grimoire ----------------------------------------------------------- */
.sp-quest > summary { list-style: none; }
.sp-quest > summary::-webkit-details-marker { display: none; }
.sp-quest > summary::after { content: '\25BE'; color: var(--sp-text-2); margin-left: 8px; }
details[open] > summary::after { content: '\25B4'; }
.sp-quest ul { padding-left: 18px; }
.sp-quest li { margin: 2px 0; }

/* Messages d'erreur inline (statuts de formulaire) */
.sp-muted.error { color: #ff6b6b; }

/* ==========================================================================
   Système d'animations (§4.1bis — « chaque interaction doit avoir un retour »)
   Généralisé à partir de l'animation d'ouverture du grimoire.
   Tout est désactivé par prefers-reduced-motion (bloc en haut de fichier).
   ========================================================================== */

/* Apparition d'un élément de liste (quêtes, séances, aliments, groupes...). */
@keyframes sp-fade-up {
  from { opacity: 0; transform: translateY(6px); }
  to   { opacity: 1; transform: translateY(0); }
}
.sp-pop { animation: sp-fade-up 260ms var(--sp-ease-bounce) both; }

/* Décalage en cascade : les listes se déplient au lieu d'apparaître d'un bloc. */
.sp-pop:nth-child(1) { animation-delay: 0ms; }
.sp-pop:nth-child(2) { animation-delay: 40ms; }
.sp-pop:nth-child(3) { animation-delay: 80ms; }
.sp-pop:nth-child(4) { animation-delay: 120ms; }
.sp-pop:nth-child(5) { animation-delay: 160ms; }
.sp-pop:nth-child(n+6) { animation-delay: 200ms; }

/* Changement d'onglet : le panneau entrant glisse au lieu d'apparaître sec. */
.sp-panel.is-active { animation: sp-fade-up 300ms var(--sp-ease-out) both; }

/* Onglets : soulignement animé de l'onglet actif. */
.sp-tab { position: relative; transition: color 180ms var(--sp-ease-out), background 180ms var(--sp-ease-out); }
.sp-tab::after {
  content: ''; position: absolute; left: 12px; right: 12px; bottom: 2px; height: 2px;
  background: var(--accent); border-radius: 2px;
  transform: scaleX(0); transform-origin: center;
  transition: transform 260ms var(--sp-ease-bounce);
}
.sp-tab.is-active::after { transform: scaleX(1); }

/* Cartes : légère élévation au survol, pour signaler qu'elles sont vivantes. */
.sp-card { transition: transform 200ms var(--sp-ease-out), box-shadow 200ms var(--sp-ease-out); }
.sp-card:hover { box-shadow: 0 14px 36px rgba(0,0,0,.5); }

/* Boutons : retour tactile net (l'échelle seule passait inaperçue sur les boutons fantômes). */
.sp-btn { position: relative; overflow: hidden; }
.sp-btn-ghost:hover { border-color: var(--accent); color: var(--accent); }
.sp-btn:disabled { opacity: .5; cursor: not-allowed; transform: none; }

/* Champs de saisie : la bordure s'anime vers l'accent au focus. */
.sp-card label > input, .sp-card label > select {
  transition: border-color 200ms var(--sp-ease-out), box-shadow 200ms var(--sp-ease-out),
              background 200ms var(--sp-ease-out);
}

/* Anneaux (calories / macros / hydratation) : le remplissage devient progressif. */
.sp-ring { transition: background 700ms var(--sp-ease-bounce); }

/* Grimoire : dépliage fluide du détail d'une séance. */
details > summary { transition: color 180ms var(--sp-ease-out); }
details > summary:hover { color: var(--accent); }
details[open] > summary ~ * { animation: sp-fade-up 240ms var(--sp-ease-out) both; }

/* Quête accomplie : impulsion verte brève, puis retour à l'état barré. */
@keyframes sp-quest-done {
  0%   { box-shadow: 0 0 0 0 rgba(57,255,20,.5); }
  40%  { box-shadow: 0 0 18px 4px rgba(57,255,20,.35); }
  100% { box-shadow: 0 0 0 0 rgba(57,255,20,0); }
}
.sp-quest.is-done { animation: sp-quest-done 900ms var(--sp-ease-out); }

/* Badge fraîchement débloqué. */
@keyframes sp-badge-in {
  0%   { opacity: 0; transform: scale(.4) rotate(-12deg); }
  70%  { transform: scale(1.12) rotate(4deg); }
  100% { opacity: 1; transform: scale(1) rotate(0); }
}
.sp-badge { animation: sp-badge-in 420ms var(--sp-ease-bounce) both; }
.sp-badge:hover { transform: translateY(-2px) scale(1.05); transition: transform 200ms var(--sp-ease-bounce); }
