:root { --map-header: calc(60px + env(safe-area-inset-top, 0px)); --sheet-height: min(380px, 50dvh); --sheet-height-expanded: 78dvh; --dht-panel-pad-x: 2rem; --dht-panel-pad-x-md: 2.5rem; --dht-panel-pad-top: 2rem; --dht-panel-pad-top-desktop: 3rem; --dht-panel-pad-bottom: 2.5rem; --dht-panel-pad-bottom-lg: 3rem; } /* Correctif mise en page desktop (2026-07-10, v5) : jetons d'espacement dedies et autonomes au panneau assistant. CAUSE REELLE du contenu "colle au bord" en desktop : tout le padding du panneau (.sheet-header/.sheet-content/.spot-detail) etait ecrit en var(--space-4, 2rem) etc. -- une valeur de repli qui ne s'applique QUE si --space-4 n'existe NULLE PART dans la cascade du navigateur. Si style.css (feuille externe, hors perimetre de ces 3 fichiers) declare deja --space-4/--space-5/--space-3/--space-6 -- meme a une valeur minime ou incoherente selon la version reellement deployee -- le repli "2rem" ecrit ici est silencieusement ignore (le repli var() ne joue jamais si la variable existe, quelle que soit sa valeur) et le panneau perd toute sa respiration sans qu'aucune ligne de ce fichier ne change : bug invisible a la simple lecture du code, qui explique le rendu "colle au bord" constate en prod alors que ce fichier semble correct. Ces nouveaux jetons --dht-panel-* sont definis ICI, dans carte.css, une seule fois : ils ne dependent plus jamais d'un fichier externe et ne peuvent plus etre neutralises par lui. Memes valeurs numeriques qu'avant (2rem/2.5rem/3rem) : aucun changement visuel voulu la ou ca fonctionnait deja, seulement une source unique et fiable partagee par la vue liste ET la vue detail. */ /* LOT Mobile Composition (2026-07-10) : reduit de min(430px, 58dvh) a min(380px, 50dvh) sur mobile. Diagnostic : au premier chargement, le panneau replie dominait deja la vue et reduisait l'archipel a un decor secondaire (retour utilisateur sur capture iPhone reelle). Objectif explicite du client : l'archipel doit rester le "hero" de la premiere vue, Miguel doit accompagner sans recouvrir. Compromis assume : sur les telephones les plus courts, le bouton "Autour de moi" peut necessiter un leger defilement dans le panneau (deja scrollable via .sheet-content) au lieu d'etre visible sans aucun geste -- ce compromis est un choix produit explicite de ce lot, pas un oubli. Le titre et l'etape en cours restent visibles sans geste. */ /* P6 (Phase 3, correctif historique conserve pour tracabilite) : 42dvh (~290px) ne suffisait pas a afficher l'etape en cours/suivante ET "Autour de moi" sans geste supplementaire ; remonte alors a 58dvh/430px. */ /* correctif P2 (audit) : la variable elle-meme inclut l'encoche, pour que .map-stage/.map-app qui l'utilisent ne se fassent pas recouvrir par un header agrandi */

/* LOT 6 (2026-07-10) -- Design System (carte.*) : jetons locaux additifs, valeurs strictement
   identiques a celles deja utilisees dans ce fichier (aucun changement visuel). Objectif :
   remplacer les valeurs repetees en dur par un nom d'intention, pour la maintenance future.
   Tache de fond, perimetre volontairement limite (pas de refonte globale de l'echelle
   typographique existante, qui resterait a valider visuellement sur un vrai navigateur avant
   toute fusion de valeurs proches -- voir changelog). */
:root {
  --map-text-2xs: 0.7rem;   /* micro-libelles (accroche meteo, notes tres discretes) */
  --map-text-xs: 0.75rem;   /* libelles secondaires courts */
  --map-text-sm: 0.78rem;   /* texte de support le plus frequent du panneau */
  --map-text-sm-alt: 0.8rem;
  --map-text-sm-alt2: 0.82rem;
  --map-text-base: 0.85rem; /* texte courant du panneau (valeur la plus utilisee) */
  --map-text-md: 0.9rem;    /* texte legerement renforce (intros, listes) */
  --map-state-warning-bg: #fff4e0;
  --map-state-warning-text: #7a5a12;
  --map-state-danger-bg: #fde3e0;
  --map-state-danger-text: #8a2c1f;
  --map-state-info-bg: #eef2f6;
  --map-state-info-text: #3d5266;
}
.map-page { height: 100dvh; overflow: hidden; background: var(--color-background); }
.map-header { position: fixed; inset: 0 0 auto; z-index: 40; display: flex; height: var(--map-header); align-items: center; justify-content: space-between; gap: var(--space-3); padding-inline: var(--space-4); padding-top: env(safe-area-inset-top, 0px); border-bottom: 1px solid rgba(221, 215, 203, 0.72); background: rgba(247, 244, 237, 0.92); backdrop-filter: blur(16px); } /* correctif P2 (audit) : dégagement de l'encoche / Dynamic Island via la variable --map-header, sans effet sur les appareils sans encoche (env() vaut alors 0) */
.map-brand, .map-header__link { display: inline-flex; align-items: center; color: var(--color-text); font-weight: 800; text-decoration: none; }
.map-brand { gap: var(--space-2); } .map-brand img { width: 44px; height: auto; }
.map-header__link { min-height: 40px; padding-inline: var(--space-3); border-radius: var(--radius-pill); background: var(--color-surface); font-size: 0.875rem; }
.map-app { position: relative; height: 100dvh; padding-top: var(--map-header); }
.map-stage { position: relative; height: calc(100dvh - var(--map-header)); overflow: hidden; background: radial-gradient(circle at 20% 8%, rgba(210, 232, 220, 0.8), transparent 38%), linear-gradient(165deg, #eef6ee 0%, #f5f0e2 55%, #faf6ef 100%); } /* LOT 2 (2026-07-10, Direction B) : degrade legerement rechauffe (la mer va vers la Creme de marque --color-bg-primary en bas de scene plutot que vers un blanc-menthe froid) -- reste une atmosphere discrete : memes deux couches (radial + lineaire), aucune texture/image ajoutee ; opacite du halo radial reduite (0.9 -> 0.8) et etalee (30% -> 38%) pour eviter tout effet "spot" qui attirerait l'oeil avant l'archipel lui-meme. */
/* correctif Option C (audit cartographique) : silhouette réelle de l'île sélectionnée, sous les points */
/* v4 (direction artistique, 2026-07-12) : ombre portee renforcee (vue ile detaillee) pour une
   vraie sensation de relief/territoire souleve, plutot que le simple contour "carte plate"
   precedent -- le double palier (portee + diffusion) reste leger, jamais un aplat noir. */
.ile-silhouette { fill: url(#dht-ile-premium-fill); stroke: #0f5f5c; stroke-width: 2.5; stroke-linejoin: round; opacity: 0.9; filter: drop-shadow(0 6px 14px rgba(15, 62, 59, 0.22)) drop-shadow(0 1.5px 3px rgba(15, 62, 59, 0.18)); } /* Rendu illustre premium (2026-07-12) : le degrade (defini une seule fois dans carte.html, cf. commentaire "Rendu illustre premium des iles") remplace la teinte plate #dff3ef -- meme couleur de depart et meme contour/trait, juste une profondeur de surface en plus ; l'ombre portee tres douce (drop-shadow) detache l'ile du fond marin, cf. demande "sensation de decouverte", sans jamais aller vers un style jeu video (flou minime, opacite faible). */
/* Phase B (audit cartographique — vue "Toutes les îles") : même silhouette, trait plus fin à
   petite échelle pour rester élégant ("carnet de voyage"), jamais un rendu carte technique. */
.ile-silhouette--mini { stroke-width: 1.5; opacity: 0.97; filter: drop-shadow(0 1.5px 3px rgba(15, 62, 59, 0.14)); } /* LOT 2 (2026-07-10, Direction B) : trait tres legerement renforce (1.3 -> 1.5) pour un rendu "carnet" un peu plus present en vue archipel -- ne touche pas .ile-silhouette (vue ile detaillee, hors perimetre de cette refonte). Rendu illustre premium (2026-07-12) : ombre portee identique mais plus legere, proportionnee a la petite echelle archipel. */
/* ==========================================================================
   RENDU ILLUSTRE PREMIUM DES ILES (2026-07-12) -- couches decoratives ajoutees par
   construireIleIllustree() (carte.js) AU-DESSUS de .ile-silhouette (meme contour, jamais remplace).
   Toutes ces couches sont purement visuelles : pointer-events:none pour ne jamais intercepter un
   clic/tap destine a l'ile ou a un pin (la delegation de clic reste sur data-island-id, cf. carte.js).
   ========================================================================== */
.ile-illustree, .ile-illustree--mini { pointer-events: none; }
.ile-silhouette-shade { fill: url(#dht-ile-premium-shade); stroke: none; mix-blend-mode: multiply; pointer-events: none; } /* Ombrage interne doux (vignette) colle au contour via clip-path : suggere un relief/une profondeur sans jamais depasser l'ile ni ajouter de nouvelle geometrie. */
.ile-silhouette-shade--mini { opacity: 0.85; } /* legerement attenue a petite echelle pour rester "carnet", jamais charge */
.ile-relief { stroke: none; pointer-events: none; opacity: 0.9; }
.ile-relief--highland { fill: url(#dht-ile-relief-highland); } /* accent tres discret suggerant un relief/zone volcanique, deduit du centre geometrique du contour -- aucune nouvelle coordonnee par ile */
.ile-relief--vegetal { fill: url(#dht-ile-relief-vegetal); } /* accent tres discret suggerant une zone vegetale basse, meme principe */
/* v6 (illustration cartographique premium, 2026-07-12) -- demande client explicite : le relief ne
   doit plus venir "d'une ombre + un degrade" mais de plusieurs couches TRES faibles superposees
   (voir construireReliefDiffus, carte.js, pour la generation des positions/tailles) : ici, juste
   le rendu graphique de chaque couche -- flou doux (jamais net, jamais "jeu video"), opacite
   volontairement basse car l'effet vient de l'ACCUMULATION de plusieurs couches, pas d'une seule. */
.ile-relief--diffus { opacity: 0.55; filter: blur(7px); }
/* v7 (relief topographique structure, 2026-07-12) : les cretes/massif central restent un peu plus
   nets (flou reduit, opacite legerement plus haute) pour que l'oeil lise une VRAIE arete, tandis
   que les vallees/zones vegetales restent tres diffuses (flou plus large) pour ne jamais rivaliser
   visuellement avec les cretes -- c'est cette hierarchie de nettete qui produit une lecture "relief
   topographique" plutot que "plusieurs taches identiques". */
.ile-relief--highland.ile-relief--diffus, .ile-relief--sommet.ile-relief--diffus { filter: blur(5px); opacity: 0.65; }
.ile-relief--ombre.ile-relief--diffus, .ile-relief--vegetal.ile-relief--diffus { filter: blur(9px); }
/* Correctif hillshade "rendu naturel" (2026-07-13, audit rendu final -- demande client explicite :
   "trop de micro-contrastes, zones blanches triangulaires, ombres trop nettes, aspect facette").
   Cause reelle identifiee : la finition precedente (v3, "hillshade plus marque") retirait tout flou
   sur ces deux couches pour un bord "net, fidele au DEM" -- mais un contour cv2 issu d'un seuillage
   binaire du hillshade suit le pixel du raster DEM, ce qui rend chaque petite facette de pente
   visible comme un polygone dur (l'aspect "low-poly"/triangule denonce). On reintroduit ici un flou
   MODERE (pas l'ancien flou 9px/5px trop diffus d'avant la v3, un compromis) qui fusionne les petites
   facettes voisines en degrade continu tout en preservant les grandes structures volcaniques (une
   caldeira ou un rempart reste largement plus grand que le rayon de flou, donc toujours lisible).
   AUCUNE donnee/JSON modifiee : uniquement le rendu de la meme geometrie "ombrage"/"lumiere" du DEM. */
.ile-relief--ombre { fill: url(#dht-ile-relief-ombre); mix-blend-mode: multiply; filter: blur(3px); } /* ombre interne de vallee -- suggere un creux/une depression sans jamais dessiner de nouvelle geometrie */
.ile-relief--crete { fill: url(#dht-ile-relief-crete); mix-blend-mode: soft-light; filter: blur(2.4px); } /* lueur de crete -- suggere une pente eclairee rasamment, complementaire de la lumiere douce globale */
/* Hillshade "rendu naturel" v2 (2026-07-13, audit final) : degrade directionnel UNIQUE pose sur le
   contour ENTIER de l'ile (voir dht-relief-lumiere-nw/dht-relief-ombre-se, carte.html -- azimut
   NO->SE, meme direction que le hillshade reel), revele localement par un masque flou construit a
   partir des vraies zones ombrage/lumiere du DEM (voir construireReliefDEM, carte.js). Remplace les
   anciennes couches .ile-relief--ombre/--crete (ci-dessus, TOUJOURS utilisees par le relief
   PARAMETRIQUE de repli -- construireReliefDiffus -- donc jamais retirees) pour le rendu DEM reel :
   plus aucun bord de polygone dur, uniquement un degrade continu, intensite volontairement faible. */
.ile-relief--ombre-globale { fill: url(#dht-relief-ombre-se); mix-blend-mode: multiply; opacity: 0.85; }
.ile-relief--lumiere-globale { fill: url(#dht-relief-lumiere-nw); mix-blend-mode: soft-light; opacity: 0.85; }
/* v7 (relief topographique structure, 2026-07-12) -- ton dedie au massif central (sommet/caldeira
   suggere par dhtAxePrincipal + construireReliefDiffus, carte.js), plus opaque et plus sombre que
   les cretes secondaires pour marquer visuellement le point culminant de chaque ile. */
.ile-relief--sommet { fill: url(#dht-ile-relief-sommet); mix-blend-mode: multiply; }
/* v6 : legere texture de grain (feTurbulence, cf. carte.html #dht-ile-grain) -- casse le rendu
   "dégradé numérique parfaitement lisse" pour donner une sensation de matière/territoire vivant.
   Opacite tres basse : perceptible seulement de tres pres, jamais un bruit visible a l'oeil nu. */
.ile-relief--grain { filter: url(#dht-ile-grain); mix-blend-mode: overlay; opacity: 0.05; }
/* v4 (direction artistique, 2026-07-12) : lisere de rive lumineux (voir construireIleIllustree,
   carte.js) -- fill:none + clip-path deja pose la-bas ne laisse voir que la moitie interieure du
   trait, donnant une fine cote eclairee juste en retrait du contour, sur vue ile ET archipel
   (plus discret en mini pour ne jamais alourdir la vue d'ensemble). */
.ile-relief--rive { fill: none; stroke: #fef8e8; stroke-width: 3.5; opacity: 0.4; }
.ile-relief--rive--mini { stroke-width: 2; opacity: 0.28; }
/* v5 (direction artistique concierge, 2026-07-12) : lumiere douce (voir dht-ile-lumiere-douce, carte.html) -- meme calque additif que la rive ci-dessus, opacite volontairement faible pour rester une illustration discrete. */
.ile-relief--lumiere { fill: url(#dht-ile-lumiere-douce); }
.ile-relief--lumiere--mini { opacity: 0.7; }
/* REMPLACEMENT COMPLET DU MOTEUR DE RELIEF (2026-07-12) -- nouvelles couches demandees :
   Couche 3 "courbes de niveau" (lignes fines concentriques autour des massifs reels, jamais sur
   les "valley") + accent "lac de cratere" + Couche 1 "fond terrain" non uniforme. */
/* Finition premium (2026-07-13, demande client "detail subtil, pas une texture dominante") :
   opacite et epaisseur fortement reduites -- desormais un detail cartographique discret, la
   lecture principale du relief etant portee par .ile-relief--hypso (teinte par palier reel) et
   par l'ombrage/lumiere renforces ci-dessus, jamais par ces traits. Le dernier palier (sommet/
   crete, --serre) reste volontairement un peu plus visible que les autres, pour rester repérable. */
/* Correctif esthetique v2 (2026-07-13, demande client "quasi imperceptibles, garder uniquement
   les grandes lignes structurantes") : opacite encore reduite (0.09 -> 0.055) et trait plus fin
   (0.6 -> 0.45). Le sous-echantillonnage cote JS (construireReliefDEM, seuilAdaptatif) fait deja le
   plus gros du travail de reduction de densite ; cette regle ne fait plus qu'estomper ce qui reste. */
.ile-relief--niveau { fill: none; stroke: #0a3d3b; stroke-width: 0.45; opacity: 0.055; }
.ile-relief--niveau--fin { opacity: 0.065; stroke-width: 0.4; } /* moteur relief donnees reelles (2026-07-13) : niveau intermediaire ajoute UNIQUEMENT pour les sommets dont l'altitude reelle verifiee depasse 1500 m (voir construireReliefDiffus/carte.js) -- meme famille visuelle que .ile-relief--niveau, juste une densite proportionnelle a une vraie donnee d'altitude. */
.ile-relief--niveau--serre { opacity: 0.15; stroke-width: 0.6; }
/* Teinte hypsometrique reelle (2026-07-13) -- voir dhtHypsometrie()/construireReliefDEM() dans
   carte.js : une forme remplie par palier d'altitude reel (littoral clair -> sommet marque),
   c'est elle qui porte desormais la lecture principale du relief DEM. fill/opacity fixes en JS
   (varient par palier), cette regle ne pose que le comportement de fusion avec les couches
   existantes (jamais de trait, jamais d'ombre projetee propre -- purement une teinte de surface). */
.ile-relief--hypso { stroke: none; mix-blend-mode: multiply; filter: blur(1.1px); } /* correctif hillshade naturel (2026-07-13) : flou tres leger, juste assez pour lisser les angles durs entre paliers d'altitude adjacents (memes contours "d" que les isolignes), sans jamais fusionner deux paliers voisins ni atténuer la teinte elle-meme. */
.ile-relief--lac { fill: url(#dht-ile-relief-lac); mix-blend-mode: normal; }
.ile-relief--lac.ile-relief--diffus { filter: blur(3px); opacity: 0.7; }
/* Lacs REELS issus du DEM (2026-07-13, correctif audit rendu final) : meme famille de couleur que
   .ile-relief--lac ci-dessus (aucune nouvelle teinte inventee), mais SANS le blur(3px) prevu pour
   une grosse ellipse artistique -- un vrai polygone OSM peut ne mesurer que 1 a 3 px sur le canevas
   900x520 (ex. "Poça Simão Dias" a São Jorge, plusieurs lagoas de Terceira/Flores) : un flou de 3px
   y serait destructeur (rayon de flou superieur a la taille de la forme), rendant le lac invisible
   -- exactement l'inverse du "toujours visible au-dessus du relief" demande. Une fine bordure
   (meme teinte que le degrade, jamais une nouvelle couleur) garantit la visibilite meme a l'echelle
   du pixel unique, sans jamais donner un aspect "pastille" artificiel (opacite du trait moderee,
   pas de contour dur/noir). */
.ile-relief--lac-reel { fill: url(#dht-ile-relief-lac-reel); mix-blend-mode: normal; stroke: #2f6a78; stroke-width: 0.85; stroke-opacity: 0.65; opacity: 1; filter: drop-shadow(0 0 1px rgba(47,106,120,0.35)); } /* POLISSAGE UI (2026-07-14, demande client "lacs plus lisibles, sans transformer en carte hydrographique") : opacite globale 0.9->1 (+11%, dans la fourchette demandee 10-15%) -- degrade dht-ile-relief-lac-reel (carte.html) volontairement NON touche : la meme teinte bleu-vert et la meme transparence relative sont conservees, seule la presence globale augmente legerement (et le contraste centre/bord avec, par effet mecanique de l'echelle). */ /* retouche finale (2026-07-13, verif finale -- demande client "remplissage bleu-vert TRES leger, contour fin, legere transparence, priorite au-dessus du relief") : degrade et opacite globale legerement allegees par rapport au correctif Round 2 (qui visait avant tout a rendre les tres petits lacs a nouveau VISIBLES apres le bug du blur -- objectif atteint) ; ce reglage plus fin les garde parfaitement lisibles (Lagoa do Fogo, Sete Cidades, Furnas verifie) tout en restant un accent discret, jamais une tache pleine. */ /* Etape C (2026-07-13, controle rendu final) : demande client -- les lacs restaient trop discrets (Sete Cidades lu comme une ombre grise, Lagoa do Fogo peu identifiable, petits plans d'eau a peine visibles). Renforce uniquement : opacite globale (0.78->0.9), opacite du contour (0.5->0.65) et epaisseur du contour (0.6->0.85, tres legerement, garde des "contours doux") + une micro-lueur (drop-shadow 1px, tres faible alpha 0.35) qui detache l'eau du relief raster sans jamais tomber dans un bleu carte touristique. Le degrade associe (dht-ile-relief-lac-reel, carte.html) passe d'une teinte plate unique a un vrai centre plus clair (#6f9fa3) vers des bords plus profonds (#2f6a78), toujours la meme famille de couleur bleu-vert deja validee -- aucune nouvelle teinte inventee. Aucune geometrie JSON touchee : le petit surcroit de lisibilite des tres petits lacs (Poca Simao Dias, Lagoa do Caldeirao, petites lagoas de Terceira/Flores/Pico) vient uniquement du contour plus marque + de la lueur, jamais d'un changement de taille de path. */
/* Finition "rendu premium" (2026-07-13, 2e passe -- demande client "remplissage bleu-vert TRES
   LEGER, contour fin, legere transparence, priorite au-dessus du relief") : degrade/trait allege par
   rapport a la version precedente (plus contrastee, elle visait a garantir la seule visibilite sur
   fond tres pale) -- reste au-dessus de tout le relief (voir ordre d'empilement, construireIleIllustree)
   et garde un contour fin net, mais la teinte est desormais discrete plutot que marquee. Aucun effet
   sur .ile-relief--lac ni sur les autres iles/rendus (classe dediee). */
/* Contour final de l'ile (2026-07-13, correctif audit rendu final) : redessine le MEME trait que
   .ile-silhouette (ligne ~35), au sommet de la pile du groupe .ile-illustree -- garantit que la
   côte reste nette au-dessus du relief/hillshade/lacs (ordre de calques explicitement demande),
   sans jamais recouvrir un pin/label (ceux-ci vivent dans des groupes SVG places APRES dans le DOM,
   voir carte.html). fill:none : ne repeint jamais l'interieur, uniquement le trait. */
.ile-contour-final { fill: none; stroke: #0f5f5c; stroke-width: 2.5; stroke-linejoin: round; opacity: 0.9; pointer-events: none; }
.ile-relief--fond-texture { fill: url(#dht-ile-relief-vegetal); opacity: 0.35; mix-blend-mode: soft-light; filter: blur(14px); }
/* RASTER de relief premium (2026-07-13, verif finale -- classe manquante ajoutee) : une seule <image>
   (voir construireReliefDEM/carte.js), deja continue et pre-lissee a la generation hors-ligne
   (generer_relief_raster.py -- hillshade analytique + teinte hypsometrique tres discrete, fond ivoire
   dominant, alpha deja pre-masque au contour exact de l'ile). mix-blend-mode: normal (le raster porte
   deja sa propre couleur/teinte finale, contrairement aux couches vectorielles ci-dessus qui teintent
   par-dessus un fond neutre) ; opacite legerement < 1 pour laisser transparaitre .ile-silhouette-shade
   (vignette de profondeur) sous le raster, coherence avec le reste du rendu. pointer-events:none comme
   tout le reste du relief (jamais interactif). image-rendering en douceur pour un agrandissement/zoom
   sans aucun artefact de pixellisation (coherent avec la demande "aucun polygone dur"). */
/* CALIBRATION FINALE DU RENDU (2026-07-13, etape 4 -- demande client "relief trop plat apres
   reduction des contrastes anti-facette") : audit du rendu reel a confirme que la cause n'est PAS
   un manque de contraste dans le PNG lui-meme (sa luminance interne s'etale deja largement, de
   ~17% a ~98%) mais son canal alpha, volontairement tres bas a la generation (max reel ~0.19,
   moyenne ~0.12 sur les zones non transparentes) pour eviter l'aspect "facette" denonce -- or ce
   raster est compose en mix-blend-mode normal par-dessus le fond ivoire de l'ile, donc a cette
   alpha le resultat est ~88% fond ivoire + 12% raster : le relief est mathematiquement noye avant
   meme d'atteindre l'ecran. AUCUNE modification du PNG/JSON/chargement : deux leviers CSS agissent
   avant ce compositing et restent donc efficaces malgre l'alpha bas :
   - opacity 0.94 -> 1 : exploite la totalite de l'alpha deja present dans le raster (gain modeste
     mais gratuit, aucune contrepartie).
   - filter contrast(1.4) saturate(1.22) : amplifie l'ecart clair/sombre et la teinte du raster
     AVANT qu'il ne soit dilue par l'alpha, donc ce qui traverse le compositing diverge davantage du
     fond ivoire -- lisibilite immediate des reliefs volcaniques (Sete Cidades, Lagoa do Fogo,
     Furnas sur Sao Miguel) sans reintroduire l'effet dur/facette (valeurs choisies et verifiees par
     simulation du compositing reel, dans la fourchette +20/+40% demandee, mix-blend-mode reste
     "normal" -- verifie mathematiquement plus efficace que multiply/hard-light a ce niveau d'alpha
     et seul mode qui restitue a la fois les creux ombres ET les cretes lumiere). Fond ivoire
     toujours dominant (l'alpha reste bas), aucune ombre/teinte sombre ajoutee, labels/POI/lacs non
     concernes (couches separees). */
/* CALIBRATION -- ETAPE 5 (2026-07-13, demande client "reste trop brumeux, topographie volcanique
   pas assez lisible malgre l'etape 4") : le plafond reel restait le canal alpha du PNG (~0.12 a 0.19
   sur 1, cf. commentaire etape 4 plus bas), qu'aucun reglage d'une couche UNIQUE ne peut depasser --
   pousser encore le contraste/opacite d'une seule image butait sur ce plafond sans gain reel de
   lisibilite. Solution retenue (piste "double rendu" demandee par le client) : le meme raster est
   maintenant duplique par carte.js en une SECONDE <image> (.ile-relief-raster-volume, voir
   construireReliefDEM) -- aucun nouvel asset, aucune donnee supplementaire, seulement une deuxieme
   composition du PNG deja charge. Les deux couches en mix-blend-mode normal s'additionnent selon
   1-(1-a1)*(1-a2) : la couverture alpha effective augmente reellement (jusqu'a ~+40% dans les zones
   de relief marque) sans jamais atteindre l'opacite totale, donc l'ivoire reste dominant partout ou
   le relief est faible. Repartition des roles (verifiee par simulation du compositing reel avant
   application) :
   - .ile-relief-raster = couche PRINCIPALE, doux : contraste/saturation moderes, porte la lecture de
     base du relief (comme avant, mais moins pousse qu'en etape 4 puisque la 2e couche complete l'effet).
   - .ile-relief-raster-volume = couche de VOLUME, faible opacite globale (0.55) mais contraste local
     nettement plus marque + leger gain de luminosite (brightness > 1, PAS un assombrissement) --
     conformement a la piste client "augmenter la luminosite des zones hautes plutot qu'assombrir" :
     elle renforce preferentiellement les cretes/rebords de caldeira (Sete Cidades), les massifs
     (Furnas) et les pentes autour des lacs (Lagoa do Fogo) sans jamais assombrir les zones plates.
   Aucun mode "multiply/hard-light" utilise (verifie plus agressif/artificiel et moins fidele aux
   hautes lumieres a ce niveau d'alpha) -- rendu volontairement teinte/doux, jamais satellite/militaire. */
.ile-relief-raster { opacity: 1; mix-blend-mode: normal; filter: contrast(1.2) saturate(1.1); pointer-events: none; image-rendering: -webkit-optimize-contrast; image-rendering: optimizeQuality; image-rendering: high-quality; }
.ile-relief-raster-volume { opacity: 0.55; mix-blend-mode: normal; filter: contrast(1.75) saturate(1.15) brightness(1.06); pointer-events: none; image-rendering: -webkit-optimize-contrast; image-rendering: optimizeQuality; image-rendering: high-quality; }
/* MICRO-AJUSTEMENT -- ETAPE 6 (2026-07-13, demande client "propre mais manque encore de lecture
   volumetrique, NE PAS augmenter le contraste global, ajouter seulement de la profondeur, opacite
   0.10 a 0.20 max"). Troisieme reutilisation du meme raster (aucun nouvel asset/donnee -- voir
   construireReliefDEM). Choix deliberes pour rester strictement dans le cadre demande :
   - mix-blend-mode MULTIPLY (au lieu de normal comme les deux couches precedentes) : multiply ne
     peut mathematiquement que foncer un pixel, jamais l'eclaircir -- donc aucune contribution
     possible a un "gain de contraste global", uniquement un supplement d'ombre/profondeur localise
     aux zones ou le raster porte deja une information de pente (interieur de caldeira, pourtour de
     lac de montagne, flancs de massif).
   - AUCUN filter ajoute (pas de contrast()/saturate()) : la teinte utilisee est celle du raster brut,
     simplement attenuee par l'opacite tres faible -- pur ombrage, pas de retouche de contraste.
   - opacity 0.18 (dans la fourchette 0.10-0.20 demandee) : effet volontairement discret, jamais
     suffisant pour faire basculer une zone plate/claire vers du sombre (l'ivoire y reste dominant,
     seules les zones qui avaient deja un peu de matiere en gagnent un peu plus). */
.ile-relief-raster-ombrage { opacity: 0.18; mix-blend-mode: multiply; pointer-events: none; image-rendering: -webkit-optimize-contrast; image-rendering: optimizeQuality; image-rendering: high-quality; }
/* ETAPE C (2026-07-13, demande client "ajouter uniquement une couche additive independante --
   sommets/caldeiras, sans jamais modifier le relief actuel"). 4e <image> (voir
   construireReliefDEM/carte.js, class="ile-relief-raster-accent"), nouvel asset totalement
   distinct (assets/relief/{id}-accent.png -- genere par generer_accent() dans
   generer_relief_raster.py, ajoute a part). Regle volontairement minimale, exactement comme
   demande : uniquement opacity + mix-blend-mode, AUCUN filter()/contrast()/saturate()/blur()/
   transform()/masque CSS -- le PNG contient deja tout (teinte fixe ivoire/gris-vert + intensite
   deja calculee a la generation, filtre par composantes connexes niveau MOYEN deja applique).
   mix-blend-mode NORMAL (comme .ile-relief-raster/-volume, pas MULTIPLY comme -ombrage) car cette
   couche doit pouvoir aussi bien eclaircir (sommets) qu'assombrir (caldeiras) selon le pixel --
   multiply ne pourrait jamais eclaircir. opacity 0.9 (leger retrait volontaire sous 1, dernier
   garde-fou cote CSS) : l'alpha reel de chaque pixel reste de toute facon tres bas (deja plafonne
   a la generation, cf. ALPHA_MAX_ACCENT=0.40 combine a une intensite normalisee), donc l'ivoire de
   fond reste partout dominant -- l'utilisateur doit sentir "le relief actuel plus lisible", jamais
   voir une nouvelle couche. */
.ile-relief-raster-accent { opacity: 0.9; mix-blend-mode: normal; pointer-events: none; }


/* Halo discret derrière chaque nom d'île : lisibilité garantie sans jamais recouvrir de
   pin/silhouette voisine, ton chaud cohérent avec --color-surface-muted, pas de style "GPS militaire". */
/* LOT 2 (2026-07-10) -- Carte archipel, lisibilite des noms d'iles : chip plus opaque + ombre
   tres discrete pour garantir le contraste quel que soit le fond (degrade mer/terre variable
   selon la position), sans jamais adopter un style "carte technique". */
.island-label-chip { fill: rgba(250, 246, 239, 0.97); stroke: rgba(15, 95, 92, 0.12); stroke-width: 1px; filter: drop-shadow(0 1px 3px rgba(90, 111, 168, 0.16)); } /* LOT 2 (2026-07-10, Direction B) : fond aligne sur --color-bg-primary (Creme de marque), opacite montee a 0.97 pour la lisibilite (priorite absolue demandee) ; le halo derriere le nom prend une pointe de Hortensia (#5a6fa8) a la place du gris neutre -- toujours tres discret (0.16), aucune forme/rotation ajoutee. */
.island-label { font-family: 'Poppins', sans-serif; letter-spacing: 0.01em; } /* ========================================================================== LABELS DE SPOTS AU ZOOM (2026-07-12) -- meme langage visuel que .island-label-chip juste au-dessus (creme de marque + halo Hortensia tres discret), a une echelle plus petite et plus subtile puisqu'il peut y en avoir plusieurs a l'ecran en meme temps (contrairement aux iles, toujours peu nombreuses). pointer-events:none partout ici : cette couche est purement decorative, jamais cliquable, ne doit jamais intercepter un clic/tap destine au pin (voir carte.js, la couche est deja aria-hidden et positionnee independamment des pins). La visibilite par palier de zoom est purement en CSS, pilotee par l'attribut data-zoom-tier pose sur .azores-svg (voir DHTMapZoom.updateNiveauZoomLabels, carte.js) : zoom normal = le Plan du Jour (.spot-label--plan, badge Miguel uniquement) + niveau 1 (incontournables, quelques lieux emblematiques par ile -- v5, direction artistique concierge) ; zoom fort = + niveau 2 (reste miradouros/plages/nature). ========================================================================== */
/* Correctif design (2026-07-12) : refonte visuelle demandee par le client -- fond blanc translucide (#FFFFFFF2), coins arrondis 10px (deja poses en attribut SVG rx=10, voir carte.js), bordure tres discrete, ombre legere, connecteur discret quand l'anti-collision deplace un label (voir .spot-label__connecteur), animation d'apparition en fondu + leger glissement (jamais un effet gadget). pointer-events:none conserve integralement sur toute la couche : aucun risque de capter un clic destine a un pin, quel que soit le style. */
.spot-label { pointer-events: none; opacity: 0; transform: translateY(4px); transition: opacity 260ms ease, transform 260ms ease; }
/* v4 (direction artistique, 2026-07-12) : ombre plus douce et plus diffuse (moins "sticker plat
   pose sur la carte", plus "petite carte qui flotte au-dessus du relief"). */
.spot-label__chip { fill: rgba(250, 247, 240, 0.90); stroke: rgba(15, 95, 92, 0.16); stroke-width: 1px; filter: drop-shadow(0 3px 8px rgba(24, 49, 47, 0.13)); } /* POLISSAGE UI (2026-07-14, demande client "moins badge application, plus pose sur la carte") : fond ivoire translucide (etait #fffffff2, blanc quasi pur) + ombre plus diffuse et plus legere (etait 5px/10px/0.18) ; contour legerement renforce (0.12->0.16) pour compenser la translucidite et garder une lisibilite parfaite aussi bien sur relief clair que sur relief sombre (caldeiras). */
.spot-label__text { font-family: 'Poppins', sans-serif; font-weight: 600; letter-spacing: 0.01em; fill: #18312f; }
.spot-label__icon { opacity: 0.82; } /* MISSION FINITION UI (2026-07-14, demande client "icones POI mieux integrees, ne doivent jamais dominer le texte") : l'icone (tspan distinct, voir finaliserLabelsSpots, carte.js) est deja rendue a taille reduite (-13%, voir it.fontSize*0.87 cote JS) ; cette regle abaisse en plus tres legerement son opacite (0.82) pour qu'elle se fonde un peu plus dans le label sans jamais nuire a la reconnaissance immediate du pictogramme. Le nom du lieu juste apres (tspan sans classe, herite de .spot-label__text) reste a opacite 1 et a la taille exacte d'avant, inchange. */
svg.spot-label__icon { overflow: visible; pointer-events: none; shape-rendering: geometricPrecision; } /* Micro Miguel (2026-07-14, raccordement bulles carte) : la meme classe .spot-label__icon est reutilisee pour le <svg> Micro Miguel imbrique (voir finaliserLabelsSpots, carte.js) -- elle herite donc deja l'opacite 0.82 ci-dessus, identique au glyphe emoji qu'elle remplace. Cette regle additionnelle ne fait qu'assurer un rendu net a petite taille et desactive les interactions, sans jamais toucher a la regle existante (fallback emoji, categories sans variante Micro). */
/* v4 (direction artistique, 2026-07-12) : onglet colore reserve aux lieux prioritaires (voir
   finaliserLabelsSpots, carte.js) -- orange signature DHT pour le Plan du Jour, teal pour le
   niveau 1. Repere de hierarchie immediat, sans texte ni icone supplementaire. */
.spot-label__accent { fill: #0f5f5c; opacity: 0.55; }
.spot-label__accent--plan { fill: #f2a65a; opacity: 0.78; } /* MISSION FINITION UI (2026-07-14, demande client "reduire fortement l'effet orange" du badge Miguel) : etait opacite 0.9 -- cette fine liseree de bord reste le repere de hierarchie "lieu recommande par Miguel" (voir commentaire v4 juste au-dessus), simplement un peu moins vive, en coherence avec le kicker assoupli ci-dessous. */
/* v2 (hierarchie visuelle, 2026-07-12) : demande client -- "le badge Miguel reste l'element dominant,
   les labels secondaires (niveau 2 : miradouros/plages/nature) doivent se faire plus discrets" --
   police deja plus petite (voir dhtPrepareLabelSpot, carte.js), on baisse ici en plus le contraste
   du texte, l'opacite du fond ET l'intensite de l'ombre (les 3 leviers demandes), jamais au point de
   nuire a la lisibilite. Le niveau 1 et le Plan du Jour (badge Miguel) ne sont jamais touches ici. */
.spot-label--tier2 .spot-label__text { font-weight: 500; fill: #4c5957; }
.spot-label--tier2 .spot-label__chip { fill: rgba(255, 255, 255, 0.78); stroke: rgba(15, 95, 92, 0.08); filter: drop-shadow(0 1px 2px rgba(24, 49, 47, 0.08)); }
/* v4 (direction artistique, 2026-07-12) : trait continu (plus de pointille "mesure technique")
   + point de rattachement plein sur le pin (voir .spot-label__point) -- lit desormais comme une
   fine attache de carte illustree, pas comme une cote/annotation GPS. */
.spot-label__connecteur { stroke: rgba(15, 95, 92, 0.42); stroke-width: 1.1; stroke-dasharray: none; }
.spot-label__point { fill: rgba(15, 95, 92, 0.55); pointer-events: none; }
.spot-label.spot-label--plan { opacity: 1; transform: translateY(0); pointer-events: auto; cursor: pointer; } /* Plan du Jour : toujours visible, jamais soumis aux paliers de zoom ci-dessous (double classe = priorite garantie sur .spot-label de base, quel que soit l'ordre des regles). MISSION FINITION UI (2026-07-14, demande client "toute la bulle de suggestion Miguel doit etre cliquable") : pointer-events remis a "auto" ICI UNIQUEMENT (la regle generale ".spot-label" plus haut reste "none" pour tous les autres labels, jamais cliquables) -- toute la surface visuelle (texte "Suggestion Miguel", nom du lieu, icone, fond du chip) devient une seule zone cliquable/tapable, deleguee vers exactement la meme action que le clic sur le pin (voir DHTInteractions.init(), listener sur labelsLayer, carte.js). */
.spot-label--plan:hover .spot-label__chip, .spot-label--plan:focus-visible .spot-label__chip { stroke: rgba(242, 166, 90, 0.62); filter: drop-shadow(0 5px 12px rgba(184, 108, 45, 0.20)); } /* MISSION FINITION UI (2026-07-14) : leger retour visuel au survol souris/au focus clavier de la nouvelle zone cliquable -- rien d'ajoute au repos, coherent avec "conserver le caractere premium, discret". */
/* v5 (direction artistique concierge, 2026-07-12) -- demande client : "vue normale = montrer l'ile
   comme une illustration touristique, garder Miguel + QUELQUES LIEUX EMBLEMATIQUES". Les labels de
   niveau 1 (incontournables, liste fermee -- voir DHT_LABELS_TIER1_TITRES_EXACTS, 1 a 6 par ile)
   sont desormais visibles DES le zoom normal, comme des lieux nommes sur une carte de guide, et non
   plus reserves au zoom intermediaire -- c'est un nombre volontairement restreint (jamais toute la
   liste de spots), coherent avec "quelques" plutot que "tous". Le niveau 2 (reste des
   miradouros/plages/nature) continue de n'apparaitre qu'au zoom fort, pour que le zoom normal
   reste epure. */
.spot-label--tier1 { opacity: 1; transform: translateY(0); pointer-events: auto; cursor: pointer; } /* MISSION FINITION UI (2026-07-14, demande client "rendre les bulles de spots cliquables") : le data-spot-id, la delegation de clic sur labelsLayer et le handler (onPinClick/onPinKeydown -> DHTUI.openDetail) existaient deja pour TOUS les labels (voir finaliserLabelsSpots, carte.js) -- seul pointer-events:none, herite de la regle generale .spot-label, empechait le clic d'atteindre ce tier. Applique uniquement quand le label est reellement visible (opacity:1 ci-dessus), jamais sur un label masque par le zoom. */
.azores-svg[data-zoom-tier="fort"] .spot-label--tier2 { opacity: 1; transform: translateY(0); pointer-events: auto; cursor: pointer; } /* meme raccordement que .spot-label--tier1 ci-dessus, applique uniquement au palier de zoom "fort" ou ce tier devient visible -- jamais cliquable tant qu'il est masque (opacity:0, regle .spot-label generale). */
.spot-label--tier1:hover .spot-label__chip, .spot-label--tier1:focus-visible .spot-label__chip, .spot-label--tier2:hover .spot-label__chip, .spot-label--tier2:focus-visible .spot-label__chip { stroke: rgba(15, 95, 92, 0.30); filter: drop-shadow(0 4px 10px rgba(24, 49, 47, 0.16)); } /* MISSION FINITION UI (2026-07-14, "retour visuel leger au survol") : meme principe que .spot-label--plan:hover ci-dessus, applique aux labels tier1/tier2 desormais cliquables -- variation discrete du contour/ombre du chip UNIQUEMENT au survol/focus, aucun changement au repos, aucune animation, aucune modification de taille/position. */
@media (prefers-reduced-motion: reduce) { .spot-label { transition: none; transform: none; } }
/* v5 (direction artistique concierge, 2026-07-12) -- demande client : "Miguel doit devenir le point
   focal... carte flottante, nom du lieu recommande". La carte du badge principal se distingue
   desormais des autres labels (fond creme chaleureux plutot que blanc neutre, liseret orange signature
   au lieu d'un simple trait gris, ombre plus prononcee) -- seule sa propre classe est touchee, aucun
   autre label n'est affecte. */
.spot-label--plan .spot-label__chip { fill: rgba(253, 248, 238, 0.93); stroke: rgba(242, 166, 90, 0.40); stroke-width: 1.3px; filter: drop-shadow(0 4px 10px rgba(184, 108, 45, 0.17)); } /* POLISSAGE UI (2026-07-14) : meme direction que .spot-label__chip ci-dessus, etait #fffaf2 opaque + ombre 7px/14px/0.22. */
.spot-label__kicker { font-family: 'Poppins', sans-serif; font-weight: 600; letter-spacing: 0.02em; fill: rgba(168, 118, 74, 0.82); } /* MISSION FINITION UI (2026-07-14, demande client "moins badge marketing, plus recommandation editoriale discrete") : etait font-weight 700 + text-transform:uppercase + fill plein #b8682d (rendu "SUGGESTION MIGUEL(TM)", effet pastille commerciale). Le texte source ("Suggestion Miguel(TM)", voir KICKER, carte.js) n'est pas modifie -- seule la CASSE VISUELLE change : text-transform:uppercase retire (on lit desormais "Suggestion Miguel(TM)", plus proche d'une legende de guide que d'un badge). Contraste et effet orange reduits (fill desature + alpha 0.82, poids de police allege 700->600, espacement des lettres resserre 0.04em->0.02em) tout en gardant une teinte chaude coherente avec l'identite Miguel. La hierarchie reste claire : ce kicker reste visuellement plus discret que le nom du lieu juste en-dessous (.spot-label--plan .spot-label__text, toujours font-weight:700). */
.spot-label--plan .spot-label__text { font-weight: 700; }

/* ==========================================================================
   REVEAL PROGRESSIF DES LABELS (v3, 2026-07-12 -- mis a jour v5, direction artistique concierge)
   idee client conservee, affinee au fil des retours. Etat actuel (v5) : le niveau 1 (incontournables,
   liste fermee -- voir DHT_LABELS_TIER1_TITRES_EXACTS) est desormais visible DES le zoom normal
   (icone + nom ensemble), pour incarner "Miguel + quelques lieux emblematiques" sur l'ile ; seul le
   niveau 2 (reste des miradouros/plages/nature, la couche la plus dense) continue de n'apparaitre
   qu'a partir du zoom fort, pour que le zoom normal reste epure ("une illustration touristique",
   pas une liste exhaustive). Le badge principal du Plan du Jour (Miguel) reste hors de cette regle :
   toujours visible, avec sa propre carte flottante dediee (voir .spot-label--plan) -- ses
   alternatives (2 a 5) suivent en revanche desormais la MEME regle de visibilite par zoom que
   n'importe quel autre spot (voir renderPins, carte.js), plus de traitement "toujours visible" qui
   les faisait ressembler a une liste GPS numerotee.
   ========================================================================== */


/* LOT 2 (2026-07-10) -- Carte archipel : entree en douceur des iles au premier affichage
   (voir renderIslands() dans carte.js pour le stagger par ile). Discret, jamais un effet de
   "reveal" tape-a-l'oeil -- juste assez pour que la carte se sente vivante des l'arrivee. */
@keyframes dht-island-enter { from { opacity: 0; transform: scale(0.95); } to { opacity: 1; transform: scale(1); } }
.island-dot-enter { transform-box: fill-box; transform-origin: center; animation: dht-island-enter 0.38s cubic-bezier(0.2, 0.8, 0.2, 1) both; } /* LOT 2 (2026-07-10, Direction B) : amplitude et duree reduites (0.92->0.95 ; 0.45s->0.38s) pour que l'archipel donne l'impression d'etre deja la et de se reveler tres brievement, plutot que de "se lancer" -- toujours desactive sous prefers-reduced-motion (regle existante conservee, voir plus bas). */

/* LOT 2 (2026-07-10) -- Carte archipel : les controles (choix d'ile, "Me localiser") sont des
   outils utilises occasionnellement, jamais le contenu principal de l'ecran. Poids visuel
   volontairement allege (ombre plus discrete, fond legerement plus transparent au repos) pour
   que l'oeil aille d'abord vers la carte elle-meme -- retrouve son poids plein au survol/focus
   pour rester parfaitement utilisable. */
.map-controls { position: absolute; top: var(--space-3); right: var(--space-3); left: var(--space-3); z-index: 10; display: flex; gap: var(--space-2); }
.control-select, .control-button { min-height: 48px; border: 1px solid var(--color-border); border-radius: var(--radius-pill); background: rgba(255, 255, 255, 0.88); color: var(--color-text); font-weight: 700; box-shadow: 0 1px 4px rgba(24, 49, 47, 0.1); transition: background-color 160ms ease, box-shadow 160ms ease; }
.control-select:hover, .control-button:hover, .control-select:focus-visible, .control-button:focus-visible { background: rgba(255, 255, 255, 0.98); box-shadow: var(--shadow-sm); }
.control-select { min-width: 0; flex: 1; padding-inline: var(--space-4); } .control-button { flex: 0 0 auto; padding-inline: var(--space-4); }
/* P6 (Phase 3A, correctif trouvé par analyse statique) : .intent-chips (ancien conteneur des chips d'intention) retiré ici -- zéro référence restante dans carte.html/carte.js depuis la migration vers "Mes envies aujourd'hui" (2.3) et le nettoyage du code JS (2.4) ; le CSS avait été oublié lors de ce nettoyage. */
.chip { flex: 0 0 auto; min-height: 44px; padding-inline: var(--space-4); border: 1px solid var(--color-border); border-radius: var(--radius-pill); background: rgba(255, 255, 255, 0.96); color: var(--color-text); font-weight: 700; box-shadow: var(--shadow-sm); } /* correctif P1 (audit) : 40px -> 44px, zone tactile */
.chip.is-active, .chip[aria-pressed="true"] { border-color: var(--color-primary); background: var(--color-primary); color: #ffffff; }
/* correctif P1 (audit Phase 1) : le bouton pluie est une fonctionnalité majeure, il doit se
   distinguer visuellement des autres intentions plutôt que de se fondre dans la liste. */
.chip-rain { border-color: #1b6fa8; background: #e8f2ff; color: #1b4a7a; }
.chip-rain.is-active, .chip-rain[aria-pressed="true"] { border-color: #1b6fa8; background: #1b6fa8; color: #ffffff; }
.map-viewport { display: flex; width: 100%; height: 100%; align-items: center; justify-content: center; padding: 112px var(--space-4) max(var(--space-4), calc(var(--sheet-height) + var(--space-3) + var(--space-4) - var(--panel-drag-offset, 0px))); transition: padding-bottom 220ms cubic-bezier(0.2, 0, 0, 1); } /* SUPPRESSION .rain-mode-note (2026-07-10) : le message meteo etant desormais fusionne dans le panneau (voir carte.js, getMessageMeteoContextuel), le bandeau independant au-dessus de .map-status disparait -- la reservation de hauteur qui lui etait dediee (+34px) est retiree ici, ce qui rend a l archipel l espace vertical qu elle occupait, sans laisser de vide (formule alignee sur la seule hauteur de .map-status desormais).*/
/* LOT Drag synchronise carte/panneau (2026-07-10) : --panel-drag-offset est ecrite en direct par le meme pointermove que le panneau (carte.js) -- la carte recupere donc l espace progressivement, au meme rythme que le doigt, au lieu de ne bouger qu au relachement. max() protege contre un padding negatif si le calcul depasse la reserve. La re-centration du contenu SVG est automatique (flex + align-items:center deja en place, aucun code supplementaire). Transition desactivee pendant le drag actif (regle .is-panel-dragging ci-dessous) pour un suivi 1:1 reel, reactivee seulement au relachement pour un settle anime -- meme principe que .assistant-panel.is-dragging. */
.map-app.is-panel-dragging .map-viewport { transition: none; }
/* Zoom/pan carte (2026-07-08) : touch-action limité à ce seul conteneur — empêche le navigateur
   de capter le pinch/scroll pour zoomer/défiler la page au-dessus de la carte ; le geste est
   entièrement géré par DHTMapZoom (voir carte.js). Aucun impact ailleurs sur le site. */
.map-viewport { touch-action: none; cursor: grab; }
/* Correctif 2026-07-08 (bis) : Safari iOS n'applique pas toujours de façon fiable le touch-action
   hérité du parent lors d'un pinch démarré directement sur l'élément <svg>. On le fixe donc aussi
   explicitement sur le SVG lui-même, en plus du conteneur, par robustesse cross-navigateur. */
.azores-svg { touch-action: none; }
.map-viewport.is-dragging { cursor: grabbing; }
.azores-svg { display: block; width: min(100%, 760px); max-height: 100%; }
.map-status { position: absolute; right: var(--space-3); bottom: calc(var(--sheet-height) + var(--space-3)); left: var(--space-3); z-index: 9; margin: 0; padding: var(--space-2) var(--space-3); border-radius: var(--radius-pill); background: rgba(255, 255, 255, 0.92); color: var(--color-text-muted); font-size: var(--map-text-xs); font-weight: 700; text-align: center; box-shadow: var(--shadow-sm); }
.assistant-panel { position: fixed; right: 0; bottom: 0; left: 0; z-index: 30; height: var(--sheet-height); overflow: hidden; display: flex; flex-direction: column; border-radius: 28px 28px 0 0; background: var(--color-surface); box-shadow: 0 -16px 48px rgba(24, 49, 47, 0.18); transition: height 220ms cubic-bezier(0.2, 0, 0, 1), transform 220ms cubic-bezier(0.2, 0, 0, 1); box-sizing: border-box; } /* correctif structurel chevauchement .spot-detail / .sheet-header (2026-07-10, v2) : l'ancienne variable --sheet-header-height (88px figes) supposait une hauteur fixe du bandeau meteo ; or .sheet-header grandit en desktop (padding-top ajoute plus bas, cf. media 1024px) sans que cette variable soit mise a jour -- .spot-detail (ancre sur cette valeur perimee) recouvrait alors le bas reel de .sheet-header (bouton "Actualiser" partiellement cache), aussi bien sur mobile que desktop, dans la vue detail. Remplace par un ancrage structurel qui ne peut plus se desynchroniser : .spot-detail devient un enfant de .sheet-content (voir carte.html) au lieu d'un frere -- il suit alors automatiquement .sheet-header dans le flux flex, quelle que soit sa hauteur reelle, sans plus aucun nombre magique a synchroniser. */
/* correctif bottom sheet (audit mobile Safari) : architecture .sheet-handle / .sheet-header (fixe) /
   .sheet-content (scroll) — remplace l'ancien overflow:hidden sur tout le panneau qui coupait
   silencieusement le texte "Comment ce score est calculé ?" et tout contenu long futur.
   .assistant-panel garde overflow:hidden UNIQUEMENT pour l'arrondi visuel des coins : plus rien
   à l'intérieur ne peut grandir au-delà de sa boîte, puisque .sheet-content absorbe tout
   excédent par défilement interne plutôt que par débordement. */
.sheet-header { flex: 0 0 auto; padding-inline: var(--dht-panel-pad-x); }
/* correctif éditorial (audit identité DHT Azores) : accroche météo compacte, une seule ligne,
   volontairement plus petite qu'un .eyebrow classique pour ne pas alourdir le header fixe de
   la feuille mobile (budget vertical limité à 42dvh replié — cf. audit bottom sheet). */
.weather-eyebrow { margin: var(--space-2) 0 0; font-size: var(--map-text-2xs); font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--color-primary-strong); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }
.sheet-content { position: relative; flex: 1 1 auto; min-height: 0; overflow-y: auto; overflow-x: hidden !important; -webkit-overflow-scrolling: touch; padding-inline: var(--dht-panel-pad-x); padding-top: var(--dht-panel-pad-top); padding-bottom: calc(var(--dht-panel-pad-bottom) + env(safe-area-inset-bottom, 0px)); } /* correctif structurel (2026-07-10, v2) : position:relative fait de .sheet-content le repere de positionnement de .spot-detail (desormais son enfant, voir carte.html) -- .spot-detail se cale ainsi toujours exactement sous .sheet-header, quelle que soit la hauteur reelle de ce dernier a n'importe quel breakpoint, sans plus jamais dependre d'une valeur figee. Fallbacks px/rem ajoutes sur les jetons d'espacement : garantit une respiration interne visible meme si le design system (style.css) ne les definit pas encore a ce point du chargement. */ /* Correctif accessibilité (post-2.2b) : l'ordre visuel doit toujours correspondre à l'ordre DOM/clavier/lecteur d'écran. On utilise donc une grille en flux automatique -- aucun grid-template-areas qui imposerait un ordre visuel différent de celui du DOM -- et c'est DHTUI.reordonnerPanneauSelonAppareil() (JS) qui déplace réellement les sections selon l'appareil, jamais une illusion CSS seule. */ .sheet-content { display: grid; grid-template-columns: 1fr; row-gap: 0; } /* correctif P2 (audit) repris ici : la marge de sécurité iOS se calcule désormais sur le conteneur qui défile réellement, pour ne jamais masquer la fin du contenu par la zone de geste système (Android) ou le bord arrondi (iPhone) */
.assistant-panel.is-expanded { height: var(--sheet-height-expanded); } .assistant-panel__handle { width: 44px; height: 5px; padding: 13px 40px; margin: 2px auto 3px; border-radius: var(--radius-pill); background: var(--color-border); background-clip: content-box; box-sizing: content-box; touch-action: none; cursor: grab; } /* correctif P1 (audit) : zone tactile réelle agrandie (~124x31px, contre 44x5px avant) sans changer l'apparence visuelle de la barre elle-même (toujours 44x5px visible grâce à background-clip), + touch-action: none pour un geste de glissement fluide non perturbé par le scroll du navigateur */ .assistant-panel.is-dragging { transition: none; }
.spot-detail { padding-inline: var(--dht-panel-pad-x); padding-top: var(--dht-panel-pad-top); } .plan-card h1 { margin-bottom: var(--space-3, 1.5rem); font-size: 1.75rem; } /* correctif bottom sheet : plan-card/alternatives sont maintenant enfants de .sheet-content, qui porte déjà le padding horizontal — plus besoin de le répéter ici (évitait un double retrait visuel) */
/* LOT 3 (2026-07-10) -- UI Polish : legere ombre en plus du degrade/bordure existants, pour que
   la carte de recommandation principale se detache clairement de la page (elle est LE contenu
   prioritaire de tout l'ecran replie) -- reprend --shadow-sm deja utilise ailleurs, pas de
   nouveau token. */
.main-recommendation { min-width: 0; padding: var(--space-4, 2rem); border: 1px solid var(--color-primary-soft); border-radius: var(--radius-xl); background: linear-gradient(180deg, #ffffff, var(--color-primary-soft)); box-shadow: var(--shadow-sm); }
.main-recommendation h2 { margin-bottom: var(--space-2, 1rem); font-size: 1.25rem; } .main-recommendation p { margin-bottom: var(--space-4, 2rem); color: var(--color-text-muted); }
.alternatives { margin-top: var(--space-4); padding-bottom: var(--space-5); } /* correctif bottom sheet : le scroll de ce bloc est désormais géré par le parent .sheet-content, plus besoin d'un max-height approximatif propre à ce seul bloc */
/* LOT 3 (2026-07-10) -- UI Polish : le titre "L'autre proposition" ne doit jamais rivaliser
   visuellement avec "Aujourd'hui avec Miguel™" (h1 du plan principal) -- discretion plutot
   que suppression, l'info reste entierement lisible. */
.alternatives h2 { margin-bottom: var(--space-2); font-size: var(--map-text-md); font-weight: 700; color: var(--color-text-muted); }
.alternatives__list { display: grid; gap: var(--space-2); }
/* LOT 3 (2026-07-10) -- UI Polish : avant ce correctif, .alternative-card (secondaire) avait un
   fond blanc plein et une bordure aussi marquee que .main-recommendation (le plan retenu par
   Miguel), ce qui brouillait la hierarchie -- l'oeil hesitait entre les deux avec un poids quasi
   identique. Fond plus discret + bordure plus fine : reste parfaitement cliquable/lisible, mais
   se lit clairement comme une alternative, pas comme un second plan principal. */
.alternative-card { width: 100%; padding: var(--space-3, 1.5rem); border: 1px solid var(--color-border); border-radius: var(--radius-lg); background: var(--color-surface-muted); color: var(--color-text); text-align: left; }
.alternative-card h3 { margin-bottom: var(--space-1); font-size: var(--map-text-md); font-weight: 600; } .alternative-card p { margin-bottom: 0; color: var(--color-text-muted); font-size: var(--map-text-base); }
/* P6 (2.2a) : moteur de journée Miguel™ — styles de base pour une lecture correcte immédiatement.
   La richesse responsive complète (mobile/tablette/desktop différenciés) est prévue en 2.2b :
   ceci garantit uniquement que rien ne s'affiche "brut" en attendant. */
.journee-etapes { min-width: 0; list-style: none; padding: 0; margin: 0; display: flex; flex-direction: column; gap: var(--space-2); }
.journee-etape__bouton { width: 100%; min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2); padding: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-lg); background: var(--color-surface); color: var(--color-text); text-align: left; }
.journee-etape__heure { flex: 0 0 auto; font-weight: 600; color: var(--color-primary); font-size: var(--map-text-base); }
.journee-etape__bouton strong { flex: 1 1 auto; min-width: 0; overflow-wrap: anywhere; word-break: normal; }
.journee-etape__motif { display: block; width: 100%; min-width: 0; flex: 1 1 100%; margin-top: var(--space-1); color: var(--color-text-muted); font-size: var(--map-text-base); overflow-wrap: anywhere; word-break: normal; }
/* Bloc "Activites a horaires fixes" V1.5 (2026-07-18, decision produit validee) : traitement
   visuel distinct pour une sortie a horaire reel (pas une simple etape suggeree) -- reutilise
   --color-accent, deja utilise pour les badges/CTA de mise en avant (spot-tooltip__badge--main),
   jamais une nouvelle couleur inventee pour ce lot. */
.journee-etape--planifiee .journee-etape__bouton { border-left: 3px solid var(--color-accent); }
.journee-etape__planifiee { display: block; width: 100%; min-width: 0; flex: 1 1 100%; margin-top: var(--space-2); padding-top: var(--space-2); border-top: 1px solid var(--color-border); }
.journee-etape__planifiee-heure { display: flex; align-items: center; gap: var(--space-1); min-width: 0; overflow-wrap: anywhere; word-break: break-word; margin: 0; font-weight: 600; color: var(--color-accent); font-size: var(--map-text-base); }
.journee-etape__planifiee-info { display: flex; align-items: center; gap: var(--space-1); min-width: 0; overflow-wrap: anywhere; word-break: break-word; margin: var(--space-1) 0 0; color: var(--color-text-muted); font-size: var(--map-text-2xs); }
.journee-etape__planifiee svg { flex-shrink: 0; width: 14px; height: 14px; }
/* Variante "sans_horaire" (2026-07-18, V1.7) : aucun token de couleur d'avertissement/orange
   n'existe dans cette feuille de style (verifie -- seuls accent/text/text-muted/border/surface sont
   utilises) ; plutot que d'inventer une couleur non alignee avec la palette, la distinction se fait
   par un style plus discret (bordure en pointilles, titre non accentue) pour signaler visuellement
   "moins certain" sans fausse alerte. */
.journee-etape--planifiee-sans-horaire .journee-etape__bouton { border-left: 3px dashed var(--color-text-muted); }
.journee-etape__planifiee--sans-horaire { border-top-style: dashed; }
.journee-etape__planifiee--sans-horaire .journee-etape__planifiee-heure { color: var(--color-text); font-weight: 500; }
.around-me { margin-top: var(--space-4); }
/* LOT 3 (2026-07-10) -- UI Polish : "Autour de moi" est la seule action independante et
   immediatement disponible de l'ecran replie (les autres sont soit passives -- lecture de la
   journee -- soit derriere un accordeon). Leger surplus de relief pour qu'elle se lise sans
   ambiguite comme LE bouton d'action principal visible d'emblee, sans toucher au style
   .button-primary global (defini hors de ce paquet de livraison). */
.around-me-button { width: 100%; box-shadow: var(--shadow-sm); }
.around-me-button:hover, .around-me-button:focus-visible { box-shadow: 0 6px 16px rgba(24, 49, 47, 0.16); }
.around-me-result { margin-top: var(--space-3); }
.around-me-suggestion { width: 100%; padding: var(--space-3); border: 1px solid var(--color-primary-soft); border-radius: var(--radius-lg); background: var(--color-primary-soft); color: var(--color-text); text-align: left; }
.around-me-suggestion span { display: block; margin-top: var(--space-1); color: var(--color-text-muted); font-size: var(--map-text-base); }
/* Harmonisation "Autour de moi" (2026-07-10) : selecteur de categories affiche une fois la
   position acquise ("Que cherchez-vous autour de vous ?"), meme style de carte que les
   suggestions ci-dessus -- pas de nouveau langage graphique, uniquement une disposition en
   grille de puces pour un choix rapide au pouce comme a la souris. */
.around-me-categories { margin-top: var(--space-3); }
.around-me-categories__question { margin-bottom: var(--space-2); font-weight: 700; color: var(--color-text); }
.around-me-categories__list { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.around-me-category-chip { display: inline-flex; align-items: center; gap: 6px; min-height: 44px; padding-inline: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-pill); background: var(--color-surface); color: var(--color-text); font-weight: 600; }
.around-me-category-chip:hover, .around-me-category-chip:focus-visible { border-color: var(--color-primary); background: var(--color-primary-soft); }
.around-me-category-chip /* Correctif (2026-07-20) : regle .cat-icon dupliquee retiree ici, la definition faisant foi (1.15em, coherente avec .icon-lucide) reste plus bas dans ce fichier -- aucun changement visuel, cette regle etait deja ecrasee par la seconde. */
.around-me-result__title { margin-bottom: var(--space-2); font-weight: 700; color: var(--color-text); }
.around-me-result .around-me-suggestion { margin-bottom: var(--space-2); }
.around-me-back { min-height: 40px; padding-inline: var(--space-3); border: 0; border-radius: var(--radius-pill); background: var(--color-surface-muted); color: var(--color-text-muted); font-weight: 700; }
/* Marqueur de position reelle sur la carte (data-user-layer) : jusqu'ici reserve dans le SVG
   mais jamais rempli -- ajoute ici avec le meme langage graphique que les pins (cercle +
   lisere blanc), teinte distincte pour ne jamais se confondre avec le Plan du Jour, et un
   halo anime pour rester reperable meme sur une carte chargee. */
.user-marker circle.user-marker__halo { fill: rgba(27, 111, 168, 0.22); animation: dht-user-pulse 2.4s ease-out infinite; }
.user-marker circle.user-marker__dot { fill: #1b6fa8; stroke: #fff; stroke-width: 3; filter: drop-shadow(0 3px 6px rgba(24, 49, 47, 0.25)); }
@keyframes dht-user-pulse { 0% { transform: scale(0.6); opacity: 0.9; } 100% { transform: scale(1.9); opacity: 0; } }
.user-marker { transform-box: fill-box; transform-origin: center; }
/* Mise en evidence des spots correspondant a la categorie choisie dans "Autour de moi" :
   meme pin que les autres spots secondaires (allspots-layer) mais accentue, pour rester
   coherent avec le langage cartographique existant plutot que d'inventer une nouvelle couche. */
.pin-around-highlight circle { fill: #1b6fa8 !important; opacity: 1 !important; stroke-width: 2.5; }
@media (prefers-reduced-motion: reduce) { .user-marker circle.user-marker__halo { animation: none; opacity: 0.35; } }
/* P6 (2.3) : "Mes envies aujourd'hui" -- fermé par défaut, reprend le style des chips déjà
   existant (profil, filtres) pour rester cohérent visuellement, sans nouveau langage graphique. */
/* LOT 3 (2026-07-10) -- UI Polish : respiration renforcee avant le groupe "utilitaire"
   (envies / explorer librement), pour separer visuellement la proposition de Miguel
   (contenu principal, lu en premier) du reste des outils secondaires -- sans rien cacher,
   uniquement plus d'espace, ce qui reduit la densite percue de l'ecran replie. */
.envies-section { margin-top: var(--space-6); }
.envies-toggle { width: 100%; padding: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-lg); background: var(--color-surface); color: var(--color-text); font-weight: 600; text-align: left; }
.envies-panel { margin-top: var(--space-3); }
.envies-intro { margin-bottom: var(--space-2); color: var(--color-text-muted); font-size: var(--map-text-base); }
.envies-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.envie-chip.is-active { background: var(--color-primary); color: #fff; border-color: var(--color-primary); }
.spot-detail { position: absolute; inset: 0; overflow-y: auto; background: var(--color-surface); padding-bottom: var(--dht-panel-pad-bottom-lg); } .spot-detail[hidden] { display: none; } /* correctif structurel (2026-07-10, v2) : inset:0 se cale desormais sur .sheet-content (voir position:relative plus haut) puisque .spot-detail en est maintenant un enfant direct (carte.html) -- il occupe donc exactement l'espace disponible sous .sheet-header, sans plus jamais dependre d'une hauteur de bandeau devinee/figee. */
/* Correctif double scroll + programme visible derriere en desktop (2026-07-12) : voir openDetail()/
   closeDetail() dans carte.js pour le detail de la cause -- ouvrir une fiche ne masquait jusqu'ici
   QUE visuellement (clipping accidentel de overflow-y:auto sur .sheet-content) le programme de la
   journee, jamais reellement en DOM. En desktop, .sheet-content passe a overflow-y:visible plus bas
   dans ce fichier (pour un ascenseur unique sur la vue LISTE, via .assistant-panel) -- sans masquage
   explicite, cela laissait le programme redevenir visible sous la fiche ET creait un second
   ascenseur concurrent sur .assistant-panel. Cette regle masque explicitement (display:none) tout
   enfant de .sheet-content AUTRE que .spot-detail pendant l'ouverture (classe posee/retiree par
   openDetail()/closeDetail()) -- universelle (pas de media query) : sur mobile/tablette, aucun
   changement visuel (c'etait deja invisible par clipping), en desktop le programme disparait
   reellement et .spot-detail{overflow-y:auto} ci-dessus redevient le seul ascenseur du panneau,
   exactement comme sur mobile/tablette (meme comportement, jamais un troisieme). */
.sheet-content.is-detail-open > :not(.spot-detail) { display: none; }
/* correctif P1-2 (audit responsive PC) : #detail-title héritait de la règle globale h2 de
   style.css (clamp jusqu'à 3rem, max-width 14ch), pensée pour un titre de page marketing en
   pleine largeur. Dans le panneau détail (largeur fixe ~420px sur desktop, ou la feuille
   mobile), ce style produisait un titre disproportionné qui s'enroulait sur une colonne bien
   trop étroite pour l'espace réellement disponible — visible notamment sur grand écran. */
.spot-detail h2 { max-width: none; font-size: 1.5rem; line-height: 1.2; letter-spacing: -0.02em; }
/* correctif P1-2b (audit responsive Desktop) : meme defaut herite de la regle globale h2 de
   style.css (max-width: 14ch) que celui deja corrige ci-dessus pour #detail-title, mais present
   sur 6 autres titres applicatifs Miguel(TM) dont la propriete max-width n'avait jamais ete
   neutralisee (seule la font-size l'etait, via .section-subtitle ou des regles locales). Override
   scope strictement a ces 6 selecteurs (id ou attribut uniques dans le DOM) : aucune autre balise
   h2 du site n'est concernee, aucune modification de style.css necessaire (carte.css est charge
   apres style.css et ces selecteurs sont de toute facon plus specifiques qu'un simple h2). */
#pourquoi-journee-title, #choix-miguel-title, #explorer-libre-title, #alternatives-title,
.carnet-modal__header h2 { max-width: none; }
.plan-card h1 {
    max-width: none;
}

.main-recommendation h2 {
    max-width: none;
}
.detail-close { min-height: 44px; margin-bottom: var(--space-3, 1.5rem); border: 0; border-radius: var(--radius-pill); background: var(--color-surface-muted); color: var(--color-text); font-weight: 800; padding-inline: var(--space-4, 2rem); }
/* Retour arriere assume (2026-07-17, v2) : le correctif sticky introduit plus haut le meme jour (".spot-detail .detail-close { position: sticky; ... }") est retire ici. Il resolvait bien la perte de visibilite du bouton "Fermer" au scroll, mais laissait le bouton flotter AU-DESSUS du contenu de la fiche (chevauchement du titre/des badges pendant le defilement, vide vertical inconsistant avec "Actualiser") au lieu de vivre dans le meme bandeau qu'"Actualiser" -- probleme structurel, pas un reglage CSS. Solution retenue : .detail-close est deplace dans .sheet-header, a cote de .weather-refresh (voir carte.html, .weather-bar__actions, et carte.js, openDetail()/closeDetail()) -- il beneficie ainsi nativement de la meme fixite qu'"Actualiser" (hors du conteneur qui defile), sans plus aucune propriete sticky/top/z-index/box-shadow a maintenir sur ce selecteur. Voir plus bas la regle .weather-bar__actions pour le placement/l'espacement dans l'entete. */
.detail-meta { font-size: var(--map-text-md); color: var(--color-text-muted); } .detail-actions { display: grid; gap: var(--space-2, 1rem); margin-top: var(--space-4, 2rem); }
.sr-only { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
.pin, .island-dot { cursor: pointer; } .pin circle { filter: drop-shadow(0 4px 8px rgba(24, 49, 47, 0.22)); } .pin .pin-main__disque { filter: saturate(0.88) drop-shadow(0 3px 6px rgba(24, 49, 47, 0.16)); } /* POLISSAGE UI (2026-07-14, demande client "marker moins dominant") : override plus specifique que ".pin circle" ci-dessus -- ombre plus douce (etait 4px/8px/0.22) + orange legerement moins sature obtenu par filter:saturate() plutot que par une retouche du gradient (dht-badge-miguel-glossy, carte.html, volontairement non touche a cette etape). */
@media (min-width: 480px) { .map-controls { right: var(--space-5); left: var(--space-5); } .spot-detail, .sheet-header, .sheet-content { padding-inline: var(--dht-panel-pad-x-md); } }
/* Correctif P0-3 (audit Phase 2/5) : min() avec dvh au lieu de valeurs fixes, pour que la
   feuille ne dépasse jamais la hauteur réelle de l'écran en paysage sur smartphone (largeur
   logique >=768px mais hauteur réelle de 375-430px sur la quasi-totalité des téléphones
   actuels). Sur une vraie tablette (hauteur généreuse), min() choisit toujours 380px/620px
   comme avant : aucun changement visuel sur iPad. */
@media (min-width: 768px) { :root { --sheet-height: min(380px, 55dvh); --sheet-height-expanded: min(620px, 85dvh); } .assistant-panel { right: var(--space-5); bottom: var(--space-5); left: auto; width: 420px; border-radius: 28px; } .map-status { right: var(--space-5); bottom: calc(var(--space-5) + var(--sheet-height) + var(--space-3)); left: auto; width: 420px; } }
@media (min-width: 768px) and (max-width: 1365px) and (pointer: coarse) { .map-viewport { padding: 112px var(--space-4) var(--space-4); } } /* Correctif tablette cible (2026-07-12) : CAUSE EXACTE -- .map-viewport (regle de base, plus haut dans ce fichier) reserve un padding-bottom calcule sur --sheet-height (~380-620px) pour laisser la place a un tiroir MOBILE PLEIN ECRAN. Or depuis la regle @media(min-width:768px) juste au-dessus, .assistant-panel n'est plus un tiroir plein largeur : il devient une carte flottante ancree en bas-droite, large de seulement 420px (right/bottom/width:420px). .map-viewport continuait pourtant, sur toute la tablette (768-1365px), a reserver cette hauteur sur TOUTE la largeur de l'ecran comme si le panneau occupait tout le bas -- sur un iPad Pro 11" paysage (1194px), ~770px de large restaient vides a gauche du panneau flottant (large de 420px seulement) alors que la carte SVG, centree dans la boite reduite par ce padding inutile, se retrouvait confinee dans un cadre bien plus petit que necessaire, avec le zoom limite a ce cadre. Desktop (>=1024px et pointer:fine, ligne 206 plus bas) n'etait pas concerne : le panneau y devient une colonne de grille et .map-viewport y ecrase deja padding-bottom par var(--space-6). Mobile (<768px) n'est pas concerne non plus : le panneau y reste un veritable tiroir plein largeur, la reservation de hauteur y est legitime et inchangee. Correctif : meme traitement que le desktop (retrait de la reservation liee a --sheet-height) applique UNIQUEMENT ici, via pointer:coarse, pour ne jamais toucher un poste desktop a souris dont la fenetre serait redimensionnee dans cette plage de largeur -- la regle pointer:fine existante (ligne 206) reste strictement prioritaire et inchangee sur son propre perimetre. .assistant-panel reste une carte flottante inchangee (position:fixed, non affectee par le padding de .map-viewport) : elle continue de se superposer proprement au-dessus de la carte agrandie (z-index:30 deja en place), comportement d'overlay volontaire, pas un chevauchement. */
/* correctif P1-1 (audit responsive) : le seuil desktop se déclenchait sur simple largeur (min-width:1024px), ce qui bascule à tort l'iPad Pro 12,9" tenu en PORTRAIT (1024px de large) vers la mise en page desktop (barre latérale fixe), alors qu'il s'agit d'un usage tactile tablette. On ajoute (pointer: fine), vrai uniquement sur souris/trackpad, jamais sur tactile tablette/mobile — les iPad restent donc sur l'interface bottom sheet tactile quelle que soit leur orientation, et seuls les écrans pilotés à la souris passent en mise en page desktop. */
@media (min-width: 1024px) and (pointer: fine) { .map-app { display: grid; grid-template-columns: clamp(420px, 40vw, 460px) minmax(320px, 1fr); height: 100dvh; } .map-stage { grid-column: 2; } .assistant-panel { position: relative; grid-column: 1; grid-row: 1; width: auto; height: calc(100dvh - var(--map-header)); overflow-y: auto; border-radius: 0; box-shadow: none; } .assistant-panel__handle { display: none; } .sheet-header { padding-top: var(--dht-panel-pad-top-desktop); padding-inline: var(--dht-panel-pad-x-md); } .sheet-content { overflow-y: visible; padding-top: var(--dht-panel-pad-top); padding-inline: var(--dht-panel-pad-x-md); } .spot-detail { padding-top: var(--dht-panel-pad-top-desktop); padding-inline: var(--dht-panel-pad-x-md); padding-bottom: var(--dht-panel-pad-bottom-lg); } .spot-detail { overflow-y: auto; } /* Correctif v2 chevauchement fiche spot desktop (2026-07-12) : revient sur le correctif precedent (position:relative) qui cassait le comportement panneau voulu (.spot-detail doit rester position:absolute;inset:0 -- voir ligne 171 -- pour remplacer visuellement le programme de la journee, avec le haut du panneau qui reste fixe). La VRAIE cause du chevauchement interne n'etait pas la position absolue elle-meme, mais UNIQUEMENT la valeur overflow-y:visible ecrite ici (correctif 'scroll unique v6') : avec inset:0 (top:0 + bottom:0, height:auto), .spot-detail est necessairement force a la hauteur de son conteneur (.sheet-content), jamais a celle de son contenu reel (regle CSS standard pour un element absolument positionne dont top ET bottom sont tous les deux fixes) -- ce qui est sans consequence tant que le surplus de contenu reste SCROLLABLE A L'INTERIEUR de la boite (overflow-y:auto, comportement mobile deja valide, jamais modifie), mais devient visible dès que ce surplus peut s'echapper de la boite au lieu d'y rester confine (overflow-y:visible, ce qui etait le cas ici en desktop). En repassant a overflow-y:auto : le panneau garde sa position/son role inchanges (remplace la journee, haut fixe), et desormais score -> analyse -> pourquoi cette recommandation -> comparaison -> webcam -> actions s'enchainent verticalement SANS chevauchement, avec leur propre scroll interne si leur hauteur cumulee depasse celle du panneau (.spot-detail devient alors lui-meme le bon conteneur de scroll pour la vue detail, exactement comme il l'est deja sur mobile/tablette -- aucun 'double scroll' puisque la vue liste [.sheet-header/.sheet-content restants] est masquee derriere pendant que la fiche est ouverte, .assistant-panel.scrollTop etant deja remis a 0 par openDetail(), carte.js ligne ~3897). */ /* correctif scroll unique (2026-07-10, v6) : .spot-detail garde overflow-y:auto en mobile (tiroir a hauteur fixe, comportement voulu) mais cree, en desktop, un DEUXIEME conteneur de scroll imbrique dans .assistant-panel (qui scrolle deja tout le panneau) -- exactement le meme risque de "double scroll" deja identifie et corrige plus haut pour .sheet-content. On applique ici la meme regle : overflow-y:visible en desktop, pour que .assistant-panel reste le seul conteneur de scroll du panneau (vue liste ET vue detail), garantissant un defilement homogene jusqu'en bas dans les deux cas. */ /* correctif cible (2026-07-10, v5) : bouton "Actualiser" (.weather-refresh, dans .sheet-header) degage du header fixe "DHT Azores" en desktop grace a --dht-panel-pad-top-desktop (3rem/48px, jeton local garanti, cf. :root). Meme occasion : .sheet-header/.sheet-content/.spot-detail recoivent ici aussi --dht-panel-pad-x-md (2.5rem/40px) en padding-inline explicite, pour que la marge laterale du panneau ne depende plus jamais, meme en desktop, d une variable externe non garantie -- c est la cause racine du contenu "colle au bord" corrigee dans ce lot (v5). Aucune nouvelle classe, aucun effet mobile (regle deja limitee a la media query desktop @1024px+pointer:fine). */ /* correctif bottom sheet : sur desktop, le panneau redevient une colonne classique qui défile en un seul bloc — on désactive le scroll interne de .sheet-content pour éviter un double scroll imbriqué, comportement desktop inchangé */ .map-status { right: var(--space-5); bottom: var(--space-5); width: auto; } .map-viewport { padding-bottom: var(--space-6); } /* correctif panneau coupe desktop (2026-07-10) : .assistant-panel.is-expanded (ligne 93, specificite 2 classes) l emportait sur la regle .assistant-panel ci-dessus (1 classe) des que la classe restait posee, capant le panneau a --sheet-height-expanded (~620px) au lieu de la pleine hauteur desktop -- regle de securite ici, avec la meme specificite que .is-expanded, pour que le comportement desktop (colonne pleine hauteur, deja documente ci-dessus) reste prioritaire dans tous les cas, y compris apres ouverture/fermeture d un detail d etape. */ .assistant-panel.is-expanded { height: calc(100dvh - var(--map-header)); } }
/* P6 (Phase 3, correctif trouvé par analyse statique) : une largeur fixe de 640/700px imposée dès 1024px de large ne laissait plus que ~380px à la carte au seuil du palier (1024-640=384px), trop étroit pour un archipel avec libellés. On passe à une largeur proportionnelle (clamp), et le côte-à-côte des deux journées n'apparaît qu'à partir de 1280px, là où chaque moitié de colonne reste réellement lisible (environ 300px chacune) plutôt que de forcer ce rendu dès 1024px. */
@media (min-width: 1280px) and (pointer: fine) {
  .map-app { grid-template-columns: clamp(560px, 46vw, 700px) minmax(360px, 1fr); }
  .azores-svg { width: min(100%, 920px); }
  .sheet-content { grid-template-columns: 1fr 1fr; column-gap: var(--space-4); }
  .weather-disagreement, .webcam-link, .around-me, .pourquoi-journee, .choix-miguel, .envies-section, .explorer-libre, .spot-detail, [data-main-recommendation] { grid-column: 1 / -1; } /* P-Finalisation (point #5) : .category-explore/.bestofday n'existent plus -- remplacés par .pourquoi-journee/.choix-miguel/.explorer-libre */
  /* Correctif chevauchement desktop (2026-07-12) : .spot-detail (position:absolute; inset:0,
     voir plus haut) manquait dans cette liste. Depuis ce bloc (>=1280px), .sheet-content passe
     en grille a 2 colonnes (ligne precedente) -- sans grid-column explicite, le placement
     automatique d'un enfant absolument positionne pour cet axe redevenait ambigu et pouvait
     le confiner a une seule piste de la grille au lieu de la couvrir en entier, laissant les
     sections en flux normal (ex. "Les choix de Miguel") visibles/superposees sous la fiche
     detail ouverte. grid-column:1/-1 force explicitement .spot-detail a couvrir toute la
     largeur de la grille, exactement comme les autres sections plein-panneau ci-dessus --
     aucun changement en dessous de 1280px (tablette/mobile non concernes), aucun changement
     visuel quand aucun detail n'est ouvert. */
  .alternatives .alternative-card { height: 100%; }
}
/* P6 (2.2b, corrigé en 2.3) : priorité cognitive par appareil -- même moteur, même contenu, seul
   l'ordre et la densité d'affichage changent. Correctif accessibilité : ceci ne réordonne plus
   visuellement via grid-template-areas (l'ordre DOM/clavier ne suivait plus l'ordre visuel).
   L'ordre réel est désormais déplacé dans le DOM par DHTUI.reordonnerPanneauSelonAppareil() (JS) ;
   cette grille ne fait plus qu'une mise en page spatiale simple, qui respecte l'ordre du DOM tel
   qu'il a été placé. */
/* P6 (Phase 3, correctif trouvé par analyse statique) : le côte-à-côte des deux journées (grille à
   deux colonnes de .sheet-content) est désormais déclaré uniquement dans le bloc @media
   (min-width: 1280px) ci-dessous, avec la largeur de panneau correspondante -- entre 1024px et
   1279px, .sheet-content reste en une seule colonne (comme sur tablette), le temps que le panneau
   élargi (clamp 420-460px) laisse la place à une carte confortable sans forcer une colonne de
   journée trop étroite pour rester lisible. */
/* Étape en cours / prochaine étape (P6, 2.2b) : mise en avant visuelle, jamais une donnée
   supplémentaire côté moteur -- purement une classe posée par la couche de présentation. */
.journee-etape.is-etape-courante .journee-etape__bouton { border-color: var(--color-primary); background: var(--color-primary-soft); }
.journee-etape.is-etape-courante .journee-etape__heure { color: var(--color-primary); }
.journee-etapes__toggle { width: 100%; margin-top: var(--space-2); padding: var(--space-2); border: none; background: none; color: var(--color-primary); font-weight: 600; text-align: center; }
.journee-etapes--suite { margin-top: var(--space-2); }
@media (prefers-reduced-motion: reduce) { .assistant-panel { transition: none; } }
@media (prefers-reduced-motion: reduce) { .map-viewport { transition: none; } } /* LOT Drag synchronise carte/panneau (2026-07-10) : meme traitement que .assistant-panel juste au-dessus. */

/* LOT Mode carte immersive (2026-07-10) : etat 3 du bottom sheet, mobile uniquement (<768px).
   Repose sur l architecture existante (.map-viewport / .map-status deja ancres
   sur --sheet-height) : on ne redefinit pas --sheet-height (trop de dependants pour le faire sans
   risque), on masque explicitement le panneau + le bandeau via .is-immersive porte
   par #map-app (ancetre commun a .map-stage et .assistant-panel), et on libere le padding bas de
   .map-viewport pour que l archipel profite de tout l espace rendu disponible. Aucune modification
   des regles de base de .map-status/.assistant-panel : uniquement des regles
   supplementaires conditionnees par .is-immersive, qui ne s appliquent jamais par defaut. */
@media (max-width: 767px) {
  .map-app.is-immersive .assistant-panel { transform: translateY(100%); box-shadow: none; pointer-events: none; }
  .map-app.is-immersive .map-status { opacity: 0; pointer-events: none; transition: opacity 220ms cubic-bezier(0.2, 0, 0, 1); } /* SUPPRESSION .rain-mode-note (2026-07-10) : element retire du HTML, plus rien a masquer ici. */
  .map-app.is-immersive .map-viewport { padding-bottom: var(--space-4); }
  .map-app.is-immersive .map-immersive-toggle { bottom: calc(var(--space-4) + env(safe-area-inset-bottom, 0px)); }
  .map-app.is-immersive .map-immersive-toggle__label { display: inline; }
  .map-app.is-immersive .map-immersive-toggle__icon--enter { display: none; }
  .map-app.is-immersive .map-immersive-toggle__icon--exit { display: inline; }
  /* Le SVG est par defaut borne par sa largeur (width: min(100%, 760px), hauteur derivee du
     ratio intrinseque du viewBox) : en immersif, le padding-bottom libere de la hauteur mais la
     boite du SVG ne grandissait pas au-dela de sa largeur, laissant du vide au-dessus/en-dessous
     (letterboxing). On bascule la contrainte dimensionnante sur la hauteur uniquement en immersif
     pour que le SVG exploite tout l espace vertical disponible. viewBox et preserveAspectRatio
     (xMidYMid meet, valeur par defaut) restent inchanges : aucun rognage, aucune deformation. */
  .map-app.is-immersive .azores-svg { width: auto; height: 100%; max-width: 100%; }
  /* Audit boutons de fermeture mobile (2026-07-18, demande explicite) : sur mobile, tous les
     boutons de fermeture affichent uniquement l'icone -- le texte "Fermer" reste dans le DOM
     (aria-label + span dedie ajoutes en HTML sur les 3 boutons reels : data-detail-close,
     data-carnet-close, data-minimap-close) mais est masque visuellement. Le wizard Miguel
     (.miguel-wizard__close) reutilise deja .detail-close pour son style et beneficie donc
     automatiquement de cette meme regle, sans code separe a ecrire pour lui. Aucun selecteur JS ne
     cible .detail-close__label pour du comportement (verifie) : masquage purement visuel, aucun
     risque de regression fonctionnelle. Zone tactile 44x44 garantie (min-height deja 44px sur
     .detail-close de base, min-width ajoute ici pour compenser la disparition du texte qui donnait
     sa largeur). Desktop (hors media query) : "Fermer" reste affiche normalement, inchange. */
  .detail-close { min-width: 44px; justify-content: center; gap: 0; }
  .detail-close__label { display: none; }
  /* Correctif (2026-07-18, audit de synchronisation demande) : le libelle "Fermer" du wizard
     (.miguel-wizard__close-label) etait jusqu'ici masque uniquement a partir de 479px (regle
     isolee plus bas dans ce fichier), pas 767px comme les 3 autres boutons de fermeture --
     incoherence reelle : entre 480px et 767px (ex. tablette portrait), le wizard affichait encore
     "Fermer" alors que fiche/carnet/mini-carte n'affichaient deja plus que l'icone. Unifie ici sur
     le meme breakpoint. La regle a 479px plus bas devient redondante avec celle-ci (elle reste en
     place, sans effet nouveau, pour ne pas toucher a un second endroit du fichier ce lot). */
  .miguel-wizard__close-label { display: none; }
  /* Renfort mobile (2026-07-18) : respiration supplementaire par rapport au right: var(--space-4)
     de base, demandee specifiquement sur mobile (la ou la pastille paraissait la plus collee). */
  .miguel-wizard__close { right: var(--space-5); }
}
@media (max-width: 767px) and (prefers-reduced-motion: reduce) {
  .map-app.is-immersive .map-status { transition: none; } /* SUPPRESSION .rain-mode-note (2026-07-10). */
}

/* ============================================================
   LOT 1 (2026-07-10) — Fluidite : transition sur le switch entre les 2
   propositions Miguel, et sur l'ouverture/fermeture des accordeons
   (envies, filtres, "voir toute la journee"). Additif uniquement :
   aucune regle existante modifiee, aucun risque de regression sur la
   disposition actuelle. Hauteur mesuree en JS (togglerAvecAnimation),
   jamais devinee ici. Voir carte.js pour la logique associee.
   ============================================================ */
[data-main-recommendation], [data-alternatives] {
  transition: opacity 180ms ease, transform 180ms ease;
}
[data-main-recommendation].is-journee-transition,
[data-alternatives].is-journee-transition {
  opacity: 0;
  transform: translateY(6px);
}
[data-envies-panel], [data-filters-panel], [data-journee-suite] {
  overflow: hidden;
  transition: height 220ms cubic-bezier(0.2, 0, 0, 1), opacity 200ms ease;
}
@media (prefers-reduced-motion: reduce) {
  [data-main-recommendation], [data-alternatives],
  [data-envies-panel], [data-filters-panel], [data-journee-suite] {
    transition: none !important;
  }
}

/* ============================================================
   PHASE 1 — Fondations critiques (ajouts, design system V2 conservé)
   ============================================================ */
.map-header__actions { display: flex; align-items: center; gap: var(--space-2); }
.map-header__carnet { display: inline-flex; align-items: center; gap: 6px; border: 0; cursor: pointer; font-family: inherit; }
.carnet-counter { display: inline-flex; align-items: center; justify-content: center; min-width: 18px; height: 18px; padding: 0 5px; border-radius: var(--radius-pill); background: var(--color-primary); color: #fff; font-size: var(--map-text-2xs); font-weight: 800; }

.weather-bar { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); margin-bottom: var(--space-2); } /* Correctif structurel fiche spot (2026-07-17, v2) : .weather-bar avait jusqu'ici toujours exactement 2 enfants directs (.weather-status a gauche, .weather-refresh a droite) et s'appuyait sur justify-content:space-between pour les ecarter. Inserer .detail-close comme 3e enfant direct aurait casse ce calage (space-between aurait pousse .weather-refresh au milieu). .weather-bar__actions (voir carte.html) regroupe "Actualiser" et "Fermer" dans UN SEUL second enfant flex, pour que .weather-bar garde son comportement a 2 blocs (statut a gauche, actions a droite), inchange. */ .weather-bar__actions { display: flex; align-items: center; gap: var(--space-2, 0.75rem); flex: 0 0 auto; } /* .detail-close vit ici dans .sheet-header (voir carte.html/carte.js) et non plus dans .spot-detail -- son margin-bottom (1.5rem, ligne 466) n'a de sens que pour un bouton en flux normal au-dessus d'un titre ; dans une rangee d'actions horizontale a cote de "Actualiser", il ne doit produire aucun espace vertical. Scoped a ce seul emplacement : les 2 autres boutons partageant la classe .detail-close (data-carnet-close, data-minimap-close) gardent leur margin-bottom d'origine, inchange. */ .weather-bar__actions .detail-close { margin-bottom: 0; }
/* Correctif (2026-07-18, point de vigilance signale -- largeur etroite 320-375px) :
   .weather-bar est en flex sans wrap ; .weather-status n'avait ni min-width:0 ni troncature, donc
   un libelle meteo long pouvait forcer un depassement horizontal et repousser
   .weather-bar__actions (Actualiser/Modifier profil) hors ecran sur les tres petits mobiles.
   Meme traitement que .weather-eyebrow (troncature propre avec ellipsis) plutot qu'un
   debordement brut. */
.weather-status { margin: 0; font-size: var(--map-text-sm); font-weight: 700; color: var(--color-text-muted); min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.weather-refresh { flex: 0 0 auto; min-height: 44px; padding-inline: var(--space-3, 1.25rem); border: 1px solid var(--color-border); border-radius: var(--radius-pill); background: var(--color-surface); color: var(--color-text); font-size: var(--map-text-xs); font-weight: 700; }
/* Bloc Miguel 3 (2026-07-17, v2 -- deplacement demande) : "Modifier profil" est une action globale sur Miguel (comme "Actualiser"), pas une action liee au contenu de la recommandation -- il vit donc desormais dans .weather-bar__actions, au meme niveau que .weather-refresh, et reutilise EXACTEMENT le meme style de bouton (pas de nouvelle famille de composant).
   La ligne de profil (.plan-card__profil-texte) redevient un simple texte informatif dans .plan-card, sans bouton ni conteneur flex : ce n'est plus une zone d'action, juste un statut. */
/* Correctif (2026-07-18, demande explicite -- debordement mobile) : white-space:nowrap +
   text-overflow:ellipsis forcaient une seule ligne et coupaient le texte de facon illisible dès
   que plusieurs categories/styles etaient selectionnes (ex. profil Explorer avec 2-3 styles).
   Remplace par un conteneur flex qui se replie sur plusieurs lignes (flex-wrap), chaque morceau
   devenant un chip individuel (voir .plan-card__profil-chip) construit par
   DHTUI.renderProfilActifMiguel() -- aucun texte tronque, hauteur qui s'adapte au nombre de choix,
   coherent avec les boutons pill existants (Actualiser/Modifier profil) puisqu'il reutilise les
   memes tokens (radius-pill, surface-muted). Comportement desktop inchange : si tout tient sur une
   ligne, le wrap ne produit visuellement rien de different qu'avant. */
.plan-card__profil-texte { margin: 0 0 var(--space-2, 0.75rem); font-size: var(--map-text-xs); color: var(--color-text-muted, var(--color-text)); display: flex; flex-wrap: wrap; align-items: center; gap: 6px; max-width: 100%; }
.plan-card__profil-icone { display: inline-flex; align-items: center; flex-shrink: 0; }
.plan-card__profil-icone svg { width: 14px; height: 14px; }
.plan-card__profil-chip { display: inline-flex; align-items: center; background: var(--color-surface-muted); border-radius: var(--radius-pill); padding: 2px 10px; line-height: 1.3; white-space: nowrap; }
.plan-card__profil-modifier { flex: 0 0 auto; min-height: 44px; padding-inline: var(--space-3, 1.25rem); border: 1px solid var(--color-border); border-radius: var(--radius-pill); background: var(--color-surface); color: var(--color-text); font-size: var(--map-text-xs); font-weight: 700; display: inline-flex; align-items: center; gap: 4px; cursor: pointer; }
.plan-card__profil-modifier:hover { background: var(--color-surface-hover, var(--color-surface)); }
/* Bloc Surf 2C (2026-07-17, decision produit validee) : bloc "Conditions surf Miguel" dans la
   fiche spot, affiche UNIQUEMENT quand la fiche est ouverte depuis une recommandation Miguel Surf
   (voir openDetail(id, {source:"miguel-surf"})) -- jamais depuis la carte, "Autour de moi" ou un
   autre univers. Volontairement pas d'eau/courant (donnee reelle indisponible, voir CHANGELOG) :
   architecture prevue pour les ajouter plus tard sans reprendre ce bloc. */
.detail-surf-bloc { margin: var(--space-3, 1rem) 0; padding: var(--space-3, 1rem); border: 1px solid var(--color-border); border-radius: var(--radius-md, 12px); background: var(--color-surface); }
.detail-surf-bloc__titre { margin: 0 0 var(--space-2, 0.75rem); font-size: var(--map-text-sm); font-weight: 700; display: flex; align-items: center; gap: 6px; }
.detail-surf-bloc__grille { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2, 0.75rem); margin: 0 0 var(--space-2, 0.75rem); }
.detail-surf-bloc__item { display: flex; flex-direction: column; gap: 2px; }
.detail-surf-bloc__item-label { display: flex; align-items: center; gap: 4px; font-size: var(--map-text-xs); color: var(--color-text-muted, var(--color-text)); }
.detail-surf-bloc__item-valeur { font-size: var(--map-text-sm); font-weight: 700; }
.detail-surf-bloc__analyse { margin: 0; font-size: var(--map-text-xs); font-style: italic; color: var(--color-text-muted, var(--color-text)); border-top: 1px solid var(--color-border); padding-top: var(--space-2, 0.75rem); }
/* Decision produit validee (2026-07-17) : mention discrete rappelant que les conditions sont
   observees au moment de la recommandation, pas une prevision garantie toute la journee. */
.detail-surf-bloc__mention { margin: var(--space-1, 0.5rem) 0 0; font-size: 0.7rem; color: var(--color-text-muted, var(--color-text)); opacity: 0.75; }
/* Bloc Explorer 2A (2026-07-17, decision produit validee) : selection multiple des styles
   ("envies") de l'ecran explorer-q2 uniquement -- 1 a 3 choix, bouton "Suivant" desactive tant
   que 0 choix. Meme famille visuelle que le reste du wizard (.miguel-card, .eyebrow), aucune
   nouvelle famille de composant introduite. */
.miguel-wizard__subtitle { margin: -6px 0 var(--space-2, 0.75rem); font-size: var(--map-text-xs); color: var(--color-text-muted, var(--color-text)); }
/* Correctif espacement (2026-07-18) : le bouton etait trop colle a la derniere ligne de cartes (margin-top 12px) -- pas de conteneur "footer" dedie dans le DOM actuel (.miguel-wizard__suivant est un simple sibling direct de .miguel-wizard__grid), donc l'espacement est porte par le bouton lui-meme plutot que par un footer qui n'existe pas encore. 28px = respiration nette (fourchette 24-32px demandee) sans creer de nouveau conteneur. */
.miguel-wizard__suivant { width: 100%; margin-top: 28px; }
.miguel-wizard__suivant[disabled] { opacity: 0.45; cursor: not-allowed; }
.weather-refresh:disabled { opacity: 0.6; }
.weather-disagreement { margin: 0 0 var(--space-2); padding: var(--space-2) var(--space-3); border-radius: var(--radius-md, 12px); background: var(--map-state-info-bg); color: var(--map-state-info-text); font-size: var(--map-text-sm); font-weight: 600; } /* LOT Mobile Composition (2026-07-10) : couleur dediee (gris-bleu neutre) au lieu de --map-state-warning-*, qui est aussi utilisee par .safety-badge--modere (alerte securite reelle, ex. meduses). Cette nuance meteo est une precision de confiance, pas un avertissement -- elle ne doit plus partager le code couleur des vraies alertes. Texte, seuil, position et .safety-badge inchanges. */
.webcam-link { display: inline-block; margin-bottom: var(--space-3); font-size: var(--map-text-sm-alt2); font-weight: 700; color: var(--color-primary); text-decoration: none; }
.webcam-link:hover { text-decoration: underline; }
/* .rain-mode-note supprimee (2026-07-10) : message fusionne dans .weather-disagreement (voir carte.js). */
/* LOT Mode carte immersive (2026-07-10) : bouton dedie (Option A -- pas de geste cache), visible
   uniquement <768px (regle desactivante plus bas). Position calquee sur le meme principe de pile
   deja utilise par .map-status : se degage de .map-status, sans dependre
   de la hauteur du panneau replie/etendu puisqu il reste ancre a --sheet-height comme le reste de la pile. */
.map-immersive-toggle { position: absolute; right: var(--space-3); bottom: calc(var(--sheet-height) + var(--space-3) + 34px + var(--space-3)); z-index: 12; /* SUPPRESSION .rain-mode-note (2026-07-10) : un seul palier de 34px desormais (celui de .map-status), le second (ancien bandeau) est retire. */ display: inline-flex; align-items: center; gap: var(--space-2); min-height: 44px; padding-inline: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-pill); background: rgba(255, 255, 255, 0.92); color: var(--color-text); font-weight: 700; font-size: var(--map-text-xs); box-shadow: var(--shadow-sm); transition: background-color 160ms ease, box-shadow 160ms ease; }
.map-immersive-toggle:hover, .map-immersive-toggle:focus-visible { background: rgba(255, 255, 255, 0.98); box-shadow: 0 2px 8px rgba(24, 49, 47, 0.16); }
.map-immersive-toggle__label, .map-immersive-toggle__icon--exit { display: none; }
@media (min-width: 768px) { .map-immersive-toggle { display: none; } } /* fonctionnalite mobile uniquement, aucun effet desktop/tablette pointer:fine */

.trademark { font-size: 0.55em; vertical-align: super; margin-left: 1px; }

.safety-badge { margin: var(--space-2) 0; padding: var(--space-2) var(--space-3); border-radius: var(--radius-md, 12px); font-size: var(--map-text-base); font-weight: 600; }
.safety-badge--modere { background: var(--map-state-warning-bg); color: var(--map-state-warning-text); }
.safety-badge--eleve { background: var(--map-state-danger-bg); color: var(--map-state-danger-text); }
.official-links { margin: var(--space-2) 0; font-size: var(--map-text-sm); color: var(--color-text-muted); }
.official-links a { color: var(--color-primary); font-weight: 700; text-decoration: none; }
.official-links a:hover { text-decoration: underline; }

.button-secondary.is-added { background: var(--color-primary-soft, #dff3ef); border-color: var(--color-primary); color: var(--color-primary); }

.carnet-modal { position: fixed; inset: 0; z-index: 60; display: flex; align-items: flex-end; justify-content: center; background: rgba(24, 49, 47, 0.45); }
.carnet-modal[hidden] { display: none; }
.carnet-modal__panel { width: 100%; max-width: 520px; max-height: 82dvh; overflow-y: auto; border-radius: 24px 24px 0 0; background: var(--color-surface); padding: var(--space-4); }
.carnet-modal__header { display: flex; align-items: center; justify-content: space-between; margin-bottom: var(--space-3); }
.carnet-modal__header h2 { margin: 0; font-size: 1.1rem; }
.carnet-group h4 { margin: var(--space-3) 0 var(--space-2); font-size: var(--map-text-md); color: var(--color-text-muted); }
.carnet-item { display: flex; align-items: flex-start; justify-content: space-between; gap: var(--space-2); padding: var(--space-2) 0; border-bottom: 1px solid var(--color-border); }
.carnet-item strong { display: block; font-size: var(--map-text-md); }
.carnet-item span { display: block; font-size: var(--map-text-sm-alt); color: var(--color-text-muted); }
.button-remove { flex: 0 0 auto; border: 0; background: none; color: #8a2c1f; font-size: var(--map-text-sm); font-weight: 700; cursor: pointer; }
.carnet-empty { color: var(--color-text-muted); font-size: var(--map-text-md); }
.carnet-modal__footer { display: flex; gap: var(--space-2); margin-top: var(--space-3); }

@media (min-width: 768px) {
  .carnet-modal { align-items: center; }
  .carnet-modal__panel { border-radius: 20px; }
}
@media print {
  .map-header, .map-stage, .assistant-panel__handle, .weather-bar, .carnet-modal__footer, .detail-close { display: none !important; }
  .carnet-modal { position: static; background: none; }
  .carnet-modal__panel { max-height: none; overflow: visible; box-shadow: none; }
}

/* ============================================================
   PHASE 2 — Carte interactive (filtres, mini-carte, pins complets, trajet)
   ============================================================ */
.map-controls { flex-wrap: wrap; row-gap: var(--space-2); }
/* Correctif BUG 2 (2026-07-10) : .filters-panel etait ancre en position:absolute sur .map-stage (pres des controles de la carte), completement deconnecte du bouton "Filtres" reel, situe dans .explorer-libre au fond du panneau Miguel (carte.html). Le clic executait bien DHTUI.togglerAvecAnimation (aucun bug JS), mais le panneau s'ouvrait hors du champ de vision de l'utilisateur -- au-dessus de la carte, parfois recouvert par .assistant-panel (z-index superieur) selon la hauteur d'ecran et l'etat replie/etendu du tiroir -- percu comme "le bouton ne fait rien". .filters-panel est desormais un enfant direct de .explorer-libre (carte.html), juste sous ses boutons, exactement comme .envies-panel le fait deja pour son propre bouton juste au-dessus : simple bloc en flux normal, plus aucune coordonnee absolue a synchroniser avec la carte. Meme systeme DHTFilters / DHTUI.togglerAvecAnimation reutilise a l'identique (aucune nouvelle logique de filtrage). */
.filters-panel { margin-top: var(--space-3); padding: var(--space-3); border-radius: var(--radius-lg); background: rgba(255, 255, 255, 0.98); box-shadow: var(--shadow-sm); }
/* Boutons de contrôle compacts (icône seule) sous 480px : garantit que "Me localiser",
   "Filtres" et "Mini-carte" tiennent sur une seule ligne à côté du sélecteur d'île. */
.control-button__label { margin-left: 4px; }
@media (max-width: 479px) {
  .control-button__label { display: none; }
  .control-button { padding-inline: var(--space-3); }
  .map-viewport { padding-top: 84px; } /* LOT Recentrage archipel mobile (2026-07-10) : sous 480px, .control-button__label est masque (regle ci-dessus), donc .map-controls tient garantie sur une seule ligne -- le degagement de 112px (calibre pour un scenario a 2 lignes qui ne peut pas se produire ici) est disproportionne et pousse tout le cadrage de la scene vers le bas, ecrasant la distance avec le bandeau Miguel tout en laissant un vide au-dessus de l archipel. 84px degage confortablement une ligne de controles (~68px) tout en rendant a l archipel un cadrage plus centre et un ecart net avec le bandeau. Aucun changement sur les silhouettes, labels, panneau, ni sur les largeurs >=480px/tablette/desktop. */
}
.filters-panel[hidden] { display: none; }
.filters-panel__list { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-bottom: var(--space-2); }
.filter-chip { min-height: 44px; padding-inline: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-pill); background: var(--color-surface); color: var(--color-text); font-size: var(--map-text-sm-alt); font-weight: 700; } /* correctif P1 (audit) : 36px écrasait le 44px de .chip en cascade, zone tactile réellement sous la norme */
/* Intégration pictogrammes officiels DHT Azores (remplacement des emojis catégories/profils, cf. sprite inline dans carte.html) */
.cat-icon { width: 1.15em; height: 1.15em; flex-shrink: 0; vertical-align: -0.2em; display: inline-block; }
/* Correctif (2026-07-20, filet de securite icones) : garantit qu'aucune icone resolue par resoudreIconesDHTTemp() (carte.js) ne peut s'afficher sans contrainte de taille, quelle que soit la classe portee (icon-lucide/cat-icon) ou un futur oubli de classe -- cible uniquement les elements portant cet attribut, aucune autre balise svg/img du site n'est concernee ; .icon-lucide/.cat-icon/regles plus specifiques (ex. .journee-etape__planifiee svg, 14px) restent prioritaires et inchangees. */
[data-dht-icon-temp] { width: 1.05em; height: 1.05em; }
/* Correctif (2026-07-20) : .detail-activite-planifiee (fiche spot, activites a horaires fixes -- ex. "Sorties en mer") n'avait AUCUNE regle CSS dans ce fichier, contrairement a son equivalent .journee-etape__planifiee (deja stylee) -- meme traitement visuel applique ici, scope strictement limite a ce bloc. */
.detail-activite-planifiee { margin: 0 0 var(--space-3); padding-top: var(--space-2); border-top: 1px solid var(--color-border); }
.detail-activite-planifiee p { margin: 0 0 var(--space-1); color: var(--color-text-muted); font-size: var(--map-text-base); overflow-wrap: anywhere; }
.detail-activite-planifiee svg { width: 1.05em !important; height: 1.05em !important; max-width: 1.05em !important; max-height: 1.05em !important; flex-shrink: 0; vertical-align: -0.18em; overflow: hidden; }
/* Bibliotheque "Micro Miguel" (validee, 2026-07-14) : variantes allegees des 8 pictos de
   categorie (nature, vue, volcan, patrimoine, plage, bienetre, faune, lazer), rendues en SVG
   inline (DHT_PICTO_MICRO dans carte.js) plutot qu'en reference au sprite. Meme boite de
   rendu que .cat-icon (aucun deplacement des chips) ; couleur Miguel validee figee en dur
   dans les pictos, cette regle ne fait qu'assurer un rendu net a tres petite taille. */
.cat-icon--micro { shape-rendering: geometricPrecision; }
.filter-chip, .profile-chip { display: inline-flex; align-items: center; gap: 6px; } /* Revue Premium : .category-chip et .badge retires de ce selecteur partage (code mort, aucune reference HTML/JS) */
.filter-chip.is-active { border-color: var(--color-primary); background: var(--color-primary-soft, #dff3ef); color: var(--color-primary); }
.filters-panel__reset { border: 0; background: none; color: var(--color-text-muted); font-size: var(--map-text-sm); font-weight: 700; text-decoration: underline; cursor: pointer; }

.pin-dim circle { opacity: 0.72; cursor: pointer; } /* MISSION FINITION UI (2026-07-14, demande client "POI secondaires plus cartographiques, effet interface reduit") : etait 0.85 -- cette regle de classe passe AVANT l'attribut inline pose par carte.js (voir renderAllSpotsPins), donc c'est bien ELLE qui pilote l'opacite au repos, et non l'attribut. Les points mis en evidence par "Autour de moi" restent inchanges : .pin-around-highlight circle (ci-dessus) impose opacity:1 en !important, prioritaire dans tous les cas. */
.pin-dim:hover circle, .pin-dim:focus circle { opacity: 1; stroke: var(--color-primary); }

.detail-trajet { margin: 0 0 var(--space-2); font-size: var(--map-text-base); font-weight: 700; color: var(--color-text); }

.minimap-modal { position: fixed; inset: 0; z-index: 61; display: flex; align-items: center; justify-content: center; background: rgba(24, 49, 47, 0.5); }
.minimap-modal[hidden] { display: none; }
.minimap-modal__panel { width: 92%; max-width: 480px; max-height: 86dvh; overflow-y: auto; border-radius: 20px; background: var(--color-surface); padding: var(--space-4); }
/* Miguel V1.6 (onboarding déclaratif) : ajout minimal, sur le même modèle que .minimap-modal
   ci-dessus (aucune variable/token nouveau, aucune règle existante modifiée). */
.miguel-onboarding-entry { display: block; width: 100%; margin-top: var(--space-2); padding: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-lg); background: var(--color-surface); color: var(--color-text); font-weight: 600; text-align: left; text-decoration: none; cursor: pointer; } /* Refonte UX Miguel (2026-07-15) : ce bouton devient visuellement le "frere" de .envies-toggle (meme hauteur, meme bordure, meme fond) -- avant cette date il etait un simple lien souligne, ce qui renforcait l'impression de deux systemes concurrents. Aucune regle de .envies-toggle modifiee, uniquement un alignement de style depuis ce cote. */
.miguel-onboarding-modal { position: fixed; inset: 0; z-index: 62; display: flex; align-items: center; justify-content: center; background: rgba(24, 49, 47, 0.5); }
.miguel-onboarding-modal[hidden] { display: none; }
.miguel-onboarding-modal__panel { width: 92%; max-width: 480px; max-height: 86dvh; overflow-y: auto; border-radius: 20px; background: var(--color-surface); padding: var(--space-4); } /* Bloc Miguel 1 -- reactivation onboarding (2026-07-17). ATTENTION, ne pas confondre avec les 3 regles juste au-dessus (.miguel-onboarding-entry / .miguel-onboarding-modal / .miguel-onboarding-modal__panel) : celles-ci stylent une AUTRE fonctionnalite, la modale manuelle "Miguel & vous" (bouton "Personnaliser Miguel", preferences memoire long terme), ouverte a la demande, jamais au chargement. Le bloc ci-dessous stylise .miguel-wizard, l'ecran d'accueil Explorer/Surf affiche automatiquement au premier chargement quand aucun profil n'est encore enregistre (voir carte.js, DHTMiguelOnboarding.init(), et carte.html, attribut data-miguel-onboarding) -- un nom de classe volontairement distinct (.miguel-wizard, pas .miguel-onboarding-modal) pour eviter toute confusion future entre ces deux fonctionnalites voisines mais independantes. */ .miguel-wizard { position: fixed; inset: 0; z-index: 65; display: flex; align-items: center; justify-content: center; background: rgba(24, 49, 47, 0.55); } .miguel-wizard[hidden] { display: none; } .miguel-wizard__panel { position: relative; width: 92%; max-width: 460px; max-height: 86dvh; overflow-y: auto; border-radius: 24px; background: var(--color-surface); padding: var(--space-5) var(--space-4) var(--space-4); text-align: center; animation: dht-detail-in 0.25s ease-out; } /* Correctif (2026-07-18, retour visuel "bulle trop proche du bord") : ce bouton est absolument
   positionne dans .miguel-wizard__panel, donc il IGNORE le padding horizontal du panneau
   (var(--space-4), applique seulement au flux normal) et se retrouvait a right: var(--space-3),
   plus proche du bord que le reste du contenu -- d'ou l'impression de pastille "collee". right
   passe a var(--space-4) par defaut (aligne sur le padding du panneau) et var(--space-5) sur
   mobile (respiration supplementaire demandee). top inchange (le probleme signale est uniquement
   l'offset horizontal, pas vertical). */
.miguel-wizard__close { position: absolute; top: var(--space-3); right: var(--space-4); min-height: 44px; padding-inline: var(--space-3); margin-bottom: 0; } /* Correctif (2026-07-18, audit de synchronisation demande) : min-height etait a 36px, ecrasant les 44px de base de .detail-close -- violait la zone tactile minimale explicitement demandee pour tous les boutons de fermeture. Remis a 44px ; ce bouton reste hidden par defaut aujourd'hui (voir carte.html), donc sans impact visuel actuel, mais correct si/quand il est revele. */ /* Correctif (2026-07-17, retour terrain iPhone) : le bouton Fermer est en absolute top-right et pouvait chevaucher le texte .eyebrow de l'ecran d'accueil (meme s'il reste hidden par defaut au premier lancement, cette marge protege toute reouverture future ou le bouton deviendrait visible). Scope volontairement limite a .miguel-wizard__panel, aucun autre .eyebrow du site n'est concerne. */  /* Correctif securite (2026-07-17) : le bouton Fermer du wizard est cache par defaut (attribut HTML hidden) et n'est revele par le JS QUE si un profil est deja enregistre (reouverture volontaire) -- au tout premier lancement, sans profil, il reste absent pour ne pas laisser l'utilisateur fermer l'ecran sans avoir choisi, ce qui le laisserait bloque sans profil ni explication. Reutilise .detail-close pour le style (icone/typo/couleur identiques), scope additionnel via .miguel-wizard__close uniquement pour le positionnement absolu dans ce panneau. */ /* Correctif (2026-07-17) : les titres d'ecran ("Bienvenue aux Acores", "Quel type de session recherchez-vous ?", etc.) provoquaient un retour a la ligne inutile, creant du vide vertical et un scroll artificiel. white-space: nowrap empeche tout retour a la ligne ; clamp() reduit la taille de police sur les ecrans etroits AVANT d'autoriser un retour ligne (priorite demandee : 1. une seule ligne, 2. lisibilite, 3. pas de scroll pour un titre) plutot qu'une taille fixe qui deborderait sur mobile. Scope strictement limite a .miguel-wizard__title, aucun autre titre du site n'est concerne. */
.miguel-wizard__title { margin: 0 0 var(--space-2); font-size: clamp(0.95rem, 4.6vw, var(--map-text-lg, 1.25rem)); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 100%; }
/* Correctif structurel (2026-07-17) : il n'existe pas de conteneur "header" commun titre+bouton dans le DOM -- .miguel-wizard__close est un element UNIQUE, positionne en absolu au niveau de .miguel-wizard__panel (pas par ecran), partage par tous les .miguel-wizard__screen. Regle unique valable pour TOUS les ecrans (accueil, univers, questions...), via :has() : elle ne s'active QUE si ce bouton devient effectivement visible (il est hidden par defaut aujourd'hui, voir carte.html) -- pas de perte de largeur/lisibilite pour l'usage actuel, protection automatique le jour ou ce bouton sera revele (reouverture volontaire, Bloc Miguel 2).
   Correctif (2026-07-18, retour terrain "Modifier profil") : 88px sous-estimait la largeur reelle du
   bouton (icone 16px + " Fermer" en gras + padding-inline var(--space-3) des deux cotes + la marge
   right: var(--space-3) avant le bord du panneau) -- constate en reouverture reelle du wizard, le
   titre venait quasiment toucher le bouton. Relevé a 132px, valeur volontairement genereuse plutot
   que de rechercher un pixel-perfect qui dependrait de tokens (--space-3/--space-4) definis hors de
   ce fichier. En complement, .miguel-wizard__close-label est masque sur tres petit ecran (media query
   plus bas) : le bouton redevient une simple icone, et la marge reservee y est reduite en consequence. */
/* Correctif (2026-07-18, retour visuel "bouton pose sur la 1ere carte") : .miguel-wizard__close
   est en position: absolute (hors flux), donc son empreinte verticale (top: var(--space-3) sur
   ~44px de haut) ne repousse RIEN en dessous par defaut -- alors que le titre/eyebrow demarre au
   padding-top du panneau (var(--space-5)), plus proche du haut que la base du bouton. Resultat :
   quand le bouton est visible, son bord bas peut arriver visuellement pres du debut du contenu
   (grille de cartes / intro), qui ne "sait" pas qu'un bouton rond occupe cette zone. Plutot que de
   deplacer le bouton (deja bien positionne, cf correctifs precedents) ou de toucher au panel dans
   son ensemble (impacterait aussi le cas bouton cache, majoritaire aujourd'hui), on agrandit
   uniquement le margin-bottom du titre/eyebrow -- scope identique au :has() existant, donc ne
   s'applique QUE quand le bouton est effectivement visible, et couvre tous les ecrans du wizard
   puisque chacun utilise .miguel-wizard__title ou .eyebrow (accueil, univers, questions,
   chargement...). Pas de margin-top negatif, pas de repositionnement absolute. */
.miguel-wizard__panel:has(.miguel-wizard__close:not([hidden])) .miguel-wizard__title,
.miguel-wizard__panel:has(.miguel-wizard__close:not([hidden])) .eyebrow {
  text-align: left;
  padding-right: 132px;
  margin-bottom: var(--space-3);
} .miguel-wizard__intro { margin: 0 0 var(--space-4); color: var(--color-text-muted); } .miguel-wizard__grid { display: grid; grid-template-columns: 1fr 1fr; gap: var(--space-2); margin-top: var(--space-3); } .miguel-card { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: var(--space-3) var(--space-2); border: 1px solid var(--color-border); border-radius: var(--radius-lg); background: var(--color-surface-muted); color: var(--color-text); font-weight: 700; text-align: center; cursor: pointer; transition: border-color 160ms ease, background-color 160ms ease; } .miguel-card:hover, .miguel-card:focus-visible { border-color: var(--color-primary); } .miguel-card.is-active { border-color: var(--color-primary); background: var(--color-surface); } .miguel-card__emoji { font-size: 1.6rem; line-height: 1; } .miguel-card--disabled { cursor: not-allowed; opacity: 0.55; } .miguel-card--disabled:hover, .miguel-card--disabled:focus-visible { border-color: var(--color-border); } .miguel-card__note { font-size: var(--map-text-xs); font-weight: 400; color: var(--color-text-muted); } /* Correctif Miguel 1 (2026-07-17) : remplacement des emojis bruts des cartes univers par des icones Lucide inline (data-dht-icon-temp, meme mecanisme que le reste du site) -- .miguel-card__emoji ci-dessus n'est plus utilisee par le HTML des 3 cartes univers mais reste definie (non supprimee) au cas ou un futur usage la reprendrait. .miguel-card__icon dimensionne le SVG (couleur heritee de currentColor, deja gere par resoudreIconesDHTTemp()). .miguel-card__title empeche le retour a la ligne du libelle ("Explorer l'ile" tenait sur deux lignes, creant un vide vertical inutile) -- scope volontairement limite a .miguel-card__title (uniquement les cartes univers du wizard Miguel), aucun autre bouton/carte du site n'est concerne par cette regle. */ .miguel-card__icon { width: 28px; height: 28px; } /* Correctif (2026-07-17) : meme logique que .miguel-wizard__title ci-dessus, appliquee aux libelles de cartes ("Explorer l'ile", "Photos & points de vue", "Belle vague / plaisir"...) -- ces cartes sont deja en 1 colonne sur mobile (voir @media max-width:479px plus bas), donc le risque de debordement y est deja limite ; clamp() + ellipsis restent une securite supplementaire pour les cas extremes (tres petits ecrans, ou 2 colonnes sur tablette). */
.miguel-card__title { white-space: nowrap; font-size: clamp(0.8rem, 3.6vw, 0.95rem); overflow: hidden; text-overflow: ellipsis; max-width: 100%; } /* Correctif accessibilite/coherence (2026-07-17) : la carte Surf porte l'attribut HTML natif disabled (empeche tout clic/évènement, aucune logique JS necessaire pour la bloquer) -- .miguel-card--disabled ne fait qu'attenuer visuellement l'etat deja garanti par l'attribut natif, elle ne remplace pas la protection reelle. */ .miguel-wizard__loading { list-style: none; margin: var(--space-4) 0 0; padding: 0; display: flex; flex-direction: column; gap: var(--space-2); text-align: left; } .miguel-wizard__loading li { padding: var(--space-2) var(--space-3); border-radius: var(--radius-lg); background: var(--color-surface-muted); color: var(--color-text-muted); font-weight: 600; transition: background-color 200ms ease, color 200ms ease; } .miguel-wizard__loading li.is-active { background: var(--color-primary); color: #fff; } .miguel-wizard__loading li.is-done { background: var(--color-surface-muted); color: var(--color-text); } @media (max-width: 479px) { .miguel-wizard__grid { grid-template-columns: 1fr; } }
.minimap-note { margin: 0 0 var(--space-3); font-size: var(--map-text-sm); color: var(--color-text-muted); }
.minimap-svg { display: block; width: 100%; height: auto; border-radius: var(--radius-lg); background: linear-gradient(180deg, #eef8f5 0%, #f7f4ed 100%); }
.minipin circle { cursor: pointer; filter: drop-shadow(0 2px 4px rgba(24, 49, 47, 0.25)); }
.minipin:hover circle, .minipin:focus circle { fill: var(--color-primary-dark, #0a3f3d); }

@media (min-width: 768px) {
  .map-controls { flex-wrap: wrap; }
}
/* Stabilisation (Phase 5) : au-delà de 1024px, l'assistant-panel repasse en flux normal
   (grille) au lieu d'une feuille flottante ; le toast et la note pluie doivent suivre
   le même ancrage que .map-status plutôt que l'ancien décalage --sheet-height, sinon
   ils restent positionnés comme si la feuille mobile existait encore. */
@media (min-width: 1024px) {
  .toast { left: auto; right: calc(420px + var(--space-6)); bottom: var(--space-5); transform: translateY(12px); }
  .toast.is-visible { transform: translateY(0); }
}

/* ============================================================
   PHASE 4 — Micro-comportements (badges, feedback, animations, transitions)
   ============================================================ */

/* Revue Premium : .spot-badges / .badge / .badge-rain supprimes -- code mort (0 reference HTML/JS, aucune construction dynamique trouvee) */

/* Explication du score, repliable */
.score-explain-toggle { display: block; margin-top: var(--space-2); border: 0; background: none; padding: 0; color: var(--color-text-muted); font-size: var(--map-text-sm); font-weight: 700; text-decoration: underline; cursor: pointer; }
.score-explain-text { margin-top: var(--space-2); padding: var(--space-3); border-radius: var(--radius-md); background: var(--color-surface-muted); color: var(--color-text-muted); font-size: var(--map-text-sm-alt2); line-height: 1.5; }
.score-explain-text[hidden] { display: none; }

/* Widget "Aujourd'hui, le meilleur jour pour..." (replié par défaut) */
/* P-Finalisation (point #5) : .bestofday* retirées (paradigme remplacé par .choix-miguel-*) */
.choix-miguel { min-width: 0; padding: 0 var(--space-4) var(--space-4); }
.choix-miguel__intro { margin: 0 0 var(--space-2); font-size: var(--map-text-base); color: var(--color-text-muted); }
.choix-miguel-list { display: grid; gap: var(--space-2); }
/* LOT 3 (2026-07-10) -- UI Polish : les items "Choix de Miguel" avaient tous la meme bordure +
   fond blanc que les cartes d'action (main-recommendation, alternative-card), ce qui les faisait
   paraitre plus importants qu'ils ne le sont (contenu de reassurance/decouverte, pas une action
   principale). Fond muted sans bordure -- seule la variante --principal garde un vrai relief,
   pour rester la seule ligne qui attire vraiment l'oeil dans cette liste. */
/* Explicabilité (2026-07-11) : .choix-miguel-item passe de <button> à <div> flex-colonne pour
   héberger deux commandes distinctes (voir renderChoixMiguel()) -- .choix-miguel-item__main
   reprend exactement l'apparence du bouton précédent (mêmes propriétés flex/justify) pour
   qu'aucune régression visuelle ne soit visible tant que "Pourquoi ?" n'est pas déplié. */
.choix-miguel-item { min-width: 0; display: flex; flex-direction: column; gap: var(--space-1); padding: var(--space-3); border: 1px solid transparent; border-radius: var(--radius-md); background: var(--color-surface-muted); font-size: var(--map-text-base); transition: transform 0.15s ease, box-shadow 0.15s ease; overflow-wrap: anywhere; cursor: pointer; }
.choix-miguel-item:hover { transform: translateY(-1px); box-shadow: var(--shadow-sm); }
/* Correctif (2026-07-20, demande Antoine) : flex-shrink:0 empeche ce span (picto + libelle
   de categorie, ex. "Observation baleines") de se faire ecraser par le titre du spot dans la
   rangee flex .choix-miguel-item__main (justify-content: space-between). Sans cela, sur mobile,
   overflow-wrap: anywhere (herite de .choix-miguel-item) autorisait une coupure en plein milieu
   du mot ("Observatio" / "n baleines") faute de place. Le <strong> (titre) continue de beneficier
   normalement de overflow-wrap: anywhere, seul ce span de libelle est concerne. */
.choix-miguel-item span { color: var(--color-text-muted); flex-shrink: 0; }
.choix-miguel-item strong { color: var(--color-text); }
.choix-miguel-item--principal { border-color: var(--color-primary); background: var(--color-primary-soft); }
.choix-miguel-item__main { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); width: 100%; min-width: 0; margin: 0; padding: 0; border: 0; background: none; text-align: left; font: inherit; color: inherit; cursor: pointer; }
.choix-miguel-item__score { font-size: var(--map-text-sm); font-weight: 700; color: var(--color-primary); }
.choix-miguel-item__toggle { align-self: flex-start; margin: 0; padding: 0; min-height: 32px; border: 0; background: none; font-size: var(--map-text-sm); font-weight: 700; color: var(--color-primary); text-decoration: underline; cursor: pointer; }
.choix-miguel-item__panel[hidden] { display: none; }
.choix-miguel-item__panel .miguel-explication { margin-top: var(--space-1); }

/* Fact-pills dans la fiche détail (métadonnées d'accessibilité, UV, lever du soleil) */
.detail-facts { display: flex; flex-wrap: wrap; gap: 6px; margin: var(--space-2) 0; }
.detail-facts[hidden] { display: none; }
.fact-pill { display: inline-flex; align-items: center; gap: 6px; padding: 4px 10px; border-radius: var(--radius-pill); background: var(--color-surface-muted); color: var(--color-text); font-size: var(--map-text-xs); font-weight: 600; } /* Correctif espacement icone/texte (2026-07-17) : .fact-pill etait le SEUL composant icone+texte de ce type dans ce fichier sans propriete «gap» -- tous ses equivalents directs deja presents (.around-me-category-chip, .map-header__carnet, .profile-chip, .detail-webcam-link, .spot-tooltip__badge) utilisent deja gap:6px (ou 4px pour la variante la plus petite). Sans gap, l espacement entre l icone SVG et le libelle ne reposait QUE sur le caractere espace litteral insere cote JS (dhtPictoPrefixFicheSpot()/dhtIconeTempHtml(), carte.js) -- rendu visuel colle, plus visible avec le trace fin des icones Lucide qu avec les anciens sprites. gap:6px reprend exactement la meme valeur que les composants freres cites ci-dessus (coherence avec la convention deja en place, pas une nouvelle valeur inventee) : s ajoute au caractere espace existant, aucune modification JS/HTML. La taille de l icone et le rythme des boutons (Fermer, Actualiser, chips .chip/.envie-chip) restent totalement inchanges -- ce correctif ne touche que .fact-pill. */

/* Toast de confirmation (feedback utilisateur, ex. ajout au carnet) */
.toast { position: fixed; left: 50%; bottom: calc(var(--sheet-height, 0px) + 24px); z-index: 80; transform: translate(-50%, 12px); padding: 10px 18px; border-radius: var(--radius-pill); background: var(--color-text); color: #fff; font-size: var(--map-text-sm-alt2); font-weight: 700; text-align: center; max-width: min(22rem, calc(100vw - (var(--space-5) * 2))); white-space: normal; overflow-wrap: break-word; opacity: 0; pointer-events: none; transition: opacity 0.25s ease, transform 0.25s ease; }
.toast.is-visible { opacity: 1; transform: translate(-50%, 0); }

/* Correctif tablette (2026-07-11) : de 768px a 1023px, .assistant-panel est deja une carte
   flottante ancree a droite, mais le toast restait centre (left:50%) jusqu'a 1024px --
   collision possible sur tablette portrait (iPad 10.9"/Pro 11" portrait, Galaxy Tab S9
   portrait). Meme decalage horizontal que la regle >=1024px existante ; bottom/transform
   restent pilotes par --sheet-height, inchanges, comportement mobile <768px inchange. */
@media (min-width: 768px) {
  .toast { left: auto; right: calc(420px + var(--space-6)); }
}

/* Animations d'apparition des pins (Plan du Jour + affichage complet) */
/* LOT 2 (2026-07-10) -- Carte archipel : courbe adoucie (0.4s cubic-bezier au lieu de ease-out
   brut) + les pins recoivent maintenant un animation-delay individuel (voir renderPins() dans
   carte.js) pour une apparition en cascade legere plutot que tous en meme temps. */
@keyframes dht-pin-enter { from { opacity: 0; transform: scale(0.4); } to { opacity: 1; transform: scale(1); } }
.pin-enter { transform-origin: center; animation: dht-pin-enter 0.4s cubic-bezier(0.2, 0.8, 0.2, 1) both; }
.pin, .pin-dim { transition: transform 0.15s ease; transform-box: fill-box; transform-origin: center; }
.pin:hover, .pin:focus, .pin-dim:hover, .pin-dim:focus { transform: scale(1.12); }
.pin-rain circle { stroke-dasharray: 3 2; }

/* v3 (identite Miguel, 2026-07-12) -- demande client : le badge principal du Plan du Jour doit se
   distinguer immediatement d'un simple numero de parcours de randonnee. Halo tres discret, en
   respiration lente, place derriere le disque orange (voir carte.js, renderPins) ; specificite
   ".pin .pin-main__halo" volontairement superieure a la regle generique ".pin circle" plus haut
   (qui lui appliquerait sinon une ombre portee peu adaptee a un anneau). Aucun impact sur le clic :
   purement decoratif, pointer-events herite du groupe .pin (deja cliquable via data-spot-id). */
.pin .pin-main__halo { fill: none; stroke: #f2a65a; stroke-width: 3; opacity: 0.22; filter: none; animation: dht-halo-respire 2.6s ease-in-out infinite; } /* POLISSAGE UI (2026-07-14) : etait stroke-width 4 / opacity 0.28 */
@keyframes dht-halo-respire { 0%, 100% { opacity: 0.16; stroke-width: 2.5; } 50% { opacity: 0.30; stroke-width: 4.5; } } /* POLISSAGE UI (2026-07-14) : amplitude reduite en cohérence avec le halo moins dominant ci-dessus */
@media (prefers-reduced-motion: reduce) { .pin .pin-main__halo { animation: none; opacity: 0.24; } } /* POLISSAGE UI (2026-07-14) : etait 0.3, coherent avec le nouveau halo */
/* v4 (direction artistique, 2026-07-12) : anneau d'identite statique (le sceau DHT), distinct du
   halo respirant ci-dessus -- meme specificite renforcee (".pin .pin-main__anneau") pour ne jamais
   herite de ".pin circle{filter:drop-shadow(...)}" plus haut. */
.pin .pin-main__anneau { fill: none; stroke: #ffffff; stroke-width: 1.2; opacity: 0.75; filter: none; } /* POLISSAGE UI (2026-07-14) : etait stroke-width 1.5 / opacity 0.85 */

/* v5 (direction artistique concierge, 2026-07-12) -- demande client : "spots secondaires = supprimer
   l'impression de liste GPS, afficher moins d'elements, apparition progressive selon le niveau de
   zoom". Les badges secondaires du Plan du Jour (alternatives 2 a 5) restent cliquables a tout
   moment (aucun display:none, aucun changement de logique/zone de clic) mais leur CHIFFRE s'attenue
   au zoom normal -- seul le badge principal (Miguel) garde toute sa presence visuelle par defaut,
   les autres redeviennent des reperes discrets, plus proches d'une pastille de carte illustree que
   d'un numero de parcours. Le chiffre revient progressivement des le zoom intermediaire, sans aucun
   changement de logique de zoom (purement pilote par [data-zoom-tier], deja pose par
   DHTMapZoom.updateNiveauZoomLabels). */
.pin-secondaire__numero { transition: opacity 220ms ease; }
.pin-secondaire__disque { transition: opacity 220ms ease, r 220ms ease; }
.azores-svg[data-zoom-tier="normal"] .pin-secondaire__numero { opacity: 0; }
.azores-svg[data-zoom-tier="normal"] .pin-secondaire__disque { opacity: 0.78; r: 7; }


/* Surlignage temporaire d'un pin (restauré de "surlignage-temporaire", V1) */
@keyframes dht-pin-highlight { 0%, 100% { filter: drop-shadow(0 0 0 rgba(242, 166, 90, 0)); } 50% { filter: drop-shadow(0 0 10px rgba(242, 166, 90, 0.9)); } }
.pin-highlight circle { animation: dht-pin-highlight 0.6s ease-in-out 3; }

/* Transitions douces déjà amorcées en V2, complétées ici */
.chip, .filter-chip { transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease; }
.alternative-card { transition: transform 0.15s ease, box-shadow 0.15s ease; }
.alternative-card:hover { transform: translateY(-2px); box-shadow: var(--shadow-sm); }
/* Revue Premium (audit technique) : ancienne regle .assistant-panel{transition:transform 0.3s ease} supprimee -- elle ecrasait silencieusement (raccourci CSS) la transition "height" declaree plus haut, cassant l'animation fluide d'ouverture/fermeture du panneau. Les deux proprietes (height + transform) sont maintenant fusionnees dans une seule declaration coherente sur .assistant-panel, avec la meme easing, pour un retour "ressort" fluide apres un glissement (swipe) sur la poignee. */
.spot-detail { animation: dht-detail-in 0.25s ease-out; }
@keyframes dht-detail-in { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
.carnet-modal__panel, .minimap-modal__panel { animation: dht-detail-in 0.25s ease-out; }

@media (prefers-reduced-motion: reduce) {
  .pin-enter, .pin-highlight circle, .toast, .spot-detail, .carnet-modal__panel, .minimap-modal__panel, .island-dot-enter { animation: none !important; transition: none !important; }
}

/* ============================================================
   PORTAGE V1 — Profils voyageurs, Concierge, exploration par catégorie
   ============================================================ */
.section-subtitle { margin: 0 0 var(--space-2); font-size: 0.95rem; font-weight: 800; color: var(--color-text); }
/* P-Finalisation (point #5) : .category-explore retirée (paradigme remplacé par .pourquoi-journee/.explorer-libre) */
.profile-chips { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.profile-chip.is-active { border-color: var(--color-primary); background: var(--color-primary); color: #fff; }
.pourquoi-journee { min-width: 0; padding: 12px var(--space-4) var(--space-4); }
.pourquoi-journee__list { display: grid; gap: var(--space-2); list-style: none; margin: 0; padding: 0; }
.pourquoi-journee__item { min-width: 0; padding: var(--space-3); border-radius: var(--radius-md); background: var(--color-surface-muted); font-size: var(--map-text-base); overflow-wrap: anywhere; }
.pourquoi-journee__item strong { display: block; color: var(--color-text); }
.pourquoi-journee__item span { color: var(--color-text-muted); }
/* Explicabilité (2026-07-11) : bloc "Score Miguel™ + Pourquoi cette recommandation ?" de
   l'étape principale, affiché au-dessus de la liste des étapes -- voir renderPourquoiJournee()
   et dhtRenderExplicationDOM(), partagés avec "Les choix de Miguel" et la fiche spot. */
.pourquoi-journee__header .miguel-explication { margin-bottom: var(--space-3); }
/* Bloc générique d'explication Miguel™ -- partagé par "Pourquoi cette journée ?", "Les choix
   de Miguel aujourd'hui" (accordéon) et la fiche spot ("Miguel aujourd'hui"). Un seul jeu de
   règles pour les 3 emplacements (voir dhtRenderExplicationDOM()), pour une apparence toujours
   identique. */
.miguel-explication { margin: 0; padding: var(--space-3); border-radius: var(--radius-md); background: var(--color-primary-soft); font-size: var(--map-text-base); height: auto; max-height: none; overflow: visible; } /* Correctif chevauchement fiche spot desktop (2026-07-12) : meme cause racine que celle deja documentee en tete de fichier pour --space-4/--dht-panel-* -- .miguel-explication est un simple <div> sans regle de hauteur ecrite ICI, donc expose a une regle generique de style.css (feuille externe, hors perimetre de ces 3 fichiers) qui pourrait imposer une height/max-height + overflow:hidden a un conteneur "carte"/"panel" generique. Resultat observe : le cadre visuel (fond/bordure) de .miguel-explication s'arretait avant la fin reelle de son contenu (liste de points forts, vigilance), qui continuait de s'afficher hors de ce cadre, superpose au bloc suivant dans le flux -- exactement le symptome de la capture. height:auto/max-height:none/overflow:visible rendus explicites ICI, une seule fois, ne dependent plus jamais d'une regle externe non garantie : .miguel-explication retrouve une hauteur strictement egale a celle de son contenu reel, quel que soit le nombre de points forts/vigilances affiches. Aucun texte, aucune police, aucun espacement modifie ; aucun contenu masque. */
.miguel-explication__score { margin: 0 0 var(--space-1); font-weight: 800; color: var(--color-text); }
/* UX confiance v2 (2026-07-11) : repère 🟢/🟠/🔴 -- purement éditorial (dhtNiveauConfianceScore()),
   affiché comme sous-titre discret du score, jamais comme une donnée supplémentaire. */
.miguel-explication__niveau { margin: 0 0 var(--space-2); font-size: var(--map-text-sm); color: var(--color-text-muted); }
.miguel-explication__title { margin: 0 0 var(--space-2); font-weight: 700; color: var(--color-text); }
.miguel-explication__sous-titre { margin: 0 0 var(--space-1); font-weight: 700; color: var(--color-text); }
.miguel-explication__points, .miguel-explication__vigilance { display: grid; gap: 2px; margin: 0; padding: 0; list-style: none; }
.miguel-explication__points { margin-bottom: var(--space-2); color: var(--color-text); }
.miguel-explication__points:last-child { margin-bottom: 0; }
.miguel-explication__vigilance-titre { margin: 0 0 2px; font-size: var(--map-text-sm); font-weight: 700; color: var(--map-state-warning-text); }
.miguel-explication__vigilance { color: var(--map-state-warning-text); }
.miguel-explication__eyebrow { margin: var(--space-3) 0 var(--space-1); font-size: var(--map-text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.04em; color: var(--color-text-muted); }
.detail-explication:empty { margin: 0; }
.detail-explication, .miguel-explication, .miguel-comparaison, .miguel-decomposition { height: auto; max-height: none; overflow: visible; } /* Correctif chevauchement fiche spot desktop (2026-07-12, suite) : protection etendue a l'ensemble de la chaine d'explication de la fiche spot (score -> analyse -> pourquoi cette recommandation -> comparaison legere), pas seulement .miguel-explication -- meme cause potentielle (regle generique de style.css, hors perimetre de ces 3 fichiers), meme correctif : ces conteneurs n'avaient aucune regle de hauteur ecrite ici, les rendant individuellement exposes. Valeurs neutres (height:auto, deja le comportement par defaut d'un <div> sans cette regle externe) : aucun changement visuel si aucune interference n'existe, correctif sans risque de regression. */
/* UX confiance v2 (2026-07-11) : le score de "Les choix de Miguel aujourd'hui" est désormais un
   bloc de texte visible en permanence sous le titre (avant : un <em> inline dans le bouton
   principal, visible seulement en un coup d'œil) -- même classe conservée pour ne pas casser un
   éventuel style existant ailleurs, mais règles adaptées à un bloc pleine largeur. */
.choix-miguel-item__score { display: block; margin: 0; font-size: var(--map-text-sm); font-weight: 700; color: var(--color-primary); }
/* UX confiance v3 (2026-07-11) : ligne interprétative sous le score dans "Les choix de Miguel"
   (🌿/👍/🙂/⚠️ + phrase, voir dhtNiveauConfianceScore()) -- même traitement discret que
   .miguel-explication__niveau, jamais une donnée technique. */
.choix-miguel-item__niveau { margin: 2px 0 0; font-size: var(--map-text-sm); color: var(--color-text-muted); }
/* UX confiance v3 (2026-07-11) : confiance temporelle -- discrète, sous le niveau, jamais une
   heure inventée (voir dhtLibelleDerniereAnalyse(), lit uniquement DHT_WX.derniereMaj). */
.miguel-explication__maj { margin: 0 0 var(--space-2); font-size: var(--map-text-xs); color: var(--color-text-muted); font-style: italic; }
/* Créneau de l'évaluation v4 (2026-07-11) : précise QUAND les conditions ont été jugées --
   voir dhtRenderExplicationDOM() (4e paramètre creneauTexte) et le cahier des charges
   "contextualiser la note par créneau horaire". Même famille visuelle discrète que le repère de
   fraîcheur météo (.miguel-explication__maj), pour ne jamais faire concurrence au score. */
.miguel-explication__creneau { margin: 0 0 2px; font-size: var(--map-text-sm); color: var(--color-text-muted); }
.miguel-explication__note-creneau { margin: var(--space-1) 0 0; font-size: var(--map-text-sm); font-style: italic; color: var(--color-text-muted); }
/* Miguel V1.8 (2026-07-15) : bloc des motifs de préférences déclarées, volontairement distinct
   de .miguel-explication (moteur météo/contexte, jamais modifié) -- fond différent pour bien
   marquer visuellement les deux couches d'explication. N'apparaît que si dhtRenderPreferencesMiguelDOM
   reçoit au moins un motif (voir carte.js). */
.miguel-preferences { margin: var(--space-2) 0 0; padding: var(--space-3); border-radius: var(--radius-md); background: var(--color-surface-muted); font-size: var(--map-text-base); }
.miguel-preferences__title { margin: 0 0 var(--space-1); font-weight: 700; color: var(--color-text); }
.miguel-preferences__list { display: grid; gap: 2px; margin: 0; padding: 0; list-style: none; color: var(--color-text); }
/* Miguel V1.10 (2026-07-15) : bloc des insights de mémoire (lecture seule de DHTMiguelMemory),
   volontairement distinct de .miguel-preferences (motifs de scoring, V1.8) et de
   .miguel-explication (moteur météo/contexte) -- affiché uniquement dans la modale onboarding
   (.miguel-onboarding-modal__panel), jamais ailleurs. N'apparaît que si dhtRenderInsightsMiguelDOM
   reçoit au moins une phrase (voir carte.js, actualiserInsights()). */
.miguel-insights { margin: var(--space-3) 0 0; padding: var(--space-3); border-radius: var(--radius-md); background: var(--color-surface-muted); font-size: var(--map-text-base); }
.miguel-insights__title { margin: 0 0 var(--space-1); font-weight: 700; color: var(--color-text); }
.miguel-insights__list { display: grid; gap: 2px; margin: 0; padding: 0; list-style: none; color: var(--color-text); }
.choix-miguel-item__creneau { margin: 2px 0 0; font-size: var(--map-text-sm); color: var(--color-text-muted); }
.pourquoi-journee__note-creneau { margin: var(--space-2) 0 0; font-size: var(--map-text-sm); font-style: italic; color: var(--color-text-muted); }
/* Décomposition pédagogique v3 (2026-07-11) : "Pourquoi ce score ?" en petits blocs thématiques
   (☀️ Météo / 🌬️ Vent / 👀 Visibilité / ⚠️ À surveiller), voir dhtRenderDecompositionDOM() --
   grille simple, aucune nouvelle donnée, uniquement une présentation plus pédagogique des mêmes
   points forts/vigilance déjà utilisés ailleurs. */
.miguel-decomposition { display: grid; gap: var(--space-2); }
.miguel-decomposition__item { padding: var(--space-2); border-radius: var(--radius-sm); background: var(--color-surface-muted); }
.miguel-decomposition__item--vigilance { background: transparent; padding: var(--space-1) 0 0; border-top: 1px solid var(--color-border); }
.miguel-decomposition__label { margin: 0 0 2px; font-size: var(--map-text-sm); font-weight: 700; color: var(--color-text); }
.miguel-decomposition__item--vigilance .miguel-decomposition__label { color: var(--map-state-warning-text); }
.miguel-decomposition__texte { margin: 0; font-size: var(--map-text-sm); color: var(--color-text-muted); }
/* Comparaison légère v3 (2026-07-11) : fiche spot UNIQUEMENT (voir dhtRenderComparaisonLegereDOM()) --
   jamais un classement, une seule phrase de mise en perspective en fin de bloc. */
.miguel-comparaison { margin-top: var(--space-3); padding-top: var(--space-3); border-top: 1px solid var(--color-border); }
.miguel-comparaison__titre { margin: 0 0 var(--space-1); font-weight: 700; color: var(--color-text); }
.miguel-comparaison__intro { margin: 0 0 var(--space-1); color: var(--color-text-muted); }
.miguel-comparaison__points { margin: 0 0 var(--space-2); padding: 0; list-style: none; display: grid; gap: 2px; color: var(--color-text); }
.miguel-comparaison__note { margin: 0; font-size: var(--map-text-sm); font-style: italic; color: var(--color-text-muted); }
/* Justification de la journée v3 (2026-07-11) : phrase fixe au-dessus du bloc score/explication
   de "Pourquoi cette journée ?" (voir renderPourquoiJournee()). */
.pourquoi-journee__justification { margin: 0 0 var(--space-2); color: var(--color-text-muted); }
/* LOT 3 (2026-07-10) -- UI Polish : "Explorer librement" est la section la moins prioritaire de
   l'ecran replie (usage occasionnel, hors parcours principal) -- titre allege pour ne plus
   concurrencer visuellement "Aujourd'hui avec Miguel™"/"Vous voulez orienter Miguel ?". */
.explorer-libre { padding: var(--space-2) var(--space-4) var(--space-4); border-top: 1px solid var(--color-border); margin-top: var(--space-3); }
.explorer-libre #explorer-libre-title, .explorer-libre .section-subtitle { font-size: var(--map-text-sm-alt); font-weight: 700; color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.03em; }
.explorer-libre__intro { margin: var(--space-2) 0 var(--space-2); font-size: var(--map-text-base); color: var(--color-text-muted); }
.explorer-libre__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); }
.plan-card__badge, .alternatives__badge { margin: 0 0 var(--space-2); font-size: var(--map-text-sm); font-weight: 700; color: var(--color-primary); }
.alternative-card__switch { font-size: var(--map-text-sm); color: var(--color-text-muted); margin: 2px 0; }
.detail-webcam-link { display: inline-flex; align-items: center; gap: 6px; margin-bottom: var(--space-3); font-size: var(--map-text-sm-alt2); font-weight: 700; color: var(--color-primary); text-decoration: none; }
.detail-webcam-link[hidden] { display: none !important; }
.detail-webcam-link:hover { text-decoration: underline; }
.icon-lucide { width: 1.05em !important; height: 1.05em !important; max-width: 1.05em !important; max-height: 1.05em !important; vertical-align: -0.18em; flex-shrink: 0; overflow: hidden; }
.journee-etape__bouton svg, .pourquoi-journee svg, .choix-miguel svg, .main-recommendation svg, .alternative-card svg { max-width: 1.15em; max-height: 1.15em; flex-shrink: 0; }
.plan-card, .alternatives { min-width: 0; }

/* P6 (Phase 3B, correction de cohérence) : .concierge-toggle/.concierge-panel/.concierge-intro
   retirées ici -- le panneau "Demander à Miguel" séparé n'existe plus, fusionné dans
   "Mes envies aujourd'hui" (voir CHANGELOG). .concierge-field/textarea restent : le champ de
   texte libre facultatif vit désormais dans ce panneau unifié. */
.concierge-field { position: relative; margin-bottom: var(--space-2); }
/* Correctif mobile (2026-07-11) : font-size force a un minimum de 16px pour ce champ de
   saisie precis (textarea #concierge-text) afin d'eviter le zoom automatique declenche
   par iOS Safari au focus sur un champ dont le font-size calcule est < 16px. Applique
   uniquement a ce selecteur : aucun autre texte de l'application n'est modifie. */
.concierge-field textarea { width: 100%; min-height: 56px; padding: var(--space-2) 52px var(--space-2) var(--space-2); border: 1px solid var(--color-border); border-radius: var(--radius-md); font-family: inherit; font-size: max(16px, var(--map-text-base)); resize: vertical; }
.envies-panel__label { margin-top: var(--space-3); }
.envies-panel__optional { font-weight: 400; color: var(--color-text-muted); font-size: var(--map-text-sm-alt); }
.envies-panel__cta { width: 100%; margin-top: var(--space-3); }
/* Correctif 2026-07-08 : centrage réel du bouton vocal (icône inchangée, glyphe 🎙️ conservé à
   l'identique). Ancien positionnement (right/bottom fixes, sans centrage flex) provoquait un léger
   débordement et un centrage vertical imparfait selon la hauteur réelle du champ. Utilisation de
   top:50%+transform pour un centrage garanti quelle que soit la hauteur du textarea, et de flex
   pour centrer parfaitement le glyphe à l'intérieur du bouton rond. */
.concierge-mic { position: absolute; top: 50%; right: 8px; transform: translateY(-50%); width: 40px; height: 40px; display: flex; align-items: center; justify-content: center; padding: 0; line-height: 1; border: 0; border-radius: 50%; background: var(--color-surface); box-shadow: var(--shadow-sm); cursor: pointer; color: var(--color-primary); }
.concierge-mic.is-listening { color: #c0392b; }
.concierge-mic.is-listening { background: #ffdada; animation: dht-pin-highlight 0.8s ease-in-out infinite; }

/* ==========================================================================
   CORRECTIF "polish" (QA finale) — Harmonisation légère des composants bouton.
   Constat : .chip/.filter-chip avaient une transition et pas les autres ;
   aucun bouton n'avait d'état :hover (souris), :active (pression tactile/clic)
   ni :focus-visible (clavier) cohérent. Résultat : certains boutons réagissaient
   au clic, d'autres non → sensation d'hétérogénéité. Ce bloc est additif,
   ne change aucune dimension ni disposition existante : risque de régression nul.
   ========================================================================== */
.control-button,
.chip,
.filter-chip,
.detail-close,
.weather-refresh,
.concierge-mic,
.map-header__link,
.map-header__carnet,
.envies-toggle {
  transition: background 0.2s ease, border-color 0.2s ease, color 0.2s ease,
              box-shadow 0.2s ease, opacity 0.2s ease, transform 0.1s ease;
} /* P6 (Phase 3B) : .concierge-toggle retiré de cette liste -- le bouton "Demander à Miguel" n'existe plus */

/* survol : uniquement sur les appareils avec un vrai pointeur, pour éviter
   un effet de survol "collé" après un tap sur mobile/tablette tactile */
@media (hover: hover) and (pointer: fine) {
  .control-button:hover,
  .chip:hover:not(.is-active):not([aria-pressed="true"]),
  .filter-chip:hover:not(.is-active),
  .detail-close:hover,
  .weather-refresh:hover:not(:disabled),
  .map-header__link:hover {
    border-color: var(--color-primary);
    box-shadow: var(--shadow-sm);
  }
  .concierge-mic:hover { box-shadow: 0 0 0 4px rgba(20, 96, 90, 0.12); }
}

/* pression : retour tactile immédiat, façon Apple/Airbnb, au clic comme au tap */
.control-button:active,
.chip:active,
.filter-chip:active,
.detail-close:active,
.weather-refresh:active:not(:disabled),
.button-mini:active,
.concierge-mic:active,
.map-header__link:active {
  transform: scale(0.96);
}

/* LOT 7 (2026-07-10) -- Finition : le même retour de pression manquait encore sur les CTA
   principaux (bouton-primary/secondary, dont "Adapter ma journée", "Voir l'itinéraire",
   "+ Ajouter à mon carnet", "Autour de moi") et sur les cartes/lignes cliquables qui ouvrent
   une fiche ou changent la proposition du jour. Même règle, même valeur (scale 0.96), pour que
   *tout* élément interactif de la carte réponde de la même façon au clic/tap -- additif, aucune
   disposition changée, cohérent avec le bloc ci-dessus (déjà non exclu par
   prefers-reduced-motion, car il s'agit d'un retour direct au geste, pas d'une animation
   décorative autonome). */
.button-primary:active,
.button-secondary:active,
.alternative-card:active,
.choix-miguel-item:active,
.around-me-suggestion:active,
.journee-etape__bouton:active {
  transform: scale(0.97);
}

/* clavier : anneau de focus visible et cohérent sur tous les contrôles,
   masqué à la souris/au tactile grâce à :focus-visible */
.control-button:focus-visible,
.chip:focus-visible,
.filter-chip:focus-visible,
.detail-close:focus-visible,
.weather-refresh:focus-visible,
.button-mini:focus-visible,
.concierge-mic:focus-visible,
.map-header__link:focus-visible,
.map-header__carnet:focus-visible,
/* LOT 4 (2026-07-10) -- Confiance : ce bloc couvrait déjà les contrôles génériques mais oubliait
   plusieurs éléments interactifs propres à la carte/au panneau -- au clavier, ils recevaient le
   focus (Tab les atteint) mais sans aucun retour visuel, ce qui est un vrai problème de confiance
   pour un usage clavier. Alignement sur le même anneau, sans rien changer visuellement à la
   souris/au tactile. */
.alternative-card:focus-visible,
.journee-etape__bouton:focus-visible,
.choix-miguel-item:focus-visible,
.around-me-suggestion:focus-visible,
.around-me-button:focus-visible,
.envies-toggle:focus-visible,
.filters-panel__reset:focus-visible,
.envies-panel__cta:focus-visible,
.pin:focus-visible,
.island-dot:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}

/* désactivé : un seul traitement visuel partagé (avant : seul .weather-refresh
   en avait un) */
.control-button:disabled,
.chip:disabled,
.filter-chip:disabled,
.button-mini:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}


/* Revue Premium : .category-results / .category-result-item supprimes -- code mort residuel de l'ancienne grille categorie (0 reference) */

/* ==========================================================================
   Prévisualisation des spots (tooltip au survol desktop / tap mobile)
   ==========================================================================
   Un seul élément réutilisé pour tous les pins (carte principale, vue archipel,
   vue île détaillée, mini-carte). Fond sombre "carnet premium" (pas une bulle HTML
   par défaut), animation fade + légère translation ~120ms, flèche qui suit le pin
   même quand la bulle est recentrée pour rester dans l'écran. */
.spot-tooltip {
  position: fixed;
  z-index: 70;
  left: 0;
  top: 0;
  max-width: 230px;
  padding: 10px 14px;
  border-radius: var(--radius-md);
  background: var(--color-primary-strong);
  color: #fff;
  font-family: var(--font-base);
  box-shadow: var(--shadow-md);
  pointer-events: none;
  opacity: 0;
  transform: translateY(4px) scale(0.97);
  transition: opacity 130ms cubic-bezier(0.2, 0, 0, 1), transform 130ms cubic-bezier(0.2, 0, 0, 1);
  will-change: opacity, transform;
}
.spot-tooltip.is-visible { opacity: 1; transform: translateY(0) scale(1); }
/* Correctif "apercu -> fiche complete" (2026-07-10) : la bulle de previsualisation etait
   purement decorative (pointer-events:none), donc jamais cliquable/tapable -- sur tactile,
   la seule facon d'ouvrir la fiche complete etait de re-toucher le pin minuscule, ce qui
   n'etait pas percu comme possible par l'utilisateur ("je vois le spot mais je dois le
   chercher ailleurs"). On active les evenements uniquement quand la bulle est visible
   (jamais quand elle est cachee en 0,0), pour ne jamais intercepter de clic ailleurs. */
.spot-tooltip.is-visible { pointer-events: auto; cursor: pointer; }
.spot-tooltip::after {
  content: "";
  position: absolute;
  left: var(--tooltip-arrow-x, 50%);
  width: 11px;
  height: 11px;
  background: inherit;
  transform: translateX(-50%) rotate(45deg);
  border-radius: 2px;
}
.spot-tooltip--above::after { bottom: -5px; }
.spot-tooltip--below::after { top: -5px; }
.spot-tooltip__title { display: flex; align-items: flex-start; gap: 6px; font-weight: 700; font-size: 0.86rem; line-height: 1.3; }
.spot-tooltip__cat { display: block; margin-top: 3px; font-size: 0.68rem; font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: rgba(255, 255, 255, 0.68); }
.spot-tooltip__badge { display: inline-flex; align-items: center; gap: 4px; margin-top: 7px; padding: 3px 9px; border-radius: var(--radius-pill); font-size: var(--map-text-2xs); font-weight: 700; }
.spot-tooltip__badge--main { background: var(--color-accent); color: #18312f; }
.spot-tooltip__badge--alt { background: rgba(255, 255, 255, 0.18); color: #fff; }
/* Correctif "apercu -> fiche complete" (2026-07-10) : ligne d'action explicite ajoutee dans
   la bulle, pour que l'invite au clic/tap soit visible sans dependre du seul curseur. */
.spot-tooltip__cta { display: block; margin-top: 7px; font-size: var(--map-text-2xs); font-weight: 700; text-decoration: underline; text-underline-offset: 2px; color: var(--color-accent); }

/* Les pins restent utilisables au clavier/tactile même avec la tooltip par-dessus */
[data-spot-id] { cursor: pointer; }

@media (prefers-reduced-motion: reduce) {
  .spot-tooltip { transition: opacity 80ms linear; transform: none !important; }
}

/* Correctif (2026-07-18) : sur tres petit ecran, le bouton .miguel-wizard__close repasse en icone
   seule (le libelle "Fermer" reste dans le DOM pour aria-label/lecteurs d'ecran, seul l'affichage
   visuel est masque) -- reduit d'autant la marge a reserver sur le titre du wizard, complement au
   correctif 132px ci-dessus qui, lui, couvre les ecrans plus larges. */
@media (max-width: 479px) {
  .miguel-wizard__close-label { display: none; }
  .miguel-wizard__panel:has(.miguel-wizard__close:not([hidden])) .miguel-wizard__title,
  .miguel-wizard__panel:has(.miguel-wizard__close:not([hidden])) .eyebrow {
    padding-right: 64px;
    /* Renfort mobile (2026-07-18) : espace supplementaire demande specifiquement sur mobile,
       au-dela du margin-bottom de base ci-dessus, pour eviter l'effet "bouton pose sur la carte"
       la ou l'espace est le plus contraint. */
    margin-bottom: var(--space-4);
  }
}
