/* ============================================================
   PATCH FINAL — pdesouza.fr
   Consolidation des rounds v2 + v3 + v4
   À charger APRÈS style.css / terminal.css / animations.css
   Le terminal du hero n'est PAS modifié.
   ============================================================
   Z-INDEX SCALE (documenté)
     0          decoratives passives (body::before)
     1-10       content & rings & timeline dots
     100-999    drawers, dropdowns, sticky panels
     1000       main navigation (.nav)
     2000       sticky modals scoped
     9998       full-screen scanline overlay (body::after)
     9999       admin / preprod overlays
     10000+     fullscreen gates, language modal
   ============================================================
   !important inventory (8 occurrences) — TOUS justifiés ci-dessous
   par un commentaire 1-ligne au-dessus de chaque déclaration.
   ============================================================
   @keyframes ownership : tout move dans css/animations.css
   sauf les keyframes locales scoped à un patch ponctuel.
   ============================================================ */

/* ============ ROUND 1 (patch v2) ============ */

/* ============================================================
   PATCH v2 — Modifications visuelles granulaires
   v2 : retour arrière sur 03E (CTA terminal) et 04D (gradient cartes)
   À ajouter en fin de style.css OU charger comme css/patch-v2.css
   APRÈS style.css.
   ============================================================

   Choix CONSERVÉS :
   - 02 D+E  Titres : barre verticale verte + halo glow
   - 05 B    Nav : crochets [ ] autour du lien actif
   - 08 FX-04  Reveal ligne par ligne (stagger)
   - 09      Liens inline : underline qui se trace

   RETIRÉ en v2 :
   - 03 E (bouton terminal animé)  → retour style actuel
   - 04 D (gradient cartes/widgets) → retour fond uni

   Terminal hero = NON TOUCHÉ.
   ============================================================ */


/* ─────────────────────────────────────────────────────────────
   02 D+E · TITRES — barre verticale + halo discret
   ───────────────────────────────────────────────────────────── */

.hero__headline {
  position: relative;
  padding-left: 1.25rem;
  text-shadow:
    0 0 40px rgba(255, 255, 255, 0.04),
    0 0 28px rgba(0, 255, 65, 0.12);
}

.hero__headline::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.12em;
  bottom: 0.12em;
  width: 4px;
  background: var(--primary);
  border-radius: 2px;
  box-shadow: 0 0 12px rgba(0, 255, 65, 0.45);
}

.article-detail__title {
  position: relative;
  padding-left: 1.1rem;
  text-shadow: 0 0 24px rgba(0, 255, 65, 0.10);
}
.article-detail__title::before {
  content: '';
  position: absolute;
  left: 0;
  top: 0.12em;
  bottom: 0.12em;
  width: 3px;
  background: var(--primary);
  border-radius: 2px;
  box-shadow: 0 0 10px rgba(0, 255, 65, 0.40);
}


/* ─────────────────────────────────────────────────────────────
   05 B · NAV — crochets [ ] autour du lien actif
   ───────────────────────────────────────────────────────────── */

.nav__link--active::before {
  content: '[';
  color: var(--primary);
  margin-right: 4px;
  opacity: 0.85;
}

.nav__link--active::after {
  content: ']';
  position: static;
  width: auto;
  height: auto;
  background: transparent;
  color: var(--primary);
  margin-left: 4px;
  opacity: 0.85;
}
.nav__link--active:hover::after { width: auto; }

.nav__drawer-links a.nav__link--active::before { content: '['; color: var(--primary); margin-right: 4px; }
.nav__drawer-links a.nav__link--active::after  { content: ']'; color: var(--primary); margin-left: 4px; }


/* ─────────────────────────────────────────────────────────────
   08 FX-04 · REVEAL LIGNE PAR LIGNE
   Ajouter class="reveal-stagger" sur un conteneur → enfants directs
   apparaissent en cascade.
   ───────────────────────────────────────────────────────────── */

.reveal-stagger > * {
  opacity: 0;
  transform: translateY(12px);
  transition:
    opacity 0.5s ease-out,
    transform 0.5s ease-out;
}
.reveal-stagger.visible > *:nth-child(1)  { transition-delay: 0ms;   }
.reveal-stagger.visible > *:nth-child(2)  { transition-delay: 80ms;  }
.reveal-stagger.visible > *:nth-child(3)  { transition-delay: 160ms; }
.reveal-stagger.visible > *:nth-child(4)  { transition-delay: 240ms; }
.reveal-stagger.visible > *:nth-child(5)  { transition-delay: 320ms; }
.reveal-stagger.visible > *:nth-child(6)  { transition-delay: 400ms; }
.reveal-stagger.visible > *:nth-child(7)  { transition-delay: 480ms; }
.reveal-stagger.visible > *:nth-child(8)  { transition-delay: 560ms; }
.reveal-stagger.visible > *:nth-child(n+9){ transition-delay: 640ms; }
.reveal-stagger.visible > *  {
  opacity: 1;
  transform: translateY(0);
}

@media (prefers-reduced-motion: reduce) {
  .reveal-stagger > * {
    opacity: 1; transform: none; transition: none;
  }
}


/* ─────────────────────────────────────────────────────────────
   09 · LIENS INLINE — underline qui se trace au hover
   ───────────────────────────────────────────────────────────── */

.article-detail__body a,
.project-detail__desc a,
a.inline-link {
  color: var(--primary);
  text-decoration: none;
  background-image: linear-gradient(var(--primary), var(--primary));
  background-size: 0% 1px;
  background-repeat: no-repeat;
  background-position: 0 100%;
  padding-bottom: 2px;
  transition: background-size 0.35s ease, color 0.2s ease;
}

.article-detail__body a:hover,
.project-detail__desc a:hover,
a.inline-link:hover {
  background-size: 100% 1px;
  color: var(--primary);
}

/* ============ ROUND 2 (patch v3) ============ */

/* ============================================================
   PATCH v3 — 11, 12, 13, 16, 17, 18, 19
   À charger APRÈS patch-v1.css et patch-v2.css
   ============================================================ */

/* --- 11 · TYPEWRITER sur jobtitle — DÉSACTIVÉ ---------------
   L'animation bloquait 1.6s la lecture du jobtitle, info critique
   pour un recruteur qui scanne le portfolio. Affichage instantané.
   Keyframes supprimés (inutilisés).
   ----------------------------------------------------------- */

/* Kicker de section — même idée, plus court */
.section__title--link,
.section__title {
  position: relative;
}

/* --- 13 · SONAR PULSE sur badges live --------------------- */
.live-pulse,
.status-badge--active,
.status-badge--live {
  position: relative;
}
.live-pulse::before,
.status-badge--active::before,
.status-badge--live::before {
  content: '';
  position: absolute;
  left: 8px;
  top: 50%;
  transform: translateY(-50%);
  width: 6px;
  height: 6px;
  border-radius: 50%;
  background: var(--primary);
  box-shadow: 0 0 0 0 rgba(0, 255, 65, 0.55);
  animation: sonar 2s ease-out infinite;
}
/* shift text so dot fits inside existing padding */
.status-badge--active,
.status-badge--live {
  padding-left: 20px !important;
}

@keyframes sonar {
  0%   { box-shadow: 0 0 0 0 rgba(0, 255, 65, 0.55); }
  70%  { box-shadow: 0 0 0 10px rgba(0, 255, 65, 0);  }
  100% { box-shadow: 0 0 0 0 rgba(0, 255, 65, 0);     }
}
@media (prefers-reduced-motion: reduce) {
  .live-pulse::before,
  .status-badge--active::before,
  .status-badge--live::before { animation: none; }
}

/* --- 16 · SCROLLBAR fluide & discrète --- */
/* Native scrollbar avec flèches → bruit visuel. Custom transparente
   avec thumb phosphor faible, plus appuyé au survol. Cross-browser
   (Firefox + WebKit), pas de JS. */
* { scrollbar-width: thin; scrollbar-color: rgba(0, 255, 65, 0.22) transparent; }

/* WebKit (Chrome/Safari/Edge) */
::-webkit-scrollbar { width: 8px; height: 8px; }
::-webkit-scrollbar-track { background: transparent; }
::-webkit-scrollbar-thumb {
  background: rgba(0, 255, 65, 0.18);
  border-radius: 4px;
  border: 2px solid transparent;
  background-clip: content-box;
  transition: background 0.2s ease;
}
::-webkit-scrollbar-thumb:hover  { background: rgba(0, 255, 65, 0.45); background-clip: content-box; }
::-webkit-scrollbar-thumb:active { background: rgba(0, 255, 65, 0.6);  background-clip: content-box; }
::-webkit-scrollbar-button { display: none; height: 0; width: 0; }
::-webkit-scrollbar-corner { background: transparent; }

/* --- 17 · CARD FLIP 3D sur project-card (projects page) -- */
/* Activé seulement si la carte a .project-card--flip */
.project-card--flip {
  perspective: 900px;
  background: transparent !important;
  border: none !important;
  padding: 0 !important;
}
.project-card--flip .project-card__inner {
  position: relative;
  width: 100%;
  min-height: 180px;
  transition: transform 0.6s cubic-bezier(0.2, 0.8, 0.2, 1);
  transform-style: preserve-3d;
}
.project-card--flip:hover .project-card__inner,
.project-card--flip:focus-within .project-card__inner {
  transform: rotateY(180deg);
}
.project-card--flip .project-card__face {
  position: absolute;
  inset: 0;
  backface-visibility: hidden;
  -webkit-backface-visibility: hidden;
  background: rgba(8, 13, 22, 0.9);
  border: 1px solid rgba(0, 255, 65, 0.25);
  border-radius: 4px;
  padding: 1rem;
  display: flex;
  flex-direction: column;
}
.project-card--flip .project-card__face--back {
  transform: rotateY(180deg);
  background: var(--bg-3);
  border-color: var(--primary);
}
/* Mobile / reduced-motion : pas de flip, face back empilée */
@media (max-width: 768px), (prefers-reduced-motion: reduce) {
  .project-card--flip { perspective: none; }
  .project-card--flip .project-card__inner { transform: none !important; transform-style: flat; }
  .project-card--flip .project-card__face { position: static; }
  .project-card--flip .project-card__face--back { transform: none; margin-top: 0.5rem; }
}

/* --- 18 · Letter-spacing respire sur les boutons ---------- */
.hero__btn,
.btn,
.project-detail__live {
  transition:
    background 0.25s ease,
    color 0.25s ease,
    border-color 0.25s ease,
    letter-spacing 0.3s ease,
    transform 0.2s ease;
}
.hero__btn:hover,
.btn:hover,
.project-detail__live:hover {
  letter-spacing: 1.4px;
}

/* --- 19 · SKELETON loading shimmer ------------------------ */
/* S'active sur les containers qui ont .is-loading.
   Sélecteur .home-articles-grid retiré (la home n'a plus de bloc Articles). */
.project-grid.is-loading .project-card,
.skeleton-card {
  position: relative;
  overflow: hidden;
  pointer-events: none;
  color: transparent !important;
}
.project-grid.is-loading .project-card * {
  visibility: hidden;
}
.project-grid.is-loading .project-card::after,
.skeleton-card::after {
  content: '';
  position: absolute;
  inset: 0;
  background:
    linear-gradient(
      90deg,
      rgba(0, 255, 65, 0.04) 0%,
      rgba(0, 255, 65, 0.16) 50%,
      rgba(0, 255, 65, 0.04) 100%
    );
  background-size: 200% 100%;
  animation: skel 1.4s linear infinite;
}
@keyframes skel {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }
}
@media (prefers-reduced-motion: reduce) {
  .project-grid.is-loading .project-card::after,
  .skeleton-card::after { animation: none; }
}

/* ============ ROUND 3 (patch v4) ============ */

/* ============================================================
   PATCH v4 — 26, 29, 31(V3), 32, 33, 37(ASCII), 39(ASCII), 40
   À charger APRÈS patch-v3.css
   ============================================================ */

/* --- 26 · ASCII BORDERS (classes utilitaires) --------------- */
.ascii-box {
  font-family: var(--font-mono);
  white-space: pre;
  color: var(--primary);
  line-height: 1.25;
  font-size: 12px;
  display: inline-block;
}
.ascii-box--double { /* même chose, utile pour cibler en JSX */ }

/* --- 29 · FILE TREE NAV ------------------------------------ */
.file-tree {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--fg);
  line-height: 1.9;
  background: rgba(8, 13, 22, 0.6);
  border: 1px solid rgba(0, 255, 65, 0.15);
  border-radius: 4px;
  padding: 0.75rem 0.75rem 0.75rem 0.75rem;
}
.file-tree__item {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 2px 6px;
  cursor: pointer;
  border-radius: 2px;
  color: var(--fg-dim);
  text-decoration: none;
  transition: background 0.15s, color 0.15s;
}
.file-tree__item:hover {
  background: rgba(0, 255, 65, 0.08);
  color: var(--primary);
}
.file-tree__item--active {
  color: var(--primary);
  background: rgba(0, 255, 65, 0.12);
}
.file-tree__item--folder { color: var(--primary); }
.file-tree__item--depth-1 { padding-left: 22px; }
.file-tree__item--depth-2 { padding-left: 38px; }
.file-tree__count {
  margin-left: auto;
  font-size: 10px;
  color: var(--fg-dim);
  opacity: 0.7;
}
.file-tree__dot {
  display: inline-block;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  flex-shrink: 0;
}
.file-tree__dot--active { background: var(--primary); }
.file-tree__dot--dev    { background: var(--amber); }
.file-tree__dot--archive{ background: var(--fg-dim); }

/* --- 31 (V3) · BREADCRUMB SHELL "cd" ------------------------ */
.bc {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--fg-dim);
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0;
  margin: 1rem 0 1.5rem;
  padding: 6px 10px;
  background: rgba(8, 13, 22, 0.5);
  border-left: 2px solid var(--primary);
}
.bc__cmd { color: var(--fg); margin-right: 6px; }
.bc__seg {
  color: var(--primary);
  text-decoration: none;
  transition: color 0.15s;
}
.bc__seg:hover { color: var(--fg-strong); text-decoration: underline; }
.bc__sep {
  color: var(--primary);
  opacity: 0.45;
  margin: 0 4px;
}
.bc__current { color: var(--fg-strong); font-weight: 500; }

/* --- 32 · READING PROGRESS BAR (fixed top) ------------------ */
.reading-progress {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  height: 2px;
  background: rgba(0, 255, 65, 0.1);
  z-index: 9999;
  pointer-events: none;
}
.reading-progress__fill {
  height: 100%;
  width: 0%;
  background: var(--primary);
  box-shadow: 0 0 8px rgba(0, 255, 65, 0.6);
  transition: width 0.1s linear;
}

/* --- 33 · BLOCKQUOTE ">" shell ------------------------------ */
.article-detail__body blockquote,
blockquote.shell-quote {
  position: relative;
  margin: 1.5rem 0;
  padding: 1rem 1rem 1rem 2.8rem;
  border-left: 2px solid var(--primary);
  background: rgba(0, 255, 65, 0.04);
  font-family: var(--font-display);
  font-style: italic;
  color: var(--fg);
  border-radius: 0 4px 4px 0;
}
.article-detail__body blockquote::before,
blockquote.shell-quote::before {
  content: '>';
  position: absolute;
  left: 1rem;
  top: 0.9rem;
  color: var(--primary);
  font-family: var(--font-mono);
  font-style: normal;
  font-weight: 700;
  font-size: 1.1rem;
}
.article-detail__body blockquote cite,
blockquote.shell-quote cite {
  display: block;
  margin-top: 0.5rem;
  font-family: var(--font-mono);
  font-size: 0.8rem;
  color: var(--fg-dim);
  font-style: normal;
}
.article-detail__body blockquote cite::before,
blockquote.shell-quote cite::before { content: '— '; }

/* Callout variants */
blockquote.shell-quote--warn { border-color: var(--amber); background: rgba(255, 215, 0, 0.04); }
blockquote.shell-quote--warn::before { content: '!'; color: var(--amber); }
blockquote.shell-quote--err  { border-color: var(--red); background: rgba(255, 68, 68, 0.04); }
blockquote.shell-quote--err::before  { content: 'x'; color: var(--red); }

/* --- 37 · FOOTER (retour arrière, inchangé) ----------------- */
/* Intentionnellement vide : on garde le footer d'origine. */

/* --- 39 (ASCII) · 404 PAGE ---------------------------------- */
.e404 {
  min-height: 70vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 1.5rem;
  padding: 3rem 1rem;
  font-family: var(--font-mono);
  color: var(--fg);
  text-align: center;
}
.e404__art {
  font-family: var(--font-mono);
  white-space: pre;
  color: var(--red);
  line-height: 1;
  font-size: clamp(10px, 2vw, 16px);
  letter-spacing: 0;
}
.e404__line { font-size: 13px; color: var(--fg-dim); }
.e404__line .p-red { color: var(--red); }
.e404__line .p-green { color: var(--primary); }
.e404__actions {
  display: flex;
  gap: 0.75rem;
  margin-top: 1rem;
  flex-wrap: wrap;
  justify-content: center;
}
.e404__btn {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--primary);
  border: 1px solid var(--primary);
  padding: 8px 14px;
  background: transparent;
  text-decoration: none;
  transition: all 0.2s;
}
.e404__btn:hover {
  background: var(--primary);
  color: var(--bg);
  letter-spacing: 1.5px;
}

/* --- 40 · STATUS BAR fixed bottom --------------------------- */
.statusbar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  height: 28px;
  display: flex;
  justify-content: space-between;
  align-items: center;
  padding: 0 14px;
  background: var(--bg-2);
  /* border-top neutralisée : phosphor rgba(0,255,65,0.3) trop voyante,
     visible comme une fine ligne verte en haut de la statusbar globale
     ET en miroir dans l'iframe threatmap (qui hérite de la même CSS). */
  border-top: 1px solid var(--border-soft);
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--fg-dim);
  z-index: 9999;
  pointer-events: none;
}
.statusbar__seg {
  display: flex;
  gap: 14px;
  align-items: center;
  pointer-events: auto;
}
.statusbar__item--green { color: var(--primary); font-weight: 600; }
.statusbar__dot {
  display: inline-block;
  width: 7px;
  height: 7px;
  border-radius: 50%;
  background: var(--primary);
  margin-right: 5px;
  box-shadow: 0 0 6px rgba(0, 255, 65, 0.7);
  animation: sb-pulse 2.4s ease-in-out infinite;
}
@keyframes sb-pulse {
  0%, 100% { opacity: 1; }
  50%      { opacity: 0.45; }
}
/* leave room so fixed content doesn't clip under statusbar */
body { padding-bottom: 28px; }

/* Hide statusbar on narrow screens (opt) */
@media (max-width: 640px) {
  .statusbar__seg--right { display: none; }
}
@media (prefers-reduced-motion: reduce) {
  .statusbar__dot { animation: none; }
}

/* ============================================================
   17. TERMINAL CARD BG — revert to legacy near-black
   ============================================================
   The brandguide tokens refactor (commit adbf8f2) shifted the
   terminal card background from #080D16 to --bg-3 (#0F1A2A),
   making cards look navy/blue. User asked for the original
   near-black tone back, on every terminal card. That hex value
   is now exposed as --bg-terminal in style.css :root.
   ============================================================ */
.terminal-card {
  background: var(--bg-terminal);
}

/* Career timeline / education / certs / lang cards — same legacy bg */
.career-tl__item,
.career-edu__item,
.career-cert,
.career-lang { background: var(--bg-terminal) !important; }

/* ============================================================
   18. WIDGETS — intrinsic responsiveness (container queries)
   ============================================================
   Make every .terminal-card--widget adapt to its own width,
   not the viewport. Useful when the widget is dropped in a
   wide hero column, a 3-col home grid, a 2-col tablet, or a
   narrow sidebar — same component, fluid behaviour.
   Avatar, paddings, gaps and timeline indent are tied to the
   container width via container queries + clamp() fallbacks.
   ============================================================ */
.terminal-card--widget {
  container-type: inline-size;
  container-name: widget;
}

/* Fluid base sizing — applies regardless of container support */
.terminal-card--widget .profile-avatar--lg {
  width: clamp(96px, 38cqi, 150px);
  height: clamp(96px, 38cqi, 150px);
}
.terminal-card--widget .terminal-card__body {
  padding: clamp(0.75rem, 3cqi, 1.25rem);
}
.terminal-card--widget .widget-career__hero {
  gap: clamp(0.5rem, 2cqi, 1rem);
}
.terminal-card--widget .profile__avatar-wrap {
  gap: clamp(0.5rem, 2cqi, 0.75rem);
  margin-bottom: clamp(0.75rem, 3cqi, 1.5rem);
}
.terminal-card--widget .timeline {
  padding-left: clamp(1rem, 4cqi, 1.5rem);
}
.terminal-card--widget .timeline__item {
  margin-bottom: clamp(0.75rem, 3cqi, 1.25rem);
}
.terminal-card--widget .timeline__item::before {
  left: clamp(-1.5rem, -4cqi, -1rem);
}
.terminal-card--widget .widget-downloads {
  gap: clamp(0.35rem, 1.5cqi, 0.5rem);
}

/* Container query — narrow widget (< 320px effective) */
@container widget (max-width: 320px) {
  .profile__name { font-size: var(--text-base); }
  .widget-career__name { font-size: var(--text-sm); }
  .widget-career__status { font-size: 0.65rem; }
  .cert-badge {
    font-size: 0.65rem;
    padding: 0.2rem 0.45rem;
    /* Allow long cert names to wrap on very narrow widgets */
    white-space: normal;
    line-height: 1.3;
  }
  .timeline__text { font-size: var(--text-xs); }
  .widget-dl-btn {
    padding: 0.3rem 0.55rem;
    font-size: 0.65rem;
  }
}

/* Container query — extra narrow (< 240px), e.g. sidebar */
@container widget (max-width: 240px) {
  .widget-career__hero {
    flex-direction: column;
    text-align: center;
    gap: 0.5rem;
  }
  .widget-career__name {
    white-space: normal;
    overflow: visible;
    text-overflow: clip;
  }
  .widget-downloads { justify-content: center; }
  .certifications { justify-content: center; }
}

/* Container query — wide widget (>= 480px), give breathing room */
@container widget (min-width: 480px) {
  .terminal-card--widget .terminal-card__body {
    padding: 1.5rem;
  }
  .widget-career__hero { gap: 1.25rem; }
}

/* Fallback for browsers without container query support
   (Safari < 16, Firefox < 110): widget still fluid via clamp() */
@supports not (container-type: inline-size) {
  .terminal-card--widget .cert-badge {
    white-space: normal;
    line-height: 1.3;
  }
}

/* ============================================================
   19. HOME COLUMNS — responsive intrinsèque (le vrai fix)
   ============================================================
   La home utilise .home-col, pas .terminal-card--widget. Sans
   ces container queries, .project-grid restait à 2-col même
   quand sa colonne parente faisait 280px → wrapping moche des
   cartes. Avec, chaque home-col s'adapte à sa largeur propre
   indépendamment du viewport.
   Note : .home-articles-grid / .article-card / .category-tab
   ont été retirés ici en même temps que la grille d'articles
   home (cf. js/main.js — la page /articles dédiée a remplacé
   ce composant).
   ============================================================ */
.home-sections > .home-col {
  container-type: inline-size;
  container-name: homecol;
}

/* Padding fluide column-aware */
.home-sections > .home-col {
  padding: clamp(1rem, 4cqi, 1.75rem);
}

/* Colonne étroite (< 360px) : grilles internes en 1-col */
@container homecol (max-width: 360px) {
  .project-grid { grid-template-columns: 1fr; gap: 0.75rem; }
  .stack-tag { font-size: 0.65rem; padding: 0.15rem 0.4rem; }
  .project-card__title { font-size: var(--text-sm); }
  .project-card__description { font-size: 0.75rem; }
}

/* Colonne très étroite (< 260px) : on resserre tout */
@container homecol (max-width: 260px) {
  .home-sections > .home-col { padding: 1rem 0.85rem; }
  .section__title { font-size: var(--text-base); }
  .timeline { padding-left: 1.1rem; }
  .timeline__item::before { left: -1.1rem; }
  .cert-badge { white-space: normal; line-height: 1.3; }
}

/* Colonne large (>= 460px) : plus d'air dans les grilles */
@container homecol (min-width: 460px) {
  .project-grid { gap: 1.25rem; }
}

/* ALSO: trigger 1-col home-sections layout earlier when the
   container itself is narrow — this complements the existing
   viewport @media queries */
.home-sections {
  container-type: inline-size;
  container-name: homesections;
}
@container homesections (max-width: 900px) {
  .home-sections { grid-template-columns: 1fr 1fr; gap: 2rem; }
  .home-sections > :last-child { grid-column: 1 / -1; }
}
@container homesections (max-width: 620px) {
  .home-sections { grid-template-columns: 1fr; gap: 2rem; }
  .home-sections > :last-child { grid-column: auto; }
}

/* ============================================================
   20. SIGNATURE FRAGMENT — terminal-style command + output
   ============================================================
   2-line fragment shown on every article-card and project-card,
   reinforcing the terminal narrative (mix B+C from brandguide).
   `currentColor` is set per accent variant:
     --green: var(--primary)        (default)
     --red:   var(--red)            (archived/failed)
     --amber: var(--amber)          (warn)
   ============================================================ */
.signature-fragment {
  font-family: var(--font-mono);
  font-size: 0.65rem;
  line-height: 1.4;
  display: flex;
  flex-direction: column;
  gap: 1px;
  margin: 0.5rem 0 0.25rem;
  padding: 0.4rem 0.55rem;
  background: rgba(0, 0, 0, 0.35);
  border-left: 2px solid currentColor;
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
  color: var(--primary);
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
}
.signature-fragment__cmd {
  color: currentColor;
  font-weight: 600;
  overflow: hidden;
  text-overflow: ellipsis;
}
.signature-fragment__out {
  color: var(--fg-dim);
  overflow: hidden;
  text-overflow: ellipsis;
}
.signature-fragment--red    { color: var(--red); }
.signature-fragment--amber  { color: var(--amber, #FFD700); }

/* (Bloc .article-card__image* retiré en même temps que la grille d'articles
   home — voir #19 plus haut.) */

/* Project card signature — replaces text-only header with B icon */
.project-card__header {
  display: flex;
  align-items: center;
  gap: 0.5rem;
  flex-wrap: wrap;
}
.project-card__sig {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  background: rgba(0, 0, 0, 0.35);
  border: 1px solid currentColor;
  border-radius: var(--radius-sm);
  color: var(--primary);
  padding: 4px;
}
.project-card__sig svg {
  width: 100%;
  height: 100%;
  display: block;
}
.project-card__sig--red   { color: var(--red); }
.project-card__sig--amber { color: var(--amber, #FFD700); }
.project-card__name { flex: 1; min-width: 0; }

/* On narrow home-col (< 360px) — let the project sig shrink slightly */
@container homecol (max-width: 360px) {
  .project-card__sig { width: 28px; height: 28px; padding: 3px; }
  .signature-fragment { font-size: 0.6rem; padding: 0.3rem 0.45rem; }
}

/* ============================================================
   21. PROJECT-CARD HEADER FIX — robust at narrow widths
   ============================================================
   Issue (cf user screenshot): in 2-col home-projects with
   home-col ~380px, each card is ~170px → long titles wrap badly
   AND the status-badge gets pushed mid-title via flex-wrap.
   Fix: bump the home-col 1-col collapse to <=460px, AND
   restructure the header into a 2-row grid so the badge always
   sits aligned with the sig, never inline with title text.
   ============================================================ */

/* Header restructure — sig top-left, badge top-right, title row 2 */
.project-card__header {
  display: grid;
  grid-template-columns: auto 1fr auto;
  grid-template-areas: "sig title badge";
  align-items: center;
  gap: 0.5rem;
  flex-wrap: nowrap;
}
.project-card__sig  { grid-area: sig; }
.project-card__name { grid-area: title; min-width: 0; word-break: break-word; }
.project-card__header .status-badge { grid-area: badge; align-self: start; }

/* Carte étroite (< 220px effective) : stack badge sous sig, titre row 2 full-width */
@container homecol (max-width: 460px) {
  .project-grid { grid-template-columns: 1fr; gap: 0.75rem; }
}
@container homecol (max-width: 360px) {
  .project-card__header {
    grid-template-columns: auto 1fr;
    grid-template-areas:
      "sig   badge"
      "title title";
  }
  .project-card__header .status-badge { justify-self: end; }
}

/* ============================================================
   22. CAREER HOME-WIDGET — fluid sizing inside .home-col (v4)
   ============================================================
   v3 ne bougeait quasi pas à largeur typique (home-col ~380px) :
   - seuil 400px pour 2-col certs jamais atteint
   - max bounds proches du défaut → no perceptible growth
   v4 :
   - bornes max remontées à des valeurs vraiment "grandes"
     (avatar 160px, name 1.7rem, section_title 1.8rem)
   - .certifications passe en grid auto-fit minmax(180px, 1fr) →
     1 col à <340px, 2 cols à >=360px, 3 cols à >=550px, sans
     breakpoint arbitraire
   ============================================================ */

/* Avatar — peut atteindre 160px sur widget large */
.home-sections > .home-col .profile-avatar--sm,
.home-sections > .home-col .profile-avatar--lg {
  width:  clamp(60px, 36cqi, 160px);
  height: clamp(60px, 36cqi, 160px);
}
.home-sections > .home-col .profile__avatar-wrap {
  gap: clamp(0.4rem, 1.8cqi, 0.95rem);
  margin-bottom: clamp(0.6rem, 2.5cqi, 1.4rem);
}

/* Profile name — peut atteindre 1.7rem */
.home-sections > .home-col .profile__name {
  font-size: clamp(0.95rem, 6cqi, 1.7rem);
  text-align: center;
  line-height: 1.2;
}

/* Section title (PARCOURS) — peut atteindre 1.8rem */
.home-sections > .home-col .section__title {
  font-size: clamp(1rem, 6cqi, 1.8rem);
}

/* Timeline */
.home-sections > .home-col .timeline {
  padding-left: clamp(0.85rem, 3.5cqi, 1.5rem);
}
.home-sections > .home-col .timeline__item {
  margin-bottom: clamp(0.55rem, 2.8cqi, 1.3rem);
}
.home-sections > .home-col .timeline__item::before {
  left: clamp(-1.5rem, -3.5cqi, -0.85rem);
}
.home-sections > .home-col .timeline__title {
  font-size: clamp(0.82rem, 4.2cqi, 1.15rem);
}
.home-sections > .home-col .timeline__text {
  font-size: clamp(0.72rem, 3.6cqi, 1.05rem);
  line-height: 1.4;
}

/* Certifications — grid AUTO-FIT (pas de breakpoint arbitraire) */
.home-sections > .home-col .certifications {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: clamp(0.3rem, 1.5cqi, 0.6rem);
}
.home-sections > .home-col .cert-badge {
  font-size: clamp(0.62rem, 2.8cqi, 0.82rem);
  padding: clamp(0.2rem, 1cqi, 0.35rem) clamp(0.45rem, 2cqi, 0.8rem);
  text-align: center;
  width: 100%;
  box-sizing: border-box;
  white-space: normal;
  line-height: 1.25;
}

/* View-all link — scale aussi */
.home-sections > .home-col .view-all {
  font-size: clamp(0.72rem, 3.2cqi, 0.95rem);
}

/* Sub-260px — fallback minimal */
@container homecol (max-width: 260px) {
  .home-sections > .home-col .certifications {
    grid-template-columns: 1fr;
    justify-content: center;
  }
  .home-sections > .home-col .profile-avatar__ring--outer { display: none; }
}


/* ============================================================
   23. HOME-SECTIONS — 2-col layout (post-articles-removal)
   ============================================================
   Articles widget retired (commit YYYY). home-sections now hosts
   2 columns instead of 3: .home-col (career) + .home-col#projects.
   The base CSS still declares 3-col grid — override here.
   ============================================================ */
.home-sections {
  grid-template-columns: 1fr 1.4fr;  /* projects gets a touch more room */
  gap: clamp(1.5rem, 4vw, 3rem);
  align-items: start;  /* chaque colonne (carte) se dimensionne à son contenu au lieu de s'étirer sur la hauteur de l'autre */
}
/* Cartes projet de l'ACCUEIL uniquement : on borne le résumé à 6 lignes max.
   N'importe quel projet ajouté reste compact automatiquement, quelle que soit
   la longueur de sa description — le texte intégral reste sur la page projet. */
#home-projects .project-card__desc {
  display: -webkit-box;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 6;
  line-clamp: 6;
  overflow: hidden;
}
@container homesections (max-width: 760px) {
  .home-sections { grid-template-columns: 1fr; gap: 2rem; }
  .home-sections > :last-child { grid-column: auto; }
}

/* a11y fallback for missing /assets/profile-photo.jpg */
.about-avatar--fallback {
  display: flex; align-items: center; justify-content: center;
  font-family: var(--font-display); font-weight: 700; font-size: 2rem;
  color: var(--primary); background: rgba(0, 255, 65, 0.05);
  border: 1px solid rgba(0, 255, 65, 0.25); border-radius: 50%;
  width: var(--avatar-size, 180px); height: var(--avatar-size, 180px);
}

/* ============================================================
   24. THREAT-SECTION — drop green frame border + neutral credit
   ============================================================
   La bordure verte rgba(0,255,65,0.12) sur .threat-section__frame
   se voyait comme une fine ligne phosphor au-dessus / en-dessous
   de l'iframe map. Remplacée par une bordure neutre alignée sur
   --border-soft (cohérent avec les autres frames du site).

   Le credit "● ransomware.live API" sous l'iframe formait visuellement
   une ligne verte horizontale (dot phosphor + glow + lien phosphor +
   texte). On désature : dot en --fg-dim sans glow, lien en --fg-dim
   avec hover cyan préservé. La phosphor reste réservée aux signatures
   et aux statusbars.
   ============================================================ */
.threat-section__frame {
  border: 1px solid var(--border-soft);
}
.threat-section__credit-dot {
  background: var(--fg-dim);
  box-shadow: none;
  animation: none;
}
.threat-section__credit-link {
  color: var(--fg-dim);
}
.threat-section__credit-link:hover {
  color: var(--cyan);
}

/* ============================================================
   25. PROJECT DEEP-DIVE — typed blocks (fixes wall-of-text)
   ============================================================
   The #project-deepdive container used to render a single 280-word
   paragraph. It now renders an array of typed blocks:
     - .dd-para     : standard paragraph (auto-paragraphed for projects
                      without a deepDiveBlocks array)
     - .dd-formula  : math/code formula card with caption + footnote
     - .dd-pivot    : "from → to" callout with a reason line
     - .dd-edges    : edge-cases list with tag chips
   Drop-cap on the very first .dd-para to anchor the eye, generous
   line-height, larger paragraph spacing.
   ============================================================ */
#project-deepdive {
  display: block;
  font-family: var(--font-sans, var(--font-mono));
}
.dd-para {
  font-size: var(--text-base);
  color: var(--fg);
  line-height: 1.75;
  margin: 0 0 1.25rem;
}
/* Drop-cap removed: was visually overpowering on letters with descenders
   (F, J, P) and broke the first line on auto-paragraphed prose. Hierarchy
   is now carried by paragraph spacing + structured blocks (formula/pivot/edges). */

/* Formula card — fenced expression with phosphor border */
.dd-formula {
  margin: 1.5rem 0;
  padding: 1rem 1.25rem;
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-left: 3px solid var(--primary);
  border-radius: var(--radius-md, 6px);
}
.dd-formula__label {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--primary);
  opacity: 0.85;
  margin-bottom: 0.6rem;
}
.dd-formula__expr {
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  color: var(--fg-strong);
  background: transparent;
  white-space: pre-wrap;
  word-break: break-word;
  margin: 0;
  padding: 0.5rem 0;
  border-top: 1px dashed var(--border-soft);
  border-bottom: 1px dashed var(--border-soft);
}
.dd-formula__note {
  font-size: var(--text-xs);
  color: var(--fg-dim);
  font-style: italic;
  margin: 0.6rem 0 0;
  line-height: 1.55;
}

/* Image card — full-width screenshot with phosphor border + mono caption */
.dd-image {
  margin: 1.75rem 0;
  padding: 0;
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-left: 3px solid var(--primary);
  border-radius: var(--radius-md, 6px);
  overflow: hidden;
}
.dd-image img {
  display: block;
  width: 100%;
  height: auto;
  background: #000;
}
.dd-image__caption {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 1px;
  color: var(--fg-dim);
  padding: 0.6rem 1.1rem;
  border-top: 1px dashed var(--border-soft);
}

/* Pivot callout — from → to with reason */
.dd-pivot {
  margin: 1.5rem 0;
  padding: 0.9rem 1.1rem;
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-radius: var(--radius-md, 6px);
}
.dd-pivot__line {
  display: flex;
  align-items: center;
  flex-wrap: wrap;
  gap: 0.6rem;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  margin-bottom: 0.5rem;
}
.dd-pivot__from {
  color: var(--fg-dim);
  text-decoration: line-through;
  text-decoration-color: rgba(255, 80, 80, 0.6);
}
.dd-pivot__arrow {
  color: var(--primary);
  letter-spacing: -1px;
  font-weight: 700;
}
.dd-pivot__to {
  color: var(--primary);
  font-weight: 600;
}
.dd-pivot__reason {
  font-size: var(--text-sm);
  color: var(--fg-dim);
  line-height: 1.6;
  margin: 0;
}

/* Edge cases callout — tag + description list */
.dd-edges {
  margin: 1.5rem 0;
  padding: 0.9rem 1.1rem 1rem;
  background: var(--bg-2);
  border: 1px solid var(--border-soft);
  border-left: 3px solid var(--orange, #ff9800);
  border-radius: var(--radius-md, 6px);
}
.dd-edges__title {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 1.2px;
  text-transform: uppercase;
  color: var(--orange, #ff9800);
  margin: 0 0 0.6rem;
}
.dd-edges__list {
  list-style: none;
  padding: 0;
  margin: 0;
  display: flex;
  flex-direction: column;
  gap: 0.55rem;
}
.dd-edges__item {
  display: grid;
  grid-template-columns: minmax(200px, 0.4fr) 1fr;
  gap: 0.9rem;
  align-items: start;
  font-size: var(--text-sm);
  line-height: 1.55;
}
.dd-edges__tag {
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  letter-spacing: 0.5px;
  color: var(--fg-strong);
  background: rgba(255, 152, 51, 0.08);
  border: 1px solid rgba(255, 152, 51, 0.25);
  border-radius: 3px;
  padding: 0.25rem 0.5rem;
  white-space: normal;
  overflow-wrap: anywhere;
  align-self: start;
}
.dd-edges__desc {
  color: var(--fg-dim);
}

@media (max-width: 640px) {
  .dd-edges__item {
    grid-template-columns: 1fr;
    gap: 0.3rem;
  }
  .dd-edges__tag { justify-self: start; }
  .dd-para:first-of-type::first-letter { font-size: 2.6rem; }
}
