/* ═══════════════════════════════════════════════════════════════════════════════
   Kalq · l'accueil, le hub des outils
   Un écran, deux outils, chacun dans son panneau : Kalq Analyse à gauche, éclairé du
   rouge du premier calque du logo ; Kalq Impôt à droite, du bleu du second. Entre eux,
   la ligne rouge de la marque sert de couture. Les deux scènes sont lues au même
   rythme : la rangée lue à gauche l'est au même instant à droite, et un point marque
   le passage sur la couture. Sous l'écran, les chiffres et l'origine. Chargée après
   commun.css.

   Les scènes sont en HTML, pas en image : leur texte garde une taille lisible (12 à
   14 px) à toutes les largeurs. Tout ce qui bouge part d'un état final complet : sans
   script, avec les animations réduites ou sur un navigateur ancien, chaque scène montre
   sa lecture faite.
   ═══════════════════════════════════════════════════════════════════════════════ */

/* ═══ L'écran ═════════════════════════════════════════════════════════════════ */
/* L'écran commence sous l'en-tête et prend la hauteur de son contenu, sans être centré.
   Il respire : la lisibilité passe avant le premier écran (02/11, la version serrée pour
   tout faire tenir était trop dense). Sur un portable, le titre, les noms et les phrases
   des deux outils et leurs scènes sont dans l'écran ; le bas des panneaux suit juste
   dessous. Sur un grand écran, tout tient. */
.hub { display: grid; align-content: start; padding-block: calc(var(--entete) + clamp(28px, 6vh, 72px)) clamp(48px, 7vh, 88px); }
.hub-ecran { display: grid; gap: clamp(32px, 5vh, 56px); }
.hub-tete { display: grid; justify-items: center; gap: 14px; text-align: center; }
/* Le titre épouse son texte : la ligne qui le lit ne traverse pas tout l'écran. */
.hub .titre-scan { width: fit-content; max-width: 100%; font-size: clamp(2.3rem, 1.2rem + 2.8vw, 3.4rem); margin-bottom: 0.1em; }

/* ═══ Les deux panneaux ═══════════════════════════════════════════════════════ */
/* Trois colonnes : Analyse, la couture, Impôt. Les panneaux partagent les rangées de
   la grille (subgrid) : statut et nom, phrase, scène, fonctions et bouton tombent à la
   même hauteur des deux côtés, et le point de la couture se pose sur la rangée des
   scènes. Le fond uni des panneaux masque le papier réglé : rien ne passe sous le texte.
   Les écarts entre rangées sont réglés par les marges des rangées 2, 4 et 5, jamais
   celle de la scène : la rangée 3 garde exactement sa hauteur, celle du point.
   --rang, la hauteur d'une rangée de scène : toute la scène en découle (voir « Les
   scènes »). */
.hub-moities {
  --scene-duree: 8s; --rang: 32px;
  position: relative; display: grid; grid-template-columns: minmax(0, 1fr) 2px minmax(0, 1fr); grid-template-rows: repeat(5, auto);
  column-gap: clamp(24px, 3vw, 48px); row-gap: 14px; width: min(100%, 1200px); margin-inline: auto;
}
.moitie {
  position: relative; isolation: isolate; grid-row: 1 / span 5; display: grid; grid-template-rows: subgrid; align-content: start; min-width: 0;
  padding: clamp(24px, 2.6vw, 36px) clamp(20px, 2.4vw, 34px); border-radius: 24px; border: 1px solid var(--nuit-filet);
  /* Le trait de l'outil en haut du panneau ; la seconde ombre, transparente au repos, est
     la lueur du panneau visé. */
  box-shadow: inset 0 2px 0 var(--trait), 0 30px 60px -30px transparent; transition: border-color 0.4s, box-shadow 0.5s var(--courbe);
  /* La scène s'incline vers la souris (rotate, posé par le script) : il lui faut une perspective. */
  perspective: 1400px;
}
.moitie-analyse { --trait: var(--nuit-accent); --vise: rgba(238, 122, 99, 0.5); grid-column: 1; background: radial-gradient(90% 55% at 0% 0%, rgba(238, 122, 99, 0.11), transparent 70%), var(--nuit-surface); }
.moitie-impots { --trait: var(--nuit-bleu); --vise: rgba(111, 168, 232, 0.5); grid-column: 3; background: radial-gradient(90% 55% at 100% 0%, rgba(111, 168, 232, 0.11), transparent 70%), var(--nuit-surface); }
/* Sous la souris, la lueur du panneau suit le curseur (projecteur de commun.js). */
.moitie.projecteur::before { z-index: -1; border-radius: inherit; }
.moitie-analyse.projecteur::before { background: radial-gradient(380px circle at var(--mx, 50%) var(--my, 50%), rgba(238, 122, 99, 0.1), transparent 70%); }
.moitie-impots.projecteur::before { background: radial-gradient(380px circle at var(--mx, 50%) var(--my, 50%), rgba(111, 168, 232, 0.1), transparent 70%); }

.moitie-tete { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 16px; }
.moitie-tete h2 { font-size: clamp(1.6rem, 1.1rem + 1.2vw, 2.2rem); font-weight: 680; letter-spacing: -0.035em; line-height: 1.05; }
.moitie-statut { display: flex; align-items: center; gap: 12px; }
/* L'état de chaque bêta : fermée (sur invitation) en jaune, ouverte en vert. */
.hub .puce-conforme { color: var(--nuit-conforme); background: rgba(92, 196, 142, 0.14); }
.hub .puce-vigilance { color: var(--nuit-vigilance); background: rgba(232, 182, 92, 0.14); }
.moitie-rang { font-family: var(--police-mono); font-size: var(--t-xs); letter-spacing: 0.1em; color: var(--nuit-doux); }
.moitie-texte { max-width: 34em; margin-bottom: 10px; font-size: 1rem; line-height: 1.6; color: var(--nuit-texte); }
.moitie-fonctions { display: grid; align-content: start; gap: 9px; margin-top: 14px; font-size: 0.9375rem; line-height: 1.5; color: var(--nuit-texte); }
/* L'icône à gauche, le texte à droite : une ligne longue revient sous son texte, pas sous l'icône. */
.moitie-fonctions li { display: grid; grid-template-columns: 15px minmax(0, 1fr); gap: 10px; align-items: start; }
.moitie-fonctions svg { width: 15px; height: 15px; margin-top: 3px; }
.moitie-fonctions .pastille { display: inline-block; margin-left: 8px; padding-block: 1px; vertical-align: 1px; line-height: 1.4; }
.fonction-coche { color: var(--nuit-conforme); }
.fonction-avenir { color: var(--nuit-doux); }
.moitie-fonctions .a-venir { color: var(--nuit-doux); }
/* Une fonction annoncée : en préparation, ou bientôt. */
.pastille {
  padding: 2px 9px; border-radius: 999px; border: 1px solid rgba(236, 238, 232, 0.3);
  font-family: var(--police-mono); font-size: 11px; font-weight: 500; letter-spacing: 0.06em; text-transform: uppercase; color: var(--nuit-texte);
}
.moitie-action { margin-top: 12px; }
.moitie-action .bouton { min-height: 46px; }

/* La couture : la ligne rouge de la marque, debout entre les panneaux, avec ses taquets. */
.hub-couture {
  position: relative; grid-column: 2; grid-row: 1 / span 5; width: 2px; transform-origin: top;
  background: var(--nuit-accent); box-shadow: 0 0 0 1px rgba(238, 122, 99, 0.12), 0 0 18px rgba(238, 122, 99, 0.4);
}
.hub-couture::before, .hub-couture::after { content: ""; position: absolute; left: -7px; width: 16px; height: 2px; background: var(--nuit-accent); }
.hub-couture::before { top: 0; }
.hub-couture::after { bottom: 0; }

/* ═══ Le panneau visé ═════════════════════════════════════════════════════════ */
/* Sous la souris ou au clavier, le panneau visé s'avance : son cadre s'allume de la
   couleur de l'outil et il grandit un peu, en s'écartant de la couture qui reste nette.
   Une transformation seulement : rien ne bouge autour, et son texte ne passe jamais sous
   sa taille de lecture. L'autre panneau ne change pas. Tout le panneau mène à son outil
   (module cartes de hub.js). */
.moitie:focus-within { border-color: var(--vise); box-shadow: inset 0 2px 0 var(--trait), 0 30px 60px -30px var(--vise); }
@media (hover: hover) {
  .moitie:hover { border-color: var(--vise); box-shadow: inset 0 2px 0 var(--trait), 0 30px 60px -30px var(--vise); }
}
@media (hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference) {
  .moitie { transition: border-color 0.4s, box-shadow 0.5s var(--courbe), scale 0.5s var(--courbe); }
  .moitie-analyse { transform-origin: 100% 50%; }
  .moitie-impots { transform-origin: 0% 50%; }
  .moitie:is(:hover, :focus-within) { z-index: 1; scale: 1.025; }
}
.moitie.cliquable { cursor: pointer; }

/* ═══ Les scènes ══════════════════════════════════════════════════════════════ */
/* Chaque scène : une source à gauche (le relevé, l'espace impots.gouv), la cible à droite
   (l'import, les dossiers du cabinet), qui la chevauche un peu. Hauteurs fixes et
   communes, toutes proportionnelles à --rang (184 px pour une rangée de 28 : marge 8,
   titre 26, quatre rangées de 28, pied 30, marge 8 ; 210 px pour les 32 d'aujourd'hui) :
   les rangées tombent aux mêmes hauteurs dans la source, dans la cible et d'une scène à
   l'autre, et aucune animation ne déplace la page. Les instants de lecture des boucles sont ceux où la ligne passe au
   milieu de chaque rangée ; ils ne dépendent que des proportions, que --rang garde.
   Changer une proportion, c'est les recalculer. */
.moitie-scene { position: relative; display: grid; grid-template-columns: minmax(0, 0.36fr) minmax(0, 0.64fr); align-items: start; height: calc(var(--rang) * 184 / 28); font-family: var(--police-mono); font-size: 13px; }
.moitie-scene ul { display: grid; }
.sc-cible {
  position: relative; z-index: 1; margin-left: -14px; padding: calc(var(--rang) * 8 / 28) 14px; border-radius: 12px; border: 1px solid rgba(236, 238, 232, 0.12);
  background: var(--nuit-surface-haute); box-shadow: 0 24px 40px -24px rgba(0, 0, 0, 0.8);
}
.sc-titre { display: flex; justify-content: space-between; align-items: center; gap: 10px; height: calc(var(--rang) * 26 / 28); font-family: var(--police); font-size: 13.5px; font-weight: 600; color: var(--nuit-texte); }
.sc-titre span + span { font-family: var(--police-mono); font-size: 12px; font-weight: 400; color: var(--nuit-doux); }
.sc-cible li { position: relative; display: grid; align-items: center; gap: 10px; height: var(--rang); border-top: 1px solid var(--nuit-filet); white-space: nowrap; font-variant-numeric: tabular-nums; color: var(--nuit-texte); }
.sc-cible li > span { overflow: hidden; text-overflow: ellipsis; }
.sc-pied { display: flex; align-items: center; height: calc(var(--rang) * 30 / 28); border-top: 1px solid var(--nuit-filet); }
.sc-pied .puce { padding-block: 3px; font-size: 12px; transform-origin: left center; }
/* La source passe sous la cible sur 14 px : sa marge droite garde son texte à découvert.
   Décalage et tête (décalage + 4 + titre) valent marge et titre de la cible. */
.sc-source { position: relative; margin-top: calc(var(--rang) * 8 / 28 - 4px); padding: 4px 26px 8px 12px; border-radius: 10px; }
.sc-source li { position: relative; isolation: isolate; display: grid; align-items: center; gap: 8px; height: var(--rang); white-space: nowrap; }
.sc-source li > span:not(.lu) { overflow: hidden; text-overflow: ellipsis; }
/* Une rangée lue : un voile et un trait de la couleur de l'outil, en place au repos. */
.lu { position: absolute; inset: 3px -6px; z-index: -1; border-radius: 4px; transform-origin: left center; }
.lu::before { content: ""; position: absolute; left: 0; top: 6px; bottom: 6px; width: 2px; }

/* Analyse : le relevé sur papier, puis l'import qui s'écrit. */
.sc-papier { background: var(--papier); color: var(--papier-encre); box-shadow: 0 18px 30px -18px rgba(0, 0, 0, 0.7); }
.sc-papier-tete { display: grid; align-content: center; gap: 3px; height: calc(var(--rang) * 26 / 28); font-size: 11px; line-height: 1.3; color: var(--papier-doux); }
.sc-papier-tete b { width: 56%; height: 6px; border-radius: 2px; background: rgba(27, 42, 65, 0.7); }
.sc-papier li { grid-template-columns: auto minmax(0, 1fr) auto; font-size: 12px; }
.sc-papier li i { height: 4px; border-radius: 2px; background: rgba(27, 42, 65, 0.18); }
.sc-papier .lu { background: rgba(238, 122, 99, 0.16); }
.sc-papier .lu::before { background: var(--papier-rature); }
.moitie-analyse .sc-cible li { grid-template-columns: 3.4em minmax(0, 1fr) auto; }
.moitie-analyse .sc-cible li > span:first-child { color: var(--nuit-doux); }
/* Le cache d'une ligne d'import : il se replie vers la droite quand la ligne est lue. */
.ecrit { position: absolute; inset: 1px -2px 0; background: var(--nuit-surface-haute); transform-origin: right center; transform: scaleX(0); }
/* La pièce qui vole de la source à la cible : un trait rouge, ou deux avis. */
.vol { position: absolute; top: 50%; transform-origin: center; transform: scale(0); pointer-events: none; }
.vol-trait { --vol-x: -130px; left: -8px; width: 14px; height: 3px; margin-top: -1.5px; border-radius: 2px; background: var(--nuit-accent); box-shadow: 0 0 10px rgba(238, 122, 99, 0.7); }

/* Impôt : l'espace impots.gouv, puis les dossiers du cabinet. */
.sc-fenetre { border: 1px solid rgba(111, 168, 232, 0.28); background: var(--nuit); color: var(--nuit-texte); font-size: 12px; }
.sc-fenetre-tete { display: flex; align-items: center; gap: 4px; height: calc(var(--rang) * 26 / 28); border-bottom: 1px solid var(--nuit-filet); color: var(--nuit-doux); font-size: 11.5px; }
.sc-fenetre-tete b { width: 6px; height: 6px; border-radius: 50%; background: rgba(236, 238, 232, 0.25); }
.sc-fenetre-tete span { margin-left: 6px; }
.sc-fenetre li { grid-template-columns: minmax(0, 1fr) auto auto; }
.sc-fenetre li i { width: 10px; height: 13px; border-radius: 2px; border: 1px solid rgba(236, 238, 232, 0.35); }
.sc-fenetre .lu { background: rgba(111, 168, 232, 0.16); }
.sc-fenetre .lu::before { background: var(--nuit-bleu); }
.moitie-impots .sc-cible li { grid-template-columns: 16px minmax(0, 1fr) auto; }
.sc-dossier { width: 16px; height: 16px; color: var(--nuit-bleu); }
.coche { display: inline-flex; gap: 6px; transform-origin: center; }
.sc-avis { display: inline-flex; align-items: center; gap: 4px; padding: 1px 8px 1px 6px; line-height: 1.5; border-radius: 999px; font-size: 11.5px; color: var(--nuit-conforme); background: rgba(92, 196, 142, 0.14); }
.sc-avis svg { width: 11px; height: 11px; }
.vol-avis { --vol-x: -150px; right: 18px; display: flex; gap: 22px; margin-top: -8px; }
.vol-avis i { width: 12px; height: 16px; border-radius: 2px; background: var(--papier); box-shadow: inset 0 3px 0 var(--nuit-bleu); }

/* La ligne de lecture : un calque de la hauteur de la scène, déplacé par transformation ;
   le trait est dessiné sur son bord haut. Au repos, il est en bas de la scène. Sur la
   couture, un point marque son passage d'un panneau à l'autre. */
.scene-balai, .hub-balai { pointer-events: none; transform: translateY(100%); }
.scene-balai { position: absolute; inset: 0 -8px; z-index: 2; }
.scene-balai::before { content: ""; position: absolute; left: 0; right: 0; top: -1px; height: 2px; }
.moitie-analyse .scene-balai::before { background: var(--nuit-accent); box-shadow: 0 0 14px rgba(238, 122, 99, 0.55); }
.moitie-impots .scene-balai::before { background: var(--nuit-bleu); box-shadow: 0 0 14px rgba(111, 168, 232, 0.55); }
.hub-balai { position: relative; grid-column: 2; grid-row: 3; z-index: 2; }
.hub-balai::before { content: ""; position: absolute; left: 50%; top: -5px; width: 10px; height: 10px; margin-left: -5px; border-radius: 50%; background: var(--nuit-accent); box-shadow: 0 0 0 4px rgba(238, 122, 99, 0.18), 0 0 16px rgba(238, 122, 99, 0.7); }

/* Les boucles : avec le script, quand les animations sont permises. Toutes les pièces
   partagent une durée et un départ, et chacune a son instant, celui où la ligne atteint
   sa rangée : le même pour les deux scènes. Le script les met en pause hors de l'écran,
   onglet caché, ou à la demande (--etat). Seules des transformations sont animées : le
   navigateur ne recalcule pas la page à chaque image. */
@media (prefers-reduced-motion: no-preference) {
  .js .hub-moities :where(.lu, .ecrit, .vol, .coche, .fin, .hub-balai, .scene-balai) {
    animation-duration: var(--scene-duree); animation-iteration-count: infinite; animation-fill-mode: both;
    animation-timing-function: var(--courbe); animation-delay: 1.2s; animation-play-state: var(--etat, paused);
  }
  .js .hub-moities :where(.hub-balai, .scene-balai) { animation-name: balai; animation-timing-function: linear; }
  .js .rang:nth-of-type(1) .lu { animation-name: lu-1; }
  .js .rang:nth-of-type(1) .ecrit { animation-name: ecrit-1; }
  .js .rang:nth-of-type(1) .vol { animation-name: vol-1; }
  .js .rang:nth-of-type(1) .coche { animation-name: coche-1; }
  .js .rang:nth-of-type(2) .lu { animation-name: lu-2; }
  .js .rang:nth-of-type(2) .ecrit { animation-name: ecrit-2; }
  .js .rang:nth-of-type(2) .vol { animation-name: vol-2; }
  .js .rang:nth-of-type(2) .coche { animation-name: coche-2; }
  .js .rang:nth-of-type(3) .lu { animation-name: lu-3; }
  .js .rang:nth-of-type(3) .ecrit { animation-name: ecrit-3; }
  .js .rang:nth-of-type(3) .vol { animation-name: vol-3; }
  .js .rang:nth-of-type(3) .coche { animation-name: coche-3; }
  .js .rang:nth-of-type(4) .lu { animation-name: lu-4; }
  .js .rang:nth-of-type(4) .ecrit { animation-name: ecrit-4; }
  .js .rang:nth-of-type(4) .vol { animation-name: vol-4; }
  .js .rang:nth-of-type(4) .coche { animation-name: coche-4; }
  .js .hub-moities .fin { animation-name: fin; }
}
@keyframes balai {
  0% { transform: translateY(0) scaleX(0); }
  5% { transform: translateY(0) scaleX(1); }
  67.5%, 88% { transform: translateY(100%) scaleX(1); animation-timing-function: var(--courbe-lecture); }
  95% { transform: translateY(0) scaleX(1); }
  100% { transform: translateY(0) scaleX(0); }
}
@keyframes lu-1 { 0%, 21.3% { transform: scaleX(0); } 23.8%, 90% { transform: scaleX(1); } 95%, 100% { transform: scaleX(0); } }
@keyframes lu-2 { 0%, 30.8% { transform: scaleX(0); } 33.3%, 90% { transform: scaleX(1); } 95%, 100% { transform: scaleX(0); } }
@keyframes lu-3 { 0%, 40.3% { transform: scaleX(0); } 42.8%, 90% { transform: scaleX(1); } 95%, 100% { transform: scaleX(0); } }
@keyframes lu-4 { 0%, 49.8% { transform: scaleX(0); } 52.3%, 90% { transform: scaleX(1); } 95%, 100% { transform: scaleX(0); } }
@keyframes ecrit-1 { 0%, 21.8% { transform: scaleX(1); } 25.8%, 90% { transform: scaleX(0); } 95%, 100% { transform: scaleX(1); } }
@keyframes ecrit-2 { 0%, 31.3% { transform: scaleX(1); } 35.3%, 90% { transform: scaleX(0); } 95%, 100% { transform: scaleX(1); } }
@keyframes ecrit-3 { 0%, 40.8% { transform: scaleX(1); } 44.8%, 90% { transform: scaleX(0); } 95%, 100% { transform: scaleX(1); } }
@keyframes ecrit-4 { 0%, 50.3% { transform: scaleX(1); } 54.3%, 90% { transform: scaleX(0); } 95%, 100% { transform: scaleX(1); } }
@keyframes vol-1 { 0%, 21.3% { transform: translateX(var(--vol-x)) scale(0); } 21.8% { transform: translateX(var(--vol-x)) scale(1); } 25.8% { transform: translateX(0) scale(1); } 27.3%, 100% { transform: translateX(0) scale(0); } }
@keyframes vol-2 { 0%, 30.8% { transform: translateX(var(--vol-x)) scale(0); } 31.3% { transform: translateX(var(--vol-x)) scale(1); } 35.3% { transform: translateX(0) scale(1); } 36.8%, 100% { transform: translateX(0) scale(0); } }
@keyframes vol-3 { 0%, 40.3% { transform: translateX(var(--vol-x)) scale(0); } 40.8% { transform: translateX(var(--vol-x)) scale(1); } 44.8% { transform: translateX(0) scale(1); } 46.3%, 100% { transform: translateX(0) scale(0); } }
@keyframes vol-4 { 0%, 49.8% { transform: translateX(var(--vol-x)) scale(0); } 50.3% { transform: translateX(var(--vol-x)) scale(1); } 54.3% { transform: translateX(0) scale(1); } 55.8%, 100% { transform: translateX(0) scale(0); } }
@keyframes coche-1 { 0%, 25.8% { transform: scale(0); } 27.8%, 90% { transform: scale(1); } 95%, 100% { transform: scale(0); } }
@keyframes coche-2 { 0%, 35.3% { transform: scale(0); } 37.3%, 90% { transform: scale(1); } 95%, 100% { transform: scale(0); } }
@keyframes coche-3 { 0%, 44.8% { transform: scale(0); } 46.8%, 90% { transform: scale(1); } 95%, 100% { transform: scale(0); } }
@keyframes coche-4 { 0%, 54.3% { transform: scale(0); } 56.3%, 90% { transform: scale(1); } 95%, 100% { transform: scale(0); } }
@keyframes fin { 0%, 59.6% { transform: scale(0); } 63.1%, 90% { transform: scale(1); } 95%, 100% { transform: scale(0); } }

/* ═══ La pause, au pied de la couture ═════════════════════════════════════════ */
/* L'appel « Rejoindre la bêta » est parti le 05/11 : il ne reste que la pause des scènes. */
.hub-pied { display: flex; justify-content: center; }
.outils-pause {
  flex: none; display: grid; place-items: center; width: 30px; height: 30px; padding: 0; border-radius: 50%;
  border: 1px solid rgba(236, 238, 232, 0.24); background: transparent; color: var(--nuit-doux); cursor: pointer; transition: color 0.2s, border-color 0.2s;
}
.outils-pause:hover { color: var(--nuit-texte); border-color: var(--nuit-doux); }
.outils-pause svg { width: 12px; height: 12px; }
.outils-pause .icone-lecture { display: none; }
.outils-pause[aria-pressed="true"] .icone-pause { display: none; }
.outils-pause[aria-pressed="true"] .icone-lecture { display: block; }
@media (prefers-reduced-motion: reduce) { .outils-pause { display: none; } }
/* Avec le script, la place du bouton est gardée dès le premier affichage : quand le
   script le montre, rien ne bouge sous les panneaux. */
@media (prefers-reduced-motion: no-preference) {
  .js .outils-pause[hidden] { display: grid !important; visibility: hidden; }
}

/* ═══ L'arrivée ═══════════════════════════════════════════════════════════════ */
/* La couture se trace, puis les deux panneaux s'ouvrent depuis elle, par découpe. La
   découpe ne tient pas après l'arrivée (backwards) : les ombres des scènes restent
   entières. */
@media (prefers-reduced-motion: no-preference) {
  .hub-tete > .surtitre { animation: montee 0.8s var(--courbe) backwards; }
  .hub-couture { animation: couture-trace 1s var(--courbe-lecture) 0.1s backwards; }
  .moitie-analyse { animation: ouvre-gauche 1.1s var(--courbe-lecture) 0.45s backwards; }
  .moitie-impots { animation: ouvre-droite 1.1s var(--courbe-lecture) 0.45s backwards; }
  .hub-pied { animation: montee 0.9s var(--courbe) 0.9s backwards; }
}
@keyframes couture-trace { from { transform: scaleY(0); } }
@keyframes ouvre-gauche { from { clip-path: inset(-40px 0 -40px 100%); } to { clip-path: inset(-40px 0 -40px 0); } }
@keyframes ouvre-droite { from { clip-path: inset(-40px 100% -40px 0); } to { clip-path: inset(-40px 0 -40px 0); } }

/* ═══ Écrans moyens, téléphone, navigateur sans subgrid ═══════════════════════ */
@media (max-width: 1100px) {
  .moitie-scene { font-size: 12px; }
  .sc-cible { padding-inline: 12px; }
}
/* Les panneaux s'empilent, la couture se couche entre eux. La source de chaque scène
   s'efface : la cible prend toute la largeur, et son texte garde sa taille. */
@media (max-width: 860px) {
  .hub-moities { grid-template-columns: minmax(0, 1fr); grid-template-rows: none; row-gap: 0; }
  .moitie, .moitie-impots { grid-column: 1; grid-row: auto; grid-template-rows: none; row-gap: 12px; }
  .hub-couture { grid-column: 1; grid-row: auto; width: 100%; height: 2px; margin-block: 28px; transform-origin: left; }
  .hub-couture::before, .hub-couture::after { top: -7px; left: auto; width: 2px; height: 16px; }
  .hub-couture::before { left: 0; }
  .hub-couture::after { right: 0; bottom: auto; }
  .hub-balai { display: none; }
  .moitie-analyse, .moitie-impots { transform-origin: 50% 50%; }
}
@media (max-width: 600px) {
  .moitie-scene { grid-template-columns: minmax(0, 1fr); font-size: 12.5px; }
  .sc-source, .vol { display: none; }
  .sc-cible { margin-left: 0; }
}
@supports not (grid-template-rows: subgrid) {
  .moitie { grid-template-rows: none; row-gap: 12px; }
  .hub-balai { display: none; }
}
@media (max-width: 860px) and (prefers-reduced-motion: no-preference) {
  @keyframes couture-trace { from { transform: scaleX(0); } }
}

/* ═══ L'origine ═══════════════════════════════════════════════════════════════ */
.origine { padding-block: clamp(56px, 8vw, 104px); text-align: center; }
.origine-contenu { display: grid; justify-items: center; gap: 18px; }
.origine-phrase { max-width: 34em; font-size: clamp(1.2rem, 1rem + 0.8vw, 1.6rem); font-weight: 550; letter-spacing: -0.02em; line-height: 1.45; text-wrap: balance; }
.origine-contact { font-size: var(--t-s); color: var(--texte-doux); }
