/* Cyberiack — couche d'effets graphiques (SITE.effets), chargée après style.css. CSS pur, sans bibliothèque.

   La charte « salle de veille » reste la base : un seul accent (cyan), couleurs vives réservées aux niveaux
   d'alerte. Cette couche lui ajoute du mouvement, sans nouvelle couleur et sans toucher au contenu.

   Règles
   1. Tout est facultatif : sans ce fichier ni effets.js, la page est complète et identique à la version sobre.
   2. Seules des propriétés composées par le navigateur bougent (translate, scale, rotate, opacity, clip-path) :
      aucun décalage de mise en page.
   3. Rien ne tourne en boucle : toute animation lancée d'elle-même se termine en moins de cinq secondes ; le reste
      répond au visiteur (pointeur, défilement, clic, changement de page).
   4. Aucun texte n'est caché ni modifié. Le plus grand élément de chaque page n'a jamais d'opacité animée.
   5. Si le visiteur a demandé moins de mouvement, style.css coupe animations et transitions, et effets.js s'arrête. */

:root {
  --fx-ease: cubic-bezier(.2, .8, .2, 1);
  --fx-spring: cubic-bezier(.3, 1.5, .5, 1);
}
/* Angle du faisceau qui parcourt le bord d'un encart (animable parce qu'il est déclaré) */
@property --fx-angle { syntax: "<angle>"; inherits: false; initial-value: 0deg; }

/* ─── 1. Transitions entre pages ───────────────────────────────────────────
   La page quittée s'efface, la suivante monte ; bandeau, en-tête et barre des rubriques restent en place.
   Le visuel d'une carte devient celui de l'article (nom posé au clic par effets.js). */
@media (prefers-reduced-motion: no-preference) {
  @view-transition { navigation: auto; }
}
::view-transition-old(root) { animation: fx-leave .16s ease-in both; }
::view-transition-new(root) { animation: fx-arrive .34s var(--fx-ease) both; }
@keyframes fx-leave { to { opacity: 0; translate: 0 -10px; } }
@keyframes fx-arrive { from { opacity: 0; translate: 0 16px; } }
.topbar { view-transition-name: bandeau; }
.masthead { view-transition-name: entete; }
.sections { view-transition-name: rubriques; }
.post-cover img { view-transition-name: visuel; }
/* Bandeau, en-tête et rubriques sont les mêmes d'une page à l'autre : seule la nouvelle image est montrée, sans
   fondu (sinon la barre des rubriques, décalée par son mini-logo quand elle est fixée, se dédouble un instant) */
::view-transition-old(bandeau), ::view-transition-old(entete), ::view-transition-old(rubriques) { display: none; }
::view-transition-new(bandeau), ::view-transition-new(entete), ::view-transition-new(rubriques) { animation: none; }
::view-transition-group(bandeau), ::view-transition-group(entete), ::view-transition-group(rubriques) { animation-duration: .34s; animation-timing-function: var(--fx-ease); }
::view-transition-group(visuel) { animation-duration: .45s; animation-timing-function: var(--fx-ease); }
::view-transition-old(visuel), ::view-transition-new(visuel) { height: 100%; object-fit: cover; }

/* ─── 2. Entrée de page ────────────────────────────────────────────────────
   Jouée une fois au chargement, en CSS seul. Le bandeau et l'en-tête, communs à toutes les pages, ne bougent pas. */
@keyframes fx-rise { from { translate: 0 18px; } }
@keyframes fx-rise-soft { from { opacity: .3; translate: 0 12px; } }
@keyframes fx-slide { from { opacity: 0; translate: 16px 0; } }
@keyframes fx-zoom { from { scale: 1.06; } }

/* Accueil : la une monte, son visuel se pose, le fil d'alertes arrive ligne par ligne */
.story { animation: fx-rise .6s var(--fx-ease) backwards; }
.story-media { animation: fx-zoom 2.2s var(--fx-ease) backwards; }
.feed li { animation: fx-slide .5s var(--fx-ease) backwards; }
.feed li:nth-child(1) { animation-delay: .08s; }
.feed li:nth-child(2) { animation-delay: .15s; }
.feed li:nth-child(3) { animation-delay: .22s; }
.feed li:nth-child(4) { animation-delay: .29s; }
.feed li:nth-child(5) { animation-delay: .36s; }
.feed li:nth-child(n+6) { animation-delay: .43s; }

/* Accueil : une ligne de balayage descend une fois sur la zone de une */
.lead-grid::before {
  content: ""; position: absolute; z-index: 3; inset: 0; pointer-events: none; opacity: 0;
  background: linear-gradient(to top, rgb(125 229 255 / .6), rgb(70 209 243 / .16) 2px, transparent) 0 0 / 100% 120px no-repeat;
  animation: fx-scan 1.9s cubic-bezier(.45, 0, .55, 1) .1s 1 backwards;
}
@keyframes fx-scan {
  0% { opacity: 0; translate: 0 -40px; }
  12% { opacity: 1; }
  88% { opacity: 1; }
  100% { opacity: 0; translate: 0 calc(100% - 120px); }
}

/* Autres pages : titre, chapô et signature montent l'un après l'autre */
.page-header > *, .post-header > *, .about-hero > *, .guide-hero > *, .notfound > :not(.terminal) { animation: fx-rise-soft .55s var(--fx-ease) backwards; }
:is(.page-header, .post-header, .notfound) > :nth-child(2) { animation-delay: .06s; }
:is(.page-header, .post-header, .notfound) > :nth-child(3) { animation-delay: .12s; }
:is(.page-header, .post-header, .notfound) > :nth-child(n+4) { animation-delay: .18s; }
.post-cover img { animation: fx-zoom 1.6s var(--fx-ease) backwards; }

/* Page introuvable : le terminal imprime ses lignes une à une */
.terminal { animation: fx-print 2.3s step-end .25s backwards; }
@keyframes fx-print {
  0% { clip-path: inset(0 0 calc(100% - 20px - 1lh) 0); }
  17% { clip-path: inset(0 0 calc(100% - 20px - 2lh) 0); }
  34% { clip-path: inset(0 0 calc(100% - 20px - 3lh) 0); }
  51% { clip-path: inset(0 0 calc(100% - 20px - 4lh) 0); }
  68% { clip-path: inset(0 0 calc(100% - 20px - 5lh) 0); }
  85%, 100% { clip-path: inset(0); }
}

/* ─── 3. Jauge d'alerte ────────────────────────────────────────────────────
   Les cinq barres se dressent l'une après l'autre ; celle du bandeau, présente sur toutes les pages, ne bouge pas. */
.lvl-bars i { transform-origin: 50% 100%; animation: fx-bar .5s var(--fx-spring) backwards; }
.lvl-bars i:nth-child(2) { animation-delay: .06s; }
.lvl-bars i:nth-child(3) { animation-delay: .12s; }
.lvl-bars i:nth-child(4) { animation-delay: .18s; }
.lvl-bars i:nth-child(5) { animation-delay: .24s; }
.topbar .lvl-bars i { animation: none; }
@keyframes fx-bar { from { scale: 1 .2; opacity: .25; } }

/* Alerte majeure (niveau 5) : le filet de couleur bat trois fois à l'arrivée à l'écran, puis se tait */
.fx-seen.lvl-5::before, .fx-seen.kev--alert::before { animation: fx-alert 1.3s ease-in-out 3; }
@keyframes fx-alert { 50% { box-shadow: 0 0 16px 2px var(--lc); } }

/* ─── 4. Révélation au défilement ──────────────────────────────────────────
   effets.js pose fx-wait sur ce qui est encore sous l'écran, puis le retire à l'arrivée. L'état d'attente reste
   lisible (jamais d'opacité nulle) : sans script, ou si l'observateur manque, rien n'est posé.
   « html.fx » donne à ces deux règles la priorité sur les transitions et le survol des cartes (section 6). */
html.fx .fx-wait { opacity: .3; translate: 0 22px; scale: .985; }
html.fx .fx-reveal { transition: opacity .6s var(--fx-ease), translate .6s var(--fx-ease), scale .6s var(--fx-ease); }

/* Titre de section : le filet se trace, la barre d'accent se dresse */
.section-title::before { transform-origin: 50% 100%; transition: scale .5s var(--fx-spring) .1s; }
.section-title::after { transform-origin: 0 50%; transition: scale .9s var(--fx-ease) .15s; }
.fx-wait.section-title::before { scale: 1 0; }
.fx-wait.section-title::after { scale: 0 1; }

/* Icônes de la méthode : le trait se dessine */
:is(.pillar, .pipeline) .ico > * { stroke-dasharray: 100; transition: stroke-dashoffset 1.1s ease .15s; }
.fx-wait .ico > * { stroke-dashoffset: 100; }

/* Encart newsletter : un faisceau fait le tour du bord, une fois à l'arrivée, puis au survol ou à la saisie */
.nl-box::after {
  content: ""; position: absolute; inset: 0; padding: 1px; border-radius: inherit; pointer-events: none; opacity: 0;
  background: conic-gradient(from var(--fx-angle), transparent 0 72%, var(--accent-hi) 88%, transparent 100%);
  -webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
  -webkit-mask-composite: xor;
  mask: linear-gradient(#000 0 0) content-box exclude, linear-gradient(#000 0 0);
}
.nl-box.fx-seen::after { animation: fx-beam 2.6s linear 1; }
.nl-box:is(:hover, :focus-within)::after { animation: fx-beam-again 2.6s linear 1; }
@keyframes fx-beam { 0% { opacity: 1; --fx-angle: 0deg; } 90% { opacity: 1; } 100% { opacity: 0; --fx-angle: 360deg; } }
@keyframes fx-beam-again { 0% { opacity: 1; --fx-angle: 0deg; } 90% { opacity: 1; } 100% { opacity: 0; --fx-angle: 360deg; } }

/* ─── 5. Boutons, liens, étiquettes ────────────────────────────────────── */
.btn { position: relative; overflow: hidden; transition: background-color .15s, border-color .15s, color .15s, scale .15s var(--fx-spring), box-shadow .25s; }
.btn::after {
  content: ""; position: absolute; inset: 0; pointer-events: none; translate: -130% 0;
  background: linear-gradient(105deg, transparent 35%, rgb(255 255 255 / .45) 50%, transparent 65%);
}
.btn--ghost::after { background: linear-gradient(105deg, transparent 35%, rgb(70 209 243 / .2) 50%, transparent 65%); }
.btn:active { scale: .96; }

/* Lien dans un article : le surlignage monte depuis le soulignement */
.prose a { border-radius: 2px; background: linear-gradient(rgb(70 209 243 / .2), rgb(70 209 243 / .2)) 0 100% / 100% 0 no-repeat; transition: color .15s, background-size .2s; }
.prose a:hover { background-size: 100% 100%; }

/* Progression de lecture : la pointe de la barre luit */
.read-progress span { box-shadow: 0 0 12px var(--accent), 0 0 3px var(--accent-hi); }

/* Étincelles au clic sur un bouton (créées par effets.js) */
.fx-spark {
  position: fixed; z-index: 60; left: 0; top: 0; width: 7px; height: 2px; margin: -1px 0 0; border-radius: 2px; pointer-events: none;
  background: var(--accent-hi); translate: var(--fx-x) var(--fx-y); rotate: var(--fx-a); transform-origin: 0 50%;
  animation: fx-spark .55s var(--fx-ease) forwards;
}
@keyframes fx-spark { from { opacity: 1; transform: translateX(8px); } to { opacity: 0; transform: translateX(var(--fx-d, 44px)) scaleX(.3); } }

/* ─── 6. Survol et pointeur (souris ou pavé tactile seulement) ─────────── */
@media (hover: hover) and (pointer: fine) {
  .btn:hover { box-shadow: 0 0 0 1px var(--accent-line), 0 8px 24px -10px rgb(70 209 243 / .55); }
  .btn:hover::after { translate: 130% 0; transition: translate .7s var(--fx-ease); }

  /* Cartes : elles avancent vers le lecteur, un halo suit le pointeur, le filet du niveau d'alerte luit, le visuel
     avance. La carte grandit au lieu de se déplacer : le pointeur posé sur un bord ne la fait pas osciller. */
  .card, .story, .pillar, .dossier-card, .offer, .pipeline li, .kev, .vendor-grid a {
    transition: border-color .2s, background-color .2s, box-shadow .3s, scale .3s var(--fx-ease), transform .25s var(--fx-ease);
  }
  .pillar, .dossier-card, .offer, .pipeline li, .vendor-grid a { position: relative; }
  :is(.card, .pillar, .dossier-card, .offer, .pipeline li):hover {
    scale: 1.015;
    box-shadow: 0 22px 44px -22px rgb(0 0 0 / .9), 0 0 0 1px var(--accent-line), 0 0 34px -12px rgb(70 209 243 / .35);
  }
  .story:hover { box-shadow: var(--shadow), 0 0 0 1px var(--accent-line), 0 0 50px -16px rgb(70 209 243 / .4); }
  :is(.card, .story, .pillar, .dossier-card, .offer, .pipeline li, .kev, .vendor-grid a)::after {
    content: ""; position: absolute; inset: 0; border-radius: inherit; pointer-events: none; opacity: 0; transition: opacity .25s;
    background: radial-gradient(340px circle at var(--fx-mx, 50%) var(--fx-my, 0%), rgb(70 209 243 / .13), transparent 62%);
  }
  :is(.card, .story, .pillar, .dossier-card, .offer, .pipeline li, .kev, .vendor-grid a):hover::after { opacity: 1; }
  /* Inclinaison : angles posés par effets.js, seulement pendant le survol (aucune transformation au repos) */
  .fx-tilt:hover { transform: perspective(1000px) rotateX(var(--fx-rx, 0deg)) rotateY(var(--fx-ry, 0deg)); }
  .card::before, .story::before, .kev::before { transition: box-shadow .3s; }
  :is(.card, .story):hover::before, .kev:hover::before { box-shadow: 0 0 18px 1px var(--lc); }
  /* Le visuel s'agrandit un peu et glisse à l'opposé du pointeur (--fx-px et --fx-py, de -1 à 1, posés par effets.js) :
     l'agrandissement laisse la marge nécessaire, le visuel ne découvre jamais le fond de la carte */
  .card-media, .story-media { transition: scale .6s var(--fx-ease), translate .3s ease-out, filter .4s; }
  .card:hover .card-media { scale: 1.06; translate: calc(var(--fx-px, 0) * -7px) calc(var(--fx-py, 0) * -4px); filter: saturate(1.15) brightness(1.06); }
  .story:hover .story-media { scale: 1.035; translate: calc(var(--fx-px, 0) * -8px) calc(var(--fx-py, 0) * -3px); filter: saturate(1.12) brightness(1.05); }

  /* Fil d'alertes : la ligne survolée avance, sa barre de niveau s'allonge */
  .feed li { transition: translate .2s var(--fx-ease); }
  .feed li::before { transition: top .2s, bottom .2s, box-shadow .2s; }
  .feed li:hover { translate: 4px 0; }
  .feed li:hover::before { top: 9px; bottom: 9px; box-shadow: 0 0 10px var(--lc); }

  /* Barre des rubriques : un filet se déploie sous la rubrique survolée */
  .sections a::before { content: ""; position: absolute; left: 12px; right: 12px; bottom: 0; height: 2px; border-radius: 2px 2px 0 0; background: var(--accent-line); scale: 0 1; transition: scale .2s var(--fx-ease); }
  .sections a:hover::before { scale: 1 1; }
  .sections .sections-mark::before { content: none; }

  /* Marque : la mire pivote et luit, un écho part du logo, le nom saute comme un signal brouillé */
  .brand { position: relative; }
  .brand img { transition: rotate .5s var(--fx-spring), filter .3s; }
  .brand:hover img { rotate: 90deg; filter: drop-shadow(0 0 10px rgb(70 209 243 / .7)); }
  .brand::before { content: ""; position: absolute; left: 0; top: 50%; width: 40px; height: 40px; margin-top: -20px; border: 1px solid var(--accent); border-radius: 50%; opacity: 0; pointer-events: none; }
  .brand:hover::before { animation: fx-ping .8s ease-out; }
  @keyframes fx-ping { from { opacity: .9; scale: .7; } to { opacity: 0; scale: 2.4; } }
  .brand-name { position: relative; }
  .brand-name::before, .brand-name::after { content: "CYBERIACK"; position: absolute; inset: 0; opacity: 0; pointer-events: none; }
  .brand:hover .brand-name::before { color: var(--accent-hi); animation: fx-glitch-a .42s steps(1); }
  .brand:hover .brand-name::after { color: var(--text); animation: fx-glitch-b .42s steps(1); }
  @keyframes fx-glitch-a {
    0% { opacity: .9; clip-path: inset(8% 0 64% 0); translate: -3px 0; }
    25% { opacity: .9; clip-path: inset(58% 0 10% 0); translate: 3px 0; }
    50% { opacity: .9; clip-path: inset(32% 0 38% 0); translate: -2px 0; }
    75% { opacity: .9; clip-path: inset(70% 0 4% 0); translate: 2px 0; }
    100% { opacity: 0; }
  }
  @keyframes fx-glitch-b {
    0% { opacity: .8; clip-path: inset(44% 0 30% 0); translate: 3px 0; }
    25% { opacity: .8; clip-path: inset(12% 0 70% 0); translate: -3px 0; }
    50% { opacity: .8; clip-path: inset(66% 0 14% 0); translate: 2px 0; }
    75% { opacity: .8; clip-path: inset(24% 0 52% 0); translate: -2px 0; }
    100% { opacity: 0; }
  }

  /* Étiquettes, pagination, partage : un petit saut au survol */
  .tags a, .pager-pages a, .sr-chips a, .share a, .share button { transition: color .15s, border-color .15s, background-color .15s, translate .2s var(--fx-spring); }
  :is(.tags a, .pager-pages a, .sr-chips a, .share a, .share button):hover { translate: 0 -2px; }
  .avatar { transition: box-shadow .3s; }
  .author-card:hover .avatar, .byline:hover .avatar { box-shadow: 0 0 0 4px rgb(70 209 243 / .12), 0 0 22px rgb(70 209 243 / .35); }

  /* Quadrillage révélé autour du pointeur, dans les marges de la page (élément créé et déplacé par effets.js) */
  .fx-grid {
    position: fixed; z-index: -1; left: 0; top: 0; width: 520px; height: 520px; margin: -260px 0 0 -260px; pointer-events: none;
    opacity: 0; transition: opacity .4s; translate: var(--fx-x, -999px) var(--fx-y, -999px);
    background-image: linear-gradient(rgb(70 209 243 / .2) 1px, transparent 1px), linear-gradient(90deg, rgb(70 209 243 / .2) 1px, transparent 1px);
    background-size: 48px 48px; background-position: var(--fx-gx, 0) var(--fx-gy, 0);
    -webkit-mask-image: radial-gradient(closest-side, #000 8%, transparent);
    mask-image: radial-gradient(closest-side, #000 8%, transparent);
  }
  .fx-grid.is-on { opacity: 1; }
}

/* ─── 7. Garde-fous ────────────────────────────────────────────────────── */
@media (prefers-reduced-motion: reduce) {
  .lead-grid::before, .fx-grid, .fx-spark { display: none; }
  html.fx .fx-wait { opacity: 1; translate: none; scale: none; }
}
@media print {
  html.fx .fx-wait { opacity: 1; translate: none; scale: none; }
  .lead-grid::before, .fx-grid, .fx-spark, .nl-box::after { display: none; }
}
