/* =============================================================================
   NOXEL // PIERRE LORET — système de polarité
   -----------------------------------------------------------------------------
   Un seul squelette, deux dialectes. La polarité est portée par <html data-pol>.

     data-pol="neg"  →  NOXEL          encre blanche sur noir, pixel, brut, rapide
     data-pol="pos"  →  PIERRE LORET   encre noire sur papier, éditorial, lent

   RÈGLE : ne jamais écrire une couleur en dur dans une page. Tout passe par les
   variables ci-dessous, sinon la page ne sait plus s'inverser.
   ============================================================================= */

/* =============================================================================
   TRANSITIONS DE PAGE NATIVES (View Transitions API)
   -----------------------------------------------------------------------------
   Le navigateur photographie la page sortante et l'entrante, puis anime de
   l'une à l'autre. Ça remplace le rideau #wipe, qui reste en repli.

   ⚠️ Ne marche QU'EN http(s). Ouvert en file:// l'origine est opaque, le
   navigateur refuse la transition et common.js retombe sur le rideau.
   Pour la voir : `python3 -m http.server 8080` puis localhost:8080.

   On ne nomme QUE .field. Tout le reste (nav, #prog, #rail, #hud, #cursor) est
   en mix-blend-mode:difference : un élément nommé est extrait de son contexte
   de fusion et virerait au blanc pendant la transition. Laissés dans le fond,
   ils se fondent avec eux-mêmes, donc invisiblement.
   ============================================================================= */
@view-transition { navigation: auto; }

/* le champ porte la polarité de la page : c'est lui qui morphe d'une page à l'autre */
.field { position:fixed; inset:0; z-index:0; background:var(--bg);
  view-transition-name:field; }
::view-transition-group(field) { animation-duration:.62s;
  animation-timing-function:cubic-bezier(.62,.04,.16,1); }

/* le fond prend le dialecte de la page d'ARRIVÉE : c'est son CSS qui pilote */
[data-pol="pos"]::view-transition-old(root),
[data-pol="pos"]::view-transition-new(root) {
  animation-duration:.6s; animation-timing-function:cubic-bezier(.62,.04,.16,1); }
[data-pol="neg"]::view-transition-old(root),
[data-pol="neg"]::view-transition-new(root) {
  animation-duration:.32s; animation-timing-function:steps(6); }

/* le curseur ne doit pas être photographié : il resterait figé dans l'image */
.vt-out #cursor, .vt-out #focus, .vt-out .ghost { opacity:0 !important; }

@property --seam { syntax:'<percentage>'; inherits:true; initial-value:50%; }

/* ---------- polarité négative (par défaut) ---------- */
:root,
[data-pol="neg"] {
  --bg:#0a0a0a; --bg-2:#0f0f0f;
  --panel:#141414; --panel-2:#1c1c1c;
  --line:#2b2b2b; --line-2:#3a3a3a;
  --ink:#f4f4f4; --dim:#9c9c9c; --dim-2:#c4c4c4;
  --pure:#ffffff;   /* l'encre absolue de cette polarité */
  --anti:#0a0a0a;   /* le fond absolu : texte posé sur --pure */

  --display:"Press Start 2P", monospace;
  --display-w:400; --display-ls:1px; --display-lh:1.12; --ds:.60;
  --corner:5px;     /* crans pixel : signature Noxel */

  --ease:cubic-bezier(.2,.9,.15,1);
  --dur:.26s; --dur-2:.42s;
}

/* ---------- polarité positive ---------- */
[data-pol="pos"] {
  --bg:#f2f0ec; --bg-2:#eae7e1;
  --panel:#e9e6e0; --panel-2:#e1ddd5;
  --line:#d6d2ca; --line-2:#bdb8ae;
  --ink:#0a0a0a; --dim:#5f5c58; --dim-2:#3c3a37;
  --pure:#0a0a0a;
  --anti:#f2f0ec;

  --display:"Space Grotesk", system-ui, sans-serif;
  --display-w:700; --display-ls:-2.5px; --display-lh:.94; --ds:1;
  --corner:0px;     /* le pro n'est pas cranté */

  --ease:cubic-bezier(.62,.04,.16,1);
  --dur:.5s; --dur-2:.82s;
}

:root { --maxw:1180px; --gut:clamp(18px,5vw,58px); }

/* =============================================================================
   BASE
   ============================================================================= */
*, *::before, *::after { box-sizing:border-box; margin:0; padding:0; }
html { scroll-behavior:smooth; background:var(--bg); }
body {
  font-family:"Space Grotesk", system-ui, sans-serif;
  background:var(--bg); color:var(--ink); line-height:1.65;
  overflow-x:hidden; -webkit-font-smoothing:antialiased; cursor:none;
  transition:background .6s var(--ease), color .6s var(--ease);
}
a { color:inherit; text-decoration:none; }
img { max-width:100%; display:block; }
/* appearance:none est INDISPENSABLE. Sans lui, macOS garde le chrome natif du
   <button> (coins arrondis, fond clair, dégradé) que background/border ne
   suppriment pas : les boutons SON et LANGUE de la nav ressortaient en pastilles
   grises au milieu d'une interface entièrement à angles droits. */
button { appearance:none; -webkit-appearance:none;
  background:none; border:0; border-radius:0; padding:0; color:inherit; font:inherit;
  letter-spacing:inherit; text-align:inherit; cursor:none; }

/* clavier : un état de focus net, jamais au survol souris */
:focus-visible { outline:2px solid var(--pure); outline-offset:3px; }
nav#nav :focus-visible, #rail :focus-visible { outline-color:#fff; }

/* l'interface native (barres, formulaires) suit la polarité de la page */
html[data-pol="neg"] { color-scheme:dark; }
html[data-pol="pos"] { color-scheme:light; }
html { scrollbar-width:thin; scrollbar-color:var(--line-2) var(--bg); }
::-webkit-scrollbar { width:11px; height:11px; }
::-webkit-scrollbar-track { background:var(--bg); }
::-webkit-scrollbar-thumb { background:var(--line-2); border:3px solid var(--bg); }
::-webkit-scrollbar-thumb:hover { background:var(--dim); }
::selection { background:var(--pure); color:var(--anti); }
/* Lisible par les moteurs et les lecteurs d'écran, invisible à l'œil.
   clip-path plutôt que display:none : ce dernier retire l'élément de
   l'arbre d'accessibilité, donc Google et VoiceOver ne le verraient pas. */
.sr-only { position:absolute; width:1px; height:1px; padding:0; margin:-1px;
  overflow:hidden; clip-path:inset(50%); white-space:nowrap; border:0; }

.mono { font-family:"DM Mono", ui-monospace, monospace; }
.pixel { font-family:"Press Start 2P", monospace; }
.dim { color:var(--dim); }

/* crans pixel : actifs en négatif, neutralisés en positif via --corner:0 */
.pix { clip-path:polygon(
  0 var(--corner), var(--corner) var(--corner), var(--corner) 0,
  calc(100% - var(--corner)) 0, calc(100% - var(--corner)) var(--corner), 100% var(--corner),
  100% calc(100% - var(--corner)), calc(100% - var(--corner)) calc(100% - var(--corner)), calc(100% - var(--corner)) 100%,
  var(--corner) 100%, var(--corner) calc(100% - var(--corner)), 0 calc(100% - var(--corner))); }

/* =============================================================================
   TEXTURE DE FOND — dense en négatif, quasi nulle en positif
   ============================================================================= */
.tex { position:fixed; inset:0; z-index:1; pointer-events:none; }
.tex .grain {
  position:absolute; inset:0;
  background-image:url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='140' height='140'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='.9' numOctaves='3'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23n)'/%3E%3C/svg%3E");
}
[data-pol="neg"] .tex .grain { opacity:.06; mix-blend-mode:screen; }
[data-pol="pos"] .tex .grain { opacity:.032; mix-blend-mode:multiply; }

.tex .weave { position:absolute; inset:0; }
[data-pol="neg"] .tex .weave {
  opacity:.5;
  background:repeating-linear-gradient(to bottom, rgba(255,255,255,.04) 0 1px, transparent 1px 3px); }
[data-pol="pos"] .tex .weave {
  opacity:1;
  background-image:repeating-linear-gradient(to right, rgba(10,10,10,.045) 0 1px, transparent 1px calc(100% / 12)); }

/* =============================================================================
   CURSEUR — carré en négatif, réticule de cadrage en positif
   ============================================================================= */
#cursor {
  position:fixed; top:0; left:0; width:13px; height:13px; background:var(--pure);
  z-index:9999; pointer-events:none; mix-blend-mode:difference;
  transition:width .16s var(--ease), height .16s var(--ease), opacity .2s; }
[data-pol="neg"] #cursor { background:#fff; }
[data-pol="pos"] #cursor { background:#fff; }
/* CREUX, jamais plein. En mix-blend-mode:difference, un carré blanc de 38 px
   posé sur une surface claire (bouton plein, tuile d'icône) devient un pavé noir
   opaque qui masque la lettre en dessous. L'anneau donne le même repère sans
   jamais cacher le contenu. */
#cursor.big, [data-pol] #cursor.big {
  width:38px; height:38px; background:none; box-shadow:inset 0 0 0 1px #fff; }

/* la rémanence se retire dès qu'on vise quelque chose : cinq carrés blancs
   traînant sur un bouton plein produisaient la même occultation */
html.hovering .ghost { opacity:0 !important; }
#cursor.aim { width:1px; height:30px; background:#fff; }
#cursor.aim::after { content:""; position:absolute; top:14.5px; left:-14.5px; width:30px; height:1px; background:#fff; }
#cursor .lab {
  position:absolute; left:50%; top:calc(100% + 12px); transform:translateX(-50%);
  font-family:"DM Mono", monospace; font-size:10px; letter-spacing:2px; white-space:nowrap;
  color:#fff; opacity:0; transition:opacity .2s; text-transform:uppercase; }
#cursor.has-lab .lab { opacity:1; }
/* rémanence : uniquement en négatif */
.ghost { position:fixed; top:0; left:0; width:13px; height:13px; background:#fff;
  z-index:9998; pointer-events:none; mix-blend-mode:difference; opacity:0; }
[data-pol="pos"] .ghost { display:none; }
@media (hover:none) { body { cursor:auto; } #cursor, .ghost { display:none; } }

/* =============================================================================
   AMORCE (boot) + BASCULE DE POLARITÉ (transition de page)
   ============================================================================= */
#leader { position:fixed; inset:0; z-index:10000; background:var(--bg); display:grid; place-items:center;
  transition:opacity .5s steps(4), visibility .5s; }
#leader.done { opacity:0; visibility:hidden; }
.lead-ring { position:relative; width:min(230px,54vw); aspect-ratio:1; display:grid; place-items:center; }
.lead-ring .ring, .lead-ring .ring2 { position:absolute; border:1px solid var(--line-2); border-radius:50%; }
.lead-ring .ring { inset:0; } .lead-ring .ring2 { inset:20%; }
.lead-ring .h, .lead-ring .v { position:absolute; background:var(--line-2); }
.lead-ring .h { left:-26%; right:-26%; top:50%; height:1px; }
.lead-ring .v { top:-26%; bottom:-26%; left:50%; width:1px; }
.lead-ring .sweep { position:absolute; inset:0; border-radius:50%;
  background:conic-gradient(rgba(255,255,255,.12) 0deg 84deg, transparent 84deg);
  animation:sweep .84s steps(7) infinite; }
[data-pol="pos"] .lead-ring .sweep { background:conic-gradient(rgba(10,10,10,.09) 0deg 84deg, transparent 84deg); }
@keyframes sweep { to { transform:rotate(360deg); } }
#cnt { position:relative; z-index:2; font-family:"Press Start 2P", monospace;
  font-size:clamp(38px,12vw,64px); color:var(--ink); }
#leader .cap { position:absolute; bottom:15%; left:0; right:0; text-align:center;
  font-family:"DM Mono", monospace; font-size:11px; letter-spacing:6px; color:var(--dim); }

#wipe { position:fixed; inset:0; z-index:9990; display:grid; place-items:center;
  opacity:0; visibility:hidden; transition:opacity .3s steps(5), visibility .3s;
  background:#0a0a0a; }
#wipe.on { opacity:1; visibility:visible; }
#wipe .w { font-family:"Press Start 2P", monospace; font-size:clamp(13px,2.4vw,18px);
  letter-spacing:1px; color:#fff; animation:blink 1s steps(2) infinite; }
#wipe[data-pol="pos"] { background:#f2f0ec; }
#wipe[data-pol="pos"] .w { color:#0a0a0a; font-family:"Space Grotesk", sans-serif;
  font-weight:700; font-size:clamp(20px,4vw,32px); letter-spacing:-1.4px; }
@keyframes blink { 50% { opacity:.25; } }

/* =============================================================================
   NAV — traitée en différence : lisible sur les deux polarités sans duplication
   ============================================================================= */
nav#nav { position:fixed; top:0; left:0; right:0; z-index:200;
  display:flex; align-items:center; gap:10px; padding:16px var(--gut);
  mix-blend-mode:difference; color:#fff; }
nav#nav .brand { font-family:"Press Start 2P", monospace; font-size:12px; letter-spacing:1px;
  display:flex; align-items:center; gap:10px; }
nav#nav .brand .mark { width:14px; height:14px; background:#fff; animation:spin 6s steps(4) infinite; }
@keyframes spin { to { transform:rotate(360deg); } }
nav#nav .links { margin-left:auto; display:flex; gap:2px; }
nav#nav .links a { font-size:13.5px; padding:8px 13px; color:rgba(255,255,255,.6);
  font-weight:500; transition:color .22s; position:relative; }
nav#nav .links a::after { content:""; position:absolute; left:13px; right:13px; bottom:4px;
  height:1px; background:#fff; transform:scaleX(0); transform-origin:left; transition:transform .35s var(--ease); }
nav#nav .links a:hover { color:#fff; }
nav#nav .links a:hover::after, nav#nav .links a.active::after { transform:scaleX(1); }
nav#nav .links a.active { color:#fff; }
nav#nav .tool-btn { font-family:"DM Mono", monospace; font-size:11.5px; padding:8px 12px;
  box-shadow:inset 0 0 0 1px rgba(255,255,255,.35); color:rgba(255,255,255,.6);
  transition:color .22s, box-shadow .22s; }
nav#nav .tool-btn:hover, nav#nav .tool-btn.on { color:#fff; box-shadow:inset 0 0 0 1px #fff; }
nav#nav .lang b { color:#fff; }
@media (max-width:820px) { nav#nav .links { display:none; } nav#nav .brand { margin-right:auto; } }

/* barre de progression de lecture */
/* en mode différence la source doit être blanche : elle s'inverse seule selon le fond */
#prog { position:fixed; top:0; left:0; height:2px; width:0; background:#fff;
  z-index:210; mix-blend-mode:difference; }

/* rail d'index de section (droite) */
#rail { position:fixed; right:14px; top:50%; transform:translateY(-50%); z-index:180;
  display:flex; flex-direction:column; gap:12px; mix-blend-mode:difference; }
#rail a { display:flex; align-items:center; justify-content:flex-end; gap:8px;
  font-family:"DM Mono", monospace; font-size:10px; letter-spacing:1px; color:rgba(255,255,255,.42);
  transition:color .3s; }
#rail a i { display:block; width:16px; height:1px; background:currentColor; transition:width .35s var(--ease); }
#rail a.on { color:#fff; } #rail a.on i { width:30px; }
#rail a span { opacity:0; transition:opacity .3s; }
#rail a:hover span, #rail a.on span { opacity:1; }
/* 1180 px de contenu + marges : en dessous de 1240 le rail mordrait dessus */
@media (max-width:1240px) { #rail { display:none; } }

/* =============================================================================
   MISE EN PAGE
   ============================================================================= */
.wrap { max-width:var(--maxw); margin:0 auto; }
.sec { position:relative; z-index:2; padding:clamp(76px,13vh,150px) var(--gut); }
.sec--tight { padding-top:0; }
.hero { position:relative; z-index:2; min-height:88vh; display:flex; flex-direction:column;
  justify-content:center; padding:clamp(118px,17vh,190px) var(--gut) clamp(50px,8vh,80px); overflow:hidden; }

.eyebrow { display:inline-flex; align-items:center; gap:9px; font-family:"DM Mono", monospace;
  font-size:11.5px; letter-spacing:2.5px; text-transform:uppercase; color:var(--ink); margin-bottom:16px; }
/* --corner réduit : sur un carré de 8px, le cran par défaut de 5px détruirait la forme */
.eyebrow i { width:8px; height:8px; background:var(--pure); display:block; --corner:2px; }

/* le titre change de police avec la polarité */
.display { font-family:var(--display); font-weight:var(--display-w);
  letter-spacing:var(--display-ls); line-height:var(--display-lh);
  font-size:calc(clamp(30px,6.4vw,80px) * var(--ds)); }
.display--xl { font-size:calc(clamp(38px,11vw,142px) * var(--ds)); }
.display--sm { font-size:calc(clamp(22px,3.6vw,42px) * var(--ds)); }
[data-pol="pos"] .display--sm { letter-spacing:-1.2px; }

.lead { color:var(--dim); font-size:clamp(15px,2vw,19px); max-width:600px; margin-top:18px; }
.body { font-size:clamp(15.5px,1.7vw,18px); line-height:1.9; }
.body p + p { margin-top:15px; }

.sec-head { display:flex; align-items:flex-end; justify-content:space-between;
  gap:24px; margin-bottom:42px; flex-wrap:wrap; }
.sec-head .idx { font-family:"DM Mono", monospace; font-size:11px; letter-spacing:3px; color:var(--dim); }
.split { display:grid; grid-template-columns:1fr 1fr; gap:clamp(30px,5vw,60px); align-items:center; }
@media (max-width:880px) { .split { grid-template-columns:1fr; } }

/* =============================================================================
   BOUTONS
   ============================================================================= */
.btn { display:inline-flex; align-items:center; gap:10px; width:max-content;
  font-family:"DM Mono", monospace; font-size:13.5px; letter-spacing:.5px;
  padding:14px 24px; transition:transform .14s var(--ease), gap .3s var(--ease); }
.btn--solid { background:var(--pure); color:var(--anti); }
.btn--line { box-shadow:inset 0 0 0 1px var(--line-2); color:var(--ink); }
.btn--line:hover { box-shadow:inset 0 0 0 1px var(--pure); }
.btn:hover { gap:16px; }
/* en positif, le bouton principal se réduit à un filet : le pro ne crie pas */
[data-pol="pos"] .btn--ghost { padding:7px 0; border-bottom:1px solid var(--pure);
  background:none; color:var(--ink); }
[data-pol="pos"] .btn--ghost:hover { gap:22px; }
[data-pol="neg"] .btn--ghost { background:var(--pure); color:var(--anti); }

.backlink { display:inline-flex; align-items:center; gap:8px; font-family:"DM Mono", monospace;
  font-size:12.5px; color:var(--dim); margin-bottom:24px; transition:color .25s, gap .25s; }
.backlink:hover { color:var(--ink); gap:14px; }

/* =============================================================================
   RÉVÉLATIONS AU SCROLL
   ============================================================================= */
.rev { opacity:0; transform:translateY(28px);
  transition:opacity .75s var(--ease), transform .75s var(--ease); }
.rev.in { opacity:1; transform:none; }
[data-rev="left"] { transform:translateX(-30px); }
[data-rev="clip"] { opacity:1; transform:none; clip-path:inset(0 100% 0 0); transition:clip-path .95s var(--ease); }
[data-rev="clip"].in { clip-path:inset(0 0 0 0); }
[data-rev="line"] { opacity:1; transform:none; }
[data-rev="line"]::after { content:""; display:block; height:1px; background:var(--line-2);
  transform:scaleX(0); transform-origin:left; transition:transform 1s var(--ease); }
[data-rev="line"].in::after { transform:scaleX(1); }

/* découpe caractère par caractère (titres)
   Le padding/margin compensé agrandit la boîte de rognage sans déplacer la ligne :
   sans lui, un line-height serré rogne les accents (É, à, ê) et les jambages. */
.ch { display:inline-block; overflow:hidden; vertical-align:bottom;
  padding:.16em 0 .1em; margin:-.16em 0 -.1em; }
.ch > i { display:inline-block; font-style:normal; transform:translateY(115%);
  transition:transform .7s var(--ease); }
.ch.in > i { transform:none; }

@media (prefers-reduced-motion:reduce) {
  * { animation-duration:.01ms !important; animation-iteration-count:1 !important;
      transition-duration:.01ms !important; scroll-behavior:auto !important; }
  .rev, .ch > i { opacity:1 !important; transform:none !important; clip-path:none !important; }
}

/* =============================================================================
   COMPOSANTS PARTAGÉS
   ============================================================================= */
/* liste-index : piliers, films, étapes */
.index-list { border-top:1px solid var(--line); }
.row { position:relative; display:grid; grid-template-columns:auto 1fr auto; gap:clamp(16px,3vw,40px);
  align-items:center; padding:clamp(20px,3vw,32px) 0; border-bottom:1px solid var(--line);
  transition:padding-left .45s var(--ease); overflow:hidden; }
.row:hover { padding-left:clamp(10px,2vw,26px); }
.row::before { content:""; position:absolute; inset:0; background:var(--panel);
  transform:scaleY(0); transform-origin:bottom; transition:transform .45s var(--ease); z-index:0; }
.row:hover::before { transform:scaleY(1); }
.row > * { position:relative; z-index:1; }
.row .no { font-family:"DM Mono", monospace; font-size:12px; letter-spacing:2px; color:var(--dim);
  transition:color .3s; min-width:26px; }
.row:hover .no { color:var(--ink); }
.row .rt { font-size:clamp(18px,2.6vw,30px); font-weight:600; letter-spacing:-.4px;
  display:flex; align-items:center; gap:12px; flex-wrap:wrap; }
[data-pol="neg"] .row .rt { font-family:"Press Start 2P", monospace; font-weight:400;
  font-size:clamp(13px,1.8vw,19px); letter-spacing:0; }
.row .rd { color:var(--dim); font-size:14px; margin-top:6px; }
.row .rm { font-family:"DM Mono", monospace; font-size:12.5px; color:var(--dim);
  white-space:nowrap; text-align:right; transition:color .3s;
  display:flex; align-items:center; justify-content:flex-end; gap:7px; }
.row .rm .i { font-size:15px; }
.row:hover .rm { color:var(--ink); }
.tag { font-family:"DM Mono", monospace; font-size:10.5px; letter-spacing:1.5px; padding:4px 9px;
  box-shadow:inset 0 0 0 1px var(--line-2); color:var(--dim); }
@media (max-width:680px) { .row { grid-template-columns:auto 1fr; } .row .rm { display:none; } }

/* cartes */
.grid { display:grid; grid-template-columns:repeat(auto-fill,minmax(248px,1fr)); gap:14px; }
.card { position:relative; padding:26px; background:var(--panel); overflow:hidden;
  display:flex; flex-direction:column; gap:13px; min-height:190px;
  transition:transform .35s var(--ease), background .35s var(--ease); }
.card::before { content:""; position:absolute; inset:0; box-shadow:inset 0 0 0 1px var(--line);
  transition:box-shadow .35s; pointer-events:none; z-index:2; }
.card:hover { transform:translateY(-5px); background:var(--panel-2); }
.card:hover::before { box-shadow:inset 0 0 0 1px var(--pure); }
.card .ic { width:46px; height:46px; display:grid; place-items:center; font-size:20px;
  background:var(--pure); color:var(--anti);
  background-image:radial-gradient(rgba(128,128,128,.22) 1px, transparent 1.4px); background-size:7px 7px; }
.card b { font-size:17px; letter-spacing:-.2px; }
.card p { color:var(--dim); font-size:13.5px; flex:1; }
.card .go { font-family:"DM Mono", monospace; font-size:12px; color:var(--dim);
  display:flex; align-items:center; gap:6px; transition:gap .3s var(--ease), color .3s; }
.card:hover .go { gap:13px; color:var(--ink); }
[data-pol="pos"] .card:hover { transform:translateY(-2px); }

/* grille collée (fonctionnalités) */
.mesh { display:grid; grid-template-columns:repeat(auto-fill,minmax(250px,1fr));
  gap:1px; background:var(--line); box-shadow:0 0 0 1px var(--line); }
.mesh > div { background:var(--bg); padding:28px 24px; min-height:180px;
  display:flex; flex-direction:column; gap:11px; transition:background .3s var(--ease); }
.mesh > div:hover { background:var(--panel); }
.mesh .fi { font-size:24px; color:var(--ink); }
.mesh b { font-size:17px; } .mesh p { color:var(--dim); font-size:13.5px; }

/* figure animée */
.figbox { position:relative; aspect-ratio:16/11; background:var(--panel);
  box-shadow:inset 0 0 0 1px var(--line); overflow:hidden; display:grid; place-items:center; }
.figbox canvas { position:absolute; inset:0; }
.figbox .lbl { position:relative; z-index:2; font-family:"Press Start 2P", monospace;
  font-size:clamp(30px,6vw,60px); color:#fff; mix-blend-mode:difference; }

/* chiffres clés */
.stats { display:grid; grid-template-columns:repeat(auto-fit,minmax(150px,1fr));
  gap:1px; background:var(--line); box-shadow:0 0 0 1px var(--line); }
.stats > div { background:var(--bg); padding:30px 20px; text-align:center; }
.stats b { display:block; font-family:var(--display); font-weight:var(--display-w);
  letter-spacing:var(--display-ls); font-size:calc(clamp(24px,4.4vw,40px) * var(--ds)); }
[data-pol="pos"] .stats b { letter-spacing:-1.5px; }
.stats span { font-family:"DM Mono", monospace; font-size:11px; letter-spacing:1.5px; color:var(--dim); }

/* étiquettes / mots-clés */
.chips { display:flex; gap:9px; flex-wrap:wrap; margin-top:22px; }
.chips span { font-family:"DM Mono", monospace; font-size:12.5px; padding:8px 14px;
  box-shadow:inset 0 0 0 1px var(--line-2); color:var(--dim); }

/* bandeau défilant */
.marquee { overflow:hidden; border-top:1px solid var(--line); border-bottom:1px solid var(--line);
  background:var(--bg-2); padding:16px 0; position:relative; z-index:2; }
.marquee .row-m { display:flex; gap:36px; width:max-content; will-change:transform; }
.marquee .row-m span { font-family:"Press Start 2P", monospace; font-size:14px; color:var(--dim);
  display:flex; align-items:center; gap:36px; white-space:nowrap; }
.marquee .row-m span::after { content:"◆"; color:var(--ink); font-size:11px; }
[data-pol="pos"] .marquee .row-m span { font-family:"Space Grotesk", sans-serif; font-weight:700;
  font-size:22px; letter-spacing:-.8px; }

/* chronologie */
.timeline { border-left:1px solid var(--line); margin-left:7px; padding-left:30px; display:grid; gap:34px; }
.tl { position:relative; }
.tl::before { content:""; position:absolute; left:-37px; top:6px; width:13px; height:13px;
  background:var(--pure); transform:scale(0); transition:transform .5s var(--ease); }
.tl.in::before { transform:scale(1); }
.tl .yr { font-family:"DM Mono", monospace; font-size:12px; letter-spacing:3px; color:var(--dim); }
.tl b { display:block; font-size:18px; margin-top:6px; }
.tl p { color:var(--dim); font-size:14.5px; margin-top:3px; }

/* encadré de note */
.note { margin-top:60px; padding:20px 22px; box-shadow:inset 0 0 0 1px var(--line);
  background:var(--panel); font-family:"DM Mono", monospace; font-size:12.5px; color:var(--dim); }

/* =============================================================================
   LECTEUR SOUNDCLOUD (page Noxel)
   ============================================================================= */
.music-grid { display:grid; grid-template-columns:1.05fr 1fr; gap:20px; align-items:start; }
@media (max-width:880px) { .music-grid { grid-template-columns:1fr; } }
.player-card { position:relative; padding:28px; background:var(--panel); box-shadow:inset 0 0 0 1px var(--line); }
.now { display:flex; align-items:center; gap:18px; }
.cover { width:86px; height:86px; flex:none; display:grid; place-items:center; font-size:34px;
  background:var(--dim-2); color:var(--anti); background-size:cover; background-position:center;
  overflow:hidden; transition:transform .3s; }
.player-card.playing .cover { animation:pulse 1.15s steps(2) infinite; }
@keyframes pulse { 50% { transform:scale(.94); } }
.now-meta b { font-size:19px; display:block; line-height:1.25; }
.now-meta small { color:var(--dim); font-family:"DM Mono", monospace; }
.prog-bar { position:relative; height:13px; margin:22px 0 13px; background:var(--panel-2);
  box-shadow:inset 0 0 0 1px var(--line); }
.prog-bar i { display:block; height:100%; width:0; background:var(--dim-2);
  background-image:radial-gradient(rgba(128,128,128,.25) 1px, transparent 1.4px); background-size:6px 6px;
  transition:width .15s linear; }
.controls { display:flex; align-items:center; gap:15px; color:var(--dim);
  font-family:"DM Mono", monospace; font-size:12.5px; }
.ctl { font-size:16px; color:var(--dim); transition:color .2s, transform .14s; }
.ctl:hover { color:var(--ink); transform:scale(1.16); }
.play { width:44px; height:44px; background:var(--pure); color:var(--anti);
  display:grid; place-items:center; font-size:15px; transition:transform .14s; }
.play:hover { transform:scale(1.09); }
.time { margin-left:auto; }
.tracks { background:var(--panel); box-shadow:inset 0 0 0 1px var(--line);
  max-height:330px; overflow-y:auto; }
.tracks::-webkit-scrollbar { width:7px; }
.tracks::-webkit-scrollbar-thumb { background:var(--line-2); }
.track { display:flex; align-items:center; gap:15px; padding:16px 21px;
  border-bottom:1px dashed var(--line); transition:background .2s, padding-left .25s; }
.track:last-child { border-bottom:none; }
.track.active, .track:hover { background:var(--panel-2); padding-left:26px; }
.track .n { font-family:"DM Mono", monospace; color:var(--dim); width:22px; }
.track.active .n, .track:hover .n { color:var(--ink); }
.track .t b { display:block; font-size:14.5px; }
.track .t small { color:var(--dim); font-size:12px; }
.track .dur { margin-left:auto; font-family:"DM Mono", monospace; color:var(--dim); font-size:12.5px; }
.track-load { padding:22px; color:var(--dim); font-size:13px; font-family:"DM Mono", monospace; }

/* équaliseur décoratif */
.eq { position:absolute; inset:auto 0 0 0; height:40vh; display:flex; align-items:flex-end;
  gap:4px; padding:0 var(--gut); z-index:0; opacity:.16; pointer-events:none; }
.eq span { flex:1; background:var(--pure); height:6%; }

/* =============================================================================
   PIED DE PAGE
   ============================================================================= */
footer { position:relative; z-index:2; padding:70px var(--gut) 46px;
  border-top:1px solid var(--line); margin-top:30px; }
.foot { max-width:var(--maxw); margin:0 auto; display:flex; justify-content:space-between;
  gap:28px; flex-wrap:wrap; align-items:center; }
.foot .big { font-family:var(--display); font-weight:var(--display-w);
  letter-spacing:var(--display-ls); line-height:1.4;
  font-size:calc(clamp(22px,4.6vw,44px) * var(--ds)); }
.socials { display:flex; gap:9px; flex-wrap:wrap; }
.socials a { display:inline-flex; align-items:center; gap:9px;
  font-family:"DM Mono", monospace; font-size:12.5px; padding:11px 16px;
  box-shadow:inset 0 0 0 1px var(--line); color:var(--dim); transition:color .25s, box-shadow .25s; }
.socials a:hover { color:var(--ink); box-shadow:inset 0 0 0 1px var(--pure); }

/* =============================================================================
   ICÔNES
   Un seul sprite externe, mis en cache une fois pour tout le site :
   <svg class="i"><use href="/icons.svg#spotify"></use></svg>
   fill:currentColor → le glyphe prend l'encre de la polarité courante, y
   compris à l'intérieur d'un bloc plein (.card .ic) où l'encre s'inverse.
   ============================================================================= */
.i { width:1em; height:1em; display:block; flex:none; fill:currentColor;
  pointer-events:none; }
.socials .i { font-size:15px; opacity:.85; transition:opacity .25s; }
.socials a:hover .i { opacity:1; }
.card .ic .i { font-size:21px; }
.btn .i { font-size:15px; }
.copyright { max-width:var(--maxw); margin:38px auto 0; font-family:"DM Mono", monospace;
  font-size:11.5px; color:var(--dim); display:flex; justify-content:space-between; gap:16px; flex-wrap:wrap; }

/* =============================================================================
   COUCHE 2 — animation avancée
   -----------------------------------------------------------------------------
   Chaque effet existe des DEUX côtés, avec deux dialectes opposés :
     négatif → stepped, brutal, pixel, court
     positif → continu, optique, lent
   C'est le même mécanisme qui parle deux langues. Ne jamais donner à l'un
   la courbe de l'autre : c'est ce qui tient la distinction pro / perso.
   ============================================================================= */

/* ---------- boîte de cadrage : verrouille l'élément survolé ---------- */
#focus { position:fixed; left:0; top:0; z-index:9997; pointer-events:none;
  mix-blend-mode:difference; opacity:0; }
#focus.on { opacity:1; }
#focus i { position:absolute; width:9px; height:9px; border:1px solid #fff; }
#focus i:nth-child(1) { left:0;  top:0;    border-right:0; border-bottom:0; }
#focus i:nth-child(2) { right:0; top:0;    border-left:0;  border-bottom:0; }
#focus i:nth-child(3) { left:0;  bottom:0; border-right:0; border-top:0; }
#focus i:nth-child(4) { right:0; bottom:0; border-left:0;  border-top:0; }
/* le pro fait un point au ralenti, comme une bague de mise au point */
[data-pol="pos"] #focus { transition:opacity .3s, transform .42s cubic-bezier(.62,.04,.16,1),
  width .42s cubic-bezier(.62,.04,.16,1), height .42s cubic-bezier(.62,.04,.16,1); }
/* Noxel claque dessus en quatre crans */
[data-pol="neg"] #focus { transition:opacity .1s, transform .16s steps(4),
  width .16s steps(4), height .16s steps(4); }
@media (hover:none) { #focus { display:none; } }

/* ---------- HUD : compteur de métrage (positif) / niveau (négatif) ---------- */
#hud { position:fixed; right:14px; bottom:16px; z-index:180; mix-blend-mode:difference;
  font-family:"DM Mono", monospace; font-size:10.5px; letter-spacing:2px;
  color:rgba(255,255,255,.5); pointer-events:none; }
@media (max-width:980px) { #hud { display:none; } }

/* ---------- révélations : deux façons d'arriver à l'image ---------- */
/* positif : la mise au point se fait, comme au tirage */
[data-rev="focus"] { opacity:0; filter:blur(10px); transform:translateY(16px) scale(1.012);
  transition:opacity .9s var(--ease), filter 1.15s var(--ease), transform 1.15s var(--ease); }
[data-rev="focus"].in { opacity:1; filter:blur(0); transform:none; }

/* dither et iris passent par un RIDEAU, pas par clip-path : la classe .pix
   utilise déjà clip-path pour les crans, et la révélation l'effacerait. */

/* négatif : le rideau se retire par paliers, comme un rafraîchissement d'écran */
[data-rev="dither"] { opacity:1; transform:none; position:relative; }
[data-rev="dither"]::after { content:""; position:absolute; inset:0; z-index:6;
  background:var(--bg); transform-origin:right; transition:transform .6s steps(9); }
[data-rev="dither"].in::after { transform:scaleX(0); }

/* iris : l'image s'ouvre par le bas */
[data-rev="iris"] { opacity:1; transform:none; position:relative; }
[data-rev="iris"]::after { content:""; position:absolute; inset:0; z-index:6;
  background:var(--bg); transform-origin:top; transition:transform 1s var(--ease); }
[data-rev="iris"].in::after { transform:scaleY(0); }
[data-rev="iris"] canvas { transform:scale(1.12); transition:transform 1.5s var(--ease); }
[data-rev="iris"].in canvas { transform:none; }
[data-pol="neg"] [data-rev="iris"]::after { transition:transform .55s steps(7); }

/* ---------- boutons : le plein balaie le contour ---------- */
.btn--line { position:relative; overflow:hidden; z-index:0; }
.btn--line::before { content:""; position:absolute; inset:0; background:var(--pure);
  transform:scaleX(0); transform-origin:left; z-index:-1; }
[data-pol="neg"] .btn--line::before { transition:transform .3s steps(5); }
[data-pol="pos"] .btn--line::before { transition:transform .6s var(--ease); }
.btn--line:hover::before { transform:scaleX(1); }
.btn--line:hover { color:var(--anti); }

/* le remplissage des lignes suit le même écart de dialecte */
[data-pol="neg"] .row::before { transition:transform .3s steps(6); }
[data-pol="neg"] .row { transition:padding-left .2s steps(4); }

/* ---------- chronologie : le trait se dessine avec le scroll ---------- */
.timeline { position:relative; }
.timeline::after { content:""; position:absolute; left:-1px; top:0; width:1px;
  height:var(--tl,0%); background:var(--pure); transition:height .12s linear; }

/* ---------- balayage de trame, en fond, côté Noxel seulement ---------- */
[data-pol="neg"] .tex::after { content:""; position:absolute; left:0; right:0; height:130px;
  background:linear-gradient(rgba(255,255,255,0), rgba(255,255,255,.05), rgba(255,255,255,0));
  animation:sweepdown 7.5s linear infinite; }
@keyframes sweepdown { from { top:-150px; } to { top:100%; } }

/* ---------- entrée chorégraphiée après l'amorce ---------- */
[data-enter] { opacity:0; transform:translateY(14px);
  transition:opacity .8s var(--ease), transform .8s var(--ease); }
[data-pol="neg"] [data-enter] { transition:opacity .3s steps(4), transform .3s steps(4); }
[data-enter].in { opacity:1; transform:none; }

@media (prefers-reduced-motion:reduce) {
  [data-rev="focus"], [data-rev="dither"], [data-rev="iris"], [data-enter] {
    opacity:1 !important; filter:none !important; transform:none !important; clip-path:none !important; }
  [data-pol="neg"] .tex::after { display:none; }
}

/* aide clavier */
#keys { position:fixed; left:var(--gut); bottom:18px; z-index:180; mix-blend-mode:difference;
  font-family:"DM Mono", monospace; font-size:10.5px; letter-spacing:1.5px;
  color:rgba(255,255,255,.4); display:flex; gap:14px; transition:color .3s; }
#keys:hover { color:#fff; }
#keys kbd { box-shadow:inset 0 0 0 1px rgba(255,255,255,.35); padding:2px 5px; font-family:inherit; }
@media (max-width:980px) { #keys { display:none; } }
