/* ==========================================================================
   Portfolio — style.css
   Charte : warm minimal, Space Grotesk + Inter Tight + JetBrains Mono.
   ========================================================================== */

/* Polices : les @font-face vivent dans static/fonts.css (chargé avant cette feuille). Ne rien redéclarer ici. */

:root {
  /* Accorde les contrôles natifs (popups de <select>, scrollbars, inputs
     date) au thème courant : même pattern que la console Espace Clients. */
  color-scheme: light;
  /* Coche SVG partagée (mask-image), remplace les anciennes coches en
     `content:` texte ; la couleur vient du `background-color` de l'élément
     masqué. Réutilisée par cdc.css (chargée après cette feuille). */
  --icon-check: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath d='m20 6-11 11-5-5' fill='none' stroke='%23000' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'/%3E%3C/svg%3E");
  --bg: #fbfaf7;
  --fg: #0a0a0a;
  --fg-soft: #404040;
  --muted: #525252;
  --muted-2: #737373;
  --muted-3: #6f6a63;   /* audit L4 : ~4.6:1 (AA) pour les petits libellés mono */
  --line: rgba(0,0,0,0.08);
  --line-soft: rgba(0,0,0,0.06);
  --line-strong: rgba(0,0,0,0.12);
  --card: #ffffff;
  --paper: #fafaf9;
  --paper-2: #f5f5f4;
  --accent: #0a0a0a;
  --accent-azur: oklch(0.62 0.18 210); /* bleu azur — clin d'œil au nom (hero animé) */
  /* Le panneau d'erreur de la maison, en trois jetons. Le lavis est
     TRANSLUCIDE : le même composant se pose sur la page, sur une carte de
     connexion et sur un formulaire, qui n'ont pas le même fond. Trois
     composants rendaient trois erreurs différentes (cf. la règle groupée
     « .alert, .form-status.is-err, .eca-error » plus bas) ; ces jetons sont
     désormais la source unique de leurs couleurs. */
  --danger-bg: rgba(180, 35, 24, 0.07);
  --danger-fg: #b42318;
  --danger-line: rgba(180, 35, 24, 0.2);

  --font-display: 'Space Grotesk', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-body: 'Inter Tight', system-ui, -apple-system, 'Segoe UI', sans-serif;
  --font-mono: 'JetBrains Mono', ui-monospace, 'SF Mono', monospace;

  --on-accent: #fbfaf7;                       /* encre sur aplat sombre/accent */
  --ease-standard: cubic-bezier(0.4, 0, 0.2, 1);
  --ease-spring: cubic-bezier(0.34, 1.4, 0.64, 1);
}

* { box-sizing: border-box; }
html, body { margin: 0; padding: 0; }
body {
  font-family: var(--font-body);
  font-size: 15px;
  line-height: 1.55;
  color: var(--fg);
  background: var(--bg);
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
a { color: inherit; }
button { font-family: inherit; }
code {
  font-family: var(--font-mono);
  font-size: 0.92em;
  background: var(--paper-2);
  padding: 1px 6px;
  border-radius: 4px;
}

/* Mesuré au navigateur sur les deux fonds réels du site : `--muted-2` tombe à
   3,62:1 sur une carte en thème sombre et à 4,35:1 sur une carte en clair,
   alors que cette classe porte du texte de contenu (phrases entières, notes de
   formulaire, mentions du pied de page). `--muted-3` passe AA partout : 4,50:1
   au pire (carte sombre) et 4,71:1 au pire en clair. Le jeton reste plus doux
   que `--muted`, donc la hiérarchie visuelle ne bouge pas. */
.muted { color: var(--muted-3); }
.small { font-size: 12px; }

/* Lien d'évitement (audit L3, WCAG 2.4.1) : hors écran, révélé au focus clavier. */
.skip-link {
  position: absolute;
  left: 8px;
  top: -48px;
  z-index: 1000;
  padding: 10px 16px;
  background: var(--fg);
  color: var(--bg);
  border-radius: 8px;
  font-weight: 600;
  text-decoration: none;
  transition: top 150ms ease;
}
.skip-link:focus { top: 8px; outline: 2px solid var(--accent); outline-offset: 2px; }
/* Un seul panneau d'erreur pour tout le site : la forme des formulaires (lavis translucide, sur tout fond). */
.alert,
.form-status.is-err,
.eca-error {
  background: var(--danger-bg);
  color: var(--danger-fg);
  border: 1px solid var(--danger-line);
  border-radius: 10px;
  padding: 12px 14px;
  font-size: 14px;
}
.alert { margin-bottom: 12px; }

/* ── Eyebrow + sections-labels (mono uppercase) ─────────────────── */
.hero-eyebrow {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--muted-3);
  letter-spacing: 0.22em;
  text-transform: uppercase;
}

/* ── Buttons ────────────────────────────────────────────────────── */
.btn-primary,
.btn-secondary,
.btn-ghost {
  display: inline-flex; align-items: center; justify-content: center; gap: 6px;
  padding: 9px 16px;
  border-radius: 8px;
  font-family: var(--font-body);
  font-size: 13px;
  /* Un <a> hérite le 1.55 du body, un <button> reçoit « normal » : la même
     classe rendait 40 px sur l'un et 36 sur l'autre, côte à côte. Un composant
     pose sa métrique ; celle du corps de texte est le choix global (mesuré :
     seuls les <button> grandissent de 4 px, aucun <a> ne bouge, et sous
     760 px le plancher tactile de 44 px gouverne déjà les deux). */
  line-height: 1.55;
  font-weight: 500;
  letter-spacing: -0.008em;
  text-decoration: none;
  cursor: pointer;
  border: 1px solid transparent;
  transition: transform 180ms ease,
              background 200ms ease,
              color 200ms ease,
              border-color 200ms ease,
              box-shadow 220ms ease;
}
.btn-primary {
  background: #0a0a0a; color: #fafaf9; border-color: #0a0a0a;
  box-shadow: 0 1px 2px rgba(0,0,0,0.10), inset 0 1px 0 rgba(255,255,255,0.08);
}
.btn-primary:hover {
  transform: translateY(-1px);
  box-shadow: 0 8px 20px -6px rgba(0,0,0,0.32), 0 2px 4px rgba(0,0,0,0.08), inset 0 1px 0 rgba(255,255,255,0.08);
}
.btn-primary:active {
  transform: translateY(0);
  box-shadow: 0 1px 2px rgba(0,0,0,0.10), inset 0 1px 0 rgba(255,255,255,0.08);
}
.btn-secondary {
  background: var(--card); color: var(--fg); border-color: var(--line);
}
.btn-secondary:hover {
  background: var(--paper);
  border-color: var(--line-strong);
  box-shadow: 0 4px 12px -4px rgba(0,0,0,0.08);
  transform: translateY(-1px);
}
.btn-secondary:active { transform: translateY(0); box-shadow: none; }
.btn-ghost {
  background: transparent; color: var(--muted); border-color: transparent;
}
.btn-ghost:hover { color: var(--fg); background: var(--paper); }
/* Piège [hidden] (cf. CLAUDE.md) : le `display: inline-flex` d'auteur ci-dessus
   bat la règle `[hidden] { display: none }` du navigateur. Un bouton masqué par
   attribut restait donc affiché et inerte — c'est le cas de « Copier les
   hashtags seuls » sur un post sans hashtags, ou du bouton de visuel sur un
   post sans image prête. La règle qui crée le piège porte sa propre parade. */
.btn-primary[hidden], .btn-secondary[hidden], .btn-ghost[hidden] { display: none; }
.link-muted {
  color: var(--muted-3);   /* même mesure que .muted : AA sur carte et sur page */
  text-decoration: none;
  font-size: 14px;
  font-weight: 500;
  letter-spacing: -0.005em;
}
.link-muted:hover { color: var(--fg); }

/* ── Topbar (fixed, glass) ───────────────────────────────────────── */
.topbar {
  position: fixed; top: 0; left: 0; right: 0;
  padding: 22px 36px;
  display: flex; justify-content: space-between; align-items: center;
  z-index: 40;
  pointer-events: none;
  background: linear-gradient(to bottom, rgba(251,250,247,0.85), rgba(251,250,247,0));
  backdrop-filter: blur(8px);
  -webkit-backdrop-filter: blur(8px);
  -webkit-mask-image: linear-gradient(to bottom, black 60%, transparent);
  mask-image: linear-gradient(to bottom, black 60%, transparent);
}
.brand {
  pointer-events: auto;
  font-family: var(--font-display);
  font-size: 16px; font-weight: 600;
  letter-spacing: -0.02em;
  color: var(--fg);
  text-decoration: none;
  background: transparent; border: 0; padding: 0; cursor: pointer;
}
.brand-logo{display:inline-block;height:44px;aspect-ratio:1116/256;background:url(/static/brand/logo.png) left center/contain no-repeat}
[data-theme=dark] .brand-logo{background-image:url(/static/brand/logo-dark.png)}
/* Le logo complet dans la barre (septembre 2026). Bloc : sans ligne de texte
   autour, la marque fait la hauteur du dessin. Sa taille suit la place que
   laisse la navigation, mesurée largeur par largeur (plus bas). */
.brand-logo--bar{display:block;height:36px}
.topbar-nav {
  display: flex; gap: 28px; align-items: center;
  pointer-events: auto;
  font-family: var(--font-body); font-size: 13px; font-weight: 500;
  letter-spacing: -0.005em;
}
.topbar-nav a {
  color: var(--muted-3); text-decoration: none;
  transition: color 150ms ease;
}
.topbar-nav a:hover { color: var(--fg); }
.topbar-nav a.is-active { color: var(--fg); font-weight: 600; }

/* ── Scroll snap container (landing) ─────────────────────────────── */

/* ── Hero ───────────────────────────────────────────────────────── */
.hero { display: flex; align-items: center; justify-content: center; }
.hero-inner {
  width: 100%; max-width: 980px;
  padding: 0 32px;
  display: flex; flex-direction: column; align-items: center;
  text-align: center;
}
.hero-eyebrow { margin-bottom: 28px; }
.hero-title {
  font-family: var(--font-display);
  font-size: clamp(56px, 9vw, 144px);
  font-weight: 600;
  letter-spacing: -0.045em;
  line-height: 0.92;
  color: var(--fg);
  margin: 0;
}

/* ── Scroll cue ─────────────────────────────────────────────────── */
.scroll-cue {
  position: absolute; bottom: 36px; left: 50%;
  transform: translateX(-50%);
  display: flex; flex-direction: column; align-items: center; gap: 12px;
  font-family: var(--font-mono);
  font-size: 10px; color: var(--muted-3);
  letter-spacing: 0.22em; text-transform: uppercase;
  pointer-events: none;
  animation: bob 2.4s ease-in-out infinite;
}
.scroll-cue svg { color: var(--muted-3); }
@keyframes bob {
  0%, 100% { transform: translateX(-50%) translateY(0); }
  50%      { transform: translateX(-50%) translateY(8px); }}

/* ── Project section ────────────────────────────────────────────── */
.project { background: var(--bg); }
.tag {
  padding: 4px 10px;
  border: 1px solid var(--line);
  border-radius: 999px;
  color: var(--muted-3);
  letter-spacing: 0.08em;
}

/* ── Mockups (mobile + web) ──────────────────────────────────────── */
.mockup { transform-origin: center; position: relative; }

.phone {
  width: 320px; height: 660px;
  border-radius: 44px;
  background: #0a0a0a;
  padding: 12px;
  box-shadow: 0 30px 80px -20px rgba(0,0,0,0.25), 0 8px 20px -8px rgba(0,0,0,0.15);
  position: relative;
}
.browser {
  width: 880px; height: 560px;
  border-radius: 12px;
  background: #fff;
  box-shadow: 0 30px 80px -20px rgba(0,0,0,0.18), 0 8px 20px -8px rgba(0,0,0,0.10);
  overflow: hidden;
  border: 1px solid var(--line-soft);
}
@keyframes skeleton-shimmer {
  0%   { background-position: 200% 0; }
  100% { background-position: -200% 0; }}

/* ── About section ──────────────────────────────────────────────── */
.about { display: flex; align-items: center; justify-content: center; padding: 0 60px; }

/* Reste de l'ancienne grille de cartes de /apps : la cellule, toujours
   utilisée par la grille « à la une » de l'accueil (.featured-grid). Les
   cartes elles-mêmes (.app-card*, .app-icon*, .app-demo-link) ont été
   remplacées par la mosaïque « bento » et ne sont plus citées nulle part
   dans le dépôt : leurs 4,6 ko payaient le contrat de poids de l'accueil
   sans rien peindre. */
.app-cell { min-width: 0; }
.app-cell[hidden] { display: none; }

/* ====================================================================== */
/* Page /apps — mosaïque « bento magnétique » (handoff C3)                 */

/* La tuile : aplat d'accent assombri (texte blanc lisible) + couches de fond.
   Un accent d'app n'est pas fait pour porter du texte : à 84 % d'accent,
   57 nœuds sur 101 tombaient sous 4,5:1 (mesuré sur les pixels peints). À
   70 %, seule la clarté descend ; un accent plus clair (un jaune) redemanderait
   la même mesure. */
.tile {
  position: relative; overflow: hidden;
  border-radius: 22px; padding: 20px;
  display: flex; flex-direction: column;
  text-decoration: none; color: #fff;
  background: color-mix(in oklch, var(--accent) 70%, #16140f);
  box-shadow:
    0 10px 22px -12px color-mix(in oklch, var(--accent) 55%, transparent),
    inset 0 1px 0 rgba(255, 255, 255, 0.20);
  transition: box-shadow 0.35s var(--ease-standard),
              transform 0.4s var(--ease-spring);
  will-change: transform;
}

.tile[hidden] { display: none; }
.tile:hover {
  box-shadow:
    0 30px 60px -18px color-mix(in oklch, var(--accent) 55%, transparent),
    inset 0 1px 0 rgba(255, 255, 255, 0.22);
  z-index: 6;
}
.tile:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }

/* Couches de fond décoratives (sous le contenu) */
.tile-halo, .tile-dots, .tile-mark {
  position: absolute; inset: 0; pointer-events: none;
}
.tile-halo {
  background: radial-gradient(120% 90% at 12% 0%,
              color-mix(in oklch, var(--accent) 60%, white) 0%, transparent 52%);
  /* Le halo tire vers le blanc : c'est lui qui éclaircit le coin haut-gauche,
     là où se lisent le badge, le nom et la pastille. Baissé d'un cinquième. */
  opacity: 0.42;
}
.tile:not(.tile--featured) .tile-halo {
  background: radial-gradient(120% 90% at 15% 0%,
              color-mix(in oklch, var(--accent) 58%, white) 0%, transparent 55%);
  opacity: 0.38;
}
.tile-dots {
  background-image: radial-gradient(circle, rgba(255, 255, 255, 0.13) 1px, transparent 1.4px);
  background-size: 18px 18px;
  opacity: 0.6;
  -webkit-mask-image: linear-gradient(135deg, #000 0%, transparent 60%);
          mask-image: linear-gradient(135deg, #000 0%, transparent 60%);
}
.tile:not(.tile--featured) .tile-dots {
  background-size: 16px 16px; opacity: 0.5;
  -webkit-mask-image: linear-gradient(135deg, #000 0%, transparent 62%);
          mask-image: linear-gradient(135deg, #000 0%, transparent 62%);
}
/* Picto de l'app en filigrane géant, bas-droite */
.tile-mark {
  inset: auto; right: -44px; bottom: -54px;
  width: 340px; height: 340px;
  color: #fff; opacity: 0.10; transform: rotate(-8deg);
  transition: transform 0.5s var(--ease-spring), opacity 0.4s ease;
}
.tile:not(.tile--featured) .tile-mark {
  right: -26px; bottom: -30px; width: 168px; height: 168px; opacity: 0.09;
}
.tile-mark svg { display: block; width: 100%; height: 100%; }
.tile-mark .tile-glyph-fallback { font-size: 220px; }
.tile:not(.tile--featured) .tile-mark .tile-glyph-fallback { font-size: 120px; }
.tile:hover .tile-mark { transform: rotate(-6deg) scale(1.06); opacity: 0.14; }

/* Contenu (au-dessus des couches) */
.tile > .tile-top,
.tile > .tile-head,
.tile > .tile-tagline,
.tile > .tile-tags,
.tile > .tile-bar { position: relative; z-index: 1; }

.tile-top { display: flex; align-items: flex-start; justify-content: space-between; gap: 8px; }
.tile-badge {
  width: 40px; height: 40px; flex-shrink: 0;
  display: flex; align-items: center; justify-content: center; padding: 8px;
  color: #fff;
  background: rgba(255, 255, 255, 0.14);
  border: 1px solid rgba(255, 255, 255, 0.20);
  border-radius: 12px;
}

.tile-badge .tile-glyph-fallback {
  font-family: var(--font-display); font-size: 22px; font-weight: 600; line-height: 1;
}

/* Vrai logo d'une app (PNG) : pastille claire, filigrane inversé. */
.app-glyph-img { display: block; width: 100%; height: 100%; object-fit: contain; }
.tile-badge:has(.app-glyph-img) { background: #fbfaf7; border-color: rgba(255, 255, 255, 0.55); padding: 5px; }

.tile-mark .app-glyph-img { filter: grayscale(1) invert(1); }

.tile-head { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; margin-top: 13px; }

.tile-name {
  font-family: var(--font-display);
  font-size: 38px; font-weight: 600; letter-spacing: -0.03em; line-height: 1;
}
.tile-name--sm { font-size: 18px; letter-spacing: -0.02em; line-height: 1.05; }

.tile-tagline {
  margin: 13px 0 0; max-width: 44ch;
  font-size: 15px; line-height: 1.55;
  color: rgba(255, 255, 255, 0.92); text-wrap: pretty;
}
.tile-tagline--sm {
  margin: 7px 0 0; flex: 1;
  font-size: 12px; line-height: 1.45; color: rgba(255, 255, 255, 0.95);
  display: -webkit-box; -webkit-line-clamp: 3; -webkit-box-orient: vertical; overflow: hidden;
}

/* Tags (satellites) */
.tile-tags { display: flex; gap: 6px; flex-wrap: wrap; margin-top: 11px; }
.tile-tag {
  font-family: var(--font-mono);
  font-size: 8px; letter-spacing: 0.1em; text-transform: uppercase;
  color: #fff; background: rgba(0, 0, 0, 0.24);   /* voile sombre : cf. .tile-pin */
  border-radius: 999px; padding: 3px 8px;
}

/* Pied (satellites) */
.tile-bar {
  margin-top: 13px; padding-top: 11px;
  border-top: 1px solid rgba(255, 255, 255, 0.16);
  display: flex; align-items: center; justify-content: space-between; gap: 8px;
}

.tile-cta {
  display: inline-flex; align-items: center; gap: 7px;
  font-family: var(--font-mono);
  font-size: 10px; letter-spacing: 0.08em; text-transform: uppercase;
  /* Encre sur pastille blanche : l'accent nu y descendait à 4,11:1 (mesuré).
     Même règle que le fond de tuile, dans l'autre sens : l'accent qui devient
     du TEXTE est assombri, celui qui reste un aplat ne bouge pas. */
  color: color-mix(in oklch, var(--accent) 66%, #16140f); background: #fff;
  border-radius: 999px; padding: 10px 17px;
  transition: transform 0.3s var(--ease-spring);
}
.tile-cta--sm {
  background: transparent; color: #fff; padding: 0;
  font-size: 8.5px; border-radius: 0;
}
.tile:hover .tile-cta { transform: translateX(3px); }

.tile-meta {
  margin-left: auto;
  font-family: var(--font-mono);
  font-size: 9px; letter-spacing: 0.12em; text-transform: uppercase;
  color: rgba(255, 255, 255, 0.92); white-space: nowrap;
}
.tile-bar .tile-meta { margin-left: 0; font-size: 8.5px; color: rgba(255, 255, 255, 0.92); }

/* Badges d'état (lien / vitrine / privée / démo) sur les tuiles */
.tile-flag {
  font-family: var(--font-mono);
  font-size: 7.5px; letter-spacing: 0.1em; text-transform: uppercase;
  color: #fff; background: rgba(0, 0, 0, 0.30);   /* voile sombre : cf. .tile-pin */
  border-radius: 999px; padding: 2px 7px;
}

/* Nature de l'app — même composant, deux poids assumés : « Outil pro » se voit
   (c'est la preuve de compétence), « Projet perso » s'efface (il ne doit pas
   parasiter la lecture d'un prospect venu pour un site). */
.tile-flag--pro,
.tile-flag--perso {
  flex: none; align-self: center;
  font-size: 8.5px; padding: 5px 10px; white-space: nowrap;
}
.tile-top .tile-flag--pro,
.tile-top .tile-flag--perso { margin-left: auto; }
.tile-flag--pro {
  /* La pastille portait l'accent PROPRE À CHAQUE APP sur du blanc : mesuré de
     3,12 à 4,47:1 selon la tuile, sous le seuil AA. Tant qu'elle disait « Outil
     pro », c'était une décoration ; depuis la vague 2 elle dit « Site » ou
     « Application », c'est-à-dire lequel des deux métiers, et ça se lit.
     L'encre est écrite en dur parce que le fond l'est aussi : `--fg` suit le
     thème et virerait au blanc sur blanc en sombre. L'accent reste sur la
     tuile entière, qui est déjà de sa couleur. */
  color: #14120e; background: #fff; font-weight: 600;
}
.tile-flag--perso {
  /* Badge « projet perso » : texte plein sur voile assombri (3,4:1 avant, sous le seuil AA). */
  color: #fff;
  background: rgba(0, 0, 0, 0.18);
  border: 1px solid rgba(255, 255, 255, 0.28);
  font-weight: 400;
}

/* Animation d'entrée « flou → net », échelonnée par tuile (--d) */
@keyframes ab-tile-in { from { opacity: 0; filter: blur(9px); } to { opacity: 1; filter: blur(0); } }

@media (prefers-reduced-motion: reduce) {

  .tile, .tile-mark, .tile-cta { transition: none; }}

/* Responsive bento : 2 colonnes puis 1 colonne */
@media (max-width: 900px) {

  .tile-name { font-size: 32px; }
}
@media (max-width: 560px) {

  .tile-name { font-size: 28px; }
  }

/* ── Page login ─────────────────────────────────────────────────── */
.page-login {
  display: grid; place-items: center; min-height: 100vh;
  background: var(--bg);
}
.login-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 36px 40px;
  width: min(380px, 92vw);
  box-shadow: 0 20px 60px -15px rgba(0,0,0,0.08);
}
.login-card .brand-logo { display: block; margin-bottom: 8px; }
.login-card .hero-eyebrow { margin: 8px 0 24px; display: block; }
.login-card form { display: grid; gap: 14px; margin-top: 20px; }
.login-card label { display: grid; gap: 6px; }
.login-card label span {
  font-family: var(--font-mono);
  font-size: 10px;
  color: var(--muted-3);
  letter-spacing: 0.18em;
  text-transform: uppercase;
}
.login-card input {
  background: var(--paper);
  color: var(--fg);
  border: 1px solid var(--line);
  padding: 11px 13px;
  border-radius: 10px;
  font-family: var(--font-body);
  font-size: 15px;
  outline: none;
  transition: all 150ms ease;
}
.login-card input:focus {
  border-color: var(--fg);
  background: var(--card);
}
.login-card .btn-primary { padding: 13px; margin-top: 4px; }
.login-card .small { margin-top: 18px; text-align: center; }
.login-card .small a { color: var(--muted); text-decoration: underline; text-decoration-color: var(--line); }

/* ── Page admin ─────────────────────────────────────────────────── */
.page-admin {
  background: var(--bg);
  padding-top: 92px;
  min-height: 100vh;
}
.admin-main {
  max-width: 880px;
  margin: 0 auto;
  padding: 32px 24px 80px;
}
.admin-main .hero-eyebrow { display: block; margin-bottom: 12px; }
.admin-title {
  font-family: var(--font-display);
  font-size: clamp(40px, 5vw, 64px);
  font-weight: 600;
  letter-spacing: -0.04em;
  line-height: 0.95;
  margin: 0 0 32px;
}
.admin-card {
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 16px;
  padding: 24px 28px;
  margin-bottom: 18px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.02);
}
.admin-card h2 {
  font-family: var(--font-display);
  font-size: 17px;
  font-weight: 600;
  letter-spacing: -0.01em;
  margin: 0 0 12px;
}
.kv-grid {
  display: grid;
  grid-template-columns: 160px 1fr;
  gap: 8px 16px;
  margin: 12px 0 0;
}
/* `display: grid` bat le [hidden] du navigateur — sans ça, la grille d'infos de
   la sauvegarde (#backupInfo) s'affiche vide (« … ») tant que R2 n'est pas
   configuré. */
.kv-grid[hidden] { display: none; }
.kv-grid dt {
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--muted-3);
  letter-spacing: 0.16em;
  text-transform: uppercase;
}
.kv-grid dd { margin: 0; color: var(--fg); }
.row {
  display: flex; gap: 10px; align-items: center; flex-wrap: wrap;
  margin-top: 16px;
}
.log {
  background: #0b0d12;
  color: #d6dbe7;
  border: 1px solid #1c2030;
  border-radius: 10px;
  padding: 12px 14px;
  max-height: 280px; overflow: auto;
  font-family: var(--font-mono);
  font-size: 12px;
  white-space: pre-wrap;
  margin-top: 14px;
}

/* ── Pages d'erreur (404 / 500) ─────────────────────────────────── */
.page-404,
.page-500 { background: var(--bg); }
/* La page d'erreur porte la barre et le pied de page : centrage sur <main>. */
.error-wrap {
  display: grid; place-items: center; min-height: 62vh;
  padding: 128px 24px 72px;
}
.error-card {
  max-width: 560px;
  text-align: left;
}
.error-card .hero-eyebrow { display: block; margin-bottom: 18px; }
.error-title {
  font-family: var(--font-display);
  font-size: clamp(56px, 8vw, 96px);
  font-weight: 600;
  letter-spacing: -0.045em;
  line-height: 0.95;
  margin: 0 0 20px;
}
/* 56 px débordait à 320 px (« introuvable. ») : un mot insécable se réduit, 12,5vw = 56 px à 448 px. */
@media (max-width: 448px) {
  .error-title { font-size: 12.5vw; }
}
.error-actions {
  display: flex; gap: 12px; flex-wrap: wrap; margin-top: 28px;
}

/* ── Dark mode ──────────────────────────────────────────────────── */
[data-theme="dark"] {
  color-scheme: dark;
  --bg: #111110;
  --fg: #f5f4f1;
  --on-accent: #111110;          /* encre sombre sur --fg clair (chip actif) */
  --fg-soft: #c8c6c0;
  --muted: #9a9896;
  --muted-2: #7a7876;
  --muted-3: #8a8884;   /* audit L4 : ~4.6:1 (AA) pour les petits libellés mono */
  --line: rgba(255,255,255,0.07);
  --line-soft: rgba(255,255,255,0.05);
  --line-strong: rgba(255,255,255,0.12);
  --card: #1c1c1a;
  --paper: #171716;
  --paper-2: #222220;
  --accent: #f5f4f1;
  /* Mêmes rôles qu'en clair, mêmes valeurs que le lavis d'erreur des
     formulaires : un seul rouge d'alerte par thème sur tout le site. */
  --danger-bg: rgba(248, 113, 113, 0.08);
  --danger-fg: #f87171;
  --danger-line: rgba(248, 113, 113, 0.22);
}

[data-theme="dark"] .topbar {
  background: linear-gradient(to bottom, rgba(17,17,16,0.88), rgba(17,17,16,0));
}
[data-theme="dark"] .btn-primary {
  background: #f5f4f1; color: #111110; border-color: #f5f4f1;
  box-shadow: 0 1px 2px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.15);
}
[data-theme="dark"] .btn-primary:hover {
  box-shadow: 0 8px 20px -6px rgba(0,0,0,0.55), 0 2px 4px rgba(0,0,0,0.25), inset 0 1px 0 rgba(255,255,255,0.15);
}
[data-theme="dark"] .browser { background: #1c1c1a; }

/* ── Theme toggle ────────────────────────────────────────────────── */
.theme-toggle {
  width: 30px; height: 30px;
  border-radius: 50%;
  background: rgba(255,255,255,0.65);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--line);
  display: flex; align-items: center; justify-content: center;
  cursor: pointer;
  color: var(--fg);
  transition: background 200ms ease, transform 200ms ease, border-color 200ms ease;
  padding: 0;
  flex-shrink: 0;
}
.theme-toggle:hover { background: rgba(255,255,255,0.92); transform: scale(1.06); }
[data-theme="dark"] .theme-toggle { background: rgba(255,255,255,0.07); }
[data-theme="dark"] .theme-toggle:hover { background: rgba(255,255,255,0.13); }
.theme-toggle .icon-sun  { display: none; }
.theme-toggle .icon-moon { display: block; }
[data-theme="dark"] .theme-toggle .icon-sun  { display: block; }
[data-theme="dark"] .theme-toggle .icon-moon { display: none; }

/* ── Responsive : tablette (≤ 880px) ────────────────────────────── */
@media (max-width: 880px) {
  .topbar { padding: 16px 20px; }
  .topbar-nav { gap: 18px; font-size: 12px; }

  .admin-main { padding: 24px 18px 60px; }
  .kv-grid { grid-template-columns: 1fr; }
}

/* ── Responsive : smartphone (≤ 640px) ──────────────────────────── *
   On enlève la chrome décorative qui chevauche le contenu sur petit
   écran, et on utilise svh/dvh pour gérer la barre Safari iOS. */
@media (max-width: 640px) {
  /* Padding safe-area (encoche iPhone) */
  .topbar {
    padding: 14px max(16px, env(safe-area-inset-right))
             14px max(16px, env(safe-area-inset-left));
  }
  .topbar-nav { gap: 14px; font-size: 12px; }
  .brand { font-size: 15px; }

  /* Hero */
  .hero { min-height: 100svh; padding: 90px 0 80px; }
  .hero-inner { padding: 0 22px; }
  .hero-eyebrow { font-size: 10px; margin-bottom: 22px; }
  .hero-title {
    font-size: clamp(46px, 13vw, 80px);
    line-height: 0.94;
    letter-spacing: -0.04em;
  }

  /* Project sections : on casse le position:absolute pour laisser
     le contenu respirer en flow vertical. */
  .project {
    min-height: 100svh;
    padding: 88px 0 72px;
  }
  .tag { padding: 3px 8px; font-size: 9px; }

  /* About */
  .about {
    min-height: 100svh;
    padding: 90px 22px 80px;
    align-items: flex-start;
  }

  /* Chrome décorative : on planque ce qui chevauche le contenu */
  .scroll-cue { bottom: 18px; font-size: 9px; gap: 8px; }

  /* Login */
  .login-card { padding: 28px 24px; border-radius: 14px; }
}

/* ==========================================================================
   Vitrine Azur Tech — home marketing, contact, pages légales, footer riche
   ========================================================================== */

/* ── Bouton large (CTA principaux) ──────────────────────────────────── */
.btn-lg {
  padding: 14px 24px;
  font-size: 15px;
  border-radius: 10px;
}

/* ── Reveal-on-scroll ───────────────────────────────────────────────────
   Robustesse : par défaut le contenu est VISIBLE (sans JS, rien ne disparaît).
   landing.js « arme » uniquement les blocs sous la ligne de flottaison
   (.is-armed → opacité 0) puis les révèle à l'entrée dans le viewport. */
.reveal {
  /* 320 ms (et non 620) : le serveur répond en ~50 ms, une cascade d'une demi-
     seconde par bloc donnait une sensation de latence sur toute la page. */
  transition: opacity 320ms cubic-bezier(0.16, 1, 0.3, 1),
              transform 320ms cubic-bezier(0.16, 1, 0.3, 1);
  will-change: opacity, transform;
}
.reveal.is-armed { opacity: 0; transform: translateY(18px); }
@media (prefers-reduced-motion: reduce) {
  .reveal, .reveal.is-armed { opacity: 1; transform: none; transition: none; }}

/* ── Page home (vitrine) ────────────────────────────────────────────── */
.page-home { background: var(--bg); }
.home { width: 100%; }

.home-hero {
  position: relative;
  min-height: 100vh;
  min-height: 100dvh;
  display: flex;
  align-items: center;
  justify-content: center;
  padding: 120px 32px 100px;
}
.home-hero-inner {
  width: 100%;
  max-width: 880px;
  text-align: center;
  display: flex;
  flex-direction: column;
  align-items: center;
}
.home-hero .hero-eyebrow { margin-bottom: 26px; }
.home-hero-title {
  font-family: var(--font-display);
  font-size: clamp(44px, 7.5vw, 104px);
  font-weight: 600;
  letter-spacing: -0.045em;
  line-height: 0.95;
  margin: 0;
  color: var(--fg);
  text-wrap: balance;
}
.home-hero-lead {
  font-size: clamp(17px, 2vw, 21px);
  color: var(--muted);
  margin: 26px auto 0;
  max-width: 620px;
  line-height: 1.5;
  letter-spacing: -0.005em;
  text-wrap: pretty;
}
.home-hero-cta {
  display: flex;
  gap: 14px;
  flex-wrap: wrap;
  justify-content: center;
  margin-top: 40px;
}
.home-hero .scroll-cue {
  pointer-events: auto;
  cursor: pointer;
  text-decoration: none;
  color: var(--muted-3);
}
.home-hero .scroll-cue:hover { color: var(--fg); }

/* ── Hero animé « Trait » (home) ─────────────────────────────────────────
   Entrée cinétique au chargement (mots du titre en cascade : montée + fondu
   + déflou) + survol « Trait » (soulignement azur qui se déploie de gauche à
   droite, le mot passe en azur, interlettrage légèrement élargi). 100 % CSS,
   aucune dépendance JS. */
.home-hero-title .hero-line { display: block; }
.home-hero-title .ab-word {
  display: inline-block;
  position: relative;
  cursor: default;
  transition: color 0.30s ease;
}

@keyframes ab-up {
  from { opacity: 0; transform: translateY(0.45em); filter: blur(7px); }
  to   { opacity: 1; transform: none;               filter: blur(0); }}
@keyframes ab-fade { from { opacity: 0; } to { opacity: 1; }}

/* Entrée : montée + fondu + déflou (cascade par mot).
   fill-mode « backwards » (et non « both ») : l'état initial s'applique pendant
   le délai (pas de flash), mais après l'animation le mot revient à son style
   naturel — SANS « filter: blur(0) » résiduel. Un filter persistant garde le
   texte sur une couche GPU et le rend flou sur mobile (Retina / forte densité). */
.home-hero-title .ab-word { animation: ab-up 0.65s cubic-bezier(0.34, 1.4, 0.64, 1) backwards; }
.home-hero-title .hero-line:nth-child(1) .ab-word:nth-child(1) { animation-delay: 0.12s; }
.home-hero-title .hero-line:nth-child(1) .ab-word:nth-child(2) { animation-delay: 0.18s; }
.home-hero-title .hero-line:nth-child(2) .ab-word:nth-child(1) { animation-delay: 0.26s; }
.home-hero-title .hero-line:nth-child(2) .ab-word:nth-child(2) { animation-delay: 0.32s; }
.home-hero-title .hero-line:nth-child(3) .ab-word:nth-child(1) { animation-delay: 0.42s; }
.home-hero-title .hero-line:nth-child(3) .ab-word:nth-child(2) { animation-delay: 0.48s; }
.home-hero-title .hero-line:nth-child(3) .ab-word:nth-child(3) { animation-delay: 0.54s; }

.home-hero .hero-eyebrow { animation: ab-up 0.7s cubic-bezier(0.34, 1.4, 0.64, 1) backwards 0s; }
.home-hero-lead          { animation: ab-up 0.7s cubic-bezier(0.34, 1.4, 0.64, 1) backwards 0.60s; }
.home-hero-cta           { animation: ab-up 0.7s cubic-bezier(0.34, 1.4, 0.64, 1) backwards 0.72s; }
.home-hero .scroll-cue   { animation: ab-fade 0.7s cubic-bezier(0.4, 0, 0.2, 1) backwards 0.95s; }

/* Survol « Trait » — soulignement azur qui se déploie */
.home-hero-title .ab-word::after {
  content: "";
  position: absolute;
  left: 0;
  right: 100%;          /* largeur nulle au repos */
  bottom: -0.02em;
  height: 0.055em;
  background: var(--accent-azur);
  transition: right 0.45s cubic-bezier(0.4, 0, 0.2, 1);
}
.home-hero-title .ab-word:hover        { color: var(--accent-azur); }
.home-hero-title .ab-word:hover::after { right: 0; }   /* le trait se déploie vers la droite (aucun reflow) */

@media (prefers-reduced-motion: reduce) {
  .home-hero-title .ab-word,
  .home-hero .hero-eyebrow,
  .home-hero-lead,
  .home-hero-cta,
  .home-hero .scroll-cue { animation: none; }
  .home-hero-title .ab-word,
  .home-hero-title .ab-word::after { transition: none; }
}

/* ── Sections génériques de la home ─────────────────────────────────── */
.home-section {
  max-width: 1080px;
  margin: 0 auto;
  padding: 96px 32px;
}
.section-head { max-width: 640px; margin: 0 0 44px; }
.section-head.reveal { /* hook for transition */ }
.section-title {
  font-family: var(--font-display);
  font-size: clamp(32px, 5vw, 56px);
  font-weight: 600;
  letter-spacing: -0.04em;
  line-height: 0.98;
  margin: 14px 0 0;
  color: var(--fg);
}
.section-sub {
  font-size: 18px;
  color: var(--muted);
  margin: 16px 0 0;
  line-height: 1.5;
  text-wrap: pretty;
}
.section-more {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  justify-content: center;
  gap: 14px 22px;
  margin-top: 44px;
}

/* ── Apps « à la une » ──────────────────────────────────────────────── */
/* Mêmes tuiles « bento » que la page /apps (cf. section « Page /apps »
   plus haut) pour une cohérence graphique : aplat d'accent, glyphe en
   filigrane, halo + trame de points. Variante `.tile--home` = satellite
   (jamais `.tile--featured`) avec une hauteur mini et le pied collé en bas. */
.featured-grid {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 18px;
}
.featured-grid .app-cell { position: relative; }
/* L'indice du rail n'existe que sur téléphone (cf. le bloc ≤ 700 px). */
.featured-hint { display: none; }
.tile--home { min-height: 236px; border-radius: 22px; }
.tile--home .tile-bar { margin-top: auto; }
.tile--home .tile-tagline--sm { -webkit-line-clamp: 2; flex: none; }

/* Lien « démo » admin flottant sur la tuile colorée (au-dessus de l'aplat) */
.tile-demo {
  position: absolute; top: 16px; right: 16px; z-index: 2;
  font-family: var(--font-mono);
  font-size: 9px; letter-spacing: 0.1em; text-transform: uppercase;
  color: #fff; text-decoration: none;
  background: rgba(0, 0, 0, 0.28);
  border: 1px solid rgba(255, 255, 255, 0.30);
  border-radius: 999px; padding: 4px 10px;
  transition: background 160ms ease, border-color 160ms ease;
}
.tile-demo:hover { background: rgba(0, 0, 0, 0.45); border-color: rgba(255, 255, 255, 0.55); }
.about-contact {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
  margin-top: 28px;
}

/* ── Section SEO (prose) + FAQ ──────────────────────────────────────── */
.home-faq { border-top: 1px solid var(--line-soft); }

.faq-list {
  max-width: 760px;
  border-top: 1px solid var(--line-soft);
}
.faq-item {
  border-bottom: 1px solid var(--line-soft);
}
.faq-q {
  list-style: none;
  cursor: pointer;
  padding: 20px 36px 20px 0;
  position: relative;
  font-family: var(--font-display);
  font-size: clamp(17px, 2.2vw, 21px);
  font-weight: 600;
  letter-spacing: -0.01em;
  color: var(--fg);
}
.faq-q::-webkit-details-marker { display: none; }
.faq-q::after {
  content: "+";
  position: absolute;
  right: 4px;
  top: 50%;
  transform: translateY(-50%);
  font-size: 24px;
  font-weight: 400;
  color: var(--muted-2);
  transition: transform 200ms ease;
}
.faq-item[open] .faq-q::after { transform: translateY(-50%) rotate(45deg); }
.faq-a {
  margin: 0;
  padding: 0 36px 22px 0;
  font-size: 16px;
  line-height: 1.6;
  color: var(--muted);
  text-wrap: pretty;
}

/* ── Footer riche (multi-pages) ─────────────────────────────────────── */
.site-footer {
  border-top: 1px solid var(--line);
  background: var(--paper);
  padding: 64px 32px 32px;
}
.site-footer-inner {
  max-width: 1180px;
  margin: 0 auto;
  display: grid;
  /* Marque + les trois piliers · Le studio · Contact. */
  grid-template-columns: 1.2fr repeat(5, 1fr);
  gap: 36px;
}
.site-footer-brand p { margin: 12px 0 14px; max-width: 320px; }
.site-footer-mail {
  font-family: var(--font-mono);
  font-size: 12px;
  color: var(--muted-3);
  text-decoration: none;
  letter-spacing: 0.02em;
}
.site-footer-mail:hover { color: var(--fg); }
.site-footer-cols { display: contents; }
.footer-col { display: flex; flex-direction: column; gap: 10px; }
.footer-col-h {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted-3);
  margin-bottom: 2px;
}
.footer-col a {
  font-size: 14px;
  color: var(--muted);
  text-decoration: none;
  transition: color 150ms ease;
}
.footer-col a:hover { color: var(--fg); }
.site-footer-base {
  max-width: 1080px;
  margin: 48px auto 0;
  padding-top: 22px;
  border-top: 1px solid var(--line-soft);
  display: flex;
  justify-content: space-between;
  gap: 12px;
  flex-wrap: wrap;
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.04em;
  color: var(--muted-3);
}
.site-footer-legal { display: flex; gap: 6px 18px; flex-wrap: wrap; order: 5; flex: 1 0 100%; }
.site-footer-legal a,
.site-footer-admin {
  color: var(--muted-3);
  text-decoration: none;
  transition: color 0.15s ease;
}
.site-footer-legal a:hover,
.site-footer-admin:hover { color: var(--fg); }

/* ── Page contact / devis ───────────────────────────────────────────── */
.page-contact { background: var(--bg); min-height: 100vh; }
.contact-wrap {
  max-width: 680px;
  margin: 0 auto;
  padding: 128px 24px 96px;
}
.contact-head { text-align: center; margin-bottom: 36px; }
.contact-head .hero-eyebrow { display: block; margin-bottom: 16px; }
.contact-title {
  font-family: var(--font-display);
  font-size: clamp(38px, 6vw, 68px);
  font-weight: 600;
  letter-spacing: -0.04em;
  line-height: 0.98;
  margin: 0 0 18px;
  color: var(--fg);
  text-wrap: balance;
}
.contact-lead {
  font-size: 18px;
  color: var(--muted);
  line-height: 1.55;
  margin: 0 auto;
  max-width: 520px;
  text-wrap: pretty;
}
.contact-form {
  display: flex;
  flex-direction: column;
  gap: 18px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 18px;
  padding: 28px 28px 24px;
  box-shadow: 0 20px 60px -30px rgba(0, 0, 0, 0.18);
}
.field { display: grid; gap: 7px; }
/* Le sujet se choisit à l'écran : pastilles à cocher, cibles de 44 px. */
.contact-subject { border: 0; padding: 0; margin: 0; min-width: 0; }
.contact-subject legend { padding: 0; }
.contact-subject-opts { display: flex; flex-wrap: wrap; gap: 8px 10px; margin-top: 8px; }
.contact-subject-opts label {
  display: inline-flex; align-items: center; gap: 9px; min-height: 44px;
  padding: 0 15px; border: 1px solid var(--line-strong); border-radius: 999px;
  background: var(--card); font-size: 14px; color: var(--fg-soft); cursor: pointer;
}
.contact-subject-opts label:has(input:checked) { border-color: var(--fg); color: var(--fg); }
.contact-subject-opts input { accent-color: var(--fg); margin: 0; }
/* Confirmation commune (POST natif et <template> clonée par contact.js). */
.contact-done { text-align: left; padding: 16px 18px; border-radius: 14px; }
.contact-done p { margin: 0; }
.contact-done p + p { margin-top: 8px; }
.contact-done a { color: inherit; text-decoration: underline; text-underline-offset: 3px; }
.field-label {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.18em;
  text-transform: uppercase;
  color: var(--muted-3);
}
.contact-form input[type="email"],
.contact-form input[type="text"],
.contact-form input[type="tel"],
.contact-form textarea {
  background: var(--paper);
  color: var(--fg);
  border: 1px solid var(--line);
  border-radius: 10px;
  padding: 12px 14px;
  font-family: var(--font-body);
  font-size: 15px;
  outline: none;
  transition: border-color 150ms ease, background 150ms ease;
  width: 100%;
}
.contact-form textarea { resize: vertical; min-height: 130px; line-height: 1.5; }
.contact-form input:focus,
.contact-form textarea:focus {
  border-color: var(--fg);
  background: var(--card);
}
/* Anneau de focus clavier visible sur les champs (audit L14) — :focus-visible
   n'apparaît pas au clic souris, seulement au clavier. */
.contact-form input:focus-visible,
.contact-form textarea:focus-visible,
.login-card input:focus-visible {
  outline: 2px solid var(--accent);
  outline-offset: 2px;
}
.contact-actions {
  display: flex;
  align-items: center;
  gap: 18px;
  flex-wrap: wrap;
  margin-top: 4px;
}
.form-note { margin: 4px 0 0; }
.form-note a { color: var(--muted); text-decoration: underline; text-decoration-color: var(--line-strong); }
.form-note a:hover { color: var(--fg); }

/* Honeypot anti-bot : invisible pour les humains, hors flux. */
.hp-field {
  position: absolute !important;
  left: -9999px !important;
  width: 1px; height: 1px;
  overflow: hidden;
}

/* Statut de soumission (succès / erreur) */
.form-status {
  margin: 0;
  font-size: 14px;
  min-height: 1.2em;
}
.form-status.is-ok {
  color: #15803d;
  background: rgba(21, 128, 61, 0.08);
  border: 1px solid rgba(21, 128, 61, 0.22);
  border-radius: 10px;
  padding: 12px 14px;
}

/* ── Pages légales ──────────────────────────────────────────────────── */
.page-legal { background: var(--bg); min-height: 100vh; }
.legal-wrap {
  max-width: 760px;
  margin: 0 auto;
  padding: 128px 24px 88px;
}
.legal-wrap .hero-eyebrow { display: block; margin-bottom: 14px; }
.legal-title {
  font-family: var(--font-display);
  font-size: clamp(34px, 5vw, 56px);
  font-weight: 600;
  letter-spacing: -0.04em;
  line-height: 0.98;
  margin: 0 0 8px;
  color: var(--fg);
}
.legal-intro {
  font-size: 18px;
  color: var(--fg-soft);
  line-height: 1.6;
  margin: 24px 0 8px;
  text-wrap: pretty;
}
.legal-section { margin-top: 30px; }
.legal-section h2 {
  font-family: var(--font-display);
  font-size: 20px;
  font-weight: 600;
  letter-spacing: -0.015em;
  margin: 0 0 10px;
  color: var(--fg);
}
.legal-section p {
  margin: 0;
  font-size: 15.5px;
  line-height: 1.65;
  color: var(--muted);
}
.legal-section p em { color: var(--muted-3); font-style: italic; }
/* Liste des sous-traitants techniques (page confidentialité) : même encre et
   même rythme que les paragraphes voisins, la puce reste discrète. */
.legal-list {
  margin: 12px 0 0;
  padding-left: 20px;
  font-size: 15.5px;
  line-height: 1.65;
  color: var(--muted);
}
.legal-list li { margin-bottom: 10px; }
.legal-list li:last-child { margin-bottom: 0; }
.legal-list strong { color: var(--fg-soft); font-weight: 600; }
.legal-list + p { margin-top: 14px; }
/* Un nom de domaine ne doit pas se couper en deux lignes. */
.legal-nowrap { white-space: nowrap; }
.legal-section a, .legal-intro a { color: var(--fg); text-decoration: underline; text-decoration-color: var(--line-strong); }
.legal-back { margin-top: 44px; }

/* ── Dark mode (composants vitrine) ─────────────────────────────────── */
[data-theme="dark"] .form-status.is-ok { color: #4ade80; background: rgba(74,222,128,0.08); border-color: rgba(74,222,128,0.22); }

/* ── Responsive (vitrine) ───────────────────────────────────────────── */
@media (max-width: 880px) {
  .home-section { padding: 72px 24px; }
  .site-footer-inner { grid-template-columns: 1fr 1fr; gap: 32px; }
  .site-footer-brand { grid-column: 1 / -1; }
}
@media (min-width: 881px) and (max-width: 1100px) {
  .site-footer-inner { grid-template-columns: repeat(3, 1fr); }
  .site-footer-brand { grid-column: 1 / -1; }
}
@media (max-width: 640px) {
  .home-hero { padding: 104px 22px 72px; min-height: 90svh; }
  .home-hero-cta { width: 100%; }
  .home-hero-cta .btn-lg { width: 100%; }
  .home-section { padding: 60px 20px; }
  .section-head { margin-bottom: 32px; }
  .featured-grid { grid-template-columns: 1fr; }
  .contact-wrap { padding: 100px 18px 72px; }
  .contact-form { padding: 22px 18px; }
  .contact-actions .btn-lg { width: 100%; }
  .legal-wrap { padding: 100px 18px 64px; }
  .site-footer { padding: 48px 20px 28px; }
  .site-footer-inner { grid-template-columns: 1fr; gap: 26px; }
  .site-footer-base { flex-direction: column; gap: 6px; }}

/* ── Page publique : acceptation de devis (« Bon pour accord ») ──────────── */
.page-devis { background: var(--bg); min-height: 100vh; }
.devis-wrap { max-width: 760px; margin: 0 auto; padding: 120px 24px 96px; }
.devis-head { text-align: center; margin-bottom: 32px; }
.devis-head .hero-eyebrow { display: block; margin-bottom: 14px; }
.devis-title { font-family: var(--font-display); font-size: clamp(28px, 5vw, 44px); margin: 0 0 12px; color: var(--fg); }
.devis-lead { color: var(--muted); font-size: 16px; }
.devis-card {
  background: var(--card); border: 1px solid var(--line); border-radius: 18px;
  padding: 28px; box-shadow: 0 20px 60px -30px rgba(0,0,0,0.18); margin-bottom: 24px;
}
.devis-parties { display: grid; grid-template-columns: 1fr 1fr; gap: 24px; margin-bottom: 24px; }
.devis-lbl { font-family: var(--font-mono); font-size: 10px; letter-spacing: .08em; text-transform: uppercase; color: var(--muted); margin-bottom: 6px; }
.devis-strong { font-weight: 600; color: var(--fg); }
.devis-table { width: 100%; border-collapse: collapse; margin: 8px 0 20px; font-size: 15px; }
.devis-table th { text-align: left; font-family: var(--font-mono); font-size: 10px; letter-spacing: .06em; text-transform: uppercase; color: var(--muted); border-bottom: 1px solid var(--line-strong); padding: 8px 10px; }
.devis-table td { padding: 10px; border-bottom: 1px solid var(--line-soft); color: var(--fg); }
.devis-table .num { text-align: right; white-space: nowrap; }
.devis-totals { margin-left: auto; max-width: 320px; }
.devis-totals .row { display: flex; justify-content: space-between; padding: 6px 0; color: var(--fg-soft); }
.devis-totals .grand { border-top: 1px solid var(--line-strong); margin-top: 6px; padding-top: 12px; font-size: 18px; font-weight: 700; color: var(--fg); }
.devis-tva { margin-top: 10px; }
.devis-block { margin-top: 20px; }
.devis-block p { margin: 4px 0 0; color: var(--fg-soft); line-height: 1.5; }
.prewrap { white-space: pre-wrap; }
.devis-accept, .devis-accepted {
  background: var(--card); border: 1px solid var(--line); border-radius: 18px; padding: 28px;
}
.devis-accept h2, .devis-accepted h2 { margin: 0 0 10px; font-size: 20px; color: var(--fg); }
.devis-accepted { border-color: rgba(22,163,74,0.4); }
.devis-form { display: flex; flex-direction: column; gap: 16px; margin-top: 16px; }
.devis-waiver {
  display: flex; gap: 10px; align-items: flex-start; cursor: pointer;
  padding: 14px 16px; border: 1px solid var(--line); border-radius: 12px;
  color: var(--fg-soft); font-size: 13px; line-height: 1.5;
}
.devis-waiver input {
  flex: 0 0 auto; width: 16px; height: 16px; margin: 2px 0 0;
  accent-color: var(--accent, #2563eb);
}
.devis-waiver:focus-within { border-color: var(--line-strong); }
/* Sortie pour qui garde ses quatorze jours : sous la case, lisible (pas de
   petites lettres grises), le gap du formulaire suffit à l'espacer. */
.devis-waiver-alt {
  margin: -6px 2px 0; font-size: 13px; line-height: 1.6; color: var(--fg-soft);
}
@media (max-width: 560px) {
  .devis-parties { grid-template-columns: 1fr; }
  .devis-totals { max-width: none; }
  .devis-form .btn-lg { width: 100%; }}

/* ── Pastille d'action de la barre de navigation ─────────────────────────── */
/* Sélecteur porté par `.topbar-nav` : sans lui, `.topbar-nav a { color }`
   (deux composantes) l'emporterait et la pastille resterait grise sur noir. */
.topbar-nav a.topbar-cta {
  display: inline-flex; align-items: center;
  padding: 8px 15px;
  border-radius: 999px;
  background: var(--fg); color: var(--bg);
  font-size: 13px; font-weight: 600; letter-spacing: -0.008em;
  text-decoration: none;
  transition: transform 180ms ease, opacity 200ms ease;
}
.topbar-nav a.topbar-cta:hover { transform: translateY(-1px); opacity: 0.9; color: var(--bg); }
.topbar-nav a.topbar-cta.is-active { opacity: 0.78; color: var(--bg); }

/* ── Réalisations clients (sites) — distinctes du catalogue d'apps ───────── */
.home-works { border-top: 1px solid var(--line-soft); }

/* ── Déroulé « comment ça se passe » (étapes) ────────────────────────────── */
.home-method { border-top: 1px solid var(--line-soft); }
.steps {
  list-style: none; margin: 0; padding: 0;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 16px;
}
.step {
  display: flex; gap: 16px; align-items: flex-start;
  border: 1px solid var(--line);
  border-radius: 18px; background: var(--card);
  padding: 22px 22px 22px 20px;
  transition: border-color 180ms ease, box-shadow 240ms ease, transform 240ms ease;
}
.step:hover {
  border-color: var(--line-strong);
  box-shadow: 0 20px 40px -28px rgba(0, 0, 0, 0.2);
  transform: translateY(-2px);
}
.step--highlight { border-color: var(--fg); }
.step-num {
  flex: none;
  width: 34px; height: 34px; border-radius: 10px;
  display: grid; place-items: center;
  font-family: var(--font-mono); font-size: 14px; font-weight: 600;
  color: var(--on-accent); background: var(--fg);
}
.step-body h3 {
  font-family: var(--font-display);
  font-size: 18px; font-weight: 600; letter-spacing: -0.01em;
  margin: 4px 0 6px; color: var(--fg);
}
.step-body p { margin: 0; font-size: 14.5px; line-height: 1.55; color: var(--muted); }
.step-body strong { color: var(--fg-soft); font-weight: 600; }
.step-body a { color: var(--fg); text-decoration: underline; text-underline-offset: 2px; }

/* ── Page « Création de site » : hero, inclus, suivi, CTA final ───────────── */
.offre-hero {
  max-width: 900px; margin: 0 auto;
  padding: 150px 32px 40px; text-align: center;
}
.offre-hero-title {
  font-family: var(--font-display);
  font-size: clamp(34px, 6vw, 64px);
  font-weight: 600; letter-spacing: -0.04em; line-height: 1.0;
  margin: 16px 0 0; color: var(--fg); text-wrap: balance;
}
.offre-hero-lead {
  font-size: clamp(17px, 2.4vw, 21px); line-height: 1.55;
  color: var(--muted); margin: 22px auto 0; max-width: 660px; text-wrap: pretty;
}
.offre-hero-lead strong { color: var(--fg-soft); font-weight: 600; }
/* Le prix d'entrée dès le hero, amené par « à partir de ». */
.offre-hero-price { font-size: 16px; color: var(--fg-soft); margin: 4px 0 20px; }
.offre-hero-price strong { font-weight: 600; color: var(--fg); }
.offre-hero .home-hero-cta { justify-content: center; margin-top: 30px; }
.offre-hero-note {
  font-family: var(--font-mono);
  font-size: 11px; letter-spacing: 0.04em; color: var(--muted-3); margin: 18px 0 0;
}

.included-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 16px;
}
.included-item {
  border: 1px solid var(--line); border-radius: 18px;
  background: var(--card); padding: 26px 24px 26px;
  transition: border-color 180ms ease, transform 240ms ease;
}
.included-item:hover { border-color: var(--line-strong); transform: translateY(-2px); }
.included-item--star { border-color: var(--fg); }
.included-ico {
  width: 40px; height: 40px; border-radius: 11px;
  display: grid; place-items: center;
  font-size: 19px; color: var(--fg);
  border: 1px solid var(--line-strong);
}
.included-item--star .included-ico { color: var(--on-accent); background: var(--fg); border-color: var(--fg); }
.included-item h3 {
  font-family: var(--font-display);
  font-size: 19px; font-weight: 600; letter-spacing: -0.02em;
  margin: 16px 0 8px; color: var(--fg);
}
.included-item p { margin: 0; font-size: 14.5px; line-height: 1.55; color: var(--muted); }
.included-item strong { color: var(--fg-soft); font-weight: 600; }

/* Rangée de pastilles de navigation, un seul composant pour trois usages (métiers, /creation-site, Réalisations). Cibles 44 px. */
.metier-autres, .rea-jump {
  display: flex; flex-wrap: wrap; gap: 10px; justify-content: center;
  max-width: 860px; margin: 0 auto;
}
/* Le sommaire suit le chapô de son hero, jamais collé dessous. */
.rea-jump { margin-top: 24px; }
.metier-autres a, .rea-jump a {
  display: inline-flex; align-items: center; min-height: 44px;
  padding: 6px 18px; border: 1px solid var(--line-strong);
  border-radius: 999px; background: var(--card); color: var(--fg-soft);
  font-size: 14px; text-decoration: none;
  transition: border-color 180ms ease, color 180ms ease;
}
.metier-autres a:hover, .rea-jump a:hover { border-color: var(--fg); color: var(--fg); }

.home-suivi { border-top: 1px solid var(--line-soft); }
.suivi-card {
  display: grid; grid-template-columns: minmax(0, 0.9fr) minmax(0, 1.1fr);
  gap: 40px; align-items: center;
}
.suivi-card--seule { grid-template-columns: minmax(0, 1fr); max-width: 640px; }
.suivi-text h2 { margin: 10px 0 0; }
.suivi-text > p {
  font-size: 17px; line-height: 1.6; color: var(--muted); margin: 18px 0 0; text-wrap: pretty;
}
.suivi-text strong { color: var(--fg); font-weight: 600; }
.suivi-points {
  list-style: none; margin: 20px 0 26px; padding: 0;
  display: flex; flex-direction: column; gap: 8px;
  color: var(--muted); font-size: 15px;
}
.suivi-points li::before {
  content: ""; display: inline-block; width: 0.8em; height: 0.8em;
  margin-right: 9px; vertical-align: -0.05em;
  background-color: var(--fg);
  -webkit-mask: var(--icon-check) center / contain no-repeat;
  mask: var(--icon-check) center / contain no-repeat;
}
/* La capture du vrai portail client (tools/capture_portail_demo.py). */
.suivi-shot { margin: 0; min-width: 0; }
.suivi-shot-frame {
  border: 1px solid var(--line-strong); border-radius: 16px; overflow: hidden;
  background: var(--card); box-shadow: 0 30px 60px -34px rgba(0, 0, 0, 0.32);
}
.suivi-shot-bar { display: flex; gap: 6px; padding: 10px 12px; background: var(--paper); border-bottom: 1px solid var(--line-soft); }
.suivi-shot-bar i { width: 9px; height: 9px; border-radius: 50%; background: var(--line-strong); }
.suivi-shot picture, .suivi-shot-img { display: block; width: 100%; height: auto; }
.suivi-shot figcaption { margin-top: 12px; font-size: 13px; line-height: 1.5; color: var(--muted-3); }

.home-cta-final { border-top: 1px solid var(--line-soft); text-align: center; }
.cta-final { max-width: 640px; margin: 0 auto; }
.cta-final > p { font-size: 18px; color: var(--muted); margin: 16px 0 0; }
.cta-final .home-hero-cta { justify-content: center; margin-top: 28px; }

@media (max-width: 880px) {
  .suivi-card { grid-template-columns: minmax(0, 1fr); gap: 28px; }}
@media (max-width: 640px) {
  .offre-hero { padding: 120px 22px 24px; }
  .steps, .included-grid { grid-template-columns: 1fr; }}

/* ==========================================================================
   MOTION SIGNATURE & DÉ-GÉNÉRICISAGE (refonte 2026)
   Direction « minimal + motion » : on garde la base warm-minimal mais on
   casse le look « tout-en-cartes » et on ajoute un motion mémorable et rare.
   Tout est dégradable : sans JS le contenu reste visible ; en reduced-motion
   toutes les animations tombent.
   ========================================================================== */

:root { --ease-out-expo: cubic-bezier(0.16, 1, 0.3, 1); }

/* ── Section markers : n° indexé (azur) + trait qui se dessine ──────────── */
.page-home .home { counter-reset: sec; }
.page-home .home-section { counter-increment: sec; }
.section-head .hero-eyebrow {
  display: inline-flex;
  align-items: center;
  gap: 12px;
  position: relative;
}
.page-home .section-head .hero-eyebrow::before {
  content: counter(sec, decimal-leading-zero);
  color: var(--accent-azur);
  font-weight: 500;
}
.section-head .hero-eyebrow::after {
  content: "";
  width: 34px;
  height: 1.5px;
  background: var(--accent-azur);
  transform: scaleX(1);
  transform-origin: left center;
  transition: transform 0.7s var(--ease-out-expo) 0.1s;
}
.section-head.reveal.is-armed .hero-eyebrow::after { transform: scaleX(0); }

/* ── Reveal choreographié : le bloc-titre ne glisse plus en masse ; chaque
     élément (eyebrow / titre / sous-titre) entre séparément. ────────────── */
.section-head.reveal.is-armed { opacity: 1; transform: none; }
.section-head .hero-eyebrow,
.section-head .section-sub {
  transition: opacity 0.34s var(--ease-out-expo), transform 0.34s var(--ease-out-expo);
}
.section-head .section-sub { transition-delay: 0.09s; }
.section-head.reveal.is-armed .hero-eyebrow { opacity: 0; transform: translateY(10px); }
.section-head.reveal.is-armed .section-sub  { opacity: 0; transform: translateY(12px); }
/* Titre : révélation par « essuyage » vertical (clip-path) — signature. */
.section-head .section-title {
  transition: clip-path 0.42s var(--ease-out-expo) 0.04s, opacity 0.36s var(--ease-out-expo) 0.04s;
  /* Le clip-path se calcule sur la boîte de bordure : sans marge basse, l'essuyage
     rogne le bas des lettres à descendantes (« votre projet. », « réponses. »).
     On ajoute du padding et on le reprend en marge négative → zéro décalage. */
  clip-path: inset(0 0 -25% 0);
  padding-bottom: 0.18em;
  margin-bottom: -0.18em;
  overflow: visible;
}
.section-head.reveal.is-armed .section-title { clip-path: inset(0 0 110% 0); opacity: 0; }

/* ── Reveal en cascade (containers [data-reveal-stagger]) ───────────────── */
.reveal[data-reveal-stagger].is-armed { opacity: 1; transform: none; }
.reveal[data-reveal-stagger] > * {
  transition: opacity 0.34s var(--ease-out-expo), transform 0.34s var(--ease-out-expo);
  transition-delay: calc(var(--i, 0) * 45ms);
}
.reveal[data-reveal-stagger].is-armed > * { opacity: 0; transform: translateY(20px); }

@media (prefers-reduced-motion: reduce) {
  .section-head .section-title,
  .section-head.reveal.is-armed .section-title { clip-path: none; opacity: 1; }
  .section-head .hero-eyebrow::after,
  .section-head.reveal.is-armed .hero-eyebrow::after { transition: none; transform: scaleX(1); }
  .reveal[data-reveal-stagger] > *,
  .reveal[data-reveal-stagger].is-armed > * { opacity: 1; transform: none; transition: none; }}
.home-hero-inner { position: relative; z-index: 1; }
@keyframes aura-drift {
  from { transform: translate(-54%, -52%) scale(0.95); }
  to   { transform: translate(-46%, -48%) scale(1.08); }}

/* ── Marquee cinétique ──────────────────────────────────────────────────── */
.marquee {
  overflow: hidden;
  border-top: 1px solid var(--line-soft);
  border-bottom: 1px solid var(--line-soft);
  background: var(--paper);
  padding: 15px 0;
  -webkit-mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
  mask-image: linear-gradient(90deg, transparent, #000 8%, #000 92%, transparent);
}
@keyframes marquee { to { transform: translateX(-50%); }}
@media (prefers-reduced-motion: reduce) {
  .marquee { -webkit-mask-image: none; mask-image: none; overflow-x: auto; }}
.work-row { border-bottom: 1px solid var(--line); position: relative; }
.work-row::before {
  content: "";
  position: absolute;
  inset: 0;
  z-index: -1;
  background: color-mix(in oklab, var(--accent) 9%, transparent);
  opacity: 0;
  transition: opacity 0.4s ease;
}
.work-row:hover::before { opacity: 1; }

/* ── Méthode condensée (3 temps) ────────────────────────────────────────── */
.method-strip {
  list-style: none;
  margin: 0;
  padding: 0;
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  border: 1px solid var(--line);
  border-radius: 22px;
  overflow: hidden;
  background: var(--card);
}
.mstep {
  padding: 30px 28px 34px;
  border-right: 1px solid var(--line);
  position: relative;
}
.mstep:last-child { border-right: 0; }
.mstep-num {
  display: inline-grid;
  place-items: center;
  width: 32px; height: 32px;
  border-radius: 50%;
  border: 1.5px solid var(--fg);
  font-family: var(--font-mono);
  font-size: 13px;
  font-weight: 500;
  color: var(--fg);
  margin-bottom: 16px;
}
.mstep h3 {
  font-family: var(--font-display);
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0 0 8px;
  color: var(--fg);
}
.mstep p { margin: 0; font-size: 14.5px; line-height: 1.55; color: var(--muted); }
.mstep p a { color: var(--fg); text-decoration: underline; text-underline-offset: 2px; }
.mstep strong { color: var(--fg-soft); font-weight: 600; }
.mstep--highlight { background: color-mix(in oklab, var(--accent-azur) 6%, var(--card)); }
.mstep--highlight .mstep-num { border-color: var(--accent-azur); color: var(--accent-azur); }
@media (max-width: 760px) {
  .method-strip { grid-template-columns: 1fr; }
  .mstep { border-right: 0; border-bottom: 1px solid var(--line); }
  .mstep:last-child { border-bottom: 0; }}

/* ── Studio (fusion à-propos / approche / piliers) ──────────────────────── */
.home-studio { border-top: 1px solid var(--line-soft); }
.studio-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 60px;
  align-items: start;
}
.studio-lead {
  font-size: clamp(18px, 2.1vw, 22px);
  line-height: 1.5;
  color: var(--fg-soft);
  margin: 26px 0 0;
  text-wrap: pretty;
}
.studio-lead strong { color: var(--fg); font-weight: 600; }
.studio-founder { font-size: 16px; line-height: 1.65; color: var(--muted); margin: 20px 0 0; text-wrap: pretty; }
.studio-founder strong { color: var(--fg); font-weight: 600; }
.studio-intro .about-contact { margin-top: 28px; }
.studio-pillars { list-style: none; margin: 0; padding: 0; }
.pillar {
  display: grid;
  grid-template-columns: auto 1fr;
  gap: 2px 20px;
  padding: 22px 0;
  border-top: 1px solid var(--line);
}
.pillar:first-child { border-top: 0; padding-top: 4px; }
.pillar-num {
  grid-row: span 2;
  font-family: var(--font-mono);
  font-size: 12px;
  letter-spacing: 0.1em;
  color: var(--accent-azur);
  padding-top: 4px;
}
.pillar h3 {
  font-family: var(--font-display);
  font-size: 19px;
  font-weight: 600;
  letter-spacing: -0.02em;
  margin: 0;
  color: var(--fg);
}
.pillar p { margin: 5px 0 0; font-size: 14.5px; line-height: 1.55; color: var(--muted); }
@media (max-width: 820px) {
  .studio-grid { grid-template-columns: 1fr; gap: 32px; }}

/* ── Curseur signature (desktop, pointeur fin, hors reduced-motion) ──────── */
.cursor-dot, .cursor-ring {
  position: fixed;
  top: 0; left: 0;
  border-radius: 50%;
  pointer-events: none;
  z-index: 9999;
  transform: translate(-50%, -50%);
  mix-blend-mode: difference;
  will-change: transform;
  opacity: 0;
  transition: opacity 0.3s ease;
}
.cursor-dot { width: 7px; height: 7px; background: #fff; }
.cursor-ring {
  width: 34px; height: 34px;
  border: 1.4px solid #fff;
  z-index: 9998;
  transition: width 0.28s var(--ease-out-expo), height 0.28s var(--ease-out-expo),
              background 0.28s ease, opacity 0.3s ease;
}
.cursor-ring.is-hover { width: 56px; height: 56px; background: rgba(255,255,255,0.06); }
.cursor-dot.is-hover { opacity: 0; }
html.has-cursor.ready .cursor-dot,
html.has-cursor.ready .cursor-ring { opacity: 1; }
html.has-cursor, html.has-cursor a, html.has-cursor button,
html.has-cursor [data-magnetic], html.has-cursor summary, html.has-cursor .work-row { cursor: none; }
html.has-cursor input, html.has-cursor textarea, html.has-cursor select,
html.has-cursor [contenteditable] { cursor: auto; }

/* ── Boutons magnétiques ────────────────────────────────────────────────── */
[data-magnetic] { transition: transform 0.3s var(--ease-out-expo), background 0.2s ease, color 0.2s ease, border-color 0.2s ease, box-shadow 0.22s ease; }
@media (prefers-reduced-motion: reduce) { [data-magnetic] { transition: background 0.2s ease; }}

/* ==========================================================================
   RÉALISATIONS — galerie « maquettes 3D » (captures réelles des sites)
   Navigateur en perspective, alterné G/D, qui se redresse au survol.
   Remplace les glyphes géométriques par du concret (anti « IA made »).
   ========================================================================== */
.works-3d {
  display: flex;
  flex-direction: column;
  gap: 92px;
}
.work3d {
  display: grid;
  grid-template-columns: 1.12fr 0.88fr;
  gap: 52px;
  align-items: center;
  perspective: 1500px;
}
.work3d:nth-child(even) { grid-template-columns: 0.88fr 1.12fr; }
.work3d:nth-child(even) .work3d-visual { order: 2; }
.work3d:nth-child(even) .work3d-body   { order: 1; }

/* ── Maquette navigateur en 3D ── */
.work3d-visual { display: block; text-decoration: none; color: inherit; }
.browser3d {
  display: block;
  border-radius: 15px;
  overflow: hidden;
  background: var(--card);
  border: 1px solid var(--line-strong);
  box-shadow:
    0 42px 80px -34px rgba(0,0,0,0.42),
    0 14px 28px -16px rgba(0,0,0,0.22);
  transform: rotateY(-16deg) rotateX(8deg) rotate(-1deg);
  transform-origin: center;
  transition: transform 0.75s var(--ease-out-expo), box-shadow 0.75s var(--ease-out-expo);
  will-change: transform;
}
.work3d:nth-child(even) .browser3d { transform: rotateY(16deg) rotateX(8deg) rotate(1deg); }
.work3d-visual:hover .browser3d,
.work3d-visual:focus-visible .browser3d,
.work3d:nth-child(even) .work3d-visual:hover .browser3d,
.work3d:nth-child(even) .work3d-visual:focus-visible .browser3d {
  transform: rotateY(0deg) rotateX(0deg) rotate(0deg) scale(1.02);
  box-shadow:
    0 55px 95px -30px rgba(0,0,0,0.46),
    0 18px 34px -16px rgba(0,0,0,0.26);
}
.browser3d-bar {
  display: flex;
  align-items: center;
  gap: 7px;
  padding: 11px 15px;
  background: var(--paper-2);
  border-bottom: 1px solid var(--line);
}
.b-dot { width: 10px; height: 10px; border-radius: 50%; background: var(--line-strong); flex: none; }
.browser3d-url {
  margin-left: 12px;
  font-family: var(--font-mono);
  font-size: 11px;
  color: var(--muted-3);
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 7px;
  padding: 3px 14px;
  max-width: 62%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
.browser3d-screen {
  display: block;
  aspect-ratio: 16 / 10;
  background: var(--paper);
  overflow: hidden;
}
/* <picture> = simple emballage des sources AVIF/WebP : il ne doit pas casser
   la boîte de l'écran (l'img porte la taille). */
.browser3d-screen picture { display: contents; }
.browser3d-screen img {
  width: 100%; height: 100%;
  object-fit: cover;
  object-position: top center;
  display: block;
}
/* Fallback (capture manquante) : cadre neutre teinté accent + glyphe + nom */
.browser3d-ph {
  width: 100%; height: 100%;
  display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 12px;
  background:
    radial-gradient(120% 90% at 50% 0%, color-mix(in oklab, var(--accent) 16%, var(--card)) 0%, var(--card) 70%);
}
.browser3d-ph-glyph { display: inline-flex; color: var(--accent); opacity: 0.85; }
.browser3d-ph-glyph svg { width: 46px; height: 46px; stroke-width: 1.4; }
.browser3d-ph-name {
  font-family: var(--font-display);
  font-size: 19px; font-weight: 600; letter-spacing: -0.02em;
  color: var(--fg-soft);
}

/* ── Texte de la réalisation ── */
.work3d-body { min-width: 0; }
.work3d-kind {
  font-family: var(--font-mono);
  font-size: 11px;
  letter-spacing: 0.14em;
  text-transform: uppercase;
  color: var(--muted-3);
}
.work3d-name {
  font-family: var(--font-display);
  font-size: clamp(24px, 3vw, 34px);
  font-weight: 600;
  letter-spacing: -0.03em;
  line-height: 1.02;
  margin: 11px 0 0;
  color: var(--fg);
}
.work3d-blurb {
  font-size: 15.5px;
  line-height: 1.6;
  color: var(--muted);
  margin: 15px 0 0;
  max-width: 44ch;
  text-wrap: pretty;
}
.work3d-tags { display: flex; flex-wrap: wrap; gap: 7px; margin: 20px 0 0; }
.work3d-tag {
  font-family: var(--font-mono);
  font-size: 10px;
  letter-spacing: 0.06em;
  text-transform: uppercase;
  color: var(--muted-3);
  border: 1px solid var(--line);
  border-radius: 999px;
  padding: 3px 10px;
}
.work3d-foot { display: flex; flex-wrap: wrap; align-items: center; gap: 18px; margin-top: 24px; }
.work3d-client { font-size: 14px; color: var(--muted-3); }
.work3d-cta {
  display: inline-flex; align-items: center; gap: 8px;
  font-size: 14px; font-weight: 600; letter-spacing: -0.01em;
  color: var(--fg); text-decoration: none;
}
.work3d-cta-label { position: relative; }
.work3d-cta-label::after {
  content: ""; position: absolute; left: 0; right: 100%; bottom: -2px; height: 1.5px;
  background: var(--accent); transition: right 0.4s var(--ease-out-expo);
}
.work3d-cta:hover .work3d-cta-label::after { right: 0; }
.work3d-cta-arr { color: var(--accent); display: inline-block; transition: transform 0.4s var(--ease-out-expo); }
.work3d-cta:hover .work3d-cta-arr { transform: translate(4px, -4px); }
.work3d-status {
  font-family: var(--font-mono);
  font-size: 10px; letter-spacing: 0.12em; text-transform: uppercase;
  color: var(--muted-3);
  border: 1px solid var(--line); border-radius: 999px; padding: 4px 11px;
}

@media (max-width: 900px) {
  .works-3d { gap: 56px; }
  .work3d, .work3d:nth-child(even) { grid-template-columns: 1fr; gap: 26px; perspective: none; }
  .work3d-visual, .work3d:nth-child(even) .work3d-visual { order: 0; }
  .work3d-body,   .work3d:nth-child(even) .work3d-body   { order: 1; }
  .browser3d, .work3d:nth-child(even) .browser3d { transform: none; }
  .browser3d { box-shadow: 0 24px 50px -28px rgba(0,0,0,0.35); }}
@media (prefers-reduced-motion: reduce) {
  .browser3d, .work3d:nth-child(even) .browser3d { transform: none; transition: none; }
  .work3d-visual:hover .browser3d { transform: none; }}

/* Fix débordement mobile : autoriser les items de grille à rétrécir sous la
   taille intrinsèque de la capture (min-width:auto sinon force la colonne). */
.work3d-visual, .work3d-body { min-width: 0; }
.browser3d, .browser3d-screen img { max-width: 100%; }
@media (max-width: 900px) {
  .work3d-blurb { max-width: 100%; }}

/* ==========================================================================
   ÉPURATION « anti-IA » — on dégage la panoplie décorative (aura, marquee,
   halos/brillance des tuiles, badges mono) et on assume du plus brut.
   ========================================================================== */

/* Étiquettes de section : label simple (fini le mono majuscule + n° + trait).
   `--muted-2` mesuré au navigateur à 4,30:1 en thème sombre (#7a7876 sur
   #111110) : sous le seuil AA de 4,5:1, et ces étiquettes portent le nom de la
   section, pas une décoration. `--muted-3` est le jeton AA du dépôt : 5,34:1 en
   sombre, 5,14:1 en clair. Deux tailles ont bougé depuis l'épuration (11 px
   mono à l'origine, 13 px corps ici) sans que la couleur suive. */
.hero-eyebrow {
  font-family: var(--font-body);
  font-size: 13px;
  font-weight: 500;
  letter-spacing: 0;
  text-transform: none;
  color: var(--muted-3);
}
.section-head .hero-eyebrow { display: block; gap: 0; padding-bottom: 0; }
.page-home .section-head .hero-eyebrow::before { content: none; }
.section-head .hero-eyebrow::after { display: none; content: none; }

/* (Les tuiles d'apps gardent leur style d'origine : aplat d'accent + halo +
   trame de points + ombre colorée — cf. « Tuiles » plus haut. L'épuration de
   ces tuiles a été annulée à la demande.) */

/* ==========================================================================
   DÉMO « LIVE » du studio de sites commerce (home #modeles)
   Faux navigateur qui rejoue l'usage du sélecteur /commerce (curseur
   synthétique, changements métier/style, plein écran). Cf. commerce-demo.js.
   ========================================================================== */
.cdemo { max-width: 960px; margin: 0 auto; position: relative; }
/* La maquette est un lien vers le sélecteur. */
.cdemo-link { display: block; color: inherit; text-decoration: none; }
.cdemo-link:focus-visible { outline: 2px solid var(--fg); outline-offset: 6px; border-radius: 18px; }
.cdemo-frame {
  position: relative;
  border-radius: 16px;
  overflow: hidden;
  background: var(--card);
  border: 1px solid var(--line-strong);
  box-shadow: 0 42px 82px -34px rgba(0,0,0,0.42), 0 13px 28px -15px rgba(0,0,0,0.18);
  transition: transform 0.6s var(--ease-out-expo), box-shadow 0.6s var(--ease-out-expo);
}
.cdemo.is-full .cdemo-frame {
  transform: scale(1.025);
  box-shadow: 0 55px 100px -30px rgba(0,0,0,0.5), 0 18px 36px -16px rgba(0,0,0,0.24);
}

/* Barre du navigateur */
.cdemo-bar { display: flex; align-items: center; gap: 12px; padding: 11px 15px; background: var(--paper-2); border-bottom: 1px solid var(--line); }
.cdemo-dots { display: inline-flex; gap: 6px; flex: none; }
.cdemo-dots i { width: 10px; height: 10px; border-radius: 50%; background: var(--line-strong); }
.cdemo-url {
  font-family: var(--font-mono); font-size: 11px; color: var(--muted-3);
  background: var(--card); border: 1px solid var(--line); border-radius: 7px;
  padding: 3px 14px; max-width: 300px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap;
}
.cdemo-full-btn {
  margin-left: auto; display: inline-grid; place-items: center;
  width: 26px; height: 26px; border-radius: 7px; flex: none;
  color: var(--muted-3); background: var(--card); border: 1px solid var(--line);
  transition: background 0.2s ease, color 0.2s ease;
}
.cdemo-full-btn.is-tap { background: var(--fg); color: var(--on-accent); border-color: var(--fg); }

/* La barre du sélecteur : menu du commerce, style segmenté, store. */
.cdemo-tools {
  display: flex; align-items: flex-end; gap: 10px 16px; flex-wrap: wrap;
  padding: 11px 16px 12px; background: var(--card); border-bottom: 1px solid var(--line);
  overflow: hidden; max-height: 200px;
  transition: max-height 0.55s var(--ease-out-expo), opacity 0.4s ease, padding 0.55s var(--ease-out-expo);
}
.cdemo.is-full .cdemo-tools { max-height: 0; opacity: 0; padding-top: 0; padding-bottom: 0; border-bottom-color: transparent; }
.cdemo-g { display: grid; gap: 5px; }
.cdemo-g em { font: normal 500 11.5px var(--font-body); color: var(--muted-3); }
.cdemo-pick, .cdemo-seg { display: inline-flex; align-items: center; height: 34px; border-radius: 999px; background: color-mix(in oklab, var(--fg) 6%, var(--card)); }
.cdemo-pick { gap: 22px; padding: 0 12px 0 14px; border: 1px solid var(--line-strong); background: var(--paper); font-size: 13px; transition: transform 0.16s ease; }
.cdemo-pick svg { color: var(--muted-3); }
.cdemo-seg { position: relative; padding: 3px; }
.cdemo-ind { position: absolute; top: 3px; bottom: 3px; left: 0; border-radius: 999px; background: var(--card); box-shadow: 0 1px 4px rgba(0,0,0,0.16); }
.cdemo.is-live .cdemo-ind { transition: transform 0.5s cubic-bezier(.3,1.3,.5,1), width 0.5s cubic-bezier(.3,1.3,.5,1); }
.cdemo-chip {
  position: relative; display: inline-flex; align-items: center; gap: 6px; padding: 0 11px; height: 100%;
  font-size: 12.5px; font-weight: 500; color: var(--muted); white-space: nowrap; transition: color 0.3s ease, transform 0.16s ease;
}
.cdemo-chip i { width: 8px; height: 8px; border-radius: 50%; background: var(--d); }
.cdemo-chip.is-on { color: var(--fg); }
.cdemo-chip.is-tap, .cdemo-pick.is-tap, .cdemo-item.is-tap { transform: scale(0.92); }
.cdemo-cta { margin-left: auto; padding: 9px 15px; border-radius: 999px; background: var(--fg); color: var(--on-accent); font-size: 12.5px; font-weight: 600; }
.cdemo-menu {
  position: absolute; z-index: 4; display: grid; min-width: 180px; padding: 5px; border-radius: 14px;
  background: var(--card); border: 1px solid var(--line); box-shadow: 0 22px 44px -18px rgba(0,0,0,0.4);
  opacity: 0; transform: translateY(-6px) scale(0.96); transform-origin: 30px 0;
  transition: opacity 0.18s ease, transform 0.34s cubic-bezier(.3,1.3,.5,1);
}
.cdemo-menu.is-open { opacity: 1; transform: none; }
.cdemo-item { padding: 8px 11px; border-radius: 9px; font-size: 13px; transition: background 0.2s ease, transform 0.16s ease; }
.cdemo-item.is-on { background: var(--paper-2); font-weight: 600; }

/* Scène : les captures en fondu, et le store de la vraie app (rayures,
   festons à la couleur de leur rayure, coffre, enseigne suspendue). */
.cdemo-stage { position: relative; aspect-ratio: 16 / 10; background: var(--paper); overflow: hidden; }
.cdemo-stage > picture { display: contents; }
.cdemo-shot {
  position: absolute; inset: 0; width: 100%; height: 100%;
  object-fit: cover; object-position: top center;
  opacity: 0; transform: scale(1.03);
  transition: opacity 0.6s var(--ease-out-expo), transform 0.9s var(--ease-out-expo);
}
.cdemo-shot.is-on { opacity: 1; transform: none; }
.cdemo-store {
  --a: #c4572f; --b: #f3e6d2;
  position: absolute; inset: 0 0 22px; z-index: 3; display: none;
  background: linear-gradient(rgba(0,0,0,0.24), transparent 16%), repeating-linear-gradient(90deg, var(--a) 0 34px, var(--b) 34px 68px);
  box-shadow: inset 0 9px 0 rgba(10,10,10,0.85);
  transform: translateY(calc(-100% - 40px)); transition: transform 0.42s cubic-bezier(.6,0,.85,.4);
}
.cdemo.is-live .cdemo-store { display: block; }
.cdemo-store::after {
  content: ""; position: absolute; top: 100%; left: 0; right: 0; height: 17px;
  background: repeating-linear-gradient(90deg, var(--a) 0 34px, var(--b) 34px 68px);
  -webkit-mask: radial-gradient(circle at 50% 0, #000 16.5px, transparent 17px) 0 0 / 34px 17px repeat-x;
  mask: radial-gradient(circle at 50% 0, #000 16.5px, transparent 17px) 0 0 / 34px 17px repeat-x;
}
.cdemo-store.is-down { transform: none; transition: transform 0.6s cubic-bezier(.3,1.25,.5,1); }
.cdemo-sign {
  position: absolute; left: 50%; top: 26%; translate: -50% 0; transform-origin: 50% -60px;
  padding: 11px 20px; border-radius: 10px; background: var(--card); border: 1px solid var(--line);
  box-shadow: 0 16px 30px -14px rgba(0,0,0,0.45); text-align: center; white-space: nowrap;
  font: 600 17px var(--font-display); color: var(--fg);
}
.cdemo-sign small { display: block; font: 500 12.5px var(--font-body); color: var(--muted-3); }
.cdemo-sign::before { content: ""; position: absolute; left: 22%; right: 22%; bottom: 100%; height: 400px; border-inline: 1px solid rgba(10,10,10,0.5); }
.cdemo-store.is-down .cdemo-sign { animation: cdemo-swing 1.2s ease-out 0.18s; }
@keyframes cdemo-swing { 0% { rotate: -7deg; } 35% { rotate: 4deg; } 65% { rotate: -2deg; } 100% { rotate: 0deg; } }
[data-theme="dark"] .cdemo-store { --a: #b44f2b; --b: #e9dac3; }
[data-theme="dark"] .cdemo-ind { background: color-mix(in oklab, var(--fg) 18%, var(--card)); }

/* Curseur synthétique */
.cdemo-cursor {
  position: absolute; top: 0; left: 0; width: 22px; height: 22px; z-index: 5;
  pointer-events: none; opacity: 0;
  filter: drop-shadow(0 2px 5px rgba(0,0,0,0.35));
  transition: transform 0.72s var(--ease-out-expo), opacity 0.4s ease;
  will-change: transform;
}
.cdemo-cursor.is-ready { opacity: 1; }
.cdemo-cursor svg { display: block; transition: transform 0.15s ease; }
.cdemo-cursor.is-press svg { transform: scale(0.78); }

/* Légende « en direct » */
.cdemo-caption { display: flex; align-items: center; justify-content: center; gap: 9px; margin-top: 16px; font-size: 13px; color: var(--muted-3); }
.cdemo-live { width: 8px; height: 8px; border-radius: 50%; background: oklch(0.6 0.15 150); flex: none; animation: cdemo-pulse 2.1s ease-out infinite; }
@keyframes cdemo-pulse {
  0%   { box-shadow: 0 0 0 0 color-mix(in oklab, oklch(0.6 0.15 150) 55%, transparent); }
  70%  { box-shadow: 0 0 0 7px transparent; }
  100% { box-shadow: 0 0 0 0 transparent; }}
[data-theme="dark"] .cdemo-live { background: #4ade80; }

@media (max-width: 720px) {
  .cdemo-url { max-width: 150px; }
  .cdemo-tools { gap: 8px 10px; padding: 10px 12px 11px; }
  .cdemo-cta, .cdemo-chip i, .cdemo-chip[data-style="carnet"] { display: none; }
  .cdemo-chip { padding: 0 8px; font-size: 11.5px; }
  .cdemo-sign { font-size: 14px; padding: 8px 14px; }}
@media (prefers-reduced-motion: reduce) {
  .cdemo-cursor, .cdemo-store { display: none !important; }
  .cdemo-shot, .cdemo-frame, .cdemo-tools, .cdemo-chip { transition: none; }
  .cdemo-shot.is-on { transform: none; }
  .cdemo-live { animation: none; }}

/* Fix nav: ancres de la home -> degager le header fixe (~74px) au scroll,
   pour que le titre de section ne passe pas sous la barre. */
.home-hero,
.home-section {
  scroll-margin-top: 88px;
}

/* ==========================================================================
   Refonte juillet 2026 — navigation mobile, prix visible, page /tarifs
   ========================================================================== */

/* ── Topbar : outils à droite + bouton burger ─────────────────────────────── */
.topbar-tools {
  pointer-events: auto;
  display: flex; align-items: center; gap: 10px;
}
/* NB : le toggle de thème de la vitrine a quitté .topbar-nav (devenue un
   tiroir sur mobile) pour .topbar-tools — l'admin garde le sien dans sa propre
   barre, d'où le ciblage par #topbarNav plus bas (jamais .topbar-nav nu). */
.nav-burger {
  display: none;                      /* desktop : la nav est déjà visible */
  width: 44px; height: 44px;          /* cible tactile conforme (≥ 44 × 44) */
  border-radius: 12px;
  background: rgba(255,255,255,0.65);
  backdrop-filter: blur(12px);
  -webkit-backdrop-filter: blur(12px);
  border: 1px solid var(--line);
  color: var(--fg);
  cursor: pointer;
  padding: 0;
  align-items: center; justify-content: center;
}
[data-theme="dark"] .nav-burger { background: rgba(255,255,255,0.07); }
.nav-burger-bars { display: grid; gap: 4px; width: 18px; }
.nav-burger-bars i {
  display: block; height: 2px; border-radius: 2px;
  background: currentColor;
  transition: transform 200ms var(--ease-standard), opacity 140ms ease;
}
.nav-burger[aria-expanded="true"] .nav-burger-bars i:nth-child(1) { transform: translateY(6px) rotate(45deg); }
.nav-burger[aria-expanded="true"] .nav-burger-bars i:nth-child(2) { opacity: 0; }
.nav-burger[aria-expanded="true"] .nav-burger-bars i:nth-child(3) { transform: translateY(-6px) rotate(-45deg); }

/* Actions du tiroir : masquées tant qu'on est en navigation horizontale. */
.topbar-nav-actions { display: none; }
.topbar-nav-more { display: none; }   /* le tiroir mobile seulement, cf. plus bas */

/* Sept rubriques (« Nos applications » depuis le 15 septembre 2026) : entre
   881 et 1024 px la rangée se resserre, mesuré à 900 px (793 px demandés pour
   728 disponibles, les libellés se coupaient sur deux lignes). */
@media (max-width: 1024px) {
  .topbar-nav { gap: 16px; font-size: 12.5px; }
  .topbar-nav a.topbar-cta { padding: 8px 12px; font-size: 12.5px; }
}

/* De 881 à 1080 px, sept rubriques ne laissent que 10 px à la marque
   (mesuré à 881) : le logo entier ne tient pas, son icône si. Même fichier,
   recadré sur l'icône, qui occupe les colonnes 0 à 294 du PNG : 298 tombe
   dans le blanc avant « Azur ». De 1081 à 1180, le logo à 36 px ferait passer
   des rubriques sur deux lignes. Sous 881 px la rangée part dans le tiroir :
   la place revient. L'admin n'a pas ces rubriques (admin.css). */
@media (min-width: 881px) and (max-width: 1080px) {
  body:not(.page-admin) .brand-logo--bar { aspect-ratio: 298 / 256; background-size: auto 100%; }
}
@media (min-width: 1081px) and (max-width: 1180px) {
  body:not(.page-admin) .brand-logo--bar { height: 30px; }
}

/* Le tiroir s'ouvre sous 880 px, plus 760 : à 800 px, sept rubriques et la
   pastille ne tiennent pas sur une ligne (657 px disponibles), et 880 est
   déjà la rupture « tablette » de cette feuille. */
@media (max-width: 880px) {
  /* La topbar redevient une barre opaque : un tiroir plein écran ne peut pas
     s'ouvrir sous un dégradé transparent. */
  .topbar { padding: 12px 16px; }
  .nav-burger { display: inline-flex; }
  /* La topbar porte un masque en dégradé (fondu vers le bas). Un masque
     s'applique aussi aux descendants : le tiroir, enfant du header, était
     donc découpé à la hauteur de la barre — panneau et liens invisibles.
     Menu ouvert, on retire le masque et on repasse la barre en opaque. */
  body.nav-open .topbar {
    -webkit-mask-image: none;
    mask-image: none;
    background: var(--bg);
    /* `backdrop-filter` fait de la topbar le bloc conteneur de ses descendants
       en `position: fixed` : le tiroir se retrouvait dimensionné à la hauteur
       de la barre (68 px) au lieu du viewport — un seul lien visible. */
    -webkit-backdrop-filter: none;
    backdrop-filter: none;
  }
  /* La marque reste cliquable au-dessus du tiroir (retour à l'accueil). */
  .topbar .brand { position: relative; z-index: 2; }
  /* Cibles tactiles du header : ≥ 44 px de haut, y compris la marque et le
     toggle de thème (mesurés à 112 × 23 et 30 × 30 avant correction). */
  .topbar .brand { display: inline-flex; align-items: center; min-height: 44px; min-width: 44px; }
  .topbar .theme-toggle, .topbar .nav-burger { width: 44px; height: 44px; border-radius: 12px; background: none; border-color: transparent; -webkit-backdrop-filter: none; backdrop-filter: none; }
  .topbar .theme-toggle:hover { background: none; transform: none; }
  .topbar-tools { gap: 2px; }

  #topbarNav {
    position: fixed;
    inset: 0;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    justify-content: flex-start;
    gap: 0;
    padding: 84px 22px 32px;
    background: var(--bg);
    overflow-y: auto;
    font-size: 17px;
    transform: translateY(-8px);
    opacity: 0;
    visibility: hidden;
    pointer-events: none;
    transition: opacity 180ms ease, transform 180ms var(--ease-standard), visibility 0s linear 180ms;
    z-index: 1;                        /* sous le burger, au-dessus du contenu */
  }
  #topbarNav.is-open {
    transform: none;
    opacity: 1;
    visibility: visible;
    pointer-events: auto;
    transition: opacity 180ms ease, transform 180ms var(--ease-standard), visibility 0s;
  }
  /* `>` : seuls les liens de navigation directs prennent l'allure « ligne de
     menu ». Sans ça, l'id (spécificité 1,0,1) écrasait la couleur des CTA
     .btn-primary / .btn-secondary du tiroir — texte noir sur fond noir. */
  #topbarNav > a {
    display: flex; align-items: center;
    min-height: 52px;                  /* ≥ 44 px, confortable au pouce */
    font-size: 17px;
    color: var(--fg);
    border-bottom: 1px solid var(--line-soft);
  }
  #topbarNav > a.is-active { font-weight: 650; }
  /* La pastille du configurateur est un `#topbarNav > a` : la règle ci-dessus
     (spécificité 1,0,1) écrasait sa couleur et la laissait en texte noir sur
     fond noir — le CTA principal du site était INVISIBLE dans le tiroir. Dans
     le menu, elle reprend l'allure des autres actions : bouton plein, centré,
     détaché de la liste de rubriques. */
  #topbarNav > a.topbar-cta {
    justify-content: center;
    margin-top: 22px;
    min-height: 48px;
    border-bottom: 0;
    border-radius: 999px;
    background: var(--fg);
    color: var(--bg);
    font-size: 15px;
    font-weight: 600;
  }
  #topbarNav > a.topbar-cta.is-active { opacity: 0.78; color: var(--bg); }
  /* Le CTA prend la place de tête du bloc d'actions : celui-ci se recolle. */
  #topbarNav > a.topbar-cta + .topbar-nav-actions { margin-top: 10px; }
  .topbar-nav-actions {
    display: flex; flex-direction: column; gap: 10px;
    margin-top: 22px;
  }
  /* « Aussi » : les entrées du pied de page, en petit sous les actions. */
  .topbar-nav-more {
    display: flex; flex-direction: column;
    margin-top: 26px; padding-top: 14px;
    border-top: 1px solid var(--line-soft);
  }
  .topbar-nav-more-h {
    font-family: var(--font-mono); font-size: 10px; letter-spacing: 0.18em;
    text-transform: uppercase; color: var(--muted-3); margin-bottom: 4px;
  }
  .topbar-nav-more a {
    display: flex; align-items: center; min-height: 44px;
    font-size: 15px; color: var(--muted);
  }
  #topbarNav .btn-primary {
    justify-content: center; min-height: 48px; font-size: 15px;
    background: #0a0a0a; color: #fafaf9; border-color: #0a0a0a;
  }
  #topbarNav .btn-secondary {
    justify-content: center; min-height: 48px; font-size: 15px;
    background: var(--card); color: var(--fg); border-color: var(--line);
  }
  .topbar-nav-phone {
    margin-top: 6px;
    text-align: center;
    font-family: var(--font-mono);
    font-size: 14px;
    color: var(--muted);
    border-bottom: 0 !important;
    justify-content: center;
  }
  /* Le burger reste par-dessus le tiroir pour pouvoir refermer. */
  .topbar-tools { position: relative; z-index: 2; }
  /* Le tiroir ouvert fige le fond (classe posée par landing.js). */
  body.nav-open { overflow: hidden; }
}
@media (prefers-reduced-motion: reduce) {
  #topbarNav, .nav-burger-bars i { transition: none; }}

/* ── Home : bandeau prix (le tarif visible sans cliquer) ──────────────────── */
/* La gouttière du bandeau ET de sa ligne d'explication est portée par le
   CONTENEUR, aux paliers de la maison (.home-section : 32 / 24 / 20). Posée sur
   l'élément, elle s'ajoutait à celle du conteneur : mesurée, la ligne
   d'explication tombait 40 px trop à droite entre 700 et 880 px, 32 px entre
   900 et 1080, 22 px vers 1100, et ne retrouvait la colonne de texte de la page
   qu'aux deux extrémités (≤ 640 px et ≥ 1144 px). */
.home-price-strip { padding: 0 32px; }
.price-strip {
  max-width: 1180px;
  margin: 0 auto;
  display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between;
  gap: 16px 26px;
  padding: 20px 26px;
  border: 1px solid var(--line);
  border-radius: 20px;
  background: var(--card);
}
.price-strip-main { display: flex; align-items: center; gap: 18px; min-width: 0; }
/* Le bandeau porte désormais une phrase (« Des tarifs abordables ») et non plus
   trois caractères : taille fluide + retour à la ligne autorisé, sinon le texte
   s'affiche à la taille prévue pour un montant et déborde. */
.price-strip-amount {
  font-family: var(--font-display);
  font-size: clamp(1.4rem, 3.2vw, 2.1rem); font-weight: 700; letter-spacing: -0.03em;
  line-height: 1.15;
  white-space: normal;
  flex: 0 1 auto;
}
.price-strip-txt { display: flex; flex-direction: column; gap: 2px; }
.price-strip-txt strong { font-size: 16px; font-weight: 600; letter-spacing: -0.01em; }
.price-strip-txt .muted { font-size: 14px; }
/* Les deux paliers sont posés APRÈS la règle de base, et dans l'ordre
   décroissant : à spécificité égale, entre deux media queries qui matchent
   toutes les deux (un écran de 600 px vérifie 880 ET 640), c'est l'ordre du
   fichier qui tranche. */
@media (max-width: 880px) {
  .home-price-strip { padding: 0 24px; }
}
@media (max-width: 640px) {
  .home-price-strip { padding: 0 20px; }
  .price-strip { padding: 18px 18px; }
  .price-strip .btn-secondary { width: 100%; justify-content: center; }}

/* La cause du prix, sous le bandeau (vague 2). Elle explique, elle ne vend
   pas : ni cadre, ni fond, ni bouton. Elle n'a AUCUNE gouttière propre : celle
   du conteneur suffit, et sa largeur est celle de la colonne de texte de la
   page (1080 px de .home-section moins ses 2 × 32 px de gouttière = 1016). Le
   bandeau, lui, reste volontairement plus large (1180 px). */
.price-strip-why {
  max-width: 1016px;
  margin: 12px auto 0;
  font-size: 14px;
  line-height: 1.6;
  color: var(--muted);
}
.price-strip-why a { color: var(--fg); font-weight: 600; text-decoration: none; border-bottom: 1px solid var(--line-strong); }
.price-strip-why a:hover { border-bottom-color: var(--fg); }
@media (hover: none) { .price-strip-why a:hover { border-bottom-color: var(--line-strong); }}

/* Home : les apps « à la une » en rail sur téléphone (CSS seul). Écrit APRÈS la règle ≤ 640 px, qu'il doit battre. */
@media (max-width: 700px) {
  .featured-hint {
    display: block;
    margin: -8px 0 10px;
    font-family: var(--font-mono);
    font-size: 10px; letter-spacing: 0.18em; text-transform: uppercase;
    color: var(--muted-3);
  }
  .featured-grid {
    grid-auto-flow: column;
    grid-auto-columns: 84%;
    grid-template-columns: none;
    overflow-x: auto;
    overscroll-behavior-x: contain;
    scroll-snap-type: x mandatory;
    scroll-padding-inline-start: 20px;
    -webkit-overflow-scrolling: touch;
    margin-inline: -20px;
    padding: 2px 20px 8px;
    gap: 12px;
    scrollbar-width: none;
  }
  .featured-grid::-webkit-scrollbar { display: none; }
  .featured-grid .app-cell { scroll-snap-align: start; }
}

/* ── Home : ce qu'on fait / ce qu'on ne fait pas (remplace le pavé SEO) ───── */
/* « Le studio » : deux panneaux à lire plutôt que deux colonnes de puces (aérer, c'est donner des bords). */
.studio-scope {
  margin-top: 44px;
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 16px 20px;
}
.scope-col {
  padding: 20px 20px 22px;
  border: 1px solid var(--line);
  border-radius: 18px;
  background: var(--paper);
}
.scope-h {
  display: block;
  font-family: var(--font-mono);
  font-size: 11px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--muted-3);
  margin-bottom: 14px;
}
.scope-col ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 13px; }
.scope-col li { position: relative; padding-left: 24px; color: var(--muted); line-height: 1.55; }
.scope-col--yes li::before {
  content: ""; position: absolute; left: 0; top: 0.28em;
  width: 0.85em; height: 0.85em;
  background-color: oklch(0.55 0.13 150);
  -webkit-mask: var(--icon-check) center / contain no-repeat;
  mask: var(--icon-check) center / contain no-repeat;
}
.scope-col--no li::before { content: "–"; position: absolute; left: 0; color: var(--muted-3); font-weight: 700; }
.scope-who {
  grid-column: 1 / -1;
  margin: 6px 0 0;
  color: var(--muted);
  line-height: 1.6;
}

/* ── Home : témoignages (rendu seulement si TESTIMONIALS est non vide) ────── */
.testimonial-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
  gap: 18px;
}
.testimonial {
  margin: 0;
  border: 1px solid var(--line);
  border-radius: 20px;
  background: var(--card);
  padding: 28px 26px 22px;
}
.testimonial blockquote {
  margin: 0 0 16px;
  font-family: var(--font-display);
  font-size: 19px; line-height: 1.45; letter-spacing: -0.015em;
  text-wrap: pretty;
}
.testimonial blockquote::before { content: "« "; }
.testimonial blockquote::after { content: " »"; }
.testimonial figcaption { display: flex; align-items: center; gap: 12px; font-size: 14px; }
.testimonial-who { display: flex; flex-direction: column; gap: 2px; min-width: 0; }
.testimonial-photo { width: 44px; height: 44px; border-radius: 50%; object-fit: cover; flex: none; }
.avis-google { display: inline-flex; align-items: center; gap: 6px; margin-top: 14px; font-size: 14px; color: var(--muted-3); text-decoration: none; }
.avis-google .ico-sm { color: var(--accent); }
a.avis-google:hover { color: var(--fg); }
.step-action { margin: 14px 0 0; }
.step-body .step-action a { text-decoration: none; }
.contact-rdv { display: flex; flex-wrap: wrap; align-items: center; gap: 10px 14px; margin: 0 0 22px; color: var(--muted); font-size: 15px; }
.home-cta-final .offre-hero-note { margin-top: 14px; }
.testimonial figcaption a { color: var(--muted-3); text-decoration: none; margin-top: 4px; }
.testimonial figcaption a:hover { color: var(--fg); }

/* ── Footer : téléphone + promesse de délai ───────────────────────────────── */
.footer-phone { font-family: var(--font-mono); }
.footer-note { color: var(--muted-3); font-size: 12px; margin-top: 2px; }

/* ── Footer : réseaux sociaux ─────────────────────────────────────────────── */
.footer-social {
  display: flex;
  gap: 2px;
  margin: 4px 0 0;
  padding: 0;
  list-style: none;
}
.footer-social a,
.footer-social .footer-qr-btn {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  /* 44 px : cible tactile minimale (une icône de 36 px se rate au pouce). */
  width: 44px;
  height: 44px;
  margin-left: -12px; /* aligne l'icône sur le texte de la colonne malgré le padding tactile */
  border-radius: 10px;
  color: var(--muted);
  transition: color 150ms ease, background 150ms ease;
}
.footer-social li + li a,
.footer-social li + li .footer-qr-btn { margin-left: 0; }
.footer-social a:hover,
.footer-social .footer-qr-btn:hover { color: var(--fg); background: var(--line-soft); }
.footer-social svg { display: block; }
/* Le bouton QR est un <button> au milieu de liens : mêmes dimensions, mais il
   faut annuler l'habillage natif. */
.footer-qr-btn { border: 0; background: transparent; padding: 0; cursor: pointer; }

/* ── Modale de partage par QR code (bouton QR du pied de page) ───────────── */
body.qr-open { overflow: hidden; }
.qr-modal {
  position: fixed; inset: 0; z-index: 320;
  display: flex; align-items: center; justify-content: center;
  padding: 20px;
}
/* Piège [hidden] (cf. CLAUDE.md) : le display:flex ci-dessus battrait le
   masquage par attribut sans cette règle. */
.qr-modal[hidden] { display: none; }
.qr-modal-backdrop {
  position: absolute; inset: 0;
  background: rgba(10, 10, 10, 0.55);
  backdrop-filter: blur(4px);
  -webkit-backdrop-filter: blur(4px);
}
.qr-modal-card {
  position: relative;
  width: 100%; max-width: 400px;
  padding: 30px 26px 24px;
  border-radius: 20px;
  background: var(--card); color: var(--fg);
  border: 1px solid var(--line);
  box-shadow: 0 24px 80px rgba(0, 0, 0, 0.35);
  text-align: center;
}
.qr-modal-close {
  position: absolute; top: 8px; right: 8px;
  display: inline-flex; align-items: center; justify-content: center;
  width: 44px; height: 44px;
  border: 0; border-radius: 12px; background: transparent;
  color: var(--muted); cursor: pointer;
  transition: color 150ms ease, background 150ms ease;
}
.qr-modal-close:hover { color: var(--fg); background: var(--line-soft); }
.qr-modal-title {
  font-family: var(--font-display);
  font-size: 24px; font-weight: 650; letter-spacing: -0.02em;
  margin: 0 0 6px;
}
.qr-modal-sub { font-size: 14px; color: var(--muted); margin: 0 0 18px; text-wrap: pretty; }
.qr-modal-img {
  display: block;
  width: min(280px, 68vw); height: auto;
  margin: 0 auto 18px;
  /* Fond blanc permanent : un QR posé sur le thème sombre resterait
     scannable grâce à cette « carte » claire. */
  background: #fff;
  padding: 10px;
  border-radius: 16px;
  border: 1px solid var(--line-soft);
}
.qr-modal-actions { display: flex; gap: 10px; justify-content: center; flex-wrap: wrap; }
.qr-modal-action {
  display: inline-flex; align-items: center; justify-content: center;
  min-height: 44px; padding: 0 20px;
  border-radius: 999px;
  border: 1px solid var(--line-strong);
  background: transparent; color: var(--fg);
  font-family: var(--font-body); font-size: 14px; font-weight: 500;
  cursor: pointer;
  transition: background 150ms ease, color 150ms ease, border-color 150ms ease;
}
.qr-modal-action:hover { background: var(--line-soft); }
.qr-modal-action-primary {
  background: var(--fg); color: var(--on-accent); border-color: var(--fg);
}
.qr-modal-action-primary:hover { background: var(--fg); opacity: 0.9; }
@media (prefers-reduced-motion: no-preference) {
  .qr-modal-backdrop { animation: qr-fade 180ms ease; }
  .qr-modal-card { animation: qr-pop 220ms var(--ease-standard); }}
@keyframes qr-fade { from { opacity: 0; }}
@keyframes qr-pop { from { opacity: 0; transform: translateY(10px) scale(0.97); }}

/* ── Page /tarifs ─────────────────────────────────────────────────────────── */
.page-tarifs { background: var(--bg); }
.tarifs-hero { padding: 150px 32px 40px; }
.tarifs-hero-inner { max-width: 900px; margin: 0 auto; }
.tarifs-hero-title {
  font-family: var(--font-display);
  font-size: clamp(32px, 5.4vw, 54px);
  font-weight: 650; letter-spacing: -0.035em; line-height: 1.05;
  margin: 16px 0 18px;
  text-wrap: balance;
}
.tarifs-hero-lead { font-size: 18px; color: var(--muted); margin: 0 0 14px; max-width: 62ch; text-wrap: pretty; }
.tarifs-hero-note { font-size: 13px; color: var(--muted-3); margin: 0; }
.ambitieux { max-width: 780px; margin: 0 auto; text-align: center; }
.ambitieux p { color: var(--muted); font-size: 16px; text-wrap: pretty; }
.ambitieux .home-hero-cta { justify-content: center; margin-top: 22px; }
@media (max-width: 640px) {
  .tarifs-hero { padding: 118px 18px 26px; }
  .tarifs-hero-lead { font-size: 16px; }}

/* ── Feuille tarifaire (partial _offre_499.html) ──────────────────────────
   Mêmes noms de classes que la modale « Tarifs » de /commerce, mais habillés
   avec les jetons du portfolio (donc compatibles clair/sombre) — le contenu
   n'existe qu'à un seul endroit, seule la peau change. */
.offer-sheet {
  max-width: 1000px;
  margin: 0 auto;
  border: 1px solid var(--line);
  border-radius: 24px;
  background: var(--card);
  padding: 30px 32px 34px;
}
.offer-sheet .offer {
  display: flex; align-items: center; gap: 18px; flex-wrap: wrap;
  border: 1px solid var(--line);
  border-radius: 18px;
  background: var(--paper);
  padding: 20px 24px;
}
.offer-sheet .offer-price { display: flex; align-items: baseline; gap: 14px; }
.offer-sheet .offer-amount {
  font-family: var(--font-display);
  font-weight: 700; font-size: clamp(38px, 7vw, 52px);
  letter-spacing: -0.035em; line-height: 0.95;
}
/* « À partir de » posé au-dessus du montant : le prix reste l'élément fort,
   mais n'apparaît jamais seul. Voir aussi la copie dans la coquille
   /commerce (CommerceVitrine/index.html), qui a sa propre peau. */
.offer-amount-prefix {
  display: block;
  font-size: .42em; font-weight: 500; letter-spacing: .02em;
  opacity: .75; margin-bottom: .15em;
}
.offer-sheet .offer-meta { font-size: 12.5px; color: var(--muted-3); line-height: 1.3; }
.offer-sheet .offer-badges { display: flex; gap: 8px; flex-wrap: wrap; margin-left: auto; }
.offer-sheet .offer-badge {
  font-size: 12.5px; font-weight: 600;
  color: var(--fg); background: var(--card);
  border: 1px solid var(--line-strong);
  padding: 8px 13px; border-radius: 999px; white-space: nowrap;
}
.offer-sheet .offer-badge.hot { color: var(--on-accent); background: var(--fg); border-color: var(--fg); }

.offer-sheet .offer-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 30px; margin-top: 26px; }
.offer-sheet .col-h {
  font-family: var(--font-mono);
  font-size: 10.5px; letter-spacing: 0.16em; text-transform: uppercase;
  color: var(--muted-3); margin-bottom: 14px;
}
.offer-sheet .offer-feats { list-style: none; margin: 0; padding: 0; display: grid; gap: 12px; }
.offer-sheet .offer-feats li {
  position: relative; padding-left: 26px;
  font-size: 14px; line-height: 1.45; color: var(--muted);
}
.offer-sheet .offer-feats li b { color: var(--fg); font-weight: 600; }
.offer-sheet .offer-feats li::before {
  content: ""; position: absolute; left: 0; top: 0.25em;
  width: 0.9em; height: 0.9em;
  background-color: oklch(0.55 0.13 150);
  -webkit-mask: var(--icon-check) center / contain no-repeat;
  mask: var(--icon-check) center / contain no-repeat;
}
.offer-sheet .flow { list-style: none; margin: 0; padding: 0; }
.offer-sheet .flow-step { position: relative; display: flex; gap: 14px; padding-bottom: 16px; }
.offer-sheet .flow-step:last-child { padding-bottom: 0; }
.offer-sheet .flow-step:not(:last-child)::before {
  content: ""; position: absolute; left: 13px; top: 30px; bottom: 0; width: 2px;
  background: var(--line-strong);
}
.offer-sheet .flow-num {
  position: relative; z-index: 1; flex: none;
  width: 28px; height: 28px; border-radius: 50%;
  display: grid; place-items: center;
  font-family: var(--font-display); font-weight: 700; font-size: 13px;
  color: var(--on-accent); background: var(--fg);
}
.offer-sheet .flow-c b { display: block; font-size: 14px; font-weight: 600; }
.offer-sheet .flow-c p { margin: 3px 0 0; font-size: 13.5px; line-height: 1.45; color: var(--muted); }

.offer-sheet .offer-compare { margin-top: 30px; padding-top: 26px; border-top: 1px solid var(--line); }
.offer-sheet .cmp-lead { margin: 2px 0 16px; font-size: 14px; line-height: 1.5; color: var(--muted); }
.offer-sheet .cmp-lead b { color: var(--fg); font-weight: 600; }
.offer-sheet .cmp-stats { display: grid; grid-template-columns: repeat(3, 1fr); gap: 12px; margin-bottom: 20px; }
.offer-sheet .cmp-stat { border: 1px solid var(--line); border-radius: 16px; background: var(--paper); padding: 15px 16px; }
.offer-sheet .cmp-stat .big {
  font-family: var(--font-display); font-weight: 700; font-size: 26px;
  letter-spacing: -0.025em; line-height: 1;
}
.offer-sheet .cmp-stat .lab { font-size: 12.5px; line-height: 1.4; color: var(--muted); margin-top: 7px; }
.offer-sheet .cmp-stat .lab b { color: var(--fg); font-weight: 600; }
/* Le tableau déborde en largeur : il scrolle DANS son cadre, jamais la page. */
.offer-sheet .cmp-wrap { overflow-x: auto; -webkit-overflow-scrolling: touch; border-radius: 12px; }
.offer-sheet .cmp-wrap:focus-visible { outline: 2px solid var(--accent); outline-offset: 3px; }
/* La mention « faites glisser » ne sert qu'au format où le tableau déborde. */
.offer-sheet .cmp-swipe { display: none; }
.offer-sheet .cmp-table { width: 100%; border-collapse: collapse; font-size: 13px; min-width: 560px; }
.offer-sheet .cmp-table th,
.offer-sheet .cmp-table td { text-align: left; padding: 10px 12px; border-bottom: 1px solid var(--line); vertical-align: top; }
.offer-sheet .cmp-table thead th {
  font-family: var(--font-mono); font-size: 9.5px; letter-spacing: 0.08em; text-transform: uppercase;
  color: var(--muted-3); font-weight: 500;
}
.offer-sheet .cmp-table tbody th { font-weight: 500; color: var(--muted); white-space: nowrap; }
.offer-sheet .cmp-mine { background: var(--paper-2); }
.offer-sheet .cmp-table thead th.cmp-mine,
.offer-sheet .cmp-table td.cmp-mine { color: var(--fg); font-weight: 650; }
.offer-sheet .cmp-yes { color: oklch(0.52 0.13 150); font-weight: 700; }
.offer-sheet .cmp-no { color: oklch(0.55 0.16 25); font-weight: 700; }
[data-theme="dark"] .offer-sheet .cmp-yes { color: oklch(0.75 0.15 150); }
[data-theme="dark"] .offer-sheet .cmp-no { color: oklch(0.72 0.15 25); }
[data-theme="dark"] .offer-sheet .offer-feats li::before { color: oklch(0.75 0.15 150); }
[data-theme="dark"] .scope-col--yes li::before { color: oklch(0.75 0.15 150); }
.offer-sheet .cmp-src { font-size: 11px; color: var(--muted-3); margin: 12px 0 0; line-height: 1.45; }

.offer-sheet .offer-after {
  display: flex; gap: 13px; align-items: flex-start;
  margin-top: 24px; padding: 16px 18px;
  border: 1px solid var(--line); border-radius: 16px; background: var(--paper);
}
.offer-sheet .offer-after-ic {
  flex: none; width: 26px; height: 26px; border-radius: 50%;
  display: grid; place-items: center; font-size: 15px;
  color: var(--fg); background: var(--paper-2);
}
.offer-sheet .offer-after p { margin: 0; font-size: 13.5px; line-height: 1.5; color: var(--muted); }
.offer-sheet .offer-after b { color: var(--fg); font-weight: 600; }
.offer-sheet .offer-actions {
  display: flex; flex-wrap: wrap; gap: 12px; margin-top: 24px;
}
.offer-sheet .note { font-size: 12.5px; color: var(--muted-3); margin: 12px 0 0; }

@media (max-width: 780px) {
  .offer-sheet { padding: 22px 18px 26px; border-radius: 20px; }
  .offer-sheet .offer-grid { grid-template-columns: 1fr; gap: 24px; }
  .offer-sheet .cmp-stats { grid-template-columns: 1fr; gap: 10px; }
  .offer-sheet .cmp-stat { display: flex; align-items: center; gap: 14px; }
  .offer-sheet .cmp-stat .big { font-size: 23px; flex: none; }
  .offer-sheet .cmp-stat .lab { margin-top: 0; }
  .offer-sheet .offer-actions .btn-primary,
  .offer-sheet .offer-actions .btn-secondary { width: 100%; justify-content: center; }}

/* La CAUSE du prix, posée sous le comparatif de marché (vague 2). Petite,
   grise, mais présente : c'est une réponse à une question, pas un argument de
   vente, et elle ne doit pas concurrencer les chiffres au-dessus. */
.cmp-why {
  margin: 14px 0 0;
  font-size: 14px;
  line-height: 1.6;
  color: var(--muted);
}
.cmp-why a { color: var(--fg); font-weight: 600; text-decoration: none; border-bottom: 1px solid var(--line-strong); }
.cmp-why a:hover { border-bottom-color: var(--fg); }
/* Sur un appareil sans souris, iOS garde l'état de survol jusqu'au tap suivant
   ailleurs. Bloc posé APRÈS la règle qu'il annule : une media query n'ajoute
   aucune priorité, seul l'ordre tranche. */
@media (hover: none) { .cmp-why a:hover { border-bottom-color: var(--line-strong); } }

/* ── Comparatif sur téléphone : le tableau défile, il faut le dire et garder
   le repère de ligne ────────────────────────────────────────────────────────
   Mesuré à 390 px : 248 des 560 px du tableau étaient hors cadre, sans le
   moindre signe qu'on pouvait faire glisser, et en glissant on perdait le
   libellé de la ligne — on lisait « 1 500 – 5 000 € » sans savoir de quoi.
   Trois réponses : la mention explicite, un cadre qui fait lire la troncature
   comme un panneau, et la colonne de critère rendue collante. */
@media (max-width: 700px) {
  .offer-sheet .cmp-swipe {
    display: block;
    margin: 0 0 8px;
    font-size: 12px; color: var(--muted-3);
  }
  /* Encadré : le tableau tronqué se lit alors comme un panneau qui défile,
     pas comme une mise en page cassée. */
  .offer-sheet .cmp-wrap {
    border: 1px solid var(--line);
    overscroll-behavior-x: contain;   /* pas de retour arrière du navigateur */
  }
  .offer-sheet .cmp-table { min-width: 520px; }
  .offer-sheet .cmp-table tbody tr:last-child th,
  .offer-sheet .cmp-table tbody tr:last-child td { border-bottom: 0; }
  .offer-sheet .cmp-table th[scope="row"],
  .offer-sheet .cmp-table thead th:first-child {
    position: sticky; left: 0; z-index: 1;
    background: var(--card);
    box-shadow: 1px 0 0 var(--line);
    white-space: normal;              /* le nowrap desktop mangerait la largeur */
    min-width: 118px;
  }
}

/* Cibles tactiles restantes mesurées à 390 px (filtres /apps 25 px, indice de
   défilement de la home 42 px) — cf. critère « ≥ 44 × 44 » du lot 8. */
@media (max-width: 760px) {

  .scroll-cue { min-height: 44px; }
  /* Contacts « en clair » de /contact : ce sont des actions à part entière
     (pas des liens au fil du texte), donc de vraies cibles tactiles. */
  .contact-direct a,
  .contact-actions .link-muted { display: inline-flex; align-items: center; min-height: 44px; }
}

/* Coordonnées affichées en clair sous le chapô de /contact. */
.contact-direct {
  margin: 6px 0 0;
  font-family: var(--font-mono);
  font-size: 13px;
  color: var(--muted-3);
  display: flex; flex-wrap: wrap; align-items: center; gap: 0 8px;
}
.contact-direct a { color: var(--fg); text-decoration: none; }
.contact-direct a:hover { text-decoration: underline; }

/* ── Accès en bas de page (Espace client / Espace admin) ─────────────── */
.site-footer-access { display: inline-flex; gap: 16px; }

/* ── Page /espace-client : porte d'entrée du portail ─────────────────── */
.eca-card {
  margin: 28px 0;
  padding: 26px 28px;
  background: var(--card);
  border: 1px solid var(--line);
  border-radius: 16px;
  box-shadow: 0 1px 2px rgba(0,0,0,0.02);
}
.eca-lead { margin: 0 0 18px; line-height: 1.6; }
.eca-label { display: block; font-size: 13px; font-weight: 600; margin-bottom: 6px; }
.eca-row { display: flex; gap: 10px; flex-wrap: wrap; }
.eca-row input {
  flex: 1 1 260px;
  min-height: 44px;
  padding: 10px 14px;
  border: 1px solid var(--line-strong);
  border-radius: 10px;
  font-size: 15px;
  font-family: inherit;
  background: var(--bg);
  color: var(--fg);
}
.eca-row input:focus { outline: none; border-color: var(--fg); }
.eca-row .btn-primary { min-height: 44px; flex: none; }
/* Panneau d'erreur de la charte (déclaré une seule fois, en tête de fichier) :
   ici, seule la marge est propre à cet écran. */
.eca-error { margin: 10px 0 0; }
.eca-hint { margin: 12px 0 0; }
@media (max-width: 640px) {
  .eca-card { padding: 20px 18px; }
  .eca-row .btn-primary { flex: 1 1 100%; }}

/* Icônes SVG inline (templates/_icons.html + static/js/icons.js) */
.ico { vertical-align: -0.15em; flex: none; }

/* ==========================================================================
   CONFORT MOBILE (audit août 2026, mesuré au navigateur à 390 et 360 px)
   Trois familles de correctifs, toutes cantonnées au téléphone : le rendu
   desktop ne bouge pas d'un pixel.
   ========================================================================== */

/* ── 1. Aucun champ sous 16 px ────────────────────────────────────────────
   Sous 16 px, iOS **zoome tout seul** au premier tap dans un champ, puis
   laisse la page agrandie : il faut pincer pour revenir. Tous nos champs
   étaient à 15 px (contact, connexion, accès Espace client) ou moins. 16 px
   est le seuil exact du comportement Safari, pas une préférence de goût. */
@media (max-width: 760px) {
  input:not([type="checkbox"]):not([type="radio"]):not([type="range"]),
  select,
  textarea,
  .contact-form input[type="email"],
  .contact-form input[type="text"],
  .contact-form input[type="tel"],
  .contact-form textarea,
  .eca-row input,
  .login-card input {
    font-size: 16px;
  }
}

/* ── 2. Cibles tactiles ───────────────────────────────────────────────────
   Complète le lot 8 (chips /apps, indice de défilement, contacts de /contact)
   avec ce que l'audit a mesuré ensuite : liens du pied de page (22 px de haut
   pour 10 px d'écart), champ de recherche de /apps (boîte de 50 px mais zone
   cliquable de 22 px : taper dans la marge ne faisait rien), liens d'action
   des réalisations et pastille « démo » des tuiles. */
@media (max-width: 760px) {
  /* Pied de page : la liste de liens devient une liste de vraies lignes. */
  .footer-col { gap: 0; }
  .footer-col a {
    display: flex; align-items: center;
    min-height: 44px;
    font-size: 15px;
  }
  .site-footer-mail,
  .site-footer-legal a,
  .site-footer-admin {
    display: inline-flex; align-items: center; min-height: 44px;
  }
  .site-footer-access { gap: 20px; flex-wrap: wrap; }

  .work3d-cta,
  .about-contact .link-muted,
  /* Seul lien de son paragraphe en fin de page légale, donc hors de
     l'exemption du lien au fil d'une phrase : il rendait 17 px de haut. */
  .legal-back .link-muted { display: inline-flex; align-items: center; min-height: 44px; }
  .tile-demo { padding: 12px 13px; }
  /* 404 : le bouton de réparation est réservé à l'admin, mais c'est le seul
     geste possible depuis un téléphone quand le site est cassé. */
  #btnRepair { min-height: 44px; }
}

/* ── 3. Micro-typographie ─────────────────────────────────────────────────
   Les libellés mono en capitales descendaient à 7,5 px : lisibles sur un
   27 pouces, pas au bout du bras dans le métro. On remonte les plus petits au
   plancher de 10-11 px sans toucher au vocabulaire graphique (mono, capitales,
   interlettrage) ni au rendu desktop. */
@media (max-width: 760px) {
  .tile-tag { font-size: 10px; padding: 4px 9px; }
  .tile-flag { font-size: 10px; }
  .tile-flag--pro,
  .tile-flag--perso { font-size: 10.5px; }

  .tile-cta { font-size: 11px; }
  .tile-cta--sm { font-size: 10.5px; }
  .tile-meta { font-size: 10px; }
  .tile-bar .tile-meta { font-size: 10px; }
  .tile-demo { font-size: 10px; }
  .field-label { font-size: 11px; letter-spacing: 0.14em; }
  .footer-col-h { font-size: 11px; letter-spacing: 0.14em; }
  .site-footer-mail { font-size: 13px; }

  .scroll-cue { font-size: 10px; }

  /* En-têtes du comparatif : c'est de la donnée qu'on lit en glissant le
     tableau, pas un ornement. 9,5 px n'y suffisait pas. */
  .offer-sheet .cmp-table thead th { font-size: 11px; letter-spacing: 0.05em; }
  .offer-sheet .col-h { font-size: 11.5px; letter-spacing: 0.12em; }
}

/* ── Page Applications métier (/applications-metier) ─────────────────────────
   Le second métier (réorientation de septembre 2026). L'ossature réutilise la
   page offre (offre-hero, included-grid, steps, faq-list, cta-final) ; ici ne
   vivent que les blocs propres : cas avant/après, signes, prix, preuves. Tout
   en jetons : le thème sombre suit sans bloc dédié. */
.home-hero-alt {
  margin: 18px 0 0;
  font-size: 15px;
  color: var(--muted);
}
.home-hero-alt a { color: var(--fg); font-weight: 600; text-decoration: none; border-bottom: 1px solid var(--line-strong); }
.home-hero-alt a:hover { border-bottom-color: var(--fg); }

.app-cases {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
  gap: 18px;
}
.app-case {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 24px 24px 22px;
  border: 1px solid var(--line);
  border-radius: 18px;
  background: var(--card);
}
.app-case-ico {
  width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line);
  border-radius: 12px;
  color: var(--fg);
  font-size: 20px;
}
.app-case h3 { margin: 4px 0 0; font-family: var(--font-display); font-size: 19px; letter-spacing: -0.01em; }

/* Les six familles : une liste à parcourir, pas six cartes à peser. Le même
   composant servait aux deux sections voisines de la page, ce qui donnait
   douze boîtes identiques à la suite. `.app-case--famille` existait déjà comme
   point d'accroche, sans aucune règle. */
.app-cases--familles {
  /* `min(...)` et non `330px` sec : sur un écran de 320 px, un minimum de
     330 px impose 330 px à la colonne quel que soit le conteneur, et la page
     part en défilement horizontal (mesuré : 350 px de contenu dans 320). */
  grid-template-columns: repeat(auto-fit, minmax(min(330px, 100%), 1fr));
  gap: 0 40px;
}
.app-case--famille {
  display: grid;
  grid-template-columns: 32px minmax(0, 1fr);
  align-items: start;
  column-gap: 14px;
  row-gap: 5px;
  padding: 18px 0 20px;
  border: 0;
  border-top: 1px solid var(--line);
  border-radius: 0;
  background: transparent;
}
.app-case--famille .app-case-ico {
  width: 32px; height: 32px;
  border-radius: 9px;
  font-size: 17px;
  grid-row: span 2;
}
.app-case--famille h3 { margin: 2px 0 0; font-size: 17px; }
.app-case--famille .app-famille-txt { margin: 0; }
.app-avant, .app-apres {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.55;
  color: var(--muted);
}
.app-avant span, .app-apres span {
  display: inline-block;
  margin-right: 8px;
  padding: 1px 8px;
  border-radius: 999px;
  font: 600 10.5px var(--font-mono);
  letter-spacing: 0.06em;
  text-transform: uppercase;
  vertical-align: 2px;
}
.app-avant span { color: var(--muted-3); border: 1px solid var(--line-strong); }
.app-apres span { color: var(--card); background: var(--fg); }
.app-apres { color: var(--fg-soft); }

/* Familles d'applications (vague 2) : même carte que .app-case, mais un seul
   paragraphe au lieu du couple avant/après. */
.app-famille-txt {
  margin: 0;
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--muted);
}
.app-familles-note {
  max-width: 760px;
  margin: 20px auto 0;
  text-align: center;
  font-size: 14.5px;
  line-height: 1.6;
  color: var(--muted);
}
.app-familles-note a { color: var(--fg); font-weight: 600; text-decoration: none; border-bottom: 1px solid var(--line-strong); }
.app-familles-note a:hover { border-bottom-color: var(--fg); }
/* La cause du prix, dans le bloc prix : une note, pas un argument de vente.
   L'élément porte les DEUX classes (`app-price-desc app-price-why`) et
   `.app-price-desc` est déclarée plus bas dans ce fichier, à spécificité égale :
   c'est l'ordre qui tranchait, et la note sortait à 15 px comme le paragraphe
   qu'elle doit suivre en retrait. On nomme la porteuse plutôt que de déplacer
   la strate, qui se lit mieux ici, avec les autres notes de la page. */
.app-price-desc.app-price-why { font-size: 14px; line-height: 1.6; }
.app-price-why { border-top: 1px solid var(--line); padding-top: 12px; font-size: 14px; }
.app-price-why a { color: var(--fg); font-weight: 600; text-decoration: none; border-bottom: 1px solid var(--line-strong); }
.app-price-why a:hover { border-bottom-color: var(--fg); }
@media (hover: none) {
  .app-familles-note a:hover, .app-price-why a:hover { border-bottom-color: var(--line-strong); }}

.app-signes-section { padding-top: 8px; }
.app-signes {
  display: flex;
  gap: 22px;
  align-items: flex-start;
  max-width: 880px;
  margin: 0 auto;
  padding: 28px 30px;
  border: 1px solid var(--line-strong);
  border-radius: 20px;
  background: var(--paper-2);
}
.app-signes-ico {
  flex: none;
  width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  border-radius: 12px;
  background: var(--fg);
  color: var(--card);
  font-size: 20px;
}
.app-signes-title { margin: 4px 0 14px; font-family: var(--font-display); font-size: 24px; letter-spacing: -0.02em; }
.app-signes-list { margin: 0 0 14px; padding: 0; list-style: none; display: grid; gap: 9px; }
.app-signes-list li { position: relative; padding-left: 24px; color: var(--fg-soft); line-height: 1.5; }
.app-signes-list li::before {
  content: "";
  position: absolute; left: 0; top: 0.55em;
  width: 12px; height: 2px;
  background: var(--muted-3);
}
.app-signes > div > .muted { margin: 0; font-size: 14.5px; line-height: 1.55; }

.app-price {
  display: grid;
  grid-template-columns: minmax(0, 1.15fr) minmax(0, 1fr);
  gap: 22px;
  align-items: stretch;
}
.app-price-main {
  padding: 30px 32px;
  border: 1px solid var(--fg);
  border-radius: 20px;
  background: linear-gradient(120deg, var(--card) 62%, var(--paper-2));
}
.app-price-amount {
  font-family: var(--font-display);
  font-size: 44px;
  font-weight: 700;
  letter-spacing: -0.03em;
  line-height: 1.05;
  margin-bottom: 14px;
}
.app-price-prefix {
  display: block;
  font: 600 12px var(--font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 6px;
}
.app-price-desc { margin: 0 0 10px; color: var(--muted); font-size: 15px; line-height: 1.6; }
.app-price-desc strong { color: var(--fg-soft); }
.app-price-compare {
  padding: 26px 28px;
  border: 1px solid var(--line);
  border-radius: 20px;
  background: var(--card);
}
.app-price-compare .col-h {
  font: 600 12px var(--font-mono);
  letter-spacing: 0.08em;
  text-transform: uppercase;
  color: var(--muted);
  margin-bottom: 14px;
}
.app-price-compare ul { margin: 0; padding: 0; list-style: none; display: grid; gap: 14px; }
.app-price-compare li { display: grid; gap: 3px; padding-bottom: 14px; border-bottom: 1px solid var(--line); }
.app-price-compare li:last-child { border-bottom: 0; padding-bottom: 0; }
.app-price-compare b { font-size: 15px; color: var(--fg); }
/* L'accent ne se porte plus par la POSITION mais par une classe explicite :
   la règle mettait en avant le dernier item quelle que soit la liste, donc
   « Export à tout moment » sur /tarifs, qui n'a rien à mettre en avant. Et
   l'accent azur sur fond de carte donne 3,12:1, sous le seuil AA pour un texte
   de 15 px : la mise en avant passe par la graisse, pas par la couleur. */
.app-price-compare li.is-nous b { font-weight: 700; }
.app-price-compare span { font-size: 14px; line-height: 1.5; color: var(--muted); }

/* Quatre preuves depuis la vague 2 : un `auto-fit` sur 280 px donne trois
   colonnes au-delà de 1000 px, donc une rangée pleine et une carte orpheline
   en dessous (mesuré de 1024 à 1440 px). Deux colonnes au-delà de 900 px : deux
   rangées pleines. Même arbitrage que « Par où commencer ? » sur l'accueil. */
.app-proofs {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 18px;
}
@media (min-width: 900px) {
  .app-proofs { grid-template-columns: repeat(2, minmax(0, 1fr)); }}
.app-proof {
  display: flex;
  flex-direction: column;
  gap: 10px;
  padding: 24px;
  border: 1px solid var(--line);
  border-radius: 18px;
  background: var(--card);
}
.app-proof-head { display: flex; align-items: center; gap: 12px; }
.app-proof-head h3 { margin: 0; font-family: var(--font-display); font-size: 19px; }
.app-proof-ico {
  width: 40px; height: 40px;
  display: inline-flex; align-items: center; justify-content: center;
  border: 1px solid var(--line);
  border-radius: 12px;
  color: var(--fg);
}
.app-proof-ico svg { width: 22px; height: 22px; }
.app-proof-ico:has(.app-glyph-img) { background: #fbfaf7; padding: 5px; }
.app-proof-link {
  margin-top: auto;
  align-self: flex-start;
  min-height: 44px;
  display: inline-flex; align-items: center;
  font-weight: 600;
  color: var(--fg);
  text-decoration: none;
}
.app-proof-link:hover { color: var(--accent-azur); }

@media (max-width: 860px) {
  .app-price { grid-template-columns: 1fr; }}
@media (max-width: 640px) {
  .app-signes { flex-direction: column; gap: 14px; padding: 22px 20px; }
  .app-signes-title { font-size: 21px; }
  .app-price-main, .app-price-compare { padding: 22px 20px; }
  .app-price-amount { font-size: 36px; }}

/* Barre de contact des téléphones (< 768 px, pages commerciales) : Appeler,
   WhatsApp, Devis. Visible sans script ; landing.js la cache tant qu'on n'a
   pas défilé 300 px. Elle s'efface sous un tiroir, une modale ou la barre
   d'estimation de /tarifs, et la pastille « Admin » monte au-dessus d'elle. */
.mbar { display: none; }
@media (max-width: 767px) {
  body.has-mbar { padding-bottom: calc(72px + env(safe-area-inset-bottom)); }
  .mbar {
    display: flex; gap: 8px; position: fixed; left: 0; right: 0; bottom: 0; z-index: 40;
    padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
    background: var(--bg); border-top: 1px solid var(--line);
    transition: transform .3s var(--ease-standard), visibility 0s;
  }
  .mbar.is-hidden { transform: translateY(110%); visibility: hidden; transition: transform .3s var(--ease-standard), visibility 0s .3s; }
  .mbar a {
    flex: 1; display: inline-flex; align-items: center; justify-content: center; gap: 7px;
    min-height: 48px; border: 1px solid var(--line-strong); border-radius: 999px;
    color: var(--fg); font-size: 15px; font-weight: 600; text-decoration: none;
  }
  .mbar .mbar-devis { background: var(--fg); border-color: var(--fg); color: var(--on-accent); }
  body.has-mbar #mn-admin-pill { bottom: calc(82px + env(safe-area-inset-bottom)); }
  body.has-opt-bar .mbar, body.nav-open .mbar, body.has-modal .mbar { display: none; }
}
@media (prefers-reduced-motion: reduce) { .mbar, .mbar.is-hidden { transition: none; } }

/* Contexte tactile : le survol colle après un tap. Bloc en FIN de fichier (seul l'ordre tranche), variante sombre nommée à part. */
@media (hover: none) {
  .btn-primary:hover {
    transform: none;
    box-shadow: 0 1px 2px rgba(0,0,0,0.10), inset 0 1px 0 rgba(255,255,255,0.08);
  }
  [data-theme="dark"] .btn-primary:hover {
    box-shadow: 0 1px 2px rgba(0,0,0,0.3), inset 0 1px 0 rgba(255,255,255,0.15);
  }
  .btn-secondary:hover {
    transform: none; box-shadow: none;
    background: var(--card); border-color: var(--line);
  }
  .btn-ghost:hover { color: var(--muted); background: transparent; }
}