/* ============================================================
   ATERET PAZ — MAQUETTE LOCALE homepage v2 (Mission restructuration)
   Tokens repris à l'identique de 05_homepage/index.html
   (palette/police/rayons/ombres confirmés dans le repo, pas
   inventés) — cf. documentation.md pour le détail des sources.
   ============================================================ */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }

:root {
  --navy:        #0B1F3A;
  --navy-light:  #1A3055;
  --orange:      #F37021;
  --orange-dark: #D45F10;
  --cream:       #F5F0E8;
  --text-muted:  #B9C2CE;
  --radius:      14px;
  --radius-sm:   8px;
  --shadow:      0 10px 40px rgba(0,0,0,.35);
  --transition:  220ms ease;
  --white:       #FFFFFF;
  --surface:       rgba(255,255,255,.04);
  --surface-hover: rgba(255,255,255,.06);
  --hairline:      rgba(255,255,255,.08);
}

html, body { height: 100%; }
/* `overflow:hidden` existait déjà sur body seul ; étendu à html pour
   empêcher toute barre de défilement native au niveau document (constaté
   Mission 2 : un dépassement infra-pixel sans conséquence visuelle pouvait
   déclencher une scrollbar native sur <html>, qui en RTL s'affiche à
   gauche et décale tout le contenu — cascade corrigée à la source). */
html { overflow: hidden; }

body {
  font-family: 'Heebo', system-ui, sans-serif;
  color: var(--cream);
  background: var(--navy);
  direction: rtl;
  text-align: right;
  -webkit-font-smoothing: antialiased;
  height: 100dvh;
  overflow: hidden;
  display: flex;
  flex-direction: column;
  padding-top: env(safe-area-inset-top, 0);
  padding-bottom: env(safe-area-inset-bottom, 0);
  padding-left: env(safe-area-inset-left, 0);
  padding-right: env(safe-area-inset-right, 0);
}
body[dir="ltr"] { direction: ltr; text-align: left; }

.display { font-family: 'Cormorant Garamond', 'Heebo', serif; }

/* ---------- בס"ד ----------
   Élément autonome en flux normal (pas position:fixed) : occupe sa
   propre bande au-dessus de l'en-tête, ne peut donc jamais se
   superposer au bouton Contacter. `direction:ltr` figé + `flex-end`
   garantit qu'il reste physiquement en haut à droite quelle que
   soit la langue active (ne suit pas le mirroring RTL/LTR). */
.bsd-bar {
  /* body porte déjà les paddings safe-area (top/right) : pas de double application ici */
  flex: none;
  direction: ltr;
  display: flex;
  justify-content: flex-end;
  padding: 4px 16px 2px;
  pointer-events: none;
  user-select: none;
}
.bsd {
  font-family: 'Cormorant Garamond', serif;
  font-size: .68rem;
  color: var(--text-muted);
}

/* ---------- Header (fixe, identique portrait/paysage) ----------
   2 lignes internes : (1) logo/nom + langues/Contacter, (2) accroche.
   Les deux restent dans le MÊME élément .topbar (même fond,
   continuité visuelle) — pas de section séparée en dessous. Cette
   structure en colonne évite toute compétition d'espace horizontale
   entre l'accroche et les contrôles (cause du débordement testé et
   corrigé lors de cette mission — cf. rapport). */
.topbar {
  flex: 0 0 auto;
  display: flex;
  flex-direction: column;
  padding: clamp(3px,0.7vh,8px) clamp(12px,2vw,24px) clamp(2px,0.5vh,5px);
  background: rgba(11,31,58,.9);
  border-bottom: 1px solid var(--hairline);
  min-width: 0;
  position: relative;
  /* Le logo (z-index:51) doit pouvoir déborder AU-DESSUS du contenu
     de la mosaïque qui suit : overflow visible obligatoire ici. */
  overflow: visible;
  z-index: 50;
}
.topbar-row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: clamp(0px, 2vw, 20px);
  min-width: 0;
}
/* Exception ciblée à 320px uniquement (cf. rapport de mission) :
   testé et mesuré, à cette largeur précise l'accroche sur la même
   rangée que logo+nom+contrôles provoque un débordement horizontal
   réel malgré la compaction maximale déjà appliquée partout ailleurs
   (375px et au-delà : aucun débordement mesuré, aucun changement).
   Premier essai (flex-wrap sur .topbar-row) écarté : il séparait
   aussi .brand et .topbar-right sur 2 lignes distinctes (eux-mêmes
   trop justes pour tenir ensemble à 320px), et le logo — ancré sur
   .brand resté en ligne 1 — recouvrait alors les boutons de langue
   tombés en ligne 2 (bouton FR rendu non cliquable, testé et
   confirmé). Solution retenue : accroche dupliquée (même clé i18n,
   mise à jour automatique) sur sa propre ligne pleine largeur SOUS
   la rangée logo/nom/contrôles, qui elle reste un bloc flex normal
   non wrappé — comportement identique à avant cette mission. */
@media (max-width: 359px) {
  .topbar-row .tagline { display: none; }
}
/* Accroche dupliquée (exception ≤359px) : masquée par défaut, ne
   participe jamais au flex de .topbar-row (élément séparé, propre
   ligne pleine largeur sous la rangée). */
.tagline.tagline-narrow-exception {
  display: none;
  flex: none;
  width: 100%;
  min-width: 0;
  margin-top: clamp(1px, 0.5vh, 4px);
  text-align: center;
  font-style: italic;
  font-weight: 600;
  color: var(--cream);
  font-size: clamp(.6rem, 3.2vw, .85rem);
  line-height: 1.2;
  /* Surcharge explicite : la classe .tagline partagée impose
     white-space:nowrap + ellipsis, ce qui coupait le DÉBUT de la
     phrase (texte centré + nowrap ne produit pas une ellipse fiable
     en CSS, juste un rognage symétrique des deux côtés — testé et
     corrigé lors de cette mission). Ici, retour à un vrai wrap sur 2
     lignes, jamais de coupure de sens. */
  white-space: normal;
  overflow: hidden;
  text-overflow: clip;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  /* Réserve pour le logo caduque : le logo circulaire ne borde plus
     hors du flux, cette ligne (≤359px) n'a plus besoin de marge dédiée. */
  padding-inline: 6px;
}
@media (max-width: 359px) {
  .tagline.tagline-narrow-exception { display: -webkit-box; }
}
.brand {
  display: flex;
  align-items: center;
  gap: clamp(1px, 2.4vw, 20px);
  min-width: 0;
  flex: none;
  position: relative;
}
/* Logo contenu dans un cercle, DANS le flux normal de .brand (plus de
   bleed hors du header). Technique reprise de labo/Hub_V1.0/hub.css
   (.brand-mark/.brand-mark img : grid+place-items, overflow:hidden,
   border-radius:50%, object-fit:cover, anneau bordure+ombre) à la
   demande explicite de David — adaptée ici aux tokens de cette
   maquette (navy/orange/crème, pas le gold de Hub_V1.0) et à une
   taille compacte cohérente avec la hauteur réelle de cette topbar
   (26-57px mesurés selon la taille d'écran, contre un header dédié
   bien plus haut côté Hub_V1.0) : dicte sa propre taille, dimensionnée
   pour rester proportionnée à la rangée logo/nom/contrôles plutôt que
   fixée à la valeur brute 78-100px de Hub_V1.0. */
.brand-logo {
  display: grid;
  place-items: center;
  width: clamp(30px, 8vw, 56px);
  aspect-ratio: 1;
  flex: none;
  overflow: hidden;
  border-radius: 50%;
  border: 2px solid var(--navy-light);
  background: var(--navy);
  box-shadow: 0 6px 16px rgba(0,0,0,.4), 0 0 0 1px rgba(243,112,33,.25);
}
.brand-logo img { display: block; width: 100%; height: 100%; object-fit: cover; }
/* Conteneur positionnant les paillettes autour du nom (taille = celle
   du texte, inline-block requis pour que les % des .sparkle se
   calent sur la boîte réelle du texte, pas sur toute la topbar). */
.brand-name-wrap {
  position: relative;
  display: inline-block;
  /* Annule le "strut" invisible de la boîte de ligne du wrapper
     (sinon sa propre police héritée, non redéfinie, agrandissait la
     hauteur de .brand au-delà du texte réel — cause d'une régression
     mesurée sur logo>topbar en 932x430 et 1366x768). */
  line-height: 0;
  z-index: 52;
}
.brand-name {
  display: inline-block;
  line-height: 1.15;
  font-weight: 700;
  font-size: clamp(.8rem, 4.6vw, 3.1rem);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
  /* Nom du salon toujours en hébreu : direction figée indépendamment de la langue active */
  direction: rtl;
  unicode-bidi: isolate;
  position: relative;
  /* Cuivré métallique — dégradé statique (pas de balayage animé),
     dominante orange/rouille. Valeurs consignées dans le rapport. */
  background: linear-gradient(135deg, #8B4A1F 0%, #E0A672 45%, #B5651D 70%, #8B4A1F 100%);
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  color: #B5651D; /* repli si background-clip:text non supporté */
}
/* ---------- Paillettes (scintillement lent et discret, boucle continue) ----------
   3 points, cycle 6-8s (contre 3.4-4.2s précédemment), pic de
   visibilité volontairement bref (~8% du cycle autour de 50%,
   contre ~50% avant) pour un effet plus ponctuel/discret. Délais et
   durées décalés pour un rendu non synchrone. GPU-friendly :
   uniquement opacity/transform, aucun reflow. */
.sparkle {
  position: absolute;
  width: 3px;
  height: 3px;
  border-radius: 50%;
  background: #FFE3C2;
  box-shadow: 0 0 3px 1px rgba(255, 227, 194, .75);
  opacity: 0;
  pointer-events: none;
  animation-name: sparkle-twinkle;
  animation-timing-function: ease-in-out;
  animation-iteration-count: infinite;
}
@keyframes sparkle-twinkle {
  0%, 46%, 100% { opacity: 0; transform: scale(.4); }
  50% { opacity: .75; transform: scale(1); }
  54% { opacity: 0; transform: scale(.4); }
}
/* Accroche — MÊME rangée que logo/nom/langues/Contacter (David
   demande explicitement l'alignement, mission précédente l'avait
   isolée sur sa propre ligne pour éviter un débordement horizontal :
   cette contrainte est retestée ici). Flex central : occupe l'espace
   restant entre .brand et .topbar-right. Une seule ligne (jamais 2,
   pour ne pas faire varier la hauteur de la rangée) — troncature par
   ellipsis si le texte ne tient pas. */
.tagline {
  /* flex-basis:0 (pas "auto") : évite un artefact où le texte long en
     nowrap contribue encore un peu à scrollWidth malgré le rendu
     visuel déjà compressé par flex-shrink (testé et corrigé lors de
     cette mission). */
  flex: 1 1 0;
  min-width: 0;
  text-align: center;
  font-style: italic;
  font-weight: 600;
  color: var(--cream);
  font-size: clamp(.56rem, 3.6vw, 1.9rem);
  line-height: 1.15;
  white-space: nowrap;
  /* `clip` (pas `hidden`) : `hidden` laissait le contenu texte non
     affiché (nowrap, ellipsis) contribuer malgré tout au scrollWidth
     de l'ancêtre dans ce cas précis (mesuré et corrigé lors de cette
     mission) — `clip` interdit tout débordement mesurable. */
  overflow: clip;
  text-overflow: ellipsis;
  padding-inline: 1px;
}
.topbar-right { display: flex; align-items: center; gap: clamp(1px, 1.6vw, 10px); flex: none; }

.lang-switch { display: inline-flex; gap: clamp(1px, 1vw, 4px); }
.lang-btn {
  font-family: inherit;
  font-size: clamp(.56rem, 1.6vw, .75rem);
  font-weight: 600;
  color: var(--text-muted);
  background: transparent;
  border: 1px solid transparent;
  border-radius: 999px;
  padding: clamp(3px, 1vh, 4px) clamp(1px, 2vw, 10px);
  cursor: pointer;
  min-height: 22px;
  transition: color var(--transition), background var(--transition), border-color var(--transition);
}
.lang-btn:hover { color: var(--cream); }
.lang-btn.active { color: var(--orange); background: var(--surface); border-color: var(--hairline); }

/* ---------- Pastille Contact (en-tête, PAS une tuile de grille) ----------
   3 liens directs toujours visibles (tel/whatsapp/carte), pas de menu à
   ouvrir/fermer — décision David, Mission 2. L'ordre visuel suit la
   direction du texte (RTL/LTR) via le flex naturel du conteneur, sans JS.
   Cible 44×44px de zone tactile par icône (clamp haut), réduite sur très
   petit mobile pour ne jamais déborder du header (clamp bas) — cf.
   documentation.md pour le compromis mesuré. */
.contact-pill {
  display: inline-flex;
  align-items: center;
  background: rgba(245,240,232,.14);
  border: 1px solid rgba(245,240,232,.28);
  border-radius: 999px;
  flex: none;
}
.contact-pill-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: clamp(24px, 7vw, 44px);
  height: clamp(24px, 7vw, 44px);
  color: var(--cream);
  border-radius: 999px;
  text-decoration: none;
  transition: background var(--transition), color var(--transition);
}
.contact-pill-link:hover,
.contact-pill-link:focus-visible { background: rgba(255,255,255,.14); color: var(--orange); }
.contact-pill-link svg { width: clamp(11px, 3.2vw, 20px); height: clamp(11px, 3.2vw, 20px); flex: none; }
.contact-pill-link.contact-pill-map { color: var(--orange); }
.contact-pill-link.contact-pill-map:hover,
.contact-pill-link.contact-pill-map:focus-visible { color: var(--orange); background: rgba(243,112,33,.18); }
.contact-pill-divider {
  width: 1px;
  align-self: stretch;
  margin-block: clamp(4px, 1.2vh, 8px);
  background: rgba(245,240,232,.28);
  flex: none;
}

/* ---------- Boutons génériques (repris de la homepage active) ---------- */
.btn-primary {
  display: inline-block;
  background: var(--orange);
  color: var(--navy);
  font-family: inherit;
  font-size: clamp(.85rem, 1.6vw, 1.05rem);
  font-weight: 700;
  border: none;
  border-radius: var(--radius);
  padding: clamp(8px,1.4vh,15px) clamp(16px,3vw,42px);
  cursor: pointer;
  box-shadow: var(--shadow);
  transition: background var(--transition), transform var(--transition);
  width: 100%;
}
.btn-primary:hover { background: var(--orange-dark); transform: translateY(-2px); }
.btn-primary:disabled {
  opacity: .45;
  cursor: not-allowed;
  pointer-events: none;
  box-shadow: none;
}

/* ============================================================
   MOSAÏQUE — CSS Grid, mobile-first
   4 zones : express / buttons / nestor / carousel
   ============================================================ */
.dashboard {
  flex: 1 1 auto;
  min-height: 0;
  display: grid;
  gap: clamp(8px, 1.6vh, 16px);
  padding: clamp(10px, 2vh, 20px);
  overflow: hidden;
}

.tile {
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: clamp(12px, 2vh, 24px);
  display: flex;
  flex-direction: column;
  min-height: 0;
  min-width: 0;
  overflow: hidden;
  transition: border-color var(--transition), background var(--transition);
}

.tile-kicker {
  font-size: .72rem;
  font-weight: 700;
  letter-spacing: .08em;
  text-transform: uppercase;
  color: var(--orange);
  margin-bottom: 8px;
  flex: none;
}
.tile-sub {
  font-size: clamp(.72rem, 1.3vw, .9rem);
  color: var(--text-muted);
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 2;
  -webkit-box-orient: vertical;
  flex: none;
  margin-bottom: clamp(6px, 1.2vh, 12px);
}
.tile-cta { flex: none; margin-top: auto; }

/* ---------- 1. RDV Express ---------- */
.tile-express {
  border-color: rgba(243,112,33,.35);
}
.express-slots {
  /* Rangement en grille (demande David, correctif visuel) — grille à 2
     colonnes de largeur égale, comme .express-services juste au-dessus,
     au lieu d'un flex-wrap "organique" où chaque puce prenait sa propre
     largeur selon le texte (moins net visuellement). */
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 8px;
  margin-bottom: clamp(8px, 1.6vh, 16px);
  flex: 1 1 auto;
  align-content: flex-start;
  /* Séparation visuelle services / créneaux (demande David) — ligne fine
     toujours présente, même avant sélection d'un service. */
  border-top: 1px solid var(--hairline);
  padding-top: clamp(8px, 1.2vh, 12px);
}
.express-slots .express-slot {
  width: 100%;
  text-align: center;
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
.express-slot {
  font-size: .82rem;
  font-weight: 700;
  color: var(--cream);
  background: rgba(255,255,255,.06);
  border: 1px solid var(--hairline);
  border-radius: 999px;
  padding: 8px 16px;
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition);
}
.express-slot:hover { border-color: rgba(243,112,33,.5); background: var(--surface-hover); }
/* État sélectionné (service OU créneau) — même règle pour les deux
   listes, elles partagent la classe .express-slot (chip identique). */
.express-slot.is-selected {
  border-color: var(--orange);
  background: rgba(243,112,33,.22);
  color: var(--cream);
}
/* Service sans correspondance réelle au chargement (Mission 7) — carte
   inerte plutôt que masquée (évite de faire bouger la grille 2x2). */
.express-slot:disabled {
  opacity: .35;
  cursor: not-allowed;
  pointer-events: none;
}
/* Grille compacte des 4 services (Mission 6) : 2x2 sur mobile/tablette
   portrait (le plus de place possible en hauteur y est plus rare), 1
   seule rangée de 4 en paysage (largeur disponible, cf. media queries
   des breakpoints existants plus bas) pour ne pas alourdir la hauteur
   du bloc RDV Express. */
.express-services {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 10px;
  margin-bottom: clamp(8px, 1.2vh, 14px);
  flex: none;
}
/* Cartes services (demande David) : plus carrées (border-radius carré au
   lieu d'une pilule fine), police plus grasse/masculine — même famille
   Heebo déjà chargée en 800, pas de nouvelle police. Portée limitée à
   .express-services : les puces de créneaux (.express-slots .express-slot)
   gardent leur style pilule existant, non concernées par cette demande.

   Base = mobile portrait : PAS d'aspect-ratio ici (testé trop grand sur
   petit mobile, David a demandé à revenir en arrière sur ce point précis
   — retour Mission "correctif visuel" — hauteur pilotée par le contenu
   seul, taille de police modérée) pour garder de la place pour au moins
   3 créneaux en dessous (cf. EXPRESS_MIN_SLOTS dans app.js). La version
   "grande carte carrée" n'est appliquée qu'à partir du breakpoint
   desktop/tablette paysage (cf. plus bas, min-width:900px+landscape),
   là où l'espace ne manque pas. */
.express-services .express-slot {
  width: 100%;
  display: flex;
  align-items: center;
  justify-content: center;
  text-align: center;
  white-space: normal;
  overflow: hidden;
  line-height: 1.15;
  padding: clamp(8px, 1.6vh, 12px) 6px;
  border-radius: var(--radius);
  font-size: clamp(.76rem, 2.6vw, .92rem);
  font-weight: 800;
  letter-spacing: .01em;
  text-transform: uppercase;
}
/* États des services/créneaux (chargement, vide, erreur — Mission 7,
   remplace la mention "démo" de la Mission 6) — une seule ligne
   tronquée, jamais de croissance de hauteur imprévue. */
.express-status-note {
  font-size: .64rem;
  color: var(--text-muted);
  opacity: .8;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  margin-bottom: clamp(6px, 1vh, 10px);
  flex: none;
}

/* ---------- 2. Deux boutons côte à côte ---------- */
.buttons-row {
  display: flex;
  gap: clamp(8px, 1.6vh, 16px);
  min-height: 0;
  min-width: 0;
}
.button-card {
  flex: 1 1 0;
  min-width: 0;
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  justify-content: center;
  gap: 4px;
  background: var(--surface);
  border: 1px solid var(--hairline);
  border-radius: var(--radius);
  padding: clamp(10px, 1.8vh, 18px) clamp(12px, 2vw, 20px);
  cursor: pointer;
  font-family: inherit;
  text-align: inherit;
  color: var(--cream);
  transition: border-color var(--transition), background var(--transition), transform var(--transition);
}
.button-card:hover { border-color: rgba(243,112,33,.45); background: var(--surface-hover); transform: translateY(-2px); }
.button-card-caption {
  font-size: .68rem;
  color: var(--text-muted);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  max-width: 100%;
}
.button-card-label {
  font-family: 'Cormorant Garamond', 'Heebo', serif;
  font-weight: 700;
  font-size: clamp(.95rem, 2vw, 1.25rem);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  max-width: 100%;
}

/* ---------- 3. Nestor — invite compacte (barre, une seule ligne) ----------
   David : pas de chat permanent, juste un champ prérempli + un bouton
   Envoyer ; hauteur pilotée par le texte (padding minimal), comme
   l'origine — le clic ouvre le vrai panneau (nestor-launcher.js,
   rechargé, sa bulle flottante masquée ci-dessous), voir app.js. */
.nestor-bar {
  display: flex;
  align-items: center;
  gap: 10px;
  min-height: 0;
  padding: clamp(8px, 1.2vh, 12px) clamp(12px, 1.8vw, 16px);
  border: 1px solid rgba(243,112,33,.5);
  box-shadow: 0 0 0 1px rgba(243,112,33,.2);
  background: linear-gradient(160deg, rgba(243,112,33,.10), var(--surface));
  border-radius: var(--radius);
}
.nestor-bar-icon {
  flex: none;
  display: inline-flex;
  color: var(--orange);
}
/* Champ clair (David : "l'intérieur de l'invit doit être plus clair") —
   contraste avec le fond sombre de la tuile, comme un vrai champ de
   saisie de chat (cf. photo de référence : champ blanc sur page sombre). */
.nestor-bar-input {
  flex: 1 1 auto;
  min-width: 0;
  background: var(--cream);
  border: none;
  border-radius: 999px;
  color: var(--navy);
  font-family: inherit;
  font-size: clamp(.82rem, 1.6vw, .98rem);
  line-height: 1.2;
  padding: 6px 12px;
}
.nestor-bar-input:focus {
  outline: none;
  box-shadow: 0 0 0 2px var(--orange);
}
.nestor-bar-input::placeholder { color: var(--text-muted); }
.nestor-bar-mic {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: clamp(24px, 3.2vh, 30px);
  height: clamp(24px, 3.2vh, 30px);
  border-radius: 50%;
  border: 1px solid var(--hairline);
  background: rgba(255,255,255,.06);
  color: var(--cream);
  cursor: pointer;
  transition: border-color var(--transition), background var(--transition);
}
.nestor-bar-mic:hover { border-color: rgba(243,112,33,.5); background: var(--surface-hover); }
.nestor-bar-send {
  flex: none;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: clamp(28px, 3.6vh, 34px);
  height: clamp(28px, 3.6vh, 34px);
  border-radius: 50%;
  border: none;
  background: var(--orange);
  color: var(--navy);
  cursor: pointer;
  transition: background var(--transition);
}
.nestor-bar-send:hover { background: var(--orange-dark); }
/* Le bouton envoi vise toujours "vers l'avant" dans le sens de lecture */
body[dir="ltr"] .nestor-bar-send svg { transform: none; }
body[dir="rtl"] .nestor-bar-send svg { transform: scaleX(-1); }
/* Bulle flottante du vrai nestor-launcher.js masquée (un seul point
   d'entrée : la barre ci-dessus) — le script reste chargé et
   fonctionnel tel quel, on masque seulement son bouton visuel et on lui
   envoie un clic réel depuis app.js. !important nécessaire : le <style>
   du script est injecté en JS après cette feuille, donc plus tardif
   dans la cascade à spécificité égale. */
#nestor-launcher-root .nestor-fab { display: none !important; }

/* ---------- 4. Carrousel fusionné promotions + Arkanocut ---------- */
.carousel-tile { padding: 0; overflow: hidden; }
.carousel {
  position: relative;
  flex: 1 1 auto;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.carousel-track {
  flex: 1 1 auto;
  min-height: 0;
  position: relative;
  overflow: hidden;
}
.carousel-slide {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  text-align: center;
  padding: clamp(16px, 2.4vh, 28px) clamp(40px, 6vw, 64px);
  opacity: 0;
  visibility: hidden;
  transition: opacity 420ms ease;
}
.carousel-slide.is-active { opacity: 1; visibility: visible; }
.carousel-slide .promo-mini-mark {
  width: 30px; height: 30px;
  border-radius: 50%;
  background: rgba(255,255,255,.06);
  color: var(--orange);
  display: flex; align-items: center; justify-content: center;
  font-weight: 800; font-size: 1rem;
  margin-bottom: 10px;
  flex: none;
}
.carousel-slide-title {
  font-family: 'Cormorant Garamond', serif;
  font-weight: 700;
  font-size: clamp(1.05rem, 2.4vw, 1.4rem);
  color: var(--cream);
  margin-bottom: 6px;
}
.carousel-slide-body {
  font-size: clamp(.78rem, 1.4vw, .95rem);
  color: var(--text-muted);
  overflow: hidden;
  display: -webkit-box;
  -webkit-line-clamp: 3;
  -webkit-box-orient: vertical;
}
.carousel-slide-arkanocut .arkanocut-visual {
  max-width: 80%;
  max-height: 100%;
  object-fit: contain;
}
.carousel-nav {
  position: absolute;
  top: 50%;
  transform: translateY(-50%);
  width: 30px; height: 30px;
  border-radius: 50%;
  border: 1px solid var(--hairline);
  background: rgba(11,31,58,.7);
  color: var(--cream);
  font-size: 1.1rem;
  line-height: 1;
  cursor: pointer;
  display: flex;
  align-items: center;
  justify-content: center;
  z-index: 2;
  transition: background var(--transition), border-color var(--transition);
}
.carousel-nav:hover { background: var(--surface-hover); border-color: rgba(243,112,33,.5); }
.carousel-prev { left: 8px; }
.carousel-next { right: 8px; }
.carousel-dots {
  flex: none;
  display: flex;
  justify-content: center;
  gap: 6px;
  padding: 8px 0 10px;
}
.carousel-dot {
  width: 6px; height: 6px;
  border-radius: 50%;
  background: var(--hairline);
  border: none;
  cursor: pointer;
  padding: 0;
  transition: background var(--transition), transform var(--transition);
}
.carousel-dot.is-active { background: var(--orange); transform: scale(1.3); }

/* ---------- Toast placeholder ---------- */
.lab-toast {
  position: fixed;
  left: 50%;
  bottom: calc(env(safe-area-inset-bottom, 0) + 18px);
  transform: translateX(-50%);
  z-index: 70;
  background: #201815;
  color: var(--cream);
  border: 1px solid rgba(243,112,33,.4);
  border-radius: var(--radius-sm);
  padding: 8px 16px;
  font-size: .78rem;
  box-shadow: var(--shadow);
  white-space: nowrap;
}

:focus-visible { outline: 2px solid var(--orange); outline-offset: 2px; }

@media (prefers-reduced-motion: reduce) {
  .carousel-slide { transition: none; }
  /* Titre : reste doré et statique, scintillement totalement désactivé. */
  .sparkle { display: none; animation: none; }
}

/* Wrappers de regroupement gauche/droite (David : colonnes indépendantes
   en paysage, cf. media queries paysage plus bas). display:contents par
   défaut : le wrapper "disparaît" de l'arbre de rendu, ses enfants
   redeviennent des enfants directs de .dashboard pour la grille — donc
   AUCUN changement de comportement sur les formats non-paysage (chaque
   tuile garde son grid-area existant, comme avant l'introduction de ces
   wrappers). */
.dashboard-left,
.dashboard-right {
  display: contents;
}

/* Structure "désaxée" commune aux 2 paliers PAYSAGE (David) — partagée
   ici via `orientation:landscape` seul, pour ne pas la dupliquer dans
   chacun des 2 media queries paysage plus bas (qui, eux, ne gèrent que
   les largeurs de colonnes différentes selon la taille). */
@media (orientation: landscape) {
  .dashboard-left {
    display: flex;
    flex-direction: column;
    gap: clamp(8px, 1.6vh, 16px);
    grid-area: left;
    min-width: 0;
    min-height: 0;
  }
  .dashboard-right {
    display: flex;
    flex-direction: column;
    gap: clamp(8px, 1.6vh, 16px);
    grid-area: right;
    min-width: 0;
    min-height: 0;
  }
  /* Gauche : Express prend tout l'espace restant, Nestor reste à sa
     hauteur fixe standard (même principe qu'en portrait) — juste ce
     qu'il faut pour l'invite de message. */
  .tile-express { flex: 1 1 auto; min-height: 0; }
  .nestor-bar { flex: none; height: 56px; }
  /* Droite : les 2 carrés (Full booking/My bookings) restent à la
     taille de leur contenu (aspect-ratio, pas étirés), le carrousel
     prend tout le reste. */
  .buttons-row { flex: none; }
  .button-card { aspect-ratio: 1 / 1; }
  .carousel-tile { flex: 1 1 auto; min-height: 0; }
}

/* ============================================================
   BREAKPOINT 0 (mobile-first, base) — mobile PORTRAIT
   Ordre obligatoire : RDV Express / boutons / Nestor / carrousel.
   320x568, 375x667, 390x844, 430x932 (portrait).
   ============================================================ */
.dashboard {
  grid-template-columns: 1fr;
  /* Nestor : hauteur FIXE (David : "taille standard, selon les
     conventions") plutôt qu'une fraction proportionnelle — 56px, dans
     la fourchette usuelle d'une barre de saisie de chat (iOS Messages/
     WhatsApp/Material ~48-56px, une seule ligne + icônes + padding).
     Le reste (express/buttons/carousel) revient aux proportions
     d'origine — CSS Grid autorise de mélanger px et fr dans la même
     liste. */
  grid-template-rows: 2.9fr 0.65fr 56px 1.0fr;
  grid-template-areas:
    "express"
    "buttons"
    "nestor"
    "carousel";
}

/* ============================================================
   BREAKPOINT 2 — tablette PORTRAIT (>=600px de large, portrait)
   768x1024 : même hiérarchie, cartes agrandies.
   ============================================================ */
@media (min-width: 600px) and (orientation: portrait) {
  .dashboard {
    /* Même hauteur fixe standard que le breakpoint de base (cf. note
       ci-dessus) — proportions d'origine pour le reste. */
    grid-template-rows: 1.6fr 0.6fr 56px 1.4fr;
  }
  .buttons-row { gap: clamp(12px, 2vw, 24px); }
}

/* ============================================================
   BREAKPOINT 3 — desktop/tablette PAYSAGE, largeur moyenne
   1024x768 : même disposition 2 colonnes que le paysage mobile,
   cartes agrandies, grille équilibrée.
   NOTE D'ORDRE : ce bloc est placé AVANT le breakpoint 1 (mobile
   paysage court) car 932x430 correspond simultanément aux DEUX
   media queries (largeur >=900 ET hauteur <=520) — les
   `grid-template-rows` du `.dashboard` diffèrent entre les deux blocs
   (1.3fr/0.7fr ici vs 1fr/0.55fr breakpoint 1), et c'est la valeur du
   breakpoint 1 qui doit gagner pour ce cas mobile-large-mais-court ;
   il doit donc rester DERNIER en ordre de source (le
   "min-width:900+landscape" ici ne s'applique alors réellement en
   pratique qu'à 1366x768/1440x900, où max-height:520 n'est jamais
   vrai). */
@media (min-width: 900px) and (orientation: landscape) {
  .dashboard {
    max-width: 1400px;
    margin: 0 auto;
    width: 100%;
    /* David : Express+Nestor (gauche) couvrent 2/3 de la largeur,
       Boutons+Carrousel (droite) couvrent 1/3. Une seule rangée : les 2
       wrappers gèrent maintenant leur propre empilement vertical
       indépendamment l'un de l'autre (cf. règle .dashboard-left/-right
       juste après) — plus de rangées partagées entre les 2 colonnes. */
    grid-template-columns: 2fr 1fr;
    grid-template-rows: 1fr;
    grid-template-areas: "left right";
  }
  /* Structure flex gauche/droite : cf. bloc commun `@media
     (orientation: landscape)` juste au-dessus (pas redéfinie ici). */
  .carousel-slide-body { -webkit-line-clamp: 4; }
  /* Services RDV Express sur une seule rangée (largeur disponible),
     pour ne pas alourdir la hauteur déjà réduite de cette tuile. */
  .express-services { grid-template-columns: repeat(4, 1fr); }
  /* Grandes cartes carrées + police imposante — approuvé par David sur
     grand écran ("top"), volontairement PAS repris tel quel sur mobile
     portrait (cf. règle de base ci-dessus) où ça prenait trop de place. */
  .express-services .express-slot {
    aspect-ratio: 4 / 3;
    padding: 6px 10px;
    font-size: clamp(1rem, 1.6vw, 1.4rem);
  }
}

/* ============================================================
   BREAKPOINT 1 — mobile PAYSAGE (hauteur réduite)
   Gauche : RDV Express + Nestor. Droite : boutons + carrousel.
   568x320, 667x375, 844x390, 932x430 (paysage).
   Placé APRÈS le breakpoint 3 (cf. note ci-dessus) : à 932x430,
   qui matche aussi min-width:900+landscape, cette règle doit
   rester la dernière en ordre de source pour que son
   `grid-template-rows` gagne sur celui du breakpoint 3.
   ============================================================ */
@media (orientation: landscape) and (max-height: 520px) {
  .dashboard {
    /* Même principe "désaxé" que le breakpoint desktop/tablette paysage
       ci-dessus : une seule rangée, chaque colonne empile ses 2 tuiles
       indépendamment via .dashboard-left/-right (flex), déjà définis
       plus haut — pas besoin de les redéfinir ici, mêmes règles. */
    grid-template-columns: 1.1fr 1fr;
    grid-template-rows: 1fr;
    grid-template-areas: "left right";
  }
  .tile-sub { -webkit-line-clamp: 1; }
  .carousel-slide-body { -webkit-line-clamp: 2; }
  /* Même logique que le breakpoint desktop/tablette paysage ci-dessus :
     services sur une seule rangée pour économiser la hauteur, très
     réduite ici (mobile paysage court). */
  .express-services { grid-template-columns: repeat(4, 1fr); }
  /* Mêmes lignes de statut (chargement/vide/erreur) masquées ici pour
     économiser la hauteur, très réduite dans ce format (compromis déjà
     signalé Mission 6 pour la mention "démo" qu'elles remplacent). */
  .express-status-note { display: none; }
}
