/* ════════════════════════════════════════════════════════════════
   Anthony De Buck · Portfolio : Direction DARK CYBERSÉCURITÉ
   Palette : near-black + accent vert terminal (#00ff9c) + cyan secondaire (#00e5ff)
   Typo : Space Grotesk (titres/corps) + JetBrains Mono (détails techniques)
   ════════════════════════════════════════════════════════════════ */

/* ════════════════════════════════════════════════════════════════
   FONTS SELF-HÉBERGÉES (subset latin, woff2)
   Servies depuis /assets/fonts : aucune requête vers Google/gstatic,
   conforme à la CSP `font-src 'self'`. font-display: swap = texte
   système affiché immédiatement puis remplacé sans FOIT bloquant.
   ════════════════════════════════════════════════════════════════ */
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal; font-weight: 400; font-display: swap;
  src: url('/assets/fonts/space-grotesk-400.woff2') format('woff2');
}
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal; font-weight: 500; font-display: swap;
  src: url('/assets/fonts/space-grotesk-500.woff2') format('woff2');
}
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal; font-weight: 600; font-display: swap;
  src: url('/assets/fonts/space-grotesk-600.woff2') format('woff2');
}
@font-face {
  font-family: 'Space Grotesk';
  font-style: normal; font-weight: 700; font-display: swap;
  src: url('/assets/fonts/space-grotesk-700.woff2') format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal; font-weight: 400; font-display: swap;
  src: url('/assets/fonts/jetbrains-mono-400.woff2') format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal; font-weight: 500; font-display: swap;
  src: url('/assets/fonts/jetbrains-mono-500.woff2') format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal; font-weight: 600; font-display: swap;
  src: url('/assets/fonts/jetbrains-mono-600.woff2') format('woff2');
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal; font-weight: 700; font-display: swap;
  src: url('/assets/fonts/jetbrains-mono-700.woff2') format('woff2');
}

:root {
  --bg:          #0a0e14;   /* near-black de fond */
  --bg-2:        #0d1219;   /* surface légèrement plus claire */
  --surface:     #11161f;   /* cartes */
  --surface-2:   #151c27;   /* hover carte */
  --ink:         #e6edf3;   /* texte principal / titres */
  --body:        #c8d0da;   /* CORPS de prose : gris clair lisible (~11:1) */
  --muted:       #9aa7b6;   /* texte secondaire (légendes, labels) */
  --faint:       #66778a;   /* texte très discret / commentaires (~5:1 sur --bg) */
  --accent:      #00ff9c;   /* vert terminal : dominante */
  --accent-dim:  #00c97c;   /* vert assombri pour grands aplats lisibles */
  --cyan:        #00e5ff;   /* cyan : secondaire */
  --border:      #1e2733;   /* bordures discrètes */
  --border-lit:  #2b3a4d;   /* bordures légèrement visibles */
  --glow:        0 0 0 1px rgba(0,255,156,.35), 0 0 24px -4px rgba(0,255,156,.45);
  --glow-cyan:   0 0 0 1px rgba(0,229,255,.35), 0 0 24px -4px rgba(0,229,255,.4);

  /* ── ÉCHELLE TYPOGRAPHIQUE MODULAIRE (ratio ~1.25, base 1rem) ──
     Réservée au corps/labels ; les titres restent en clamp() fluide. */
  --fs-xs:   0.78rem;   /* labels mono, tags */
  --fs-sm:   0.875rem;  /* notes, légendes */
  --fs-base: 1rem;      /* corps de texte */
  --fs-md:   1.08rem;   /* lead, accroche */
  --fs-lg:   1.25rem;
  --fs-xl:   1.563rem;
  --lh-tight: 1.25;     /* titres */
  --lh-snug:  1.5;      /* sous-titres */
  --lh-body:  1.75;     /* prose confortable */

  /* ── SYSTÈME D'ESPACEMENT (échelle 4px, multiples réguliers) ── */
  --sp-1: 4px;
  --sp-2: 8px;
  --sp-3: 12px;
  --sp-4: 16px;
  --sp-5: 24px;
  --sp-6: 32px;
  --sp-7: 48px;
  --sp-8: 64px;
  --sp-9: 80px;
  --sp-10: 96px;

  /* Rythme vertical des sections (fluide, cohérent partout) */
  --section-pad: clamp(56px, 9vw, 88px);
  --hero-pad-top: clamp(72px, 12vw, 104px);

  /* Largeur de lecture confortable pour la prose */
  --measure: 65ch;

  /* ── TRANSITIONS COHÉRENTES (mêmes durées/easings partout) ── */
  --ease: cubic-bezier(.2, .7, .2, 1);
  --t-fast: .15s var(--ease);
  --t-mid:  .25s var(--ease);
  --t-slow: .5s var(--ease);
}

/* Contrastes WCAG AA (sur fond --bg #0a0e14) :
   --ink   #e6edf3 → 15.0:1  ✓ (titres / texte fort)
   --body  #c8d0da → 11.4:1  ✓ (CORPS de prose : confort de lecture)
   --muted #9aa7b6 →  8.0:1  ✓ (texte secondaire)
   --faint #66778a →  4.9:1  ✓ (détails discrets, gros texte uniquement)
   --accent #00ff9c → 13.9:1 ✓ (accents / titres seulement, jamais en gros volume)
   --cyan  #00e5ff → 11.2:1  ✓
   --bg sur --accent (boutons pleins) → inversé, conforme ✓ */

* { box-sizing: border-box; margin: 0; padding: 0; }

html { scroll-behavior: smooth; overflow-x: hidden; }

body {
  font-family: 'Space Grotesk', system-ui, -apple-system, sans-serif;
  background: var(--bg);
  color: var(--body);
  font-size: var(--fs-base);
  line-height: var(--lh-body);
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: hidden;
}

/* Grille technique de fond, ultra discrète, fixée derrière tout */
body::before {
  content: "";
  position: fixed;
  inset: 0;
  z-index: -2;
  background-image:
    linear-gradient(rgba(0,255,156,.025) 1px, transparent 1px),
    linear-gradient(90deg, rgba(0,255,156,.025) 1px, transparent 1px);
  background-size: 48px 48px;
  pointer-events: none;
}
/* Halo radial subtil en haut de page */
body::after {
  content: "";
  position: fixed;
  top: -20%;
  left: 50%;
  width: 900px;
  height: 600px;
  transform: translateX(-50%);
  z-index: -2;
  background: radial-gradient(ellipse at center, rgba(0,255,156,.10), transparent 70%);
  pointer-events: none;
}

.wrap { max-width: 880px; margin: 0 auto; padding: 0 var(--sp-5); }

a { color: var(--accent); }

/* ── SKIP-LINK : caché hors écran, révélé au focus clavier ── */
.skip-link {
  position: fixed;
  top: var(--sp-2);
  left: var(--sp-2);
  z-index: 10000;
  transform: translateY(-150%);
  background: var(--accent);
  color: #04140d;
  font-family: 'JetBrains Mono', monospace;
  font-size: var(--fs-sm);
  font-weight: 600;
  padding: 10px 16px;
  border-radius: 6px;
  text-decoration: none;
  box-shadow: 0 0 24px -2px rgba(0,255,156,.6);
  transition: transform var(--t-mid);
}
.skip-link:focus {
  transform: translateY(0);
  outline: 2px solid var(--ink);
  outline-offset: 2px;
}
/* La cible du skip-link reçoit le focus programmatique : pas d'anneau
   disgracieux sur tout le <main>, mais focus réellement déplacé. */
#contenu:focus { outline: none; }
#contenu:focus-visible { outline: none; }

/* Texte mono utilitaire */
.mono { font-family: 'JetBrains Mono', ui-monospace, monospace; }

/* ── HEADER ── */
header {
  padding: 22px 0;
  display: flex;
  justify-content: space-between;
  align-items: center;
  gap: 12px;
  flex-wrap: wrap;
  border-bottom: 1px solid var(--border);
}
.brand {
  font-family: 'JetBrains Mono', monospace;
  font-size: 1rem;
  font-weight: 600;
  letter-spacing: .5px;
  color: var(--ink);
  display: inline-flex;
  align-items: center;
  gap: 8px;
}
.brand::before {
  content: "$";
  color: var(--accent);
  font-weight: 700;
}
.nav-cta a {
  font-family: 'JetBrains Mono', monospace;
  font-size: .82rem;
  font-weight: 500;
  color: var(--accent);
  text-decoration: none;
  border: 1px solid var(--border-lit);
  padding: 9px 16px;
  border-radius: 6px;
  white-space: nowrap;
  min-height: 40px;
  display: inline-flex;
  align-items: center;
  background: rgba(0,255,156,.03);
  transition: box-shadow var(--t-mid), border-color var(--t-mid), background var(--t-mid);
}
.nav-cta a:hover,
.nav-cta a:focus-visible {
  border-color: var(--accent);
  box-shadow: var(--glow);
  background: rgba(0,255,156,.08);
  outline: none;
}

/* ── HEADER : groupe droit (sélecteur langue + CTA) ── */
.header-right {
  display: flex;
  align-items: center;
  gap: var(--sp-4);
}
/* ── SÉLECTEUR DE LANGUE FR | EN (lien simple, zéro JS) ── */
.lang-switch {
  display: inline-flex;
  align-items: center;
  gap: 6px;
  font-family: 'JetBrains Mono', monospace;
  font-size: .8rem;
  font-weight: 500;
}
.lang-switch a {
  color: var(--muted);
  text-decoration: none;
  padding: 6px 8px;
  border-radius: 5px;
  min-height: 44px;
  min-width: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  transition: color var(--t-mid), background var(--t-mid);
}
.lang-switch a:hover,
.lang-switch a:focus-visible {
  color: var(--accent);
  background: rgba(0,255,156,.06);
  outline: none;
}
.lang-switch a[aria-current="page"] {
  color: var(--accent);
  font-weight: 700;
}
.lang-sep { color: var(--border-lit); }

/* ── HERO ── */
.section-hero {
  position: relative;
  overflow: hidden;
}
.hero-inner {
  max-width: 880px;
  margin: 0 auto;
  padding: var(--hero-pad-top) var(--sp-5) var(--section-pad);
  position: relative;
  z-index: 1;
}
/* lignes scanline animées très discrètes sur le hero */
.section-hero::after {
  content: "";
  position: absolute;
  inset: 0;
  z-index: 0;
  background: repeating-linear-gradient(
    to bottom,
    transparent 0,
    transparent 2px,
    rgba(0,255,156,.02) 3px,
    transparent 4px
  );
  pointer-events: none;
}
.hero-eyebrow {
  font-family: 'JetBrains Mono', monospace;
  font-size: .78rem;
  font-weight: 500;
  letter-spacing: 1px;
  color: var(--accent);
  margin-bottom: 22px;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  padding: 6px 12px;
  border: 1px solid var(--border-lit);
  border-radius: 999px;
  background: rgba(0,255,156,.04);
}
.hero-eyebrow::before {
  content: "";
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 10px var(--accent);
  animation: pulse 2.4s ease-in-out infinite;
}
@keyframes pulse {
  0%, 100% { opacity: 1; }
  50% { opacity: .35; }
}
.hero-prompt {
  font-family: 'JetBrains Mono', monospace;
  font-size: .9rem;
  color: var(--faint);
  margin-bottom: 14px;
}
.hero-prompt .cmd { color: var(--cyan); }
.section-hero h1 {
  font-size: clamp(2.1rem, 5.6vw, 3.5rem);
  font-weight: 600;
  line-height: 1.1;
  letter-spacing: -1px;
  color: var(--ink);
  max-width: 760px;
  margin-bottom: var(--sp-5);
  /* Réserve la hauteur pendant la frappe du typewriter (anti layout-shift CLS).
     ~4 lignes sur mobile étroit, réduit sur large où le titre tient en ~3. */
  min-height: calc(4 * 1.1em);
}
@media (min-width: 600px) {
  .section-hero h1 { min-height: calc(3 * 1.1em); }
}
.section-hero h1 .hl {
  color: var(--accent);
  text-shadow: 0 0 30px rgba(0,255,156,.4);
}
/* curseur clignotant après le titre typewriter */
.cursor {
  display: inline-block;
  width: .58ch;
  background: var(--accent);
  margin-left: 2px;
  box-shadow: 0 0 12px var(--accent);
  animation: blink 1.05s steps(1) infinite;
}
@keyframes blink { 50% { opacity: 0; } }
.section-hero .lead {
  font-size: var(--fs-md);
  color: var(--body);
  max-width: min(60ch, 100%);
  margin-bottom: var(--sp-6);
  line-height: var(--lh-body);
}
.cta-hero {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
}
.cta-hero a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: var(--accent);
  color: #04140d;
  font-family: 'JetBrains Mono', monospace;
  font-weight: 600;
  font-size: .95rem;
  padding: 15px 28px;
  border-radius: 8px;
  text-decoration: none;
  min-height: 52px;
  transition: transform var(--t-fast), box-shadow var(--t-mid);
}
.cta-hero a:hover,
.cta-hero a:focus-visible {
  transform: translateY(-2px);
  box-shadow: 0 0 28px -2px rgba(0,255,156,.6);
  outline: none;
}

/* ── SECTIONS GÉNÉRIQUES ── */
.section-contact { padding: var(--section-pad) 0; border-top: 1px solid var(--border); }
.section-proofs  { padding: var(--section-pad) 0; border-top: 1px solid var(--border); }

.section-label {
  font-family: 'JetBrains Mono', monospace;
  font-size: var(--fs-xs);
  font-weight: 500;
  letter-spacing: 1px;
  color: var(--accent);
  margin-bottom: var(--sp-5);
  display: inline-flex;
  align-items: center;
}
.section-label::before {
  content: "// ";
  color: var(--faint);
  margin-right: 6px;
  white-space: pre;
}

.section-contact h2,
.section-proofs h2 {
  font-size: clamp(1.5rem, 3.2vw, 2.1rem);
  font-weight: 600;
  color: var(--ink);
  max-width: 620px;
  line-height: var(--lh-tight);
  margin-bottom: var(--sp-6);
  letter-spacing: -.5px;
  text-wrap: balance;
}
.section-proofs h2 { margin-bottom: var(--sp-7); }

.section-contact p {
  font-size: var(--fs-base);
  color: var(--body);
  line-height: var(--lh-body);
  max-width: var(--measure);
  margin-bottom: var(--sp-4);
}
.section-contact p:last-of-type { margin-bottom: 0; }
.section-contact p strong { color: var(--ink); font-weight: 600; }

/* note "téléchargez le CV" sous le contact : espacée du bloc CTA */
.cv-fallback { margin-top: var(--sp-5); font-size: var(--fs-sm); }

/* badge ">" devant le nom de l'employeur dans Expérience */
.role-line {
  font-family: 'JetBrains Mono', monospace;
  margin-bottom: var(--sp-2) !important;
}
.role-line::before {
  content: "> ";
  color: var(--accent);
}

/* ── CARTES DE COMPÉTENCES / RÉALISATION ── */
.proof-list {
  display: grid;
  grid-template-columns: 1fr;
  gap: 18px;
}
.proof-item {
  position: relative;
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 12px;
  padding: 26px 26px 28px;
  overflow: hidden;
  transition: transform var(--t-mid), border-color var(--t-mid), box-shadow var(--t-mid), background var(--t-mid);
}
/* liseré accent en haut de carte, révélé au hover */
.proof-item::before {
  content: "";
  position: absolute;
  top: 0; left: 0; right: 0;
  height: 2px;
  background: linear-gradient(90deg, var(--accent), var(--cyan));
  transform: scaleX(0);
  transform-origin: left;
  transition: transform .35s ease;
}
.proof-item:hover,
.proof-item:focus-within {
  transform: translateY(-4px);
  border-color: var(--border-lit);
  background-color: var(--surface-2);
  box-shadow: var(--glow);
}
.proof-item:hover::before,
.proof-item:focus-within::before {
  transform: scaleX(1);
}
.proof-item h3 {
  font-size: 1.12rem;
  font-weight: 600;
  color: var(--ink);
  margin-bottom: 14px;
  display: flex;
  align-items: center;
  gap: 10px;
}
.proof-item h3::before {
  content: ">";
  font-family: 'JetBrains Mono', monospace;
  color: var(--accent);
  font-weight: 700;
}
.proof-item p {
  font-size: var(--fs-sm);
  color: var(--body);
  line-height: var(--lh-body);
}

/* pills de techno monospace */
.tags {
  list-style: none;
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin-top: 18px;
}
.tags li {
  font-family: 'JetBrains Mono', monospace;
  font-size: .74rem;
  color: var(--accent);
  border: 1px solid var(--border-lit);
  background: rgba(0,255,156,.04);
  padding: 4px 10px;
  border-radius: 999px;
  white-space: nowrap;
  transition: border-color var(--t-mid), color var(--t-mid);
}
.proof-item:hover .tags li { border-color: rgba(0,255,156,.35); }

/* ── CONTACT CTA OUTLINE ── */
.cta-outline { margin-top: 32px; }
.cta-outline a {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  background: transparent;
  color: var(--accent);
  font-family: 'JetBrains Mono', monospace;
  font-weight: 600;
  font-size: 1rem;
  padding: 14px 26px;
  border: 1px solid var(--border-lit);
  border-radius: 8px;
  text-decoration: none;
  min-height: 50px;
  transition: box-shadow var(--t-mid), border-color var(--t-mid), background var(--t-mid);
}
.cta-outline a::before { content: "→ "; color: var(--faint); }
.cta-outline a:hover,
.cta-outline a:focus-visible {
  border-color: var(--accent);
  box-shadow: var(--glow);
  background: rgba(0,255,156,.06);
  outline: none;
}
.section-contact a { color: var(--accent); text-decoration: none; }
.section-contact a:hover,
.section-contact a:focus-visible { text-decoration: underline; }

/* ── FOOTER ── */
footer {
  border-top: 1px solid var(--border);
  padding: var(--sp-6) 0 var(--sp-7);
  color: var(--muted);
  font-size: var(--fs-sm);
  font-family: 'JetBrains Mono', monospace;
}
footer a { color: var(--muted); text-decoration: none; }
footer a:hover,
footer a:focus-visible { color: var(--accent); }
.footer-links {
  margin-top: var(--sp-2);
  display: flex;
  flex-wrap: wrap;
  gap: var(--sp-1) var(--sp-5);
}
/* zone tactile confortable sur les liens légaux (≥44px de hauteur) */
.footer-links a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  padding: 4px 0;
}

/* ── SCROLL-REVEAL ──
   Progressive enhancement : visible par défaut. L'état caché (opacity:0)
   n'est appliqué que si JS est vivant (html.js, posé par app.js), pour que
   le contenu reste visible si le script ne tourne pas (WebView, JS cassé). */
.js .reveal {
  opacity: 0;
  transform: translateY(22px);
  transition: opacity .6s var(--ease), transform .6s var(--ease);
  will-change: opacity, transform;
}
.js .reveal.is-visible {
  opacity: 1;
  transform: none;
}

/* ── FOCUS GLOBAL VISIBLE ── */
:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 3px;
  border-radius: 4px;
}

/* ════════════════════════════════════════════════════════════════
   RESPONSIVE : vérifié à 360px / 768px / 1440px
   Objectifs : zéro débordement horizontal, cibles tactiles ≥44px,
   terminal lisible, status bar discrète (chemin masqué) sur mobile.
   ════════════════════════════════════════════════════════════════ */

/* Grand écran : largeur de lecture un peu plus généreuse */
@media (min-width: 1280px) {
  .wrap, .hero-inner { max-width: 920px; }
}

@media (min-width: 720px) {
  .proof-list { grid-template-columns: repeat(2, 1fr); }
  /* La réalisation unique occupe toute la largeur */
  .section-proofs.single .proof-list { grid-template-columns: 1fr; }
}

/* Tablette / petit portable */
@media (max-width: 768px) {
  .section-hero h1 { font-size: clamp(1.9rem, 7vw, 2.6rem); }
  .section-hero .lead { max-width: 100%; }
  /* Cibles tactiles confortables (≥44px) pour le CTA d'en-tête */
  .nav-cta a { min-height: 44px; }
}

/* Mobile (≈360:480px) */
@media (max-width: 480px) {
  .wrap { padding: 0 var(--sp-4); }
  .hero-inner { padding: clamp(56px, 16vw, 72px) var(--sp-4) var(--sp-8); }
  header { padding: var(--sp-4) 0; gap: var(--sp-2); }
  /* En-tête : la marque garde sa ligne, le bloc droit (langue + liens)
     passe dessous sur toute la largeur et wrappe, plus aucun débordement. */
  .brand { font-size: .92rem; }
  /* Layout déterministe : langue sur sa ligne, puis les 2 CTA côte à côte
     en largeurs égales. Évite l'escalier mal aligné du flex-wrap libre,
     qui cassait différemment selon la largeur exacte du téléphone. */
  .header-right {
    gap: var(--sp-3);
    flex-wrap: wrap;
    width: 100%;
    justify-content: flex-start;
  }
  .lang-switch { font-size: .74rem; gap: 2px; flex-basis: 100%; }
  .lang-switch a { padding: 6px 5px; min-width: 30px; }
  .nav-cta {
    display: flex;
    flex-wrap: nowrap;
    gap: var(--sp-2);
    width: 100%;
  }
  .nav-cta a {
    flex: 1 1 0;
    justify-content: center;
    padding: 11px 10px;
    font-size: .76rem;
    min-height: 44px;
  }
  .cta-hero { flex-direction: column; align-items: stretch; }
  .cta-hero a { justify-content: center; width: 100%; }
  .proof-item { padding: var(--sp-5) var(--sp-4); }
  /* Empêche tout débordement des longues chaînes mono (tags, commandes) */
  .tags li { font-size: .72rem; }
  /* Terminal : garde une hauteur exploitable sans manger tout l'écran */
  .term-body { max-height: 46vh; }
  /* Lien CV de secours (prose) : zone tactile plus large.
     Exclut les boutons .cta-outline a / .cta-hero a qui ont leur propre layout. */
  .section-contact p a { display: inline-block; padding: 4px 0; }
}

/* Très petit (≤360px) : on resserre encore sans casser */
@media (max-width: 360px) {
  .hero-eyebrow { font-size: .72rem; letter-spacing: .5px; }
  .stat .num { font-size: 1.6rem; }
}

/* ── STATUS BAR responsive : discrète, jamais gênante ── */
@media (max-width: 700px) {
  /* Le chemin de fichier central est masqué : il déborderait sinon */
  #status-bar .sb-file { display: none; }
  #status-bar .sb-branch { font-size: .66rem; }
}
@media (max-width: 420px) {
  /* Encore plus minimal : mode + heure seulement */
  #status-bar .sb-branch { display: none; }
  #status-bar .sb-pos { display: none; }
}

/* ════════════════════════════════════════════════════════════════
   CANVAS DE FOND : réseau de nœuds qui pulse (très discret)
   Fixé tout au fond, sous la grille et le contenu. Le JS gère le rendu,
   le throttle et la pause onglet caché. Opacité faible = lisibilité
   du texte jamais compromise.
   ════════════════════════════════════════════════════════════════ */
#bg-canvas {
  position: fixed;
  inset: 0;
  z-index: -3;          /* sous body::before (grille, -2) et body::after */
  pointer-events: none;
  opacity: .5;
}

/* ════════════════════════════════════════════════════════════════
   BOOT SEQUENCE : faux écran de boot terminal (overlay par-dessus)
   Le contenu réel reste dans le DOM (SEO/no-JS) ; ceci n'est qu'un
   voile temporaire, retiré après ~1.5 s ou au skip.
   ════════════════════════════════════════════════════════════════ */
#boot[hidden] { display: none !important; }
#boot {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: var(--bg);
  color: var(--accent);
  font-family: 'JetBrains Mono', ui-monospace, monospace;
  font-size: .92rem;
  line-height: 1.85;
  padding: clamp(24px, 6vw, 80px);
  display: flex;
  flex-direction: column;
  justify-content: center;
  overflow: hidden;
  transition: opacity .5s ease;
}
#boot.boot-done {
  opacity: 0;
  pointer-events: none;
}
.boot-lines { max-width: 720px; width: 100%; margin: 0 auto; }
.boot-line {
  white-space: pre-wrap;
  opacity: 0;
  transform: translateY(4px);
  transition: opacity .25s ease, transform .25s ease;
}
.boot-line.on { opacity: 1; transform: none; }
.boot-ok  { color: var(--accent); }
.boot-tag { color: var(--cyan); }
.boot-dim { color: var(--faint); }
.boot-cursor {
  display: inline-block;
  width: .6ch;
  height: 1.1em;
  vertical-align: -.18em;
  background: var(--accent);
  box-shadow: 0 0 12px var(--accent);
  animation: blink 1.05s steps(1) infinite;
}
.boot-skip {
  position: absolute;
  bottom: clamp(18px, 4vw, 40px);
  left: 50%;
  transform: translateX(-50%);
  color: var(--faint);
  font-size: .76rem;
  letter-spacing: .5px;
  /* reset des styles UA du <button> pour garder l'aspect d'avant */
  appearance: none;
  background: none;
  border: 0;
  padding: 6px 10px;
  font-family: inherit;
  cursor: pointer;
  border-radius: 6px;
}
.boot-skip:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
  color: var(--accent);
}
/* Évite un flash de contenu non boot-é : pendant le boot le scroll est figé */
body.booting { overflow: hidden; }

/* ════════════════════════════════════════════════════════════════
   HERO TERMINAL INTERACTIF : mini-shell sous le hero
   PLUS optionnel : le contenu texte du hero reste pour SEO/no-JS.
   Injecté par JS dans .term-mount (vide en HTML → rien si JS off).
   ════════════════════════════════════════════════════════════════ */
.term {
  margin-top: 34px;
  max-width: 680px;
  background: var(--surface);
  border: 1px solid var(--border-lit);
  border-radius: 10px;
  overflow: hidden;
  box-shadow: 0 0 0 1px rgba(0,255,156,.06), 0 18px 50px -20px rgba(0,0,0,.8);
}
.term-bar {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 14px;
  background: var(--bg-2);
  border-bottom: 1px solid var(--border);
  font-family: 'JetBrains Mono', monospace;
  font-size: .74rem;
  color: var(--faint);
}
.term-dot {
  width: 11px; height: 11px; border-radius: 50%;
  background: var(--border-lit);
}
.term-dot.g { background: var(--accent); box-shadow: 0 0 8px rgba(0,255,156,.5); }
.term-title { margin-left: 8px; }
.term-body {
  padding: 16px 16px 6px;
  font-family: 'JetBrains Mono', monospace;
  font-size: .86rem;
  line-height: 1.7;
  max-height: 320px;
  overflow-y: auto;
  color: var(--ink);
}
.term-out { white-space: pre-wrap; word-break: break-word; }
.term-out .ln { display: block; }
.term-out .c-accent { color: var(--accent); }
.term-out .c-cyan   { color: var(--cyan); }
.term-out .c-muted  { color: var(--muted); }
.term-out .c-faint  { color: var(--faint); }
.term-echo { color: var(--cyan); }
.term-inputline {
  display: flex;
  align-items: center;
  gap: 8px;
  padding: 10px 16px 16px;
  font-family: 'JetBrains Mono', monospace;
  font-size: .86rem;
}
.term-prompt { color: var(--accent); white-space: nowrap; }
.term-input {
  flex: 1;
  background: transparent;
  border: none;
  outline: none;
  color: var(--ink);
  font-family: 'JetBrains Mono', monospace;
  font-size: 16px;           /* ≥16px = pas de zoom auto iOS au focus */
  line-height: 1.4;
  min-height: 28px;
  caret-color: var(--accent);
  min-width: 0;
}
.term-input::placeholder { color: var(--muted); }
.term-inputline:focus-within {
  box-shadow: inset 0 0 0 2px rgba(0,255,156,.55);
  border-radius: 6px;
}
/* label visuellement masqué mais lisible par lecteur d'écran */
.sr-only {
  position: absolute;
  width: 1px; height: 1px;
  padding: 0; margin: -1px;
  overflow: hidden;
  clip: rect(0,0,0,0);
  white-space: nowrap;
  border: 0;
}

/* ════════════════════════════════════════════════════════════════
   COMPTEURS ANIMÉS + BARRES DE COMPÉTENCE
   Animés au scroll (IntersectionObserver, même pattern que .reveal).
   Chiffres = uniquement des valeurs déjà vraies dans le contenu.
   ════════════════════════════════════════════════════════════════ */
.stats {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 14px;
  margin-top: 28px;
}
@media (min-width: 560px) {
  .stats { grid-template-columns: repeat(4, 1fr); }
}
.stat {
  background: var(--surface);
  border: 1px solid var(--border);
  border-radius: 10px;
  padding: 18px 16px;
  text-align: left;
}
.stat .num {
  font-family: 'JetBrains Mono', monospace;
  font-size: 1.9rem;
  font-weight: 700;
  color: var(--accent);
  line-height: 1.1;
  text-shadow: 0 0 24px rgba(0,255,156,.3);
}
.stat .num .suffix { color: var(--cyan); }
.stat .lbl {
  font-size: .82rem;
  color: var(--muted);
  margin-top: 6px;
  line-height: 1.4;
}

/* Barres de niveau sur les cartes de compétence */
.skillbar {
  margin-top: 18px;
  display: flex;
  flex-direction: column;
  gap: 4px;
}
.skillbar .skl-head {
  display: flex;
  justify-content: space-between;
  font-family: 'JetBrains Mono', monospace;
  font-size: .72rem;
  color: var(--faint);
  letter-spacing: .3px;
}
.skillbar .skl-track {
  height: 6px;
  border-radius: 999px;
  background: var(--bg-2);
  border: 1px solid var(--border);
  overflow: hidden;
}
.skillbar .skl-fill {
  height: 100%;
  width: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--accent), var(--cyan));
  transition: width 1.1s cubic-bezier(.2,.7,.2,1);
}

/* ════════════════════════════════════════════════════════════════
   MICRO-INTERACTION : tilt léger au hover (en plus du glow existant)
   Le JS applique --rx/--ry ; transform composé avec le translateY hover.
   ════════════════════════════════════════════════════════════════ */
.proof-item {
  transform-style: preserve-3d;
}
.proof-item.tilt:hover {
  transform: perspective(720px)
             rotateX(var(--ry, 0deg))
             rotateY(var(--rx, 0deg))
             translateY(-4px);
}

/* ════════════════════════════════════════════════════════════════
   EFFET GLITCH sur le titre hero (h1 + .hero-eyebrow)
   CSS-only, clip-path + text-shadow décalé RGB.
   Boucle lente (8 s) pour rester lisible, pas de sapin de Noël.
   ════════════════════════════════════════════════════════════════ */
@keyframes glitch-clip {
  0%,  92%, 100% { clip-path: inset(0 0 100% 0); transform: translate(0, 0);   opacity: 0; }
  93%             { clip-path: inset(8%  0 80%  0); transform: translate(-3px, 1px); opacity: 1; }
  94%             { clip-path: inset(62% 0 12%  0); transform: translate( 3px,-1px); opacity: 1; }
  95%             { clip-path: inset(30% 0 50%  0); transform: translate(-2px, 2px); opacity: 1; }
  96%             { clip-path: inset(0   0 0    0); transform: translate(0, 0);   opacity: 0; }
}
@keyframes glitch-red {
  0%,  92%, 100% { opacity: 0; transform: translate(0, 0); }
  93%             { opacity: .7; transform: translate( 4px,-1px); }
  94%             { opacity: .7; transform: translate(-4px, 2px); }
  95%             { opacity: .5; transform: translate( 2px,-2px); }
  96%             { opacity: 0; }
}
@keyframes glitch-blue {
  0%,  92%, 100% { opacity: 0; transform: translate(0, 0); }
  93%             { opacity: .6; transform: translate(-4px, 1px); }
  94%             { opacity: .6; transform: translate( 3px,-2px); }
  95%             { opacity: .4; transform: translate(-2px, 1px); }
  96%             { opacity: 0; }
}

.section-hero h1 {
  position: relative;
}
/* Calque rouge (canal R décalé) : aria-hidden géré sur le h1 par JS */
.section-hero h1::before {
  content: attr(data-glitch);
  position: absolute;
  inset: 0;
  color: #ff003c;
  mix-blend-mode: screen;
  animation: glitch-red 8s steps(1) infinite;
  pointer-events: none;
  user-select: none;
}
/* Calque bleu (canal B décalé) */
.section-hero h1::after {
  content: attr(data-glitch);
  position: absolute;
  inset: 0;
  color: #00e5ff;
  mix-blend-mode: screen;
  animation: glitch-blue 8s steps(1) infinite;
  animation-delay: .05s;
  pointer-events: none;
  user-select: none;
}

/* ════════════════════════════════════════════════════════════════
   OVERLAY CRT : scanlines + flicker très discret sur toute la page
   Overlay décoratif fixé dessus tout, aria-hidden (injecté par JS).
   Opacity volontairement basse pour ne PAS compromettre le contraste.
   ════════════════════════════════════════════════════════════════ */
@keyframes crt-flicker {
  0%, 19%, 21%, 50%, 52%, 100% { opacity: .04; }
  20%, 51% { opacity: .06; }
}
#crt-overlay {
  position: fixed;
  inset: 0;
  z-index: 9998;        /* dessus tout sauf boot (#boot = 9999) */
  pointer-events: none;
  background: repeating-linear-gradient(
    to bottom,
    rgba(0, 0, 0, .08) 0px,
    rgba(0, 0, 0, .08) 1px,
    transparent 1px,
    transparent 3px
  );
  animation: crt-flicker 4.5s steps(1) infinite;
  will-change: opacity;
}

/* ════════════════════════════════════════════════════════════════
   MICRO-INTERACTION CARTES : scan-line qui balaie au hover
   Pseudo-élément ::after ajouté via la classe .proof-item existante
   (::before est déjà pris par le liseré accent).
   ════════════════════════════════════════════════════════════════ */
@keyframes card-scan {
  0%   { top: -4px; opacity: .55; }
  100% { top: calc(100% + 4px); opacity: 0; }
}
.proof-item::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: -4px;
  height: 2px;
  background: linear-gradient(90deg,
    transparent 0%,
    rgba(0,255,156,.6) 30%,
    rgba(0,229,255,.8) 50%,
    rgba(0,255,156,.6) 70%,
    transparent 100%
  );
  opacity: 0;
  pointer-events: none;
  border-radius: 1px;
  /* déclenché par :hover via animation */
}
.proof-item:hover::after,
.proof-item:focus-within::after {
  animation: card-scan .55s ease-in forwards;
}

/* ════════════════════════════════════════════════════════════════
   MATRIX RAIN : overlay canvas éphémère (commande `matrix` + Konami)
   Injecté/retiré par JS. Plein écran, décoratif, aria-hidden.
   Sous le boot/CRT mais au-dessus du contenu pour l'effet « waouh ».
   ════════════════════════════════════════════════════════════════ */
.matrix-rain {
  position: fixed;
  inset: 0;
  z-index: 9990;
  pointer-events: none;
  opacity: 1;
  transition: opacity .3s ease;
}

/* ════════════════════════════════════════════════════════════════
   KONAMI : burst de glitch intensifié quelques secondes
   Accélère la boucle glitch du titre + secoue très légèrement.
   ════════════════════════════════════════════════════════════════ */
@keyframes konami-shake {
  0%, 100% { transform: translate(0, 0); }
  20% { transform: translate(-1px, 1px); }
  40% { transform: translate(1px, -1px); }
  60% { transform: translate(-1px, -1px); }
  80% { transform: translate(1px, 1px); }
}
.konami-glitch .section-hero h1::before {
  animation: glitch-red 0.45s steps(1) infinite !important;
}
.konami-glitch .section-hero h1::after {
  animation: glitch-blue 0.45s steps(1) infinite !important;
}
.konami-glitch .section-hero h1 {
  animation: konami-shake 0.3s steps(2) infinite;
}

/* ════════════════════════════════════════════════════════════════
   FADE-IN GLOBAL DE PAGE : apparition douce au chargement
   CSS pur : pas de dépendance JS, pas de FOUC. Désactivé si reduce.
   ════════════════════════════════════════════════════════════════ */
@keyframes page-fade-in {
  from { opacity: 0; }
  to   { opacity: 1; }
}
body {
  animation: page-fade-in .45s var(--ease) both;
}

/* ════════════════════════════════════════════════════════════════
   STATUS BAR : barre fixe en bas, façon tmux/vim
   Contenu mis à jour en JS toutes les secondes.
   ════════════════════════════════════════════════════════════════ */
#status-bar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  z-index: 200;
  height: 22px;
  display: flex;
  align-items: center;
  justify-content: space-between;
  padding: 0 14px;
  background: var(--bg-2);
  border-top: 1px solid var(--border);
  font-family: 'JetBrains Mono', monospace;
  font-size: .7rem;
  color: var(--faint);
  user-select: none;
  pointer-events: none; /* purement décoratif : ne capture pas les clics */
  overflow: hidden;
}
#status-bar .sb-mode {
  background: var(--accent);
  color: #04140d;
  font-weight: 700;
  padding: 0 8px;
  height: 100%;
  display: flex;
  align-items: center;
  letter-spacing: .5px;
  flex-shrink: 0;
}
#status-bar .sb-branch {
  color: var(--cyan);
  flex-shrink: 0;
}
#status-bar .sb-file {
  flex: 1;
  text-align: center;
  color: var(--muted);
  white-space: nowrap;
  overflow: hidden;
  text-overflow: ellipsis;
}
#status-bar .sb-right {
  display: flex;
  align-items: center;
  gap: 12px;
  flex-shrink: 0;
}
#status-bar .sb-pos  { color: var(--faint); }
#status-bar .sb-time { color: var(--accent); }

/* Compensation : le footer ne doit pas être masqué par la status bar */
body { padding-bottom: 22px; }

/* ════════════════════════════════════════════════════════════════
   CURSEUR CUSTOM : réticule / viseur (pointer:fine uniquement)
   Deux couches injectées par app.js : un anneau lissé + un point net.
   Le curseur natif est masqué sur les zones intérieures quand actif.
   ════════════════════════════════════════════════════════════════ */
.cursor-ring,
.cursor-dot {
  position: fixed;
  top: 0;
  left: 0;
  z-index: 9997;             /* sous CRT (9998) et boot (9999) */
  pointer-events: none;
  opacity: 0;
  will-change: transform;
}
.cursor-ring {
  width: 30px;
  height: 30px;
  margin: 0;
  border: 1px solid rgba(0,255,156,.65);
  border-radius: 50%;
  box-shadow: 0 0 12px -2px rgba(0,255,156,.5), inset 0 0 8px -4px rgba(0,255,156,.5);
  transition: width .18s var(--ease), height .18s var(--ease),
              border-color .18s var(--ease), opacity .25s ease;
}
/* réticule : deux traits fins formant une croix au centre de l'anneau */
.cursor-ring::before,
.cursor-ring::after {
  content: "";
  position: absolute;
  background: rgba(0,255,156,.7);
}
.cursor-ring::before {
  top: 50%; left: -7px; right: -7px; height: 1px; transform: translateY(-50%);
}
.cursor-ring::after {
  left: 50%; top: -7px; bottom: -7px; width: 1px; transform: translateX(-50%);
}
.cursor-dot {
  width: 5px;
  height: 5px;
  border-radius: 50%;
  background: var(--accent);
  box-shadow: 0 0 10px rgba(0,255,156,.9);
}
/* visible seulement quand le pointeur est dans la fenêtre */
body.cursor-on .cursor-ring,
body.cursor-on .cursor-dot { opacity: 1; }
/* survol d'un élément interactif → le viseur « lock » (cyan + agrandi) */
.cursor-ring.is-lock {
  width: 46px;
  height: 46px;
  border-color: rgba(0,229,255,.8);
  box-shadow: 0 0 18px -2px rgba(0,229,255,.6), inset 0 0 10px -4px rgba(0,229,255,.6);
}
.cursor-ring.is-lock::before,
.cursor-ring.is-lock::after { background: rgba(0,229,255,.85); }
.cursor-ring.is-press { width: 22px; height: 22px; }
/* masque le curseur natif quand le custom est actif (desktop only) */
body.has-custom-cursor.cursor-on,
body.has-custom-cursor.cursor-on a,
body.has-custom-cursor.cursor-on button,
body.has-custom-cursor.cursor-on .proof-item,
body.has-custom-cursor.cursor-on .stat { cursor: none; }
/* mais on garde un curseur texte explicite dans les champs de saisie */
body.has-custom-cursor.cursor-on input,
body.has-custom-cursor.cursor-on textarea { cursor: text; }

/* ════════════════════════════════════════════════════════════════
   SPOTLIGHT : halo radial doux qui suit le curseur, derrière le contenu
   Variables --spot-x/--spot-y posées par app.js. z négatif = sous le
   texte (jamais de perte de contraste), au-dessus du canvas de fond.
   ════════════════════════════════════════════════════════════════ */
#spotlight {
  position: fixed;
  inset: 0;
  z-index: -1;               /* au-dessus du canvas (-3) et de la grille (-2) */
  pointer-events: none;
  opacity: 0;
  transition: opacity .4s ease;
  background: radial-gradient(
    320px circle at var(--spot-x, 50%) var(--spot-y, 50%),
    rgba(0,255,156,.07),
    rgba(0,229,255,.035) 40%,
    transparent 68%
  );
}

/* ════════════════════════════════════════════════════════════════
   GLOW DIRECTIONNEL des cartes tilt : un halo suit le curseur
   Variables --mx/--my posées par app.js (initTilt). Pseudo-élément
   dédié pour ne pas entrer en conflit avec ::before (liseré) / ::after
   (scan-line). On utilise un layer interne via box-shadow radial.
   ════════════════════════════════════════════════════════════════ */
.proof-item.tilt {
  --mx: 50%;
  --my: 50%;
}
.proof-item.tilt > * { position: relative; z-index: 1; }
.proof-item.tilt::before,
.proof-item.tilt::after { z-index: 2; }
/* halo radial peint via un background-image radial posé sur la carte,
   centré sur le curseur (--mx/--my), sous le contenu */
.proof-item.tilt {
  background-image: radial-gradient(
    260px circle at var(--mx) var(--my),
    rgba(0,255,156,.10),
    transparent 60%
  );
  background-repeat: no-repeat;
  background-color: var(--surface);
  transition: transform var(--t-mid), border-color var(--t-mid),
              box-shadow var(--t-mid), background-color var(--t-mid),
              background-image 0s;
}
.proof-item.tilt.tilt-active { background-color: var(--surface-2); }

/* ════════════════════════════════════════════════════════════════
   REVEAL EN CASCADE (stagger) : délai croissant --d par carte
   Le module .reveal porte l'opacité de la SECTION ; ici on décale
   chaque carte à l'intérieur. Combiné avec is-visible du parent.
   ════════════════════════════════════════════════════════════════ */
.proof-item.stagger {
  opacity: 0;
  transform: translateY(18px) scale(.985);
  transition: opacity .55s var(--ease), transform .55s var(--ease);
  transition-delay: var(--d, 0ms);
  will-change: opacity, transform;
}
.reveal.is-visible .proof-item.stagger {
  opacity: 1;
  transform: none;
}
/* La section RÉALISATIONS (carte unique) n'a pas la classe .reveal sur
   le même nœud que .proof-list ? Si, elle l'a → couvert. */

/* ════════════════════════════════════════════════════════════════
   MAGNETIC BUTTONS : translation douce vers le curseur (--tx/--ty)
   Composée avec les transforms hover existants via une variable.
   ════════════════════════════════════════════════════════════════ */
.magnetic {
  --tx: 0px;
  --ty: 0px;
  transition: transform var(--t-fast), box-shadow var(--t-mid),
              border-color var(--t-mid), background var(--t-mid);
}
.cta-hero a.magnetic {
  transform: translate(var(--tx), var(--ty));
}
.cta-hero a.magnetic:hover,
.cta-hero a.magnetic:focus-visible {
  transform: translate(var(--tx), var(--ty)) translateY(-2px);
}
.cta-outline a.magnetic,
.nav-cta a.magnetic {
  transform: translate(var(--tx), var(--ty));
}

/* ── RÉDUCTION DE MOUVEMENT ── */
@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after {
    animation: none !important;
    transition: none !important;
  }
  /* page-fade-in est tué par animation:none ci-dessus ; sans ça le body
     reste figé sur l'état de départ (opacity:0) et la page apparaît vide. */
  body { opacity: 1 !important; }
  .reveal { opacity: 1; transform: none; }
  .cursor { opacity: 1; }
  /* Compteurs/barres : valeur finale directe, pas d'animation */
  .skillbar .skl-fill { transition: none; }
  .boot-line { opacity: 1; transform: none; }
  /* Le tilt est désactivé : on retombe sur le hover translateY simple */
  .proof-item.tilt:hover { transform: translateY(-4px); }
  #bg-canvas { display: none; }
  /* Glitch, CRT, scan-line : tous désactivés */
  .section-hero h1::before,
  .section-hero h1::after { display: none; }
  #crt-overlay { display: none; }
  .proof-item:hover::after,
  .proof-item:focus-within::after { animation: none !important; }

  /* ── Effets premium ajoutés : tous neutralisés en reduced-motion ── */
  /* Curseur custom & spotlight : pas injectés en JS (reduce coupe initCursor
     /initSpotlight), mais on garde un filet de sécurité défensif si présents. */
  .cursor-ring, .cursor-dot, #spotlight { display: none !important; }
  body.has-custom-cursor.cursor-on,
  body.has-custom-cursor.cursor-on * { cursor: auto !important; }
  /* Glow directionnel des cartes : pas de halo qui suit, fond plat */
  .proof-item.tilt {
    background-image: none !important;
    transition: none !important;
  }
  /* Stagger : état final visible immédiatement, aucun délai */
  .proof-item.stagger {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    transition-delay: 0ms !important;
  }
  /* Magnetic : pas de translation */
  .magnetic, .cta-hero a.magnetic, .cta-outline a.magnetic, .nav-cta a.magnetic {
    transform: none !important;
  }
}

/* ════════════════════════════════════════════════════════════════
   POINTEUR GROSSIER (tactile) : aucun curseur custom / spotlight.
   Filet de sécurité CSS : même si du JS s'égarait, on neutralise.
   ════════════════════════════════════════════════════════════════ */
@media (pointer: coarse) {
  .cursor-ring, .cursor-dot, #spotlight { display: none !important; }
  body.has-custom-cursor,
  body.has-custom-cursor * { cursor: auto !important; }
}
