/* ============================================================
   Skydex — app.css : coquille SPA, navigation, vues.
   Typo (convention actuelle des maquettes) :
   Barlow = cartes / viseur / hangar · Inter = paywall / profil.
   ============================================================ */

* { box-sizing: border-box; margin: 0; -webkit-tap-highlight-color: transparent; }
html, body { height: 100%; }
body {
  background: #000; color: var(--txt);
  font-family: 'Barlow', sans-serif;
  display: flex; justify-content: center;
  -webkit-font-smoothing: antialiased;
}
/* le "téléphone" : plein écran mobile, cadré 430px sur desktop */
#app { position: relative; width: 100%; max-width: 430px; height: 100dvh; overflow: hidden; background: var(--bg-1); }

.hidden { display: none !important; }

.view { position: absolute; inset: 0; overflow-y: auto; padding-bottom: 96px; }
#view-scan { overflow: hidden; padding-bottom: 0; }

/* ============ NAVIGATION (4 onglets, Scan à DROITE et proéminent) ============
   Passée de 3 à 4 onglets le 4 août 2026 : le radar devient une destination.
   ⚠️ Le Scan n'est plus central et ne DÉBORDE PLUS au-dessus de la barre.
   Avec 4 onglets, un bouton central tomberait entre deux ; et un rond qui
   déborde au bord droit de l'écran entrerait en conflit avec l'arrondi de
   l'écran et la zone sûre du bas sur iPhone. Il reste nettement plus gros et
   plus contrasté que les trois autres, donc toujours le geste évident.
   Les onglets se partagent l'espace restant à parts égales (flex: 1), ce qui
   évite la largeur fixe de 84 px qui débordait à 4 sur un écran de 375 px. */
.nav {
  position: absolute; bottom: 0; left: 0; right: 0; z-index: 20;
  display: flex; align-items: flex-end; justify-content: space-between; gap: 2px;
  background: rgba(10,14,22,.92); backdrop-filter: blur(10px);
  border-top: 1px solid #1c2940; padding: 10px 10px calc(14px + env(safe-area-inset-bottom));
}
.nav .tab { text-align: center; font-size: .56rem; letter-spacing: .06em; text-transform: uppercase;
  color: #56637a; cursor: pointer; flex: 1; min-width: 0; padding-bottom: 2px; }
.nav .tab svg { width: 22px; height: 22px; stroke: currentColor; fill: none; stroke-width: 1.8; margin-bottom: 2px; }
.nav .tab.on { color: var(--blue-soft); }
/* ⚠️ L'onglet Scan occupe une case de MÊME LARGEUR que les trois autres
   (flex: 1 hérité, aucune exception ici) : les quatre centres sont donc
   équidistants et la barre est régulière. Une première version le mettait en
   `flex: 0 0 auto`, ce qui rétrécissait sa case à 52 px et le collait au bord
   droit — la position paraissait « bizarre » sans qu'on voie pourquoi.
   Le Scan se distingue par la TAILLE de son rond, pas par sa place. */
/* ⚠️ LE ROND DÉBORDE AU-DESSUS DE LA BARRE (~30 %, demande de l'auteur du
   5 août 2026) : la bordure du menu passe DERRIÈRE le cercle, comme un bouton
   d'appareil photo posé sur le bord. Deux effets voulus : le Scan est mis en
   évidence, et la barre perd de la hauteur (le débordement sort le cercle du
   calcul de hauteur du flex, ce sont les trois autres onglets qui la fixent).
   La marge se décompose ainsi : 10px annulent le padding-top de .nav, et 16px
   passent au-dessus de la bordure — 16/52 ≈ 31 % du cercle.
   Le fond du cercle est OPAQUE : c'est lui qui « coupe » visuellement la
   bordure, aucun autre artifice n'est nécessaire. Ceci REVIENT partiellement
   sur la décision de la veille (« ne déborde plus ») : arbitrage esthétique de
   l'auteur, assumé. */
.nav .tab .scanbtn {
  width: 52px; height: 52px; border-radius: 50%; background: #12203a; border: 2px solid #2b62c4;
  display: flex; align-items: center; justify-content: center; margin: -26px auto 2px;
  box-shadow: 0 4px 14px rgba(0,0,0,.45);
}
.nav .tab.on .scanbtn { background: #1a3050; }
.nav .tab .scanbtn svg { width: 26px; height: 26px; margin: 0; stroke: #cfe0f5; }

/* ============ VUE SCAN (viseur) ============ */
#view-scan { background: #0b0f16; }
#cam { position: absolute; inset: 0; width: 100%; height: 100%; object-fit: cover; }
.scrim { position: absolute; inset: 0; pointer-events: none;
  background: linear-gradient(180deg, rgba(0,0,0,.45) 0%, transparent 22%, transparent 68%, rgba(0,0,0,.55) 100%); }

#gate { position: absolute; inset: 0; z-index: 10; background: radial-gradient(ellipse at 50% 35%, #16233a, #070b12 75%);
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 18px; padding: 32px; text-align: center; }
#gate .logo { font-family: 'Barlow Condensed'; font-style: italic; font-weight: 800; font-size: 2.4rem; letter-spacing: .08em; }
#gate .logo b { color: var(--blue-soft); }
#gate p { opacity: .6; font-size: .9rem; max-width: 300px; line-height: 1.5; }
#activate { appearance: none; border: 0; border-radius: 16px; background: #2b62c4; color: #fff;
  font-size: 1.1rem; font-weight: 600; padding: 16px 34px; cursor: pointer; font-family: inherit; }

.hud { position: absolute; inset: 0; }

/* ⚠️ pointer-events: none EST INDISPENSABLE, ce n'est pas une optimisation.
   .compass est en absolute pleine largeur ET vient APRÈS .topbtns dans le DOM :
   son bloc .deg (le grand « 90° », un div donc pleine largeur malgré son texte
   centré) se peignait par-dessus les deux boutons ronds et avalait les clics.
   Il ne restait qu'un liseré de ~4 px cliquable en bas de chaque bouton, donc
   le radar ET le panneau de debug étaient inatteignables au doigt — bug signalé
   sur téléphone le 4 août 2026, et invisible en test souris précis.
   Rien dans le ruban boussole n'est interactif : il n'affiche que des valeurs. */
.compass { position: absolute; top: 0; left: 0; right: 0; padding: 46px 0 8px; text-align: center;
  pointer-events: none; }
/* ============ FINESSE DU VISEUR — v2 RETENUE (5 août 2026) ============
   Histoire en trois temps, à connaître avant de retoucher : v1 fine mais
   bleutée semi-transparente (langage du radar) → REJETÉE par l'auteur →
   restaurée → puis redemandée avec LE correctif : mêmes tailles fines, traits
   BLANCS ET QUASI OPAQUES, et réticule remonté (44 % → 40 %, il collait le
   bandeau d'indication).
   Sa raison est la bonne : le radar vit sur un fond sombre maîtrisé, la
   semi-transparence y est un outil ; le viseur vit SUR L'IMAGE CAMÉRA —
   nuages clairs, contre-jour — et un trait à 25-50 % y disparaît.
   RÈGLE DU VISEUR : la finesse se joue sur l'ÉPAISSEUR et la TAILLE,
   jamais sur l'OPACITÉ. */
.compass .deg { font-family: 'Barlow Condensed'; font-weight: 600; font-size: 1.25rem;
  line-height: 1; font-variant-numeric: tabular-nums; letter-spacing: .04em;
  color: #fff; text-shadow: 0 1px 4px rgba(0,0,0,.6); }
.ribbon { position: relative; height: 22px; margin-top: 6px; overflow: hidden;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 18%, #000 82%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 18%, #000 82%, transparent); }
.ribbon .tick { position: absolute; top: 0; transform: translateX(-50%); text-align: center; }
.ribbon .tick .bar { width: 1px; height: 5px; background: rgba(255,255,255,.85); margin: 0 auto; }
.ribbon .tick.maj .bar { height: 9px; background: #fff; }
/* demi-tirets des 5° : plus courts et à 50 % — la SEULE opacité tolérée sur le
   viseur, parce que leur discrétion est précisément leur fonction */
.ribbon .tick.min .bar { height: 3px; background: rgba(255,255,255,.5); }
.ribbon .tick .lab { font-family: 'Barlow'; font-size: .56rem; letter-spacing: .06em;
  color: rgba(255,255,255,.8); margin-top: 2px; text-shadow: 0 1px 3px rgba(0,0,0,.6); }
.ribbon .center { position: absolute; left: 50%; top: 0; width: 1.5px; height: 12px;
  background: var(--blue-soft); transform: translateX(-50%);
  box-shadow: 0 0 6px rgba(111,168,255,.6); }

/* top 40 % et non 44 : en bas de sa course, le réticule collait le bandeau
   d'indication (« 2 candidats — choisis ») — signalé par l'auteur. Le centre
   remonte, l'air revient. L'élévation (.elev) est alignée sur ce même 40 %. */
.reticle { position: absolute; left: 50%; top: 40%; transform: translate(-50%,-50%); width: 220px; height: 220px; pointer-events: none; }
/* fin (1,5 px) mais quasi opaque : voir la règle en tête de section */
.corner { position: absolute; width: 26px; height: 26px; border: 1.5px solid rgba(255,255,255,.92); }
.corner.tl { top: 0; left: 0; border-right: 0; border-bottom: 0; }
.corner.tr { top: 0; right: 0; border-left: 0; border-bottom: 0; }
.corner.bl { bottom: 0; left: 0; border-right: 0; border-top: 0; }
.corner.br { bottom: 0; right: 0; border-left: 0; border-top: 0; }
.cross { position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%); width: 26px; height: 26px; }
.cross::before, .cross::after { content: ''; position: absolute; background: rgba(255,255,255,.9); }
.cross::before { left: 50%; top: 0; width: 1px; height: 100%; transform: translateX(-50%); }
.cross::after { top: 50%; left: 0; height: 1px; width: 100%; transform: translateY(-50%); }
.reticle.locked .corner { border-color: var(--green-check); }
.reticle.locked .cross::before, .reticle.locked .cross::after { background: var(--green-check); }

/* ancré au bord droit, pas à distance fixe du centre : sinon le libellé
   déborde de l'écran sur les téléphones plus étroits que 430 px */
/* alignée sur le CENTRE du réticule : si l'un remonte, l'autre suit */
.elev { position: absolute; right: 16px; top: 40%; transform: translateY(-50%); text-align: right; }
.elev .v { font-family: 'Barlow Condensed'; font-weight: 600; font-size: 1.05rem; line-height: 1;
  font-variant-numeric: tabular-nums; letter-spacing: .04em;
  color: #fff; text-shadow: 0 1px 4px rgba(0,0,0,.6); }
.elev .l { font-family: 'Barlow'; font-size: .52rem; letter-spacing: .12em; text-transform: uppercase;
  color: rgba(255,255,255,.65); text-shadow: 0 1px 3px rgba(0,0,0,.6); }

.bottom { position: absolute; left: 0; right: 0; bottom: 0; padding: 14px 20px 100px; }
.detect { display: flex; align-items: center; gap: 12px; background: rgba(10,16,24,.6); backdrop-filter: blur(8px);
  border: 1px solid rgba(255,255,255,.1); border-radius: 16px; padding: 12px 14px; margin-bottom: 18px; }
.radar { flex: 0 0 40px; width: 40px; height: 40px; border-radius: 50%; border: 1.5px solid rgba(255,255,255,.25); position: relative; overflow: hidden; }
.radar .sweep { position: absolute; inset: 0; border-radius: 50%;
  background: conic-gradient(from 0deg, rgba(111,168,255,.5), transparent 70%); animation: spin 2s linear infinite; }
.radar .dot { position: absolute; left: 50%; top: 50%; width: 7px; height: 7px; border-radius: 50%; background: #566; transform: translate(-50%,-50%); }
.detect.on .radar { border-color: var(--green-check); }
.detect.on .radar .sweep { background: conic-gradient(from 0deg, rgba(74,222,128,.6), transparent 70%); }
.detect.on .radar .dot { background: var(--green-check); box-shadow: 0 0 8px var(--green-check); }
@keyframes spin { to { transform: rotate(360deg); } }
.detect .txt { flex: 1; }
.detect .txt .t { font-weight: 600; font-size: .95rem; }
.detect .txt .s { font-size: .72rem; opacity: .6; }
.detect .chev { flex: 0 0 auto; width: 18px; height: 18px; stroke: #fff; fill: none; stroke-width: 2; opacity: .5; transition: transform .2s; }

.candlist { max-height: 0; overflow: hidden; transition: max-height .25s ease; }
.sheet.open .candlist { max-height: 340px; overflow-y: auto; }
.sheet.open .chev { transform: rotate(180deg); }
.candhead { font-size: .7rem; letter-spacing: .1em; text-transform: uppercase; opacity: .55; padding: 12px 4px 6px; }
.cand { display: flex; align-items: center; gap: 12px; padding: 10px 12px; margin-bottom: 8px;
  background: rgba(10,16,24,.6); backdrop-filter: blur(8px); border: 1px solid rgba(255,255,255,.1); border-radius: 14px; cursor: pointer; }
.cand:active { background: rgba(20,30,44,.8); }
.cand.top { border-color: var(--green-check); }
.cand .offset { flex: 0 0 46px; width: 46px; height: 46px; border-radius: 10px; border: 1px solid rgba(255,255,255,.2); position: relative; }
.cand .offset::before, .cand .offset::after { content: ''; position: absolute; background: rgba(255,255,255,.2); }
.cand .offset::before { left: 50%; top: 6px; bottom: 6px; width: 1px; transform: translateX(-50%); }
.cand .offset::after { top: 50%; left: 6px; right: 6px; height: 1px; transform: translateY(-50%); }
.cand .offset .pt { position: absolute; left: 50%; top: 50%; width: 9px; height: 9px; border-radius: 50%; background: var(--blue-soft); transform: translate(-50%,-50%); }
.cand.top .offset .pt { background: var(--green-check); box-shadow: 0 0 6px var(--green-check); }
.cand .info { flex: 1; min-width: 0; }
.cand .nm { font-weight: 600; font-size: .95rem; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.cand .mt { font-size: .72rem; opacity: .65; }
.cand .sepv { flex: 0 0 auto; text-align: right; }
.cand .sepv .n { font-family: 'Barlow Condensed'; font-weight: 700; font-size: 1.2rem; line-height: 1; }
.cand .sepv .u { font-size: .55rem; opacity: .5; letter-spacing: .05em; }

.controls { display: flex; align-items: center; justify-content: center; }
.shutter { position: relative; width: 76px; height: 76px; border-radius: 50%; border: 4px solid #fff;
  background: rgba(255,255,255,.15); cursor: pointer; transition: transform .1s, background .1s; }
.shutter:active { transform: scale(.92); }
.shutter.ready { background: #fff; }
.shutter.ready:active { background: #dbe4f0; }

/* ---- retour au déclenchement (4 août 2026) ----
   Le `:active` seul ne suffisait pas : sur mobile il s'annule au moindre
   glissement du doigt, et le déclencheur se confond avec le bouton Scan de la
   barre basse, juste en dessous. Trois signaux qui ne peuvent pas se rater :
   un enfoncement franc, une onde qui se propage, un éclair bref de l'écran. */
.shutter.fire { animation: shFire .34s cubic-bezier(.2,.9,.3,1); }
@keyframes shFire {
  0%   { transform: scale(1); }
  28%  { transform: scale(.86); }
  100% { transform: scale(1); }
}
/* onde circulaire émise depuis le déclencheur */
.shutter::after { content: ''; position: absolute; inset: -4px; border-radius: 50%;
  border: 3px solid rgba(255,255,255,.9); opacity: 0; pointer-events: none; }
.shutter.fire::after { animation: shWave .55s ease-out; }
@keyframes shWave {
  0%   { transform: scale(1);   opacity: .9; }
  100% { transform: scale(2.1); opacity: 0; }
}
/* éclair de capture, par-dessus la caméra mais sous le HUD */
#shutter-flash { position: absolute; inset: 0; background: #fff; opacity: 0;
  pointer-events: none; z-index: 3; }
#shutter-flash.go { animation: shFlash .22s ease-out; }
@keyframes shFlash {
  0%   { opacity: 0; }
  18%  { opacity: .34; }
  100% { opacity: 0; }
}
/* Anneau qui respire quand un avion est verrouillé : distingue clairement le
   déclencheur du bouton de navigation, et dit qu'il est armé. */
.shutter.ready { box-shadow: 0 0 0 0 rgba(55,214,122,.55); animation: shArmed 1.9s ease-in-out infinite; }
@keyframes shArmed {
  0%, 100% { box-shadow: 0 0 0 0 rgba(55,214,122,.5); }
  50%      { box-shadow: 0 0 0 10px rgba(55,214,122,0); }
}
.shutter.fire.ready { animation: shFire .34s cubic-bezier(.2,.9,.3,1); }

.topbtns { position: absolute; top: 46px; left: 16px; right: 16px; display: flex; justify-content: space-between; align-items: center; }
.iconbtn { width: 40px; height: 40px; border-radius: 50%; background: rgba(10,16,24,.55); backdrop-filter: blur(6px);
  border: 1px solid rgba(255,255,255,.12); display: flex; align-items: center; justify-content: center; cursor: pointer; }
.iconbtn svg { width: 18px; height: 18px; stroke: #fff; fill: none; stroke-width: 2; }
.quota-chip { display: flex; align-items: baseline; gap: 5px; background: rgba(10,16,24,.55); backdrop-filter: blur(6px);
  border: 1px solid rgba(255,255,255,.12); border-radius: 999px; padding: 8px 14px; }
.quota-chip .n { font-family: 'Barlow Condensed'; font-weight: 700; font-size: 1.05rem; line-height: 1; }
.quota-chip .l { font-size: .58rem; letter-spacing: .1em; text-transform: uppercase; opacity: .6; }
.quota-chip.low .n { color: #fbbf24; }
.sim-chip { position: absolute; top: 100px; right: 16px; background: rgba(251,191,36,.15); border: 1px solid rgba(251,191,36,.5);
  color: #fbbf24; font-size: .6rem; letter-spacing: .18em; padding: 4px 10px; border-radius: 999px; }

.debug { position: absolute; top: 96px; left: 16px; background: rgba(6,10,16,.82); backdrop-filter: blur(8px);
  border: 1px solid rgba(255,255,255,.12); border-radius: 12px; padding: 10px 12px; font-size: .72rem; line-height: 1.7; font-variant-numeric: tabular-nums; z-index: 5; }
.debug b { color: var(--blue-soft); font-weight: 600; }
.debug .cal { color: #fbbf24; }

/* ============ VUE HANGAR ============ */
#view-hangar { background: #0a0e16; color: #e8ecf4; padding: 18px 14px 110px; }
.brand { display: flex; align-items: baseline; justify-content: space-between; margin-bottom: 4px; }
.brand .logo { font-family: 'Barlow Condensed'; font-style: italic; font-weight: 800;
  font-size: 1.9rem; letter-spacing: .08em; text-transform: uppercase; color: #efe9da; }
.brand .logo b { background: linear-gradient(120deg, #9dc4f0, #4a7fc9);
  -webkit-background-clip: text; background-clip: text; color: transparent; }
.brand .base { font-size: .58rem; letter-spacing: .3em; color: #56637a; text-transform: uppercase; }

.dexstats { display: flex; gap: 0; margin: 14px 0 16px;
  background: #101828; border: 1px solid #1c2940; border-radius: 16px; padding: 12px 4px; }
.dexstats .stat { flex: 1; text-align: center; padding: 0 6px; }
.dexstats .stat + .stat { border-left: 1px solid #1c2940; }
.dexstats .lbl { font-size: .56rem; letter-spacing: .1em; text-transform: uppercase; color: #6b7a94; margin-bottom: 3px; }
.dexstats .val { font-family: 'Barlow Condensed'; font-style: italic; font-weight: 800; font-size: 1.25rem; }
.dexstats .val small { font-size: .8rem; color: #6b7a94; font-weight: 600; }

.filters { display: flex; gap: 8px; margin-bottom: 16px; }
.filters button { appearance: none; border: 1px solid #22304a; background: #101828; color: #9fb0c8;
  font-family: 'Barlow'; font-size: .78rem; font-weight: 600; padding: 8px 14px; border-radius: 999px; cursor: pointer; }
.filters button.active { background: #2b62c4; border-color: #2b62c4; color: #fff; }
.count { font-size: .72rem; color: #56637a; letter-spacing: .08em; text-transform: uppercase; margin-bottom: 10px; }

.grid { display: grid; grid-template-columns: repeat(2, 1fr); gap: 12px; }
@media (min-width: 400px) { .grid { grid-template-columns: repeat(3, 1fr); } }

.mini { border-radius: 16px; padding: 5px; cursor: pointer; background: var(--frame); position: relative; transition: transform .12s ease; }
.mini:active { transform: scale(.96); }
.mini-inner { border-radius: 12px; overflow: hidden; background: var(--dark); }
.mini-top { display: flex; justify-content: space-between; align-items: center;
  padding: 6px 8px 4px; font-family: 'Barlow Condensed'; font-style: italic; }
.mini-top .num { font-weight: 800; font-size: .95rem; color: #fff; }
.mini-top .stars { color: #e3b23c; font-size: .7rem; letter-spacing: 1px; }
.mini.tier-commune .mini-top .stars { color: #9db7d4; }
.mini .ph { height: 92px; background: #1a2534; }
.mini .ph img { width: 100%; height: 100%; object-fit: cover; display: block; }
.mini .ph .hero-ph { height: 100%; display: flex; align-items: center; justify-content: center;
  background: linear-gradient(180deg, #2c4360, #1c2c42); }
.mini .ph .hero-ph svg { width: 40px; height: 40px; fill: rgba(255,255,255,.22); }
.mini .ph .hero-ph span { display: none; }
.mini .nm { font-family: 'Barlow Condensed'; font-style: italic; font-weight: 700;
  font-size: .86rem; text-transform: uppercase; line-height: 1.05; padding: 7px 8px 2px; color: #fff; min-height: 34px; }
.mini .tier-nm { font-size: .58rem; font-weight: 700; letter-spacing: .1em; text-transform: uppercase; color: var(--accent); padding: 0 8px 7px; }
.mini .foot { display: flex; border-top: 1px solid rgba(255,255,255,.12); padding: 6px 8px 8px; gap: 6px; }
.mini .foot div { flex: 1; }
.mini .foot .v { font-family: 'Barlow Condensed'; font-style: italic; font-weight: 800; font-size: .95rem; }
.mini .foot .l { font-size: .5rem; letter-spacing: .08em; text-transform: uppercase; color: rgba(255,255,255,.45); }

.mini.locked { --frame: #141b28; cursor: default; }
.mini.locked .mini-inner { background: #0e1420; }
.mini.locked .ghost { height: 92px; display: flex; align-items: center; justify-content: center; }
.mini.locked .ghost svg { width: 54px; height: 54px; fill: #1c2637; }
.mini.locked .q { text-align: center; font-family: 'Barlow Condensed'; font-weight: 800; font-size: 1.5rem; color: #2b3a52; }
.mini.locked .secret { text-align: center; font-size: .58rem; letter-spacing: .28em; color: #2b3a52; text-transform: uppercase; padding: 4px 0 12px; }
.mini.locked .mini-top .num { color: #2b3a52; }
.mini.locked .lock svg { width: 13px; height: 13px; stroke: #2b3a52; fill: none; stroke-width: 2; }

/* modale carte complète */
.modal { position: absolute; inset: 0; z-index: 40; display: none;
  align-items: center; justify-content: center; flex-direction: column; gap: 14px;
  background: rgba(4,7,12,.9); backdrop-filter: blur(6px); padding: 18px; overflow: auto;
  perspective: 1400px; }
.modal.open { display: flex; }
/* la carte du Hangar s'incline elle aussi (holo.js) */
#modalCard { transform-style: preserve-3d; }
.modal .close-btn { appearance: none; border: 1px solid #33415c; background: #101828; color: #ccd6e6;
  border-radius: 999px; padding: 10px 26px; font-family: 'Barlow'; font-size: .9rem; cursor: pointer; flex: 0 0 auto; }

/* ---- bandeau des appareils vus de ce type ----
   La ligne de tête est toujours là (elle porte la flotte mondiale) ;
   seule la rangée de puces disparaît quand on n'a vu qu'un appareil. */
#modalInstances { display: none; width: min(400px, 92vw); flex: 0 0 auto; }
#modalInstances.show { display: block; }
#modalInstances .inst-head { font-size: .62rem; letter-spacing: .14em; text-transform: uppercase;
  color: #7d8ca0; margin-bottom: 8px; text-align: center; }
/* la flotte mondiale ressort : c'est l'information de rareté */
#modalInstances .inst-head b { color: var(--blue-soft); font-weight: 700; }
#modalInstances .inst-row { display: flex; gap: 8px; overflow-x: auto; padding-bottom: 4px;
  scrollbar-width: none; }
#modalInstances .inst-row::-webkit-scrollbar { display: none; }
#modalInstances .inst { flex: 0 0 auto; appearance: none; cursor: pointer; text-align: left;
  background: #101828; border: 1px solid #22304a; border-radius: 12px; padding: 8px 12px;
  font-family: 'Barlow'; color: #9fb0c8; }
#modalInstances .inst:active { background: #16223a; }
#modalInstances .inst.on { border-color: var(--blue-soft); background: #14243f; color: #fff; }
#modalInstances .inst .reg { display: block; font-family: 'Barlow Condensed'; font-style: italic;
  font-weight: 800; font-size: 1rem; letter-spacing: .02em; }
#modalInstances .inst .meta { display: block; font-size: .62rem; color: #6b7a90; margin-top: 1px; }
#modalInstances .inst.on .meta { color: #9db0c6; }

/* ============ OVERLAY RÉVÉLATION ============ */
#overlay-reveal { position: absolute; inset: 0; z-index: 50; display: none;
  background: radial-gradient(ellipse at 50% 30%, #1a2230, #0b0f16 70%);
  flex-direction: column; align-items: center; justify-content: center; gap: 18px; padding: 18px; overflow: auto; }
#overlay-reveal.open { display: flex; }
#overlay-reveal .hint { color: #7e8a9b; font-size: .85rem; letter-spacing: .04em; text-align: center; }
#overlay-reveal .stage { perspective: 1400px; }
/* pas de transition CSS ici : l'inclinaison est lissée image par image
   par holo.js, une transition en plus rendrait le mouvement mou et en retard */
#overlay-reveal .tilt { transform-style: preserve-3d; }
#overlay-reveal .flipper { position: relative; transform-style: preserve-3d;
  transition: transform .85s cubic-bezier(.25,.7,.3,1.05); }
#overlay-reveal .flipper.revealed { transform: rotateY(180deg); }
#overlay-reveal .face { backface-visibility: hidden; -webkit-backface-visibility: hidden; }
#overlay-reveal .face.front { position: relative; transform: rotateY(180deg); }
#overlay-reveal .face.back { position: absolute; inset: 0; z-index: 2; cursor: pointer; }
#overlay-reveal .flipper.revealed .face.back { pointer-events: none; }
/* halo en box-shadow — jamais de filter (aplatit le contexte 3D, casse le flip) */
#overlay-reveal .stage.waiting .cardback { animation: breathe 2.6s ease-in-out infinite; border-radius: 24px; }
@keyframes breathe {
  0%, 100% { box-shadow: 0 0 18px var(--glow); }
  50%      { box-shadow: 0 0 46px var(--glow); }
}
#overlay-reveal .stage.revealed-glow .face.front .card { box-shadow: 0 12px 40px rgba(0,0,0,.5), 0 0 34px var(--glow); }
#overlay-reveal .flipper.shaking { animation: shake .5s ease-in-out; }
@keyframes shake {
  0%,100% { transform: rotate(0); }
  20% { transform: rotate(-2.2deg) translateX(-4px); }
  40% { transform: rotate(2.4deg) translateX(5px); }
  60% { transform: rotate(-2.6deg) translateX(-6px); }
  80% { transform: rotate(2deg) translateX(4px); }
}
#overlay-reveal .burst { position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background: radial-gradient(circle at 50% 45%, var(--glow), transparent 55%); z-index: 5; }
#overlay-reveal .burst.go { animation: burstA .7s ease-out; }
@keyframes burstA { 0% { opacity: 0; } 25% { opacity: .85; } 100% { opacity: 0; } }
/* le reflet holographique lui-même est générique : voir .card.holo dans design-system.css */
#overlay-reveal .actions { display: flex; gap: 10px; opacity: 0; pointer-events: none; transition: opacity .4s; }
#overlay-reveal .actions.show { opacity: 1; pointer-events: auto; }
#overlay-reveal .actions button { appearance: none; border: 1px solid #33415c; background: #101828; color: #ccd6e6;
  border-radius: 999px; padding: 11px 20px; font-family: 'Barlow'; font-size: .88rem; cursor: pointer; }
#overlay-reveal .actions button.primary { background: #2b62c4; border-color: #2b62c4; color: #fff; }
#overlay-reveal .mute { position: absolute; top: 14px; right: 14px; z-index: 7; appearance: none;
  border: 1px solid #2c3a4d; background: #16202e; border-radius: 999px; width: 42px; height: 42px;
  font-size: 1.05rem; cursor: pointer; }

/* ============ VUE PROFIL (Inter) ============ */
#view-profile { font-family: 'Inter', -apple-system, sans-serif;
  background: linear-gradient(180deg, #0f1c30 0%, #0a111d 40%, #070c14 100%); padding: 0 0 110px; }
#view-profile .topbar { display: flex; align-items: center; justify-content: space-between; padding: 20px 22px 6px; }
#view-profile .topbar .back { width: 40px; height: 40px; border-radius: 50%; border: 1px solid rgba(255,255,255,.14);
  background: rgba(255,255,255,.03); display: flex; align-items: center; justify-content: center; cursor: pointer; }
#view-profile .topbar .back svg { width: 18px; height: 18px; stroke: #fff; stroke-width: 2; fill: none; }
#view-profile .topbar .title { font-size: 1.05rem; font-weight: 600; }
#view-profile .topbar .spacer { width: 40px; }
#view-profile .content { padding: 10px 22px 30px; }

.pf-head { display: flex; flex-direction: column; align-items: center; margin: 14px 0 6px; }
.pf-avatar { width: 104px; height: 104px; border-radius: 50%; position: relative;
  background: #16233a; border: 2px solid rgba(255,255,255,.12); overflow: hidden; }
.pf-avatar img { width: 100%; height: 100%; object-fit: cover; display: none; }
.pf-avatar.has-img img { display: block; }
.pf-avatar .ph { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; }
.pf-avatar.has-img .ph { display: none; }
.pf-avatar .ph svg { width: 46px; height: 46px; fill: #43597a; }
.pf-avatar .cam { position: absolute; right: 2px; bottom: 2px; width: 32px; height: 32px; border-radius: 50%;
  background: var(--blue-btn); border: 3px solid #0a111d; display: flex; align-items: center; justify-content: center; }
.pf-avatar .cam svg { width: 15px; height: 15px; stroke: #fff; stroke-width: 2; fill: none; }
.pf-name { margin-top: 14px; font-size: 1.3rem; font-weight: 700; }
.pf-plan { margin-top: 8px; font-size: .62rem; font-weight: 700; letter-spacing: .14em; padding: 4px 12px; border-radius: 6px;
  background: rgba(255,255,255,.07); color: var(--txt-2); }
.pf-plan.pro { background: rgba(61,139,253,.15); color: var(--blue); }

.pf-stats { display: flex; margin: 22px 0 18px; background: rgba(255,255,255,.03);
  border: 1px solid rgba(255,255,255,.08); border-radius: 16px; padding: 14px 4px; }
.pf-stats .stat { flex: 1; text-align: center; padding: 0 6px; }
.pf-stats .stat + .stat { border-left: 1px solid rgba(255,255,255,.07); }
.pf-stats .val { font-size: 1.25rem; font-weight: 700; }
.pf-stats .lbl { font-size: .6rem; letter-spacing: .1em; text-transform: uppercase; color: var(--txt-3); margin-top: 3px; }

/* ---- en-tête : emblème + bague de progression + identité ---- */
.pf-hero { display: flex; align-items: center; gap: 18px; padding: 6px 0 20px; }
.pf-hero .badge { position: relative; flex: 0 0 124px; width: 124px; height: 124px; }
.pf-hero .ring { position: absolute; inset: 0; width: 100%; height: 100%; }
.pf-hero .emb { position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; }
/* photo + anneau de rang : le trou des 10 anneaux fait 60 % du canevas,
   donc UN seul réglage suffit pour les dix — la photo ne saute jamais
   d'un rang à l'autre. La photo est dessous, l'anneau par-dessus. */
.pf-hero .badge .photo { position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%);
  width: 58%; height: 58%; border-radius: 50%; object-fit: cover; z-index: 1; }
.pf-hero .badge .emb-img { position: absolute; left: 50%; top: 50%; transform: translate(-50%,-50%);
  width: 90%; height: auto; z-index: 2; }
.pf-hero .badge.withphoto .emb-img { width: 100%; }
/* État verrouillé : on grise l'image livrée, pas besoin d'un fichier de plus.
   Assombrir davantage effacerait la silhouette — il faut qu'on devine encore
   la forme du rang à atteindre, c'est tout l'intérêt de le montrer. */
.emb-img.locked { filter: grayscale(1) brightness(.75) contrast(.75); opacity: .5; }
.pf-next .nextemb { position: relative; }
.pf-next .nextemb .lock { position: absolute; left: 50%; top: 52%; transform: translate(-50%,-50%); }
.pf-next .nextemb .lock svg { width: 17px; height: 17px; stroke: #9db0c6; fill: rgba(10,17,29,.7); stroke-width: 1.8; }
.pf-hero .lvl { position: absolute; left: 50%; bottom: -4px; transform: translateX(-50%);
  width: 30px; height: 27px; display: flex; align-items: center; justify-content: center;
  background: #16233a; border: 1px solid #2b62c4; color: #cfe0f5;
  font-size: .78rem; font-weight: 700; font-variant-numeric: tabular-nums;
  clip-path: polygon(50% 0, 100% 25%, 100% 75%, 50% 100%, 0 75%, 0 25%); }
.pf-hero .who { flex: 1; min-width: 0; }
.pf-hero .rk { font-size: .68rem; letter-spacing: .16em; text-transform: uppercase; color: var(--blue); font-weight: 600; }
.pf-hero .nm { font-size: 1.45rem; font-weight: 700; line-height: 1.1; margin: 2px 0 7px; overflow-wrap: anywhere; }
.pf-hero .fl { margin-top: 9px; font-size: 1.05rem; font-weight: 700; color: var(--blue-soft); letter-spacing: .04em; }
.pf-hero .lv { font-size: .74rem; color: var(--txt-3); }
.pf-hero .pf-plan { display: inline-block; }

/* ---- prochaine étape ---- */
.pf-next { display: flex; align-items: center; gap: 14px;
  background: rgba(255,255,255,.03); border: 1px solid rgba(255,255,255,.08);
  border-radius: 16px; padding: 14px 16px; margin-bottom: 12px; }
.pf-next .col { flex: 1; min-width: 0; }
.pf-next .top { display: flex; justify-content: space-between; align-items: baseline; gap: 8px; }
.pf-next .lbl { font-size: .6rem; letter-spacing: .14em; text-transform: uppercase; color: var(--txt-3); }
.pf-next .xp { font-size: .74rem; font-weight: 600; color: var(--blue-soft); font-variant-numeric: tabular-nums; white-space: nowrap; }
.pf-next .nm { font-size: 1.12rem; font-weight: 700; margin: 3px 0 10px; }
.pf-next .bar { height: 6px; border-radius: 999px; background: rgba(255,255,255,.08); overflow: hidden; }
.pf-next .bar i { display: block; height: 100%; border-radius: 999px;
  background: linear-gradient(90deg, #2f7bf0, #6fa8ff); transition: width .5s ease; }
.pf-next .hint { margin-top: 7px; font-size: .7rem; color: var(--txt-hint); }
.pf-next .nextemb { flex: 0 0 62px; display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,.03); border: 1px solid rgba(255,255,255,.08); border-radius: 14px; padding: 6px 4px; }

/* ---- dernière découverte + planisphère ---- */
.pf-disc { position: relative; overflow: hidden; margin-bottom: 12px;
  background: rgba(255,255,255,.03); border: 1px solid rgba(255,255,255,.08); border-radius: 16px; padding: 13px 16px 15px; }
.pf-disc .lbl { position: relative; z-index: 1; font-size: .6rem; letter-spacing: .14em;
  text-transform: uppercase; color: var(--txt-3); margin-bottom: 11px; }
.pf-disc .worldmap { position: absolute; right: -6%; top: 6%; width: 74%; height: 92%; opacity: .5; pointer-events: none; }
.pf-disc .row { position: relative; z-index: 1; display: flex; align-items: center; gap: 13px; }
.pf-disc .thumb { flex: 0 0 66px; height: 66px; border-radius: 12px; overflow: hidden;
  background: #16233a; border: 1px solid rgba(255,255,255,.08); display: flex; align-items: center; justify-content: center; }
.pf-disc .thumb img { width: 100%; height: 100%; object-fit: cover; }
.pf-disc .thumb .ph svg { width: 30px; height: 30px; fill: #3a4c66; }
.pf-disc .txt { flex: 1; min-width: 0; }
.pf-disc .txt .nm { font-size: .96rem; font-weight: 600; }
.pf-disc .txt .ds { font-size: .74rem; color: var(--txt-3); margin-top: 2px; overflow-wrap: anywhere; }

/* ---- 4 tuiles de stats ---- */
.pf-tiles { display: grid; grid-template-columns: repeat(4, 1fr); gap: 8px; margin-bottom: 12px; }
.pf-tiles .tile { background: rgba(255,255,255,.03); border: 1px solid rgba(255,255,255,.08);
  border-radius: 14px; padding: 11px 6px 10px; text-align: center; }
.pf-tiles .ic { display: block; margin: 0 auto 6px; width: 22px; height: 22px; }
.pf-tiles .ic svg { width: 22px; height: 22px; fill: none; stroke-width: 1.7; }
.pf-tiles .ic.b svg { stroke: #6fa8ff; } .pf-tiles .ic.g svg { stroke: #4ade80; }
.pf-tiles .ic.y svg { stroke: #fbbf24; } .pf-tiles .ic.p svg { stroke: #c084fc; }
.pf-tiles .v { font-size: 1.15rem; font-weight: 700; line-height: 1; font-variant-numeric: tabular-nums; }
.pf-tiles .v small { font-size: .62rem; font-weight: 600; color: var(--txt-3); }
.pf-tiles .l { font-size: .56rem; letter-spacing: .1em; text-transform: uppercase; color: var(--txt-2); margin-top: 5px; }
.pf-tiles .s { font-size: .54rem; color: var(--txt-hint); margin-top: 2px; }

/* ---- défi du jour ---- */
.pf-daily { display: flex; align-items: center; gap: 13px; margin-bottom: 12px;
  background: rgba(61,139,253,.06); border: 1px solid rgba(61,139,253,.24); border-radius: 16px; padding: 13px 16px; }
.pf-daily.done { background: rgba(74,222,128,.07); border-color: rgba(74,222,128,.3); }
.pf-daily .ic { flex: 0 0 34px; height: 34px; }
.pf-daily .ic svg { width: 34px; height: 34px; fill: none; stroke: var(--blue-soft); stroke-width: 1.5; }
.pf-daily.done .ic svg { stroke: var(--green-check); }
.pf-daily .txt { flex: 1; min-width: 0; }
.pf-daily .lbl { font-size: .58rem; letter-spacing: .14em; text-transform: uppercase; color: var(--txt-3); }
.pf-daily .nm { font-size: 1rem; font-weight: 600; margin-top: 1px; }
.pf-daily .xp { font-size: .72rem; color: var(--blue-soft); font-weight: 600; margin-top: 2px; }
.pf-daily.done .xp { color: var(--green-check); }
.pf-daily .pg { flex: 0 0 auto; min-width: 52px; text-align: center; font-size: .8rem; font-weight: 600;
  color: var(--txt-2); background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.1);
  border-radius: 999px; padding: 6px 10px; font-variant-numeric: tabular-nums; }
.pf-daily.done .pg { color: var(--green-check); border-color: rgba(74,222,128,.4); }


/* ---- hauts faits : filtres, réclamation, animation de gain ---- */
.pf-ach .tabs { display: flex; gap: 6px; margin-bottom: 9px; }
.pf-ach .tb { flex: 1; appearance: none; cursor: pointer; font-family: inherit;
  background: rgba(255,255,255,.03); border: 1px solid rgba(255,255,255,.08);
  border-radius: 999px; padding: 7px 4px; color: var(--txt-3); font-size: .7rem; font-weight: 600; }
.pf-ach .tb.on { background: #2b62c4; border-color: #2b62c4; color: #fff; }
.pf-ach .tb b { display: inline-block; background: rgba(255,255,255,.22); border-radius: 999px;
  padding: 0 5px; margin-left: 3px; font-size: .64rem; }
.pf-ach .tb.on b { background: rgba(0,0,0,.28); }

.pf-ach .claim-all { display: block; width: 100%; appearance: none; cursor: pointer; font-family: inherit;
  background: linear-gradient(90deg, #2f7bf0, #6fa8ff); border: 0; color: #fff;
  border-radius: 13px; padding: 12px; font-size: .9rem; font-weight: 600; margin-bottom: 8px; position: relative; }
.pf-ach .more { display: block; width: 100%; appearance: none; cursor: pointer; font-family: inherit;
  background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.1); color: var(--txt-2);
  border-radius: 12px; padding: 10px; font-size: .78rem; font-weight: 600; margin-top: 8px; }

/* une carte réclamable est un bouton : elle doit se sentir cliquable */
.pf-ach .ach.todo { width: 100%; text-align: left; appearance: none; cursor: pointer; font-family: inherit;
  background: rgba(61,139,253,.1); border-color: rgba(61,139,253,.42); position: relative; }
.pf-ach .ach.todo:active { transform: scale(.985); }
.pf-ach .ach .tick.ready { background: linear-gradient(135deg, #2f7bf0, #6fa8ff); color: #fff; font-size: .8rem; }
.pf-ach .ach .xp { flex: 0 0 auto; align-self: center; font-size: .8rem; font-weight: 700; color: var(--blue-soft); }
.pf-ach .ach .xp.got { color: var(--green-check); }
.pf-ach .ach .xp.dim { color: var(--txt-hint); font-weight: 600; }
.pf-ach .ach .body { display: flex; flex-direction: column; }
.pf-ach .ach.empty { justify-content: center; color: var(--txt-hint); font-size: .8rem; padding: 18px 12px; }
/* la carte encaissée s'efface au lieu de sauter */
.pf-ach .ach.leaving { animation: achLeave .6s ease forwards; }
@keyframes achLeave {
  0% { opacity: 1; transform: scale(1); }
  100% { opacity: 0; transform: scale(.9); }
}
/* « +80 XP » qui s'élève */
.xp-pop { position: absolute; right: 14px; top: 50%; pointer-events: none;
  font-size: 1rem; font-weight: 800; color: #6fa8ff; text-shadow: 0 2px 10px rgba(0,0,0,.6);
  animation: xpPop .9s ease-out forwards; }
@keyframes xpPop {
  0%   { opacity: 0; transform: translateY(0) scale(.8); }
  22%  { opacity: 1; transform: translateY(-10px) scale(1.12); }
  100% { opacity: 0; transform: translateY(-40px) scale(1); }
}

/* pastille de réclamation sur l'onglet Profil */
.nav .tab { position: relative; }
.nav .tab .badge-n { position: absolute; top: -2px; right: 18px; min-width: 16px; height: 16px;
  border-radius: 999px; background: #f87171; color: #fff; font-size: .58rem; font-weight: 700;
  display: flex; align-items: center; justify-content: center; padding: 0 4px; box-shadow: 0 0 0 2px #0a111d; }

/* ---- percentile anonyme ---- */
.pf-pct { display: flex; align-items: center; gap: 12px; margin-bottom: 12px;
  background: rgba(255,255,255,.03); border: 1px solid rgba(255,255,255,.08);
  border-radius: 16px; padding: 12px 16px; }
.pf-pct.high { background: rgba(61,139,253,.07); border-color: rgba(61,139,253,.26); }
.pf-pct .ic svg { width: 22px; height: 22px; fill: none; stroke: #7fa8dd; stroke-width: 1.8; }
.pf-pct.high .ic svg { stroke: var(--blue-soft); }
.pf-pct b { display: block; font-size: .9rem; font-weight: 600; }
.pf-pct small { display: block; font-size: .68rem; color: var(--txt-hint); margin-top: 1px; }

/* ---- ligne des scans ---- */
.pf-scans { display: flex; align-items: center; gap: 11px; margin-bottom: 18px; padding: 0 4px; }
.pf-scans .ic svg { width: 22px; height: 22px; fill: none; stroke: #7fa8dd; stroke-width: 1.8; }
.pf-scans b { display: block; font-size: .86rem; font-weight: 600; }
.pf-scans small { display: block; font-size: .72rem; color: var(--txt-hint); margin-top: 1px; }

/* ---- série de jours ---- */
.pf-streak { display: flex; align-items: center; gap: 12px; margin-bottom: 12px;
  background: rgba(255,255,255,.03); border: 1px solid rgba(255,255,255,.08);
  border-radius: 16px; padding: 12px 16px; }
.pf-streak .flame { flex: 0 0 34px; height: 34px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,.05); }
.pf-streak .flame svg { width: 18px; height: 18px; fill: #46566c; }
.pf-streak.hot .flame { background: rgba(251,146,60,.14); }
.pf-streak.hot .flame svg { fill: #fb923c; }
.pf-streak .txt { flex: 1; min-width: 0; }
.pf-streak .txt .lbl { font-size: .6rem; letter-spacing: .12em; text-transform: uppercase; color: var(--txt-3); }
.pf-streak .txt .val { font-size: 1.05rem; font-weight: 700; }
.pf-streak.hot .txt .val { color: #fb923c; }
.pf-streak .side { text-align: right; flex: 0 0 auto; max-width: 46%; }
.pf-streak .best { font-size: .7rem; font-weight: 600; color: var(--txt-2); }
.pf-streak .state { font-size: .62rem; color: var(--txt-hint); margin-top: 2px; }

/* ---- hauts faits ---- */
.pf-ach { margin-bottom: 18px; }
.pf-ach .head { display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 9px; padding: 0 2px; }
.pf-ach .head span:first-child { font-size: .6rem; letter-spacing: .14em; text-transform: uppercase; color: var(--txt-3); }
.pf-ach .cnt { font-size: .74rem; font-weight: 600; color: var(--blue-soft); }
/* `.items` et non `.grid` : `.grid` est déjà la grille du Hangar, la réutiliser
   ici héritait de ses colonnes et tronquait les cartes. Deux colonnes comme la
   maquette ; la pastille de pourcentage remplace la barre de progression, qui
   n'a plus la place. */
.pf-ach .items { display: grid; grid-template-columns: repeat(2, 1fr); gap: 8px; }
.pf-ach .items .pg { display: none; }
.pf-ach .items .ach { padding: 10px 11px; gap: 9px; }
.pf-ach .items .tick { flex: 0 0 26px; height: 26px; font-size: .54rem; }
.pf-ach .items .ach.done .tick { font-size: .8rem; }
.pf-ach .items .nm { font-size: .8rem; line-height: 1.15; }
.pf-ach .items .ds { font-size: .62rem; line-height: 1.25; margin-top: 2px; }
.pf-ach .ach { display: flex; gap: 11px; align-items: flex-start;
  background: rgba(255,255,255,.025); border: 1px solid rgba(255,255,255,.07);
  border-radius: 13px; padding: 11px 13px; }
.pf-ach .ach.done { background: rgba(61,139,253,.07); border-color: rgba(61,139,253,.3); }
.pf-ach .tick { flex: 0 0 30px; height: 30px; border-radius: 50%; display: flex; align-items: center; justify-content: center;
  background: rgba(255,255,255,.06); color: var(--txt-hint); font-size: .58rem; font-weight: 700; }
.pf-ach .ach.done .tick { background: var(--blue-btn); color: #fff; font-size: .9rem; }
.pf-ach .body { flex: 1; min-width: 0; }
.pf-ach .nm { font-size: .88rem; font-weight: 600; }
.pf-ach .ach:not(.done) .nm { color: var(--txt-2); }
.pf-ach .ds { font-size: .68rem; color: var(--txt-hint); margin-top: 1px; }
.pf-ach .pg { height: 3px; border-radius: 999px; background: rgba(255,255,255,.08); margin-top: 7px; overflow: hidden; }
.pf-ach .pg i { display: block; height: 100%; background: #46566c; border-radius: 999px; }

.pf-rows { background: rgba(255,255,255,.03); border: 1px solid rgba(255,255,255,.08); border-radius: 16px; padding: 4px 16px; margin-bottom: 18px; }
.pf-row { display: flex; align-items: center; gap: 12px; padding: 13px 0; }
.pf-row + .pf-row { border-top: 1px solid rgba(255,255,255,.06); }
.pf-row svg { width: 19px; height: 19px; stroke: #7fa8dd; fill: none; stroke-width: 1.7; flex: 0 0 auto; }
.pf-row .lbl { flex: 1; font-size: .8rem; color: var(--txt-3); }
.pf-row .val { font-size: .88rem; font-weight: 500; }

.pf-quota { text-align: center; font-size: .78rem; color: var(--txt-hint); margin-bottom: 20px; }

.pf-actions { display: flex; flex-direction: column; gap: 10px; }
.pf-actions button { width: 100%; border: 0; border-radius: 13px; padding: 15px; font-family: inherit;
  font-size: 1rem; font-weight: 600; color: #fff; cursor: pointer; }
.pf-actions .edit-btn { background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.12); }
.pf-actions .pro-btn { background: var(--blue-btn); line-height: 1.25; }
.pf-actions .pro-btn small { display: block; font-size: .7rem; font-weight: 400; opacity: .85; margin-top: 2px; }
/* libelle sur deux lignes dans les rangees de preferences */
.pf-row.two .lbl { display: flex; flex-direction: column; }
.pf-row.two .lbl small { font-size: .66rem; color: var(--txt-hint); margin-top: 1px; }

/* — édition (portée de profile-edit.html) — */
#profile-edit .field,
#onboarding .ob-form .field { margin-bottom: 20px; }
#profile-edit .field label,
#onboarding .ob-form .field label { display: block; font-size: .74rem; font-weight: 600; letter-spacing: .06em;
  text-transform: uppercase; color: var(--txt-3); margin-bottom: 8px; }
#profile-edit .field .wrap,
#onboarding .ob-form .field .wrap { display: flex; align-items: center; gap: 11px; background: rgba(255,255,255,.04);
  border: 1px solid rgba(255,255,255,.1); border-radius: 13px; padding: 0 14px; }
#profile-edit .field .wrap:focus-within,
#onboarding .ob-form .field .wrap:focus-within { border-color: var(--blue); }
#profile-edit .field .wrap svg,
#onboarding .ob-form .field .wrap svg { width: 19px; height: 19px; stroke: #7fa8dd; fill: none; stroke-width: 1.7; flex: 0 0 auto; }
#profile-edit .field input,
#onboarding .ob-form .field input { flex: 1; background: none; border: 0; outline: none; color: #fff; font-family: inherit;
  font-size: 1rem; padding: 14px 0; }
#profile-edit .field input::placeholder,
#onboarding .ob-form .field input::placeholder { color: #56657d; }
#profile-edit .field .help,
#onboarding .ob-form .field .help { font-size: .72rem; color: var(--txt-hint); margin-top: 6px; }
#profile-edit .avatar-wrap,
#onboarding .ob-form .avatar-wrap { display: flex; flex-direction: column; align-items: center; margin: 18px 0 30px; }
#profile-edit .avatar-wrap .pf-avatar,
#onboarding .ob-form .avatar-wrap .pf-avatar { cursor: pointer; }
#profile-edit .avatar-wrap .hint,
#onboarding .ob-form .avatar-wrap .hint { margin-top: 12px; font-size: .82rem; color: var(--txt-3); }
#profile-edit .save button,
#onboarding .ob-form .save button { width: 100%; border: 0; border-radius: 13px; padding: 15px; font-family: inherit;
  font-size: 1rem; font-weight: 600; color: #fff; background: var(--blue-btn); cursor: pointer; }
#profile-edit .toast,
#onboarding .ob-form .toast { text-align: center; font-size: .84rem; color: var(--green); font-weight: 500; height: 18px;
  margin-top: 8px; opacity: 0; transition: opacity .2s; }
#profile-edit .toast.show,
#onboarding .ob-form .toast.show { opacity: 1; }
/* gain d'XP : on le distingue du simple accuse d'enregistrement */
#profile-edit .toast.xp,
#onboarding .ob-form .toast.xp { color: var(--blue-soft); font-weight: 600; }
#profile-edit input[type=file],
#onboarding .ob-form input[type=file] { display: none; }

/* ============ OVERLAY PAYWALL (Inter) ============ */
#overlay-paywall { position: absolute; inset: 0; z-index: 60; display: none; overflow-y: auto;
  font-family: 'Inter', -apple-system, sans-serif;
  background: linear-gradient(180deg, #14273f 0%, #0d1626 30%, #0a111d 56%, #070c14 100%); }
#overlay-paywall.open { display: block; }
#overlay-paywall .hero { position: absolute; top: 0; left: 0; right: 0; height: 440px; z-index: 0; }
#overlay-paywall .hero img { width: 100%; height: 100%; object-fit: cover; object-position: center 34%; }
#overlay-paywall .hero::after { content: ''; position: absolute; inset: 0;
  background: linear-gradient(180deg, rgba(7,12,20,.15) 0%, rgba(7,12,20,.22) 32%, rgba(9,15,26,.62) 62%, rgba(9,15,26,.92) 84%, #070c14 100%); }
#overlay-paywall .content { position: relative; z-index: 1; padding: 22px 24px 26px; }
#overlay-paywall .close { width: 42px; height: 42px; border-radius: 50%; border: 1px solid rgba(255,255,255,.16);
  background: rgba(10,17,29,.35); backdrop-filter: blur(6px); display: flex; align-items: center; justify-content: center; cursor: pointer; }
#overlay-paywall .close svg { width: 17px; height: 17px; stroke: #fff; stroke-width: 2; fill: none; }
#overlay-paywall .kicker { display: flex; align-items: center; gap: 8px; margin: 76px 0 18px; }
#overlay-paywall .kicker svg { width: 19px; height: 19px; fill: var(--blue); }
#overlay-paywall .kicker span { color: var(--blue); font-weight: 600; font-size: .74rem; letter-spacing: .16em; }
#overlay-paywall h1 { font-size: 2.05rem; font-weight: 700; line-height: 1.14; letter-spacing: -.015em; }
#overlay-paywall h1 .blue { color: var(--blue); }
#overlay-paywall .sub { margin-top: 16px; color: #a9b8cc; font-size: .92rem; font-weight: 400; line-height: 1.5; max-width: 320px; }
#overlay-paywall .social { display: inline-flex; align-items: center; gap: 11px; margin-top: 24px;
  background: rgba(255,255,255,.035); border: 1px solid rgba(255,255,255,.08); border-radius: 999px; padding: 7px 16px 7px 8px; }
#overlay-paywall .social .av { width: 28px; height: 28px; border-radius: 50%; border: 2px solid #0d1626; margin-right: -10px;
  display: flex; align-items: center; justify-content: center; }
#overlay-paywall .social .av svg { width: 13px; height: 13px; fill: rgba(255,255,255,.7); }
#overlay-paywall .social .txt { font-size: .84rem; font-weight: 400; color: #c7d3e2; margin-left: 5px; }
#overlay-paywall .social .txt b { color: var(--blue); font-weight: 600; }
#overlay-paywall .plans { display: flex; gap: 12px; margin-top: 28px; }
#overlay-paywall .plan { flex: 1; background: rgba(255,255,255,.03); border: 1px solid rgba(255,255,255,.08);
  border-radius: 18px; padding: 18px 16px 16px; position: relative; }
#overlay-paywall .plan.reco { border-color: var(--blue); box-shadow: 0 0 0 1px var(--blue), 0 8px 30px rgba(61,139,253,.15);
  background: rgba(61,139,253,.05); }
#overlay-paywall .popular { position: absolute; top: -11px; left: 50%; transform: translateX(-50%); white-space: nowrap;
  background: var(--blue); font-size: .6rem; font-weight: 600; letter-spacing: .1em; padding: 5px 12px; border-radius: 999px; }
#overlay-paywall .row1 { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; }
#overlay-paywall .pname { font-size: .75rem; font-weight: 600; letter-spacing: .05em; color: #c7d3e2; }
#overlay-paywall .chip { font-size: .58rem; font-weight: 600; padding: 4px 8px; border-radius: 6px; }
#overlay-paywall .chip.grey { background: rgba(255,255,255,.07); color: var(--txt-2); }
#overlay-paywall .chip.green { background: rgba(55,214,122,.13); color: var(--green); }
#overlay-paywall .price { margin-top: 13px; font-size: 1.85rem; font-weight: 700; letter-spacing: -.02em; line-height: 1; white-space: nowrap; }
#overlay-paywall .price small { font-size: .82rem; font-weight: 400; color: var(--txt-2); letter-spacing: 0; }
#overlay-paywall .permo { margin-top: 7px; font-size: .8rem; font-weight: 400; color: var(--txt-2); }
#overlay-paywall .btn { display: block; width: 100%; text-align: center; border: 0; border-radius: 12px; padding: 14px;
  margin-top: 18px; font-family: inherit; font-size: .92rem; font-weight: 600; color: #fff; cursor: pointer; }
#overlay-paywall .btn.blue { background: var(--blue-btn); }
#overlay-paywall .btn.green { background: linear-gradient(90deg, #34d17e, #21b6c4); }
#overlay-paywall .foot { text-align: center; margin-top: 11px; font-size: .78rem; font-weight: 400; }
#overlay-paywall .foot.grey { color: #7d8ca0; }
#overlay-paywall .foot.green { color: var(--green); font-weight: 500; }
#overlay-paywall .compare { margin-top: 26px; background: rgba(255,255,255,.025); border: 1px solid rgba(255,255,255,.07);
  border-radius: 18px; padding: 18px 18px 8px; }
#overlay-paywall .chead { display: grid; grid-template-columns: 1fr 58px 58px; align-items: center; padding-bottom: 14px; }
#overlay-paywall .chead .t { font-size: .68rem; font-weight: 600; letter-spacing: .06em; color: var(--txt-3); }
#overlay-paywall .chead .c { text-align: center; font-size: .68rem; font-weight: 600; color: var(--txt-3); }
#overlay-paywall .chead .c.pro span { background: var(--blue-btn); color: #fff; padding: 3px 9px; border-radius: 6px; font-size: .62rem; }
#overlay-paywall .frow { display: grid; grid-template-columns: 1fr 58px 58px; align-items: center; padding: 12px 0;
  border-top: 1px solid rgba(255,255,255,.06); }
#overlay-paywall .frow .lbl { display: flex; align-items: center; gap: 13px; }
#overlay-paywall .frow .ic svg { width: 21px; height: 21px; stroke: #7fa8dd; fill: none; stroke-width: 1.5; }
#overlay-paywall .frow .nm { font-size: .86rem; font-weight: 500; }
#overlay-paywall .frow .ds { font-size: .68rem; font-weight: 400; color: #7d8ca0; margin-top: 2px; }
#overlay-paywall .frow .cell { text-align: center; font-size: .82rem; font-weight: 400; }
#overlay-paywall .frow .cell.free { color: #c7d3e2; }
#overlay-paywall .frow .cell.unl { color: var(--green); font-weight: 600; }
#overlay-paywall .frow .cell svg { width: 17px; height: 17px; stroke: var(--green-check); fill: none; stroke-width: 2.2; }
#overlay-paywall .frow .cell .dash { color: #46566c; }
#overlay-paywall .legal { margin-top: 22px; text-align: center; font-size: .74rem; font-weight: 400; color: #7d8ca0; line-height: 1.5; }
#overlay-paywall .legal a { color: var(--blue); text-decoration: none; }
#overlay-paywall .devtoast { position: fixed; left: 50%; bottom: 30px; transform: translateX(-50%); z-index: 70;
  background: rgba(55,214,122,.14); border: 1px solid rgba(55,214,122,.45); color: var(--green);
  font-size: .8rem; padding: 10px 18px; border-radius: 999px; opacity: 0; transition: opacity .25s; pointer-events: none; white-space: nowrap; }
#overlay-paywall .devtoast.show { opacity: 1; }

/* ============ OVERLAY MONTÉE EN GRADE ============
   Célèbre le changement de rang. Réutilise le vocabulaire de la révélation
   (fond radial, burst, halo en box-shadow) pour ne pas inventer un second
   langage visuel. z-index 55 : au-dessus de la révélation (50), sous le
   paywall (60) — mais le guetteur ne déclenche jamais par-dessus un autre
   overlay, donc les deux ne se croisent pas en pratique. */
#overlay-rankup { position: absolute; inset: 0; z-index: 55; display: none;
  background: radial-gradient(ellipse at 50% 34%, #1b2436, #080c13 72%);
  align-items: center; justify-content: center; padding: 22px; overflow: auto; }
#overlay-rankup.open { display: flex; }

#overlay-rankup .ru-burst { position: absolute; inset: 0; pointer-events: none; opacity: 0;
  background: radial-gradient(circle at 50% 42%, rgba(111,168,255,.85), transparent 58%); }
#overlay-rankup.swap .ru-burst { animation: ruBurst .85s ease-out; }
@keyframes ruBurst { 0% { opacity: 0; } 22% { opacity: .9; } 100% { opacity: 0; } }

/* perspective : sans elle, l'inclinaison 3D de l'emblème (holo.js) ne se voit pas */
#overlay-rankup .ru-box { position: relative; display: flex; flex-direction: column;
  align-items: center; text-align: center; gap: 0; perspective: 900px; }

#overlay-rankup .ru-kicker { font-family: 'Barlow Condensed'; font-style: italic; font-weight: 800;
  font-size: .74rem; letter-spacing: .3em; text-transform: uppercase; color: var(--blue-soft);
  opacity: 0; transform: translateY(6px); animation: ruIn .5s .1s ease-out forwards; }
@keyframes ruIn { to { opacity: 1; transform: none; } }

/* ---- l'emblème : anneau + échange ancien/nouveau ---- */
#overlay-rankup .ru-emb { position: relative; width: 168px; height: 168px; margin: 16px 0 4px;
  display: grid; place-items: center; }
#overlay-rankup .ru-ring { position: absolute; inset: 0; width: 100%; height: 100%; }
#overlay-rankup .ru-old,
#overlay-rankup .ru-new { position: absolute; display: grid; place-items: center; z-index: 1; }
#overlay-rankup .ru-old img, #overlay-rankup .ru-new img,
#overlay-rankup .ru-old svg, #overlay-rankup .ru-new svg { display: block; }
/* ---- dissolution de l'ancien grade, puis forge du nouveau ----
   L'idée vient de la maquette du 4 août : le nouveau grade se FABRIQUE à
   partir de l'ancien, au lieu d'un fondu entre deux images — ça raconte la
   progression au lieu de la constater.

   ⚠️ POURQUOI UN MASQUE ET PAS DE VRAIES PARTICULES : faire éclater un PNG en
   particules impose de lire ses pixels dans un canvas (ou du WebGL) et d'en
   animer des centaines — coûteux, et ça rame sur un vieil iPhone. Ici un
   masque en dégradé balaie le badge de bas en haut : on obtient la lecture
   « ça se dissout / ça se reforge » en CSS pur, sans risque de performance.
   On anime mask-position (interpolé nativement) et non le gradient lui-même,
   dont l'interpolation est inégale d'un navigateur à l'autre. */
#overlay-rankup .ru-old,
#overlay-rankup .ru-new {
  -webkit-mask-size: 100% 300%;  mask-size: 100% 300%;
  -webkit-mask-repeat: no-repeat; mask-repeat: no-repeat;
}
/* L'ANCIEN se désintègre en partant du bas. Masque 3× plus haut que le badge :
   à la position 0 0 le badge voit le tiers OPAQUE du dégradé (donc visible),
   à 0 100% il voit le tiers transparent (donc effacé). Désaturé au départ,
   comme les rangs verrouillés du Profil : c'est ce qu'on quitte. */
#overlay-rankup .ru-old { filter: grayscale(1) brightness(.75) contrast(.75); opacity: .9;
  -webkit-mask-image: linear-gradient(to top, transparent 46%, #000 54%);
          mask-image: linear-gradient(to top, transparent 46%, #000 54%);
  -webkit-mask-position: 0 0; mask-position: 0 0;
  transition: -webkit-mask-position .5s ease-in, mask-position .5s ease-in, opacity .5s ease-in; }
#overlay-rankup.dissolve .ru-old { -webkit-mask-position: 0 100%; mask-position: 0 100%; opacity: .5; }

/* LE NOUVEAU se forge dans l'autre sens : dégradé inversé, donc à 0 0 il est
   masqué et à 0 100% il est complet — et il se remplit du bas vers le haut. */
#overlay-rankup .ru-new {
  -webkit-mask-image: linear-gradient(to bottom, transparent 46%, #000 54%);
          mask-image: linear-gradient(to bottom, transparent 46%, #000 54%);
  -webkit-mask-position: 0 0; mask-position: 0 0; }
#overlay-rankup.forge .ru-new {
  -webkit-mask-position: 0 100%; mask-position: 0 100%;
  transition: -webkit-mask-position .62s cubic-bezier(.3,.7,.2,1), mask-position .62s cubic-bezier(.3,.7,.2,1); }
/* verrouillage : léger à-coup d'échelle, l'équivalent visuel du clic métallique */
#overlay-rankup.swap .ru-new { animation: ruLock .42s cubic-bezier(.2,1.6,.35,1); }
@keyframes ruLock { 0% { transform: scale(1); } 45% { transform: scale(1.07); } 100% { transform: scale(1); } }

/* le front lumineux qui accompagne la forge : une barre qui monte avec le masque */
#overlay-rankup .ru-emb::before { content: ''; position: absolute; left: 8%; right: 8%; height: 22px;
  bottom: -6%; z-index: 2; pointer-events: none; opacity: 0; border-radius: 50%;
  background: radial-gradient(ellipse at center, rgba(190,222,255,.95), rgba(111,168,255,.35) 45%, transparent 72%); }
#overlay-rankup.dissolve .ru-emb::before { animation: ruFront 1.3s ease-in-out forwards; }
@keyframes ruFront {
  0%   { opacity: 0; bottom: -6%; }
  18%  { opacity: 1; }
  85%  { opacity: .9; bottom: 96%; }
  100% { opacity: 0; bottom: 104%; }
}
/* halo pulsant sous le nouvel emblème */
#overlay-rankup.swap .ru-emb::after { content: ''; position: absolute; width: 118px; height: 118px;
  border-radius: 50%; z-index: 0; pointer-events: none;
  box-shadow: 0 0 40px 12px rgba(111,168,255,.35); animation: ruGlow 2.4s ease-in-out infinite; }
@keyframes ruGlow {
  0%, 100% { box-shadow: 0 0 26px 6px rgba(111,168,255,.24); }
  50%      { box-shadow: 0 0 52px 16px rgba(111,168,255,.42); }
}

/* ---- les étoiles, sous le badge, allumées une par une ----
   Dessinées à part et non par-dessus l'emblème : les étoiles sont déjà
   gravées dans les PNG livrés, se caler dessus au pixel casserait à la
   première nouvelle planche. */
#overlay-rankup .ru-stars { display: flex; gap: 9px; height: 26px; align-items: center; margin-top: 6px; }
#overlay-rankup .ru-star svg { width: 22px; height: 22px; display: block; }
#overlay-rankup .ru-star svg path { fill: #2c3648; }
#overlay-rankup .ru-star { opacity: .5; transform: scale(.7); transition: opacity .3s, transform .3s; }
#overlay-rankup .ru-star.on { opacity: 1; transform: scale(1); animation: ruStar .5s cubic-bezier(.2,1.6,.35,1); }
#overlay-rankup .ru-star.on svg path { fill: #f3d878; filter: drop-shadow(0 0 6px rgba(243,216,120,.65)); }
@keyframes ruStar { 0% { transform: scale(.6); } 60% { transform: scale(1.45); } 100% { transform: scale(1); } }

/* ---- textes ---- */
#overlay-rankup .ru-lvl, #overlay-rankup .ru-name, #overlay-rankup .ru-fl,
#overlay-rankup .ru-next { opacity: 0; transform: translateY(8px); transition: opacity .45s ease, transform .45s ease; }
#overlay-rankup.text .ru-lvl  { opacity: 1; transform: none; transition-delay: 0s; }
#overlay-rankup.text .ru-name { opacity: 1; transform: none; transition-delay: .1s; }
#overlay-rankup.text .ru-fl   { opacity: 1; transform: none; transition-delay: .2s; }
#overlay-rankup.text .ru-next { opacity: 1; transform: none; transition-delay: .3s; }
#overlay-rankup .ru-lvl { margin-top: 14px; font-size: .64rem; letter-spacing: .22em;
  text-transform: uppercase; color: #8fa1b8; }
#overlay-rankup .ru-name { font-family: 'Barlow Condensed'; font-style: italic; font-weight: 800;
  font-size: 2.5rem; line-height: 1.05; color: #fff; margin-top: 4px; }
#overlay-rankup .ru-fl { font-family: 'Barlow Condensed'; font-style: italic; font-weight: 700;
  font-size: .95rem; letter-spacing: .16em; color: var(--blue-soft); margin-top: 2px; }
#overlay-rankup .ru-next { font-size: .78rem; color: #7e8a9b; margin-top: 12px; max-width: 260px; }

#overlay-rankup .ru-btn { margin-top: 22px; appearance: none; border: 0; cursor: pointer;
  background: var(--blue); color: #fff; border-radius: 999px; padding: 12px 34px;
  font-family: 'Barlow'; font-size: .92rem; opacity: 0; pointer-events: none; transition: opacity .4s; }
#overlay-rankup.cta .ru-btn { opacity: 1; pointer-events: auto; }

/* écrans courts : on réduit l'emblème et le titre plutôt que de faire défiler */
@media (max-height: 680px) {
  #overlay-rankup .ru-emb { width: 132px; height: 132px; margin: 10px 0 2px; }
  #overlay-rankup .ru-name { font-size: 2rem; }
  #overlay-rankup .ru-next { display: none; }
}

/* ---- bandeau de nouveauté à la révélation (4 août 2026) ----
   Rend visible le barème d'XP : un nouveau type paie plein tarif, un nouvel
   appareil du même type une fraction, un doublon presque rien. Affiché APRÈS le
   flip seulement — le viseur ne dévoile rien avant la capture. */
#rv-novelty { display: none; align-items: center; gap: 10px; padding: 7px 16px;
  border-radius: 999px; font-family: 'Barlow'; font-size: .8rem; letter-spacing: .02em;
  opacity: 0; transform: translateY(6px); transition: opacity .4s ease, transform .4s ease; }
#rv-novelty[class] { display: inline-flex; }
#rv-novelty.show { opacity: 1; transform: none; }
#rv-novelty .lbl { font-family: 'Barlow Condensed'; font-style: italic; font-weight: 800;
  text-transform: uppercase; letter-spacing: .1em; }
#rv-novelty .xp { font-weight: 600; opacity: .9; }
/* nouveau type : l'événement majeur, on le marque en vert franc */
#rv-novelty.nv-newType { background: rgba(55,214,122,.16); border: 1px solid rgba(55,214,122,.5); color: #6ee79c; }
/* nouvel appareil : la collection par immatriculation, en bleu */
#rv-novelty.nv-newAircraft { background: rgba(47,123,240,.16); border: 1px solid rgba(111,168,255,.45); color: #8fbaff; }
/* déjà vu : discret, sans culpabiliser — ça rapporte quand même un peu */
#rv-novelty.nv-repeat { background: rgba(255,255,255,.06); border: 1px solid rgba(255,255,255,.14); color: #9db0c6; }

/* ============ ONBOARDING — écran de bienvenue (4 août 2026) ============
   Fond en image, texte en HTML par-dessus : le lettrage doit pouvoir être
   traduit et s'adapter à toutes les hauteurs d'écran, ce qu'une maquette
   aplatie en une seule image interdirait. */
#onboarding { position: absolute; inset: 0; z-index: 90; display: flex;
  background: #06111f; overflow: hidden; }
#onboarding.hidden { display: none; }
#onboarding.closing { animation: obOut .42s ease forwards; }
@keyframes obOut { to { opacity: 0; transform: scale(1.04); } }

#onboarding .ob-bg { position: absolute; inset: 0;
  background: url('../../assets/brand/onboarding-bg.webp') center bottom / cover no-repeat; }
/* voile haut : l'image générée n'est pas assez sombre en haut pour garantir la
   lisibilité du wordmark sur tous les écrans */
#onboarding .ob-scrim { position: absolute; inset: 0; background:
  linear-gradient(180deg, rgba(4,12,24,.82) 0%, rgba(4,12,24,.35) 34%, rgba(4,12,24,0) 52%,
                  rgba(4,12,24,.55) 84%, rgba(4,12,24,.9) 100%); }

#onboarding .ob-content { position: relative; z-index: 2; flex: 1; display: flex;
  flex-direction: column; align-items: center; padding: 8vh 26px calc(26px + env(safe-area-inset-bottom)); }
#onboarding .ob-badge { width: 132px; height: 132px; display: block;
  filter: drop-shadow(0 10px 26px rgba(0,0,0,.55)); }
#onboarding .ob-wordmark { width: min(320px, 78vw); height: auto; display: block; margin-top: 18px; }
#onboarding .ob-baseline { margin-top: 10px; font-family: 'Barlow Condensed'; font-weight: 700;
  font-size: .82rem; letter-spacing: .3em; text-transform: uppercase; color: #9dc4f0;
  text-align: center; }
#onboarding .ob-spacer { flex: 1; min-height: 24px; }

/* choix de la langue : deux boutons côte à côte, pas un menu déroulant —
   deux options se montrent, elles ne se déplient pas. Chaque langue est
   nommée DANS sa langue, seule façon d'être compris avant d'avoir choisi. */
#onboarding .ob-lang { display: flex; gap: 10px; margin-bottom: 18px; }
#onboarding .ob-langbtn { appearance: none; cursor: pointer; display: flex; align-items: center;
  gap: 8px; padding: 10px 18px; border-radius: 999px; font-family: 'Barlow'; font-size: .9rem;
  color: #cfe0f5; background: rgba(8,18,32,.55); border: 1px solid rgba(255,255,255,.16);
  backdrop-filter: blur(8px); transition: border-color .2s, background .2s, color .2s; }
#onboarding .ob-langbtn .fl { font-size: 1.15rem; line-height: 1; }
#onboarding .ob-langbtn.on { color: #fff; border-color: var(--blue-soft);
  background: rgba(47,123,240,.28); }

#onboarding .ob-cta { appearance: none; border: 0; cursor: pointer; width: 100%;
  max-width: 420px; padding: 17px 24px; border-radius: 16px;
  background: linear-gradient(180deg, #4f97ff, #2f7bf0); color: #fff;
  font-family: 'Barlow Condensed'; font-weight: 700; font-size: 1.18rem;
  letter-spacing: .12em; text-transform: uppercase;
  box-shadow: 0 10px 30px rgba(47,123,240,.45); }
#onboarding .ob-cta:active { transform: scale(.985); }

/* écrans courts : on réduit l'emblème plutôt que de faire défiler */
@media (max-height: 700px) {
  #onboarding .ob-content { padding-top: 5vh; }
  #onboarding .ob-badge { width: 100px; height: 100px; }
  #onboarding .ob-wordmark { width: min(260px, 70vw); margin-top: 12px; }
}

/* ---- onboarding : gestion des étapes ----
   Une seule étape visible à la fois, et le fond CHANGE d'une étape à l'autre :
   c'est ce qui donne la sensation d'avancer sans barre de progression. */
#onboarding .ob-content { display: none; }
#onboarding[data-step="1"] .ob-content[data-for="1"],
#onboarding[data-step="2"] .ob-content[data-for="2"],
#onboarding[data-step="3"] .ob-content[data-for="3"],
#onboarding[data-step="4"] .ob-content[data-for="4"] { display: flex; animation: obIn .45s ease both; }
@keyframes obIn { from { opacity: 0; transform: translateY(10px); } }
#onboarding[data-step="2"] .ob-bg {
  background-image: url('../../assets/brand/onboarding-bg-2.webp'); }

/* ---- étape 2 : les autorisations ---- */
#onboarding .ob-perm { justify-content: flex-start; }
#onboarding .ob-head { text-align: center; margin-bottom: 26px; }
#onboarding .ob-title { font-family: 'Barlow Condensed'; font-style: italic; font-weight: 800;
  font-size: 2rem; color: #fff; letter-spacing: .02em; }
#onboarding .ob-sub { margin-top: 8px; font-family: 'Barlow'; font-size: .92rem;
  color: #b9cde6; max-width: 300px; margin-inline: auto; line-height: 1.45; }

#onboarding .ob-perms { display: flex; flex-direction: column; gap: 12px; width: 100%; max-width: 420px; }
#onboarding .ob-perm-row { display: flex; align-items: flex-start; gap: 13px;
  padding: 14px 16px; border-radius: 16px; background: rgba(8,18,32,.62);
  border: 1px solid rgba(255,255,255,.12); backdrop-filter: blur(8px); }
#onboarding .ob-perm-row .ic { flex: 0 0 34px; width: 34px; height: 34px; border-radius: 50%;
  display: flex; align-items: center; justify-content: center;
  background: rgba(47,123,240,.2); border: 1px solid rgba(111,168,255,.35); }
#onboarding .ob-perm-row .ic svg { width: 18px; height: 18px; stroke: var(--blue-soft);
  stroke-width: 1.8; fill: none; stroke-linecap: round; stroke-linejoin: round; }
#onboarding .ob-perm-row .tx { flex: 1; display: flex; flex-direction: column; gap: 3px; }
#onboarding .ob-perm-row .nm { font-family: 'Barlow'; font-weight: 600; font-size: .95rem; color: #fff; }
#onboarding .ob-perm-row .ds { font-family: 'Barlow'; font-size: .8rem; color: #9db0c6; line-height: 1.35; }
/* Indispensable vs recommandé : l'app fonctionne sans caméra (viseur sur fond
   sombre), et le dire augmente l'acceptation au lieu de tout exiger en bloc. */
#onboarding .ob-perm-row .tag { flex: 0 0 auto; align-self: center; font-size: .6rem;
  letter-spacing: .1em; text-transform: uppercase; padding: 4px 8px; border-radius: 999px;
  font-family: 'Barlow'; font-weight: 600; }
#onboarding .ob-perm-row .tag.req { color: #6ee79c; background: rgba(55,214,122,.14);
  border: 1px solid rgba(55,214,122,.4); }
#onboarding .ob-perm-row .tag.opt { color: #9db0c6; background: rgba(255,255,255,.06);
  border: 1px solid rgba(255,255,255,.14); }

#onboarding .ob-privacy { font-family: 'Barlow'; font-size: .74rem; line-height: 1.5;
  color: #8fa1b8; text-align: center; max-width: 340px; margin: 0 auto 16px; }
/* Étape 2 : le bas de l'image (nuages éclairés) rend le texte légal illisible.
   On renforce le voile là, sans toucher au reste de la photo. */
#onboarding[data-step="2"] .ob-scrim { background:
  linear-gradient(180deg, rgba(4,12,24,.86) 0%, rgba(4,12,24,.55) 30%, rgba(4,12,24,.35) 52%,
                  rgba(4,12,24,.82) 78%, rgba(4,12,24,.96) 100%); }
#onboarding .ob-privacy { color: #a9bcd2; text-shadow: 0 1px 6px rgba(0,0,0,.7); }

/* ---- onboarding étapes 3 et 4 : champs de profil ----
   On réutilise .field / .wrap / .avatar-wrap / .pf-avatar de l'écran d'édition
   du Profil : rien n'est redéfini ici sauf ce qui est propre à l'onboarding
   (fond translucide, bouton secondaire), pour que les deux écrans ne puissent
   pas diverger visuellement. */
#onboarding[data-step="3"] .ob-bg,
#onboarding[data-step="4"] .ob-bg {
  background-image: url('../../assets/brand/onboarding-bg-2.webp'); }
#onboarding[data-step="3"] .ob-scrim,
#onboarding[data-step="4"] .ob-scrim { background:
  linear-gradient(180deg, rgba(4,12,24,.9) 0%, rgba(4,12,24,.72) 40%,
                  rgba(4,12,24,.86) 76%, rgba(4,12,24,.97) 100%); }
#onboarding .ob-form { justify-content: flex-start; }
#onboarding .ob-form .field { width: 100%; max-width: 420px; margin-bottom: 16px; }
#onboarding .ob-form .avatar-wrap { margin-bottom: 22px; }
#onboarding .ob-form input[type="file"] { display: none; }
/* les champs de saisie doivent rester lisibles par-dessus la photo */
#onboarding .ob-form .wrap { background: rgba(8,18,32,.72); }

#onboarding .ob-xp { font-family: 'Barlow Condensed'; font-style: italic; font-weight: 700;
  font-size: .84rem; letter-spacing: .12em; text-transform: uppercase; color: #6ee79c;
  margin-bottom: 14px; text-align: center; }
/* bouton secondaire : présent mais discret — passer une étape facultative ne
   doit pas ressembler à un échec */
#onboarding .ob-skip { appearance: none; background: none; border: 0; cursor: pointer;
  margin-top: 12px; padding: 8px 14px; font-family: 'Barlow'; font-size: .86rem;
  color: #9db0c6; text-decoration: underline; text-underline-offset: 3px; }

/* ---- sélecteur de langue dans le Profil ---- */
.pe-langs { display: flex; gap: 10px; }
.pe-lang { flex: 1; appearance: none; cursor: pointer; display: flex; align-items: center;
  justify-content: center; gap: 8px; padding: 12px 10px; border-radius: 14px;
  font-family: 'Inter', sans-serif; font-size: .92rem; color: #9db0c6;
  background: #101828; border: 1px solid #22304a; transition: border-color .2s, color .2s, background .2s; }
.pe-lang .fl { font-size: 1.1rem; line-height: 1; }
.pe-lang.on { color: #fff; border-color: var(--blue-soft); background: #14243f; }

/* ============ LOGO DE MARQUE EN IMAGE (4 août 2026) ============
   Le wordmark était du TEXTE CSS (Barlow Condensed italic) à trois endroits :
   gate du Scan, bandeau du Hangar, dos de carte. Il est désormais le vrai
   lettrage de marque, identique à l'écran d'accueil et à l'icône d'app.
   Les tailles reprennent celles des textes remplacés pour ne rien décaler. */
.logo-img { display: block; height: auto; }
.logo-img.gate  { width: min(268px, 72vw); margin: 0 auto 4px; }   /* remplaçait 2,4rem */
.logo-img.brand { width: 148px; }                                   /* remplaçait 1,45rem */
.logo-img.back  { width: 150px; margin-top: 2px; }                  /* dos de carte, 2rem */

/* Dos de carte : le badge réel remplace le dessin qui l'imitait (cadre + avion
   + étincelle + traînée redessinés en CSS). Même emplacement, même gabarit. */
.cardback-inner .mark-img { width: 96px; height: 96px; display: block;
  filter: drop-shadow(0 6px 16px rgba(0,0,0,.45)); }

/* Slot verrouillé du Hangar : la silhouette du badge, très atténuée. Un slot
   vide reste ainsi reconnaissable comme une carte Skydex, au lieu d'un avion
   générique. On garde la teinte sombre d'origine (#1c2637) via un filtre plutôt
   qu'une seconde image. */
.mini.locked .ghost img { width: 62px; height: 62px; display: block;
  filter: grayscale(1) brightness(.42) contrast(.85); opacity: .55; }

/* ============ RADAR « LE CIEL MAINTENANT » (4 août 2026) ============
   Sonar PPI : un faisceau tourne, les points s'allument à son passage.
   ⚠️ L'illumination n'est PAS calculée en JavaScript : chaque point porte la
   même animation, décalée par un animation-delay proportionnel à son azimut
   relatif au cap (posé en style inline par radar.js). Faisceau et points
   partagent ainsi la même horloge CSS et restent synchronisés sans une seule
   frame de JS — ce qui compte, car rAF est throttlé en arrière-plan. */
/* Devenu une VUE (onglet) et non plus un overlay : plus de z-index, plus de
   display:none piloté par .open — c'est .view/.hidden du routeur qui décide,
   comme pour les trois autres onglets. On garde le fond en dégradé, qui fait
   l'identité de l'écran. */
#view-radar { background: radial-gradient(ellipse at 50% 38%, #0d1b2c, #05090f 72%);
  padding: 20px 20px 96px; }
#view-radar .rd-box { display: flex; flex-direction: column; align-items: center;
  width: 100%; max-width: 440px; margin: 0 auto; }
#view-radar .rd-head { text-align: center; margin-bottom: 18px; }
#view-radar .rd-title { font-family: 'Barlow Condensed'; font-style: italic; font-weight: 800;
  font-size: 1.75rem; color: #fff; }
#view-radar .rd-sub { font-family: 'Barlow'; font-size: .84rem; color: #8fa1b8; margin-top: 3px; }

/* ============ LE CADRAN, EN DEUX COUCHES (5 août 2026) ============
   Demande de l'auteur : des traits plus subtils, un fond qui n'est pas uni,
   une lueur légère, une gradation fine sur le grand cercle, et les distances
   écrites sur les cercles. Tout en CSS, aucune image — rien à régénérer si la
   palette change.

   ⚠️ ARCHITECTURE : CE QUI TOURNE ET CE QUI NE TOURNE PAS.
     .rd-stage  statique  → taille, fond, lueur. Le cadre du cadran.
     .rd-disc   TOURNE    → faisceau, axes, avions. Eux seuls dépendent du cap.
     .rd-dial   statique  → cercles de distance, étiquettes, point central.
   Un cercle est symétrique : le faire tourner ne change rien à l'écran mais
   coûte une recomposition par image. Une première version plaçait les cercles
   DANS le disque avec une contre-rotation pour garder le reflet fixe : cinq
   couches masquées retransformées 60 fois par seconde, et l'auteur a signalé
   que la rotation n'était « toujours pas hyper fluide » sur son téléphone.
   Maintenant une seule couche bouge. Et les étiquettes restent droites par
   construction, alors que dans le disque elles auraient tourné à l'envers.

   ⚠️ LA TECHNIQUE DES ANNEAUX À DÉGRADÉ : un `border` ne peut pas porter de
   dégradé angulaire. On peint donc un DISQUE entier en `conic-gradient`, puis
   on n'en garde que le bord avec un `mask` en `radial-gradient` qui rend
   transparent tout ce qui est à moins de (rayon − épaisseur). Résultat : un
   anneau fin dont l'intensité varie sur le tour.
   ⚠️ `-webkit-mask` est indispensable : Safari, donc l'iPhone, la cible.
   ⚠️ Dégradés SYMÉTRIQUES et brillants EN HAUT (`from 0deg`) : la lumière vient
   d'au-dessus, comme partout ailleurs. Un essai à `from 200deg` mettait la
   brillance en bas à gauche — l'œil le trouve faux sans savoir le nommer. */

#view-radar .rd-stage { position: relative; width: min(320px, 82vw); aspect-ratio: 1;
  border-radius: 50%;
  /* FOND EN DEUX COUCHES, et non un dégradé centré : une lueur DÉCENTRÉE vers le
     haut, puis l'assombrissement vers le bord. C'est le décentrage qui enlève
     l'effet « plat ». ⚠️ Il est sur la couche STATIQUE, sinon la source de
     lumière tournerait avec le cadran. */
  background:
    radial-gradient(circle at 50% 26%, rgba(104,158,224,.22), transparent 62%),
    radial-gradient(circle at 50% 50%, rgba(24,52,82,.66) 0%, rgba(13,30,49,.8) 52%, rgba(6,14,24,.97) 100%);
  /* LUEUR : deux diffusions externes froides de portées différentes, plus un
     assombrissement interne du bord. Pas de `filter`, plus coûteux, et que la
     doc du projet interdit ailleurs (il aplatit les contextes 3D). */
  box-shadow: 0 0 34px rgba(61,139,253,.16), 0 0 90px rgba(61,139,253,.07),
              inset 0 0 38px rgba(6,14,24,.55); }

/* la couche qui tourne : le haut de l'écran = la direction regardée */
#view-radar .rd-disc { position: absolute; inset: 0; border-radius: 50%; overflow: hidden;
  /* Promotion explicite en couche GPU : c'est le seul élément transformé à
     chaque image, donc autant dire au navigateur de ne pas le re-rastériser.
     À ne PAS étendre au reste du cadran — `will-change` sur des éléments qui
     ne bougent pas consomme de la mémoire vidéo pour rien. */
  will-change: transform;
  /* ⚠️ AUCUNE transition sur le transform. `--cap` est posé à chaque image par
     boucleCap() : une transition de .6 s serait relancée 60 fois par seconde et
     le disque traînerait loin derrière le poignet. Le lissage est fait en JS
     (EASE_CAP), pas en CSS. */
  transform: rotate(var(--cap, 0deg)); }

/* la couche statique des distances, par-dessus le faisceau */
#view-radar .rd-dial { position: absolute; inset: 0; border-radius: 50%;
  pointer-events: none; }

/* CERCLES DE DISTANCE. L'inset est calculé par radar.js depuis la distance, pas
   écrit ici : les cercles et leurs étiquettes viennent du même tableau, donc ils
   ne peuvent pas se contredire. */
#view-radar .rd-dial .ring { position: absolute; border-radius: 50%; border: 0;
  background: conic-gradient(from 0deg,
    rgba(126,180,255,.52), rgba(126,180,255,.26) 22%, rgba(126,180,255,.09) 50%,
    rgba(126,180,255,.26) 78%, rgba(126,180,255,.52));
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 1px), #000 calc(100% - 1px));
          mask: radial-gradient(farthest-side, transparent calc(100% - 1px), #000 calc(100% - 1px)); }

/* LE PLUS GRAND CERCLE (40 km, inset 0) : le plus marqué, avec la gradation la
   plus franche — c'est le bord du cadran, il porte la finition. */
#view-radar .rd-dial .ring.bord {
  background: conic-gradient(from 0deg,
    rgba(150,196,255,.85), rgba(140,186,255,.42) 20%, rgba(120,170,255,.13) 50%,
    rgba(140,186,255,.42) 80%, rgba(150,196,255,.85));
  -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 1.5px), #000 calc(100% - 1.5px));
          mask: radial-gradient(farthest-side, transparent calc(100% - 1.5px), #000 calc(100% - 1.5px)); }

/* ⚠️ LIMITE DE SCAN (30 km) — d'une AUTRE COULEUR que les autres cercles, avec
   un voile très léger vers l'intérieur : ce qui est dedans est atteignable, ce
   qui est dehors ne l'est pas. Demandé par l'auteur le 4 août 2026, parce que
   rien ne disait au joueur où s'arrête le scannable.
   ⚠️ MAIS CE CERCLE EST UNE APPROXIMATION, ET C'EST DOCUMENTÉ : le vrai critère
   n'est pas la distance, c'est la TAILLE APPARENTE (MIN_ARCMIN). Un 747 de 64 m
   reste capturable à 30 km ; un Learjet de 12 m est écarté dès ~21 km, donc bien
   à l'intérieur du cercle. Le cercle donne le plafond absolu (MAX_DIST_M), et
   c'est l'ÉTAT DE CHAQUE POINT qui porte la vérité par avion — voir .blip.petit.
   ⚠️ Il REPREND UN VRAI BORDER, en tirets : c'est sa signature, et un anneau
   masqué en conic-gradient ne peut pas être pointillé. Il annule donc le fond et
   le masque radial de `.ring`, et utilise un masque ANGULAIRE qui fait respirer
   les tirets sur le tour — même intention, autre moyen. */
#view-radar .rd-dial .ring.limite {
  background: none;
  border: 1.25px dashed rgba(74,222,128,.75);
  box-shadow: inset 0 0 30px rgba(55,214,122,.09), 0 0 16px rgba(55,214,122,.13);
  -webkit-mask: conic-gradient(from 0deg, #000, rgba(0,0,0,.62) 24%, rgba(0,0,0,.4) 50%, rgba(0,0,0,.62) 76%, #000);
          mask: conic-gradient(from 0deg, #000, rgba(0,0,0,.62) 24%, rgba(0,0,0,.4) 50%, rgba(0,0,0,.62) 76%, #000); }

/* ============ COURONNE GRADUÉE (5 août 2026) ============
   Tirets tous les 15° et quatre points cardinaux, sur le bord du plus grand
   cercle. Elle vit DANS le disque, donc elle tourne avec le cap : c'est ce qui
   fait qu'elle indique le nord réel pendant qu'on pivote.

   ⚠️ Le rayon est exprimé en CSS et non mesuré en JS : `min(320px, 82vw)` est la
   taille du cadran, donc `/2` en donne le rayon. Aucune lecture de layout, donc
   aucun risque de valeur périmée au redimensionnement.

   ⚠️ POSITIONNEMENT PAR ORBITE : on tourne à l'azimut voulu, puis on translate
   vers l'extérieur. C'est ce qui évite de calculer un sinus et un cosinus par
   élément, et ça reste une seule propriété `transform` — donc compositable. */
#view-radar .rd-bezel { position: absolute; inset: 0; pointer-events: none;
  --rr: calc(min(320px, 82vw) / 2); }

/* TIRETS — aucune transformation propre au-delà de leur placement : ils tournent
   avec le disque, ce qui est exactement le comportement voulu pour un trait
   radial. Couleur du grand cercle à 20 %, comme demandé. */
#view-radar .rd-bezel .rd-tick { position: absolute; left: 50%; top: 50%;
  width: 1px; height: 4px; margin: -2px 0 0 -.5px;
  background: rgba(150,196,255,.2);
  transform: rotate(calc(var(--az) * 1deg)) translateY(calc(-1 * (var(--rr) - 5px))); }
/* trois longueurs : c'est la hiérarchie qui rend une graduation lisible.
   ⚠️ LA MARGE DU HAUT DOIT VALOIR LA MOITIÉ DE LA HAUTEUR, sinon le centre de
   rotation n'est plus le centre du disque et le tiret se retrouve déplacé d'une
   distance qui dépend de son azimut. Mesuré avant correctif, avec la marge de
   -2px héritée des tirets courts : les 4 tirets majeurs tombaient à 151 px du
   centre au nord, 153 au nord-est, 155 au sud — 4 px d'écart, donc une couronne
   visiblement décentrée là où elle est la plus lisible. Les 16 tirets courts,
   eux, étaient tous exactement à 155 px.
   Les translations sont réglées pour que les trois longueurs se terminent sur le
   MÊME rayon extérieur et poussent vers l'intérieur, comme sur un cadran. */
#view-radar .rd-bezel .rd-tick.mid { height: 6px; margin-top: -3px;
  transform: rotate(calc(var(--az) * 1deg)) translateY(calc(-1 * (var(--rr) - 6px))); }
#view-radar .rd-bezel .rd-tick.maj { height: 8px; margin-top: -4px;
  background: rgba(150,196,255,.32);
  transform: rotate(calc(var(--az) * 1deg)) translateY(calc(-1 * (var(--rr) - 7px))); }

/* POINTS CARDINAUX — petits, gris, discrets (demande de l'auteur).
   ⚠️ La dernière rotation annule DEUX choses : l'orbite (`--az`) et la rotation
   du disque (`--cap`). Sans elle, la lettre part à l'envers dès qu'on se tourne.
   C'est la seule raison pour laquelle ces quatre éléments sont retransformés à
   chaque image ; ne pas la « simplifier ». */
#view-radar .rd-bezel .rd-card { position: absolute; left: 50%; top: 50%;
  width: 16px; height: 16px; margin: -8px 0 0 -8px;
  line-height: 16px; text-align: center;
  font-family: 'Barlow'; font-size: .56rem; font-weight: 600; letter-spacing: .04em;
  color: rgba(160,176,196,.72);
  /* ⚠️ 21px et non 15px : à 15, la lettre touchait le tiret majeur de son propre
     azimut et « —N » se lisait comme un trait d'union. Il faut de l'air entre la
     graduation et la lettre. */
  transform: rotate(calc(var(--az) * 1deg)) translateY(calc(-1 * (var(--rr) - 21px)))
             rotate(calc(-1 * var(--az) * 1deg - var(--cap, 0deg))); }
/* le nord se distingue à peine des trois autres : assez pour le trouver d'un
   coup d'œil, pas assez pour devenir un élément d'interface.
   ⚠️ Classe posée par radar.js, PAS `:first-of-type` — les tirets sont aussi des
   <span>, donc le premier de ce type est un tiret et la règle ne matchait rien. */
#view-radar .rd-bezel .rd-card.nord { color: rgba(200,216,236,.9); }

/* ÉTIQUETTES DE DISTANCE (demande de l'auteur : « la numérotation dans les
   cercles concentriques »). Posées juste sous chaque cercle, décalées de l'axe
   vertical pour ne pas s'asseoir sur la croix. Elles restent droites parce
   qu'elles vivent sur la couche statique. */
#view-radar .rd-dial .rd-lab { position: absolute; left: 50%; margin-left: 7px;
  font-family: 'Barlow'; font-size: .58rem; letter-spacing: .06em;
  color: rgba(150,180,215,.65); font-variant-numeric: tabular-nums;
  /* l'ombre porte n'est pas cosmétique : sans elle, le chiffre posé sur un
     cercle ou sur un axe devient illisible */
  text-shadow: 0 1px 3px rgba(0,0,0,.85), 0 0 6px rgba(0,0,0,.6); }
#view-radar .rd-dial .rd-lab.limite { color: rgba(110,231,156,.9); font-weight: 600; }

#view-radar .rd-disc .rd-cross { position: absolute; }
#view-radar .rd-disc .rd-cross.v { left: 50%; top: 0; bottom: 0; width: 1px;
  background: linear-gradient(to bottom, transparent 2%, rgba(111,168,255,.17) 26%,
    rgba(111,168,255,.17) 74%, transparent 98%); }
#view-radar .rd-disc .rd-cross.h { top: 50%; left: 0; right: 0; height: 1px;
  background: linear-gradient(to right, transparent 2%, rgba(111,168,255,.17) 26%,
    rgba(111,168,255,.17) 74%, transparent 98%); }
#view-radar .rd-dial .me { position: absolute; left: 50%; top: 50%; width: 8px; height: 8px;
  margin: -4px 0 0 -4px; border-radius: 50%; background: #6ee79c;
  box-shadow: 0 0 10px rgba(110,231,156,.9); }
#view-radar .rd-disc .beam { position: absolute; inset: 0; border-radius: 50%;
  background: conic-gradient(from 0deg, rgba(111,168,255,.42), rgba(111,168,255,.06) 22%, transparent 34%);
  animation: rdSweep 4s linear infinite; }
@keyframes rdSweep { to { transform: rotate(360deg); } }

/* les points : invisibles, puis flash au passage du faisceau */
#view-radar .blips { position: absolute; inset: 0; }
#view-radar .blip { position: absolute; width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px;
  border-radius: 50%; opacity: 0; animation: rdPing 4s linear infinite; }
@keyframes rdPing {
  0%   { opacity: 1; transform: scale(1.9); }
  10%  { opacity: .95; transform: scale(1); }
  70%  { opacity: .28; }
  100% { opacity: .12; }
}
#view-radar .blip.ok      { background: #6fa8ff; box-shadow: 0 0 10px rgba(111,168,255,.95); }
/* une NOUVEAUTÉ se distingue au premier regard : c'est ce qui fait sortir */
#view-radar .blip.neuf    { background: #6ee79c; box-shadow: 0 0 14px rgba(110,231,156,1);
  width: 11px; height: 11px; margin: -5.5px 0 0 -5.5px; }
#view-radar .blip.inconnu { background: #8fa1b8; box-shadow: 0 0 8px rgba(143,161,184,.7); }
#view-radar .blip.loin    { background: #46566b; box-shadow: none; }
/* Dans le cercle de 30 km mais TROP PETIT pour être vu à l'œil (taille
   apparente sous MIN_ARCMIN) : le déclencheur le refuserait. Creux plutôt que
   plein — il est là, mais on ne peut pas l'avoir. C'est ce qui rattrape
   l'approximation du cercle de limite. */
#view-radar .blip.petit   { background: transparent; box-shadow: none;
  border: 1.5px solid rgba(143,161,184,.75); }

/* légende du disque : sans elle, les couleurs des points sont une devinette */
#view-radar .rd-legend { display: flex; flex-wrap: wrap; justify-content: center;
  gap: 6px 14px; margin-top: 14px; font-family: 'Barlow'; font-size: .66rem; color: #8fa1b8; }
#view-radar .rd-legend span { display: inline-flex; align-items: center; gap: 5px; }
#view-radar .rd-legend i { width: 9px; height: 9px; border-radius: 50%; flex: 0 0 auto; }
#view-radar .rd-legend i.neuf { background: #6ee79c; }
#view-radar .rd-legend i.ok { background: #6fa8ff; }
#view-radar .rd-legend i.petit { border: 1.5px solid rgba(143,161,184,.75); }
#view-radar .rd-legend i.loin { background: #46566b; }

#view-radar .rd-stats { display: flex; align-items: baseline; gap: 12px; margin: 18px 0 4px; }
#view-radar .rd-count { font-family: 'Barlow Condensed'; font-style: italic; font-weight: 800;
  font-size: 1.5rem; color: #fff; }
#view-radar .rd-new { font-family: 'Barlow'; font-size: .84rem; color: #8fa1b8; }
#view-radar .rd-new.has { color: #6ee79c; font-weight: 600; }

#view-radar .rd-list { width: 100%; margin-top: 12px; display: flex; flex-direction: column; gap: 7px; }
#view-radar .rd-row { display: flex; align-items: center; gap: 10px; padding: 10px 13px;
  border-radius: 12px; background: rgba(255,255,255,.04); border: 1px solid rgba(255,255,255,.09);
  font-family: 'Barlow'; font-size: .88rem; color: #cfe0f5; }
#view-radar .rd-row.neuf { border-color: rgba(55,214,122,.42); background: rgba(55,214,122,.09); }
/* Lignes SANS le nom de l'avion depuis le 4 août 2026 (décision de l'auteur) :
   le rang à gauche, la distance à droite. Le nom en disait trop — le viseur ne
   dévoile pas l'appareil avant la capture, c'est une règle du projet, et le
   radar ne doit pas la contourner. Le rang suffit à faire sortir de chez soi. */
#view-radar .rd-row .tier { font-size: .68rem; letter-spacing: .1em; padding: 4px 9px;
  border-radius: 999px; background: rgba(255,255,255,.07); flex: 0 0 auto; }
#view-radar .rd-row .grow { flex: 1; min-width: 0; }
#view-radar .rd-row .tier.rare { color: #5fd0a4; } #view-radar .rd-row .tier.epique { color: #f096c8; }
#view-radar .rd-row .tier.legendaire { color: #d9b64a; } #view-radar .rd-row .tier.commune { color: #9db7d4; }
#view-radar .rd-row .km { color: #8fa1b8; font-variant-numeric: tabular-nums; }
#view-radar .rd-empty { text-align: center; font-family: 'Barlow'; font-size: .86rem;
  color: #8fa1b8; padding: 14px; }

/* capteurs pas démarrés : on explique au lieu de montrer un disque vide */
#view-radar .rd-gate { margin-top: 22px; text-align: center; }
#view-radar .rd-gate.hidden { display: none; }
#view-radar .rd-gate-t { font-family: 'Barlow'; font-size: .88rem; color: #9db0c6;
  line-height: 1.45; margin-bottom: 14px; }
#view-radar .rd-gate button { appearance: none; cursor: pointer; border: 0;
  background: var(--blue); color: #fff; border-radius: 999px; padding: 13px 28px;
  font-family: 'Barlow Condensed'; font-weight: 700; font-size: 1rem;
  letter-spacing: .08em; text-transform: uppercase; }

/* ============ VOLET D'ALERTE RARETÉ (5 août 2026) ============
   Prévient qu'un épique ou un légendaire vient d'entrer dans le rayon du radar.
   Glisse depuis le haut, se referme seul, et reste atteignable depuis n'importe
   quel onglet — c'est pour ça qu'il vit hors des vues.
   ⚠️ z-index sous les overlays de révélation et de montée en grade : une carte
   qu'on vient de retourner a la priorité (alerte.js s'en abstient aussi côté JS,
   les deux gardes sont volontaires). */
#alerte { position: absolute; top: 0; left: 0; right: 0; z-index: 40;
  padding: calc(10px + env(safe-area-inset-top)) 12px 0;
  pointer-events: none;
  transform: translateY(-130%); transition: transform .42s cubic-bezier(.2,.9,.25,1); }
#alerte.on { transform: translateY(0); pointer-events: auto; }
#alerte .al-box { display: flex; align-items: center; gap: 11px;
  background: rgba(13,22,38,.94); backdrop-filter: blur(10px);
  border: 1px solid var(--frame-solid, rgba(255,255,255,.14));
  border-left: 3px solid var(--accent, #f096c8);
  border-radius: 14px; padding: 11px 12px;
  box-shadow: 0 10px 30px rgba(0,0,0,.55); }
/* l'étoile reprend la couleur du tier : on reconnaît la rareté avant de lire */
#alerte .al-star { font-size: .82rem; letter-spacing: -1px; color: var(--accent, #f096c8);
  flex: 0 0 auto; }
#alerte .al-tx { flex: 1; min-width: 0; }
#alerte .al-t { font-family: 'Barlow Condensed'; font-style: italic; font-weight: 800;
  font-size: 1.02rem; color: #fff; line-height: 1.1; }
#alerte .al-s { font-family: 'Barlow'; font-size: .72rem; color: #9db0c6; margin-top: 1px; }
#alerte .al-go { appearance: none; cursor: pointer; flex: 0 0 auto;
  border: 0; background: var(--blue, #2f7bf0); color: #fff; border-radius: 999px;
  padding: 8px 15px; font-family: 'Barlow Condensed'; font-weight: 700;
  font-size: .82rem; letter-spacing: .08em; text-transform: uppercase; }
#alerte .al-x { appearance: none; cursor: pointer; flex: 0 0 auto;
  border: 0; background: transparent; color: #6b7a90; font-size: .9rem;
  padding: 6px 2px 6px 4px; line-height: 1; }

/* ============ RETOURS TESTEURS (temporaire, phase de test — 5 août 2026) ====
   Bouton discret au-dessus de TOUTE l'app + volet en 3 étapes, DA Skydex,
   AUCUN emoji (consigne). Préfixe fb- (règle des modules). Se coupe par
   CFG.FEEDBACK.ENABLED = false — ne pas supprimer, une prochaine phase de
   test le réutilisera. */
#fb-btn { position: absolute; top: calc(8px + env(safe-area-inset-top)); right: 12px;
  z-index: 39;   /* sous le volet d'alerte (40) : une alerte qui glisse passe devant */
  width: 34px; height: 34px; border-radius: 50%; padding: 0; cursor: pointer;
  background: rgba(10,16,24,.55); backdrop-filter: blur(6px);
  border: 1px solid rgba(255,255,255,.14); color: #8fa1b8;
  display: flex; align-items: center; justify-content: center; }
#fb-btn.hidden { display: none; }
#fb-btn svg { width: 17px; height: 17px; stroke: currentColor; fill: none; stroke-width: 1.8; }

#fb-overlay { position: absolute; inset: 0; z-index: 66; display: none;
  background: rgba(4,8,14,.72); backdrop-filter: blur(4px);
  align-items: flex-end; justify-content: center; }
#fb-overlay.open { display: flex; }
.fb-box { position: relative; width: 100%; max-width: 480px;
  background: #0d1626; border: 1px solid rgba(255,255,255,.1); border-bottom: 0;
  border-radius: 22px 22px 0 0; padding: 22px 20px calc(26px + env(safe-area-inset-bottom));
  animation: fbUp .32s cubic-bezier(.2,.9,.25,1); }
@keyframes fbUp { from { transform: translateY(40px); opacity: 0; } }

.fb-t { font-family: 'Barlow Condensed'; font-style: italic; font-weight: 800;
  font-size: 1.4rem; color: #fff; margin-bottom: 14px; }
.fb-x { position: absolute; top: 12px; right: 12px; appearance: none; border: 0;
  background: transparent; color: #6b7a90; font-size: .95rem; cursor: pointer; padding: 6px; }

.fb-choices { display: flex; flex-direction: column; gap: 9px; }
.fb-choice { display: flex; align-items: center; gap: 13px; text-align: left;
  appearance: none; cursor: pointer; background: rgba(255,255,255,.04);
  border: 1px solid rgba(255,255,255,.1); border-radius: 14px; padding: 13px 14px;
  color: #e6edf6; font-family: 'Barlow'; }
.fb-choice .ic { flex: 0 0 38px; height: 38px; border-radius: 50%;
  background: #14273f; display: flex; align-items: center; justify-content: center; }
.fb-choice .ic svg { width: 19px; height: 19px; stroke: #7fa8dd; fill: none; stroke-width: 1.8; }
.fb-choice .tx { display: flex; flex-direction: column; gap: 1px; }
.fb-choice .tx b { font-size: .95rem; font-weight: 600; }
.fb-choice .tx i { font-style: normal; font-size: .74rem; color: #8fa1b8; }

.fb-msg { width: 100%; min-height: 120px; resize: vertical;
  background: rgba(255,255,255,.05); border: 1px solid rgba(255,255,255,.12);
  border-radius: 12px; color: #fff; font-family: 'Barlow'; font-size: .95rem;
  padding: 12px 13px; line-height: 1.45; }
.fb-msg:focus { outline: none; border-color: rgba(61,139,253,.55); }

.fb-shot { display: flex; align-items: center; gap: 11px; cursor: pointer;
  background: rgba(255,255,255,.04); border: 1px dashed rgba(255,255,255,.2);
  border-radius: 12px; padding: 12px 13px; color: #9db0c6;
  font-family: 'Barlow'; font-size: .86rem; margin-bottom: 14px; }
.fb-shot .ic svg { width: 18px; height: 18px; stroke: #7fa8dd; fill: none; stroke-width: 1.8; }
.fb-shot i { font-style: normal; color: #6b7a90; }
.fb-lab { display: block; font-size: .68rem; letter-spacing: .08em; text-transform: uppercase;
  color: #8fa1b8; margin: 2px 0 6px; }
.fb-name { width: 100%; background: rgba(255,255,255,.05);
  border: 1px solid rgba(255,255,255,.12); border-radius: 12px; color: #fff;
  font-family: 'Barlow'; font-size: .95rem; padding: 12px 13px; }
.fb-name:focus { outline: none; border-color: rgba(61,139,253,.55); }

.fb-row { display: flex; gap: 10px; margin-top: 16px; }
.fb-sec { flex: 0 0 auto; appearance: none; cursor: pointer;
  border: 1px solid #33415c; background: transparent; color: #9db0c6;
  border-radius: 999px; padding: 12px 20px; font-family: 'Barlow'; font-size: .88rem; }
.fb-cta { flex: 1; appearance: none; cursor: pointer; border: 0;
  background: var(--blue, #2f7bf0); color: #fff; border-radius: 999px; padding: 13px 22px;
  font-family: 'Barlow Condensed'; font-weight: 700; font-size: 1rem;
  letter-spacing: .08em; text-transform: uppercase; }
.fb-cta:disabled { opacity: .35; cursor: default; }
.fb-err { margin-top: 12px; font-family: 'Barlow'; font-size: .82rem; color: #fda4af; }

.fb-done { text-align: center; padding: 8px 0 4px; }
.fb-done .ic { display: inline-flex; width: 52px; height: 52px; border-radius: 50%;
  background: rgba(55,214,122,.12); border: 1px solid rgba(55,214,122,.4);
  align-items: center; justify-content: center; margin-bottom: 12px; }
.fb-done .ic svg { width: 24px; height: 24px; stroke: #4ade80; fill: none; stroke-width: 2.2; }
.fb-done p { font-family: 'Barlow'; font-size: .88rem; color: #9db0c6;
  margin: 6px 0 18px; line-height: 1.5; }
