/* Accueil — scène « les modules en orbite » (boss 16/10, prototype B2 : propositions/B2_modules_en_orbite_fluide.html).
   Remplace la maquette « Factures récentes » dans l'en-tête. Feuille statique versionnée : modifier = bumper ?v= dans
   templates/home.html ET réécrire static/css/accueil_orbite.css.version (pré-porte).
   Structure : .orb > .orb-view (cadre à ratio fixe, conteneur) > .orb-scene (522×640 de conception, mise à l'échelle)
   .ob-md = carte-module ; .ob-pl = picto de lieu ; .ob-pt = particule ; .ob-tr.ob-in / .ob-rt = trait aller / retour.
   États posés par static/js/accueil_orbite.js : .ob-go (mini-scène rejouée), .ob-on (carte en cours), .ob-up (pastille
   reçue, texte = data-up), .ob-hit (centre touché), .ob-idle (hors écran : mouvements permanents en pause),
   .ob-still (sans mouvement : image fixe, tout allumé). Toutes les classes sont préfixées ob- (.badge, .pill existent
   ailleurs). Aucune couleur sur un élément nu (garde contraste 16/10) ; textes ≥ 4,5:1 sur leurs fonds. */
.orb{position:relative;margin:0 auto;max-width:640px}
.orb *,.orb *::before,.orb *::after{box-sizing:border-box}
.orb-cap{margin:12px auto 0;max-width:560px;text-align:center;font-size:.86rem;line-height:1.5;color:#475569;unicode-bidi:plaintext}
/* cadre : le ratio suit la conception (522×640) ; la scène est dessinée à taille fixe puis mise à l'échelle du cadre */
.orb-view{position:relative;width:100%;aspect-ratio:522/640;container-type:inline-size}
.orb-scene{position:absolute;left:0;top:0;width:522px;height:640px;transform-origin:0 0;transform:scale(1);
  background:radial-gradient(ellipse at 50% 50%,#eaf2ff 0,rgba(255,255,255,0) 52%)}
@media (min-width:1400px){.orb-scene{transform:scale(1.1724)}}
@media (min-width:992px) and (max-width:1199.98px){.orb-scene{transform:scale(.8276)}}
@media (max-width:991.98px){.orb{max-width:560px;margin-top:28px}.orb-scene{transform:scale(1.0728)}}
@media (min-width:576px) and (max-width:767.98px){.orb-scene{transform:scale(.9425)}}
/* échelle exacte = largeur du cadre / 522 (tan∘atan2 donne un nombre) ; les navigateurs sans cqw gardent les paliers ci-dessus */
@media (min-width:760px){.orb-scene{transform:scale(tan(atan2(100cqw,522px)))}}
.orb-svg,.orb-tr{position:absolute;inset:0;width:100%;height:100%;overflow:hidden;z-index:0}
/* orbites qui dérivent sans fin, particules qui entrent (ciel) et sortent (bleu) */
.ob-rg{fill:none;stroke:#cfd5e2;stroke-width:1.2;stroke-dasharray:3 9;animation:ob-drift 40s linear infinite}
.ob-r2{stroke-dasharray:2 10;animation:ob-drift 55s linear infinite reverse}
@keyframes ob-drift{to{stroke-dashoffset:-300}}
.ob-pt{fill:#09bffe;visibility:hidden;animation:ob-flow 3.8s linear infinite}
.ob-pt.ob-o{fill:#024dec}
@supports (offset-path:path("M0 0h1")){.ob-pt{visibility:visible}}
@keyframes ob-flow{0%{offset-distance:0%;opacity:0}15%{opacity:.9}85%{opacity:.9}100%{offset-distance:100%;opacity:0}}
.ob-tr{fill:none;stroke-linecap:round;stroke-dasharray:.6 1;stroke-dashoffset:.6}
.ob-tr line{stroke-width:3}
.ob-tr line:first-child{stroke-width:11;opacity:.35}
.ob-in line{stroke:#09bffe}
.ob-rt line{stroke:#024dec}
.ob-core,.ob-md,.ob-ring,.ob-badge{z-index:1}
/* centre : disque + halo qui respire en continu */
.ob-core{position:absolute;left:50%;top:50%;width:108px;height:108px;transform:translate(-50%,-50%)}
.ob-core::before,.ob-core::after{content:"";position:absolute;inset:0;border-radius:50%;border:2px solid rgba(9,191,254,.6);animation:ob-breathe 3.6s ease-out infinite}
.ob-core::after{animation-delay:1.8s}
@keyframes ob-breathe{0%{transform:scale(1);opacity:.7}100%{transform:scale(1.6);opacity:0}}
.ob-disc{position:relative;width:100%;height:100%;border-radius:50%;background:#fff;border:1px solid #dde1eb;display:flex;align-items:center;justify-content:center;box-shadow:0 16px 36px -14px rgba(2,77,236,.4),0 0 0 0 rgba(9,191,254,0);transition:box-shadow .4s}
.ob-core.ob-hit .ob-disc{box-shadow:0 16px 36px -14px rgba(2,77,236,.4),0 0 0 12px rgba(9,191,254,.22);transition-duration:.1s}
.ob-disc svg{width:56px;height:56px}
/* cartes-modules (fixes) */
.ob-md{position:absolute;left:var(--x);top:var(--y);width:150px;transform:translate(-50%,-50%);background:#fff;border:1px solid #dde1eb;border-radius:12px;padding:8px 9px 9px;box-shadow:0 8px 20px -12px rgba(15,23,42,.25);transition:border-color .3s,box-shadow .3s,transform .3s}
.ob-md.ob-on{border-color:#024dec;box-shadow:0 0 0 3px rgba(2,77,236,.16),0 16px 32px -12px rgba(2,77,236,.5);transform:translate(-50%,-50%) scale(1.05)}
/* pastille « mise à jour reçue » (retour du centre) ; sans attribut data-up : rien */
.ob-md::after{content:attr(data-up);position:absolute;top:-9px;inset-inline-end:8px;background:#024dec;color:#fff;font-size:10px;font-weight:600;line-height:18px;padding:0 7px;border-radius:9px;box-shadow:0 4px 10px -4px rgba(2,77,236,.6);opacity:0;transform:translateY(4px);white-space:nowrap;unicode-bidi:plaintext}
.ob-md:not([data-up])::after{display:none}
.ob-md.ob-up::after{animation:ob-chip 1.6s ease-out forwards}
@keyframes ob-chip{0%{opacity:0;transform:translateY(4px) scale(.8)}12%{opacity:1;transform:none}80%{opacity:1;transform:none}100%{opacity:0;transform:translateY(-4px)}}
.ob-hd{display:flex;align-items:center;gap:7px;font-size:12px;font-weight:600;line-height:1.1;color:#1e293b}
.ob-hd i{flex:none;width:24px;height:24px;border-radius:8px;background:#e1f6ff;color:#024dec;display:flex;align-items:center;justify-content:center;transition:background .3s,color .3s}
.ob-md.ob-on .ob-hd i,.ob-still .ob-hd i{background:#024dec;color:#fff}
.ob-hd svg,.ob-pl svg{width:16px;height:16px;fill:none;stroke:currentColor;stroke-width:1.75;stroke-linecap:round;stroke-linejoin:round}
.ob-pl svg{width:17px;height:17px}
/* mini-scènes : l'état de repos est l'état « fait » ; .ob-go rejoue la scène (on revide, puis on remplit) */
.ob-ev{position:relative;margin-top:7px;font-size:10.5px;line-height:14px;color:#475569}
.ob-ev p{display:flex;justify-content:space-between;align-items:center;gap:6px;margin:0;min-height:14px}
.ob-ev b{font-weight:600;color:#1e293b;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
.ob-ev em{font-style:normal;font-variant-numeric:tabular-nums;font-weight:600;color:#1e293b;white-space:nowrap}
.ob-ev span{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
.ob-ev b,.ob-ev span,.ob-ev em,.ob-badge span{unicode-bidi:plaintext}
.ob-ev [dir=ltr]{unicode-bidi:isolate}
.ob-ev .ob-tt{border-top:1px dashed #dde1eb;margin-top:2px;padding-top:2px;color:#1e293b}
.ob-ev .ob-ok{color:#166534}
/* ticket balayé par une ligne de lecture, lignes qui s'allument au passage */
.ob-sl{position:absolute;left:4px;right:4px;top:0;height:2px;border-radius:2px;background:#024dec;box-shadow:0 0 10px 2px rgba(2,77,236,.5);opacity:0}
.ob-go .ob-sl{animation:ob-scan .8s ease-in-out forwards}
@keyframes ob-scan{0%{opacity:0;transform:translateY(0)}12%{opacity:1}88%{opacity:1}100%{opacity:0;transform:translateY(56px)}}
.ob-tk p{margin:0 -4px;padding:0 4px;border-radius:4px}
.ob-go .ob-tk p{animation:ob-lit .6s ease-out forwards;animation-delay:calc(var(--d,0)*1ms)}
@keyframes ob-lit{0%{background:transparent}30%{background:#eaf2ff}100%{background:transparent}}
/* barres de dépôt : se revident puis se remplissent, compteur qui revient */
.ob-ev u{display:block;height:6px;border-radius:3px;background:#eceff5;margin:3px 0 4px;overflow:hidden;text-decoration:none}
.ob-ev u i{display:block;height:100%;border-radius:3px;background:#024dec;transform:scaleX(var(--w,1));transform-origin:0 50%}
.ob-ev u i:dir(rtl){transform-origin:100% 50%}
.ob-go .ob-ev u i{animation:ob-refill .9s cubic-bezier(.3,0,.2,1) forwards;animation-delay:calc(var(--d,0)*1ms)}
@keyframes ob-refill{0%{transform:scaleX(var(--w,1))}18%{transform:scaleX(0)}100%{transform:scaleX(var(--w,1))}}
.ob-go .ob-st em{animation:ob-blink .9s ease-out forwards;animation-delay:calc(var(--d,0)*1ms)}
@keyframes ob-blink{0%{opacity:1}15%{opacity:0}55%{opacity:0}100%{opacity:1}}
/* lignes qui repassent par un squelette gris puis se remplissent en cascade. Le texte est soit plein, soit absent
   (steps) — jamais à demi transparent : la sonde de contraste lit la page pendant que la scène tourne. */
.ob-rx span,.ob-rx em{--c:#475569;border-radius:3px}
.ob-rx em,.ob-tt.ob-rx span{--c:#1e293b}
.ob-rx .ob-ok{--c:#166534}
.ob-go .ob-rx span,.ob-go .ob-rx em{animation:ob-reskel .7s ease-out forwards,ob-rehide .7s steps(1,end) forwards;animation-delay:calc(var(--d,0)*1ms)}
@keyframes ob-reskel{0%{background:transparent}25%{background:#eceff5}60%{background:#eceff5}100%{background:transparent}}
@keyframes ob-rehide{0%{color:var(--c)}25%{color:transparent}60%{color:var(--c)}100%{color:var(--c)}}
/* lignes qui se recalculent (creux puis retour) */
.ob-go .ob-pa p{animation:ob-recalc .6s ease-out forwards;animation-delay:calc(var(--d,0)*1ms)}
@keyframes ob-recalc{0%{opacity:1;transform:none}25%{opacity:.25;transform:translateY(4px)}100%{opacity:1;transform:none}}
/* valeur qui change : l'ancienne revient un instant, la nouvelle se repose */
.ob-ev .ob-sw{display:grid;justify-items:end}
.ob-sw span{grid-area:1/1}
.ob-sw .ob-o{opacity:0}
.ob-go .ob-sw .ob-o{animation:ob-old .8s ease-out forwards;animation-delay:calc(var(--d,0)*1ms)}
.ob-go .ob-sw .ob-n{animation:ob-new .8s ease-out forwards;animation-delay:calc(var(--d,0)*1ms)}
@keyframes ob-old{0%{opacity:0}10%{opacity:1}60%{opacity:1}75%{opacity:0}100%{opacity:0}}
@keyframes ob-new{0%{opacity:1;transform:none}10%{opacity:0;transform:translateY(4px)}65%{opacity:0;transform:translateY(4px)}100%{opacity:1;transform:none}}
.ob-ev .ob-pill{justify-items:start;margin-top:5px;height:20px}
.ob-pill span{border-radius:10px;padding:0 9px;line-height:20px;font-size:10.5px;font-weight:600;width:max-content}
.ob-pill .ob-o{background:#eceff5;color:#475569}
.ob-pill .ob-n{background:#e1f1e5}
/* pictos de lieux (coins et entre-deux) */
.ob-ring{position:absolute;inset:0;pointer-events:none}
.ob-pl{position:absolute;left:var(--x);top:var(--y);transform:translate(-50%,-50%);display:flex;flex-direction:column;align-items:center;gap:4px;font-size:10.5px;line-height:1;white-space:nowrap;color:#475569;transition:color .3s}
.ob-pl i{position:relative;width:32px;height:32px;border-radius:50%;background:#fff;border:1px solid #dde1eb;color:#475569;display:flex;align-items:center;justify-content:center;box-shadow:0 4px 12px -6px rgba(15,23,42,.3);transition:background .3s,border-color .3s,color .3s}
.ob-pl i::after{content:"";position:absolute;inset:-1px;border-radius:50%;border:2px solid #09bffe;opacity:0}
.ob-pl.ob-on,.ob-still .ob-pl{color:#024dec}
.ob-pl.ob-on i,.ob-still .ob-pl i{background:#e1f6ff;border-color:#0299d0;color:#024dec}
.ob-pl.ob-on i::after{animation:ob-ping .8s ease-out}
@keyframes ob-ping{0%{opacity:.9;transform:scale(1)}100%{opacity:0;transform:scale(2.1)}}
/* badge de fin de tour + étincelles ; il s'efface en fondu pendant que le tour suivant démarre */
.ob-badge{position:absolute;left:50%;top:calc(50% + 78px);transform:translate(-50%,-50%);white-space:nowrap}
.ob-badge span{position:relative;display:inline-block;background:#15803d;color:#fff;font-size:12px;font-weight:700;padding:6px 14px;border-radius:999px;box-shadow:0 10px 24px -10px rgba(21,128,61,.7);opacity:0;transform:scale(.5);transition:opacity .35s,transform .35s}
.ob-badge.ob-on span{animation:ob-pop .5s cubic-bezier(.3,1.6,.5,1) forwards}
@keyframes ob-pop{0%{opacity:0;transform:scale(.5)}60%{opacity:1;transform:scale(1.1)}100%{opacity:1;transform:scale(1)}}
.ob-badge i{position:absolute;left:50%;top:50%;width:6px;height:6px;margin:-3px;border-radius:50%;background:#024dec;opacity:0}
.ob-badge i:nth-child(2n){background:#09bffe}
.ob-badge i:nth-child(3n){background:#15803d}
.ob-badge.ob-on i{animation:ob-spark .7s ease-out forwards;animation-delay:calc(var(--k,0)*50ms)}
@keyframes ob-spark{0%{opacity:1;transform:rotate(var(--a)) translateX(16px) scale(1)}100%{opacity:0;transform:rotate(var(--a)) translateX(70px) scale(.2)}}
/* hors écran : les mouvements permanents sont mis en pause ; sans mouvement : image fixe, tout allumé */
.ob-idle .ob-rg,.ob-idle .ob-pt,.ob-idle .ob-core::before,.ob-idle .ob-core::after{animation-play-state:paused}
.ob-still *,.ob-still *::before,.ob-still *::after{animation:none!important;transition:none!important}
.ob-still .ob-pt{display:none}
.ob-still .ob-badge span,.ob-still .ob-md::after{opacity:1;transform:none}
@media (prefers-reduced-motion:reduce){
.orb-scene *,.orb-scene *::before,.orb-scene *::after{animation:none!important;transition:none!important}
.ob-pt{display:none}
.ob-badge span,.ob-md::after{opacity:1;transform:none}
.ob-pl{color:#024dec}.ob-pl i{background:#e1f6ff;border-color:#0299d0;color:#024dec}.ob-hd i{background:#024dec;color:#fff}
}
/* à l'étroit (téléphone) : grille 2 colonnes autour du centre, pictos en rangée dessous, sans mise à l'échelle */
@media (max-width:759.98px){
.orb-view{aspect-ratio:auto;container-type:normal}
.orb-scene{position:relative;width:auto;height:auto;transform:none;display:grid;grid-template-columns:minmax(0,1fr) 48px minmax(0,1fr);gap:12px 6px;background:none}
.orb-svg{display:none}
.ob-core{position:relative;left:auto;top:auto;transform:none;width:48px;height:48px;grid-area:2/2/4/3;align-self:center;justify-self:center}
.ob-disc svg{width:30px;height:30px}
.ob-md{position:relative;left:auto;top:auto;transform:none;width:auto;min-width:0;grid-column:var(--gc);grid-row:var(--gr)}
.ob-md.ob-on{transform:scale(1.03)}
.ob-ring{position:relative;grid-column:1/-1;grid-row:6;display:flex;flex-wrap:wrap;justify-content:center;gap:10px 0;padding-top:4px}
.ob-pl{position:relative;left:auto;top:auto;transform:none;flex:0 0 25%}
.ob-badge{position:relative;left:auto;top:auto;transform:none;grid-column:1/-1;grid-row:5;justify-self:center}
}
