/*!
 * base.css — socle commun de roycepfirsch.com (accueil « RUSHES » de nuit + /breezz/ de jour)
 * Couches : reset · tokens · base · layout · components · utilities · motion
 *
 * Les feuilles de page (home.css, breezz.css) sont NON layerisées : leurs règles normales
 * l'emportent toujours sur ce fichier, quelle que soit la spécificité. Les seules règles
 * !important d'ici ([hidden], .sr-only, .w-*, filet reduced-motion) gagnent sur elles.
 *
 * Mode d'emploi complet : work/core_api.md (même contenu que l'en-tête de core.js).
 */
@layer reset, tokens, base, layout, components, utilities, motion;

/* =========================================================================
   RESET
   ========================================================================= */
@layer reset {
  *, *::before, *::after { box-sizing: border-box; }
  html { -webkit-text-size-adjust: 100%; text-size-adjust: 100%; }
  body, h1, h2, h3, h4, h5, h6, p, figure, blockquote, dl, dd, ol, ul { margin: 0; }
  h1, h2, h3, h4, h5, h6 { font-size: inherit; font-weight: inherit; }
  ol, ul { padding: 0; list-style: none; }
  img, picture, video, svg, canvas { display: block; max-width: 100%; }
  img, video { height: auto; }
  input, button, textarea, select { font: inherit; color: inherit; letter-spacing: inherit; }
  button { background: none; border: 0; padding: 0; cursor: pointer; text-align: inherit; -webkit-tap-highlight-color: transparent; }
  a { color: inherit; text-decoration-thickness: 1px; text-underline-offset: .18em; -webkit-tap-highlight-color: transparent; }
  table { border-collapse: collapse; }
  dialog { color: inherit; }
  [hidden] { display: none !important; }
}

/* =========================================================================
   TOKENS (spec §3) — couleurs, typo, espacements, mouvement, thèmes
   ========================================================================= */
@layer tokens {
  :root {
    /* Palette */
    --nuit: #07080A;
    --ardoise: #14181D;
    --ardoise-2: #1E242B;
    --pellicule: #EDEAE3;
    /* Gris des légendes, crédits et HUD sur fond sombre : ≥ 8:1 sur --nuit, ≥ 7,5:1 sur --ardoise
       (ancienne valeur #8C929A trop juste en 11–12 px sur fond texturé, tour 2 du jury). */
    --cendre: #A9AFB6;
    --neon: #1FD6C8;
    --bz-noir: #07080A;
    --bz-turquoise: #1FD6C8;
    --bz-ciel: #DDF3F1;
    --bz-papier: #F6F3EC;
    --bz-peche: #FFB48A;
    --bz-framboise: #E8336D;
    --encre: #0B0C0E;
    /* Encre secondaire : ≥ 6,5:1 sur pêche et turquoise, ≥ 10:1 sur ciel et papier */
    --encre-2: #353A40;
    --blanc: #FFFFFF;
    --filet-clair: rgba(11, 12, 14, .18);
    --filet-nuit: rgba(237, 234, 227, .18);
    --voile: rgba(7, 8, 10, .72);

    /* Familles (2 seulement) */
    --font: 'Archivo', system-ui, -apple-system, 'Segoe UI', Roboto, Arial, sans-serif;
    --font-serif: 'Instrument Serif', Georgia, 'Times New Roman', serif;

    /* Échelle (tour 4 : libellés HUD jamais sous 12 px, 13 px dès 1 625 px de large) */
    --t-hud: clamp(12px, .8vw, 13px);
    --t-s: 14px;
    --t-base: clamp(17px, .9rem + .2vw, 18px);
    --t-m: clamp(20px, 1.1rem + .6vw, 28px);
    --t-l: clamp(32px, 1.6rem + 2vw, 56px);
    --t-xl: clamp(52px, 2rem + 6vw, 128px);
    --t-xxl: clamp(4.5rem, 19vw, 17rem);

    /* Paliers de largeur */
    --w-serre: 62%;
    --w-mid: 87%;
    --w-normal: 100%;
    --w-large: 125%;

    /* Grille */
    --cols: 4;
    --goutt: 12px;
    --marge: 16px;

    /* Espacements (base 4) */
    --sp-1: 4px; --sp-2: 8px; --sp-3: 12px; --sp-4: 16px; --sp-5: 24px; --sp-6: 32px;
    --sp-7: 48px; --sp-8: 64px; --sp-9: 96px; --sp-10: 128px; --sp-11: 160px;
    --sec-y: clamp(64px, 9vw, 160px);

    /* Gabarits fixes */
    --topbar-h: 48px;
    --bottom-h: 56px;
    --dock-h: 64px;
    --safe-b: env(safe-area-inset-bottom, 0px);

    /* Rayons */
    --r-0: 0;
    --r-pill: 9999px;
    --r-bulle: 18px;

    /* Profondeur */
    --z-sticky: 10; --z-hud: 50; --z-bottom: 50; --z-cursor: 60; --z-grain: 70; --z-menu: 80; --z-loader: 90;

    /* Mouvement */
    --ease-out: cubic-bezier(.16, 1, .3, 1);
    --ease-inout: cubic-bezier(.76, 0, .24, 1);
    --d-flash: 80ms; --d-tap: 120ms; --d-ui: 240ms; --d-whip: 550ms; --d-raccord: 800ms; --d-title: 900ms; --d-iris: 1200ms;

    /* Thème par défaut = accueil, de nuit */
    --bg: var(--nuit);
    --fg: var(--pellicule);
    --muted: var(--cendre);
    --line: var(--ardoise-2);
    --surface: var(--ardoise);
    --accent: var(--neon);
    --focus: var(--neon);
    --btn-bg: var(--neon);
    --btn-fg: var(--nuit);
    --btn-bg-h: var(--pellicule);
    --btn-fg-h: var(--nuit);
    --menu-bg: var(--nuit);
    --menu-fg: var(--pellicule);
    --menu-muted: var(--cendre);
    --menu-line: var(--ardoise-2);
    --pill-bg: var(--ardoise);
    --pill-fg: var(--pellicule);
    --toast-bg: var(--ardoise);
    --toast-fg: var(--pellicule);
    --cursor-bg: var(--pellicule);
    --cursor-fg: var(--nuit);
    --grain-o: .06;
    /* Couleur du volet des View Transitions (page d'ARRIVÉE : ce sont ses styles qui s'appliquent) */
    --vt-volet: var(--nuit);
  }
  /* Mobile : libellés HUD et légendes à 13 px minimum, approche resserrée (lecture au pouce) */
  @media (max-width: 767px) {
    :root { --t-hud: 13px; --hud-ls: .04em; }
  }
  @media (min-width: 768px) {
    :root { --cols: 8; --goutt: 16px; --marge: 32px; --topbar-h: 56px; }
  }
  @media (min-width: 1200px) {
    :root { --cols: 12; --marge: clamp(24px, 3vw, 48px); }
  }

  /* Thème /breezz/ : de jour */
  html[data-page="breezz"] {
    --bg: var(--bz-ciel);
    --fg: var(--encre);
    --muted: var(--encre-2);
    --line: var(--filet-clair);
    --surface: var(--bz-papier);
    --accent: var(--encre);
    --focus: var(--encre);
    --btn-bg: var(--encre);
    --btn-fg: var(--bz-ciel);
    --btn-bg-h: var(--bz-framboise);
    --btn-fg-h: var(--encre);
    --menu-bg: var(--bz-papier);
    --menu-fg: var(--encre);
    --menu-muted: var(--encre-2);
    --menu-line: var(--filet-clair);
    --pill-bg: var(--encre);
    --pill-fg: var(--bz-ciel);
    --toast-bg: var(--encre);
    --toast-fg: var(--bz-ciel);
    --cursor-bg: var(--encre);
    --cursor-fg: var(--bz-ciel);
    --grain-o: .04;
    --vt-volet: var(--bz-ciel);
  }

  /* Aplats « LUT » (/breezz/) : chaque section redéfinit fond + encres.
     Jamais de texte néon sur clair, jamais de blanc ni d'encre-2 sur framboise. */
  [data-lut="ciel"]      { --bg: var(--bz-ciel);      --fg: var(--encre); --muted: var(--encre-2); --line: var(--filet-clair); --focus: var(--encre); --accent: var(--encre); }
  [data-lut="papier"]    { --bg: var(--bz-papier);    --fg: var(--encre); --muted: var(--encre-2); --line: var(--filet-clair); --focus: var(--encre); --accent: var(--encre); }
  [data-lut="peche"]     { --bg: var(--bz-peche);     --fg: var(--encre); --muted: var(--encre-2); --line: var(--filet-clair); --focus: var(--encre); --accent: var(--encre); }
  [data-lut="turquoise"] { --bg: var(--bz-turquoise); --fg: var(--encre); --muted: var(--encre-2); --line: var(--filet-clair); --focus: var(--encre); --accent: var(--encre); }
  [data-lut="framboise"] { --bg: var(--bz-framboise); --fg: var(--encre); --muted: var(--encre);   --line: var(--filet-clair); --focus: var(--encre); --accent: var(--encre); --btn-bg-h: var(--bz-papier); }
  [data-lut="noir"]      { --bg: var(--bz-noir);      --fg: var(--pellicule); --muted: var(--cendre); --line: var(--filet-nuit); --focus: var(--neon); --accent: var(--neon);
                           --btn-bg: var(--bz-ciel); --btn-fg: var(--encre); --btn-bg-h: var(--bz-peche); --btn-fg-h: var(--encre); }

  /* Thèmes de la topbar (CUT, piloté par core.js) */
  .topbar[data-theme="dark"]  { --hud-bg: var(--nuit);      --hud-fg: var(--pellicule); --rec: var(--neon);         --hud-focus: var(--neon);  --bar-line: rgba(237, 234, 227, .14); }
  .topbar[data-theme="light"] { --hud-bg: var(--bz-papier); --hud-fg: var(--encre);     --rec: var(--bz-framboise); --hud-focus: var(--encre); --bar-line: rgba(11, 12, 14, .14); }
  /* Point REC invisible sur un aplat de même couleur : il passe à l'encre */
  .topbar[data-bar-lut="framboise"] { --rec: var(--encre); }
  .topbar[data-bar-lut="turquoise"] { --rec: var(--encre); }
}

/* =========================================================================
   BASE — typographie et rôles (spec §3.2). Aucune transformation de casse :
   les capitales sont écrites dans copy.md telles qu'elles s'affichent.
   ========================================================================= */
@layer base {
  /* Pas de scrollbar-gutter : la gouttière réservée laissait une bande de la couleur de <html>
     au bord droit des sections colorées (navigateurs à barres masquées ou en superposition).
     La barre de défilement suit la section courante (--sb-track / --sb-thumb posés par core.js). */
  html {
    background: var(--bg);
    color: var(--fg);
    overflow-x: clip;
    scroll-padding-top: calc(var(--topbar-h) + 16px);
    scrollbar-color: var(--sb-thumb, rgba(140, 146, 154, .6)) var(--sb-track, var(--bg));
  }
  body {
    min-height: 100vh;
    min-height: 100svh;
    background: var(--bg);
    background-image: var(--noise, none);
    background-size: 128px 128px;
    color: var(--fg);
    font-family: var(--font);
    font-size: var(--t-base);
    font-weight: 400;
    font-stretch: 100%;
    line-height: 1.55;
    font-kerning: normal;
    -webkit-font-smoothing: antialiased;
    -moz-osx-font-smoothing: grayscale;
    overflow-x: clip;
    overflow-wrap: break-word;
  }
  ::selection { background: var(--accent); color: var(--bg); }
  [data-lut] { background-color: var(--bg); color: var(--fg); }
  [id] { scroll-margin-top: var(--topbar-h); }
  main:focus, [tabindex="-1"]:focus { outline: none; }
  :focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }
  p, li, dd, figcaption { text-wrap: pretty; }
  /* Image en échec de chargement : pas de texte alternatif brut à l'écran (il reste lu par les lecteurs d'écran) */
  main img { color: transparent; font-size: 0; }
  strong, b { font-weight: 700; }
  sup { font-size: .62em; line-height: 0; vertical-align: .62em; font-weight: 600; }

  /* Rôles typographiques */
  .hud {
    font-family: var(--font);
    font-weight: 600;
    font-stretch: 75%;
    font-size: var(--t-hud);
    line-height: 1.3;
    letter-spacing: var(--hud-ls, .08em);
    font-variant-numeric: tabular-nums;
  }
  .mega {
    font-family: var(--font);
    font-weight: 900;
    font-stretch: 62%;
    font-size: var(--t-xxl);
    line-height: .86;
    letter-spacing: 0;
    /* Tour 4 : à 62 % de largeur, l'espace d'Archivo se referme (« Lancerles formats ») */
    word-spacing: .1em;
    text-wrap: balance;
  }
  .mega--xl { font-size: var(--t-xl); word-spacing: .12em; }
  .mega, .mega--xl { overflow-wrap: normal; hyphens: manual; }
  .title {
    font-family: var(--font);
    font-weight: 900;
    font-stretch: 62%;
    font-size: var(--t-l);
    line-height: .92;
    letter-spacing: 0;
    word-spacing: .16em;
    text-wrap: balance;
  }
  /* Filet de sécurité : titres en Archivo 62 % des feuilles de page (semaines, concepts, besoins, menu…).
     Entre 24 et 56 px, l'espace inter-mots d'Archivo très condensé et très gras ne se voit presque plus
     (« Écouteret préparer », « Faire entrerles gens »). Zéro spécificité : une feuille de page qui fixe son
     propre word-spacing l'emporte toujours. */
  :where(.menu__label, .hero__title, .tplan__big, .trailer__title, .route__end, .diag__k, .concept__hook,
         .concept__label li, .anim__big, .anim__side, .concept__title, .plan__title, .week__title, .needs__t,
         .series__name, .goals__strike, .gcol__t, .banc__mark-name, .paques__v, .pell__card-big, .ugc__f,
         .next-card__title, .end__t) { word-spacing: .16em; }
  .wide {
    font-weight: 800;
    font-stretch: 125%;
    letter-spacing: -.01em;
    word-spacing: normal; /* à 125 %, l'espace d'origine suffit */
  }
  .sub {
    font-weight: 700;
    font-stretch: 87%;
    font-size: var(--t-m);
    line-height: 1.25;
  }
  .small { font-size: var(--t-s); line-height: 1.45; }
  .muted { color: var(--muted); }
}

/* =========================================================================
   LAYOUT — grille 4 / 8 / 12, marges, sections
   ========================================================================= */
@layer layout {
  .wrap { padding-inline: var(--marge); }
  .grid {
    display: grid;
    grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
    column-gap: var(--goutt);
    padding-inline: var(--marge);
  }
  /* Placement par variables : style="--c-m:1/-1; --c-t:1/7; --c-d:2/8" */
  .g-col { grid-column: var(--c-m, 1 / -1); min-width: 0; }
  @media (min-width: 768px) { .g-col { grid-column: var(--c-t, var(--c-m, 1 / -1)); } }
  @media (min-width: 1200px) { .g-col { grid-column: var(--c-d, var(--c-t, var(--c-m, 1 / -1))); } }

  .sec { position: relative; padding-block: var(--sec-y); }
  .sec--full { min-height: 100vh; min-height: 100svh; }
  /* Mobile : un écran « plein » s'arrête au-dessus de la barre du bas / du dock */
  @media (max-width: 767px) {
    html[data-page="home"] .sec--full { min-height: calc(100svh - var(--bottom-h) - var(--safe-b)); }
    html[data-page="breezz"] .sec--full { min-height: calc(100svh - var(--dock-h) - var(--safe-b)); }
  }
  main { display: block; }
}

/* =========================================================================
   COMPONENTS (spec §4, C01 → C22)
   ========================================================================= */
@layer components {

  /* ---------- C22 Lien d'évitement ---------- */
  .skip {
    position: fixed; top: 8px; left: 8px; z-index: 100;
    padding: 12px 16px; background: var(--fg); color: var(--bg);
    font-weight: 700; text-decoration: none;
    transform: translateY(-200%);
  }
  .skip:focus-visible, .skip:focus { transform: none; outline: 2px solid var(--focus); outline-offset: 2px; }

  /* ---------- Pavé : texte posé sur un aplat plein, comme un sous-titre incrusté ---------- */
  .pave {
    display: inline-flex; align-items: center; gap: .5em;
    padding: 3px 7px 2px;
    background: var(--hud-bg, var(--bg));
    color: var(--hud-fg, var(--fg));
    white-space: nowrap;
  }

  /* ---------- C01 Topbar HUD ----------
     Une seule règle : une BANDE pleine (::before) de la couleur de la section qui passe dessous
     (--bar-bg, posé par core.js en CUT), à 92 % + flou. Le texte de la page ne peut plus passer
     entre les étiquettes. Seule exception : au-dessus d'un héros vidéo ([data-pill-hide] ou
     [data-bar-clear] sous la barre), la bande s'efface (.is-clear) et les étiquettes reprennent
     leur pavé plein, lisible sur l'image. Jamais les deux fonds en même temps.
     Mobile (< 768) : la barre se range au scroll vers le bas et revient au scroll vers le haut. */
  .topbar {
    position: fixed; inset: 0 0 auto 0; z-index: var(--z-hud);
    height: var(--topbar-h);
    display: grid; grid-template-columns: minmax(0, 1fr) auto minmax(0, 1fr); align-items: center; column-gap: 8px;
    padding-inline: var(--marge);
    color: var(--hud-fg);
    pointer-events: none;
    transition: transform var(--d-ui) var(--ease-out);
  }
  /* Bande OPAQUE (tour 3) : à 92 % + flou, le texte de la page transparaissait derrière les libellés
     (« MENU » dédoublé, « Voir les 3 autres » fantôme sous le logo). */
  .topbar::before {
    content: ""; position: absolute; inset: 0; z-index: -1; pointer-events: none;
    background: var(--bar-bg, var(--hud-bg));
    box-shadow: inset 0 -1px 0 var(--bar-line, transparent);
  }
  .topbar.is-clear::before { visibility: hidden; }
  /* Rangement mobile : la barre sort d'un bloc (translateY), thème et bande inchangés pendant le mouvement */
  .topbar.is-hidden { transform: translateY(-100%); }
  .topbar > * { pointer-events: auto; }
  .topbar :focus-visible { outline-color: var(--hud-focus); }
  .topbar .pave, .topbar__btn, .site-logo, .chapter-pill {
    font-weight: 600; font-stretch: 75%; font-size: var(--t-hud); line-height: 1.3;
    letter-spacing: var(--hud-ls, .08em); font-variant-numeric: tabular-nums;
  }
  /* Sur la bande, les étiquettes n'ont plus d'aplat propre ; sur un héros, elles le reprennent */
  .topbar .pave { background: transparent; color: inherit; transition: none; }
  .topbar.is-clear .pave { background: var(--hud-bg); color: var(--hud-fg); }
  .site-logo {
    justify-self: start;
    display: inline-flex; align-items: center; min-height: 44px;
    text-decoration: none;
  }
  .topbar__mid { justify-self: center; display: flex; align-items: center; min-width: 0; }
  .topbar__tc { display: inline-flex; align-items: center; }
  .rec { color: var(--rec); font-size: 10px; line-height: 1; }
  .tc { font-variant-numeric: tabular-nums; }
  .topbar__right { justify-self: end; display: flex; align-items: center; gap: 4px; }
  .topbar__btn {
    position: relative;
    display: inline-flex; align-items: center; justify-content: center;
    min-height: 44px; min-width: 44px;
    text-decoration: none; color: inherit;
  }
  @media (hover: hover) {
    .topbar__btn:hover .pave, .site-logo:hover .pave, .chapter-pill:hover .pave { background: var(--hud-fg); color: var(--hud-bg); }
    .topbar__btn:hover .dot-bz { outline: 1px solid var(--hud-bg); }
  }
  .topbar__opt { display: none; }
  @media (min-width: 768px) { .topbar__opt { display: inline-flex; } }
  .dot-bz { display: inline-block; width: 6px; height: 6px; border-radius: 50%; background: var(--bz-turquoise); flex: none; }
  .topbar__progress { position: absolute; left: 0; right: 0; top: 0; height: 2px; pointer-events: none; }
  .topbar__progress span { display: block; height: 100%; background: var(--rec); transform-origin: 0 50%; transform: scaleX(0); }
  @media (min-width: 900px) { .topbar__progress { display: none; } }
  /* /breezz/ : sans le lien « ← SHOWREEL » (mobile), le logo porte la flèche de retour */
  @media (max-width: 767px) {
    html[data-page="breezz"] .site-logo .pave::before { content: "←"; }
  }
  /* Très petits écrans (< 360 px) : le mot REC s'efface, le point et le timecode restent */
  @media (max-width: 359px) {
    .topbar__tc [data-copy="GLOBAL.NAV.REC"] { display: none; }
    .topbar .pave { padding-inline: 4px; letter-spacing: .02em; }
    .topbar .pave, .topbar__btn, .site-logo, .chapter-pill { font-size: 12px; }
    html[data-page="breezz"] .site-logo .pave::before { content: none; }
  }

  /* ---------- C03 Menu « Sommaire » ---------- */
  .menu {
    position: fixed; inset: 0;
    width: 100%; height: 100%; max-width: none; max-height: none;
    margin: 0; padding: 0; border: 0;
    background: var(--menu-bg); color: var(--menu-fg);
    overflow-y: auto; overscroll-behavior: contain;
  }
  .menu::backdrop { background: var(--menu-bg); }
  .menu :focus-visible { outline-color: var(--focus); }
  .menu__inner {
    min-height: 100%;
    display: grid;
    grid-template-columns: repeat(var(--cols), minmax(0, 1fr));
    grid-template-rows: auto 1fr auto;
    column-gap: var(--goutt);
    padding: 0 var(--marge) calc(var(--sp-5) + var(--safe-b));
  }
  .menu__head {
    grid-column: 1 / -1;
    display: flex; align-items: center; justify-content: space-between;
    height: var(--topbar-h);
  }
  .menu__title { color: var(--menu-muted); }
  .menu__close { --hud-bg: var(--menu-fg); --hud-fg: var(--menu-bg); }
  .menu__nav { grid-column: 1 / -1; align-self: center; padding-block: var(--sp-4); }
  .menu__list { display: grid; }
  .menu__list li { overflow: visible; }
  .menu.is-anim .menu__list li { overflow: clip; }
  .menu__list a {
    position: relative;
    display: flex; align-items: baseline; gap: var(--sp-3);
    padding-block: 2px;
    text-decoration: none; color: inherit;
  }
  .menu__num { min-width: 2.4em; color: var(--menu-muted); flex: none; }
  .menu__label {
    font-weight: 900; font-stretch: 62%;
    font-size: min(var(--t-xl), calc((100svh - 300px) / var(--n, 10) / .92));
    line-height: .92; text-wrap: balance;
  }
  @media (min-width: 768px) { .menu__label { white-space: nowrap; } }
  @media (max-width: 767px) {
    .menu__num { min-width: 2em; }
    .menu__label { font-size: min(var(--t-xl), calc((100svh - 300px) / var(--n, 10) / .92), 11.5vw); }
    .menu__list a { padding-block: 3px; }
  }
  .menu__list a[aria-current] .menu__num { color: var(--accent); }
  .menu__list a[aria-current] .menu__num::before { content: "● "; }
  @media (min-width: 900px) and (hover: hover) {
    .menu__list a:hover .menu__label { font-stretch: 87%; }
    .menu__list a:hover .menu__num { color: var(--accent); }
  }
  @media (min-width: 900px) {
    .menu__list a:focus-visible .menu__label { font-stretch: 87%; }
    .menu__list a:focus-visible .menu__num { color: var(--accent); }
  }
  .menu__poster { display: none; }
  @media (min-width: 1200px) {
    .menu__nav { grid-column: 1 / span 8; }
    .menu__poster {
      display: block; grid-column: 9 / span 4; grid-row: 2; align-self: center;
      aspect-ratio: 4 / 5; max-height: 62svh; justify-self: end; width: 100%;
      background: var(--surface); visibility: hidden;
    }
    .menu__poster.is-on { visibility: visible; }
    .menu__poster img { width: 100%; height: 100%; object-fit: cover; }
  }
  .menu__foot {
    grid-column: 1 / -1;
    display: grid; grid-template-columns: repeat(auto-fit, minmax(150px, 1fr));
    gap: var(--sp-4) var(--sp-6);
    padding-top: var(--sp-4);
    border-top: 1px solid var(--menu-line);
    font-size: var(--t-s);
  }
  .menu__col { display: grid; align-content: start; justify-items: start; gap: var(--sp-2); }
  .menu__k { color: var(--menu-muted); }
  .menu__col .topbar__btn { min-height: 36px; justify-content: flex-start; }
  /* Liens texte du pied de menu : cibles de 44 px sans chevauchement (voir .link sur pointeur tactile :
     la zone de 44 px prend sa place, plus besoin d'écart compensatoire) */
  @media (pointer: coarse) { .menu__col { gap: 0; } .menu__col .menu__k { margin-bottom: 4px; } .menu__col .topbar__btn { min-height: 44px; } }
  .menu__toggle { --hud-bg: var(--menu-fg); --hud-fg: var(--menu-bg); }
  .menu__cross { align-self: end; font-weight: 700; font-size: var(--t-base); }
  @media (max-width: 767px) { .menu__cross { grid-column: 1 / -1; justify-self: start; } }

  /* ---------- C04 Chapitre en cours : dans la topbar, à droite du timecode (desktop ≥ 900) ----------
     Plus de pastille flottante en bas d'écran : elle recouvrait du contenu. Clic = Sommaire.
     Masqué tant qu'un [data-pill-hide] (héros) croise le milieu de l'écran. */
  .chapter-pill {
    position: relative;
    display: none; align-items: center;
    min-height: 44px; padding: 0;
    color: inherit; white-space: nowrap;
  }
  .chapter-pill .pave { gap: .6em; }
  .chapter-pill .pave::before { content: ""; flex: none; width: 1px; height: 1.1em; margin-right: .2em; background: currentColor; opacity: .4; }
  .topbar.is-clear .chapter-pill .pave::before { display: none; }
  @media (min-width: 900px) { .chapter-pill { display: inline-flex; } }
  /* Mobile et tablette (< 900 px), tour 4 : passé le héros, le CHAPITRE EN COURS remplace le timecode au centre
     de la barre (REC / J01 n'apprenaient rien au visiteur). Libellé seul, tronqué proprement si besoin.
     Sur le héros ([data-pill-hide]), le timecode reste. */
  @media (max-width: 899px) {
    .topbar { grid-template-columns: auto minmax(0, 1fr) auto; }
    .topbar__mid { justify-self: stretch; justify-content: center; }
    .chapter-pill { display: inline-flex; min-width: 0; max-width: 100%; }
    .chapter-pill .pave { min-width: 0; max-width: 100%; }
    .chapter-pill .pave::before, .chapter-pill__num, .chapter-pill .pave > span[aria-hidden] { display: none; }
    .chapter-pill__label { display: block; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
    .topbar__mid:has(.chapter-pill:not(.is-hidden)) .topbar__tc { display: none; }
  }
  .chapter-pill.is-hidden { display: none; }

  /* ---------- C05 Barre du bas (accueil) / dock CTA (/breezz/) — mobile < 768 ---------- */
  .tabbar, .cta-dock { display: none; }
  @media (max-width: 767px) {
    html[data-page="home"] body { padding-bottom: calc(var(--bottom-h) + var(--safe-b)); }
    /* /breezz/ : tour 5, plus de réserve fixe sous le pied de page (≈ 250 px de vide en fin de page).
       Le dock s'efface (.is-away, core.js) dès que la section contact (qui a ses propres boutons Écrire / CV)
       ou le pied de page est à l'écran : rien à réserver en bas. Sans JS, le dock n'est jamais masqué :
       la réserve reste (html:not(.js)). */
    html[data-page="breezz"] .site-footer { padding-bottom: calc(var(--sp-7) + var(--safe-b)); }
    html[data-page="breezz"]:not(.js) .site-footer { padding-bottom: calc(var(--sp-7) + var(--dock-h) + var(--safe-b)); }
    .tabbar {
      position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-bottom);
      display: grid; grid-template-columns: repeat(5, minmax(0, 1fr));
      padding-bottom: var(--safe-b);
      background: var(--nuit); color: var(--pellicule);
      border-top: 1px solid var(--ardoise-2);
      transition: transform var(--d-ui) var(--ease-out);
    }
    .tabbar.is-hidden { transform: translateY(100%); }
    .tabbar a {
      position: relative;
      min-height: var(--bottom-h); min-width: 44px;
      display: flex; align-items: center; justify-content: center; gap: 6px;
      font-weight: 600; font-stretch: 75%; font-size: var(--t-hud); letter-spacing: .06em;
      text-decoration: none; color: inherit;
    }
    .tabbar a:active { background: var(--ardoise); }
    /* Dock /breezz/ : bande pleine sur toute la largeur (plus de texte visible autour des pilules),
       même hauteur que le padding-bottom du body. Il s'efface quand les boutons Écrire / CV de la page
       sont à l'écran (pas de doublon), puis revient. */
    .cta-dock {
      position: fixed; left: 0; right: 0; bottom: 0; z-index: var(--z-bottom);
      display: flex; gap: 8px; padding: 8px 12px calc(8px + var(--safe-b));
      background: var(--bz-papier); color: var(--encre);
      box-shadow: 0 -1px 0 var(--filet-clair);
      transition: transform var(--d-ui) var(--ease-out);
      --btn-bg: var(--encre); --btn-fg: var(--bz-ciel); --btn-bg-h: var(--bz-framboise); --btn-fg-h: var(--encre); --focus: var(--encre);
    }
    .cta-dock.is-away { transform: translateY(110%); }
    .cta-dock .btn { min-height: 48px; padding-inline: 16px; }
    .cta-dock .btn--primary { flex: 1.6 1 0; }
    .cta-dock .btn--ghost { flex: 1 1 0; }
    .cta-dock__short { display: none; }
    .cta-dock.is-compact { padding-block: 6px calc(6px + var(--safe-b)); }
    .cta-dock.is-compact .btn { min-height: 44px; }
    .cta-dock.is-compact .cta-dock__long { display: none; }
    .cta-dock.is-compact .cta-dock__short { display: inline; }
  }

  /* ---------- C06 Boutons et liens ---------- */
  .btn {
    position: relative;
    display: inline-flex; align-items: center; justify-content: center; gap: 8px;
    min-height: 52px; padding: 0 24px;
    font-family: var(--font); font-weight: 700; font-stretch: 100%; font-size: 16px; line-height: 1.1;
    text-decoration: none; white-space: nowrap;
    border: 1px solid transparent;
    transition: transform var(--d-tap) linear, background-color var(--d-tap) linear, color var(--d-tap) linear;
  }
  .btn:active { transform: scale(.97); }
  @media (max-width: 767px) { .btn { min-height: 48px; } }
  .btn--primary { background: var(--btn-bg); color: var(--btn-fg); border-radius: var(--r-pill); }
  /* Deux variantes seulement, même hauteur : primaire = pilule pleine, secondaire = pilule contour */
  .btn--ghost { background: transparent; color: inherit; border-color: currentColor; border-radius: var(--r-pill); }
  /* Survol « REC » (pointeur fin) : l'aplat de survol balaie la pilule de gauche à droite (clip-path,
     240 ms rp-out) et un point REC s'allume à gauche du libellé. ::after = aplat (sous le texte,
     isolation), ::before reste réservé au focus « viseur ». */
  .btn--primary, .btn--ghost {
    isolation: isolate;
    --btn-fill: var(--btn-bg-h); --btn-fill-fg: var(--btn-fg-h); --btn-rec: var(--bz-framboise);
  }
  .btn--ghost { --btn-fill: var(--fg); --btn-fill-fg: var(--bg); }
  html[data-page="breezz"] .btn--primary { --btn-rec: var(--encre); }
  [data-lut="framboise"] .btn--primary { --btn-rec: var(--bz-framboise); }
  .btn--primary::after, .btn--ghost::after {
    content: ""; position: absolute; inset: -1px; z-index: -1; border-radius: inherit; pointer-events: none;
    background:
      radial-gradient(circle closest-side, var(--btn-rec) 0 3.5px, transparent 4px) 9px 50% / 8px 8px no-repeat,
      var(--btn-fill);
    clip-path: inset(0 100% 0 0 round var(--r-pill));
    transition: clip-path var(--d-ui) var(--ease-out);
  }
  @media (hover: hover) {
    .btn--primary, .btn--ghost { transition: transform var(--d-tap) linear, color var(--d-ui) var(--ease-out), border-color var(--d-ui) var(--ease-out); }
    .btn--primary:hover, .btn--ghost:hover { color: var(--btn-fill-fg); }
    .btn--ghost:hover { border-color: var(--btn-fill); }
    .btn--primary:hover::after, .btn--ghost:hover::after { clip-path: inset(0 0 0 0 round var(--r-pill)); }
  }
  .btn--icon {
    position: relative;
    display: inline-grid; place-items: center;
    width: 44px; height: 44px; padding: 0;
    background: var(--nuit); color: var(--pellicule);
    font-family: var(--font); font-size: 16px; line-height: 1;
    border-radius: var(--r-0);
    transition: transform var(--d-tap) linear;
  }
  .btn--icon:active { transform: scale(.97); }
  @media (hover: hover) { .btn--icon:hover { background: var(--pellicule); color: var(--nuit); } }
  .btn--icon:disabled { opacity: .35; cursor: default; }
  .link {
    position: relative; display: inline;
    text-decoration: none;
    background-image: linear-gradient(currentColor, currentColor);
    background-size: 100% 1px; background-position: 0 100%; background-repeat: no-repeat;
    padding-bottom: 2px;
  }
  .link::after {
    content: ""; position: absolute; left: 0; right: 0; bottom: -1px; height: 2px;
    background: currentColor; transform: scaleX(0); transform-origin: 0 50%;
    transition: transform var(--d-ui) var(--ease-out);
  }
  .link:hover::after, .link:focus-visible::after { transform: scaleX(1); }
  /* Pointeur tactile : la boîte du lien fait ≥ 44 px de haut (padding vertical ≈ (44 px − 1 ligne) / 2).
     Tour 5 : plus AUCUNE marge négative. Les anciennes marges (−14 / −15 px) gardaient la mise en page
     intacte mais faisaient déborder la zone tactile sur la cible voisine dès que deux liens / boutons
     étaient empilés à moins de 30 px (« Voir en entier, avec le son » recouvert de 27 px par « Voir sur
     Instagram »). Désormais :
     - lien DANS une phrase (display: inline) : le padding n'agrandit pas la ligne (règle CSS des boîtes en
       ligne), la mise en page ne bouge pas ; la zone déborde seulement sur le texte voisin ;
     - lien posé seul (élément de grille / flex, inline-flex, bouton) : la zone de 44 px PREND sa place
       dans la mise en page, elle ne peut plus mordre sur la cible d'à côté.
     Le filet reste collé au texte (origine content-box). */
  @media (pointer: coarse) {
    .link {
      --link-py: 12px;
      padding-block: var(--link-py); margin-block: 0;
      background-origin: content-box; background-position: 0 calc(100% + 2px);
    }
    @supports (padding-top: 1lh) {
      .link { --link-py: max(6px, calc(22px - .5lh)); }
    }
    .link::after { bottom: calc(var(--link-py) - 1px); }
  }

  /* ---------- C17 Focus « viseur » : 4 coins de 10 px, traits de 2 px, décalés de 4 px ---------- */
  :where(.btn, .btn--icon, .topbar__btn, .site-logo, .tabbar a, .menu__list a, .chapter-pill, .story__tap, .story__skip, .lightbox__item, .sheet__handle):focus-visible {
    outline: none;
  }
  :where(.btn, .btn--icon, .topbar__btn, .site-logo, .tabbar a, .menu__list a, .chapter-pill, .story__tap, .story__skip, .lightbox__item, .sheet__handle):focus-visible::before {
    content: ""; position: absolute; inset: -4px; pointer-events: none; z-index: 2;
    --fc: var(--hud-focus, var(--focus));
    background:
      linear-gradient(var(--fc) 0 0) 0 0 / 10px 2px, linear-gradient(var(--fc) 0 0) 0 0 / 2px 10px,
      linear-gradient(var(--fc) 0 0) 100% 0 / 10px 2px, linear-gradient(var(--fc) 0 0) 100% 0 / 2px 10px,
      linear-gradient(var(--fc) 0 0) 0 100% / 10px 2px, linear-gradient(var(--fc) 0 0) 0 100% / 2px 10px,
      linear-gradient(var(--fc) 0 0) 100% 100% / 10px 2px, linear-gradient(var(--fc) 0 0) 100% 100% / 2px 10px;
    background-repeat: no-repeat;
  }
  .site-logo, .menu__list a, .tabbar a, .story__skip, .lightbox__item, .sheet__handle { position: relative; }
  .story__tap:focus-visible::before { inset: 6px; }

  /* Viseur décoratif (coins de cadre) : <span class="viseur" aria-hidden="true" style="--vs:24px"></span> */
  .viseur {
    position: absolute; inset: var(--vi, 0); pointer-events: none;
    --vc: var(--viseur-c, currentColor); --vs: 12px; --vw: 1px;
    background:
      linear-gradient(var(--vc) 0 0) 0 0 / var(--vs) var(--vw), linear-gradient(var(--vc) 0 0) 0 0 / var(--vw) var(--vs),
      linear-gradient(var(--vc) 0 0) 100% 0 / var(--vs) var(--vw), linear-gradient(var(--vc) 0 0) 100% 0 / var(--vw) var(--vs),
      linear-gradient(var(--vc) 0 0) 0 100% / var(--vs) var(--vw), linear-gradient(var(--vc) 0 0) 0 100% / var(--vw) var(--vs),
      linear-gradient(var(--vc) 0 0) 100% 100% / var(--vs) var(--vw), linear-gradient(var(--vc) 0 0) 100% 100% / var(--vw) var(--vs);
    background-repeat: no-repeat;
  }

  /* ---------- C07 Étiquettes de crédit ---------- */
  .tag {
    display: inline-block;
    padding: 4px 8px;
    border: 1px solid currentColor;
    font-weight: 600; font-stretch: 75%; font-size: 12px; line-height: 1.25; letter-spacing: .08em;
    white-space: nowrap;
  }
  .tag--hud { background: var(--nuit); color: var(--pellicule); }
  .tag--sticker {
    background: var(--tag-bg, var(--bz-peche)); color: var(--encre);
    border: 2px solid var(--encre);
    font-size: 12px;
    transform: rotate(var(--tag-rot, -2deg));
  }
  .tag--r0 { --tag-rot: -2deg; } .tag--r1 { --tag-rot: 1.5deg; } .tag--r2 { --tag-rot: -1deg; } .tag--r3 { --tag-rot: 2deg; }
  @media (max-width: 767px) { .tag { font-size: 13px; letter-spacing: .04em; } }

  /* ---------- C08 Figure vidéo / image ---------- */
  .reel, .still { position: relative; margin: 0; min-width: 0; }
  /* Fond de secours (tour 4) : tant que l'affiche n'est pas arrivée, ou si elle échoue, le cadre n'est jamais un
     rectangle noir : amorce de pellicule (ton moyen du thème courant, hachures fines, lumière en haut). */
  .reel__frame, .still__frame {
    position: relative; overflow: hidden;
    background-color: var(--ardoise-2);
    background-color: color-mix(in srgb, var(--fg) 13%, var(--bg));
    background-image:
      linear-gradient(180deg, rgba(255, 255, 255, .07), rgba(255, 255, 255, 0) 45%),
      repeating-linear-gradient(135deg, rgba(127, 127, 127, .08) 0 1px, transparent 1px 12px);
  }
  .reel__frame > video, .reel__frame > img, .reel__frame > picture, .reel__frame > picture > img,
  .still__frame > img, .still__frame > picture, .still__frame > picture > img {
    display: block; width: 100%; height: 100%; object-fit: cover;
  }
  /* Poster de repli sans JS (<noscript>) : avec JS, core.js pose l'attribut poster à l'approche (data-poster) */
  .vposter { position: absolute; inset: 0; z-index: 1; display: block; width: 100%; height: 100%; object-fit: cover; pointer-events: none; }
  .reel__play {
    position: absolute; left: 50%; top: 50%; z-index: 3;
    transform: translate(-50%, -50%);
    width: 56px; height: 56px; font-size: 18px;
  }
  .reel__play:active { transform: translate(-50%, -50%) scale(.97); }
  .reel__fallback {
    position: absolute; left: 8px; bottom: 8px; z-index: 2;
    padding: 6px 10px; background: var(--nuit); color: var(--pellicule);
    font-size: var(--t-s); font-weight: 600;
  }
  .reel__cap, .still__cap { display: grid; gap: 4px; padding-top: 8px; }
  .reel__credit { color: var(--muted); font-size: var(--t-hud); font-weight: 600; font-stretch: 75%; letter-spacing: .06em; line-height: 1.35; }
  .evin { color: var(--muted); font-size: 12px; font-weight: 600; font-stretch: 75%; letter-spacing: .04em; line-height: 1.35; }
  @media (max-width: 767px) { .evin { font-size: 13px; } .reel__credit { font-size: 13px; letter-spacing: .03em; } }

  /* ---------- C09 Lightbox ---------- */
  .lightbox {
    position: fixed; inset: 0;
    width: 100%; height: 100%; max-width: none; max-height: none;
    margin: 0; padding: 0; border: 0;
    /* Tour 5 : fond plein (plus rien de la page ne transparaît autour du Reel ni sous « À suivre »).
       z-index : repli si showModal() échoue (dialogue alors hors de la couche supérieure). */
    background: var(--nuit); color: var(--pellicule);
    z-index: calc(var(--z-loader) + 1);
    overflow: hidden; overscroll-behavior: contain;
    --focus: var(--neon); --hud-focus: var(--neon);
    --muted: var(--cendre);
    --hud-bg: var(--pellicule); --hud-fg: var(--nuit);
  }
  .lightbox::backdrop { background: var(--nuit); }
  .lightbox[open] {
    display: grid;
    grid-template-columns: minmax(0, 1fr);
    grid-template-rows: auto minmax(0, 1fr) auto;
  }
  .lightbox__top {
    display: flex; align-items: center; justify-content: space-between; gap: var(--sp-4);
    min-height: 56px; padding: 6px var(--marge);
  }
  .lightbox__meta { display: flex; flex-wrap: wrap; gap: .3em 1em; align-items: baseline; min-width: 0; }
  .lightbox__count { color: var(--neon); }
  .lightbox__title { font-weight: 700; font-stretch: 87%; font-size: var(--t-s); letter-spacing: 0; color: var(--pellicule); }
  .lightbox__date { color: var(--cendre); }
  .lightbox__actions { display: flex; gap: 4px; flex: none; }
  .lightbox .btn--icon { background: var(--ardoise); color: var(--pellicule); }
  @media (hover: hover) { .lightbox .btn--icon:hover { background: var(--pellicule); color: var(--nuit); } }
  .lightbox__main {
    position: relative; min-height: 0;
    touch-action: pan-y;
  }
  /* La scène remplit toute la zone ; le média s'y inscrit en « contain » (9:16, 4:5, 1:1, 4:3). */
  .lightbox__stage {
    position: absolute; inset: 0 calc(var(--marge) + 56px);
    max-height: 900px; margin-block: auto;
    container-type: size;
    display: grid; place-items: center;
  }
  /* Le média prend exactement le format du fichier (--arw / --arh posés par core.js) : les contrôles natifs collent à l'image */
  .lightbox__stage > video, .lightbox__stage > img {
    display: block;
    width: min(100cqw, calc(100cqh * var(--arw, 9) / var(--arh, 16)));
    height: min(100cqh, calc(100cqw * var(--arh, 16) / var(--arw, 9)));
    object-fit: contain; background: #000;
  }
  .lightbox__prev, .lightbox__next { position: absolute; top: 50%; transform: translateY(-50%); z-index: 2; }
  .lightbox__prev { left: var(--marge); }
  .lightbox__next { right: var(--marge); }
  .lightbox__prev:active, .lightbox__next:active { transform: translateY(-50%) scale(.97); }
  .lightbox__below {
    display: grid; justify-items: center; gap: 2px;
    padding: 8px var(--marge) calc(12px + var(--safe-b));
    text-align: center;
  }
  .lightbox__credit { color: var(--pellicule); font-size: var(--t-hud); }
  /* Lien vers la publication originale (créé par core.js quand le média a un identifiant Instagram) */
  .lightbox__ig { color: var(--pellicule); font-size: var(--t-hud); margin-top: 2px; }
  .lightbox__ig span[aria-hidden] { margin-left: .35em; }
  .lightbox__nocounter { display: none; }
  .lightbox__upnext-toggle { display: none; }
  .lightbox__upnext {
    display: none;
  }
  .lightbox__list { display: grid; gap: 2px; }
  .lightbox__item {
    width: 100%;
    display: flex; justify-content: space-between; align-items: baseline; gap: 12px;
    padding: 10px 12px; min-height: 44px;
    background: var(--ardoise); color: var(--pellicule);
    font-size: var(--t-s); line-height: 1.3; text-align: left;
  }
  @media (hover: hover) { .lightbox__item:hover { background: var(--ardoise-2); } }
  .lightbox__item[aria-current] { box-shadow: none; background: var(--pellicule); color: var(--nuit); }
  .lightbox__item[aria-current] .hud { color: var(--nuit); }
  .lightbox__item .hud { color: var(--cendre); flex: none; }
  @media (min-width: 1200px) {
    .lightbox[open] { grid-template-columns: minmax(0, 1fr) 320px; }
    .lightbox__top { grid-column: 1 / -1; }
    .lightbox__main { grid-column: 1; grid-row: 2; }
    .lightbox__below { grid-column: 1; grid-row: 3; }
    .lightbox__upnext {
      display: block; grid-column: 2; grid-row: 2 / 4;
      overflow-y: auto; padding: 0 var(--marge) var(--sp-5) 0;
    }
    .lightbox__upnext-k { color: var(--cendre); margin-bottom: 8px; }
    .lightbox.is-img[open] { grid-template-columns: minmax(0, 1fr); }
  }
  /* Mode image (classe posée par core.js) : pas de liste « À suivre » */
  .lightbox.is-img .lightbox__upnext, .lightbox.is-img .lightbox__upnext-toggle { display: none; }
  @media (max-width: 1199px) {
    .lightbox__upnext-toggle { display: inline-flex; margin-top: 6px; }
    .lightbox.show-list .lightbox__upnext {
      display: block; position: absolute; left: 0; right: 0; top: 56px; z-index: 5;
      max-height: 62svh; overflow-y: auto; overscroll-behavior: contain;
      padding: 12px var(--marge) 16px;
      background: var(--nuit); border-bottom: 1px solid var(--ardoise-2);
    }
    .lightbox__upnext-k { color: var(--cendre); margin-bottom: 8px; }
  }
  @media (max-width: 767px) {
    .lightbox__stage { inset: 0; }
    /* Flèches sorties de l'image (les contrôles natifs sont en bas de la vidéo) : dans la rangée du bas */
    .lightbox__prev, .lightbox__next { position: fixed; top: auto; bottom: calc(10px + var(--safe-b)); transform: none; }
    .lightbox__prev:active, .lightbox__next:active { transform: scale(.97); }
    .lightbox__prev { left: 8px; }
    .lightbox__next { right: 8px; }
    .lightbox__below { padding-inline: 60px; min-height: 64px; }
  }

  /* ---------- C10 Lecteur de stories ---------- */
  .story {
    position: relative;
    display: grid;
    background: var(--ardoise);
    color: var(--pellicule);
    overflow: hidden;
    touch-action: pan-y;
    -webkit-user-select: none; user-select: none;
    -webkit-touch-callout: none;
    --focus: var(--neon);
    --story-bar: rgba(237, 234, 227, .35);   /* segments : fond */
    --story-fill: var(--pellicule);          /* segments : progression (à redéfinir sur fond clair) */
  }
  .story:focus-visible { outline: 2px solid var(--focus); outline-offset: 3px; }
  .story__items { display: grid; gap: var(--sp-4); min-width: 0; }
  .story__item { position: relative; min-width: 0; }
  .story__item > video, .story__item > img, .story__item > picture img { display: block; width: 100%; height: 100%; object-fit: cover; }
  .rp .story.is-ready .story__items { gap: 0; }
  .rp .story.is-ready .story__item { grid-area: 1 / 1; }
  .rp .story.is-ready .story__item:not(.is-active) { visibility: hidden; }
  /* Entre le 1er rendu et l'init de core.js (scripts defer, CDN) : même géométrie qu'une fois prêt,
     1er plan seul visible. Évite le saut de mise en page et un instantané faux pour les View Transitions.
     Si core.js ne démarre pas, le script de tête retire .js au bout de 3 s : retour aux plans empilés. */
  .js .story:not(.is-ready) .story__items { gap: 0; }
  .js .story:not(.is-ready) .story__item { grid-area: 1 / 1; }
  .js .story:not(.is-ready) .story__item:not(:first-child) { visibility: hidden; }
  .story__bars {
    position: absolute; top: 8px; left: 8px; right: 8px; z-index: 4;
    display: flex; gap: 3px; pointer-events: none;
  }
  .story__bars li { position: relative; flex: 1 1 0; height: 2px; background: var(--story-bar); overflow: hidden; }
  .story__bars li::after {
    content: ""; position: absolute; inset: 0;
    background: var(--story-fill);
    transform-origin: 0 50%; transform: scaleX(var(--p, 0));
  }
  .story__tap { position: absolute; top: 0; bottom: 0; z-index: 2; background: transparent; }
  .story__tap--prev { left: 0; width: 30%; }
  .story__tap--next { right: 0; width: 70%; }
  .story__controls {
    position: absolute; top: 18px; right: 8px; z-index: 4;
    display: flex; align-items: center; gap: 4px;
  }
  .story__count { padding: 3px 7px 2px; background: var(--nuit); color: var(--pellicule); }
  .story__pause { width: 44px; height: 44px; }
  /* ▶ central : lecture automatique refusée (mode économie d'énergie) ; au-dessus des zones de tap */
  .story__play {
    position: absolute; left: 50%; top: 50%; z-index: 5;
    transform: translate(-50%, -50%);
    width: 56px; height: 56px; font-size: 18px;
  }
  .story__play:active { transform: translate(-50%, -50%) scale(.97); }
  .story__skip {
    display: inline-flex; align-items: center; min-height: 44px; padding: 0 12px;
    background: var(--nuit); color: var(--pellicule);
    font-weight: 600; font-stretch: 75%; font-size: var(--t-hud); letter-spacing: .08em;
  }
  @media (hover: hover) { .story__skip:hover { background: var(--pellicule); color: var(--nuit); } }
  html:not(.js):not(.rp) .story__bars, html:not(.js):not(.rp) .story__tap, html:not(.js):not(.rp) .story__controls { display: none; }

  /* ---------- C11 Bottom sheet ---------- */
  .sheet {
    position: fixed; inset: auto 0 0 0;
    width: 100%; max-width: none; max-height: 88svh; height: auto;
    margin: 0; padding: 0; border: 0;
    background: var(--bz-papier); color: var(--encre);
    --focus: var(--encre); --fg: var(--encre); --bg: var(--bz-papier); --muted: var(--encre-2); --line: var(--filet-clair);
    overflow: hidden;
    transform: translateY(100%);
    transition: transform .45s var(--ease-out);
  }
  .sheet.is-in { transform: none; }
  .sheet::backdrop { background: var(--voile); }
  .sheet__panel {
    position: relative;
    max-height: 88svh; overflow-y: auto; overscroll-behavior: contain;
    padding: 8px var(--marge) calc(24px + var(--safe-b));
  }
  .sheet__handle {
    display: block; width: 100%; height: 28px; margin: 0 auto 4px;
    background: transparent; cursor: grab;
  }
  .sheet__handle::after {
    content: ""; position: absolute; left: 50%; top: 12px;
    width: 40px; height: 4px; margin-left: -20px; background: var(--encre);
  }
  .sheet__close { position: absolute; top: 6px; right: var(--marge); background: var(--encre); color: var(--bz-ciel); }
  @media (hover: hover) { .sheet__close:hover { background: var(--bz-framboise); color: var(--encre); } }
  .sheet__body { padding-top: 8px; }
  @media (min-width: 900px) {
    .sheet { inset: 0 0 0 auto; width: 480px; height: 100%; max-height: none; transform: translateX(100%); }
    .sheet__panel { height: 100%; max-height: none; padding-top: 16px; }
    .sheet__handle { display: none; }
    .sheet__body { padding-top: 48px; }
  }

  /* ---------- C12 Toast ---------- */
  .toast {
    position: fixed; left: 50%; bottom: calc(24px + var(--safe-b)); z-index: var(--z-cursor);
    transform: translateX(-50%);
    max-width: calc(100vw - 32px);
    padding: 10px 14px;
    background: var(--toast-bg); color: var(--toast-fg);
    font-weight: 600; font-stretch: 75%; font-size: var(--t-hud); letter-spacing: .08em;
    visibility: hidden; pointer-events: none;
  }
  .toast.is-on { visibility: visible; }
  @media (min-width: 900px) { .toast { bottom: 32px; } }
  @media (max-width: 767px) {
    html[data-page="home"] .toast { bottom: calc(var(--bottom-h) + 12px + var(--safe-b)); }
    html[data-page="breezz"] .toast { bottom: calc(var(--dock-h) + 8px + var(--safe-b)); }
  }

  /* ---------- Repli « M'écrire » : la messagerie ne s'est pas ouverte (navigateur intégré d'Instagram,
     poste sans client mail). Petit panneau non modal créé par core.js, même peau HUD sur les deux pages. ---------- */
  .mailhint {
    position: fixed; left: 50%; bottom: calc(24px + var(--safe-b)); z-index: var(--z-menu);
    transform: translateX(-50%);
    width: min(460px, calc(100vw - 24px)); max-width: none; margin: 0;
    display: none; gap: 10px;
    padding: 16px 16px 18px; border: 1px solid rgba(237, 234, 227, .22);
    background: var(--nuit); color: var(--pellicule);
    --fg: var(--pellicule); --bg: var(--nuit); --muted: var(--cendre); --focus: var(--neon); --hud-focus: var(--neon);
    --btn-bg: var(--pellicule); --btn-fg: var(--nuit); --btn-bg-h: var(--neon); --btn-fg-h: var(--nuit);
  }
  .mailhint[open] { display: grid; }
  .mailhint__k { color: var(--cendre); padding-right: 48px; }
  .mailhint__addr {
    font-weight: 700; font-stretch: 87%; font-size: clamp(20px, 5.4vw, 26px); line-height: 1.15;
    overflow-wrap: anywhere; -webkit-user-select: all; user-select: all;
  }
  .mailhint__row { display: flex; flex-wrap: wrap; align-items: center; gap: 8px 16px; }
  .mailhint__dm { color: var(--cendre); font-size: var(--t-s); }
  .mailhint__close { position: absolute; top: 6px; right: 6px; background: var(--ardoise); }
  @media (max-width: 767px) {
    html[data-page="home"] .mailhint { bottom: calc(var(--bottom-h) + 12px + var(--safe-b)); }
    html[data-page="breezz"] .mailhint { bottom: calc(var(--dock-h) + 8px + var(--safe-b)); }
  }
  html.mailhint-open .toast { z-index: calc(var(--z-menu) + 1); transform: translate(-50%, calc(-1 * var(--mailhint-h, 160px) - 12px)); }

  /* ---------- C13 Odomètre ---------- */
  .odo { display: inline-block; white-space: nowrap; font-variant-numeric: tabular-nums; --odo-h: 1.08em; }
  .odo__vis { display: inline-flex; align-items: flex-start; line-height: var(--odo-h); height: var(--odo-h); white-space: pre; }
  .odo__col { display: inline-block; width: 1ch; height: var(--odo-h); overflow: hidden; text-align: center; }
  .odo__stack { display: flex; flex-direction: column; }
  .odo__stack > span, .odo__ch { display: block; height: var(--odo-h); line-height: var(--odo-h); }
  .odo__ch { display: inline-block; white-space: pre; }

  /* ---------- C15 Bulle « tu » ---------- */
  .bulle {
    position: relative; display: inline-block;
    max-width: 26ch;
    padding: 12px 18px 13px;
    background: var(--blanc); color: var(--encre);
    border-radius: var(--r-bulle);
    font-weight: 700; font-stretch: 87%; font-size: var(--t-m); line-height: 1.2;
  }
  .bulle::after {
    content: ""; position: absolute; left: 20px; bottom: -10px;
    border-style: solid; border-width: 12px 12px 0 0;
    border-color: var(--blanc) transparent transparent transparent;
  }

  /* Cellules bordées sur leurs 4 côtés (tableaux de chiffres, logistique) */
  .cells { display: grid; grid-template-columns: repeat(var(--cells, 2), minmax(0, 1fr)); }
  .cells > * { border: 1px solid var(--line); margin: 0 -1px -1px 0; padding: var(--sp-4); min-width: 0; }

  /* ---------- C16 Curseur ---------- */
  .cursor {
    display: none;
    position: fixed; left: 0; top: 0; z-index: var(--z-cursor);
    width: 72px; height: 72px; margin: -36px 0 0 -36px;
    pointer-events: none;
    mix-blend-mode: difference;
    opacity: 0;
    transition: opacity .2s linear;
  }
  .has-cursor .cursor { display: block; }
  .cursor.is-on { opacity: 1; }
  .cursor__disc {
    position: absolute; inset: 0; border-radius: 50%;
    background: var(--pellicule);
    transform: scale(.1111);
    transition: transform .25s var(--ease-out);
  }
  .cursor__label {
    position: absolute; inset: 0; display: grid; place-items: center;
    color: var(--cursor-fg);
    font-weight: 600; font-stretch: 75%; font-size: 12px; letter-spacing: .08em; white-space: nowrap;
    opacity: 0;
  }
  .cursor__c { position: absolute; width: 12px; height: 12px; border: 0 solid var(--pellicule); opacity: 0; }
  .cursor__c:nth-child(3) { left: 0; top: 0; border-left-width: 1px; border-top-width: 1px; }
  .cursor__c:nth-child(4) { right: 0; top: 0; border-right-width: 1px; border-top-width: 1px; }
  .cursor__c:nth-child(5) { left: 0; bottom: 0; border-left-width: 1px; border-bottom-width: 1px; }
  .cursor__c:nth-child(6) { right: 0; bottom: 0; border-right-width: 1px; border-bottom-width: 1px; }
  .cursor.is-label { mix-blend-mode: normal; }
  .cursor.is-label .cursor__disc { transform: scale(1); background: var(--cursor-bg); }
  .cursor.is-label .cursor__label { opacity: 1; }
  .cursor.is-viseur .cursor__disc { transform: scale(0); }
  .cursor.is-viseur .cursor__c { opacity: 1; }
  .cursor.is-viseur.is-label .cursor__disc { transform: scale(0); }
  .cursor.is-viseur .cursor__label { color: var(--pellicule); }

  /* ---------- C21 Grain ----------
     Tour 3 : plus de calque plein écran par-dessus la page (il voilait les vidéos et les photos de Royce).
     Le grain est une texture posée sur les FONDS (body, sections [data-hud] / [data-lut], voir utilities) :
     les médias passent dessus, nets, avec leurs vraies couleurs. Ancien balisage <div class="grain"> neutralisé. */
  .grain { display: none; }

  /* ---------- C19 Pied de page ---------- */
  .site-footer {
    display: grid; gap: var(--sp-2);
    background-color: var(--bg);
    padding: var(--sp-8) var(--marge) var(--sp-7);
    font-size: var(--t-s); line-height: 1.5;
    color: var(--muted);
  }
  .site-footer p { max-width: 80ch; }
  .site-footer__line:first-child { color: var(--fg); }
  .site-footer a { color: var(--fg); }
  /* /breezz/ : « ← Retour au showreel » (tour 5 : lien vers le portfolio visible en fin de page sur mobile) */
  .site-footer__home { margin-top: var(--sp-2); font-weight: 700; }
  .site-footer__home .link { display: inline-flex; align-items: center; gap: .35em; }

  /* ---------- H00 Loader « clap » (accueil seulement) ---------- */
  .loader { display: none; }
  .js.has-loader .loader {
    position: fixed; inset: 0; z-index: var(--z-loader);
    display: grid; place-content: center; justify-items: center; gap: var(--sp-5);
    background: var(--nuit); color: var(--pellicule);
    pointer-events: none;
    animation: rp-loader-safety 0s linear 2.6s forwards;
  }
  .loader__clap { display: grid; grid-template-columns: repeat(2, minmax(0, auto)); border: 1px solid var(--ardoise-2); }
  .loader__cell {
    display: grid; gap: 4px; min-width: 9.5em;
    padding: 10px 14px;
    border: 1px solid var(--ardoise-2); margin: 0 -1px -1px 0;
    font-size: 14px;
  }
  .loader__k { color: var(--cendre); }
  .loader__tc { font-size: var(--t-l); font-weight: 600; font-stretch: 75%; letter-spacing: .04em; font-variant-numeric: tabular-nums; }
  .loader.is-black > * { visibility: hidden; }
  @media (max-width: 767px) {
    .loader__cell { min-width: 8.5em; font-size: 12px; padding: 8px 10px; }
  }

  /* Image noire de coupe (RP.blackFrame) */
  .blackframe { position: fixed; inset: 0; z-index: 95; background: #000; pointer-events: none; }

  /* Fantômes du WHIP (créés par core.js) */
  .whip-ghost {
    position: absolute; top: 0; bottom: 0; left: 0; width: 2px; z-index: 6;
    background: currentColor; pointer-events: none;
  }

  /* Liens de repli vidéo : visibles seulement sans JS */
  .js .reel__fallback, .rp .reel__fallback { display: none; }
}

/* =========================================================================
   UTILITIES
   ========================================================================= */
@layer utilities {
  .sr-only {
    position: absolute !important; width: 1px !important; height: 1px !important;
    padding: 0 !important; margin: -1px !important; overflow: hidden !important;
    clip: rect(0 0 0 0) !important; clip-path: inset(50%) !important;
    white-space: nowrap !important; border: 0 !important;
  }
  .serif {
    font-family: var(--font-serif);
    font-style: italic;
    font-weight: 400;
    font-stretch: normal;
    letter-spacing: 0;
  }
  /* Coupe de largeur : changement de classe, jamais d'interpolation */
  .w-62  { font-stretch: 62% !important; }
  .w-75  { font-stretch: 75% !important; }
  .w-87  { font-stretch: 87% !important; }
  .w-100 { font-stretch: 100% !important; }
  .w-112 { font-stretch: 112% !important; }
  .w-125 { font-stretch: 125% !important; }
  .nowrap { white-space: nowrap; }
  .is-ramp { white-space: nowrap; }
  /* Grain (C21) sur les fonds de section : !important parce que les feuilles de page posent leurs aplats
     avec le raccourci « background: » (qui remettrait l'image à none). Une section qui a besoin de sa propre
     image de fond met data-grain="off". --noise (PNG 128 px avec alpha = --grain-o) est généré par core.js. */
  :is([data-hud], [data-lut]):not([data-grain="off"]) { background-image: var(--noise, none) !important; }
  /* Élément qui n'a de sens qu'avec core.js (masqué si le JS n'a pas démarré) */
  html:not(.js):not(.rp) .needs-core { display: none !important; }
  /* Sans JS : le poster (data-poster, normalement posé par core.js) s'affiche en fond.
     L'image vient du <noscript data-nojs-posters> du <head> : jamais téléchargée quand le JS tourne. */
  html:not(.js):not(.rp) video[data-poster] { background-position: center; background-size: cover; background-repeat: no-repeat; }
}

/* =========================================================================
   MOTION — états initiaux (seulement .js + mouvement autorisé), View Transitions,
   filet prefers-reduced-motion
   ========================================================================= */
@layer motion {
  /* Lenis 1.3.27 (copie de dist/lenis.css ; overflow:hidden au lieu de clip pour garder la gouttière) */
  html.lenis, html.lenis body { height: auto; }
  .lenis:not(.lenis-autoToggle).lenis-stopped { overflow: hidden; }
  .lenis [data-lenis-prevent], .lenis [data-lenis-prevent-wheel], .lenis [data-lenis-prevent-touch],
  .lenis [data-lenis-prevent-vertical], .lenis [data-lenis-prevent-horizontal] { overscroll-behavior: contain; }
  .lenis.lenis-smooth iframe { pointer-events: none; }
  .lenis.lenis-autoToggle { transition-property: overflow; transition-duration: 1ms; transition-behavior: allow-discrete; }
  html.rp-lock { overflow: hidden; }

  /* Mouvements permanents (désactivés en reduced-motion) */
  @media (prefers-reduced-motion: no-preference) {
    .rec { animation: rp-rec 2s ease-in-out infinite alternate; }
    .grain { animation: rp-grain .6s steps(6) infinite; }
  }

  /* Lignes masquées de SplitText (mask:'lines', classe rp-line-mask) : le masque est en overflow:clip ;
     on lui donne de l'air au-dessus et au-dessous pour ne pas rogner les accents des capitales
     (É, Ê, À) ni les jambages sur les .mega à interligne .86. */
  .rp-line-mask { padding-top: .2em; margin-top: -.2em; padding-bottom: .08em; margin-bottom: -.08em; }

  /* États initiaux des révélations : n'existent que sous .js ET mouvement autorisé.
     opacity (et non visibility) : un titre pas encore révélé reste dans l'arbre d'accessibilité. */
  @media (prefers-reduced-motion: no-preference) {
    .js [data-reveal="lines"]:not([data-revealed]),
    .js [data-reveal="wcut"]:not([data-revealed]) { opacity: 0; }
    .js [data-reveal="iris"]:not([data-revealed]) { clip-path: var(--iris-from, inset(18% 30% 18% 30%)); }
    .js [data-reveal="iris"][data-iris="line"]:not([data-revealed]) { clip-path: inset(50% 0% 50% 0%); }
    .js [data-reveal="iris"][data-iris="up"]:not([data-revealed]) { clip-path: inset(100% 0% 0% 0%); }
    .js [data-reveal="whip"]:not([data-revealed]) { clip-path: inset(0% 0% 0% 100%); }
    .js [data-reveal="strike"]:not([data-revealed]) :is([data-strike-path], path) { stroke-dasharray: 1; stroke-dashoffset: 1; }
  }
  @media (prefers-reduced-motion: no-preference) and (max-width: 767px) {
    .js [data-reveal="iris"]:not([data-revealed]):not([data-iris]) { clip-path: var(--iris-from-m, inset(10% 6% 10% 6%)); }
  }

  /* C20 View Transitions (multi-pages, même origine) — tour 3 : une COUPE au volet, jamais de fondu.
     Aucune superposition en transparence (mix-blend normal, aucune opacité intermédiaire) :
     1. un volet opaque (--vt-volet de la page d'arrivée : ciel vers /breezz/, nuit vers l'accueil)
        balaie l'ancienne page de droite à gauche (420 ms) ;
     2. la nouvelle page le suit à 180 ms, révélée par le même bord : entre les deux, une bande pleine.
     La topbar a son propre nom : elle est coupée avec sa page (même balayage), jamais fondue avec l'autre.
     Raccord breezz-hero (photo de la carte H11 → cadre de la bande-annonce) seulement s'il est visible des
     deux côtés (décidé par core.js au pageswap + script de tête au pagereveal), sinon il suit la page. */
  @media (prefers-reduced-motion: no-preference) {
    @view-transition { navigation: auto; }
  }
  .topbar { view-transition-name: topbar; }
  html.vt-hero :is(.next-card__photo, .trailer__frame) { view-transition-name: breezz-hero; }
  ::view-transition-group(root) { background: var(--vt-volet); }
  ::view-transition-group(topbar) { animation: none; }
  ::view-transition-image-pair(root), ::view-transition-image-pair(topbar) { isolation: auto; }
  ::view-transition-old(root), ::view-transition-old(topbar) {
    mix-blend-mode: normal; animation: .42s var(--ease-inout) both rp-vt-out;
  }
  ::view-transition-new(root), ::view-transition-new(topbar) {
    mix-blend-mode: normal; animation: .42s var(--ease-inout) .18s both rp-vt-in;
  }
  ::view-transition-group(breezz-hero) { animation-duration: .6s; animation-timing-function: var(--ease-inout); }
  /* La photo de la carte garde son image jusqu'au passage du volet, puis COUPE sur le cadre de la bande-annonce */
  ::view-transition-old(breezz-hero) { mix-blend-mode: normal; animation: .3s steps(1, end) both rp-vt-hide; }
  ::view-transition-new(breezz-hero) { mix-blend-mode: normal; animation: .3s steps(1, end) both rp-vt-show; }

  @keyframes rp-vt-out { from { clip-path: inset(0 0 0 0); } to { clip-path: inset(0 100% 0 0); } }
  @keyframes rp-vt-in { from { clip-path: inset(0 0 0 100%); } to { clip-path: inset(0 0 0 0); } }
  @keyframes rp-vt-hide { from { opacity: 1; } to { opacity: 0; } }
  @keyframes rp-vt-show { from { opacity: 0; } to { opacity: 1; } }
  @keyframes rp-rec { from { opacity: 1; } to { opacity: .35; } }
  @keyframes rp-grain {
    0% { transform: translate(0, 0); } 17% { transform: translate(-5%, 3%); } 33% { transform: translate(4%, -6%); }
    50% { transform: translate(-3%, 7%); } 67% { transform: translate(6%, -2%); } 83% { transform: translate(-2%, 5%); } 100% { transform: translate(0, 0); }
  }
  @keyframes rp-loader-safety { to { visibility: hidden; } }

  /* Filet de sécurité global */
  @media (prefers-reduced-motion: reduce) {
    *, *::before, *::after {
      animation-duration: .01ms !important;
      animation-iteration-count: 1 !important;
      transition-duration: .01ms !important;
      scroll-behavior: auto !important;
    }
    ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }
  }
}
