/* ══ Accueil : « Par où commencer ? » en grille projecteur (design Site v3) ═══
   Feuille DE PAGE (chargée par landing.html seulement, patron de methode.css) :
   le contrat de poids de l'accueil compte style.css, et le bloc de la cascade
   de /apps n'a rien à y faire ; symétriquement celui-ci n'a rien à faire sur
   /apps. Six cadres photo au format 2,05:1, trois par rangée. Le script
   static/js/spotlight.js met en lumière le cadre le plus proche du centre de
   l'écran (`.is-on`), les autres passent en gris et en retrait, et la
   description du cadre en lumière s'écrit sous la grille. Deux écarts assumés
   par rapport à la maquette, pour le visiteur qui arrive : le libellé reste
   lisible sur TOUS les cadres (le projecteur hiérarchise, il ne cache pas), et
   un clic navigue toujours. Sans script : tout en couleur, pas de description
   sous la grille (elle ne serait jamais remplie). */
/* La grille est plus large que les autres sections (1240 px contre 1080) : à
   1080, trois cadres par rangée tombent à 327 px et leurs captures ne se
   lisent plus. Le même seuil commande les ruptures : deux par rangée sous
   1120 px (à 1121 px un cadre fait 345 px ; à 1024, le portable le plus
   courant, trois par rangée en faisaient 309), un par rangée sous 700 px (à
   701 px, 321 px). Le bloc-titre garde sa mesure de 640 px. */
.home-start { max-width: 1240px; }
.spot-grid {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 10px;
}
.spot-tile {
  position: relative;
  display: block;
  flex: 0 0 calc((100% - 20px) / 3);
  min-width: 0;
  aspect-ratio: 2.05 / 1;
  border-radius: 14px;
  overflow: hidden;
  background: var(--paper-2);
  color: #fff;
  text-decoration: none;
  transition: transform 0.55s var(--ease-spring);
}
/* L'ombre du cadre en lumière est un calque à part dont seule l'OPACITÉ
   s'anime : une transition de box-shadow repeint le cadre et ses 80 px de
   flou à chaque image (mesuré : 936 repeints sur 61 images de défilement),
   l'opacité tourne sur le compositeur. Hors de la boîte rognée du cadre,
   sinon l'ombre ne dépasserait pas de lui : c'est le parent qui la porte. */
.spot-tile::after {
  content: "";
  position: absolute; inset: 0;
  border-radius: inherit;
  box-shadow: 0 30px 80px -30px rgba(0, 0, 0, 0.35);
  opacity: 0;
  transition: opacity 0.55s var(--ease-standard);
  pointer-events: none;
}
.spot-tile picture,
.spot-tile .spot-img { position: absolute; inset: 0; width: 100%; height: 100%; }
.spot-tile .spot-img {
  display: block;
  object-fit: cover;
  object-position: top center;
  transition: transform 0.7s var(--ease-standard);
}
/* Le zoom au survol sous un garde (hover: hover) : sur un appareil tactile
   iOS garde l'état de survol jusqu'au tap suivant (règle maison). */
@media (hover: hover) {
  .spot-tile:hover .spot-img { transform: scale(1.03); }
}
/* Cadre sans capture : aplat d'accent assombri, même mélange que les tuiles
   d'app (70 % d'accent : c'est la clarté qui décide de la lisibilité du
   blanc), trame de points et picto en filigrane. */
.spot-panel {
  position: absolute; inset: 0;
  background: color-mix(in oklch, var(--spot-accent, var(--accent-azur)) 70%, #16140f);
}
.spot-panel::before {
  content: ""; position: absolute; inset: 0;
  background-image: radial-gradient(circle, rgba(255, 255, 255, 0.14) 1px, transparent 1.4px);
  background-size: 16px 16px;
  -webkit-mask-image: linear-gradient(135deg, #000 0%, transparent 62%);
  mask-image: linear-gradient(135deg, #000 0%, transparent 62%);
}
.spot-panel svg {
  position: absolute; right: 8%; top: 50%;
  width: 34%; height: 60%;
  transform: translateY(-50%);
  opacity: 0.22;
}
/* Le voile est ce qui porte le libellé : mesuré au navigateur sur les pixels
   réellement peints, à 0,66 d'opacité en bas le blanc tombait à 3,0:1 sur
   les captures claires (le cadre du cahier des charges, une page presque
   blanche). Le bas du voile est donc plus dense et remonte plus haut, la
   moitié supérieure de la capture reste dégagée. */
.spot-veil {
  position: absolute; inset: 0;
  background: linear-gradient(to top, rgba(0, 0, 0, 0.82) 0%, rgba(0, 0, 0, 0.66) 26%,
                              rgba(0, 0, 0, 0.3) 48%, rgba(0, 0, 0, 0) 70%);
  pointer-events: none;
}
.spot-cap {
  position: absolute; left: 0; right: 0; bottom: 0;
  padding: 12px 14px;
  display: flex; justify-content: space-between; align-items: flex-end; gap: 12px;
  font-size: 12.5px; line-height: 1.25;
  text-shadow: 0 1px 6px rgba(0, 0, 0, 0.55);
}
.spot-cap-txt { min-width: 0; }
.spot-title {
  display: block; margin: 0;
  font-family: var(--font-display);
  font-size: 15px; font-weight: 700; letter-spacing: -0.01em;
  color: inherit;
}
.spot-sub { font-weight: 400; opacity: 0.92; }
.spot-kind {
  flex: none;
  font-family: var(--font-mono);
  font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
  white-space: nowrap;
  background: rgba(255, 255, 255, 0.92); color: #0a0a0a;
  border-radius: 999px; padding: 4px 9px;
  text-shadow: none;
}
/* La description de chaque cadre est aussi dans son lien, hors écran : le
   lecteur d'écran l'entend avec le nom, le paragraphe sous la grille n'a pas
   besoin d'être annoncé à chaque défilement. */
.spot-sr {
  position: absolute; width: 1px; height: 1px; margin: -1px;
  padding: 0; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; border: 0;
}
/* Projecteur (script armé). Le fondu ne porte que sur l'IMAGE (et l'aplat
   de repli), jamais sur le cadre entier : la maquette éteignait tout le
   cadre, libellé compris, et un cadre éteint ne disait plus ce qu'il ouvre.
   Le voile sombre du bas reste opaque, donc le libellé blanc reste lisible
   sur un cadre en retrait comme sur le cadre en lumière. */
.spot-grid.is-live .spot-tile { transform: scale(0.985); }
.spot-grid.is-live .spot-tile .spot-img,
.spot-grid.is-live .spot-tile .spot-panel {
  opacity: 0.5;
  filter: grayscale(1) contrast(0.78) brightness(1.06);
}
.spot-grid.is-live .spot-tile.is-on { transform: none; }
.spot-grid.is-live .spot-tile.is-on::after { opacity: 1; }
.spot-grid.is-live .spot-tile.is-on .spot-img,
.spot-grid.is-live .spot-tile.is-on .spot-panel,
.spot-grid.is-live .spot-tile:focus-visible .spot-img,
.spot-grid.is-live .spot-tile:focus-visible .spot-panel { opacity: 1; filter: none; }
.spot-tile:focus-visible { outline: 2px solid var(--fg); outline-offset: 3px; }
.spot-grid.is-live .spot-tile .spot-img,
.spot-grid.is-live .spot-tile .spot-panel {
  transition: opacity 0.55s var(--ease-standard), filter 0.55s var(--ease-standard),
              transform 0.7s var(--ease-standard);
}
/* En thème sombre, un cadre « éteint » s'assombrit plutôt que de blanchir :
   un gris clair sur le papier sombre ferait ressortir les cadres en retrait
   plus que celui en lumière. */
[data-theme="dark"] .spot-grid.is-live .spot-tile .spot-img,
[data-theme="dark"] .spot-grid.is-live .spot-tile .spot-panel {
  opacity: 0.55;
  filter: grayscale(1) contrast(0.85) brightness(0.75);
}
[data-theme="dark"] .spot-grid.is-live .spot-tile.is-on .spot-img,
[data-theme="dark"] .spot-grid.is-live .spot-tile.is-on .spot-panel,
[data-theme="dark"] .spot-grid.is-live .spot-tile:focus-visible .spot-img,
[data-theme="dark"] .spot-grid.is-live .spot-tile:focus-visible .spot-panel { opacity: 1; filter: none; }
.spot-desc {
  margin: 22px auto 0;
  max-width: 640px;
  text-align: center;
  font-size: 15px; line-height: 1.5;
  color: var(--muted);
  min-height: 46px;
  text-wrap: pretty;
}
/* Sans script, le paragraphe reste vide : il n'existe pas. En reduced-motion la
   grille n'est pas armée non plus, mais le survol et le focus écrivent la
   description : c'est donc le VIDE qui la cache, pas l'absence du script. */
.spot-grid:not(.is-live) + .spot-desc:empty { display: none; }
@media (max-width: 1120px) {
  .spot-tile { flex-basis: calc((100% - 10px) / 2); }
}
@media (max-width: 700px) {
  .spot-tile { flex-basis: 100%; }
  .spot-grid.is-live .spot-tile { transform: none; }
  .spot-cap { padding: 10px 12px; }
  /* Sur téléphone la grille fait six cadres de haut (plus de 1000 px) : posée
     sous la grille, la description du cadre en lumière était hors écran pour
     quatre cadres sur six (mesuré à 390 px). Elle se colle donc au bas de la
     fenêtre le temps du parcours de la grille, et disparaît quand rien n'est
     en lumière (vide) plutôt que de laisser une bande blanche. Les marges
     négatives valent la gouttière de .home-section à cette largeur (20 px). */
  .spot-grid.is-live + .spot-desc {
    position: sticky;
    bottom: 0;
    z-index: 2;
    margin: 14px -20px 0;
    padding: 10px 20px calc(10px + env(safe-area-inset-bottom));
    min-height: 0;
    font-size: 14px;
    background: color-mix(in oklab, var(--bg) 94%, transparent);
    -webkit-backdrop-filter: blur(10px);
    backdrop-filter: blur(10px);
    border-top: 1px solid var(--line);
  }
  .spot-grid.is-live + .spot-desc:empty { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .spot-tile, .spot-tile::after, .spot-tile .spot-img, .spot-tile .spot-panel { transition: none; }
  .spot-tile:hover .spot-img { transform: none; }
  /* Le cadre survolé ou focalisé se signale sans mouvement : une ombre. */
  .spot-tile.is-on::after { opacity: 1; }
}
