/* DHT Azores — map CSS production build 20260823-map-layout-v1-4-7: surgical mobile/tablet map block vertical alignment. */
/* Patch A "code couleur pins" (2026-07-25, demande Antoine, palette validee) : 4 paliers de pertinence du jour, lus par carte.js (dhtNiveauPinScore(), fill="var(--pin-score-...)") sur les 3 couches de pins (Plan du Jour, points discrets, mini-carte) -- source UNIQUE de ces teintes, jamais de valeur hex dupliquee en JS. Palette volontairement distincte de --color-primary (teal, categories) et --color-accent (orange, ancien disque Miguel) : le code couleur encode la QUALITE de l'opportunite du jour, pas la categorie ni "est-ce le choix de Miguel" (ce role reste tenu par l'anneau/halo du pin principal, inchanges). */
:root {
  --pin-score-excellent: #123b5a; /* score >= 80 : "Très bonne fenêtre" -- MAJ 2026-07-25 (retour Antoine "contraste encore faible avec le turquoise") : bleu plus profond/premium. Etait #1d4d73. */
  --pin-score-good: #63b7a6;      /* score 60-79 : "Bon choix" -- MAJ 2026-07-25 (retour Antoine "trop proche du bleu profond") : turquoise, pour une lecture instantanee sans legende (bleu fonce = tres confiant / turquoise = bonne opportunite / ambre = compromis / gris = faible). Etait #4a90c2. */
  --pin-score-medium: #d6a24a;    /* score 35-59 : "Possible mais compromis" */
  --pin-score-low: #8e9a9a;       /* score < 35 : "Faible opportunité" */
}
: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 { isolation: isolate; 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; }
/* Correctif responsive header mobile (31/07/2026, demande Antoine suite a capture iPhone -- le
   libelle EN "Notebook" plus long que le FR "Carnet" faisait chevaucher le logo) : .map-brand
   reprend EXACTEMENT la meme doctrine que .site-brand (style.css, header des pages marketing,
   deja valide sur mobile) -- le mot-symbole "DHT Azores" reste TOUJOURS visible sur une seule
   ligne (flex-shrink:0, white-space:nowrap herite par son <span>), jamais tronque ni rejete sur 2
   lignes. C'est .map-header__actions (Carnet/Notebook, Accueil/Home, langue) qui absorbe la
   contrainte d'espace -- voir min-width:0 ci-dessous et le media query 480px plus bas, qui masque
   UNIQUEMENT le libelle textuel du bouton Carnet (icone + compteur restent visibles, et le bouton
   garde un aria-label traduit -- voir carte.html), exactement comme .control-button__label le
   fait deja pour "Autour de moi" sur .map-controls. Correction structurelle valable pour
   N'IMPORTE QUEL libelle plus long dans n'importe quelle langue, pas un patch cible sur
   "Notebook". */
.map-brand { gap: var(--space-2); flex-shrink: 0; white-space: nowrap; min-width: 0; }
.map-brand img { width: 44px; height: auto; flex-shrink: 0; }
.map-header__link { min-height: 40px; padding-inline: var(--space-3); border-radius: var(--radius-pill); background: var(--color-surface); font-size: 0.875rem; white-space: nowrap; flex-shrink: 0; }
.map-header__actions { min-width: 0; }
.map-header__carnet { min-width: 0; }
@media (max-width: 480px) {
  .map-header { gap: var(--space-2); padding-inline: var(--space-3); }
  .map-header__actions { gap: var(--space-1, 0.25rem); }
  .map-header__carnet-label { position: absolute; width: 1px; height: 1px; overflow: hidden; clip-path: inset(50%); white-space: nowrap; }
  .map-header__carnet { gap: 4px; padding-inline: var(--space-2, 0.5rem); }
  .map-header__link { padding-inline: var(--space-2, 0.5rem); font-size: 0.8rem; }
}
/* Palier telephone etroit (iPhone SE 375px et en-dessous, meme palier que style.css/.site-header
   pour la coherence du site) : resserrage supplementaire, la marque et les 3 actions restent
   toutes visibles et cliquables sans chevauchement, quelle que soit la langue active. */
@media (max-width: 400px) {
  .map-brand img { width: 32px; }
  .map-brand span { font-size: 0.85rem; }
  .map-header__link { min-height: 36px; }
  .map-header__carnet { padding-inline: var(--space-1, 0.25rem); }
}
.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: var(--color-accent); 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. */
/* Phase A.1 "la bulle Suggestion Miguel(TM) doit suivre la couleur du pin" (2026-07-25, demande
   Antoine) : remplace le fond/contour orange fixe ci-dessus UNIQUEMENT quand une classe de niveau
   est presente (voir dhtPrepareLabelSpot()/finaliserLabelsSpots(), carte.js) -- le texte du kicker
   ("Suggestion Miguel(TM)") et sa couleur restent INCHANGES (choix explicite Antoine : garder le
   statut, changer seulement la bordure/le fond). Regles rangees dans le meme ordre que les paliers
   dhtNiveauPinScore() (carte.js) et les tokens --pin-score-* (Patch A, plus haut dans ce fichier).
   Specificite (2 classes : .spot-label--plan + .spot-label--niveau-*) volontairement superieure a
   la regle generique juste au-dessus, pour l'emporter sans !important. */
.spot-label--plan.spot-label--niveau-excellent .spot-label__chip { fill: rgba(18, 59, 90, 0.10); stroke: rgba(18, 59, 90, 0.45); } /* MAJ 2026-07-25 : alignee sur le nouveau --pin-score-excellent (etait rgba(29, 77, 115, ...)). */
.spot-label--plan.spot-label--niveau-bon .spot-label__chip { fill: rgba(99, 183, 166, 0.12); stroke: rgba(99, 183, 166, 0.45); } /* MAJ 2026-07-25 : teinte alignee sur le nouveau --pin-score-good turquoise (etait rgba(74, 144, 194, ...), bleu). */
.spot-label--plan.spot-label--niveau-compromis .spot-label__chip { fill: rgba(214, 162, 74, 0.14); stroke: rgba(214, 162, 74, 0.45); }
.spot-label--plan.spot-label--niveau-faible .spot-label__chip { fill: rgba(142, 154, 154, 0.14); stroke: rgba(142, 154, 154, 0.45); }
.spot-label--niveau-excellent .spot-label__accent--plan { fill: var(--pin-score-excellent); opacity: 0.78; }
.spot-label--niveau-bon .spot-label__accent--plan { fill: var(--pin-score-good); opacity: 0.78; }
.spot-label--niveau-compromis .spot-label__accent--plan { fill: var(--pin-score-medium); opacity: 0.78; }
.spot-label--niveau-faible .spot-label__accent--plan { fill: var(--pin-score-low); opacity: 0.78; }
.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); }
/* Patch C1 "légende contextuelle des couleurs" (2026-07-25, demande Antoine) : bouton discret
   dans les CONTRÔLES CARTE (.map-controls, superposés à la carte elle-même) -- volontairement
   PAS dans "Explorer librement" (Filtres/Mini-carte, qui vivent dans le panneau assistant, pas
   sur la carte). Icône seule (symbole "ⓘ", U+24D8), sans libellé texte, pour rester compact dans
   une barre déjà occupée par le sélecteur d'île + "Autour de moi" -- aria-label explicite
   compense l'absence de texte visible pour l'accessibilité. */
.control-button--icon-only { flex: 0 0 auto; width: 48px; padding-inline: 0; font-size: 1.1rem; line-height: 1; display: flex; align-items: center; justify-content: center; }
/* Passe "Carte des conditions maintenant" (2026-08-16) : simple état visuel du bouton ; aucune logique de score dans le CSS. */
.conditions-maintenant-button.is-active { background: var(--color-primary); border-color: var(--color-primary); color: #fff; box-shadow: var(--shadow-sm); }
@media (min-width: 480px) { .conditions-maintenant-button { width: auto; min-width: max-content; padding-inline: var(--space-4); gap: 6px; white-space: nowrap; } }
.conditions-maintenant-button.is-active:hover, .conditions-maintenant-button.is-active:focus-visible { background: var(--color-primary-strong, var(--color-primary)); }
.conditions-maintenant-layer { pointer-events: none; }
.conditions-maintenant-point { pointer-events: auto; cursor: pointer; outline: none; }
.conditions-maintenant-point__halo { fill: currentColor; opacity: 0.16; }
.conditions-maintenant-point__disque { fill: currentColor; stroke: #fff; stroke-width: 1.5; vector-effect: non-scaling-stroke; }
.conditions-maintenant-point--excellent { color: var(--pin-score-excellent); }
.conditions-maintenant-point--bon { color: var(--pin-score-good); }
.conditions-maintenant-point--compromis { color: var(--pin-score-medium); }
.conditions-maintenant-point--faible { color: var(--pin-score-low); }
.conditions-maintenant-point--indisponible { color: #a7aeac; }
.conditions-maintenant-point:focus-visible .conditions-maintenant-point__halo { opacity: 0.34; stroke: var(--color-primary); stroke-width: 2; }
/* CONTRAT-technique-geolocalisation-carte.md : variante compacte du bouton existant, reservee au
   bandeau de geolocalisation (bouton "Detecter mon ile"), pas de nouveau style cree de toutes pieces. */
.control-button--compact { min-height: 36px; padding-inline: var(--space-3); font-size: 0.85rem; flex: 0 0 auto; }
/* Correctif (27/07/2026, retour Antoine sur capture iPhone) : bandeau initialement pose en flux
   normal (aucun "position"), alors qu'il est un sibling direct de .map-controls et .legende-popover
   dans .map-stage -- lesquels sont TOUS LES DEUX en position:absolute (carte flottante). Un element
   en flux normal se rend au meme endroit (haut de .map-stage) que les elements absolus, d'ou le
   chevauchement visuel exact constate (texte du bandeau superpose au selecteur d'ile, bouton
   deborde). Correctif : meme traitement que .legende-popover (cf. juste plus bas dans ce fichier,
   meme commentaire "jamais superpose aux controles eux-memes") -- ancre en absolu, juste sous
   .map-controls, avec les memes marges gauche/droite qu'elle (voir aussi le media query 480px+
   plus bas, qui aligne les deux sur les memes valeurs --space-5). Passage de border-radius pill a
   radius-lg : un bandeau qui peut passer sur 2 lignes (texte + bouton) sur petit ecran n'a plus une
   forme de pilule coherente, contrairement a un badge court sur une seule ligne. */
.geoloc-banner { position: absolute; top: calc(var(--space-3) + 56px); left: var(--space-3); right: var(--space-3); z-index: 9; display: flex; align-items: center; gap: var(--space-3); flex-wrap: wrap; padding: var(--space-2) var(--space-3); border-radius: var(--radius-lg); background: rgba(255, 255, 255, 0.92); border: 1px solid var(--color-border); font-size: 0.9rem; box-shadow: 0 1px 4px rgba(24, 49, 47, 0.1); }
/* CONTRAT-technique-carte-mobile-finition-ux.md, Patch 3.1 (27/07/2026, retour Antoine sur audit
   "tap spots apres zoom") : ce bandeau ne bloque plus les taps destines a la carte en dessous --
   seul son bouton (interaction reelle) reste cliquable. Bonne pratique standard pour tout overlay
   informatif au-dessus d'une zone interactive. */
.geoloc-banner { pointer-events: none; }
.geoloc-banner button { pointer-events: auto; }
.geoloc-banner[hidden] { display: none; }
.geoloc-banner span { flex: 1 1 200px; min-width: 0; }
/* Mise en avant temporaire du selecteur d'ile manuel (Cas 2 : position hors Acores) -- jamais bloquant,
   jamais desactivant, disparait automatiquement (voir DHTUI.mettreEnEvidenceSelecteurIle()). */
.control-select--focus-suggestion { box-shadow: 0 0 0 3px rgba(24, 49, 47, 0.35), var(--shadow-sm); }
/* Patch C1 : popover flottant, PAS une légende permanente -- caché par défaut (hidden), ouvert/
   fermé uniquement par clic sur data-legende-button (voir carte.js, DHTInteractions.init()).
   Ancré en absolu dans .map-stage (position: relative, cf. règle plus haut dans ce fichier),
   juste sous .map-controls, jamais superposé aux contrôles eux-mêmes. */
.legende-popover { position: absolute; top: calc(var(--space-3) + 56px); right: var(--space-3); z-index: 11; max-width: min(300px, calc(100% - 2 * var(--space-3))); background: rgba(255, 255, 255, 0.97); border: 1px solid var(--color-border); border-radius: var(--radius-lg); box-shadow: var(--shadow-md); padding: var(--space-4); }
.legende-popover__close { position: absolute; top: var(--space-2); right: var(--space-2); border: none; background: transparent; color: var(--color-text-muted); padding: 4px; border-radius: 50%; cursor: pointer; display: flex; }
.legende-popover__close:hover, .legende-popover__close:focus-visible { background: rgba(15, 95, 92, 0.08); }
.legende-popover__title { margin: 0 var(--space-5) var(--space-2) 0; font-size: 0.95rem; font-weight: 700; color: var(--color-text); }
.legende-popover__text { margin: 0 0 var(--space-3); font-size: 0.85rem; color: var(--color-text-muted); line-height: 1.4; }
.legende-popover__list { margin: 0 0 var(--space-3); padding: 0; list-style: none; display: flex; flex-direction: column; gap: 6px; font-size: 0.85rem; color: var(--color-text); }
.legende-popover__list li { display: flex; align-items: center; gap: 8px; }
.legende-popover__dot { width: 10px; height: 10px; border-radius: 50%; flex: 0 0 auto; display: inline-block; }
.legende-popover__dot--excellent { background: var(--pin-score-excellent); }
.legende-popover__dot--bon { background: var(--pin-score-good); }
.legende-popover__dot--compromis { background: var(--pin-score-medium); }
.legende-popover__dot--faible { background: var(--pin-score-low); }
.conditions-maintenant-legend { right: var(--space-3); left: auto; }
.legende-popover__dot--indisponible { background: #a7aeac; }
@media (max-width: 767px) { .conditions-maintenant-legend { right: var(--space-3); left: var(--space-3); max-width: none; } }
.legende-popover__footnote { margin: 0; font-size: 0.78rem; color: var(--color-text-muted); font-style: italic; line-height: 1.35; }
/* 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; }
/* CONTRAT-technique-carte-mobile-finition-ux.md, Patch 3.3 (27/07/2026) : padding-top exprime via
   --map-top-safe-area (defaut 80px, valeur historique du correctif P2 du 24/07, calibree pour
   .map-controls seul) plutot qu'une valeur figee -- systeme extensible : .map-viewport--banner-visible
   (posee/retiree par DHTUI.actualiserEspaceCartePourBandeau()) l'augmente le temps que le bandeau
   geoloc est reellement affiche, pour ne plus jamais chevaucher visuellement le haut de la carte. */
.map-viewport { display: flex; width: 100%; height: 100%; align-items: center; justify-content: center; padding: var(--map-top-safe-area, 80px) 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); }
/* V1.4.7 — restauration chirurgicale du positionnement validé : le bloc .map-stage entier
   revient à sa position de flux sur mobile/tablette. Aucun décalage secondaire n'est appliqué
   au SVG, aux bulles/labels ou aux overlays : tous restent solidaires des contrôles de la carte. */
.map-viewport--banner-visible { --map-top-safe-area: 132px; } /* Correctif P2 (2026-07-24, audit mobile) : 112px de padding-top etait largement superieur a ce que necessite .map-controls (barre ile + "Autour de moi", ~56px de hauteur utile incluant son offset top:12px) -- reduit a 80px, ce qui laisse encore ~24px de respiration sous les controles tout en rendant a l'archipel une bonne partie de l'espace vertical mort constate sur mobile. Aucun changement sur le padding-bottom (formule de synchronisation carte/panneau deja finement calibree, cf. LOT Drag synchronise ci-dessous -- non touchee pour ne pas re-introduire de regression sur le drag). */ /* 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); }
/* CONTRAT-technique-carte-mobile-finition-ux.md, Patch 3.2 (27/07/2026) : pastille meteo purement
   informative (texte seul, verifie dans carte.html -- aucun bouton), ne doit pas intercepter les
   taps vers la carte lorsqu'un spot se retrouve dans sa zone apres un zoom/pan. */
/* BUG-MIGUEL-STATUS-OVERLAP-01 — correction V1.4 (2026-08-20) :
   contrat historique conserve pour l'etat replie : .map-status reste exactement ancre sur
   --sheet-height + --space-3, comme dans la base comparee sans regression.
   Lorsque le bottom-sheet est reellement .is-expanded, la bulle suit la hauteur expanded.
   Le selecteur cible uniquement le panneau direct de #map-app et reste strictement mobile.
   Aucun JS, moteur Miguel™, scoring, carte ou contenu n'est modifie. */
@media (max-width: 767px) {
  .map-app:has(> .assistant-panel.is-expanded) .map-status {
    bottom: calc(var(--sheet-height-expanded) + var(--space-3));
  }
}
.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 P1 (2026-07-24, audit direction artistique) : CAUSE DU "panneau vide" au chargement --
   .assistant-panel etait visible des le premier rendu synchrone (DHTUI.render() au DOMContentLoaded),
   avant que la meteo (DHT_WX) n'ait fini de charger, donnant l'impression d'un composant casse/qui
   attend. Correctif purement visuel/sequencement : le panneau reste invisible et non interactif
   (opacity/pointer-events) jusqu'a ce que carte.js lui ajoute .is-ready -- exclusivement une fois
   qu'une reponse (recommandation ou message de repli gracieux) est reellement disponible. Aucune
   ligne du moteur de decision (calculerScoreSpot, dhtGenererDeuxJournees, etc.) n'est modifiee : le
   premier rendu de la carte/des iles n'est ni retarde ni cache, seul ce tiroir/cette colonne l'est. */
.assistant-panel { opacity: 0; transform: translateY(24px); pointer-events: none; }
.assistant-panel.is-ready { opacity: 1; transform: translateY(0); pointer-events: auto; transition: opacity 320ms cubic-bezier(0.2, 0, 0, 1), transform 320ms cubic-bezier(0.2, 0, 0, 1), height 220ms cubic-bezier(0.2, 0, 0, 1); }
@media (prefers-reduced-motion: reduce) { .assistant-panel { transition: none; } .assistant-panel.is-ready { transition: none; } } /* 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; touch-action: pan-y; overscroll-behavior-y: contain; 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); }
/* CONTRAT-technique-carte-mobile-finition-ux.md, Patch 1 (27/07/2026) : etat "pre-choix" du tiroir
   mobile, actif UNIQUEMENT tant qu'aucun choix d'ile (manuel ou GPS) n'a ete fait --
   DHTUI.appliquerEtatPreChoixPanneau() pose cette classe selon DHTState.hasChosenIsland (jamais
   DHTState.island seul, pour ne jamais reapparaitre apres un retour a "Toutes les iles"). Hauteur
   reduite au strict minimum (poignee + titre court) pour que l'archipel soit visible des l'arrivee,
   plutot que le contenu reel (meteo/plan du jour/boutons) simplement rogne par overflow:hidden comme
   c'etait le cas auparavant. Scope volontairement limite au mobile (<768px) : desktop/tablette
   (.assistant-panel devient une carte flottante ou une colonne pleine hauteur, jamais un tiroir
   replie) ne sont pas concernes par ce mode. */
@media (max-width: 767px) {
  .assistant-panel--pre-choix { height: 56px; }
  /* .is-expanded l'emporte toujours si les 2 classes sont presentes (specificite 2 classes > 1
     classe) -- garde-fou explicite du contrat : le geste de glissement manuel (poignee) reste
     possible meme sans choix d'ile, et revele alors le contenu reel existant (aucun etat bloque). */
  .assistant-panel--pre-choix.is-expanded { height: var(--sheet-height-expanded); }
  .assistant-panel--pre-choix:not(.is-expanded) .sheet-header,
  .assistant-panel--pre-choix:not(.is-expanded) .sheet-content { display: none; }
  .sheet-compact-title { display: none; margin: 0; padding: 0 var(--dht-panel-pad-x) var(--space-2); font-weight: 700; color: var(--color-text); text-align: center; }
/* Micro-correctif (27/07/2026, audit tactile) : cet element est desormais reellement cliquable
   (voir carte.js, setupPanelDrag()) -- affordance visuelle + suppression du delai de tap ~300ms
   sur mobile (comportement identique a .assistant-panel__handle, deja en touch-action: none pour
   son propre usage de glissement ; ici manipulation suffit, aucun glissement attendu sur ce texte). */
.assistant-panel--pre-choix:not(.is-expanded) .sheet-compact-title { cursor: pointer; touch-action: manipulation; }
  .assistant-panel--pre-choix:not(.is-expanded) .sheet-compact-title { display: block; }
}
.assistant-panel__handle { position: relative; 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. position:relative ajouté ci-dessus (lot "poignée panneau", 2026-07-27) uniquement pour positionner le chevron ci-dessous : n'affecte ni la taille, ni le padding, ni la zone tactile déjà corrigée. */ .assistant-panel.is-dragging { transition: none; }
/* Lot "poignée panneau Miguel™" (2026-07-27) : chevron purement visuel, affordance d'ouverture/fermeture
   du tiroir. Volontairement pointer-events:none -- le geste (tap ou glissement) reste porté par toute
   la surface de .assistant-panel__handle, déjà corrigée (P1), jamais par le chevron seul. Une unique
   icône "chevron-up" (voir DHTIcons.js) tournée à 180deg selon .is-expanded, plutôt que deux icônes
   à basculer : plus simple, un seul point de vérité visuel. */
.assistant-panel__chevron { position: absolute; top: 50%; right: 20px; transform: translateY(-50%); color: var(--color-text-muted); pointer-events: none; transition: transform 0.2s ease; }
/* Correctif (2026-07-27, audit terrain confirme par Antoine) : deux causes cumulees rendaient le
   chevron totalement invisible malgre une resolution DHTIcons correcte --
   1) right:14px placait le chevron dans la zone de clipping du coin haut-droit de
      .assistant-panel (border-radius:28px + overflow:hidden, carte.css ~L422) : passe a
      right:20px, largement hors de ce rayon de 28px, quelle que soit la largeur d'ecran (la
      media query 480px+ qui ajustait finement ce decalage est donc retiree, devenue inutile) ;
   2) width/height:14px etaient definis sur .assistant-panel__chevron seul (specificite egale a
      [data-dht-icon-temp], filet de securite icones du 2026-07-20, carte.css ~L1159) : a
      specificite egale, la regle la plus tardive dans le fichier l'emportait (1.05em au lieu de
      14px). Corrige ci-dessous par une regle STRICTEMENT PLUS SPECIFIQUE
      (.assistant-panel__handle .assistant-panel__chevron), qui bat [data-dht-icon-temp] par la
      specificite (deux classes contre un attribut) et non par une regle plus tardive ou un
      !important -- le filet de securite global reste intact et inchange pour toutes les autres
      icones du site. */
.assistant-panel__handle .assistant-panel__chevron { width: 14px; height: 14px; }
.assistant-panel.is-expanded .assistant-panel__chevron { transform: translateY(-50%) rotate(180deg); }
.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. */
/* Phase 2A.1 (2026-07-22) -- Carte Miguel(TM) premium (Option 1, validee Antoine) : la carte de
   decision du jour devient l'objet visuel principal du panneau -- CSS pur, aucun changement de
   DOM/JS, uniquement des tokens deja en place (--radius-xl, --shadow-md, --color-accent) portes
   a une intensite superieure. Le trait d'accent en haut de carte est la SEULE utilisation de
   l'orange ici (signature Miguel(TM) ponctuelle, jamais un fond orange -- regle Phase 1). */
/* Phase 2B-4 (2026-07-22) -- CORRECTIF chevauchement photo/titre (regression Phase 2B-1).
   L'ancienne technique de "bleed" en marges negatives sur .miguel-hero__media (pour faire deborder
   la photo jusqu'aux bords de .plan-card--hero) etait fragile et provoquait un chevauchement visuel
   avec le titre/contenu qui suit. Nouvelle structure, plus robuste : .plan-card--hero n'a plus AUCUN
   padding propre (juste le cadre visuel : bordure, radius, ombre, overflow:hidden) ; la photo occupe
   naturellement tout le haut de la carte sans marge negative ; tout le texte (titre/badge/
   explication/timeline/CTA) vit dans un nouveau conteneur .miguel-hero__content qui porte SEUL le
   padding et le fond degrade. Structure DOM correspondante dans carte.html (voir commentaire
   Phase 2B-4 associe) ; aucun data-*/id/classe fonctionnelle existant n'a change, uniquement un
   wrapper de presentation ajoute -- carte.js n'a besoin d'aucune modification. */
/* Phase 3A-bis (2026-07-23, demande Antoine -- "carnet de voyage premium, pas tableau de
   resultats") : .plan-card--hero vivait deja a l'interieur de .assistant-panel (le "tiroir"
   mobile/colonne desktop, deja son propre cadre arrondi + ombre, voir .assistant-panel plus
   haut) -- lui donner EN PLUS sa propre bordure/ombre/dégradé créait une carte dans la carte,
   exactement l'effet "dashboard" a faire disparaitre. Retire : bordure, ombre, degrade et
   trait d'accent orange. Le contenu se pose directement sur le fond du panneau, comme une
   page de carnet plutot qu'une vignette. border-radius/overflow conserves (ne clippent plus
   aucune photo -- l'ancien hero photo unique est retire depuis la 2C-1 quinquies -- mais
   restent sans risque au cas ou un futur bloc les reutiliserait). */
.plan-card--hero { padding: 0; border: 0; border-radius: var(--radius-xl); box-shadow: none; overflow: hidden; background: none; }
.miguel-hero__content { padding: var(--space-5, 2.5rem); border-top: 0; background: none; }

/* Phase 2C-1 bis (2026-07-22, recalibrage narratif complet -- retour Antoine, refs Komoot /
   Polarsteps / Roadtrippers) : ABANDON complet du mecanisme "photo + texte en overlay" des
   Phases 2C-1/2C-2/correctif du 2026-07-22 (c'etait la cause du bug de chevauchement constate en
   capture, et surtout ca donnait un rendu "banniere marketing" plutot qu'une vraie photo de
   voyage). Nouvelle regle simple : la photo (.miguel-hero__media) reste TOUJOURS propre, sans
   aucun texte ni degrade dessus. .miguel-hero__heading (badge + lieu + titre + accroche) vit
   TOUJOURS dans .miguel-hero__content, sous la photo -- plus jamais deplace en JS (voir
   carte.js : le bloc insertBefore/classList de la 2C-1 est entierement retire, pas seulement
   corrige). Rendu uniquement, aucun changement moteur/scoring/meteo/confiance. */
.miguel-hero__heading { margin: 0 0 var(--space-3, 1.5rem); }
/* Hierarchie voulue : badge (petit sceau) -> lieu (kicker discret, l'ancre reelle du jour) ->
   h1 (le "nom de la journee", la decision Miguel -- element le plus visible du bloc) -> accroche
   (la phrase humaine de recommandation, ambiance conversationnelle plutot que rapport). */
.miguel-hero__heading .plan-card__badge { margin: 0 0 var(--space-3, 1.5rem); }
.miguel-hero__lieu { margin: 0 0 0.35rem; font-size: 0.78rem; font-weight: 600; letter-spacing: 0.06em; text-transform: uppercase; color: var(--color-text-muted); }
/* Phase 3A-bis (2026-07-23, demande Antoine -- "le titre editorial doit devenir l'element
   emotionnel principal") : agrandi (1.65rem -> 1.85rem, encore plus en desktop ci-dessous)
   pour rester l'ancre visuelle n°1 de l'ecran, maintenant que le titre lui-meme est un vrai
   titre editorial (voir dhtNommerJourneeEditorial(), carte.js) et non plus une categorie. */
.miguel-hero__heading h1 { margin: 0; font-size: 1.85rem; line-height: 1.2; }
@media (min-width: 1024px) and (pointer: fine), (min-width: 768px) and (pointer: coarse) and (any-hover: none) and (max-aspect-ratio: 8/5) { .miguel-hero__heading h1 { font-size: 2.05rem; } } /* Convergence mode tablette (01/08/2026) : regle desktop etendue telle quelle (aucune valeur modifiee), cf. RAPPORT-livraison-mode-tablette. */
.miguel-hero__accroche { margin: 0.6rem 0 0; max-width: 48ch; font-size: 1.05rem; font-weight: 400; font-style: italic; line-height: 1.55; color: var(--color-text); }
.miguel-hero__accroche:empty { display: none; }
/* Resume en "chips" (Phase 2C-1 bis, retour Antoine : "ligne dashboard" -> puces a la maniere
   Komoot/Roadtrippers -- distance/duree/difficulte affichees comme des badges, pas une phrase
   technique jointe par des "•"). Memes 3 informations qu'avant (nb etapes / phase / confiance
   courte), voir carte.js -- seule la structure DOM et le style changent. */
/* Phase 2C-1 ter (2026-07-22, retour Antoine valide) : retour a une simple ligne de metadonnees
   ("4 étapes · Journée complète · Confiance élevée", separateur median, aucun fond/pastille) --
   registre Komoot, pour ne plus se confondre visuellement avec les tags de profil utilisateur
   (.plan-card__profil-chip, seule vraie "chip" coloree restante sur l'ecran). */
.miguel-hero__summary { margin: var(--space-4, 2rem) 0 0; font-size: 0.9rem; font-weight: 600; color: var(--color-text-muted); }
/* Phase 2C-1 ter : "Le parcours" reutilise directement .main-recommendation h2 (deja stylee un peu
   plus bas dans ce fichier) -- classe ajoutee uniquement pour un accroche CSS explicite/futur. */
.miguel-hero__section-title { }
/* CTA hero (Phase 2C-1) : deux actions cote a cote (primaire plein, secondaire discret), au lieu
   d'un unique lien -- clarte d'action demandee (repere Roadtrippers). Reutilise entierement
   .miguel-hero__cta existant pour le style de base, la variante secondaire ne fait qu'attenuer
   fond/couleur, aucune nouvelle action creee (voir carte.js : data-open-detail deja existant pour
   le primaire, DHTUI.changerJourneeAvecTransition() deja existant pour le secondaire). */
/* Phase 2C-1 quater (2026-07-22, retour Antoine) : le CTA primaire reste compact (jamais
   pleine largeur -- flex-start l'empeche de s'etirer meme si le conteneur est en colonne sur
   mobile), le secondaire n'est plus un bouton du tout : simple lien texte souligne, sans
   fond/bordure/pilule, pour ne jamais rivaliser visuellement avec le lieu recommande. */
.miguel-hero__actions { display: flex; flex-direction: column; align-items: flex-start; gap: 0.6rem; margin-top: var(--space-4, 2rem); }
.miguel-hero__cta--primaire { align-self: flex-start; }
/* Phase 2C-1 quinquies (2026-07-22, retour Antoine -- "assistant qui decide, pas comparateur") :
   .miguel-hero__cta--secondaire est retiree (plus aucun bouton a cote du primaire -- carte.js ne
   genere plus ce bouton). L'unique acces a l'autre journee est desormais .alternative-lien,
   tout en bas de la carte (voir plus loin dans ce fichier). */
/* Phase 2C-1 bis : le parcours (timeline + CTA) remonte juste apres le resume -- l'utilisateur
   voit "ou aller" avant les preuves meteo detaillees (voir .miguel-hero__explication plus bas,
   repositionne APRES dans le DOM -- carte.html). */
.main-recommendation { min-width: 0; margin-top: var(--space-4, 2rem); padding-top: var(--space-4, 2rem); border-top: 1px solid var(--color-border); background: none; box-shadow: none; }
.main-recommendation h2 { margin-bottom: var(--space-3, 1.5rem); font-size: 1.1rem; font-weight: 600; color: var(--color-text); } .main-recommendation p { margin-bottom: var(--space-4, 2rem); color: var(--color-text-muted); }

/* Phase 2C-1 quinquies (2026-07-22, retour Antoine -- "la photo doit illustrer chaque etape, pas
   la journee") : l'ancienne photo hero unique (.miguel-hero__media, liee a la 1ere etape
   seulement) est retiree. Remplacee par une photo PAR ETAPE dans la timeline -- voir
   .journee-etape__media ci-dessous, pres des regles .journee-etape existantes. */

/* Photo par etape (timeline) -- 3 variantes cote affichage, jamais de photo inventee :
   - .journee-etape__media--grande : la SEULE etape mise en avant par Miguel (score le plus eleve
     parmi les etapes affichees, calcule cote rendu dans carte.js, aucun changement moteur) ;
     pleine largeur, ratio immersif, jamais de texte dessus (meme regle que l'ancien hero).
   - .journee-etape__media--petite : vignette carree, a cote du texte, pour les autres etapes
     ayant une photo editoriale verifiee.
   - Etape sans photo verifiee : aucun bloc media genere par carte.js -- ligne texte seule,
     inchangee par rapport a avant ce lot. */
.journee-etape__ligne { align-items: flex-start; }
.journee-etape__corps { display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2); flex: 1 1 auto; min-width: 0; }
.journee-etape__media { position: relative; display: block; flex-shrink: 0; overflow: hidden; border-radius: var(--radius-md, 0.5rem); background: var(--color-primary-soft); }
.journee-etape__media img { width: 100%; height: 100%; object-fit: contain; object-position: center; display: block; }
.journee-etape__media--petite { width: 56px; height: 56px; }
.journee-etape--moment-fort .journee-etape__ligne { flex-direction: column; align-items: stretch; gap: 0; padding-bottom: var(--space-4); }
.journee-etape__media--grande { width: 100%; aspect-ratio: 16 / 9; border-radius: var(--radius-md, 0.5rem); }
.journee-etape--moment-fort .journee-etape__contenu { width: 100%; }
.journee-etape--moment-fort .journee-etape__corps { padding: var(--space-3) 0 0; }
/* Correctif (2026-07-22, retour Antoine -- "le probleme majeur c'est la taille de la photo, on
   ne voit que ca") : l'ancien ratio portrait 4/5 sur desktop (>=1024px) datait d'un panneau etroit
   (420-460px), pour compenser le manque de largeur par un effet vertical immersif. Depuis
   l'elargissement du panneau (460-760px, meme jour), ce meme ratio applique a une colonne
   beaucoup plus large produisait une photo demesuree (jusqu'a ~950px de haut a 760px de large),
   qui masquait tout le reste de la carte a l'ouverture. Retire : le desktop conserve desormais le
   ratio 16/9 de base (comme mobile), plus adapte a une colonne large, et un plafond de hauteur
   viewport est ajoute pour eviter toute domination de l'ecran quelle que soit la largeur. */
@media (min-width: 1024px) and (pointer: fine), (min-width: 768px) and (pointer: coarse) and (any-hover: none) and (max-aspect-ratio: 8/5) { .journee-etape__media--grande { max-height: 46vh; } } /* Convergence mode tablette (01/08/2026) : regle desktop etendue telle quelle. */
@media (max-width: 767px) { .journee-etape__media--grande { max-height: 32vh; } }
/* .journee-etape__credit remplace le 2026-07-24 par le composant partage .media-credit-btn/.media-credit-tip (voir plus bas) -- plus jamais visible en permanence, demande Antoine. */
/* Jamais de credit visible sur mobile (meme regle que l'ancien hero photo -- pas de vrai
   :hover tactile, risque de pseudo-etat "colle"). */

/* Photo editoriale de la fiche spot (2026-07-24, chantier photo) : meme resolution/qualite que
   la photo par etape ci-dessus (resoudrePhotoEditorialeSpot()), place directement sous le
   titre -- si aucune photo verifiee n'existe pour ce spot, [data-detail-media] reste hidden et
   la fiche s'affiche exactement comme avant ce lot (aucune photo inventee). */
.detail-media { position: relative; display: block; width: 100%; aspect-ratio: 16 / 9; overflow: hidden; border-radius: var(--radius-md, 0.5rem); background: var(--color-primary-soft); margin: var(--space-2, 1rem) 0; }
.detail-media img { width: 100%; height: 100%; object-fit: cover; display: block; }
@media (min-width: 1024px) and (pointer: fine), (min-width: 768px) and (pointer: coarse) and (any-hover: none) and (max-aspect-ratio: 8/5) { .detail-media { max-height: 46vh; } } /* Convergence mode tablette (01/08/2026) : regle desktop etendue telle quelle. */
@media (max-width: 767px) { .detail-media { max-height: 32vh; } }
@media (min-width: 768px) and (max-width: 1024px) {
  .detail-media { max-width: 180px; max-height: 120px; margin-inline: auto; }
}
/* Credit photo discret (2026-07-24, demande Antoine -- "en desktop je ne veux pas voir
   l'affichage du credit sur les photos") : composant PARTAGE par la fiche spot (.detail-media)
   et le Plan du Jour (.journee-etape__media--grande). Le texte de credit n'est plus jamais
   visible en permanence, ni desktop ni mobile -- seulement au survol (:hover, desktop) ou au
   tap (.is-open, gere par le listener delegue dans carte.js) sur la petite icone "i". L'attribution
   (obligatoire pour les photos CC BY/CC BY-SA du catalogue, cf. editorial-media.js) reste donc
   presente et accessible (aria-label sur le bouton pour les lecteurs d'ecran), sans jamais
   alourdir visuellement la photo. */
.media-credit-btn { position: absolute; right: 0.5rem; bottom: 0.5rem; z-index: 2; width: 1.4rem; height: 1.4rem; padding: 0; border: none; border-radius: 50%; background: rgba(15, 20, 20, 0.55); color: #fff; font-family: Georgia, "Times New Roman", serif; font-style: italic; font-size: 0.75rem; line-height: 1; display: flex; align-items: center; justify-content: center; cursor: pointer; }
/* Correctif zone tactile (2026-07-25, demande Antoine, "le (i) ne reagit pas au tap mobile") :
   le disque visible fait 1.4rem (22.4px), sous le minimum recommande pour le tactile (44px Apple
   HIG / 48px Material) -- explique un clic souris precis qui fonctionne toujours, un tap au doigt
   qui rate frequemment sa cible, tout en bord de photo. Correctif : zone de tap INVISIBLE
   elargie via ::before (aucune peinture, juste une boite plus grande), le disque visible ne
   change pas d'un pixel -- "aucun bruit visuel" respecte. */
.media-credit-btn::before { content: ""; position: absolute; inset: -11px; }
.media-credit-btn:hover, .media-credit-btn:focus-visible { background: rgba(15, 20, 20, 0.8); }
.media-credit-tip { position: absolute; right: 0.5rem; bottom: 2.1rem; z-index: 3; max-width: 78%; margin: 0; padding: 0.3rem 0.6rem; border-radius: var(--radius-md, 0.4rem); background: rgba(15, 20, 20, 0.85); color: #fff; font-size: 0.7rem; line-height: 1.3; opacity: 0; pointer-events: none; transition: opacity 0.15s ease; }
.media-credit-btn:hover + .media-credit-tip, .media-credit-btn:focus-visible + .media-credit-tip, .media-credit-tip.is-open { opacity: 1; pointer-events: auto; }
@media (prefers-reduced-motion: reduce) { .media-credit-tip { transition: none; } }

/* Phase 2B-1 -- decision (badge), deja existant (.plan-card__badge), simplement mis en valeur
   davantage puisqu'il porte maintenant seul le role de "sceau" (les classes fantomes
   .miguel-card__header/.miguel-choice-badge sont abandonnees, elles n'etaient jamais rendues). */
/* Phase 2C-1 quater (2026-07-22, retour Antoine -- "reduire plutot que multiplier") : le badge
   perd son fond/bordure/ombre (registre "sticker") pour devenir un simple repere textuel, comme
   un kicker editorial Komoot/Polarsteps -- icone + texte, aucune boite. Scope inchange
   (.plan-card--hero .plan-card__badge), aucun effet sur les autres usages de .plan-card__badge. */
/* Phase 3A-bis : "Votre journee est prete" devient un kicker editorial discret -- couleur
   sourde (color-text-muted, plus la teinte ambree qui lisait comme une alerte de statut),
   petite taille, majuscules espacees (registre carnet de voyage / Polarsteps), jamais de
   fond ni de pastille (deja le cas avant ce lot, renforce ici). */
.plan-card--hero .plan-card__badge { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0; border-radius: 0; background: none; border: 0; color: var(--color-text-muted); font-weight: 600; font-size: 0.72rem; letter-spacing: 0.07em; text-transform: uppercase; box-shadow: none; }
.plan-card--hero .plan-card__badge svg { width: 0.85em; height: 0.85em; opacity: 0.75; }

/* Phase 2B-1 -- justification condensee (reutilise .miguel-explication existant via
   dhtRenderExplicationDOM, aucune nouvelle fonction de rendu). Le niveau de confiance devient une
   pastille pleine (jamais un emoji) pour se rapprocher des signaux de type Komoot/Roadtrippers. */
/* Phase 2C-1 quater (2026-07-22, retour Antoine -- "uniquement des separateurs fins et de
   l'espace negatif" pour les sections secondaires) : la boite pleine (.miguel-explication,
   fond vert clair) est APLATIE uniquement dans ce contexte precis (selecteur descendant scope a
   .miguel-hero__explication -- la fiche spot et les autres emplacements qui partagent la meme
   classe .miguel-explication gardent leur fond inchange, aucune regression ailleurs). Remplacee
   par un simple filet fin en haut, comme les autres sections secondaires du hero. */
.miguel-hero__explication { margin: var(--space-4, 2rem) 0 0; padding-top: var(--space-4, 2rem); border-top: 1px solid var(--color-border); }
.miguel-hero__explication .miguel-explication { background: none; padding: 0; border-radius: 0; box-shadow: none; }
.miguel-hero__explication .miguel-explication__niveau { display: inline-flex; align-items: center; gap: 0.5em; margin: 0 0 var(--space-3); padding: 0; border: 0; border-radius: 0; background: none; font-size: 0.85rem; font-weight: 700; color: var(--color-primary-strong, var(--color-primary)); }
.miguel-hero__explication .miguel-explication__niveau::before { content: ""; flex-shrink: 0; width: 0.55em; height: 0.55em; border-radius: 50%; background: var(--color-primary); }
.miguel-hero__explication .miguel-explication__title { margin: 0 0 var(--space-3); max-width: 38ch; font-family: var(--font-base); font-size: 1.15rem; font-weight: 600; line-height: 1.6; color: var(--color-text); }
@media (min-width: 1024px) and (pointer: fine), (min-width: 768px) and (pointer: coarse) and (any-hover: none) and (max-aspect-ratio: 8/5) { .miguel-hero__explication .miguel-explication__title { max-width: 46ch; } } /* Convergence mode tablette (01/08/2026) : regle desktop etendue telle quelle. */

/* Phase 2B-1 -- CTA (action), reutilise le mecanisme d'ouverture de fiche existant (data-open-detail) */
.miguel-hero__cta { display: inline-flex; align-items: center; gap: 0.4rem; margin-top: 0; padding: 0.55rem 1.1rem; border: 0; border-radius: var(--radius-pill); background: var(--color-primary); color: #fff; font-family: var(--font-base); font-size: 0.88rem; font-weight: 600; cursor: pointer; transition: transform 0.15s ease, box-shadow 0.15s ease; }
.miguel-hero__cta:hover { box-shadow: var(--shadow-sm); transform: translateY(-1px); }
.miguel-hero__cta:focus-visible { outline: 2px solid var(--color-accent); outline-offset: 2px; }
@media (prefers-reduced-motion: reduce) { .miguel-hero__cta { transition: none; } .miguel-hero__cta:hover { transform: none; } }

/* Phase 1 bis A (2026-07-22) -- Carte Miguel(TM) premium : habillage visuel de l'en-tete
   .miguel-card__header / .miguel-card__resume, deja genere par renderJourneeSelectionnee()
   dans carte.js (badge de confiance via .miguel-choice-badge + phrase narrative issue de
   dhtConstruireExplicationSpot) mais jusqu'ici sans CSS -- affichage non stylise par defaut.
   Aucune nouvelle donnee : uniquement une nouvelle hierarchie de rendu, sur des sorties deja
   produites par dhtNiveauConfianceScore et dhtConstruireExplicationSpot. Pas de photo de spot
   (decision deja actee dans le code : aucun champ photo fiable sur les spots reels -- on ne
   simule pas une donnee qui n'existe pas). */
.miguel-card__header {
  display: flex;
  flex-direction: column;
  gap: var(--space-3, 1.5rem);
  margin-bottom: var(--space-4, 2rem);
  padding-bottom: var(--space-3, 1.5rem);
  border-bottom: 1px solid rgba(15, 95, 92, 0.12);
}
/* Phase 2A.1 -- dans ce contexte precis (en-tete de la carte de decision), le badge doit etre
   le premier repere que l'oeil capte : un "sceau" de decision, pas une etiquette. Override
   volontairement SCOPE a .miguel-card__header (et non applique a .miguel-choice-badge en general)
   pour ne pas alterer sa taille dans les autres emplacements deja prevus pour ce meme composant
   partage (liste "Choix de Miguel", futur badge sur le pin principal -- cf. commentaire style.css
   ligne ~163), qui ont des contraintes d'espace differentes. */
.miguel-card__header .miguel-choice-badge {
  align-self: flex-start;
  padding: 0.45rem 0.9rem;
  font-size: 0.85rem;
  letter-spacing: 0.01em;
  border-color: rgba(242, 166, 90, 0.55);
  box-shadow: var(--shadow-sm);
}
/* Phrase de decision Miguel(TM) : reste en Poppins (regle Phase 1 validee -- Jost reserve aux
   titres H1/H2/H3), mais se distingue du reste du texte du bloc par un poids et une taille
   superieurs + une bordure d'accent teal (jamais orange : cette phrase explique une decision,
   elle n'est pas elle-meme le badge "Choix de Miguel(TM)" juste au-dessus). */
.miguel-card__resume {
  margin: 0;
  max-width: 34ch;
  padding-left: var(--space-4, 2rem);
  border-left: 3px solid var(--color-primary-soft);
  font-family: var(--font-base);
  font-size: 1.15rem;
  font-weight: 600;
  line-height: 1.6;
  color: var(--color-text);
}
/* Phase 2A.1 -- desktop uniquement : le panneau devient plus large (voir media query
   min-width:1024px plus bas dans ce fichier), la phrase de decision peut donc respirer un peu
   plus sans devenir illisible (mesure de confort ~38-40 caracteres au lieu de 34). */
@media (min-width: 1024px) and (pointer: fine),
  (min-width: 768px) and (pointer: coarse) and (any-hover: none) and (max-aspect-ratio: 8/5) {
  .miguel-card__resume { max-width: 40ch; }
} /* Convergence mode tablette (01/08/2026) : regle desktop etendue telle quelle. */

.alternatives { margin-top: var(--space-4); padding-top: var(--space-4); border-top: 1px solid var(--color-border); 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. Bordure haute ajoutee (2C-1 quinquies) : desormais un simple lien, la separation hairline vient de la section elle-meme. */
/* 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__list { display: block; }
/* Phase 2C-1 quinquies (2026-07-22, retour Antoine -- "assistant qui decide, pas comparateur") :
   l'ancienne "mini-carte" alternative (titre + nb d'etapes visibles avant le clic) est retiree.
   .alternative-lien est un simple lien texte, sans aucun aperçu du contenu de l'autre journee --
   c'est le SEUL point d'acces a la 2e proposition du moteur (measure delibere de ne montrer
   qu'une seule recommandation a la fois, voir carte.js). */
.alternative-lien { display: inline-flex; align-items: center; gap: 0.35rem; padding: 0; border: 0; background: none; color: var(--color-text-muted); font-size: 0.9rem; font-weight: 500; text-decoration: underline; text-decoration-color: var(--color-border); text-underline-offset: 2px; }
.alternative-lien::after { content: "\2192"; }
/* 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. */
/* Phase 2A.1 -- timeline visuelle du programme, en CSS pur (counter-reset/counter-increment +
   ::before), sans AUCUN changement de balisage : .journee-etapes est deja une liste (<ul>),
   .journee-etape deja un <li> -- on numerote et on relie ce qui existe deja, comme une vraie
   feuille de route plutot qu'une simple succession de blocs. Garde-fou explicite : la liste de
   continuation (.journee-etapes--suite, injectee par carte.js lors du "voir plus") NE reinitialise
   PAS le compteur (selecteur :not() ci-dessous), pour que la numerotation reste continue entre le
   debut de journee et sa suite au lieu de redemarrer a "1". */
.journee-etapes:not(.journee-etapes--suite) { counter-reset: dht-etape; }
.journee-etapes { position: relative; min-width: 0; list-style: none; padding: 0 0 0 var(--space-5, 2rem); margin: 0; display: flex; flex-direction: column; gap: var(--space-3, 1.5rem); }
.journee-etapes::before { content: ""; position: absolute; left: calc(var(--space-5, 2rem) / 2 - 1px); top: 0.35em; bottom: 0.35em; width: 2px; background: var(--color-primary-soft); }
.journee-etape { counter-increment: dht-etape; position: relative; }
.journee-etape::before { content: counter(dht-etape); position: absolute; left: calc(var(--space-5, 2rem) * -1); top: 0; width: var(--space-4, 2rem); height: var(--space-4, 2rem); display: flex; align-items: center; justify-content: center; border-radius: 50%; background: var(--color-primary); color: #fff; font-size: var(--map-text-xs); font-weight: 700; z-index: 1; }
/* Phase 3A-bis (2026-07-23, demande Antoine -- "le parcours doit ressembler a un carnet de
   route, moins liste technique") : chaque etape n'est plus une case bordee sur fond blanc
   (effet "liste de resultats") mais une ligne du recit, separee de la suivante par un simple
   trait fin -- la ligne verticale + les puces numerotees (.journee-etapes::before /
   .journee-etape::before, juste au-dessus, INCHANGEES) restent le seul repere structurel,
   comme le tracé d'un itineraire sur un carnet de voyage papier. Plus de respiration
   verticale (padding). Aucun changement de balisage, aucune donnee retiree. */
.journee-etape__ligne { position: relative; display: flex; align-items: stretch; min-width: 0; gap: var(--space-2); padding: var(--space-3) 0 var(--space-4); border-bottom: 1px solid var(--color-border); }
.journee-etape:last-child .journee-etape__ligne { border-bottom: 0; padding-bottom: 0; }
.journee-etape__contenu { position: relative; flex: 1 1 auto; min-width: 0; display: flex; }
.journee-etape__bouton { flex: 1 1 auto; width: 100%; min-width: 0; display: flex; flex-wrap: wrap; align-items: baseline; gap: var(--space-2); padding: 0 2.75rem 0 0; border: 0; border-radius: 0; background: none; color: var(--color-text); text-align: left; cursor: pointer; font: inherit; appearance: none; -webkit-appearance: none; }
.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__ligne { border-left: 3px solid var(--color-accent); padding-left: var(--space-3); }
.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__ligne { border-left: 3px dashed var(--color-text-muted); padding-left: var(--space-3); }
.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; }
/* Passe « Que faire maintenant ? » — couche additive 2026-08-16.
   Même langage visuel que .around-me : aucun remplacement du composant existant,
   aucune règle mobile globale modifiée. */
.que-faire-maintenant { margin-bottom: 16px; }
.que-faire-maintenant__trigger { width: 100%; }
.que-faire-maintenant__panel { margin-top: var(--space-3); }
.que-faire-maintenant__header { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); margin-bottom: var(--space-2); }
.que-faire-maintenant__header strong { display: block; font-weight: 800; }
.que-faire-maintenant__header span { display: block; margin-top: 2px; color: var(--color-text-muted); font-size: var(--map-text-xs); }
.que-faire-maintenant__list { display: grid; gap: var(--space-2); }
.que-faire-maintenant__card { display: grid; grid-template-columns: auto minmax(0, 1fr) auto; gap: var(--space-2); 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); text-align: left; box-shadow: var(--shadow-sm); }
.que-faire-maintenant__card:hover, .que-faire-maintenant__card:focus-visible { border-color: var(--color-primary); background: var(--color-primary-soft); }
.que-faire-maintenant__rank { display: inline-flex; width: 1.7rem; height: 1.7rem; align-items: center; justify-content: center; border-radius: 50%; background: var(--color-primary-soft); color: var(--color-primary-strong); font-weight: 800; }
.que-faire-maintenant__body { min-width: 0; }
.que-faire-maintenant__spot { display: block; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.que-faire-maintenant__meta, .que-faire-maintenant__reason { display: block; margin-top: 2px; color: var(--color-text-muted); font-size: var(--map-text-xs); line-height: 1.35; }
.que-faire-maintenant__reason { color: var(--color-text); }
.que-faire-maintenant__score { display: grid; min-width: 3.7rem; justify-items: end; align-content: center; }
.que-faire-maintenant__score strong { font-size: 1.15rem; line-height: 1; }
.que-faire-maintenant__score span { margin-top: 3px; color: var(--color-text-muted); font-size: 0.62rem; line-height: 1.1; text-align: right; }
.que-faire-maintenant__score--excellent strong { color: var(--pin-score-excellent); }
.que-faire-maintenant__score--good strong { color: var(--pin-score-good); }
.que-faire-maintenant__score--medium strong { color: var(--pin-score-medium); }
.que-faire-maintenant__score--low strong { color: var(--pin-score-low); }
.que-faire-maintenant__avoid { display: grid; gap: 3px; margin-top: var(--space-3); padding: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-lg); background: var(--color-surface-muted); color: var(--color-text-muted); font-size: var(--map-text-xs); }
.que-faire-maintenant__avoid strong { color: var(--color-text); }
.que-faire-maintenant__empty { margin: 0; padding: var(--space-3); border-radius: var(--radius-lg); background: var(--color-surface-muted); color: var(--color-text-muted); }
@media (max-width: 400px) {
  .que-faire-maintenant__card { grid-template-columns: auto minmax(0, 1fr) auto; padding: var(--space-2); }
  .que-faire-maintenant__score { min-width: 3.2rem; }
}

/* Passe « Réorganiser ma journée » — 2026-08-16.
   Couche additive, même langage visuel que « Que faire maintenant ? ». */
.reorganiser-journee { margin-bottom: 16px; }
.reorganiser-journee__trigger { width: 100%; }
.reorganiser-journee__panel { margin-top: var(--space-3); padding: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-lg); background: var(--color-surface); }
.reorganiser-journee__header { display: grid; gap: 3px; margin-bottom: var(--space-2); }
.reorganiser-journee__header strong { font-weight: 800; }
.reorganiser-journee__header span, .reorganiser-journee__locked, .reorganiser-journee__message { color: var(--color-text-muted); font-size: var(--map-text-xs); line-height: 1.4; }
.reorganiser-journee__locked { margin: 0 0 var(--space-2); }
.reorganiser-journee__list { display: grid; gap: var(--space-1); margin: 0; padding: 0; list-style: none; }
.reorganiser-journee__list li { display: grid; grid-template-columns: 1.55rem minmax(0, 1fr); gap: var(--space-2); align-items: center; padding: var(--space-2); border-radius: var(--radius-md); background: var(--color-surface-muted); }
.reorganiser-journee__list li > span { display: inline-flex; width: 1.55rem; height: 1.55rem; align-items: center; justify-content: center; border-radius: 50%; background: var(--color-primary-soft); color: var(--color-primary-strong); font-weight: 800; font-size: var(--map-text-xs); }
.reorganiser-journee__list li strong { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.reorganiser-journee__actions { display: flex; flex-wrap: wrap; gap: var(--space-2); margin-top: var(--space-3); }
.reorganiser-journee__actions .button { min-height: 42px; }
@media (max-width: 400px) {
  .reorganiser-journee__panel { padding: var(--space-2); }
  .reorganiser-journee__actions { display: grid; }
  .reorganiser-journee__actions .button { width: 100%; }
}

/* 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; -webkit-overflow-scrolling: touch; touch-action: pan-y; overscroll-behavior-y: contain; 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,
.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); }
.detail-close[hidden] { display: none !important; }
/* 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); } .detail-seo-link { display: inline-flex; align-items: center; justify-content: center; gap: .45rem; min-height: 40px; padding: .55rem .75rem; margin-top: .1rem; color: var(--color-text-muted); font-size: .9rem; font-weight: 600; text-decoration: none; border: 1px solid rgba(19,56,158,.16); border-radius: 12px; background: transparent; }
/* Correctif CTA conditionnel (2026-08-24) : si aucun lien officiel ou aucune page SEO
   n'existe, le bouton entier doit rester invisible. Les classes de bouton imposent un
   display explicite et peuvent neutraliser le comportement natif de [hidden]. */
.detail-official-link[hidden],
.detail-seo-link[hidden] { display: none !important; }
 .detail-seo-link:hover { color: var(--color-primary, #13389e); border-color: rgba(19,56,158,.28); background: rgba(19,56,158,.04); }
.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); } .geoloc-banner { 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) and (pointer: fine) { :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; } } /* Convergence mode tablette (01/08/2026) : cette "carte flottante" est reservee aux petites fenetres desktop -- rendue explicite (pointer:fine) pour ne jamais etre heritee par la tablette, qui passe directement en grille plein ecran (cf. #map-app etendu plus bas). Aucune valeur modifiee. */
/* Correctif tablette cible (2026-07-12) SUPPRIME et CONVERGE (01/08/2026, sprint Mode Tablette) : ce correctif compensait un padding-bottom reserve pour un tiroir mobile alors que la tablette (768-1365px, pointer:coarse) avait deja une carte flottante depuis la regle @media(min-width:768px). Depuis ce sprint, la tablette ne passe plus JAMAIS par l'etat "carte flottante" (cette regle est desormais strictement pointer:fine, cf. plus haut) : elle beneficie directement de la grille plein ecran partagee avec le desktop (#map-app, etendue plus bas), qui fixe elle-meme .map-viewport{padding-bottom:var(--space-6)}, quelle que soit la largeur au-dela de 768px. Ce correctif ponctuel est donc devenu un doublon obsolete -- retire plutot que laisse coexister avec la nouvelle regle unifiee, conformement a la doctrine de convergence demandee par Antoine. */
/* 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), (min-width: 768px) and (pointer: coarse) and (any-hover: none) and (max-aspect-ratio: 8/5) { /* Convergence mode tablette (01/08/2026) : grille desktop (carte + colonne Miguel(TM) permanentes) etendue telle quelle a la tablette tactile -- meme proportions de colonnes, meme scroll unique, meme masquage de la poignee de glissement (.assistant-panel__handle plus bas dans ce bloc). Seule difference tactile : voir le bloc dedie "cibles tactiles tablette" en fin de fichier. AUDIT COMPLEMENTAIRE (01/08/2026, meme jour) : le critere initial (min-width:768px + pointer:coarse + any-hover:none) faisait basculer en mode tablette tout smartphone tenu en paysage au-dela de 768px de large (ex. iPhone 12/13/14 : 844px, 14 Pro Max : 932px), un usage frequent et non marginal pour une carte/GPS -- corrige par l'ajout de (max-aspect-ratio:8/5) : 8/5 (=1.6, ratio d'ecran 16/10) est un standard d'affichage deja utilise par l'industrie pour les tablettes/ordinateurs portables, PAS un seuil invente pour ce correctif. Verification sur les appareils reels : aucune tablette connue (iPad, Android) ne depasse un ratio de 1.6 quelle que soit son orientation (iPad standard/Pro 11"/Pro 12,9"/mini : 1.33 a 1.43 en paysage, <1 en portrait), tandis qu'aucun smartphone du marche ne descend sous 1.6 en paysage (le plus "carre" connu, iPhone SE 16:9, atteint deja 1.78) -- marge de securite confortable (~11%) entre les deux familles d'appareils, sans JavaScript ni nouveau seuil de largeur/hauteur. Cf. RAPPORT-livraison-mode-tablette-01-08.md, section audit aspect-ratio, pour l'etude complete des alternatives ecartees. */ .map-app { display: grid; grid-template-columns: clamp(460px, 38vw, 560px) minmax(280px, 1fr); height: 100dvh; }
  /* Correctif (2026-07-22, retour Antoine -- "audit UX desktop, reequilibrage largeur panneau") :
     panneau Miguel(TM) elargi (420-460px -> 460-560px). La recommandation est le coeur du produit,
     la carte est decorative sur ce breakpoint -- inspiration Komoot/Polarsteps/Roadtrippers ou le
     contenu editorial recoit la largeur, jamais la carte/liste. Repris a 1280px+ ci-dessous. */ .map-stage { grid-column: 2; } .azores-svg { width: 100%; max-width: none; } .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),
  (min-width: 1280px) and (pointer: coarse) and (any-hover: none) and (max-aspect-ratio: 8/5) {
  /* Convergence mode tablette (01/08/2026) : affinage grand ecran desktop etendu tel quel aux tablettes larges (ex. iPad Pro 12,9" en paysage, 1366px) -- resout par construction le cas limite deja identifie (cet appareil beneficie desormais du meme affinage que le desktop equivalent, plutot que de rester dans une zone grise entre deux correctifs). */
  .map-app { grid-template-columns: clamp(620px, 44vw, 760px) minmax(320px, 1fr); }
  .azores-svg { width: 100%; max-width: none; }
  /* Correctif (2026-07-22, retour Antoine -- "audit UX desktop, reequilibrage largeur panneau") :
     l'ancienne grille a 2 colonnes de .sheet-content (P6/Phase 3) est retiree ici. Elle datait du
     mode "comparateur" ou 2 journees completes s'affichaient cote a cote -- paradigme abandonne
     depuis la Phase 2C-1 quinquies (une seule recommandation affichee, l'autre derriere un lien
     discret, jamais deux colonnes de contenu equivalent). .alternatives n'avait jamais ete ajoutee
     a la liste "grid-column: 1 / -1" ci-dessous : cause exacte du bug signale (le lien "Je prefere
     une autre ambiance", devenu minuscule depuis qu'il n'est plus une grande carte, se retrouvait
     seul dans la 2e colonne, laissant un grand vide a cote de la recommandation principale
     retrecie). .sheet-content repasse en 1 colonne pleine largeur (comportement <1280px, deja
     valide) : le panneau elargi ci-dessus (620-760px) profite alors immediatement de tout l'espace
     gagne pour LA recommandation Miguel(TM), sans qu'aucune section secondaire ne vienne le
     partager. */
  /* Note (2026-07-22) : l'ancien correctif "chevauchement desktop" (2026-07-12) forcait
     .spot-detail en grid-column:1/-1 pour compenser la grille a 2 colonnes ci-dessus, desormais
     retiree. .sheet-content etant revenu a une seule colonne a ce palier (comme <1280px, deja
     valide), .spot-detail (position:absolute; inset:0, voir plus haut) couvre a nouveau toute
     la largeur nativement, sans regle explicite necessaire. */
}
/* 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. */
/* Phase 3A-bis : coherent avec .journee-etape--planifiee/-sans-horaire (juste au-dessus,
   deja un trait d'accent a gauche, jamais un fond plein) -- "l'etape en cours" perd son
   fond colore plein cadre (trop "carte selectionnee" / dashboard) au profit du meme
   registre discret : un trait de couleur, rien de plus. */
.journee-etape.is-etape-courante .journee-etape__ligne { border-left: 3px solid var(--color-primary); background: none; padding-left: var(--space-3); }
.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); }

/* Icone switch sur le parcours Miguel(TM) (2026-08-01, demande Antoine -- mission "Ajouter
   l'icone de switch sur parcours Miguel(TM)") : discrete, a droite du nom de chaque etape, sur
   la meme ligne que l'heure/le nom -- .journee-etape__corps (heure + <strong> + ce controle +
   motif) est deja flex-wrap (voir plus haut), ce controle en devient simplement un nouvel
   element flex, exactement comme .journee-etape__heure et <strong>, sans toucher a leur ordre
   ni a leur propre mise en page.
   - flex: 0 0 auto -- ne se laisse jamais comprimer/etirer par le titre voisin (jamais de
     retour a la ligne du seul fait de cette icone : c'est bien <strong> qui absorbe l'espace,
     grace a son flex: 1 1 auto deja existant). Aucun `order` CSS : la position juste après le
     titre (et avant le motif, qui passe déjà en flex: 1 1 100% et saute donc naturellement à la
     ligne suivante) vient directement de l'ordre HTML généré par etapeHtml() dans carte.js.
   - 26x26px visibles (desktop/mobile) : gabarit discret, coherent avec .legende-popover__close
     (meme registre "icone ronde discrete" deja utilise ailleurs sur cette meme carte) ; zone
     tactile reellement cliquable/tappable etendue a 40x40px minimum via ::before (meme technique
     que .media-credit-btn::before, cf. plus haut), invisible, sans jamais agrandir le rendu
     visuel ni perturber le flux du texte autour. */
.journee-etape__switch-shell {
  position: absolute;
  top: 0;
  right: 0;
  flex: 0 0 auto;
  align-self: center;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
}
.journee-etape__switch {
  position: relative;
  /* .journee-etape__corps applique align-items: baseline (pour aligner l'heure et le titre sur
     leur ligne de texte) -- sans repli explicite, une icône ronde sans texte (donc sans vraie
     "baseline") se retrouverait décalée vers le bas par rapport au titre. align-self: center la
     recentre verticalement sur sa propre ligne, sans toucher à l'alignement baseline du reste
     (heure/titre/motif, inchangés). */
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 26px;
  height: 26px;
  border: 1px solid var(--color-border);
  border-radius: 50%;
  background: transparent;
  color: transparent;
  cursor: pointer;
  transition: background-color 160ms ease, border-color 160ms ease, color 160ms ease, transform 120ms ease;
  z-index: 1;
}
.journee-etape__switch::before { content: ""; position: absolute; inset: -7px; } /* correctif P1 (audit) : zone tactile réelle 40x40px, cf. .media-credit-btn::before */
@media (min-width: 768px) and (max-width: 1024px) {
  .map-app { grid-template-columns: clamp(360px, 38vw, 460px) minmax(0, 1fr); }
  .map-app .assistant-panel__handle { display: flex; }
  .map-app.is-immersive .map-stage { grid-column: 1 / -1; }
  .map-app.is-immersive .assistant-panel { display: none; }
  .map-app.is-immersive .map-status { opacity: 0; pointer-events: none; }
  .map-app.is-immersive .map-viewport { padding-bottom: var(--space-4); }
  .map-app.is-immersive .map-immersive-toggle {
    display: inline-flex;
    right: var(--space-4);
    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; }
}

@media (min-width: 768px) and (pointer: coarse) and (any-hover: none) and (max-aspect-ratio: 8/5) { .journee-etape__switch::before { inset: -9px; } } /* Mode tablette (01/08/2026) : SEULE difference tactile sur ce composant -- cible portee de 40x40px (40=26+2*7, doctrine mobile/desktop) a 44x44px (44=26+2*9, doctrine tablette Antoine "44px minimum"), sans agrandir le rendu visuel du bouton (toujours 26px), meme technique ::before invisible que .media-credit-btn (qui atteint deja ~44px et n'a donc besoin d'aucun changement, verifie). Aucune autre regle de ce fichier ne necessite cet ajustement : tous les autres boutons/cibles tactiles pertinents (.detail-close, .weather-refresh, .control-button/.control-select, .map-immersive-toggle) sont deja a min-height:44px ou plus. */
.journee-etape__switch-icone { position: absolute; width: 14px; height: 14px; max-width: 14px; max-height: 14px; color: var(--color-text-muted); pointer-events: none; z-index: 0; }
.journee-etape__switch-trigger { display: none; position: relative; align-items: center; justify-content: center; width: 26px; height: 26px; padding: 0; border: 1px solid var(--color-border); border-radius: 50%; background: var(--color-surface); color: var(--color-text-muted); cursor: pointer; transition: background-color 160ms ease, border-color 160ms ease, color 160ms ease, transform 120ms ease; z-index: 1; }
.journee-etape__switch-trigger::before { content: ""; position: absolute; inset: -7px; }
.journee-etape__switch-trigger-icone { width: 15px; height: 15px; max-width: 15px; max-height: 15px; pointer-events: none; }
.dht-switch-ux-ready .journee-etape__switch-trigger { display: inline-flex; }
.dht-switch-ux-ready .journee-etape__switch--native { position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0; overflow: hidden; clip: rect(0 0 0 0); clip-path: inset(50%); white-space: nowrap; opacity: 0; pointer-events: none; }
.dht-switch-ux-ready .journee-etape__switch--native:focus-visible { position: relative; width: 26px; height: 26px; margin: 0; clip: auto; clip-path: none; opacity: 1; pointer-events: auto; }
.dht-switch-ux-ready .journee-etape__switch-icone { display: none; }
.dht-switch-ux-ready .journee-etape__switch-shell:hover .journee-etape__switch-trigger { background: var(--color-primary-soft); border-color: var(--color-primary); color: var(--color-primary); }
.journee-etape__switch-trigger:active { transform: scale(0.88); }
.journee-etape__switch-trigger:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.miguel-switch-modal { position: fixed; inset: 0; z-index: 1200; display: flex; align-items: flex-end; justify-content: center; padding: var(--space-3); background: rgba(15, 20, 20, 0.48); }
.miguel-switch-modal[hidden] { display: none; }
.miguel-switch-modal__panel { width: min(100%, 34rem); max-height: min(82dvh, 42rem); overflow-y: auto; padding: var(--space-4); border: 1px solid var(--color-border); border-radius: var(--radius-xl, 1.25rem) var(--radius-xl, 1.25rem) var(--radius-lg, 0.9rem) var(--radius-lg, 0.9rem); background: var(--color-surface); box-shadow: 0 18px 48px rgba(15, 20, 20, 0.22); }
.miguel-switch-modal__panel .carnet-modal__header { position: sticky; top: calc(var(--space-4) * -1); z-index: 1; margin: calc(var(--space-4) * -1) calc(var(--space-4) * -1) var(--space-3); padding: var(--space-4); background: var(--color-surface); }
.miguel-switch-modal__panel h2 { display: flex; align-items: center; gap: var(--space-2); margin: 0; }
.miguel-switch-modal__intro { margin: 0 0 var(--space-3); color: var(--color-text-muted); }
.miguel-switch-modal__list { display: grid; gap: var(--space-2); }
.miguel-switch-choice { display: grid; grid-template-columns: 2.25rem minmax(0, 1fr); align-items: center; gap: var(--space-3); width: 100%; min-height: 64px; padding: var(--space-3); border: 1px solid var(--color-border); border-radius: var(--radius-lg, 0.9rem); background: var(--color-surface); color: var(--color-text); text-align: left; cursor: pointer; }
.miguel-switch-choice:hover, .miguel-switch-choice:focus-visible { border-color: var(--color-primary); background: var(--color-primary-soft); }
.miguel-switch-choice:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.miguel-switch-choice__icone { width: 1.5rem; height: 1.5rem; color: var(--color-primary); }
.miguel-switch-choice__contenu { display: grid; gap: 0.18rem; min-width: 0; }
.miguel-switch-choice__titre { overflow-wrap: anywhere; }
.miguel-switch-choice__infos { color: var(--color-text-muted); font-size: var(--map-text-sm); }
body.dht-miguel-switch-modal-open { overflow: hidden; }
@media (min-width: 768px) {
  .miguel-switch-modal { align-items: center; }
  .miguel-switch-modal__panel { border-radius: var(--radius-xl, 1.25rem); }
}
/* survol : uniquement sur les appareils avec un vrai pointeur (meme garde que le reste de la
   carte, cf. bloc "@media (hover: hover) and (pointer: fine)" plus haut) -- jamais d'effet de
   survol "collé" après un tap sur mobile/tablette tactile. Jamais sur l'icone desactivee. */
@media (hover: hover) and (pointer: fine) {
  .journee-etape__switch:not(.journee-etape__switch--disabled):hover {
    background: var(--color-primary-soft);
    border-color: var(--color-primary);
    color: var(--color-primary);
  }
  .journee-etape__switch-shell:hover .journee-etape__switch-icone { color: var(--color-primary); }
}
/* pression : meme retour tactile immediat que le reste des controles de la carte
   (.control-button:active, .journee-etape__bouton:active, cf. plus haut). */
.journee-etape__switch:not(.journee-etape__switch--disabled):active { transform: scale(0.88); }
/* clavier : meme anneau de focus que tous les autres controles de la carte (cf. bloc
   ":focus-visible" partagé plus haut) -- ajouté ici plutôt que fusionné dans la liste commune
   pour ne pas modifier une règle déjà partagée par de nombreux sélecteurs sans lien direct avec
   cette mission. */
.journee-etape__switch:focus-visible {
  outline: 2px solid var(--color-primary);
  outline-offset: 2px;
}
/* Aucune alternative pertinente pour cette étape (déterminé au rendu, cf. carte.js) : icône
   visuellement neutralisée, non cliquable, non focusable -- jamais un clic silencieux qui ne
   ferait rien sans indication visuelle. */
.journee-etape__switch--disabled {
  opacity: 0.4;
  cursor: not-allowed;
}
/* 26px visibles + 7px de marge invisible de chaque côté (::before ci-dessus) = 40x40px de zone
   tactile réelle sur toutes les tailles d'écran, y compris mobile -- aucune règle supplémentaire
   n'est nécessaire ici. */
@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. */
/* Micro UX responsive — fiche spot immersive mobile/tablette (2026-08-23) : lorsqu'une fiche spot
   est ouverte depuis la carte ou depuis une étape du parcours Miguel™, le même .spot-detail reste
   la source de vérité et le panneau assistant prend toute la hauteur disponible SOUS le header global.
   Aucun changement desktop : ce bloc est strictement limité au mobile et aux tablettes tactiles.
   Pas de nouvelle logique JS, pas de changement de contenu, scoring, météo, webcam ou navigation. */
@media (max-width: 767px),
       (min-width: 768px) and (pointer: coarse) and (any-hover: none) and (max-aspect-ratio: 8/5) {
  .map-app:has(.sheet-content.is-detail-open) .assistant-panel {
    position: fixed;
    top: var(--map-header);
    right: 0;
    bottom: 0;
    left: 0;
    width: auto;
    height: calc(100dvh - var(--map-header));
    border-radius: 0;
    box-shadow: 0 -8px 32px rgba(24, 49, 47, 0.12);
    z-index: 35;
  }
  .map-app:has(.sheet-content.is-detail-open) .assistant-panel.is-expanded {
    height: calc(100dvh - var(--map-header));
  }
}

@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-22, retour Antoine -- "il faut aussi la croix en haut pour fermer
   l'accordeon si on veut revenir a la carte de l'ile") : [data-panel-collapse] reutilise le
   style .detail-close (meme icone/typo, comme .miguel-wizard__close et les autres boutons
   "Fermer" du site), mais n'a de sens que quand le panneau mobile est deplie (.is-expanded) --
   sur mobile non-deplie, la carte est deja visible, et sur desktop le panneau est une colonne
   pleine hauteur permanente (.assistant-panel__handle est deja masque dans ce cas, meme regle
   ici). Purement visuel/etat CSS : aucun JS de bascule hidden necessaire, is-expanded est deja
   gere par le handle existant (voir carte.js). */
.assistant-panel:not(.is-expanded) [data-panel-collapse] { display: none; }
@media (min-width: 1024px) and (pointer: fine), (min-width: 768px) and (pointer: coarse) and (any-hover: none) and (max-aspect-ratio: 8/5) { [data-panel-collapse] { display: none !important; } } /* Convergence mode tablette (01/08/2026) : sur tablette comme sur desktop, le panneau n'est plus un tiroir a "reouvrir" -- ce bouton n'a plus lieu d'exister, regle desktop etendue telle quelle. */
/* 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; }
@media (max-width: 767px) {
  /* Les actions passent sous le statut météo sur mobile.
     Aucun changement de logique, uniquement composition visuelle. */
  .weather-bar {
    flex-wrap: wrap;
  }
  .weather-status {
    flex: 1 1 100%;
    width: 100%;
  }
  .weather-bar__actions {
    flex: 1 1 100%;
    width: 100%;
    min-width: 0;
    display: grid;
    grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
    gap: 0.5rem;
  }
  .weather-bar__actions .weather-refresh,
  .weather-bar__actions .plan-card__profil-modifier,
  .weather-bar__actions .reorganiser-journee__visual-trigger {
    min-width: 0;
    width: 100%;
    min-height: 40px;
    height: 40px;
    padding-inline: 0.9rem;
  }
  .weather-bar__actions .weather-refresh {
    grid-column: 1;
    grid-row: 1;
  }
  .weather-bar__actions .plan-card__profil-modifier {
    grid-column: 2;
    grid-row: 1;
  }
  .weather-bar__actions .reorganiser-journee__visual-trigger {
    grid-column: 1 / -1;
    grid-row: 2;
    width: 100%;
  }
  /* V95 — correctif chirurgical du bouton retour carte : le contrôle [data-panel-collapse]
     est le 4e enfant de la grille des actions. Sans placement explicite, CSS Grid l'étire sur
     toute la largeur disponible. On conserve la même zone tactile, mais le rendu visuel reste
     compact et aligné à droite sous les actions. Aucun JS ni comportement de bascule modifié. */
  .weather-bar__actions [data-panel-collapse] {
    grid-column: 2;
    grid-row: 3;
    width: 44px;
    min-width: 44px;
    min-height: 40px;
    height: 40px;
    padding-inline: 0;
    justify-self: end;
  }

  /* V5 — masquage contextuel des actions pendant le scroll du parcours.
     Le header reste fixe ; seul le bloc des trois actions se replie pour rendre sa hauteur au
     contenu. Le comportement est piloté par .assistant-panel.is-actions-hidden-on-scroll,
     posé par carte.js uniquement sur mobile et uniquement dans la vue parcours. */
  .assistant-panel.is-actions-hidden-on-scroll .weather-bar {
    row-gap: 0;
  }
  .weather-bar {
    row-gap: var(--space-2, 0.75rem);
    transition: row-gap 180ms ease;
  }
  .assistant-panel.is-actions-hidden-on-scroll .weather-bar__actions {
    max-height: 0;
    margin: 0;
    overflow: hidden;
    opacity: 0;
    pointer-events: none;
    transform: translateY(-8px);
  }
  .weather-bar__actions {
    max-height: 140px;
    opacity: 1;
    transform: translateY(0);
    transition: max-height 180ms ease, opacity 140ms ease, transform 180ms ease;
  }
}


/* 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. */
/* Phase 2C-1 ter (2026-07-22, retour Antoine valide) : petit intitule dedie au-dessus des chips
   de profil ("Vos envies pour cette sortie"), affiche/masque en meme temps qu'elles (voir
   carte.js) -- distingue clairement cette famille ("preferences utilisateur") du resume pratique
   juste au-dessus (metadonnees factuelles, sans pastille). */
.plan-card__profil-titre { margin: 0 0 0.6rem; padding-top: var(--space-4, 2rem); border-top: 1px solid var(--color-border); font-size: 0.78rem; font-weight: 700; letter-spacing: 0.04em; text-transform: uppercase; color: var(--color-text-muted); }
.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)); }
/* Adapter ma journée — bouton VISUEL uniquement (2026-08-18)
   Aucun data-* d'action, aucun listener : cette étape ne branche volontairement
   aucune logique. Sur mobile, il occupe sa propre ligne pour éviter tout
   débordement horizontal ; les deux actions existantes restent côte à côte. */
.reorganiser-journee__visual-trigger {
  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-primary);
  color: var(--color-surface);
  font-size: var(--map-text-xs);
  font-weight: 700;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 6px;
  white-space: nowrap;
  cursor: pointer;
}

/* Adapter ma journée — état de calcul visible. Le spinner est ajouté au bouton lui-même,
   sans modifier sa géométrie ni le comportement des autres actions. */
@keyframes dht-action-spinner { to { transform: rotate(360deg); } }
.dht-action-busy { cursor: wait !important; }
.dht-action-busy::before {
  content: "";
  width: 14px;
  height: 14px;
  flex: 0 0 14px;
  border: 2px solid currentColor;
  border-right-color: transparent;
  border-radius: 50%;
  animation: dht-action-spinner 700ms linear infinite;
}
@media (prefers-reduced-motion: reduce) {
  .dht-action-busy::before { animation: none; }
}

/* 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; }
/* Finition UX Premium Randonnee (03/08/2026, retour Antoine REMY) : les phrases de
   explication.decomposition (Conditions randonnee Miguel(TM)) sont plus longues que les valeurs
   chiffrees habituelles de ces chips (ex. fiche technique Surf/Rando) -- variante pleine largeur
   en une seule colonne, memes chips, meme grille, aucune nouvelle structure. */
.detail-surf-bloc__grille--pleine-largeur { grid-template-columns: 1fr; }
/* Meme couleur d'alerte que .safety-badge--modere / .score-badge--moyen (map-state-warning-*,
   DEJA existante) : fait ressortir immediatement la vigilance quand elle est presente, sans
   introduire une nouvelle teinte. */
.detail-surf-bloc__item--vigilance .detail-surf-bloc__item-label,
.detail-surf-bloc__item--vigilance .detail-surf-bloc__item-valeur { color: var(--map-state-warning-text); }
.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; }

/* Sprint Surf 1 (01/08/2026, spec validee Antoine REMY) : bloc de classement surf, AJOUTE a cote
   du systeme hero/alternatives existant (ne touche a aucune regle ci-dessus). Reprend les memes
   variables de design (--color-border/--color-surface/--space-*/--radius-md/--map-text-*) pour
   rester visuellement coherent avec le reste du parcours Miguel, sans dupliquer .detail-surf-bloc*
   (la grille de conditions techniques reutilise directement ces classes, cf. carte.js). */
.surf-classement { margin: var(--space-3, 1rem) 0; padding: 0 var(--space-2, 0.75rem); }
.surf-classement:empty { display: none; }
.surf-classement__titre { margin: 0 0 var(--space-2, 0.75rem); font-size: var(--map-text-md, 1rem); font-weight: 700; display: flex; align-items: center; gap: 6px; }
.surf-classement__carte { margin: 0 0 var(--space-2, 0.75rem); padding: var(--space-3, 1rem); border: 1px solid var(--color-border); border-radius: var(--radius-md, 12px); background: var(--color-surface); }
.surf-classement__carte--principale { border-width: 2px; }
.surf-classement__carte--alternative { cursor: pointer; }
.surf-classement__badge { margin: 0 0 4px; font-size: var(--map-text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.02em; color: var(--color-text-muted, var(--color-text)); }
.surf-classement__nom { margin: 0 0 2px; font-size: var(--map-text-md, 1rem); font-weight: 700; }
.surf-classement__qualite-titre { margin: 0 0 var(--space-2, 0.75rem); font-size: var(--map-text-sm); font-weight: 600; }
.surf-classement__pourquoi-titre { margin: 0 0 4px; font-size: var(--map-text-xs); font-weight: 700; }
.surf-classement__pourquoi-liste { margin: 0 0 var(--space-2, 0.75rem); padding-left: 1.1em; font-size: var(--map-text-xs); color: var(--color-text-muted, var(--color-text)); }
.surf-classement__analyse { margin: 0 0 var(--space-2, 0.75rem); font-size: var(--map-text-xs); font-style: italic; color: var(--color-text-muted, var(--color-text)); }
.surf-classement__conditions-titre { margin: 0 0 var(--space-1, 0.5rem); font-size: var(--map-text-xs); font-weight: 700; border-top: 1px solid var(--color-border); padding-top: var(--space-2, 0.75rem); }
.surf-classement__autres-titre { margin: var(--space-2, 0.75rem) 0 var(--space-1, 0.5rem); font-size: var(--map-text-sm); font-weight: 700; }
.surf-classement__alternatives { display: grid; gap: var(--space-2, 0.75rem); }

/* Correctif UX (01/08/2026, retour Antoine REMY suite a relecture visuelle du Sprint Surf 2A) :
   le CTA "Spot Surf" (ex-"Fiche surf") est deplace de .detail-actions (tout en bas de la fiche,
   au meme niveau que "Y aller"/"Ajouter au carnet") vers juste apres .detail-score (avant la
   description) -- il s'agit de la valeur ajoutee principale de la fiche pour un surfeur, elle
   doit etre visible immediatement, pas decouverte en bas de page apres defilement. Le panneau
   .detail-surf-fiche suit juste apres dans le DOM (inchange par ailleurs), pour qu'un depliage
   s'affiche au bon endroit, avant la description generaliste du spot. Bouton reutilise
   .button/.button-primary (identite visuelle "Y aller", coherente avec le design system), avec
   un modificateur __toggle uniquement pour la largeur/l'alignement icone+texte -- aucune nouvelle
   couleur inventee. */
.detail-surf-cta { margin: var(--space-3, 1rem) 0; }
/* Correctif Responsive -- Bloc Premium conditionnel (02/08/2026, retour Antoine REMY : capture
   d'ecran "Piscinas Naturais de Velas" montrant un pave vide ".detail-surf-cta__toggle" affiche
   sur un spot NON premium). Cause reelle : [hidden] (regle native du navigateur, specificite
   0,1,0) et .detail-surf-cta__toggle { display:flex } (specificite 0,1,0) sont a specificite
   egale -- une regle d'auteur l'emporte toujours sur la regle native du navigateur, donc
   [hidden] etait silencieusement ignore et le bouton restait affiche (vide, sans texte/icone).
   On force explicitement display:none avec une specificite superieure (classe + attribut),
   pour .detail-surf-cta__toggle ET pour le conteneur .detail-surf-cta lui-meme (defensif, au
   cas ou une regle future ajoute un display sur ce conteneur). Resultat : quand JS pose
   `hidden` (cf. carte.js openDetail(), variable premiumDisponible), le conteneur ET son
   contenu disparaissent reellement, sans marge ni padding residuel -- le texte suivant remonte
   automatiquement. Regle generique, valable pour Surf Premium comme pour toute future fiche
   Premium (Randonnee, Plongee, Whale Watching, ...) reutilisant ce meme composant. */
.detail-surf-cta[hidden],
.detail-surf-cta__toggle[hidden] { display: none; }
/* Correctif UX (02/08/2026, retour Antoine REMY : "le bouton est beaucoup trop massif ... ce
   n'est pas une action, c'est l'ouverture d'un panneau") : accordeon discret (icone + libelle +
   chevron), plus un gros CTA vert plein -- classes .button/.button-primary retirees du markup
   (carte.html). Couleurs/bordures reprises de --color-primary/--color-border/--radius-md deja
   utilises ailleurs (ex. .detail-surf-fiche), aucune nouvelle couleur inventee. */
.detail-surf-cta__toggle {
  width: 100%; display: flex; align-items: center; gap: 8px;
  padding: 10px 14px; border: 1px solid var(--color-border); border-radius: var(--radius-md, 12px);
  background: var(--color-primary-soft, #eef7f5); color: var(--color-primary-strong, var(--color-primary));
  font-weight: 700; font-size: var(--map-text-sm, 0.9rem); cursor: pointer; text-align: left;
}
.detail-surf-cta__toggle:hover { filter: brightness(0.97); }
.detail-surf-cta__icon { display: inline-flex; flex-shrink: 0; }
.detail-surf-cta__icon svg { width: 20px; height: 20px; }
.detail-surf-cta__label { flex: 1 1 auto; }
.detail-surf-cta__chevron { display: inline-flex; flex-shrink: 0; transition: transform 0.15s ease; transform: rotate(180deg); }
.detail-surf-cta__toggle[aria-expanded="true"] .detail-surf-cta__chevron { transform: rotate(0deg); }
/* Refonte UX hierarchie fiche surf (02/08/2026, demande Antoine REMY) : badges "Spot Surf" +
   niveau juste apres le titre -- reprend --color-primary/--color-primary-soft/--radius-pill,
   deja utilises ailleurs (ex. .chip.is-active), aucune nouvelle couleur inventee. */
.detail-surf-badges { display: flex; flex-wrap: wrap; gap: 6px; margin: 6px 0 0; }
.detail-surf-badge { display: inline-flex; align-items: center; gap: 4px; padding: 3px 10px; border-radius: var(--radius-pill); font-size: var(--map-text-xs); font-weight: 700; }
.detail-surf-badge--type { background: var(--color-primary); color: #ffffff; text-transform: uppercase; letter-spacing: 0.02em; }
.detail-surf-badge--niveau { background: var(--color-primary-soft, #dff3ef); color: var(--color-primary-strong, var(--color-primary)); }
/* Sprint Surf 2A (01/08/2026, spec validee Antoine REMY) : bouton "Fiche surf" + panneau
   depliable, AJOUTES a cote du systeme existant (aucune regle ci-dessus modifiee). Reprend les
   memes variables de design que .detail-surf-bloc*/.surf-classement* pour rester coherent,
   et reutilise directement .detail-surf-bloc__grille/__item/__item-label/__item-valeur pour la
   grille de conditions techniques (cf. carte.js, construireBlocFicheSurfTechniqueHTML). */
.detail-surf-fiche { margin: var(--space-3, 1rem) 0 0; padding: var(--space-3, 1rem); border: 1px solid var(--color-border); border-radius: var(--radius-md, 12px); background: var(--color-surface); }
.detail-surf-fiche__bloc + .detail-surf-fiche__bloc { margin-top: var(--space-3, 1rem); padding-top: var(--space-3, 1rem); border-top: 1px solid var(--color-border); }
/* Correction (verification fonctionnelle statique, 01/08/2026) : la classe de base
   .detail-surf-fiche__bloc et ses deux modificateurs etaient utilises par
   construireBlocFicheSurfEditorialeHTML()/construireBlocFicheSurfTechniqueHTML() (carte.js)
   mais jamais definis ici -- trouve par la verification fonctionnelle poussee demandee par
   Antoine REMY (les tests unitaires ne verifient que le contenu HTML, pas la completude CSS). */
.detail-surf-fiche__bloc { }
.detail-surf-fiche__bloc--editorial { }
/* Correctif UX (02/08/2026, retour Antoine REMY : "la partie technique est excellente ... je la
   mettrais dans une vraie carte, comme les Conditions Miguel") : meme traitement visuel que
   .detail-surf-bloc (fond + bordure + coins arrondis), a l'interieur du panneau deja carte lui-
   meme -- fait ressortir la fiche technique sans dupliquer la structure. */
.detail-surf-fiche__bloc--technique { background: var(--color-primary-soft, #eef7f5); border: 1px solid var(--color-border); border-radius: var(--radius-md, 12px); padding: var(--space-3, 1rem); }
/* Correctif UX (02/08/2026, retour Antoine REMY : "je transformerais les listes a puces en
   badges") : remplace les <ul><li> de profilIdeal/eviterSi/hazards par des pastilles, meme
   patron que .detail-surf-badge (--radius-pill, --color-primary-soft) deja utilise sous le
   titre -- aucune nouvelle couleur, juste une variante par ton (neutre/alerte). */
.detail-surf-fiche__badges { display: flex; flex-wrap: wrap; gap: 6px; margin: 4px 0 0; padding: 0; list-style: none; }
.detail-surf-fiche__badge { display: inline-flex; align-items: center; gap: 4px; padding: 4px 10px; border-radius: var(--radius-pill); font-size: var(--map-text-xs); font-weight: 600; background: var(--color-primary-soft, #eef7f5); color: var(--color-primary-strong, var(--color-primary)); }
/* Reprend --color-warning, deja etabli et utilise ailleurs (.detail-conditions-acces, meme
   fallback #b45309) plutot que d'inventer un nouveau ton "danger" -- meme famille de couleur
   pour "a eviter si" et "risques", coherent avec l'alerte d'acces existante. */
.detail-surf-fiche__badge--eviter { background: color-mix(in srgb, var(--color-warning, #b45309) 12%, transparent); color: var(--color-warning, #b45309); }
.detail-surf-fiche__badge--hazard { background: color-mix(in srgb, var(--color-warning, #b45309) 16%, transparent); color: var(--color-warning, #b45309); }
.detail-surf-fiche__badge--hazard svg, .detail-surf-fiche__badge--eviter svg { width: 13px; height: 13px; }

.detail-surf-fiche__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-fiche__sous-titre { margin: var(--space-2, 0.75rem) 0 4px; font-size: var(--map-text-xs); font-weight: 700; text-transform: uppercase; letter-spacing: 0.02em; color: var(--color-text-muted, var(--color-text)); }
.detail-surf-fiche__identite { margin: 0; font-size: var(--map-text-sm); }
.detail-surf-fiche__quand-miguel { margin: 0; font-size: var(--map-text-xs); font-style: italic; color: var(--color-text-muted, var(--color-text)); }
.detail-surf-fiche__profil-liste { margin: 0 0 var(--space-1, 0.5rem); padding-left: 1.1em; font-size: var(--map-text-xs); }
.detail-surf-fiche__securite-liste { margin: 0 0 var(--space-1, 0.5rem); padding-left: 0; list-style: none; font-size: var(--map-text-xs); display: grid; gap: 4px; }
.detail-surf-fiche__message-invite { margin: 0 0 var(--space-2, 0.75rem); font-size: var(--map-text-xs); font-style: italic; color: var(--color-text-muted, var(--color-text)); }
.surf-classement__note { margin: 0; font-size: var(--map-text-xs); color: var(--color-text-muted, var(--color-text)); }


/* 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; }
/* Phase 1 bis C (2026-07-22) : habillage premium uniquement -- getMessageMeteoContextuel(),
   ses seuils et sa frequence d'apparition restent strictement inchanges (decision validee :
   Miguel ne doit parler que lorsqu'il a une vraie information a apporter, jamais "pour
   donner l'impression d'etre intelligent"). Palette alignee sur la famille visuelle Miguel(TM)
   (meme --color-primary-soft que .main-recommendation) plutot que le gris-bleu neutre
   precedent, pour que ce message soit percu comme la voix de Miguel, pas comme une notification
   d'app generique. Toujours pas de rouge, aucune icone (aucune information fiable dans le texte
   libre pour choisir une icone meteo pertinente sans inventer une logique de detection --
   voir echange du 2026-07-22), aucun texte ajoute (le contenu reste exclusivement celui ecrit
   par carte.js, data-weather-disagreement). */
.weather-disagreement { margin: 0 0 var(--space-3); padding: var(--space-3) var(--space-4); border: 1px solid rgba(15, 95, 92, 0.14); border-radius: var(--radius-lg); background: var(--color-primary-soft); color: var(--color-primary-strong); font-size: var(--map-text-sm); font-weight: 600; line-height: 1.5; }
.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-3) 0; font-size: var(--map-text-sm); color: var(--color-text-muted); }
.official-links__titre { display: block; font-weight: 800; color: var(--color-text); font-size: var(--map-text-md); margin-bottom: 2px; }
.official-links__intro { margin: 2px 0 var(--space-2); }
.official-links__liste { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 6px; }
.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); }
[data-detail-route] .icon-lucide { margin-right: 0.45em; }
.detail-official-link .icon-lucide { margin-right: 0.45em; }

.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); }

/* Fiche technique Premium commune Rando / Surf : déclencheur et modale responsive. */
.fiche-technique-trigger { display: flex; align-items: center; justify-content: space-between; gap: var(--space-3); width: 100%; margin: var(--space-3) 0; padding: var(--space-3) var(--space-4); border: 1px solid var(--color-border); border-radius: var(--radius-lg); background: var(--color-surface); color: var(--color-text); box-shadow: var(--shadow-sm); cursor: pointer; text-align: left; touch-action: manipulation; transition: border-color 160ms ease, background-color 160ms ease, box-shadow 160ms ease, transform 160ms ease; }
.fiche-technique-trigger:hover { border-color: var(--color-primary); background: var(--color-surface-hover); box-shadow: var(--shadow-md); }
.fiche-technique-trigger:active { transform: translateY(1px); }
.fiche-technique-trigger:focus-visible { outline: 3px solid var(--color-primary-soft); outline-offset: 2px; }
.fiche-technique-trigger__main, .fiche-technique-trigger__type { display: inline-flex; align-items: center; gap: var(--space-2); min-width: 0; }
.fiche-technique-trigger__main { font-weight: 800; }
.fiche-technique-trigger__type { color: var(--color-text-muted); font-size: var(--map-text-sm); font-weight: 700; white-space: nowrap; }
.fiche-technique-trigger__chevron { flex: 0 0 auto; color: var(--color-primary); }
.fiche-technique-modal { position: fixed; inset: 0; z-index: 66; display: flex; align-items: center; justify-content: center; padding: max(var(--space-3), env(safe-area-inset-top, 0px)) var(--space-3) max(var(--space-3), env(safe-area-inset-bottom, 0px)); background: rgba(24, 49, 47, 0.5); overscroll-behavior: contain; touch-action: none; }
.fiche-technique-modal[hidden] { display: none; }
.fiche-technique-modal__panel { display: flex; flex-direction: column; width: min(100%, 760px); max-height: min(88dvh, 760px); overflow-y: auto; overscroll-behavior: contain; -webkit-overflow-scrolling: touch; border: 1px solid rgba(221, 215, 203, 0.9); border-radius: var(--radius-xl); background: var(--color-surface); box-shadow: var(--shadow-md); box-sizing: border-box; touch-action: pan-y; }
.fiche-technique-modal__panel > .carnet-modal__header { position: sticky; top: 0; z-index: 1; flex: 0 0 auto; margin: 0; padding: var(--space-4); border-bottom: 1px solid var(--color-border); background: var(--color-surface); }
.fiche-technique-modal__panel .detail-close { margin-bottom: 0; }
.fiche-technique-modal__body { min-width: 0; padding: var(--space-4); }
.fiche-technique-modal__spot { display: flex; align-items: center; gap: var(--space-2); margin: 0 0 var(--space-3); color: var(--color-text); font-size: var(--map-text-md); font-weight: 800; }
@media (max-width: 767px) { .fiche-technique-modal { align-items: flex-start; padding-top: calc(var(--map-header) + var(--space-2)); } .fiche-technique-modal__panel { width: 100%; max-height: calc(100dvh - var(--map-header) - var(--space-4)); border-radius: var(--radius-lg); } .fiche-technique-modal__panel > .carnet-modal__header, .fiche-technique-modal__body { padding-inline: var(--space-3); } .fiche-technique-trigger { padding-inline: var(--space-3); } .fiche-technique-trigger__type { display: none; } }

.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); }
.carnet-modal__footer [data-carnet-print] { display: inline-flex; align-items: center; gap: 0.45em; }
.carnet-item .carnet-item__spot-link { display: block; font-size: var(--map-text-md); font-weight: 800; color: var(--color-text); text-decoration: underline; text-underline-offset: 0.14em; }
.carnet-item .carnet-item__spot-link:hover { color: var(--color-primary); }

@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: var(--map-top-safe-area, 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); }

.pin-equipement--barbecue { cursor: pointer; }
.pin-equipement--barbecue .pin-equipement__icone { color: var(--color-accent); pointer-events: none; overflow: visible; }
.pin-equipement--barbecue:hover .pin-equipement__icone,
.pin-equipement--barbecue:focus .pin-equipement__icone { opacity: 1 !important; }

.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; min-width: 0; 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); overflow-wrap: anywhere; max-width: 100%; } /* 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 { font-size: clamp(0.8rem, 3.6vw, 0.95rem); max-width: 100%; } /* Correctif (2026-08-04, capture Antoine REMY) : le nowrap+ellipsis ci-dessus etait volontairement pense (voir commentaire d'origine juste avant cette regle) pour les 3 cartes "univers" (Explorer l'ile / Surf / Randonnee), afin d'eviter un retour a la ligne indesirable. Mais .miguel-card__title est une classe PARTAGEE par remplirChoix(), utilisee par TOUS les ecrans du wizard (styles, voyageur, niveaux, objectifs) -- la regle s'appliquait donc aussi a des libelles bien plus longs ("Ocean & baignades sauvages", "Photos & points de vue"...), qui se retrouvaient coupes avec "...". Correctif : le nowrap+ellipsis est desormais restreint au conteneur reel des 3 cartes univers ([data-miguel-univers-grid], attribut deja present dans le HTML, distinct du [data-miguel-choices] generique utilise par tous les autres ecrans) ; partout ailleurs, le libelle peut desormais s'enrouler normalement sur 2 lignes si necessaire -- comportement standard et attendu pour des cartes de choix, pas de risque connu de vide vertical ici puisque .miguel-card n'a pas de hauteur fixe (padding uniquement, confirme par la regle .miguel-card plus haut). */ [data-miguel-univers-grid] .miguel-card__title { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } /* 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; } } /* Correctif P4 (2026-07-24, audit mobile) : .miguel-card n'avait pas de min-width:0 -- par defaut, une cellule de grille CSS ne peut pas retrecir sous la largeur min-content de son contenu (ex. un long libelle .miguel-card__note comme "Photos & points de vue"), ce qui peut forcer la grille entiere a deborder horizontalement du panneau et donner l'impression de cartes coupees/tronquees. min-width:0 (ajoute ci-dessus sur .miguel-card) + overflow-wrap:anywhere sur .miguel-card__note (ajoute ci-dessus) permettent au texte de revenir a la ligne au lieu de forcer un debordement, sur toutes les largeurs (375/390/430px). Le passage a 1 seule colonne sous 479px (regle existante, non modifiee) couvre deja tous les iPhone actuels (SE 375, standard 390, Pro Max 428) -- ce correctif est une securite additionnelle pour les cas extremes (zoom navigateur, texte agrandi via accessibilite, futurs breakpoints intermediaires), sans changer le pattern d'interaction (grille conservee, pas de carrousel). */
.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) and (pointer: fine),
  (min-width: 768px) and (pointer: coarse) and (any-hover: none) and (max-aspect-ratio: 8/5) {
  .toast { left: auto; right: calc(420px + var(--space-6)); bottom: var(--space-5); transform: translateY(12px); }
  .toast.is-visible { transform: translateY(0); }
} /* Convergence mode tablette (01/08/2026) : la regle etait deja ambigue (aucune condition pointer), ce qui aurait pu entrer en collision avec la nouvelle regle tablette -- rendue explicite (pointer:fine) puis etendue telle quelle a la tablette, qui utilise le meme panneau plein hauteur que le desktop des 768px (cf. #map-app). Aucune valeur modifiee. */

/* ============================================================
   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é. */
/* Phase 3A-ter (2026-07-23, demande Antoine -- harmonisation visuelle des zones secondaires) :
   meme registre que la timeline principale (Phase 3A-bis) -- plus de fond colore ni de cadre
   par option, un simple trait fin separe chaque ligne. "Les choix de Miguel(TM) aujourd'hui"
   doit rester une liste qui donne envie d'explorer, jamais une carte qui rivalise avec la
   recommandation principale au-dessus. */
.choix-miguel-item { min-width: 0; display: flex; flex-direction: column; gap: var(--space-1); padding: var(--space-3) 0; border: 0; border-bottom: 1px solid var(--color-border); border-radius: 0; background: none; font-size: var(--map-text-base); transition: opacity 0.15s ease; overflow-wrap: anywhere; cursor: pointer; }
.choix-miguel-item:last-child { border-bottom: 0; padding-bottom: 0; }
.choix-miguel-item:hover { opacity: 0.82; }
/* 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-left: 3px solid var(--color-primary); padding-left: var(--space-3); background: none; }
.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); }

/* "Explorer une autre idee" (2026-07-24, chantier UX, demande Antoine -- "eviter l'effet bouton
   application classique", inspiration produits voyage premium type Komoot/Polarsteps) : pas de
   fond ni de cadre de bouton, un controle typographique discret en pied de bulle, chevrons fins
   qui s'ecartent legerement au survol/focus pour suggerer un mouvement d'exploration -- jamais un
   CTA qui rivalise visuellement avec la recommandation principale au-dessus. */
.choix-miguel-item__contenu { transition: opacity 0.18s ease, transform 0.18s ease; }
.choix-miguel-item__contenu--transition { opacity: 0; transform: translateX(6px); }
/* Correctif hierarchie visuelle (2026-07-24, retour Antoine -- "pas un probleme technique mais
   un probleme de hierarchie visuelle") : le controle utilisait --color-text-muted, exactement la
   meme couleur que le texte purement informatif voisin (.choix-miguel-item__creneau juste
   au-dessus) -- il se fondait dans du texte statique au lieu de signaler une action. Alignement
   sur la convention deja etablie par .choix-miguel-item__toggle ("Pourquoi ce choix ?", couleur
   d'accent + souligne) MAIS volontairement un cran plus discret : meme couleur d'accent, poids
   600 (au lieu de 700) et surtout AUCUN soulignement permanent (seulement au survol/focus) --
   pour rester dans l'esprit "exploration discrete", pas un second lien identique au premier. */
.choix-miguel-item__explorer { display: flex; align-items: center; justify-content: center; gap: var(--space-1); width: 100%; margin-top: var(--space-2); padding: 0.55rem 0; min-height: 44px; border: 0; background: none; cursor: pointer; font: inherit; font-size: var(--map-text-xs); font-weight: 600; letter-spacing: 0.04em; text-transform: uppercase; color: var(--color-primary); text-decoration: none; text-underline-offset: 3px; transition: color 0.2s ease, text-decoration-color 0.2s ease; }
.choix-miguel-item__explorer:hover, .choix-miguel-item__explorer:focus-visible { text-decoration: underline; }
.choix-miguel-item__explorer-chevron { font-weight: 300; font-size: 1.1rem; line-height: 1; transition: transform 0.25s ease; }
.choix-miguel-item__explorer:hover .choix-miguel-item__explorer-chevron:first-child, .choix-miguel-item__explorer:focus-visible .choix-miguel-item__explorer-chevron:first-child { transform: translateX(-3px); }
.choix-miguel-item__explorer:hover .choix-miguel-item__explorer-chevron:last-child, .choix-miguel-item__explorer:focus-visible .choix-miguel-item__explorer-chevron:last-child { transform: translateX(3px); }
.choix-miguel-item__retour { display: block; margin: 0.2rem 0 0; padding: 0; border: 0; background: none; cursor: pointer; font: inherit; font-size: var(--map-text-2xs); color: var(--color-text-muted); text-decoration: underline; }
.choix-miguel-item__retour[hidden] { display: none; }
.choix-miguel-item__intro-alt { margin: 0 0 0.2rem; font-size: var(--map-text-2xs); font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: var(--color-text-muted); }
.choix-miguel-item__difference { margin: 0.2rem 0 0; font-size: var(--map-text-sm); font-style: italic; color: var(--color-text-muted); }

/* Miniature editoriale des cartes "Choix de Miguel(TM)" (2026-07-24, chantier photo) : meme
   resolution que la fiche spot et le Plan du Jour (resoudrePhotoEditorialeSpot()) -- vignette
   discrete au-dessus du titre, jamais de credit ici (carte trop petite pour rester lisible).
   Si aucune photo verifiee n'existe pour ce spot, aucun element n'est genere par carte.js et la
   carte s'affiche exactement comme avant ce lot. */
.choix-miguel-item__media { position: relative; display: block; width: 100%; aspect-ratio: 16 / 9; overflow: hidden; border-radius: var(--radius-md, 0.5rem); background: var(--color-primary-soft); margin-bottom: var(--space-2, 0.5rem); } /* Patch C1.5 (2026-07-25) : position:relative ajoute pour ancrer .media-credit-btn/.media-credit-tip (position:absolute), meme principe que .journee-etape__media et .detail-media, cf. carte.css plus haut. */
.choix-miguel-item__media img { width: 100%; height: 100%; object-fit: contain; object-position: center; display: block; }

/* Vignette chiffree du score Miguel(TM) (2026-07-24, demande Antoine -- reintegration du score
   visible dans toute l'experience). Palette REUTILISEE des tokens premium existants
   (--color-primary/--color-primary-soft pour le vert, --map-state-warning-* et
   --map-state-danger-* deja utilises ailleurs pour les alertes -- jamais de rouge/vert/orange
   satures "feu tricolore", conformement a la demande explicite). Un seul composant partage par
   la bulle de carte, les cartes "Choix de Miguel™", la fiche spot et le Plan du Jour. */
.score-badge { display: inline-flex; align-items: center; gap: 0.3em; padding: 0.15rem 0.55rem; border-radius: var(--radius-pill); font-weight: 700; font-size: var(--map-text-sm); line-height: 1.4; white-space: nowrap; }
.score-badge__dot { width: 0.5em; height: 0.5em; border-radius: 50%; flex-shrink: 0; }
.score-badge__sur100 { font-weight: 500; opacity: 0.75; font-size: 0.85em; }
.score-badge--haut { background: var(--color-primary-soft); color: var(--color-primary-strong); }
.score-badge--haut .score-badge__dot { background: var(--color-primary); }
.score-badge--moyen { background: var(--map-state-warning-bg); color: var(--map-state-warning-text); }
.score-badge--moyen .score-badge__dot { background: var(--map-state-warning-text); }
.score-badge--bas { background: var(--map-state-danger-bg); color: var(--map-state-danger-text); }
.score-badge--bas .score-badge__dot { background: var(--map-state-danger-text); }
.score-badge--detaille { font-size: var(--map-text-base); padding: 0.25rem 0.7rem; }

/* Score dans la bulle de previsualisation (carte) -- ligne secondaire, sous le titre/badge,
   jamais a la place du nom (demande explicite "ne pas prendre la place du nom"). */
.spot-tooltip__score { display: flex; align-items: center; gap: 0.4em; margin-top: 0.2rem; font-size: var(--map-text-sm); color: var(--color-text-muted); flex-wrap: wrap; }
.spot-tooltip__score-label { font-weight: 500; }

/* Score en fiche spot -- juste sous la photo/le titre, avant le lien vers l'explication deja
   presente plus bas dans la fiche. */
.detail-score { display: flex; align-items: center; gap: var(--space-2, 0.5rem); margin: var(--space-2, 0.5rem) 0; flex-wrap: wrap; }
.detail-score__link { margin: 0; padding: 0; border: 0; background: none; font: inherit; font-size: var(--map-text-sm); font-weight: 700; color: var(--color-primary); text-decoration: underline; cursor: pointer; }

/* Score du Plan du Jour -- seule zone ou le format detaille "X/100" est autorise (demande
   explicite), presentee comme un bloc identifiable a part, sous l'accroche principale. */
.plan-score { margin: var(--space-2, 0.5rem) 0 var(--space-3, 1rem); display: flex; flex-direction: column; align-items: flex-start; gap: 0.2rem; }
.plan-score__eyebrow { margin: 0; font-size: var(--map-text-sm); font-weight: 600; color: var(--color-text-muted); text-transform: uppercase; letter-spacing: 0.03em; }
.plan-score__label { margin: 0.1rem 0 0; font-size: var(--map-text-sm); color: var(--color-text-muted); }
.plan-score__link { margin: 0.2rem 0 0; padding: 0; border: 0; background: none; font: inherit; font-size: var(--map-text-sm); font-weight: 700; color: var(--color-primary); text-decoration: underline; cursor: pointer; }

/* 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; }
/* Section "Liens officiels" (2026-07-31, demande Antoine REMY) : meme registre typographique que
   .miguel-explication__eyebrow (kicker discret) pour le titre, liste simple sans puce pour rester
   coherent avec le reste de la fiche spot (aucun nouveau pattern visuel invente). Masquee entierement
   via [hidden] si aucun lien n'existe pour le spot -- voir openDetail() dans carte.js. */
.detail-liens-officiels { margin: var(--space-2) 0; }
.detail-liens-officiels__titre { margin: 0 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-liens-officiels__list { list-style: none; margin: 0; padding: 0; display: flex; flex-direction: column; gap: 4px; }
.detail-liens-officiels__list a { color: var(--color-primary); text-decoration: underline; font-size: var(--map-text-sm); }
.detail-liens-officiels__list a:hover, .detail-liens-officiels__list a:focus-visible { text-decoration-thickness: 2px; }
/* Bloc "Conditions d'acces" (2026-07-31, demande Antoine REMY) : information REGLEMENTAIRE,
   volontairement distincte du bloc meteo (.miguel-explication, "A surveiller :") et du bloc
   descriptif (adresse/duree/facts) -- voir NOTE-technique-conditionsAcces-31-07.md. Positionne
   juste apres le titre, avant la photo : c'est la premiere chose lue, avant que l'utilisateur ne
   se projette sur la sortie. Toujours visible si le spot a conditionsAcces.requis === true,
   jamais conditionne au score du jour (idem emoji Unicode direct, coherent avec le reste du
   fichier qui n'utilise pas de nouvelle icone SVG pour ce type de repere -- cf. 🟢/🟠/🔴 dans
   dhtRenderExplicationDOM()). */
.detail-conditions-acces { margin: var(--space-2) 0; padding: 10px 12px; border-radius: 10px; background: color-mix(in srgb, var(--color-warning, #b45309) 12%, transparent); border: 1px solid color-mix(in srgb, var(--color-warning, #b45309) 35%, transparent); }
.detail-conditions-acces__titre { margin: 0 0 2px; font-weight: 700; font-size: var(--map-text-sm); color: var(--color-warning, #b45309); }
.detail-conditions-acces__texte { margin: 0; font-size: var(--map-text-sm); color: var(--color-text); }
/* Rappel narratif de Miguel™ (meme information, formulation differente) : simple paragraphe
   supplementaire dans le bloc d'explication existant, jamais mélangé aux motifs meteo. */
.miguel-explication__conditions-acces { margin: var(--space-1) 0 0; font-size: var(--map-text-sm); font-weight: 600; }
.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) and (pointer: fine) {
  .toast { left: auto; right: calc(420px + var(--space-6)); }
} /* Convergence mode tablette (01/08/2026) : regle reservee aux petites fenetres desktop (carte flottante, cf. L.918) -- rendue explicite (pointer:fine) pour ne jamais etre heritee par erreur par la tablette, qui passe directement par la regle toast 1024px etendue (panneau plein hauteur des 768px, jamais l'etat carte flottante). Aucune valeur modifiee. */

/* 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); }
/* Feedback tactile mobile : le premier contact sur un spot doit etre perceptible immediatement,
   sans introduire de logique JS ni modifier le comportement desktop/tablette. */
@media (max-width: 767px) {
  .pin:active, .pin-dim:active { transform: scale(1.18); }
}
.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: var(--color-accent); 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-lien { transition: color 0.15s ease, text-decoration-color 0.15s ease; }
/* Phase 2C-1 quinquies (2026-07-22) : simple lien texte, pas de fond au survol (ce n'est plus une
   carte/ligne de liste, juste une invitation textuelle discrete). */
.alternative-lien:hover { color: var(--color-primary); text-decoration-color: currentColor; }
/* 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. */
/* Phase 3A-ter (2026-07-23, demande Antoine -- "harmonisation visuelle des zones
   secondaires") : le fond colore plein (var(--color-primary-soft)) et le cadre disparaissent --
   ce bloc partage (fiche spot + accordeon "Les choix de Miguel") se pose desormais a plat sur
   le fond de la page, comme le reste de la refonte editoriale (Phase 3A-bis). La hierarchie
   interne (.miguel-explication__niveau, deja son propre trait discret en pointilles juste en
   dessous) reste le seul repere visuel necessaire -- aucun second cadre autour. */
.miguel-explication { margin: 0; padding: 0; border-radius: 0; background: none; font-size: var(--map-text-base); height: auto; max-height: none; overflow: visible; } /* Correctif chevauchement fiche spot desktop (2026-07-12, conserve) : .miguel-explication reste un simple <div> sans regle de hauteur ecrite ICI, pour ne jamais dependre d'une regle generique externe (style.css) qui imposerait height/max-height + overflow:hidden a un conteneur "carte"/"panel" generique -- meme raisonnement qu'avant ce lot, uniquement le fond/cadre visuel change ici. Aucun texte, aucune police, aucun contenu masque. */
/* Phase 1 bis B (2026-07-22) : le score brut Miguel(TM) ("Score Miguel(TM) : 87/100") ne doit
   plus etre expose a l'utilisateur -- regle validee : traduire la decision, jamais montrer la
   mecanique interne (score/pourcentage). dhtRenderExplicationDOM() continue de le calculer et de
   l'ecrire dans le DOM (aucune fonction JS modifiee), on le masque uniquement en CSS. Le repere
   convivial .miguel-explication__niveau (deja purement editorial depuis "UX confiance v2",
   2026-07-11) devient donc le SEUL element visible de ce role, promu ici au rang de sous-titre
   principal (poids/couleur renforces) puisqu'il n'a plus le score au-dessus de lui. */
.miguel-explication__score { display: none; }
/* Phase 2A.1 -- la confiance devient une transition visuelle entre la decision (badge + phrase,
   au-dessus) et la justification (points forts, en dessous) : puce pleine + separation discrete,
   sans jamais sortir .miguel-explication__niveau de son bloc d'explication commun (demande
   explicite Antoine -- "la confiance reste une transition, pas un element isole"). Couleur teal
   (--color-primary), jamais orange : reprend exactement la meme regle que la coche des points
   forts juste en dessous (voir Phase 1 bis B), pour une lecture visuelle continue du bloc. */
.miguel-explication__niveau { display: flex; align-items: center; gap: 0.55em; margin: 0 0 var(--space-3); padding-bottom: var(--space-2); border-bottom: 1px dashed rgba(15, 95, 92, 0.18); font-size: 1.05rem; font-weight: 700; color: var(--color-text); }
.miguel-explication__niveau::before { content: ""; flex-shrink: 0; width: 0.6em; height: 0.6em; border-radius: 50%; background: var(--color-primary); }
.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; }
/* Phase 1 bis B (2026-07-22) : repere visuel "coche" devant chaque point fort, pur CSS ::before
   (aucun texte/contenu ajoute en JS). Couleur teal (--color-primary), jamais orange : cette liste
   explique une decision, elle n'est pas elle-meme le badge "Choix de Miguel(TM)". */
.miguel-explication__points > li { display: flex; align-items: flex-start; gap: 0.45em; }
.miguel-explication__points > li::before { content: "✓"; flex-shrink: 0; color: var(--color-primary); font-weight: 700; }
.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); }
/* Patch C2.2 (2026-07-25, demande Antoine) : meme intention visuelle que .miguel-hero__accroche
   (couleur de texte normale, PAS text-muted -- c'est une phrase de raisonnement Miguel(TM), pas
   une information secondaire comme le creneau/niveau juste au-dessus), simplement une taille
   adaptee a une carte plus petite. font-style non italique ici (contrairement au hero) pour ne
   pas se confondre visuellement avec .choix-miguel-item__difference (alternative), qui reste,
   elle, en italique. */
.choix-miguel-item__resume { margin: 0.35rem 0 0; font-size: var(--map-text-sm); line-height: 1.45; color: var(--color-text); }
.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 { margin: 0 0 var(--space-2); font-size: var(--map-text-sm); font-weight: 700; color: var(--color-primary); }
.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; } .detail-webcam-vision-status { margin: calc(var(--space-3) * -0.5) 0 var(--space-3); font-size: var(--map-text-sm); color: var(--color-text-secondary); }
.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 { 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-lien: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-lien: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);
  }
}

/* ==========================================================================
   Compacite Desktop/Tablette -- composants Fiche Premium Surf/Rando (04/08/2026,
   retour Antoine REMY : "le mobile a ete calibre en premier, mais les composants
   premium Surf/Rando reutilisent probablement des tailles qui etaient optimisees
   pour la lecture tactile ... en desktop/tablette, il faut reduire uniquement les
   variantes grands ecrans, sans toucher aux regles mobiles"). Couche strictement
   ADDITIVE placee en fin de fichier : memes composants, memes couleurs, memes
   contenus, memes classes -- uniquement des surcharges de taille pour les largeurs
   >= 768px, qui gagnent naturellement sur les regles plus haut dans ce fichier
   (specificite identique -- un seul selecteur de classe -- mais declarees plus
   tard : ordre de cascade, aucun !important necessaire). Aucune des regles
   ci-dessous ne s'applique sous 768px : le mobile (calibrage tactile "pouce",
   breakpoint <768px) reste a 100% inchange.
   Perimetre volontairement limite a 3 familles de composants partagees par la
   fiche Surf ET la fiche Rando (donc aussi par une fiche mixte Surf>Rando, qui
   reutilise exactement le meme HTML/CSS) : photo de la fiche (.detail-media),
   bouton d'ouverture du Guide (.detail-surf-cta__toggle), chips meteo/technique/
   logistique (.detail-surf-bloc__*). Aucune modification de carte.js, du HTML,
   des classes elles-memes, ni du breakpoint mobile existant.
   Verifie sur : fiche Surf, fiche Rando, fiche mixte Surf>Rando (memes classes
   partagees => memes reductions automatiquement), et tablette paysage (768-1199px
   -- palier "Tablette" ci-dessous ; un iPad en paysage grand format >=1200px de
   large suit alors logiquement le palier "Desktop", coherent avec une logique
   volontairement basee sur la seule largeur, comme demande). */

/* --- Palier Tablette (768-1199px) : reduction legere --- */
@media (min-width: 768px) {
  /* 1. Photo de la fiche (.detail-media, partagee par toutes les fiches spot, y
     compris Surf/Rando Premium ET la carte de recommandation Miguel -- meme
     composant partout) : remplace le max-height en vh (jusqu'a 46vh, tres haut
     sur grand ecran) par une hauteur fixe raisonnable -- meme object-fit:cover
     deja en place (carte.css, regle .detail-media img).
     Valeur ajustee le 04/08/2026 (retour Antoine sur capture desktop reelle,
     photo encore trop haute a 260px) : 150px sur ce premier palier. */
  .detail-media { max-height: 150px; }

  /* 2. Bouton d'ouverture du Guide Surf/Rando (.detail-surf-cta__toggle) : plus
     besoin d'une cible "pouce mobile" au clavier/souris -- meme composant, memes
     couleurs, texte identique, seul le gabarit est reduit. */
  .detail-surf-cta__toggle { padding: 8px 14px; min-height: 42px; }
  .detail-surf-cta__icon svg { width: 18px; height: 18px; }

  /* 2bis. Boutons d'action du bandeau superieur de la fiche/du panneau (04/08/2026,
     retour Antoine sur capture desktop reelle : "Actualiser", "Randonnee"
     [= .plan-card__profil-modifier, affiche l'univers actif du profil Miguel --
     PAS un bouton lie au spot ouvert] et "Fermer" restaient a la taille "pouce
     mobile", min-height:44px, memes 3 selecteurs). Memes boutons, memes couleurs,
     meme texte -- uniquement le gabarit est reduit. */
  .weather-refresh,
  .plan-card__profil-modifier,
  .detail-close { min-height: 42px; }

  /* 3. Chips (Conditions Rando Miguel(TM), fiche technique Surf/Rando, synthese
     logistique) : memes chips, memes couleurs, memes contenus -- espacement et
     texte legerement reduits. */
  .detail-surf-bloc__grille { gap: var(--space-1, 0.25rem); }
  .detail-surf-bloc__item-label { font-size: var(--map-text-2xs, 0.7rem); }
}

/* --- Palier Desktop (>= 1200px) : reduction plus nette --- */
@media (min-width: 1200px) {
  /* Valeur ajustee le 04/08/2026 (idem ci-dessus) : 170px sur ce second palier. */
  .detail-media { max-height: 170px; }
  .detail-surf-cta__toggle { padding: 6px 12px; min-height: 38px; }
  .weather-refresh,
  .plan-card__profil-modifier,
  .detail-close { min-height: 38px; }
  .detail-surf-bloc__item-valeur { font-size: var(--map-text-xs, 0.75rem); }
  .detail-surf-fiche__bloc--technique { padding: var(--space-2, 0.5rem); }
}


/* ==========================================================================
   Placeholder photo "Aucune photo disponible" (04/08/2026, demande Antoine
   REMY -- "je ne laisserais jamais un cadre vide" / "la photo est une partie
   essentielle de la decision de l'utilisateur"). Couche ADDITIVE : reutilise
   EXACTEMENT les memes conteneurs que les vraies photos -- .detail-media
   (fiche spot), .journee-etape__media--grande (photo vedette du Plan du
   Jour), .choix-miguel-item__media (cartes "Choix de Miguel(TM)") --, memes
   aspect-ratio 16/9, memes border-radius, memes regles responsives desktop/
   tablette (cf. bloc Compacite Desktop/Tablette plus haut, applicable telles
   quelles a .detail-media que la photo soit reelle ou de remplacement).
   AUCUNE difference de gabarit possible entre un spot avec photo et un spot
   sans photo : seul le contenu interne change (fond degrade + logo DHT en
   tres leger filigrane + icone appareil photo + texte). Le modificateur
   .dht-media--vide est pose par carte.js sur le MEME element que la photo
   (jamais un nouvel element parallele), donc herite deja de tout le
   dimensionnement existant.
   Perimetre volontairement limite aux 3 surfaces de decision identifiees
   avec Antoine (fiche spot, photo vedette du jour, cartes Choix de
   Miguel(TM)) -- PAS les vignettes secondaires du Plan du Jour
   (.journee-etape__media--petite), qui restent en texte seul comme avant
   (comportement deja acceptable, hors scope de cette demande). */
.detail-media.dht-media--vide,
.journee-etape__media--grande.dht-media--vide,
.choix-miguel-item__media.dht-media--vide {
  position: relative;
  background: linear-gradient(135deg, var(--color-primary-soft) 0%, var(--color-surface-muted) 100%);
}
/* Correctif (04/08/2026, bug remonte par Antoine via capture -- icone d'image cassee visible en
   haut a gauche du placeholder) : la regle historique ".detail-media img { display: block; }"
   (deja presente avant ce sprint) est une regle d'AUTEUR, donc elle l'emporte systematiquement
   sur l'attribut HTML "hidden" pose en JS (une regle CSS d'auteur bat toujours le style par
   defaut du navigateur associe a [hidden], quelle que soit la specificite). Resultat : l'img vide
   (src="") restait donc affichee -- petite icone "image cassee" du navigateur -- superposee au
   placeholder. Corrige en la masquant explicitement ici, uniquement quand .dht-media--vide est
   actif (le cas normal avec une vraie photo n'est pas touche). */
.detail-media.dht-media--vide img {
  display: none;
}
.detail-media.dht-media--vide::before,
.journee-etape__media--grande.dht-media--vide::before,
.choix-miguel-item__media.dht-media--vide::before {
  content: "";
  position: absolute;
  inset: 0;
  background-image: url("Logo_dht_azores.png");
  background-repeat: no-repeat;
  background-position: center;
  background-size: 34%;
  opacity: 0.1;
  pointer-events: none;
}
.dht-media-manquant {
  position: relative;
  z-index: 1;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 6px;
  width: 100%;
  height: 100%;
  padding: var(--space-2, 0.5rem);
  text-align: center;
  color: var(--color-text-muted);
}
.dht-media-manquant__icon {
  width: 26px;
  height: 26px;
  stroke: currentColor;
  fill: none;
  stroke-width: 1.6;
  opacity: 0.6;
}
.dht-media-manquant__titre {
  font-weight: 700;
  font-size: var(--map-text-sm, 0.85rem);
  color: var(--color-text);
  margin: 0;
  line-height: 1.25;
}
.dht-media-manquant__texte {
  font-size: var(--map-text-2xs, 0.7rem);
  max-width: 24ch;
  margin: 0;
  line-height: 1.3;
}
/* Vignette tres compacte (carte Choix de Miguel(TM), plus petite que la fiche/le moment fort) :
   texte secondaire masque, seuls le titre court et l'icone restent lisibles a cette taille. */
.choix-miguel-item__media.dht-media--vide .dht-media-manquant__texte { display: none; }
.choix-miguel-item__media.dht-media--vide .dht-media-manquant__icon { width: 20px; height: 20px; }
.choix-miguel-item__media.dht-media--vide .dht-media-manquant__titre { font-size: var(--map-text-2xs, 0.7rem); }

/* Correctif audit wizard (Sprint 3, 2026-08-04, demande Antoine) : .miguel-wizard__grid restait
   figee a 2 colonnes quelle que soit la largeur d'ecran (voir regle de base plus haut, seule
   exception connue : @media max-width:479px qui repasse a 1 colonne). Deux problemes reels
   identifies par audit direct du CSS (aucune capture disponible pour cette session, verification
   faite sur le code) :
   1) Sur tablette/desktop, des cartes toujours forcees en 2 colonnes sur un panneau large
      deviennent disproportionnees (tres larges, peu de hauteur) -- "tailles incoherentes".
   2) Nombre impair de cartes sur plusieurs ecrans du wizard (rythmes:3, niveaux surf:3, objectifs
      surf:3, et desormais STYLES:7 depuis l'ajout de "Saveurs locales" en Sprint 3 -- ce dernier
      ecran passait de 6 cartes, pair, a 7, impair) => la derniere carte se retrouve seule sur sa
      ligne, alignee a gauche, avec un vide a droite : exactement la "grille cassee" signalee.
   Correctif en 2 volets, CSS uniquement (aucun changement de logique/JS, aucun risque fonctionnel) :
   a) 3 colonnes a partir de la tablette (768px), conservees en desktop (aucune 4e colonne ajoutee
      pour rester sur une taille de carte proportionnee, cf. demande "rendu premium homogene").
   b) Centrage automatique de la derniere carte quand elle est seule sur sa ligne, pour les deux
      largeurs de grille (2 colonnes = mobile/petite tablette, 3 colonnes = tablette/desktop) --
      regle generique par position (nth-child), qui s'applique a N'IMPORTE QUEL ecran du wizard
      ayant un nombre impair de cartes, present ou futur, sans cas particulier code en dur.
   Mobile (<479px, 1 colonne) : explicitement non touche, aucune carte ne peut y etre "seule sur
   sa ligne" puisqu'il n'y a qu'une carte par ligne -- conforme a la demande "sans degrader mobile". */
@media (min-width: 768px) {
  .miguel-wizard__grid { grid-template-columns: 1fr 1fr 1fr; }
}
@media (min-width: 480px) and (max-width: 767px) {
  .miguel-wizard__grid > *:last-child:nth-child(odd) {
    grid-column: 1 / -1;
    justify-self: center;
    width: calc(50% - (var(--space-2) / 2));
  }
}
@media (min-width: 768px) {
  .miguel-wizard__grid > *:last-child:nth-child(3n + 1) {
    grid-column: 1 / -1;
    justify-self: center;
    width: calc((100% - (2 * var(--space-2))) / 3);
  }
}



/* Lightbox premium autonome, construite sur la galerie déjà générée par l’application. */
.dht-premium-lightbox {
  position: fixed;
  inset: 0;
  z-index: 1300;
  isolation: isolate;
  display: grid;
  place-items: center;
  padding: max(var(--space-4), env(safe-area-inset-top)) max(var(--space-4), env(safe-area-inset-right)) max(var(--space-4), env(safe-area-inset-bottom)) max(var(--space-4), env(safe-area-inset-left));
  background: rgba(8, 22, 29, 0.9);
  color: var(--color-text-inverse, #fff);
  overscroll-behavior: contain;
  touch-action: none;
}
.dht-premium-lightbox[hidden] { display: none; }
.dht-premium-lightbox__panel {
  position: relative;
  width: auto;
  height: auto;
  max-width: min(100%, 1120px);
  max-height: min(100%, 900px);
  display: grid;
  grid-template-rows: minmax(0, 1fr) auto;
  gap: var(--space-3);
  padding: clamp(16px, 3vw, 30px);
  border: 1px solid rgba(255, 255, 255, 0.14);
  border-radius: 26px;
  background: rgba(18, 35, 42, 0.96);
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.42);
  animation: dht-premium-lightbox-in 180ms ease-out;
}
.dht-premium-lightbox__stage {
  position: relative;
  min-width: 0;
  min-height: 0;
  width: 100%;
  height: 100%;
  display: grid;
  place-items: center;
  overflow: hidden;
  border-radius: 18px;
  background: rgba(3, 12, 17, 0.72);
}
.dht-premium-lightbox__img {
  /* La scène est dimensionnée par JS sur le ratio natif de la photo.
     L'image remplit donc une scène de même ratio : aucun crop, aucune
     déformation, quelle que soit l'orientation. */
  display: block;
  width: 100%;
  height: 100%;
  max-width: 100%;
  max-height: 100%;
  margin: 0;
  object-fit: contain;
  object-position: center center;
  user-select: none;
  -webkit-user-drag: none;
}
.dht-premium-lightbox__close,
.dht-premium-lightbox__nav {
  display: inline-grid;
  place-items: center;
  border: 1px solid rgba(255, 255, 255, 0.18);
  color: #fff;
  background: rgba(18, 35, 42, 0.86);
  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.28);
  cursor: pointer;
  transition: transform 160ms ease, background 160ms ease, border-color 160ms ease;
}
.dht-premium-lightbox__close:hover,
.dht-premium-lightbox__nav:hover {
  transform: translateY(-1px);
  background: rgba(37, 67, 73, 0.96);
  border-color: rgba(255, 255, 255, 0.34);
}
.dht-premium-lightbox__close:focus-visible,
.dht-premium-lightbox__nav:focus-visible {
  outline: 2px solid rgba(255, 255, 255, 0.9);
  outline-offset: 3px;
}
.dht-premium-lightbox__close {
  position: absolute;
  top: max(12px, env(safe-area-inset-top));
  right: max(12px, env(safe-area-inset-right));
  z-index: 3;
  width: 44px;
  height: 44px;
  padding: 0;
  border-radius: 50%;
}
.dht-premium-lightbox__nav {
  position: absolute;
  top: 50%;
  z-index: 2;
  width: 46px;
  height: 46px;
  padding: 0;
  border-radius: 50%;
  transform: translateY(-50%);
}
.dht-premium-lightbox__nav:hover { transform: translateY(calc(-50% - 1px)); }
.dht-premium-lightbox__nav[hidden] { display: none; }
.dht-premium-lightbox__nav--prev { left: 14px; }
.dht-premium-lightbox__nav--next { right: 14px; }
.dht-premium-lightbox__meta {
  min-height: 22px;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: var(--space-2);
  padding-inline: 56px;
}
.dht-premium-lightbox__credit,
.dht-premium-lightbox__counter {
  margin: 0;
  color: rgba(255, 255, 255, 0.76);
  font-size: 0.78rem;
  line-height: 1.35;
  text-align: center;
}
.dht-premium-lightbox__counter { font-weight: 700; letter-spacing: 0.04em; }
.dht-premium-lightbox__credit[hidden],
.dht-premium-lightbox__counter[hidden] { display: none; }
body.dht-premium-lightbox-open { overflow: hidden; }

/* MIGUEL PREMIUM LIGHTBOX — adaptive native-ratio geometry (2026-08-26)
   The panel follows the native aspect ratio of the current photo while remaining
   fully constrained by the viewport. The image is never cropped or distorted. */
@media (min-width: 1024px) and (pointer: fine) {
  .dht-premium-lightbox__panel {
    box-sizing: border-box;
    max-width: calc(100vw - 32px);
    max-height: calc(100dvh - 32px);
  }
  .dht-premium-lightbox__stage {
    display: grid;
    place-items: center;
  }
  .dht-premium-lightbox__img {
    justify-self: center;
    align-self: center;
  }
}

@keyframes dht-premium-lightbox-in {
  from { opacity: 0; transform: scale(0.985); }
  to { opacity: 1; transform: scale(1); }
}
@media (max-width: 700px) {
  .dht-premium-lightbox {
    padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
  }
  .dht-premium-lightbox__panel {
    max-width: 100%;
    max-height: 100%;
    border-radius: 0;
    padding: 16px;
    padding-top: max(56px, calc(env(safe-area-inset-top) + 44px));
    padding-bottom: max(16px, env(safe-area-inset-bottom));
    background: rgba(8, 22, 29, 0.98);
  }
  .dht-premium-lightbox__stage { border-radius: 12px; }
  .dht-premium-lightbox__nav { width: 42px; height: 42px; }
  .dht-premium-lightbox__nav--prev { left: 10px; }
  .dht-premium-lightbox__nav--next { right: 10px; }
}
@media (prefers-reduced-motion: reduce) {
  .dht-premium-lightbox__panel,
  .dht-premium-lightbox__close,
  .dht-premium-lightbox__nav { animation: none; transition: none; }
}

/* Pré-voyage Miguel™ — contexte d'expérience (2026-08-19) : deux portes d'entrée explicites,
   sans modifier le pattern existant des autres écrans du wizard. */
.miguel-wizard__grid--context { margin-top: var(--space-4); }
.miguel-card--context { min-height: 150px; justify-content: center; padding: var(--space-4) var(--space-3); }
.miguel-card--context .miguel-card__icon { width: 30px; height: 30px; margin-bottom: 4px; }
.miguel-card--context .miguel-card__title { white-space: normal; overflow: visible; text-overflow: clip; }
.miguel-card--context .miguel-card__note { line-height: 1.45; }
.miguel-wizard__choix-ile-neutre { margin-top: var(--space-3); width: 100%; }

/* MIGUEL LIVE V2 — espacement structurel + grille Date/Île (2026-08-19) :
   Audit : LIVE est inséré comme premier enfant de .sheet-content, puis
   .weather-disagreement, puis .webcam-link. La passe précédente ciblait par erreur
   .webcam-link : elle ne créait donc pas l'espace demandé entre LIVE et « Conditions actuelles ».
   Le correctif cible désormais uniquement le couple LIVE -> weather-disagreement lorsqu'il est visible.
   La grille Date/Île reçoit en parallèle des tracks minmax(0,1fr) et min-width:0 pour neutraliser
   le min-content sizing du champ date sur Safari/iOS. Desktop pointer:fine inchangé. */
@media (max-width: 767px) {
  .miguel-live:not([hidden]) + .weather-disagreement:not([hidden]) { margin-top: 18px; }
  .miguel-live__trip-fields { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) !important; }
  .miguel-live__trip-fields > label,
  .miguel-live__trip-fields > div { min-width: 0; }
  .miguel-live__trip-fields input[type="date"] { min-width: 0; }
}
@media (min-width: 768px) and (pointer: coarse) and (any-hover: none) and (max-aspect-ratio: 8/5) {
  .miguel-live:not([hidden]) + .weather-disagreement:not([hidden]) { margin-top: 22px; }
  .miguel-live__trip-fields { grid-template-columns: minmax(0, 1fr) minmax(0, 1fr) !important; }
  .miguel-live__trip-fields > label,
  .miguel-live__trip-fields > div { min-width: 0; }
  .miguel-live__trip-fields input[type="date"] { min-width: 0; }
}


/* ==========================================================================
   MIGUEL™ LIVE — V3 compact / repliable (2026-08-19)
   --------------------------------------------------------------------------
   Le module reste fonctionnellement identique. Seul son rendu est repliable :
   fermé par défaut, ouvert après interaction ou lorsqu'une alerte LIVE existe.
   Le formulaire Date/Île conserve son contrat responsive existant.
   ========================================================================== */
.miguel-live { margin: 0 0 var(--space-3); }
.miguel-live__inner { border: 1px solid var(--color-border); border-radius: var(--radius-lg); background: var(--color-surface); overflow: hidden; }
.miguel-live__topline { display: flex; align-items: stretch; min-width: 0; }
.miguel-live__toggle { flex: 1 1 auto; min-width: 0; min-height: 52px; display: flex; align-items: center; gap: 9px; padding: 10px 12px; border: 0; background: transparent; color: var(--color-text); font: inherit; text-align: left; cursor: pointer; touch-action: manipulation; }
.miguel-live__toggle:focus-visible, .miguel-live__info-button:focus-visible, .miguel-live__info-close:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; }
.miguel-live__dot { width: 9px; height: 9px; flex: 0 0 9px; border-radius: 50%; background: var(--color-primary-strong); box-shadow: 0 0 0 3px var(--color-primary-soft); }
.miguel-live__title { flex: 0 0 auto; font-weight: 800; letter-spacing: .01em; }
.miguel-live__summary { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--color-text-muted); font-size: var(--map-text-xs); font-weight: 600; }
.miguel-live__alert-summary { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--color-primary-strong); font-size: var(--map-text-xs); font-weight: 700; }
.miguel-live__chevron { width: 9px; height: 9px; flex: 0 0 9px; margin-left: auto; border-right: 2px solid currentColor; border-bottom: 2px solid currentColor; transform: rotate(45deg) translateY(-2px); transition: transform .18s ease; }
.miguel-live__inner.is-open .miguel-live__chevron { transform: rotate(225deg) translateY(-2px); }
.miguel-live__info-button { flex: 0 0 44px; width: 44px; min-height: 52px; margin: 0; padding: 0; border: 0; border-left: 1px solid var(--color-border); background: transparent; color: var(--color-text-muted); cursor: pointer; touch-action: manipulation; }
.miguel-live__info-button span { display: inline-flex; align-items: center; justify-content: center; width: 21px; height: 21px; border: 1.5px solid currentColor; border-radius: 50%; font-size: 12px; font-weight: 800; line-height: 1; }
.miguel-live__info { margin: 0 12px 10px; padding: 10px 11px; border-radius: var(--radius-md); background: var(--color-surface-muted); color: var(--color-text-muted); }
.miguel-live__info[hidden], .miguel-live__body[hidden] { display: none !important; }
.miguel-live__info strong { display: block; margin: 0 0 4px; color: var(--color-text); font-size: var(--map-text-sm); }
.miguel-live__info p { margin: 0; font-size: var(--map-text-xs); line-height: 1.45; }
.miguel-live__info-close { margin-top: 7px; padding: 0; border: 0; background: none; color: var(--color-primary); font: inherit; font-size: var(--map-text-xs); font-weight: 700; text-decoration: underline; cursor: pointer; }
.miguel-live__body { padding: 0 12px 12px; }
.miguel-live__text { margin: 0 0 8px; color: var(--color-text-muted); font-size: var(--map-text-xs); line-height: 1.4; }
.miguel-live__trip-fields { display: grid; grid-template-columns: minmax(0, 1fr) minmax(0, 1fr); gap: 8px; margin-top: 8px; }
.miguel-live__trip-fields label, .miguel-live__island-field { display: block; min-width: 0; font-size: 11px; font-weight: 700; }
.miguel-live__trip-fields input[type="date"] { display: block; width: 100%; min-width: 0; margin-top: 4px; box-sizing: border-box; }
.miguel-live__island-field > div { margin-top: 4px; color: var(--color-text-muted); font-weight: 500; }
.miguel-live__date-readout { margin-top: 8px; color: var(--color-text-muted); font-size: 11px; }
.miguel-live__footer { display: flex; align-items: center; justify-content: space-between; gap: var(--space-2); margin-top: 8px; }
.miguel-live__checked { color: var(--color-text-muted); font-size: 11px; }
.miguel-live__action { margin-top: 8px; }
.miguel-live__inner.is-alert { border-color: var(--color-primary-soft); }

@media (min-width: 768px) and (max-width: 1366px) {
  .miguel-live__trip-fields { gap: 20px; }
}

@media (max-width: 767px) {
  .miguel-live__toggle { min-height: 50px; padding: 9px 11px; }
  .miguel-live__info-button { min-height: 50px; }
  .miguel-live__body { padding-inline: 11px; }
  .miguel-live__trip-fields { gap: 16px; }
}


/* ==========================================================
   Sprint 3 — Memory Transparency
   Bloc "Ma mémoire Miguel™"
   Ajout isolé : aucune modification des composants existants
   ========================================================== */

.miguel-memory {
    margin-top: 1rem;
    padding: 1rem;
    border-radius: var(--dht-radius-card, 16px);
    background: var(--dht-card-background, rgba(255,255,255,.04));
}

.miguel-memory-content {
    display: flex;
    flex-direction: column;
    gap: .75rem;
}

.miguel-memory-item {
    padding: .85rem;
    border-radius: var(--dht-radius-card, 12px);
    background: var(--dht-card-background-secondary, rgba(255,255,255,.03));
}

.miguel-memory-confidence {
    margin-top: .4rem;
    font-size: .85rem;
    opacity: .75;
}

.miguel-memory-actions {
    display: flex;
    flex-wrap: wrap;
    gap: .6rem;
    margin-top: .9rem;
}

.miguel-memory-actions .button {
    flex: 1 1 auto;
}


/* Sprint 3 - Repositionnement bloc carte mobile/tablette V4
   Position de référence du bloc carte sur mobile/tablette.
   Mobile/tablette uniquement ; desktop inchangé.
   Ne modifie ni le viewport, ni le SVG, ni le panneau Miguel. */
@media (max-width: 1024px) {
  .map-stage {
    transform: translateY(0);
  }
}

/* Sprint 3 - Repositionnement tablette V5
   Même correction visuelle que le mobile, mais sur le vrai palier
   tablette tactile (y compris les tablettes larges en paysage).
   Desktop souris/trackpad totalement inchangé. */
@media (min-width: 768px) and (pointer: coarse) and (any-hover: none) and (max-aspect-ratio: 8/5) {
  .map-stage {
    transform: translateY(0);
  }
}

/* Sprint 3 - Repositionnement tablette V6
   Même correction que le mobile validé, pour les tablettes tactiles
   dont la largeur CSS dépasse 1024px. Desktop classique inchangé. */
@media (min-width: 1025px) and (pointer: coarse) {
  .map-stage {
    transform: translateY(0);
  }
}


/* Micro-correction cartographique — 2026-08-23 / V1.4.19 : remontée visuelle
   UNIQUEMENT du SVG de la carte pour rééquilibrer l'espace entre l'archipel et la bulle
   Miguel™. Le header, le sélecteur d'île, la bulle basse et le .map-viewport restent
   strictement inchangés. Le déplacement porte sur le SVG lui-même et conserve son
   repère géométrique/viewBox ; aucun JS, aucune donnée, aucun zoom/pan ni aucun autre
   composant n'est modifié. Le mode carte immersive mobile est explicitement exclu. */
@media (max-width: 767px) {
  .map-app:not(.is-immersive) .map-viewport > .azores-svg {
    position: relative;
    top: -24px;
  }
}

/* Correction de portée V1.4.20 — le correctif SVG -24px de V1.4.19 était accidentellement
   ciblé desktop souris. Le périmètre validé est MOBILE + TABLETTE TACTILE uniquement ; desktop
   souris/trackpad revient donc strictement au rendu V1.4.18. Aucun viewport, header, sélecteur,
   bulle, GPS, JS ou géométrie n'est modifié. */
@media (min-width: 768px) and (pointer: coarse) and (any-hover: none) and (max-aspect-ratio: 8/5),
       (min-width: 1025px) and (pointer: coarse) {
  .map-app:not(.is-immersive) .map-viewport > .azores-svg {
    position: relative;
    top: -24px;
  }
}

/* Micro-correction V1.4.21 — bouton d'exploration carte ↙↗ : positionné juste sous la rangée
   des contrôles de carte, aligné à droite comme le contrôle météo/conditions visible dans cette
   zone. Mobile + tablette tactile uniquement ; le header, le sélecteur d'île, la bulle basse et
   le SVG restent inchangés. Aucun centrage dans la hauteur totale de l'écran. Desktop souris/trackpad
   reste strictement inchangé et le mode immersif conserve son ancrage existant. */
@media (max-width: 767px) {
  .map-app:not(.is-immersive) .map-immersive-toggle {
    top: calc(var(--space-3) + 48px + var(--space-2));
    bottom: auto;
    transform: none;
  }
}

@media (min-width: 768px) and (pointer: coarse) and (any-hover: none) and (max-aspect-ratio: 8/5),
       (min-width: 1025px) and (pointer: coarse) {
  .map-immersive-toggle {
    display: inline-flex;
  }
  .map-app:not(.is-immersive) .map-immersive-toggle {
    top: calc(var(--space-3) + 48px + var(--space-2));
    bottom: auto;
    transform: none;
  }
}
