/* ==========================================================================
   nicolaspieper.com - design system v2026
   Docs-inspired: sober, ivory, one International Orange accent.
   ========================================================================== */

/* --------------------------------------------------------------------------
   Fonts (self-hosted, variable)
   -------------------------------------------------------------------------- */
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../fonts/inter-var-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Inter';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../fonts/inter-var-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../fonts/sourceserif4-var-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'Source Serif 4';
  font-style: normal;
  font-weight: 100 900;
  font-display: swap;
  src: url('../fonts/sourceserif4-var-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url('../fonts/jetbrainsmono-var-latin.woff2') format('woff2');
  unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
  font-family: 'JetBrains Mono';
  font-style: normal;
  font-weight: 100 800;
  font-display: swap;
  src: url('../fonts/jetbrainsmono-var-latin-ext.woff2') format('woff2');
  unicode-range: U+0100-02BA, U+02BD-02C5, U+02C7-02CC, U+02CE-02D7, U+02DD-02FF, U+0304, U+0308, U+0329, U+1D00-1DBF, U+1E00-1E9F, U+1EF2-1EFF, U+2020, U+20A0-20AB, U+20AD-20C0, U+2113, U+2C60-2C7F, U+A720-A7FF;
}

/* --------------------------------------------------------------------------
   Tokens
   -------------------------------------------------------------------------- */
:root {
  /* Light (default) - ivory & ink */
  --bg: #FAF9F5;
  --bg-raised: #F2F0E9;
  --bg-inset: #EDEBE2;
  --ink: #171716;
  --ink-soft: #45443F;
  --muted: #66655E;
  --border: #E3E1D7;
  --border-strong: #CFCCC0;

  /* Brand accent - International Orange, from the logo (#FF4F00) */
  --brand: #FF4F00;           /* the pure brand orange - logo, boldest moments */
  --accent: #FF4F00;          /* decorative: marks, borders, bullets, active, focus */
  --accent-ink: #C23C00;      /* deep orange, text-safe on ivory (5.1:1 AA) */
  --accent-soft: #FFE7DC;     /* tinted surfaces */
  --accent-glow: rgba(255, 79, 0, 0.12);
  --focus-ring: #C23C00;      /* deep orange, ≥4.5:1 → clears the 3:1 UI minimum everywhere */

  --code-bg: #21201C;
  --code-ink: #EDEBE2;

  --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
  --font-serif: 'Source Serif 4', Georgia, 'Times New Roman', serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', Menlo, monospace;

  --header-h: 60px;
  --sidebar-w: 264px;
  --content-w: 47rem;
  --radius: 6px;
  --radius-sm: 3px;

  /* iOS safe areas (0 on devices without a notch / home indicator) */
  --safe-top: env(safe-area-inset-top, 0px);
  --safe-right: env(safe-area-inset-right, 0px);
  --safe-bottom: env(safe-area-inset-bottom, 0px);
  --safe-left: env(safe-area-inset-left, 0px);
  /* total height occupied by the fixed header, incl. the status-bar / Dynamic Island */
  --header-offset: calc(var(--header-h) + var(--safe-top));
  --gutter: clamp(16px, 3vw, 32px);

  --shadow-1: 0 1px 2px rgba(23, 23, 22, 0.05), 0 2px 8px rgba(23, 23, 22, 0.04);
  --shadow-2: 0 2px 4px rgba(23, 23, 22, 0.06), 0 12px 32px rgba(23, 23, 22, 0.10);
  --sticker-shadow-ink: rgba(23, 23, 22, 0.18);

  color-scheme: light;
}

:root[data-theme="dark"] {
  --bg: #262624;
  --bg-raised: #2E2E2B;
  --bg-inset: #21211F;
  --ink: #F0EEE7;
  --ink-soft: #C9C7BE;
  --muted: #9F9D93;
  --border: #3B3A36;
  --border-strong: #4C4B45;

  --brand: #FF4F00;
  --accent: #FF4F00;
  --accent-ink: #FF8551;      /* light orange, text-safe on dark (6.3:1 AA) */
  --accent-soft: #3A2318;
  --accent-glow: rgba(255, 79, 0, 0.20);
  --focus-ring: #FF4F00;      /* 4.6:1 on #262624 */

  --code-bg: #1B1B19;
  --code-ink: #E6E4DB;

  --shadow-1: 0 1px 2px rgba(0, 0, 0, 0.25), 0 2px 8px rgba(0, 0, 0, 0.2);
  --shadow-2: 0 2px 4px rgba(0, 0, 0, 0.3), 0 12px 32px rgba(0, 0, 0, 0.35);
  --sticker-shadow-ink: rgba(0, 0, 0, 0.45);

  color-scheme: dark;
}

/* --------------------------------------------------------------------------
   Base
   -------------------------------------------------------------------------- */
*, *::before, *::after { box-sizing: border-box; }

html {
  /* Safari samples the root canvas for its safe-area tint. Keep that canvas
     tied to the active theme instead of relying on the body's propagated paint. */
  background: var(--bg);
  scroll-behavior: smooth;
  scroll-padding-top: calc(var(--header-offset) + 24px);
  -webkit-text-size-adjust: 100%;
}

body {
  margin: 0;
  background: var(--bg);
  color: var(--ink);
  font-family: var(--font-sans);
  font-size: 1rem;
  line-height: 1.65;
  -webkit-font-smoothing: antialiased;
  text-rendering: optimizeLegibility;
  overflow-x: clip;                        /* guard against accidental sideways scroll on mobile */
  -webkit-tap-highlight-color: transparent; /* no grey flash on tap (iOS) */
}

::selection { background: #C23C00; color: #FFF; }

a { color: var(--accent-ink); text-decoration: none; }
a:hover { text-decoration: underline; text-underline-offset: 3px; }

img { max-width: 100%; height: auto; }

.skip-link {
  position: absolute;
  left: -9999px;
  z-index: 100;
  background: var(--accent-ink);
  /* clair : ivoire sur #C23C00 (5.1:1) · sombre : #262624 sur #FF8551 (6.3:1).
     Un #FFF codé en dur tombait à 2.4:1 sur l'orange clair du thème sombre. */
  color: var(--bg);
  padding: 10px 18px;
  border-radius: var(--radius-sm);
}
.skip-link:focus { left: 16px; top: 12px; }

/* Texte pour lecteurs d'écran uniquement (ex. annonce des nouveaux onglets). */
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

:focus-visible {
  outline: 2px solid var(--focus-ring);
  outline-offset: 2px;
  border-radius: 2px;
}

/* --------------------------------------------------------------------------
   Header
   -------------------------------------------------------------------------- */
.site-header {
  position: fixed;
  inset: 0 0 auto 0;
  height: var(--header-offset);
  padding-top: var(--safe-top);        /* push the bar below the status bar / Dynamic Island */
  padding-left: max(var(--gutter), var(--safe-left));
  padding-right: max(var(--gutter), var(--safe-right));
  display: flex;
  align-items: center;
  gap: 20px;
  /* Safari needs one solid color on the fixed element touching the viewport.
     A backdrop filter can leave its browser tint cached on the previous theme. */
  background: var(--bg);
  -webkit-backdrop-filter: none;
  backdrop-filter: none;
  border-bottom: 1px solid var(--border);
  z-index: 50;
}

.brand {
  display: flex;
  align-items: center;
  gap: 11px;
  color: var(--ink);
  font-weight: 600;
  font-size: 0.98rem;
  letter-spacing: -0.01em;
  white-space: nowrap;
}
.brand:hover { text-decoration: none; }

.brand-mark {
  width: 30px;
  height: 30px;
  border-radius: 4px;
  display: block;
  object-fit: cover;
  flex: none;
}

.header-nav {
  display: flex;
  align-items: center;
  gap: 4px;
  margin-left: 8px;
}
.header-nav a {
  color: var(--muted);
  font-size: 0.9rem;
  font-weight: 500;
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  position: relative;
}
.header-nav a:hover { color: var(--ink); background: var(--bg-raised); text-decoration: none; }
.header-nav a[aria-current="page"] { color: var(--ink); }
.header-nav a[aria-current="page"]::after {
  content: '';
  position: absolute;
  right: 10px;
  bottom: 2px;
  left: 10px;
  height: 2px;
  background: var(--accent);
}

.header-actions {
  margin-left: auto;
  display: flex;
  align-items: center;
  gap: 8px;
}

.lang-switch {
  display: flex;
  align-items: center;
  border: 1px solid var(--border);
  border-radius: 999px;
  padding: 2px;
  font-family: var(--font-mono);
  font-size: 0.72rem;
}
.lang-switch a, .lang-switch span {
  padding: 3px 9px;
  border-radius: 999px;
  color: var(--muted);
  line-height: 1.4;
}
.lang-switch [aria-current="true"] {
  background: var(--ink);
  color: var(--bg);
  font-weight: 600;
}
.lang-switch a:hover { text-decoration: none; color: var(--ink); }

.icon-btn {
  appearance: none;
  border: 1px solid var(--border);
  background: transparent;
  color: var(--muted);
  width: 40px;
  height: 40px;
  border-radius: 999px;
  display: grid;
  place-items: center;
  cursor: pointer;
  transition: color 0.15s ease, background-color 0.15s ease, transform 0.12s ease;
}
.icon-btn:hover { color: var(--ink); background: var(--bg-raised); }
.icon-btn:active { transform: scale(0.96); }
.icon-btn svg { width: 16px; height: 16px; }

/* Le chrome interactif fond ses changements d'état comme les .btn : sans ces
   transitions, survols et scrollspy claquaient à côté d'éléments qui fondent. */
.header-nav a,
.lang-switch a,
.side-group a,
.footer-col a,
.breadcrumb a {
  transition: color 0.15s ease, background-color 0.15s ease, border-color 0.15s ease;
}
.brand span { transition: color 0.15s ease; }
.brand:hover span { color: var(--accent-ink); }

/* Bascule de thème : fondu croisé des icônes (opacité, échelle, flou) au
   lieu d'un échange display qui téléportait l'état. Les deux icônes occupent
   la même cellule de la grille du bouton ; prefers-reduced-motion (bloc
   global) rend l'échange instantané. Aucune transition au premier rendu :
   les transitions ne se déclenchent qu'au changement d'état. */
.theme-toggle .icon-sun,
.theme-toggle .icon-moon {
  grid-area: 1 / 1;
  transition: opacity 0.2s ease, transform 0.2s cubic-bezier(0.2, 0, 0, 1), filter 0.2s ease;
}
.theme-toggle .icon-moon { opacity: 0; transform: scale(0.25); filter: blur(2px); }
:root[data-theme="dark"] .theme-toggle .icon-moon { opacity: 1; transform: scale(1); filter: blur(0); }
:root[data-theme="dark"] .theme-toggle .icon-sun { opacity: 0; transform: scale(0.25); filter: blur(2px); }

.menu-btn { display: none; }
.menu-btn .menu-line {
  transform-origin: 8px 8px;
  transition: transform 0.2s ease, opacity 0.15s ease;
}
.menu-btn[aria-expanded="true"] .menu-line--top { transform: translateY(4px) rotate(45deg); }
.menu-btn[aria-expanded="true"] .menu-line--middle { opacity: 0; }
.menu-btn[aria-expanded="true"] .menu-line--bottom { transform: translateY(-4px) rotate(-45deg); }

/* --------------------------------------------------------------------------
   Layout: sidebar + content
   -------------------------------------------------------------------------- */
.layout {
  display: grid;
  grid-template-columns: var(--sidebar-w) minmax(0, 1fr);
  max-width: 1280px;
  margin: 0 auto;
  padding-top: var(--header-offset);
}

.sidebar {
  position: sticky;
  top: var(--header-offset);
  height: calc(100vh - var(--header-offset));
  height: calc(100dvh - var(--header-offset)); /* dvh: avoids iOS Safari toolbar cut-off */
  overflow-y: auto;
  overscroll-behavior: contain;
  padding: 28px 20px 40px clamp(16px, 2vw, 24px);
  border-right: 1px solid var(--border);
  scrollbar-width: thin;
}

.side-group { margin-bottom: 22px; }
/* Étiquettes de groupes en <p class="side-title"> : des <h2> dans la sidebar
   précédaient le h1 de la page dans le plan des titres (navigation lecteur
   d'écran) ; les repères de landmarks suffisent. */
.side-group > .side-title {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--muted);
  margin: 0 0 8px;
  padding-left: 10px;
}
.side-group ul { list-style: none; margin: 0; padding: 0; }
.side-group li { margin: 1px 0; }
.side-group a {
  display: block;
  padding: 6px 10px;
  border-radius: var(--radius-sm);
  color: var(--ink-soft);
  font-size: 0.88rem;
  line-height: 1.45;
  border-left: 2px solid transparent;
}
.side-group a:hover { background: var(--bg-raised); color: var(--ink); text-decoration: none; }
.side-group a.active {
  color: var(--accent-ink);
  font-weight: 600;
  background: var(--accent-glow);
  border-left-color: var(--accent);
  border-radius: 0 var(--radius-sm) var(--radius-sm) 0;
}
/* Page courante dans le tiroir du CV (liens de pages, sans scrollspy). */
.side-group a[aria-current="page"] {
  color: var(--accent-ink);
  font-weight: 600;
}

/* --------------------------------------------------------------------------
   Content
   -------------------------------------------------------------------------- */
.content {
  min-width: 0; /* let the grid track shrink below the content's intrinsic width */
  padding: 40px clamp(20px, 4vw, 56px) 80px;
  padding-left: max(clamp(20px, 4vw, 56px), var(--safe-left));
  padding-right: max(clamp(20px, 4vw, 56px), var(--safe-right));
  padding-bottom: max(80px, calc(48px + var(--safe-bottom)));
  max-width: calc(var(--content-w) + 2 * clamp(20px, 4vw, 56px));
}

.breadcrumb {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  color: var(--muted);
  margin-bottom: 26px;
  display: flex;
  align-items: center;
  gap: 8px;
  flex-wrap: wrap;
}
.breadcrumb a { color: var(--muted); }
.breadcrumb a:hover { color: var(--accent-ink); }
.breadcrumb .sep { opacity: 0.5; }
.breadcrumb [aria-current="page"] { color: var(--accent-ink); font-weight: 600; }

/* Typography */
h1, h2, h3, h4 { color: var(--ink); scroll-margin-top: calc(var(--header-h) + 20px); }

h1 {
  font-family: var(--font-serif);
  font-size: clamp(2.1rem, 5vw, 2.9rem);
  font-weight: 600;
  line-height: 1.12;
  letter-spacing: -0.015em;
  margin: 0 0 18px;
}

h2 {
  font-family: var(--font-serif);
  font-size: 1.65rem;
  font-weight: 600;
  line-height: 1.25;
  letter-spacing: -0.01em;
  margin: 3.2rem 0 1rem;
}

h3 {
  font-size: 1.13rem;
  font-weight: 650;
  margin: 2.2rem 0 0.7rem;
  letter-spacing: -0.005em;
}

h4 {
  font-size: 0.98rem;
  font-weight: 650;
  margin: 1.6rem 0 0.5rem;
}

p { margin: 0 0 1rem; }
p, li { color: var(--ink-soft); }
strong { color: var(--ink); font-weight: 650; }

/* Retours à la ligne : titres équilibrés, paragraphes sans orphelines. */
h1, h2 { text-wrap: balance; }
p, li { text-wrap: pretty; }

/* Les navigateurs coupent le français trop agressivement dans les colonnes
   étroites. Les vrais jetons longs gardent leurs protections locales. */
:lang(fr) p, :lang(fr) li { hyphens: none; }

/* Mesure du texte courant : la colonne de 47rem laisse monter les paragraphes
   pleine largeur à ~96 caractères par ligne (le ch du « 0 » surestime la
   largeur réelle d'Inter d'environ 25 %). 60ch ≈ 77 caractères réels ; les
   composants (terminal, grilles, filets) gardent la pleine largeur. */
.content p, .content ul, .content ol { max-width: 60ch; }

/* Surlignage « marqueur » - réservé aux un ou deux faits qu'un visiteur doit
   retenir de la page. <mark class="hl"> enveloppe l'emphase existante ; la
   teinte vient du design system (--accent-soft, calibrée clair + sombre).
   Si tout est surligné, rien ne l'est : deux occurrences max par page. */
mark.hl {
  background: var(--accent-soft);
  color: inherit;
  padding: 0.08em 0.2em;
  margin: 0 -0.12em;
  border-radius: 0.25em;
  box-decoration-break: clone;
  -webkit-box-decoration-break: clone;
}

ul, ol { padding-left: 1.35rem; margin: 0 0 1.1rem; }
li { margin: 0.3rem 0; }
li::marker { color: var(--accent); }

hr {
  border: none;
  border-top: 1px solid var(--border);
  margin: 2.6rem 0;
}

/* Section separators, docs-style */
.doc-section { border-top: 1px solid var(--border); margin-top: 3rem; }
.doc-section:first-of-type { border-top: none; margin-top: 0; }
/* Sur la page Work, la première étude de cas garde son filet : le sticker
   doit avoir quelque chose à chevaucher (le geste signature du système). */
.page-work .case-study.doc-section:first-of-type {
  border-top: 1px solid var(--border);
  margin-top: 3rem;
}

/* Anchored headings */
.anchor-heading { position: relative; }
.anchor-heading .anchor {
  opacity: 0;
  transition: opacity 0.12s ease;
  margin-left: 8px;
  color: var(--muted);
  font-family: var(--font-mono);
  font-size: 0.8em;
  font-weight: 400;
}
.anchor-heading:hover .anchor,
.anchor-heading .anchor:focus-visible,
.anchor-heading:focus-within .anchor { opacity: 1; }
.anchor-heading .anchor:hover { color: var(--accent-ink); text-decoration: none; }

/* Eyebrow / kicker */
.eyebrow {
  font-family: var(--font-mono);
  font-size: 0.74rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.11em;
  color: var(--accent-ink);
  margin: 0 0 14px;
}

.lead {
  font-size: 1.14rem;
  line-height: 1.7;
  color: var(--ink-soft);
}

.page-intro { margin-bottom: 3rem; }
.page-intro h1 { max-width: 820px; }
.hero-intro { max-width: 40rem; }

.work-list {
  border-top: 1px solid var(--border);
  margin: 1.5rem 0;
}
.work-summary {
  display: grid;
  grid-template-columns: minmax(150px, 0.8fr) minmax(180px, 0.9fr) minmax(240px, 1.5fr);
  gap: 10px 24px;
  padding: 22px 0;
  border-bottom: 1px solid var(--border);
  scroll-margin-top: calc(var(--header-offset) + 24px);
}
.work-summary .eyebrow,
.work-summary h3,
.work-summary p { margin: 0; }
.work-summary h3 { font-size: 1rem; }
.work-summary .text-link { grid-column: 3; }
.text-link { font-weight: 650; }
.text-link span { display: inline-block; transition: transform 0.15s ease; }
.text-link:hover span { transform: translateX(3px); }
.case-study > h3 { margin-top: 1.8rem; }

.page-work .content { max-width: calc(53rem + 2 * clamp(20px, 4vw, 56px)); }
/* Études de cas en flux unique : les étiquettes h3 coiffent leur bloc et
   le texte habille les stickers flottés, à toutes les largeurs (le
   traitement mobile, adoré, généralisé ; l'ancienne grille à étiquettes
   latérales rendait le flottement impossible sur desktop). flow-root :
   chaque section contient ses flottants, aucun sticker ne peut déborder
   sur le filet de la section suivante. */
/* max-width 38rem : la même mesure que le flux des articles de blog.
   Sans elle, le flottant se pose à droite de la section, hors de la
   colonne de texte (60ch), et le texte ne l'habille jamais. */
.page-work .case-study { display: flow-root; max-width: 38rem; }
.page-work .case-study::before {
  content: attr(data-case);
  display: block;
  margin-top: 3rem;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 650;
  letter-spacing: 0.12em;
  color: var(--accent-ink);
}
.page-work .case-study > h2 { margin-top: 0.55rem; }
.page-work .case-study > h3 {
  margin: 1.85rem 0 0;
  font-family: var(--font-sans);
  font-size: 0.86rem;
  font-weight: 650;
  line-height: 1.5;
  letter-spacing: 0;
  text-transform: none;
  color: var(--ink);
}
.page-work .case-study > h3 + p,
.page-work .case-study > h3 + ul,
.page-work .case-study > h3 + .case-sticker + p,
.page-work .case-study > h3 + .case-sticker + ul { margin-top: 0.65rem; }
.page-work--indexed .case-study::before { display: none; }
.page-work--indexed .case-study > h2 { margin-top: 1.75rem; }

/* Index de lecture : quatre raccourcis, sans transformer la page en grille
   de cartes. Les traits prolongent la structure éditoriale du site. */
.case-index {
  margin: 0 0 3.5rem;
  padding-top: 18px;
  border-top: 1px solid var(--border-strong);
}
.case-index > .eyebrow { margin-bottom: 10px; }
.case-index-list {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  list-style: none;
  margin: 0;
  padding: 0;
  border-bottom: 1px solid var(--border);
}
.case-index-item { margin: 0; border-top: 1px solid var(--border); }
.case-index-item:nth-child(-n + 2) { border-top: 0; }
.case-index-item:nth-child(even) { border-left: 1px solid var(--border); }
.case-index-item a {
  display: grid;
  grid-template-columns: 2.2rem minmax(0, 1fr);
  gap: 2px 12px;
  min-height: 100%;
  padding: 15px 16px;
  color: var(--ink);
  transition: background-color 0.15s ease;
}
.case-index-item a:hover {
  background: var(--accent-glow);
  text-decoration: none;
}
.case-index-item a > span {
  grid-row: 1 / 3;
  font-family: var(--font-mono);
  font-size: 0.72rem;
  font-weight: 650;
  color: var(--accent-ink);
}
.case-index-item strong { font-size: 0.9rem; line-height: 1.4; }
.case-index-item small { font-size: 0.78rem; line-height: 1.45; color: var(--muted); }
.page-next {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 20px;
  margin-top: 3.5rem;
  padding: 20px 0;
  border-top: 1px solid var(--border);
  border-bottom: 1px solid var(--border);
}
.page-next a { font-weight: 650; }
.page-next .next-primary { color: var(--accent-ink); }

/* --------------------------------------------------------------------------
   Components
   -------------------------------------------------------------------------- */

/* Buttons */
.btn-row { display: flex; gap: 12px; flex-wrap: wrap; margin: 26px 0 8px; }

.btn {
  display: inline-flex;
  align-items: center;
  gap: 8px;
  padding: 10px 18px;
  border-radius: var(--radius-sm);
  font-size: 0.92rem;
  font-weight: 600;
  line-height: 1.4;
  border: 1px solid transparent;
  cursor: pointer;
  transition: transform 0.12s ease, border-color 0.15s ease, background-color 0.15s ease, color 0.15s ease;
}
.btn:hover { text-decoration: none; }
.btn:active { transform: translateY(1px); }
.btn svg { width: 15px; height: 15px; }

.btn-primary { background: var(--ink); color: var(--bg); }
.btn-primary:hover { background: var(--accent-ink); color: #FFF; }
:root[data-theme="dark"] .btn-primary:hover { color: var(--bg); }

.btn-ghost { border-color: var(--border-strong); color: var(--ink); background: transparent; }
.btn-ghost:hover { border-color: var(--accent); color: var(--accent-ink); background: var(--accent-glow); }

/* Terminal / code block */
.terminal {
  background: var(--code-bg);
  color: var(--code-ink);
  border-radius: var(--radius);
  margin: 30px 0;
  box-shadow: var(--shadow-2);
  overflow: hidden;
  font-size: 0.84rem;
}
.terminal-bar {
  display: flex;
  align-items: center;
  gap: 6px;
  padding: 10px 14px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.08);
}
.terminal-bar i {
  width: 10px;
  height: 10px;
  border-radius: 50%;
  background: rgba(255, 255, 255, 0.16);
}
.terminal-bar i:first-child { background: var(--accent); }
.terminal-bar .terminal-title {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: rgba(255, 255, 255, 0.58);
}
.terminal pre {
  margin: 0;
  padding: 16px 18px 20px;
  font-family: var(--font-mono);
  line-height: 1.75;
  overflow-x: auto;
}
.terminal .t-prompt { color: var(--accent); }
.terminal .t-cmd { color: #FFF; font-weight: 500; }
.terminal .t-key { color: #8FB573; }
.terminal .t-dim { color: rgba(255, 255, 255, 0.58); }
.terminal--signature { max-width: 38rem; margin-top: 24px; }

/* Callout (docs note) */
.callout {
  display: flex;
  gap: 12px;
  background: var(--accent-soft);
  border: 1px solid color-mix(in srgb, var(--accent) 35%, transparent);
  border-radius: var(--radius);
  padding: 14px 16px;
  margin: 1.4rem 0;
  font-size: 0.93rem;
}
.callout .co-icon { flex: none; color: var(--accent-ink); margin-top: 2px; }
.callout .co-icon svg { width: 16px; height: 16px; }
.callout p { margin: 0; }
.callout p + p { margin-top: 8px; }

/* Cards */
.card-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(210px, 1fr));
  gap: 14px;
  margin: 1.4rem 0;
}
.card {
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 18px;
  position: relative;
  transition: border-color 0.15s, box-shadow 0.15s;
}
/* Pas de survol sur les cartes inertes : un état hover promet un clic. */
.card h3, .card h4 { margin: 0 0 6px; font-size: 0.98rem; }
.card p { margin: 0; font-size: 0.88rem; color: var(--muted); }
.card .card-kicker {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--accent-ink);
  display: block;
  margin-bottom: 8px;
}
a.card { display: block; color: inherit; }
a.card:hover { text-decoration: none; border-color: var(--accent); box-shadow: var(--shadow-1); }

/* Stat tiles */
.stat-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
  gap: 14px;
  margin: 1.6rem 0;
}
.stat {
  border: 1px solid var(--border);
  border-radius: var(--radius);
  padding: 16px 18px;
  background: var(--bg-raised);
}
.stat .stat-n {
  font-family: var(--font-serif);
  font-size: 1.85rem;
  font-weight: 600;
  color: var(--accent-ink);
  line-height: 1.1;
  letter-spacing: -0.01em;
}
.stat .stat-l {
  font-size: 0.8rem;
  color: var(--muted);
  margin-top: 6px;
  line-height: 1.4;
}
.stat-band {
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 0;
  border-top: 1px solid var(--border-strong);
  border-bottom: 1px solid var(--border-strong);
}
.stat-band .stat {
  padding: 20px 18px;
  border: 0;
  border-left: 1px solid var(--border);
  border-radius: 0;
  background: transparent;
}
.stat-band .stat:first-child { padding-left: 0; border-left: 0; }
.stat-band .stat:last-child { padding-right: 0; }

/* Une réalisation ouvre la section, les trois suivantes forment un
   répertoire compact. La différence de taille porte la priorité. */
.work-list--featured {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
}
.work-list--featured .work-summary--featured {
  grid-column: 1 / -1;
  padding: 28px 0;
}
.work-list--featured .work-summary--compact {
  display: flex;
  flex-direction: column;
  gap: 9px;
  padding: 20px;
  border-right: 1px solid var(--border);
}
.work-list--featured .work-summary--compact:nth-child(2) { padding-left: 0; }
.work-list--featured .work-summary--compact:last-child { padding-right: 0; border-right: 0; }
.work-list--featured .work-summary--compact .text-link { margin-top: auto; }

/* Portrait - floated headshot in the overview */
.portrait {
  float: right;
  width: clamp(140px, 32%, 184px);
  margin: 2px 0 14px 26px;
}
.portrait img {
  display: block;
  width: 100%;
  height: auto;
  /* die-cut sticker: keeps its own white outline - no card border/radius */
  filter: drop-shadow(0 7px 18px var(--sticker-shadow-ink));
}

/* Sticker - Pampy, die-cut sticker slapped on the page.
   The artwork is a bust (flat-cut chest): the caption card is pinned to the
   bottom edge of the figure so the cut edge is tucked behind it at every
   width (a width-relative negative margin failed between 500 and 560px:
   the offset scaled with the figure while the caption height is font-fixed). */
.sticker {
  float: right;
  width: clamp(120px, 27%, 156px);
  margin: 0 4px 12px 24px;
  position: relative;
  padding-bottom: 10px;
}
.sticker img {
  display: block;
  width: 100%;
  height: auto;
  transform: rotate(-6deg);
  transform-origin: 50% 82%;
  filter: drop-shadow(0 6px 14px var(--sticker-shadow-ink));
  transition: transform 0.25s ease-out; /* sortie : le sticker se repose sans rebond */
}
.sticker figcaption {
  position: absolute;
  left: 0;
  right: 0;
  bottom: 0;            /* pinned to the cut edge : coverage independent of width */
  background: var(--bg-raised);
  border: 1px solid var(--border);
  border-radius: var(--radius-sm);
  padding: 5px 8px;
  text-align: center;
  font-family: var(--font-mono);
  font-size: 0.72rem;   /* plancher de lisibilité du mono en mixte */
  letter-spacing: 0.04em;
  color: var(--muted);
  box-shadow: var(--shadow-1);
}
/* Stickers d'étude de cas - le traitement mobile généralisé : flottés à
   droite DANS le texte, qui les habille comme un sticker posé sur la
   page. La position du <figure> dans le markup varie d'une section à
   l'autre (à hauteur du passage qui le concerne) : c'est ce décalage qui
   fait carnet de bord. Taille et angle par sticker via la section. */
.page-work #solutions-team { --sticker-w: 190px; --sticker-tilt: -4deg; }
.page-work #secure-platforms { --sticker-w: 180px; --sticker-tilt: 4deg; }
.page-work #iot-platform { --sticker-w: 170px; --sticker-tilt: -5deg; }
.page-work #document-factory { --sticker-w: 200px; --sticker-tilt: 3deg; }
.case-sticker {
  float: right;
  width: min(var(--sticker-w, 180px), 32%);
  margin: 0.5rem -10px 0.8rem 22px;
}
.case-sticker img {
  display: block;
  width: 100%;
  height: auto;
  transform: rotate(var(--sticker-tilt, -5deg));
  /* Ombre discrète : le grand halo (8px/18px) alourdissait le sticker. */
  filter: drop-shadow(0 3px 7px var(--sticker-shadow-ink));
  transition: transform 0.25s ease-out; /* sortie : se repose sans rebond */
}
/* Survol réservé aux vrais pointeurs : au tap, l'état :hover restait collé
   (sticker figé en rotation). L'entrée garde la courbe à ressort, la sortie
   se pose avec l'ease-out court déclaré sur l'état de repos. */
@media (hover: hover) and (pointer: fine) {
  .sticker:hover img {
    transform: rotate(4deg) scale(1.05);
    transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
  }
  .case-sticker:hover img {
    transform: rotate(1deg) scale(1.04);
    transition: transform 0.4s cubic-bezier(0.34, 1.56, 0.64, 1);
  }
}
@media (prefers-reduced-motion: reduce) {
  .sticker img, .case-sticker img { transition: none; }
  .sticker:hover img { transform: rotate(-6deg); }
  .case-sticker:hover img { transform: rotate(var(--sticker-tilt, -5deg)); }
}
@media (max-width: 560px) {
  .work-summary { grid-template-columns: 1fr; }
  .work-summary .text-link { grid-column: 1; }
  /* Portrait : flotté à droite du lead, comme les stickers de la page Work,
     plutôt qu'un bloc centré qui coupe le hero en deux. Cap réduit pour que
     la colonne d'habillage garde ~25 caractères par ligne (à 140px elle
     tombait à 2-3 mots par ligne). Pampy garde son traitement centré à
     carte-légende, qui fonctionne bien. */
  .portrait { width: min(112px, 30vw); margin: 0.2rem -4px 8px 14px; }
  .lead { font-size: 1.05rem; }
  /* Le <br> volontaire du h1 impose des lignes bancales sous 560px. */
  h1 br { display: none; }
  .sticker { float: none; width: min(200px, 55%); margin: 4px auto 20px; }
}

@media (max-width: 720px) {
  /* Cap réduit pour laisser une colonne de texte d'au moins ~200px sur
     un écran de 375px (à 148px elle tombait à 3-4 mots par ligne sur
     les quatre études de cas). */
  .case-sticker { width: min(118px, 33vw); margin: 0.4rem -4px 0.6rem 14px; }
  /* gap 28px : les halos de tap de 12px des deux liens empilés se
     chevauchaient de 4px avec le gap de 20px. */
  .page-next { align-items: flex-start; flex-direction: column; gap: 28px; }
}

/* Badges / chips */
.chip-row { display: flex; flex-wrap: wrap; gap: 8px; margin: 1rem 0 1.4rem; }
.chip {
  font-family: var(--font-mono);
  font-size: 0.76rem;
  padding: 4px 11px;
  border: 1px solid var(--border-strong);
  border-radius: 999px;
  color: var(--ink-soft);
  background: var(--bg-raised);
}
.chip.chip-accent {
  border-color: color-mix(in srgb, var(--accent) 45%, transparent);
  color: var(--accent-ink);
  background: var(--accent-soft);
}

/* Principles list */
.principles { display: grid; gap: 4px; margin: 1.4rem 0; }
.principle {
  display: grid;
  grid-template-columns: 34px 1fr;
  gap: 14px;
  padding: 14px 12px;
  border-radius: var(--radius);
}
.principle .p-n {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  font-weight: 600;
  color: var(--accent-ink);
  padding-top: 3px;
}
.principle h3 { margin: 0 0 4px; font-size: 1rem; }
.principle p { margin: 0; font-size: 0.92rem; }
.principles--home {
  gap: 0;
  border-top: 1px solid var(--border-strong);
  border-bottom: 1px solid var(--border-strong);
}
.principles--home .principle {
  padding: 18px 0;
  border-top: 1px solid var(--border);
  border-radius: 0;
}
.principles--home .principle:first-child { border-top: 0; }

/* Checklist (what I bring) */
.checklist { list-style: none; padding: 0; margin: 1.2rem 0; display: grid; gap: 10px; }
.checklist li {
  display: flex;
  gap: 12px;
  align-items: baseline;
  margin: 0;
}
.checklist li::before {
  content: '→';
  font-family: var(--font-mono);
  color: var(--accent);
  font-weight: 600;
  flex: none;
}

/* Contact block */
.contact-panel {
  background: var(--code-bg);
  color: var(--code-ink);
  border-radius: var(--radius);
  padding: clamp(24px, 4vw, 40px);
  margin: 2rem 0 1rem;
  box-shadow: var(--shadow-2);
}
.contact-panel h2 {
  color: #FFF;
  margin: 0 0 10px;
}
.contact-panel p { color: rgba(255, 255, 255, 0.72); }
.contact-panel--focused p { max-width: 46ch; }
.contact-panel .btn-primary { background: var(--brand); color: #201203; }
.contact-panel .btn-primary:hover { background: #FF6A2B; color: #201203; }
.contact-panel .btn-ghost { border-color: rgba(255, 255, 255, 0.25); color: #FFF; }
.contact-panel .btn-ghost:hover { border-color: var(--accent); color: var(--accent); background: transparent; }

/* Footer */
/* Footer - colophon du site : identité, trois groupes de liens dans la langue
   mono de la sidebar, clin d'œil terminal et ligne de base typographique.
   Chaque lien est un bloc à hauteur voulue : l'ancien footer à une ligne
   gonflait au hasard des retours à la ligne selon le navigateur. */
.site-footer {
  margin-top: 4.5rem;
  border-top: 1px solid var(--border);
  padding: 32px 0 max(22px, var(--safe-bottom));
  color: var(--muted);
}
.footer-grid {
  display: grid;
  grid-template-columns: minmax(200px, 1.5fr) repeat(3, minmax(110px, 1fr));
  gap: 28px 20px;
}
.footer-id { display: flex; flex-direction: column; align-items: flex-start; gap: 8px; }
.footer-tag { margin: 0; font-size: 0.82rem; }
.footer-exit {
  margin: 4px 0 0;
  font-family: var(--font-mono);
  font-size: 0.78rem;
}
.footer-exit .fx-prompt { color: var(--accent); }
.footer-col .side-title {
  font-family: var(--font-mono);
  font-size: 0.68rem;
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.09em;
  color: var(--muted);
  margin: 0 0 6px;
}
.footer-col a {
  display: block;
  padding: 5px 0;
  color: var(--ink-soft);
  font-size: 0.88rem;
}
.footer-col a:hover { color: var(--accent-ink); }
.footer-col a[aria-current="page"] { color: var(--accent-ink); }
.footer-base {
  margin-top: 28px;
  padding-top: 16px;
  border-top: 1px solid var(--border);
  display: flex;
  justify-content: space-between;
  flex-wrap: wrap;
  gap: 6px 24px;
  font-size: 0.78rem;
}
.footer-base p { margin: 0; }
@media (max-width: 640px) {
  .footer-grid { grid-template-columns: 1fr 1fr; }
  .footer-id { grid-column: 1 / -1; }
}

/* Blog : la meta d'article (date, temps de lecture) sous le titre ;
   tout le reste réutilise les composants existants (page-intro,
   doc-section, work-summary, callout, terminal). */
.blog-list { margin: 1.4rem 0; }
.blog-featured {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 0.85fr);
  gap: clamp(24px, 4vw, 46px);
  align-items: center;
  padding: 10px 0 30px;
  border-bottom: 1px solid var(--border-strong);
  scroll-margin-top: calc(var(--header-offset) + 24px);
}
.blog-featured-media { margin: 0; }
.blog-featured-media img {
  display: block;
  width: 100%;
  height: auto;
  transform: rotate(-1deg);
  filter: drop-shadow(0 6px 14px var(--sticker-shadow-ink));
}
.blog-featured-content .post-meta { margin: 0 0 12px; }
.blog-featured-content h3 { margin: 0 0 10px; font-size: 1.25rem; }
.blog-featured-content > p:not(.post-meta) { margin: 0 0 14px; color: var(--ink-soft); }
.blog-compact-list { border-top: 0; }
.blog-compact:first-child { border-top: 0; }

/* Deux largeurs, une seule grille dans les articles (décision Nicolas) :
   tout le flux textuel (prose, titres, listes, principes, callout,
   terminal) partage une mesure FIXE de 38rem, l'équivalent des 60ch
   effectifs de la prose figé en rem, car ch varie avec le corps de
   chaque bloc (le terminal en 0.84rem obtenait un 60ch plus étroit que
   le callout). Les figures visuelles (héros, diagramme, façade vidéo)
   s'étendent à 45rem, alignées sur le même bord gauche : débord franc
   et systématique plutôt qu'un dégradé accidentel de largeurs. Scope
   `article` : accueil, réalisations et pages d'erreur inchangés. */
.content article .doc-section > *,
.content article .page-intro .lead { max-width: 38rem; }
.content article .post-hero,
.content article .post-diagram,
.content article .video-facade { max-width: 45rem; }
.post-meta {
  font-family: var(--font-mono);
  font-size: 0.78rem;
  color: var(--muted);
  letter-spacing: 0.02em;
  margin: -16px 0 26px;
}
/* Dans les cartes d'index, la meta s'empile volontairement (date, temps
   de lecture, catégorie) : la colonne est trop étroite pour une ligne
   avec séparateurs, qui se repliait en escalier. */
.work-summary .post-meta { margin: 0 0 6px; display: grid; gap: 3px; justify-items: start; }
.post-meta .post-cat { color: var(--accent-ink); font-weight: 600; }

/* Illustration d'en-tête d'article : sticker large centré sous l'intro,
   WebP à fond transparent (le bord die-cut blanc porte les deux thèmes).
   Posé avec une très légère inclinaison, comme les stickers du reste du
   site ; il se redresse au survol (pointeurs fins uniquement). Le bloc
   global prefers-reduced-motion neutralise la transition. */
.post-hero { margin: 4px 0 36px; }
.post-hero img {
  display: block;
  width: 100%;
  height: auto;
  transform: rotate(-1.2deg);
  transition: transform 0.25s cubic-bezier(0.23, 1, 0.32, 1);
}
@media (hover: hover) and (pointer: fine) {
  .post-hero:hover img { transform: rotate(0deg) scale(1.015); }
}

/* Façade vidéo : aucune requête tierce avant le clic (fidèle au « sans
   tracking » du site). Sans JavaScript, la façade est un lien YouTube ;
   au clic, un petit script la remplace par l'iframe youtube-nocookie. */
.video-facade {
  position: relative;
  display: block;
  border-radius: var(--radius);
  overflow: hidden;
  box-shadow: var(--shadow-2);
  margin: 26px 0 8px;
}
.video-facade img { display: block; width: 100%; height: auto; }
.video-facade .vf-play {
  position: absolute;
  inset: 0;
  margin: auto;
  width: 72px;
  height: 50px;
  border-radius: 12px;
  background: rgba(23, 23, 22, 0.82);
  display: flex;
  align-items: center;
  justify-content: center;
  transition: background-color 0.15s ease, transform 0.15s ease;
}
.video-facade .vf-play svg { width: 26px; height: 26px; fill: #FFF; margin-left: 3px; }
.video-facade:hover .vf-play { background: var(--brand); transform: scale(1.06); }
.video-embed { margin: 26px 0 8px; }
.video-embed iframe {
  display: block;
  width: 100%;
  aspect-ratio: 16 / 9;
  border: 0;
  border-radius: var(--radius);
  box-shadow: var(--shadow-2);
}
.vf-note {
  font-family: var(--font-mono);
  font-size: 0.76rem;
  color: var(--muted);
  margin: 0 0 26px;
}

/* Diagramme d'article : SVG inline aux tokens du site (pas de lib). */
.post-diagram { margin: 26px 0; }
.post-diagram__viewport { min-width: 0; }
.post-diagram__viewport svg { display: block; width: 100%; height: auto; }
.post-diagram__hint {
  display: none;
  font-family: var(--font-mono);
  font-size: 0.76rem;
  color: var(--accent-ink);
  margin: 0 0 8px;
}
.post-diagram .d-box { fill: var(--bg-raised); stroke: var(--border-strong); rx: 4px; }
.post-diagram .d-box--ai { fill: var(--accent-soft); stroke: var(--accent); }
.post-diagram text { font-family: var(--font-mono); fill: var(--ink); }
.post-diagram .d-dim { fill: var(--muted); }
.post-diagram .d-accent { fill: var(--accent-ink); font-weight: 600; }
.post-diagram .d-arrow { stroke: var(--border-strong); stroke-width: 1.4; fill: none; }
.post-diagram .d-head { fill: var(--border-strong); }
.post-diagram figcaption {
  font-family: var(--font-mono);
  font-size: 0.72rem;
  color: var(--muted);
  margin-top: 8px;
}

/* Functional article models. They summarize an argument with rules and
   sequence instead of adding another decorative illustration. */
.content article .post-model { max-width: 45rem; }
.post-model {
  margin: 28px 0 34px;
  padding: 18px 0 14px;
  border-top: 1px solid var(--border-strong);
  border-bottom: 1px solid var(--border-strong);
}
.post-model__label {
  margin: 0 0 10px;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  font-weight: 650;
  color: var(--accent-ink);
  letter-spacing: 0.04em;
}
.post-model figcaption {
  margin: 14px 0 0;
  font-family: var(--font-mono);
  font-size: 0.74rem;
  color: var(--muted);
}
.responsibility-map {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr);
  gap: 20px;
  align-items: stretch;
}
.responsibility-map__lane ul {
  list-style: none;
  padding: 0;
  margin: 0;
  display: grid;
  gap: 7px;
}
.responsibility-map__lane li {
  margin: 0;
  color: var(--ink-soft);
  font-size: 0.9rem;
}
.responsibility-map__lane li::before {
  content: '→';
  margin-right: 8px;
  color: var(--accent);
  font-family: var(--font-mono);
}
.responsibility-map__hinge {
  display: grid;
  align-content: center;
  gap: 8px;
  padding: 0 18px;
  border-left: 1px solid var(--border);
  border-right: 1px solid var(--border);
  font-family: var(--font-mono);
  font-size: 0.68rem;
  color: var(--muted);
  text-align: center;
}
.responsibility-map figcaption { grid-column: 1 / -1; }
.operating-model ol {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(5, minmax(0, 1fr));
}
.operating-model li {
  position: relative;
  min-width: 0;
  margin: 0;
  padding: 0 18px;
  border-left: 1px solid var(--border);
}
.operating-model li:first-child { padding-left: 0; border-left: 0; }
.operating-model li:last-child { padding-right: 0; }
.operating-model li:not(:last-child)::after {
  content: '→';
  position: absolute;
  top: 0;
  right: -0.42em;
  z-index: 1;
  padding: 0 2px;
  background: var(--bg);
  color: var(--accent-ink);
  font-family: var(--font-mono);
}
.operating-model strong {
  display: block;
  margin-bottom: 7px;
  font-size: 0.86rem;
  line-height: 1.35;
}
.operating-model li span {
  display: block;
  color: var(--muted);
  font-size: 0.78rem;
  line-height: 1.45;
}

/* Pages d'erreur (404.html et 4xx/5xx à la racine). Mise en page centrée,
   sans header ni footer : le lien brand ramène à l'accueil. Le terminal
   rejoue une commande plausible avec son vrai code de sortie shell. Entrée
   en fondu décalé héritée de la 404 d'origine, seul « budget delight » du
   site ; navigateurs sans @starting-style : affichage instantané ;
   prefers-reduced-motion : couvert par le bloc global plus bas. */
.err-wrap {
  min-height: 100vh;
  min-height: 100dvh;
  display: grid;
  /* minmax(0, 1fr) : comme pour .layout, une piste auto se calerait sur le
     min-content du <pre> du terminal et déborderait du padding sur mobile ;
     piste bornée, le <pre> défile à l'intérieur comme sur l'accueil. */
  grid-template-columns: minmax(0, 1fr);
  place-items: center;
  padding: max(24px, env(safe-area-inset-top)) max(24px, env(safe-area-inset-right)) max(24px, env(safe-area-inset-bottom)) max(24px, env(safe-area-inset-left));
}
.err { text-align: center; width: 100%; max-width: 34rem; }
.err .brand { justify-content: center; margin-bottom: 28px; }
.err .code { font-family: var(--font-mono); color: var(--accent-ink); font-size: 0.8rem; letter-spacing: 0.1em; }
.err .terminal { text-align: left; margin: 28px 0 0; }
.err .btn-row { justify-content: center; }
.err > * {
  opacity: 1;
  transform: translateY(0);
  transition: opacity 0.35s cubic-bezier(0.23, 1, 0.32, 1), transform 0.35s cubic-bezier(0.23, 1, 0.32, 1);
}
.err > :nth-child(2) { transition-delay: 60ms; }
.err > :nth-child(3) { transition-delay: 120ms; }
.err > :nth-child(4) { transition-delay: 180ms; }
.err > :nth-child(5) { transition-delay: 240ms; }
.err > :nth-child(6) { transition-delay: 300ms; }
.err > :nth-child(7) { transition-delay: 360ms; }
.err > :nth-child(8) { transition-delay: 420ms; }
@starting-style {
  .err > * { opacity: 0; transform: translateY(10px); }
}

/* Sticker 404 : Pampy rapporte un bout de page (« fetch failed »).
   Entrée avec un léger pop incliné (la 404 est le seul budget delight
   du site), puis ébrouement de chien au survol ou au toucher.
   prefers-reduced-motion (bloc global) fige tout instantanément. */
.err .err-sticker { margin: 10px 0 0; }
.err .err-sticker img {
  width: min(52vw, 220px);
  height: auto;
  transform-origin: 50% 88%;
}
@starting-style {
  .err > .err-sticker { transform: translateY(12px) scale(0.9) rotate(-5deg); }
}
@media (hover: hover) and (pointer: fine) {
  .err-sticker img:hover { animation: pampy-shake 0.6s ease-in-out; }
}
.err-sticker img:active { animation: pampy-shake 0.6s ease-in-out; }
@keyframes pampy-shake {
  0%   { transform: rotate(0); }
  20%  { transform: rotate(-6deg) scale(1.04); }
  40%  { transform: rotate(5deg)  scale(1.04); }
  60%  { transform: rotate(-3deg) scale(1.02); }
  80%  { transform: rotate(2deg)  scale(1.01); }
  100% { transform: rotate(0)     scale(1); }
}

/* --------------------------------------------------------------------------
   Responsive
   -------------------------------------------------------------------------- */
@media (max-width: 980px) {
  /* minmax(0, 1fr) - a bare 1fr cannot shrink below the track's min-content
     (the terminal <pre> is ~625px wide), which forced a 665px layout on phones */
  .layout { grid-template-columns: minmax(0, 1fr); }

  .menu-btn { display: grid; }

  .sidebar {
    position: fixed;
    inset: var(--header-offset) auto 0 0;
    width: min(320px, 85vw);
    background: var(--bg);
    border-right: 1px solid var(--border);
    /* clear the home indicator + notch in landscape */
    padding: 24px max(20px, var(--safe-left)) max(40px, calc(24px + var(--safe-bottom)));
    transform: translateX(-102%);
    visibility: hidden; /* keeps off-screen links out of the tab order */
    transition: transform 0.22s ease, visibility 0s 0.22s;
    z-index: 40;
    box-shadow: none;
    overscroll-behavior: contain;
  }
  .sidebar.open {
    transform: translateX(0);
    visibility: visible;
    transition: transform 0.22s ease, visibility 0s;
    box-shadow: var(--shadow-2);
  }

  .backdrop {
    position: fixed;
    inset: var(--header-offset) 0 0 0;
    background: rgba(23, 23, 22, 0.35);
    z-index: 39;
    opacity: 0;
    pointer-events: none;
    transition: opacity 0.2s;
  }
  .backdrop.show { opacity: 1; pointer-events: auto; }

  /* Lock the page behind the open drawer (modal behaviour) */
  body.nav-open { overflow: hidden; }

  .header-nav { display: none; }
}

/* Bigger touch targets on touch devices (Apple HIG: 44px) */
@media (pointer: coarse) {
  .icon-btn { width: 44px; height: 44px; }
  .lang-switch a, .lang-switch span { padding: 7px 12px; }
  .header-nav a { padding: 10px 12px; }
  .side-group a { padding: 12px 10px; }
  .btn { min-height: 44px; }
  /* Liens texte autonomes (étude de cas, fil d'Ariane, pagination) : la boîte
     de tap grandit par padding + marge négative, sans bouger la mise en page. */
  .text-link,
  .breadcrumb a,
  .page-next a { display: inline-block; padding: 12px 6px; margin: -12px -6px; }
  /* Pilule de langue : zone de tap invisible étendue à ~44px. */
  .lang-switch a { position: relative; }
  .lang-switch a::before { content: ''; position: absolute; inset: -8px -4px; }
  /* Ancres de titres : invisibles au survol qui n'existe pas au tactile,
     elles restent repérables et gagnent une zone de tap honnête.
     0.75 : --muted à 45 % tombait sous 3:1 (repère UI illisible). */
  .anchor-heading .anchor { opacity: 0.75; padding: 8px 10px; margin-left: 2px; }
  /* Hauteur tactile délibérée et identique dans tous les navigateurs.
     column-gap : en flex, l'espace devant la flèche « ↗ » est rogné par le
     moteur (espace en tête d'item) ; le gap le remplace, sans effet sur les
     liens à nœud texte unique. */
  .footer-col a { display: flex; align-items: center; min-height: 44px; padding: 0; column-gap: 0.35em; }
}

@media (max-width: 560px) {
  .site-header .brand span { display: none; }
  .site-header .header-actions > a.icon-btn { display: none; }
  .content { padding-top: 28px; }
  h2 { font-size: 1.45rem; }

  .portrait--mobile-block {
    float: none;
    width: min(150px, 42vw);
    margin: 12px auto 18px;
  }

  .content article .terminal pre,
  .terminal--signature pre,
  .err .terminal pre {
    white-space: pre-wrap;
    overflow-wrap: anywhere;
  }

  .responsibility-map { grid-template-columns: 1fr; gap: 16px; }
  .responsibility-map__hinge {
    grid-template-columns: repeat(3, auto);
    justify-content: start;
    padding: 12px 0;
    border: 0;
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
  }
  .operating-model ol { grid-template-columns: 1fr; }
  .operating-model li,
  .operating-model li:first-child,
  .operating-model li:last-child {
    padding: 14px 0;
    border: 0;
    border-top: 1px solid var(--border);
  }
  .operating-model li:first-child { border-top: 0; padding-top: 0; }
  .operating-model li:last-child { padding-bottom: 0; }
  .operating-model li:not(:last-child)::after {
    content: '↓';
    top: auto;
    right: 0;
    bottom: -0.75em;
  }
}

@media (max-width: 720px) {
  .case-index-list { grid-template-columns: 1fr; }
  .case-index-item,
  .case-index-item:nth-child(-n + 2) { border-top: 1px solid var(--border); }
  .case-index-item:first-child { border-top: 0; }
  .case-index-item:nth-child(even) { border-left: 0; }

  .page-work--indexed .case-sticker {
    float: none;
    width: min(var(--sticker-w, 180px), 58vw);
    margin: 1.2rem auto 1.4rem;
  }

  .stat-band { grid-template-columns: repeat(2, minmax(0, 1fr)); }
  .stat-band .stat,
  .stat-band .stat:first-child,
  .stat-band .stat:last-child { padding: 16px; }
  .stat-band .stat:nth-child(odd) { padding-left: 0; border-left: 0; }
  .stat-band .stat:nth-child(even) { padding-right: 0; border-left: 1px solid var(--border); }
  .stat-band .stat:nth-child(n + 3) { border-top: 1px solid var(--border); }

  .work-list--featured { grid-template-columns: 1fr; }
  .work-list--featured .work-summary--featured,
  .work-list--featured .work-summary--compact,
  .work-list--featured .work-summary--compact:nth-child(2),
  .work-list--featured .work-summary--compact:last-child {
    grid-column: auto;
    grid-template-columns: 1fr;
    padding: 20px 0;
    border-right: 0;
  }
  .work-list--featured .work-summary .text-link { grid-column: 1; }

  .blog-featured { grid-template-columns: 1fr; }
  .blog-featured-media { max-width: 30rem; }

  .post-diagram__hint { display: block; }
  .post-diagram__viewport {
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scrollbar-width: thin;
    padding: 8px 0 12px;
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
  }
  .post-diagram__viewport svg { width: 720px; max-width: none; }
}

@media (prefers-reduced-motion: reduce) {
  html { scroll-behavior: auto; }
  *, *::before, *::after { transition: none !important; animation: none !important; }
}

/* --------------------------------------------------------------------------
   Impression des pages hors CV (le CV a son propre bloc dans cv.css).
   Sans ces règles, terminal et panneau contact imprimaient blanc sur blanc :
   les fonds sombres sautent par défaut à l'impression.
   -------------------------------------------------------------------------- */
@media print {
  /* Palette encre sur papier quel que soit le thème : l'attribut
     data-theme="dark" continue de s'appliquer à l'impression, et ses jetons
     (--ink ivoire...) rendraient le texte quasi invisible sur papier.
     Même motif que le bloc print de cv.css. */
  :root,
  :root[data-theme="dark"],
  :root[data-theme="light"] {
    --bg: #FFFFFF;
    --bg-raised: #FFFFFF;
    --bg-inset: #FFFFFF;
    --ink: #000000;
    --ink-soft: #1F1F1E;
    --muted: #4A4943;
    --border: #D8D6CC;
    --border-strong: #B9B6A9;
    --accent: #9A4A26;
    --accent-ink: #9A4A26;
    --accent-soft: #FFFFFF;
    --accent-glow: transparent;
    color-scheme: light;
  }

  .site-header,
  .sidebar,
  .backdrop,
  .skip-link { display: none !important; }
  .layout { display: block; padding-top: 0; }
  body { background: #FFF; color: #000; }
  .terminal,
  .contact-panel {
    background: #FFF;
    color: #000;
    box-shadow: none;
    border: 1px solid #999;
  }
  .terminal .t-prompt,
  .terminal .t-cmd,
  .terminal .t-key,
  .contact-panel h2 { color: #000; }
  .terminal .t-dim,
  .terminal .terminal-title,
  .contact-panel p { color: #444; }
  .contact-panel .btn { background: #FFF; color: #000; border: 1px solid #999; }
}
