@font-face {
  font-family: "Silkscreen";
  /* woff2 d'abord : meme dessin, deux fois plus leger. Le ttf reste en repli
     pour les navigateurs qui l'ignorent. */
  src:
    url("./assets/fonts/Silkscreen-Regular.woff2") format("woff2"),
    url("./assets/fonts/Silkscreen-Regular.ttf") format("truetype");
  font-display: swap;
  font-style: normal;
  font-weight: 400;
}

:root {
  color-scheme: dark;
  --tn-bg: #000000;
  --tn-text: #f5f5f2;
  --tn-muted: #a3a3a3;
  --tn-line: #292929;
  --tn-line-light: #444442;
  --tn-amber: #f5ad00;
  --tn-amber-light: #ffd45a;
  --tn-leaf: #6f873f;
  --tn-gutter: clamp(24px, 5vw, 80px);
  --tn-content: 1440px;
  --tn-copy: 680px;
  --tn-header: 76px;
  --tn-slow: 900ms cubic-bezier(0.2, 0.7, 0.2, 1);
  font-family:
    Inter, "Helvetica Neue", Helvetica, Arial, system-ui, -apple-system,
    sans-serif;
  font-synthesis: none;
  text-rendering: optimizeLegibility;
}

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

html {
  overflow-x: clip;
  background: var(--tn-bg);
  scroll-behavior: smooth;
  scrollbar-color: var(--tn-line-light) var(--tn-bg);
}

body {
  margin: 0;
  min-width: 320px;
  overflow-x: hidden;
  background: var(--tn-bg);
  color: var(--tn-text);
  font-size: 16px;
  line-height: 1.55;
}

body::before {
  position: fixed;
  inset: 0;
  z-index: -1;
  border: 1px solid transparent;
  content: "";
  pointer-events: none;
}

a {
  color: inherit;
  text-decoration: none;
}

button,
a {
  -webkit-tap-highlight-color: transparent;
}

button {
  font: inherit;
}

a:focus-visible,
button:focus-visible {
  outline: 2px solid var(--tn-amber-light);
  outline-offset: 4px;
}

.skip-link {
  position: fixed;
  top: 10px;
  left: 10px;
  z-index: 100;
  min-height: 44px;
  padding: 11px 16px;
  translate: 0 -150%;
  background: var(--tn-text);
  color: var(--tn-bg);
  font-weight: 700;
}

.skip-link:focus {
  translate: 0;
}

.site-header {
  position: fixed;
  top: 0;
  right: 0;
  left: 0;
  z-index: 20;
  display: grid;
  grid-template-columns: minmax(190px, 1fr) auto minmax(190px, 1fr);
  align-items: center;
  min-height: var(--tn-header);
  padding: 0 var(--tn-gutter);
  border-bottom: 1px solid transparent;
  background: rgba(0, 0, 0, 0.94);
  transition:
    border-color 240ms ease,
    min-height 240ms ease;
}

.site-header.is-scrolled {
  min-height: 64px;
  border-color: var(--tn-line);
}

.brand {
  display: inline-flex;
  align-items: center;
  gap: 13px;
  width: max-content;
  min-height: 44px;
  color: var(--tn-amber-light);
  font-family: "Silkscreen", monospace;
  font-size: 0.92rem;
  letter-spacing: 0.02em;
}

/* ==========================================================================
   La marque : cinq pixels qui tombent.

   Le logo au repos ne change pas — cinq pixels en croix, coeur clair, pied
   vert. L'animation ne fait que les amener : ils tombent du haut, s'ecrasent,
   rebondissent une fois et se posent. Rien ne subsiste apres, l'etat final est
   exactement l'etat de repos.

   Le mot arrive de la meme facon, mais de gauche a droite : chaque lettre
   tombe, rebondit, se pose. Elle part de rien — opacite nulle — et c'est le
   keyframe 0 % qui le dit, jamais une regle de base : une regle de base qui
   cacherait le mot laisserait un lockup vide partout ou l'animation ne joue
   pas (impression, `prefers-reduced-motion`, JS coupe).

   Les pixels sont poses en absolu par --col / --row, en pas de grille : une
   grille CSS aurait fait grandir la boite pendant la chute, et donc pousse le
   mot a chaque image. Les tailles passent par --px / --gap et jamais par
   scale() : un pixel doit tomber sur une valeur entiere, sinon ses bords
   s'anticrenellent et le lockup perd le grain qui fait tout son interet.
   ========================================================================== */

/* Le tempo est porte par le lockup entier, pas par le mark : le mot doit se
   caler sur la meme chute, et il n'est pas dans la fleur.

   --drop est le cycle, pas la duree du mouvement. La chute d'un element
   occupe les 12 premiers pour cent (300 ms) ; le reste est du repos, ce qui
   donne a la boucle de la page de demonstration le temps de respirer entre
   deux passages. Sur le site, l'animation ne joue qu'une fois : le lockup est
   pose en une seconde, et plus rien ne bouge. */
.brand,
.hero-product-mark {
  --drop: 2.4s;
}

/* Hauteur d'un pas de chute pour le mot, en pixels ENTIERS et non en em.
   Un pas en em vaut 11,232 px au hero : la lettre tombe alors sur des demi
   pixels, et Silkscreen — une police bitmap — se retrouve reechantillonnee a
   chaque palier. Tout le dessin est fonde sur des bords nets ; le mot doit
   tomber avec la meme discipline que les pixels du mark. */
.brand {
  --rise: 4px;
}

.hero-product-mark {
  --rise: 11px;
}

.brand-pixels {
  --px: 5px;
  --gap: 2px;
  --pitch: calc(var(--px) + var(--gap));
  position: relative;
  display: block;
  flex: none;
  width: calc(3 * var(--px) + 2 * var(--gap));
  height: calc(3 * var(--px) + 2 * var(--gap));
}

.brand-pixels i {
  position: absolute;
  top: calc(var(--row) * var(--pitch));
  left: calc(var(--col) * var(--pitch));
  width: var(--px);
  height: var(--px);
  background: var(--tn-amber);
}

.brand-pixels i:nth-child(1) {
  --col: 1;
  --row: 0;
}

.brand-pixels i:nth-child(2) {
  --col: 0;
  --row: 1;
}

.brand-pixels i:nth-child(3) {
  --col: 1;
  --row: 1;
  background: var(--tn-amber-light);
}

.brand-pixels i:nth-child(4) {
  --col: 2;
  --row: 1;
}

.brand-pixels i:nth-child(5) {
  --col: 1;
  --row: 2;
  background: var(--tn-leaf);
}

/* Le mot, une lettre par element. Les <span> sont colles, sans espace ni
   retour a la ligne entre eux : c'est ce qui garantit qu'une synthese vocale
   lit TOURNESOL et non neuf lettres.

   `inline-block` est structurel, pas cosmetique : `translate` ne s'applique
   pas a un element en ligne non remplace — sans lui, les lettres ne tombent
   pas du tout. */
/* `nowrap` est structurel : neuf inline-block peuvent se couper entre eux la
   ou un seul noeud de texte sans espace ne le pouvait pas. Sans cette regle,
   le mot se brise au milieu — TOURNE / SOL — des que la place manque. */
.brand-word {
  white-space: nowrap;
}

.brand-word span {
  display: inline-block;
}

.brand-word span:nth-child(1) { --i: 0; }
.brand-word span:nth-child(2) { --i: 1; }
.brand-word span:nth-child(3) { --i: 2; }
.brand-word span:nth-child(4) { --i: 3; }
.brand-word span:nth-child(5) { --i: 4; }
.brand-word span:nth-child(6) { --i: 5; }
.brand-word span:nth-child(7) { --i: 6; }
.brand-word span:nth-child(8) { --i: 7; }
.brand-word span:nth-child(9) { --i: 8; }

/* --------------------------------------------------------------------------
   La chute.

   `steps(1, end)` partout : la valeur tient jusqu'au keyframe suivant, puis
   saute. Aucune interpolation — un pixel qui glisse en 300 ms n'est plus un
   pixel, c'est un objet. La chute se lit donc comme une suite de positions,
   resserrees a l'approche du sol : c'est ce qui donne la pesanteur, sans
   courbe d'acceleration.

   L'eclat a l'impact passe par filter: brightness() et non par une couleur —
   c'est le seul moyen de faire briller un pixel sans savoir de quelle couleur
   il est. Le pied est vert, le coeur est clair, les branches sont ambre : une
   couleur en dur aurait uniformise les trois.
   -------------------------------------------------------------------------- */

@keyframes tn-drop {
  0% {
    translate: 0 calc(var(--pitch) * -3);
    opacity: 0;
  }
  0.5% {
    opacity: 1;
  }
  3% {
    translate: 0 calc(var(--pitch) * -2);
  }
  6% {
    translate: 0 calc(var(--pitch) * -1);
  }
  9% {
    translate: 0 0;
    filter: brightness(2.4);
  }
  10% {
    filter: brightness(1);
  }
  10.5% {
    translate: 0 calc(var(--pitch) * -1);
  }
  12.5%,
  100% {
    translate: 0 0;
  }
}

/* Meme mouvement, meme rythme, autre unite : la lettre tombe de six pas de
   --rise la ou le pixel tombe de six pas de grille. */
@keyframes tn-letter {
  0% {
    translate: 0 calc(var(--rise) * -3);
    opacity: 0;
  }
  0.5% {
    opacity: 1;
  }
  3% {
    translate: 0 calc(var(--rise) * -2);
  }
  6% {
    translate: 0 calc(var(--rise) * -1);
  }
  9% {
    translate: 0 0;
    filter: brightness(1.9);
  }
  10% {
    filter: brightness(1);
  }
  10.5% {
    translate: 0 calc(var(--rise) * -1);
  }
  12.5%,
  100% {
    translate: 0 0;
  }
}

/* --------------------------------------------------------------------------
   Declenchement.

   `backwards` est ce qui fait tenir le « de rien » : avant que le retard ne
   soit ecoule, c'est le keyframe 0 % qui s'applique — la lettre n'est pas
   encore la. Sans fill-mode, elle serait visible, puis disparaitrait d'un
   coup au moment de tomber.

   Aucun `forwards` en revanche : une fois l'animation finie, on veut revenir
   au style de base, qui est exactement l'etat de repos de la marque. C'est ce
   qui garantit qu'aucune animation ne peut laisser le logo dans un etat qui
   n'est pas les cinq pixels.
   -------------------------------------------------------------------------- */

.hero-product-mark .brand-pixels i {
  animation: tn-drop var(--drop) steps(1, end) backwards 1
    calc(var(--i-px, 0) * 45ms);
}

.brand-pixels i:nth-child(1) { --i-px: 0; }
.brand-pixels i:nth-child(2) { --i-px: 1; }
.brand-pixels i:nth-child(3) { --i-px: 2; }
.brand-pixels i:nth-child(4) { --i-px: 3; }
.brand-pixels i:nth-child(5) { --i-px: 4; }

/* Le mot part quand le dernier pixel est au sol : le lockup s'ecrit d'un seul
   geste, de la croix vers la derniere lettre. */
.hero-product-mark .brand-word span {
  animation: tn-letter var(--drop) steps(1, end) backwards 1
    calc(400ms + var(--i, 0) * 34ms);
}

/* Dans l'en-tete et le pied de page, la chute ne se rejoue qu'au survol — et
   UNE SEULE FOIS. En boucle, le lockup repasserait par son keyframe 0 %,
   c'est-a-dire par l'invisible, toutes les 2,4 s : le logo clignoterait sous
   le curseur de quelqu'un qui est simplement en train de le viser. Le compteur
   a 1 suffit a le rejouer a chaque nouveau survol, puisque la regle est retiree
   puis reappliquee quand le curseur repasse.

   Ici, et ici seulement, pas de `backwards` : la marque est DEJA affichee: la
   faire disparaitre 400 ms le temps que son tour arrive serait un defaut, pas
   une entree en matiere. Sans fill-mode, chaque element garde son style de
   base — pose, visible — jusqu'a son propre retard, puis saute en haut et
   retombe. L'opacite nulle du keyframe 0 % ne dure alors que 12 ms, moins
   d'une image a 60 Hz : elle sert l'entree du hero, elle ne se voit pas ici.

   Le survol est filtre par `hover: hover` : sur un ecran tactile, `:hover`
   reste colle apres un appui, et le lockup rejouerait sa chute a chaque
   effleurement. `:focus-visible` reste en dehors du filtre — c'est le chemin
   clavier, et il existe aussi sur les appareils tactiles. */
@media (hover: hover) {
  .brand:hover .brand-pixels i {
    animation: tn-drop var(--drop) steps(1, end) 1
      calc(var(--i-px, 0) * 45ms);
  }

  .brand:hover .brand-word span {
    animation: tn-letter var(--drop) steps(1, end) 1
      calc(400ms + var(--i, 0) * 34ms);
  }
}

.brand:focus-visible .brand-pixels i {
  animation: tn-drop var(--drop) steps(1, end) 1
    calc(var(--i-px, 0) * 45ms);
}

.brand:focus-visible .brand-word span {
  animation: tn-letter var(--drop) steps(1, end) 1
    calc(400ms + var(--i, 0) * 34ms);
}

/* A l'impression, la marque est posee. Sans cette regle, une page imprimee
   avant que l'animation n'ait tourne — onglet ouvert en arriere-plan, par
   exemple — sortirait avec le mot invisible : `backwards` applique le
   keyframe 0 %, qui est a opacite nulle. */
@media print {
  .brand-pixels i,
  .brand-word span {
    animation: none !important;
  }
}

.site-header nav {
  display: flex;
  align-items: center;
  gap: clamp(13px, 1.7vw, 30px);
  min-width: 0;
}

.site-header nav a,
.header-action {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: #d7d7d3;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.72rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
  transition: color 160ms ease;
}

.site-header nav a {
  position: relative;
  flex: 0 0 auto;
  font-size: clamp(0.6rem, 0.78vw, 0.7rem);
  letter-spacing: 0.1em;
  white-space: nowrap;
}

/* Underline the section currently in view, so the bar reads as a position. */
.site-header nav a::after {
  position: absolute;
  right: 0;
  bottom: 9px;
  left: 0;
  height: 1px;
  background: var(--tn-amber);
  content: "";
  opacity: 0;
  transition: opacity 160ms ease;
}

.site-header nav a[aria-current="true"]::after {
  opacity: 1;
}

.site-header nav a:hover,
.site-header nav a[aria-current="true"],
.header-action:hover {
  color: var(--tn-amber-light);
}

.header-end {
  display: flex;
  align-items: center;
  justify-content: flex-end;
  gap: clamp(14px, 2vw, 28px);
  justify-self: end;
}

.header-action {
  border-bottom: 1px solid var(--tn-amber);
}

.lang-switch {
  display: flex;
  align-items: center;
  gap: 8px;
  margin: 0;
  color: #7d7d78;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.68rem;
  letter-spacing: 0.12em;
}

.lang-switch a {
  display: inline-flex;
  align-items: center;
  min-height: 44px;
  color: #d7d7d3;
  transition: color 160ms ease;
}

.lang-switch a:hover {
  color: var(--tn-amber-light);
}

.lang-switch [aria-current="true"] {
  color: var(--tn-amber);
}

.lang-switch::before {
  color: var(--tn-line-light);
  content: "";
}

main {
  display: block;
}

.hero {
  position: relative;
  display: grid;
  grid-template-columns: minmax(430px, 0.95fr) minmax(460px, 1.05fr);
  align-items: center;
  min-height: 100svh;
  padding: calc(var(--tn-header) + 48px) var(--tn-gutter) 72px;
  overflow: hidden;
  border-bottom: 1px solid var(--tn-line);
  isolation: isolate;
}

.hero-copy {
  position: relative;
  z-index: 3;
  max-width: 670px;
}

.hero-product-mark {
  display: inline-flex;
  align-items: center;
  gap: 22px;
  margin: 0 0 26px;
  color: var(--tn-amber-light);
  font-family: "Silkscreen", monospace;
  font-size: clamp(1.6rem, 2.6vw, 2.4rem);
  letter-spacing: 0.02em;
}

/* Le mark du hero est le meme dessin, en pixels plus gros — pas le meme
   dessin agrandi. `scale()` aurait donne des pixels de 6,3 px, donc des bords
   flous une fois sur deux. */
.hero-product-mark .brand-pixels {
  --px: 11px;
  --gap: 4px;
  margin-right: 4px;
}

.concept-status {
  display: flex;
  align-items: center;
  gap: 12px;
  margin: 0 0 32px;
  color: var(--tn-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.7rem;
  letter-spacing: 0.13em;
  text-transform: uppercase;
}

.concept-status span {
  width: 6px;
  height: 6px;
  background: var(--tn-amber);
}

h1,
h2,
p {
  margin-top: 0;
}

h1 {
  max-width: 18ch;
  margin-bottom: 30px;
  font-family: "Silkscreen", monospace;
  font-size: clamp(2.3rem, 3.2vw, 3.8rem);
  font-weight: 400;
  line-height: 1.14;
  letter-spacing: 0;
  text-wrap: balance;
  white-space: nowrap;
}

h2 {
  max-width: 15ch;
  margin-bottom: 28px;
  font-family: "Silkscreen", monospace;
  font-size: clamp(1.85rem, 3.25vw, 3.55rem);
  font-weight: 400;
  line-height: 1.08;
  letter-spacing: 0;
  text-wrap: balance;
}

[data-motion-section] h2::after {
  display: block;
  width: 72px;
  height: 2px;
  margin-top: 24px;
  background: var(--tn-amber);
  content: "";
  opacity: 0;
  transform: scaleX(0);
  transform-origin: left center;
  transition:
    opacity 240ms ease,
    transform 700ms cubic-bezier(0.2, 0.7, 0.2, 1);
}

[data-motion-section].is-in-view h2::after {
  opacity: 1;
  transform: scaleX(1);
}

.hero-intro,
.section-copy p,
.tracking-copy p,
.feature-heading > p:last-child,
.specs-heading p,
.programme-copy > p {
  max-width: 62ch;
  color: var(--tn-muted);
  font-size: clamp(1rem, 1.4vw, 1.2rem);
  line-height: 1.7;
}

.hero-intro {
  max-width: 54ch;
  margin-bottom: 38px;
  color: #cececa;
}

.hero-actions {
  display: flex;
  flex-wrap: wrap;
  gap: 14px;
}

.button {
  display: inline-flex;
  background: transparent;
  align-items: center;
  justify-content: center;
  min-height: 50px;
  padding: 0 24px;
  border: 1px solid var(--tn-line-light);
  color: var(--tn-text);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.74rem;
  letter-spacing: 0.1em;
  text-align: center;
  text-transform: uppercase;
  transition:
    border-color 180ms ease,
    background 180ms ease,
    color 180ms ease;
}

.button-primary {
  border-color: var(--tn-amber);
  color: var(--tn-amber-light);
}

.button:hover {
  border-color: var(--tn-text);
  background: var(--tn-text);
  color: var(--tn-bg);
}

.button-primary:hover {
  border-color: var(--tn-amber-light);
  background: var(--tn-amber-light);
}

.hero-visual {
  position: relative;
  z-index: 1;
  min-width: 0;
  min-height: min(76vh, 820px);
}

.model-stage {
  position: absolute;
  inset: 1% 0 114px -8%;
  overflow: hidden;
}

.model-version {
  position: absolute;
  top: 22px;
  left: 0;
  z-index: 4;
  display: inline-flex;
  align-items: center;
  gap: 10px;
  margin: 0;
  color: var(--tn-muted);
  font-family: "Silkscreen", monospace;
  font-size: 0.62rem;
  letter-spacing: 0.08em;
}

.model-version::before {
  width: 6px;
  height: 6px;
  background: var(--tn-amber);
  content: "";
}

.model-stage:focus-visible {
  outline: 1px solid var(--tn-amber-light);
  outline-offset: 4px;
}

.model-stage canvas,
.model-poster {
  position: absolute;
  inset: 0;
  display: block;
  width: 100%;
  height: 100%;
}

.model-poster {
  object-fit: contain;
  opacity: 0;
  transition: opacity 240ms ease;
}

.model-poster.is-visible {
  opacity: 1;
}

.model-stage canvas {
  z-index: 2;
  cursor: grab;
  opacity: 0;
  transition: opacity 320ms ease;
  touch-action: pan-y;
}

.model-stage canvas:active {
  cursor: grabbing;
}

.model-stage canvas,
.composition-stage canvas {
  transition: opacity 420ms ease;
}

.model-stage.is-ready canvas {
  opacity: 1;
}

/* Plus de cartouche de chargement : la scene reste simplement noire, puis le
   modele apparait en fondu. Le message subsiste pour les lecteurs d'ecran, que
   l'attente laisserait autrement sans reponse — il est retire du visuel, pas de
   l'accessibilite. */
.model-loading {
  position: absolute;
  width: 1px;
  height: 1px;
  margin: -1px;
  padding: 0;
  overflow: hidden;
  border: 0;
  clip-path: inset(50%);
  white-space: nowrap;
}

.model-stage.is-ready .model-loading {
  display: none;
}

.model-controls {
  position: absolute;
  right: 124px;
  bottom: 0;
  left: 0;
  z-index: 4;
  display: grid;
  grid-template-columns: repeat(2, minmax(150px, 1fr));
  gap: 8px 20px;
  min-width: 0;
  margin: 0;
  padding: 22px 18px 0 0;
  border: 0;
  border-top: 1px solid var(--tn-line);
}

.model-controls legend {
  position: absolute;
  top: 0;
  left: 0;
  padding: 0 10px 0 0;
  translate: 0 -50%;
  background: var(--tn-bg);
  color: var(--tn-muted);
  font-family: "Silkscreen", monospace;
  font-size: 0.56rem;
  line-height: 1;
}

.axis-control {
  display: grid;
  grid-template-rows: auto 44px;
  min-width: 0;
}

.axis-control-label {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 16px;
}

.axis-control label,
.axis-control output {
  color: var(--tn-text);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.68rem;
  font-variant-numeric: tabular-nums;
  letter-spacing: 0.1em;
}

.axis-control label {
  color: var(--tn-muted);
}

.axis-control output {
  min-width: 5ch;
  color: var(--tn-amber-light);
  text-align: right;
}

.axis-control input[type="range"] {
  width: 100%;
  min-width: 0;
  min-height: 44px;
  margin: 0;
  accent-color: var(--tn-amber);
  cursor: ew-resize;
}

.axis-control input[type="range"]:focus-visible {
  outline: 2px solid var(--tn-amber-light);
  outline-offset: 2px;
}

.model-controls:disabled {
  opacity: 0.46;
}

.model-controls:disabled input {
  cursor: default;
}

#model-control-note {
  grid-column: 1 / -1;
  margin: -7px 0 0;
  color: #777772;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.56rem;
  line-height: 1.3;
  letter-spacing: 0.04em;
}

.motion-toggle {
  position: absolute;
  right: 0;
  bottom: 10px;
  z-index: 4;
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-width: 96px;
  min-height: 44px;
  border: 0;
  border-bottom: 1px solid var(--tn-line-light);
  background: transparent;
  color: var(--tn-muted);
  cursor: pointer;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.motion-toggle:hover {
  color: var(--tn-text);
}

.motion-toggle:disabled {
  color: var(--tn-muted);
  cursor: default;
}

.scroll-cue {
  position: absolute;
  bottom: 28px;
  left: var(--tn-gutter);
  display: inline-flex;
  align-items: center;
  gap: 12px;
  min-height: 44px;
  color: var(--tn-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.65rem;
  letter-spacing: 0.12em;
  text-transform: uppercase;
}

.scroll-cue i {
  display: block;
  width: 36px;
  height: 1px;
  background: var(--tn-line-light);
}

.section-shell,
.tracking,
.tracking-person,
.text-section,
.connectivity,
.team,
.specifications,
.programme {
  position: relative;
  padding: clamp(64px, 7vw, 108px) var(--tn-gutter);
  border-bottom: 1px solid var(--tn-line);
}

.section-shell {
  display: grid;
  grid-template-columns: minmax(300px, 0.78fr) minmax(420px, 1.22fr);
  align-items: center;
  gap: clamp(50px, 8vw, 130px);
}

.text-section {
  display: flex;
  align-items: center;
}

.text-section .section-copy,
.text-section .tracking-copy {
  max-width: 820px;
}

.text-section:nth-of-type(even) {
  background: #030303;
}

.optics-lab {
  position: relative;
  padding: clamp(60px, 6.5vw, 100px) var(--tn-gutter);
  overflow: hidden;
  border-bottom: 1px solid var(--tn-line);
  background: #030303;
}

.optics-lab::before {
  position: absolute;
  top: 0;
  left: var(--tn-gutter);
  width: 8px;
  height: 8px;
  background: var(--tn-amber);
  content: "";
}

.optics-lab-heading {
  display: grid;
  grid-template-columns: minmax(310px, 0.9fr) minmax(380px, 1.1fr);
  align-items: end;
  gap: clamp(42px, 7vw, 110px);
  max-width: 1320px;
  margin: 0 auto clamp(54px, 7vw, 92px);
}

.optics-lab-heading h2 {
  grid-column: 1;
  margin-bottom: 0;
}

.optics-lab-heading > p:last-child {
  grid-column: 2;
  margin: 0 0 4px;
  color: var(--tn-muted);
  font-size: clamp(1rem, 1.35vw, 1.17rem);
  line-height: 1.7;
}

/* Every kicker sits this far above its title, whatever the container. */
.optics-lab-heading,
.composition-heading,
.feature-heading,
.specs-heading {
  row-gap: 20px;
}

.feature-heading {
  display: grid;
  align-content: start;
}

.section-kicker {
  grid-column: 1 / -1;
  margin: 0;
  color: var(--tn-amber);
  font-family: "Silkscreen", monospace;
  font-size: 0.68rem;
  letter-spacing: 0.08em;
}

.optics-simulator {
  max-width: 1320px;
  margin: 0 auto;
  border: 1px solid var(--tn-line);
  background: var(--tn-bg);
}

.optics-toolbar {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  min-height: 68px;
  padding: 10px 18px 10px 24px;
  border-bottom: 1px solid var(--tn-line);
}

.optics-toolbar p {
  margin: 0;
  color: var(--tn-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.68rem;
  letter-spacing: 0.06em;
  text-transform: uppercase;
}

.optics-toolbar button {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 44px;
  padding: 0 15px;
  border: 1px solid var(--tn-line-light);
  background: transparent;
  color: var(--tn-text);
  cursor: pointer;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.64rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

.optics-toolbar button:hover,
.optics-toolbar button:focus-visible {
  border-color: var(--tn-amber);
  color: var(--tn-amber-light);
}

.optics-stage {
  display: block;
  width: 100%;
  aspect-ratio: 800 / 430;
  min-height: 360px;
  max-height: 680px;
  background: #020202;
  touch-action: none;
  user-select: none;
}

.optics-stage path,
.optics-stage line,
.optics-stage circle,
.optics-stage rect {
  vector-effect: non-scaling-stroke;
}

.optics-sun-arc,
.optics-grid-line,
.optics-normal {
  fill: none;
  stroke: var(--tn-line-light);
  stroke-width: 1;
}

.optics-sun-arc {
  stroke: #6f5200;
  stroke-dasharray: 5 8;
}

.optics-grid-line {
  stroke: #181818;
}

.optics-ray {
  stroke-linecap: square;
  stroke-width: 2;
}

.optics-ray-in {
  stroke: var(--tn-amber);
}

.optics-ray-out {
  stroke: var(--tn-text);
}

.optics-normal {
  stroke-dasharray: 5 7;
}

.optics-mirror {
  stroke: #d8dde0;
  stroke-width: 8;
}

.optics-stage-wrap {
  position: relative;
}

.optics-pivot {
  fill: var(--tn-amber);
}

.optics-handle {
  cursor: grab;
  outline: none;
}

.optics-handle:active {
  cursor: grabbing;
}

.optics-handle:focus-visible {
  filter: drop-shadow(0 0 7px var(--tn-amber));
}

.optics-sun circle,
.optics-sun rect {
  fill: var(--tn-amber);
  stroke: var(--tn-amber-light);
  stroke-width: 1;
}

.optics-sun path {
  fill: none;
  stroke: var(--tn-amber);
  stroke-width: 2;
}

/* The target stays hollow so anything behind it — the sun above all — keeps
   showing through if the two ever line up. */
.optics-target rect,
.optics-target path {
  fill: none;
  stroke: var(--tn-text);
  stroke-width: 1.5;
}

.optics-target rect:last-child {
  fill: var(--tn-text);
}

.optics-label {
  fill: var(--tn-muted);
  font-family: "Silkscreen", monospace;
  font-size: 11px;
}

.optics-direction {
  fill: var(--tn-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 10px;
  letter-spacing: 0.12em;
}

.optics-course-label {
  fill: var(--tn-amber);
  font-family: "Silkscreen", monospace;
  text-anchor: middle;
}

.optics-label-mirror {
  fill: var(--tn-text);
}

.optics-readout {
  display: grid;
  grid-template-columns: repeat(4, 1fr);
  margin: 0;
  border-top: 1px solid var(--tn-line);
}

.optics-readout div {
  min-width: 0;
  padding: 18px 22px 20px;
  border-right: 1px solid var(--tn-line);
}

.optics-readout div:last-child {
  border-right: 0;
}

.optics-readout dt,
.optics-readout dd {
  margin: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  letter-spacing: 0.08em;
}

.optics-readout dt {
  color: var(--tn-muted);
  font-size: 0.58rem;
}

.optics-readout dd {
  margin-top: 8px;
  color: var(--tn-text);
  font-size: clamp(0.82rem, 1.3vw, 1rem);
}

.optics-readout div:last-child dd {
  color: var(--tn-amber-light);
}

.section-copy {
  max-width: var(--tn-copy);
}












.composition {
  position: relative;
  padding: clamp(64px, 7vw, 108px) var(--tn-gutter);
  border-bottom: 1px solid var(--tn-line);
  background: #030303;
}

.composition-heading {
  display: grid;
  gap: 18px;
  max-width: var(--tn-content);
  margin: 0 auto clamp(48px, 6vw, 84px);
}

.composition-heading h2 {
  margin-bottom: 0;
}





/* Durability, folded into the composition heading as a compact strip. */
.composition-durability {
  display: grid;
  grid-template-columns: minmax(260px, 0.9fr) minmax(280px, 1.1fr);
  align-items: center;
  gap: clamp(20px, 3vw, 48px);
  margin-top: 8px;
  padding-top: 26px;
  border-top: 1px solid var(--tn-line);
}

.composition-durability p {
  max-width: 48ch;
  margin: 0;
  color: #7d7d78;
  font-size: 0.86rem;
  line-height: 1.6;
}

.composition-durability ul {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  margin: 0;
  padding: 0;
  list-style: none;
}

.composition-durability li {
  padding: 4px 14px;
  border-left: 1px solid var(--tn-line);
  color: var(--tn-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.58rem;
  line-height: 1.45;
  letter-spacing: 0.09em;
}

.composition-durability li:first-child {
  padding-left: 0;
  border-left: 0;
}

.composition-layout {
  display: grid;
  grid-template-columns: minmax(250px, 0.72fr) minmax(420px, 1.28fr);
  align-items: start;
  gap: clamp(32px, 4.5vw, 76px);
  max-width: var(--tn-content);
  margin: 0 auto;
}

.composition-list {
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--tn-line);
  list-style: none;
  counter-reset: none;
}

.composition-row {
  border-bottom: 1px solid var(--tn-line);
}

.composition-row button {
  display: grid;
  grid-template-columns: 34px 1fr;
  align-items: center;
  gap: 14px;
  width: 100%;
  min-height: 46px;
  padding: 9px 6px 9px 0;
  border: 0;
  border-left: 2px solid transparent;
  background: transparent;
  color: var(--tn-muted);
  cursor: pointer;
  text-align: left;
  transition:
    color 220ms ease,
    border-color 220ms ease,
    padding-left 220ms ease;
}

.composition-row button:hover {
  color: var(--tn-text);
}

.composition-row.is-active button {
  padding-left: 12px;
  border-left-color: var(--tn-amber);
  color: var(--tn-text);
}

.composition-row-index {
  color: var(--tn-line-light);
  font-family: "Silkscreen", monospace;
  font-size: 0.68rem;
  transition: color 220ms ease;
}

.composition-row.is-active .composition-row-index {
  color: var(--tn-amber);
}

.composition-row-body {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  min-width: 0;
}

.composition-row-body strong {
  font-size: 0.82rem;
  font-weight: 500;
  letter-spacing: 0.04em;
}

.composition-row-body > span {
  color: #7d7d78;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.6rem;
  letter-spacing: 0.06em;
  text-align: right;
  white-space: nowrap;
}

.composition-row.is-active .composition-row-body > span {
  color: var(--tn-muted);
}

.composition-viewer {
  position: relative;
  display: grid;
  gap: 18px;
  min-width: 0;
}

.composition-stage {
  position: relative;
  aspect-ratio: 5 / 6;
  max-height: 76svh;
  border: 1px solid var(--tn-line);
  background: #000000;
}

.composition-stage canvas {
  display: block;
  width: 100%;
  height: 100%;
  opacity: 0;
  transition: opacity var(--tn-slow);
  touch-action: pan-y;
  cursor: grab;
}

.composition-stage.is-ready canvas {
  opacity: 1;
}

.composition-stage.is-ready .model-loading {
  display: none;
}

.composition-markers {
  position: absolute;
  inset: 0;
  z-index: 2;
  opacity: 0;
  pointer-events: none;
  transition: opacity 260ms ease;
}

.composition-marker {
  position: absolute;
  top: 0;
  left: 18px;
  display: inline-block;
  translate: 0 -50%;
  padding: 3px 6px;
  border: 1px solid var(--tn-line-light);
  background: rgba(0, 0, 0, 0.72);
  color: var(--tn-muted);
  cursor: pointer;
  font-family: "Silkscreen", monospace;
  font-size: 0.56rem;
  line-height: 1;
  pointer-events: auto;
}

.composition-marker:hover {
  border-color: var(--tn-muted);
  color: var(--tn-text);
}

.composition-marker::after {
  position: absolute;
  top: 50%;
  left: 100%;
  width: var(--leader, 0);
  height: 1px;
  transform: rotate(var(--leader-angle, 0rad));
  transform-origin: 0 50%;
  background: var(--tn-line);
  content: "";
}

.composition-marker.is-active {
  border-color: var(--tn-amber);
  color: var(--tn-amber-light);
}

.composition-marker.is-active::after {
  background: rgba(245, 173, 0, 0.55);
}

.composition-note {
  margin: 0;
  min-height: 2.6em;
  max-width: 62ch;
  color: var(--tn-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.68rem;
  line-height: 1.5;
  letter-spacing: 0.03em;
}

.composition-controls {
  display: grid;
  grid-template-columns: minmax(180px, 1fr) auto;
  align-items: end;
  gap: 12px 28px;
  padding-top: 20px;
  border-top: 1px solid var(--tn-line);
}

.composition-buttons {
  display: flex;
  flex-wrap: wrap;
  gap: 8px 20px;
}

.composition-button {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  min-height: 44px;
  padding: 0;
  border: 0;
  border-bottom: 1px solid var(--tn-line-light);
  background: transparent;
  color: var(--tn-muted);
  cursor: pointer;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.66rem;
  letter-spacing: 0.1em;
  text-transform: uppercase;
}

.composition-button:hover {
  color: var(--tn-text);
}

.composition-button[aria-pressed="true"] {
  border-bottom-color: var(--tn-amber);
  color: var(--tn-amber-light);
}

#composition-control-note {
  grid-column: 1 / -1;
  margin: 0;
  color: #777772;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.56rem;
  line-height: 1.4;
  letter-spacing: 0.04em;
}


.tracking {
  display: grid;
  grid-template-columns: minmax(320px, 0.88fr) minmax(440px, 1.12fr);
  align-items: center;
  gap: clamp(48px, 8vw, 130px);
  overflow: hidden;
}

.tracking-copy {
  position: relative;
  z-index: 2;
}

.tracking-person {
  grid-template-columns: minmax(440px, 1.1fr) minmax(320px, 0.9fr);
  background: #030303;
}

.fusion {
  width: min(100%, 720px);
  padding: clamp(20px, 3vw, 36px);
  border: 1px solid var(--tn-line);
}

.fusion-stage {
  display: block;
  width: 100%;
  height: auto;
}

.fusion-traces path {
  fill: none;
  stroke: var(--tn-line-light);
  stroke-width: 1;
}

.fusion-labels text {
  fill: var(--tn-text);
  font-family: "Silkscreen", monospace;
  font-size: 15px;
  text-anchor: end;
}

.fusion-nodes rect {
  fill: var(--tn-amber);
}

.fusion-core {
  fill: #0a0a0a;
  stroke: var(--tn-amber);
  stroke-width: 1;
}

.fusion-core-label {
  fill: var(--tn-amber-light);
  font-family: "Silkscreen", monospace;
  font-size: 16px;
  text-anchor: middle;
}

.fusion-output {
  fill: var(--tn-text);
  font-family: "Silkscreen", monospace;
  font-size: 16px;
}

.fusion-output-cell {
  fill: var(--tn-amber);
}

.fusion-spark {
  fill: none;
  stroke: var(--tn-amber-light);
  stroke-width: 5;
  stroke-dasharray: 4 96;
  stroke-dashoffset: 100;
  opacity: 0;
}

/* One cycle: every source lights its own trace and sends a pixel down it to
   the fusion box; once they have all landed the box locks and emits. */
.fusion.is-motion-active .fusion-spark,
.fusion.is-motion-active .fusion-trace-in,
.fusion.is-motion-active .fusion-nodes rect {
  animation-duration: 2.6s;
  animation-iteration-count: infinite;
}

.fusion.is-motion-active .fusion-spark {
  animation-name: fusion-run;
  animation-timing-function: steps(20, end);
}

.fusion.is-motion-active .fusion-trace-in {
  animation-name: fusion-trace-live;
  animation-timing-function: steps(2, end);
}

.fusion.is-motion-active .fusion-nodes rect {
  animation-name: fusion-node;
  animation-timing-function: steps(2, end);
}

.fusion.is-motion-active [data-route="2"] {
  animation-delay: 0.13s;
}

.fusion.is-motion-active [data-route="3"] {
  animation-delay: 0.26s;
}

.fusion.is-motion-active [data-route="4"] {
  animation-delay: 0.39s;
}

.fusion.is-motion-active [data-route="5"] {
  animation-delay: 0.52s;
}

.fusion.is-motion-active .fusion-spark[data-route="6"] {
  animation-name: fusion-emit;
  animation-timing-function: steps(10, end);
  animation-delay: 0s;
}

.fusion.is-motion-active .fusion-trace-bus,
.fusion.is-motion-active .fusion-trace-feed {
  animation: fusion-trace-live 2.6s steps(2, end) infinite;
  animation-delay: 0.2s;
}

.fusion.is-motion-active .fusion-trace-out {
  animation: fusion-trace-out 2.6s steps(2, end) infinite;
}

.fusion.is-motion-active .fusion-core {
  animation: fusion-lock 2.6s steps(2, end) infinite;
}

.fusion.is-motion-active .fusion-core-label {
  animation: fusion-lock-label 2.6s steps(2, end) infinite;
}

.fusion.is-motion-active .fusion-output-cell {
  animation: fusion-node 2.6s steps(2, end) infinite;
  animation-delay: 1.75s;
}

@keyframes fusion-run {
  0% {
    stroke-dashoffset: 100;
    opacity: 0;
  }
  4% {
    opacity: 1;
  }
  46% {
    stroke-dashoffset: 0;
    opacity: 1;
  }
  50%,
  100% {
    stroke-dashoffset: 0;
    opacity: 0;
  }
}

@keyframes fusion-emit {
  0%,
  67% {
    stroke-dashoffset: 100;
    opacity: 0;
  }
  69% {
    stroke-dashoffset: 100;
    opacity: 1;
  }
  88% {
    stroke-dashoffset: 0;
    opacity: 1;
  }
  92%,
  100% {
    stroke-dashoffset: 0;
    opacity: 0;
  }
}

@keyframes fusion-node {
  0%,
  6% {
    fill: var(--tn-amber-light);
  }
  12%,
  100% {
    fill: var(--tn-amber);
  }
}

@keyframes fusion-trace-live {
  0% {
    stroke: var(--tn-line-light);
  }
  3%,
  48% {
    stroke: var(--tn-amber);
  }
  54%,
  100% {
    stroke: var(--tn-line-light);
  }
}

@keyframes fusion-trace-out {
  0%,
  67% {
    stroke: var(--tn-line-light);
  }
  69%,
  90% {
    stroke: var(--tn-amber);
  }
  94%,
  100% {
    stroke: var(--tn-line-light);
  }
}

@keyframes fusion-lock {
  0%,
  63% {
    fill: #0a0a0a;
  }
  65%,
  74% {
    fill: #241c07;
  }
  78%,
  100% {
    fill: #0a0a0a;
  }
}

@keyframes fusion-lock-label {
  0%,
  63% {
    fill: var(--tn-amber-light);
  }
  65%,
  74% {
    fill: #fff6dd;
  }
  78%,
  100% {
    fill: var(--tn-amber-light);
  }
}






.energy {
}







/* Kept as standalone selectors: grouping them with another figure's rules
   is what let a cleanup pass strip the charger's ink by accident. */
/* Three control paths, one per row so each device faces its own label.
   The wireless one is drawn as a wave instead of a wire. */
.connectivity-access {
  display: grid;
  grid-template-columns: minmax(0, 1fr) auto;
  align-items: center;
  gap: clamp(24px, 4vw, 64px);
  grid-column: 1 / -1;
}

.connectivity-access {
  grid-column: 1 / -1;
}

.access-rows {
  display: grid;
  margin: 0;
  padding: 0;
  border-top: 1px solid var(--tn-line);
  list-style: none;
}

.access-rows li {
  display: grid;
  grid-template-columns: 58px minmax(0, 1.5fr) minmax(78px, 1fr);
  align-items: center;
  gap: clamp(12px, 2vw, 26px);
  padding: 20px 0;
  border-bottom: 1px solid var(--tn-line);
}

.access-glyph svg {
  display: block;
  width: 100%;
  height: auto;
}

.access-ink rect,
.access-ink path,
.access-ink circle {
  fill: none;
  stroke: #8d8d85;
  stroke-width: 1.5;
  stroke-linejoin: round;
}

.access-pivot {
  fill: var(--tn-amber);
}

.access-text {
  display: grid;
  gap: 7px;
  min-width: 0;
}

.access-text strong {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.72rem;
  font-weight: 400;
  letter-spacing: 0.1em;
}

.access-text span {
  color: var(--tn-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.6rem;
  letter-spacing: 0.08em;
}

.access-links {
  display: grid;
  gap: 8px;
}

.access-link {
  display: block;
  width: 100%;
  height: 24px;
}

.access-link-wire {
  fill: none;
  stroke: var(--tn-line-light);
  stroke-width: 1;
  vector-effect: non-scaling-stroke;
}

.access-link-spark {
  fill: none;
  stroke: var(--tn-amber-light);
  stroke-width: 4;
  stroke-dasharray: 5 95;
  stroke-dashoffset: 100;
  opacity: 0;
  vector-effect: non-scaling-stroke;
}

.access-head {
  display: grid;
  gap: 12px;
  justify-items: center;
  margin: 0;
}

.access-head svg {
  display: block;
  width: clamp(96px, 12vw, 140px);
  height: auto;
}

.access-head figcaption {
  color: var(--tn-amber-light);
  font-family: "Silkscreen", monospace;
  font-size: 0.62rem;
  letter-spacing: 0.06em;
}

.connectivity-access.is-motion-active .access-link-spark,
.connectivity-access.is-motion-active .access-link-wire {
  animation-duration: 3.9s;
  animation-iteration-count: infinite;
}

.connectivity-access.is-motion-active .access-link-spark {
  animation-name: access-run;
  animation-timing-function: steps(18, end);
}

.connectivity-access.is-motion-active .access-link-wire {
  animation-name: access-live;
  animation-timing-function: steps(2, end);
}

.connectivity-access.is-motion-active li:nth-child(2) .access-link-spark,
.connectivity-access.is-motion-active li:nth-child(2) .access-link-wire {
  animation-delay: 1.3s;
}

.connectivity-access.is-motion-active li:nth-child(3) .access-link-spark,
.connectivity-access.is-motion-active li:nth-child(3) .access-link-wire {
  animation-delay: 2.6s;
}

@keyframes access-run {
  0% {
    stroke-dashoffset: 100;
    opacity: 0;
  }
  3% {
    opacity: 1;
  }
  28% {
    stroke-dashoffset: 0;
    opacity: 1;
  }
  32%,
  100% {
    stroke-dashoffset: 0;
    opacity: 0;
  }
}

@keyframes access-live {
  0% {
    stroke: var(--tn-line-light);
  }
  2%,
  30% {
    stroke: var(--tn-amber);
  }
  34%,
  100% {
    stroke: var(--tn-line-light);
  }
}

.charger {
  display: grid;
  gap: 18px;
  justify-items: center;
  margin: 0;
}

.charger svg {
  display: block;
  width: 100%;
  height: auto;
}

.charger figcaption {
  color: var(--tn-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.58rem;
  letter-spacing: 0.1em;
  text-align: center;
  text-wrap: balance;
}

.charger-line path,
.charger-line circle {
  fill: none;
  stroke: #8d8d85;
  stroke-width: 1.4;
  stroke-linejoin: round;
}

.charger-label text {
  fill: #8b8b82;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11px;
  letter-spacing: 0.1em;
}

.fusion-ink path,
.fusion-ink circle {
  fill: none;
  stroke: var(--tn-line-light);
  stroke-width: 1.6;
  stroke-linejoin: round;
}

/* Le profil du chargeur n'avait pas son repere de pivot, contrairement aux deux
   autres : meme traitement, l'axe de tilt se lit sur les trois. */
.charger-line .charger-pivot {
  fill: var(--tn-amber);
  stroke: none;
}

.fusion-pivot-dot {
  fill: var(--tn-amber);
}

/* The mirror is the working part, so it is the one line drawn in amber. Two
   classes: the per-diagram `.access-ink path` rules are (0-1-1) and would win. */
/* La plaque et son spigot sont peints APRES le bras et remplis de la couleur du
   fond : ils l'occultent la ou ils passent devant. C'est ce qui manquait — dans
   le modele l'axe de tilt est perpendiculaire au plan du profil, donc le bras
   arrive par derriere, mais une vue de profil ne peut pas le dire autrement
   qu'en cachant ce qui est masque. */
.profile-tilt path {
  fill: var(--tn-bg);
}

.profile-tilt .profile-plate {
  fill: var(--tn-bg);
  stroke: var(--tn-amber);
}

/* La plaque est un rectangle centre sur le sommet du bras, donc le centre de
   sa boite EST le pivot : elle tourne sans jamais se decrocher.
   Pas de scaleX ici. Une echelle non uniforme composee avec la rotation
   produirait un cisaillement, pas une rotation — le pan de profil se
   representerait de toute facon par rien de visible. */
/* Le spigot fait corps avec la plaque et tourne avec elle ; l'axe est a son
   BOUT, la ou il rejoint la machine. La boite du groupe va donc de y=18,5 (haut
   de la plaque) a y=40 (l'axe), et l'origine est en BAS de cette boite.
   Le spigot descend jusqu'au boitier moteur : c'est le seul bras, il n'y a plus
   de tube fixe entre les deux. Longueur 40, la plus grande qui conserve les
   180° — a 46 la plaque entre dans le fut et se bloque a 90°. */
.profile-tilt {
  transform-box: fill-box;
  transform-origin: 50% 100%;
}

/* Periodes premieres entre elles : le couple pan/tilt ne retombe jamais au
   meme endroit, le mouvement ne se lit pas comme une boucle. */
.access-head.is-motion-active .profile-tilt,
.connectivity-access.is-motion-active .profile-tilt {
  animation: profile-tilt 7.3s ease-in-out infinite;
}

.access-head.is-motion-active .profile-pan,

.charger.is-motion-active .profile-tilt {
  animation: profile-tilt 8.9s ease-in-out infinite;
}


.fusion.is-motion-active .profile-tilt {
  animation: profile-seek 2.6s ease-in-out infinite;
  animation-delay: 1.75s;
}


@keyframes profile-tilt {
  0% {
    transform: rotate(-90deg);
  }
  12% {
    transform: rotate(-34deg);
  }
  24% {
    transform: rotate(-62deg);
  }
  37% {
    transform: rotate(12deg);
  }
  49% {
    transform: rotate(-21deg);
  }
  61% {
    transform: rotate(58deg);
  }
  73% {
    transform: rotate(90deg);
  }
  86% {
    transform: rotate(27deg);
  }
  100% {
    transform: rotate(-90deg);
  }
}


/* Reponse breve a chaque paquet, dans le schema de fusion. */
@keyframes profile-seek {
  0%,
  46% {
    transform: rotate(-90deg);
  }
  62% {
    transform: rotate(41deg);
  }
  78% {
    transform: rotate(90deg);
  }
  90% {
    transform: rotate(4deg);
  }
  100% {
    transform: rotate(-90deg);
  }
}

.charger-batt path {
  fill: none;
  stroke: var(--tn-line-light);
  stroke-width: 1.4;
  stroke-linejoin: round;
}

.charger-notch-in {
  stroke: var(--tn-amber) !important;
  stroke-width: 2 !important;
}

.charger-leds rect {
  fill: var(--tn-amber);
}

/* Hot swap: the left pack pulls off and comes back while the right one keeps
   the output alive — the whole point of a two-slot ballast. */
.charger.is-motion-active .charger-batt[data-side="left"] {
  animation: batt-swap 7s ease-in-out infinite;
}

.charger.is-motion-active .charger-leds rect[data-side="left"] {
  animation: batt-led 7s steps(1, end) infinite;
}

@keyframes batt-swap {
  0%,
  46% {
    transform: translateX(0);
  }
  58%,
  72% {
    transform: translateX(-86px);
  }
  86%,
  100% {
    transform: translateX(0);
  }
}

@keyframes batt-led {
  0%,
  50% {
    fill: var(--tn-amber);
  }
  52%,
  82% {
    fill: #3a3a35;
  }
  88%,
  100% {
    fill: var(--tn-amber);
  }
}

.energy {
}







/* Kept as standalone selectors: grouping them with another figure's rules
   is what let a cleanup pass strip the charger's ink by accident. */
/* Three control paths, one per row so each device faces its own label.
   The wireless one is drawn as a wave instead of a wire. */

@keyframes access-live {
  0% {
    stroke: var(--tn-line-light);
  }
  2%,
  30% {
    stroke: var(--tn-amber);
  }
  34%,
  100% {
    stroke: var(--tn-line-light);
  }
}

.charger-notch path {
  fill: none;
  stroke: var(--tn-amber);
  stroke-width: 2;
  stroke-linejoin: miter;
}

/* Le courant sort du XLR et rejoint la base de Tournesol. Deux classes, car
   `.charger-line path` est (0-1-1) et l'emporterait sur une classe seule : le
   fil resterait gris, donc invisible sur le fond noir.
   pathLength="100" rend le pointille independant de la longueur reelle du
   trace ; 4 impulsions de periode 25 bouclent sans saut. */
.charger-line .charger-flow {
  stroke: var(--tn-amber);
  stroke-width: 2.6;
  stroke-linecap: round;
  stroke-dasharray: 5 20;
  stroke-dashoffset: 100;
}

.charger.is-motion-active .charger-flow {
  animation: charger-flow 3.2s linear infinite;
}

@keyframes charger-flow {
  to {
    stroke-dashoffset: 0;
  }
}

.charger-mark {
  fill: var(--tn-amber) !important;
  font-family: "Silkscreen", monospace !important;
  font-size: 15px !important;
}


.connectivity,
.team {
  display: grid;
  grid-template-columns: minmax(300px, 0.76fr) minmax(520px, 1.24fr);
  align-items: start;
  gap: clamp(56px, 9vw, 150px);
  min-height: auto;
}

.feature-heading {
  max-width: var(--tn-copy);
}

.feature-heading h2 {
  margin-bottom: 28px;
}

.feature-heading > p:last-child {
  margin-bottom: 0;
}

.connectivity {
  background: #030303;
}

.connectivity-grid {
  margin: 0;
  border-top: 1px solid var(--tn-line-light);
}

.connectivity-grid div {
  position: relative;
  padding: 26px 0 28px 26px;
  border-bottom: 1px solid var(--tn-line);
}

.connectivity-grid div::before {
  position: absolute;
  top: 31px;
  left: 0;
  width: 7px;
  height: 7px;
  background: var(--tn-amber);
  content: "";
}

.connectivity-grid dt,
.connectivity-grid dd {
  margin: 0;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  letter-spacing: 0.08em;
}

.connectivity-grid dt {
  color: var(--tn-text);
  font-size: 0.72rem;
}

.connectivity-grid dd {
  margin-top: 8px;
  color: var(--tn-muted);
  font-size: 0.66rem;
}




.team {
  background: #030303;
}

.team-grid {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: 1px;
  margin: 0;
  padding: 0;
  border: 1px solid var(--tn-line);
  background: var(--tn-line);
  list-style: none;
}

.team-grid li {
  display: flex;
  flex-direction: column;
  justify-content: space-between;
  min-height: 220px;
  padding: 28px;
  background: var(--tn-bg);
}

.team-grid span {
  color: var(--tn-amber);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.66rem;
  letter-spacing: 0.1em;
}

.team-grid strong {
  font-family: "Silkscreen", monospace;
  font-size: clamp(0.9rem, 1.6vw, 1.3rem);
  font-weight: 400;
  line-height: 1.3;
}

.team-grid em {
  margin-top: 10px;
  color: var(--tn-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.62rem;
  font-style: normal;
  letter-spacing: 0.12em;
}

.crls {
  background: #050505;
}

.crls-media {
  position: relative;
  display: block;
  align-self: center;
  overflow: hidden;
  border: 1px solid var(--tn-line);
}

.crls-photo {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 1.48;
  object-fit: cover;
}

.crls-brand {
  position: absolute;
  right: 0;
  bottom: 0;
  left: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  min-height: 78px;
  padding: 18px 22px;
  border-top: 1px solid var(--tn-line);
  background: rgba(0, 0, 0, 0.9);
}

.crls-brand img {
  width: min(45%, 220px);
  height: auto;
  filter: invert(1);
}

.crls-brand small {
  color: var(--tn-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.6rem;
  letter-spacing: 0.08em;
  text-align: right;
}

.origin {
  background: #030303;
}

.origin .section-copy p + p {
  margin-top: 22px;
}

.origin .section-copy em {
  color: var(--tn-text);
}




.specifications {
  display: grid;
  grid-template-columns: minmax(300px, 0.76fr) minmax(520px, 1.24fr);
  gap: clamp(56px, 9vw, 150px);
  align-items: start;
  min-height: auto;
}

/* `.section-kicker` carries a negative bottom margin that offsets a grid gap,
   so this heading has to be a grid too or the kicker lands on the title. */
.specs-heading {
  display: grid;
  gap: 18px;
  align-content: start;
}

.specs-heading h2 {
  margin-bottom: 0;
}

.specs-list {
  margin: 0;
  border-top: 1px solid var(--tn-line-light);
}

.specs-list div {
  display: grid;
  grid-template-columns: minmax(140px, 0.7fr) minmax(220px, 1.3fr);
  gap: 24px;
  align-items: baseline;
  padding: 22px 0;
  border-bottom: 1px solid var(--tn-line);
}

.specs-list dt,
.specs-list dd {
  margin: 0;
}

.specs-list dt {
  color: var(--tn-muted);
  font-size: 0.9rem;
}

.specs-list dd {
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.74rem;
  letter-spacing: 0.07em;
}

/* Deux colonnes, comme les autres sections : le discours a gauche, le dessin
   V1 a droite. Il coupait le texte en deux quand tout etait empile. */
.programme {
  display: grid;
  grid-template-columns: minmax(300px, 0.95fr) minmax(320px, 1.05fr);
  align-items: center;
  gap: clamp(44px, 7vw, 120px);
  align-content: center;
}

.programme-copy {
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  min-width: 0;
}

.programme h2 {
  max-width: 17ch;
}

.programme-copy > p {
  margin-bottom: 18px;
}

.programme-pixels {
  display: flex;
  gap: 8px;
  margin-bottom: 48px;
}

.programme-pixels i {
  width: 8px;
  height: 8px;
  background: var(--tn-amber);
}

.programme-pixels i:nth-child(2),
.programme-pixels i:nth-child(6) {
  translate: 0 -12px;
}

.programme-pixels i:nth-child(3),
.programme-pixels i:nth-child(5) {
  translate: 0 -22px;
}

.programme-pixels i:nth-child(4) {
  translate: 0 -27px;
  background: var(--tn-amber-light);
}




/* Le soleil traverse l'arc : chaque point s'allume a son tour, de gauche a
   droite, puis l'arc se repose. L'animation porte sur `transform` et jamais
   sur `translate` — c'est ce dernier qui tient la forme de l'arc, et les deux
   proprietes se composent au lieu de s'ecraser. Elle ne touche pas non plus au
   fond, pour laisser au point du sommet sa teinte plus claire. */
.programme.is-in-view .programme-pixels i {
  animation: programme-sun 3.8s ease-in-out infinite;
}

.programme-pixels i:nth-child(1) {
  animation-delay: 0s;
}

.programme-pixels i:nth-child(2) {
  animation-delay: 0.14s;
}

.programme-pixels i:nth-child(3) {
  animation-delay: 0.28s;
}

.programme-pixels i:nth-child(4) {
  animation-delay: 0.42s;
}

.programme-pixels i:nth-child(5) {
  animation-delay: 0.56s;
}

.programme-pixels i:nth-child(6) {
  animation-delay: 0.7s;
}

.programme-pixels i:nth-child(7) {
  animation-delay: 0.84s;
}

@keyframes programme-sun {
  0%,
  55%,
  100% {
    opacity: 0.5;
    transform: scale(1);
  }
  18% {
    opacity: 1;
    transform: scale(1.55);
  }
}

@keyframes mechanism-index {
  0% {
    transform: translateY(0);
  }
  68%,
  100% {
    transform: translateY(322px);
  }
}

@keyframes signal-pulse {
  50% {
    opacity: 0.3;
    transform: scale(0.65);
  }
}

@keyframes power-cell {
  45% {
    background: var(--tn-amber-light);
    transform: translateY(-5px);
  }
}


footer {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 24px;
  min-height: 130px;
  padding: 32px var(--tn-gutter);
}

footer p {
  margin: 0;
  color: var(--tn-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.68rem;
  letter-spacing: 0.08em;
  text-transform: uppercase;
}

@media (max-width: 1050px) {
  .programme {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(40px, 6vw, 64px);
  }

  .section-shell,
  .tracking,
  .tracking-person,
  .connectivity,
  .team,
  .specifications {
    grid-template-columns: 1fr 1fr;
    gap: 52px;
  }

  .site-header {
    grid-template-columns: 1fr auto;
  }

  .composition-layout {
    grid-template-columns: 1fr;
  }

  .composition-viewer {
    order: 1;
  }

  .composition-list {
    order: 2;
  }

  /* Not enough room beside the brand: the bar drops to its own scrollable
     row rather than disappearing, so the sections stay reachable. */
  :root {
    --tn-header: 118px;
  }

  .site-header {
    align-items: start;
    padding-top: 10px;
  }

  .site-header nav {
    grid-row: 2;
    grid-column: 1 / -1;
    min-width: 0;
    gap: 20px;
    margin: 0 calc(var(--tn-gutter) * -1);
    padding: 0 var(--tn-gutter);
    overflow-x: auto;
    scrollbar-width: none;
  }

  .site-header nav::-webkit-scrollbar {
    display: none;
  }

  .site-header.is-scrolled {
    min-height: var(--tn-header);
  }

  .hero {
    grid-template-columns: minmax(400px, 0.95fr) minmax(390px, 1.05fr);
  }

  .optics-lab-heading {
    grid-template-columns: minmax(280px, 0.85fr) minmax(340px, 1.15fr);
    gap: 44px;
  }
}

@media (max-width: 760px) {
  .section-shell,
  .tracking,
  .tracking-person,
  .text-section,
  .connectivity,
  .team,
  .specifications {
    grid-template-columns: 1fr;
    min-height: auto;
    padding-top: 104px;
    padding-bottom: 104px;
  }

  .composition-durability {
    grid-template-columns: 1fr;
  }

  .connectivity-access,
  .luminator {
    grid-template-columns: 1fr;
  }

  .access-rows li {
    grid-template-columns: 48px minmax(0, 1fr);
    row-gap: 10px;
  }

  .access-links {
    grid-column: 1 / -1;
  }

  .access-head svg {
    width: 84px;
  }

  :root {
    /* Compact brand row plus the scrollable section bar underneath. */
    --tn-header: 106px;
  }

  .composition-stage {
    aspect-ratio: 4 / 5;
    max-height: 66svh;
  }

  .composition-controls {
    grid-template-columns: 1fr;
    align-items: stretch;
  }

  .composition-buttons {
    justify-content: space-between;
  }

  .composition-row-body {
    align-items: flex-start;
    flex-direction: column;
    gap: 3px;
  }

  .composition-row-body > span {
    text-align: left;
  }

  .site-header {
    min-height: var(--tn-header);
  }

  .brand {
    font-size: 0.78rem;
  }

  .header-action {
    font-size: 0.62rem;
  }

  .hero {
    grid-template-columns: 1fr;
    align-content: start;
    min-height: auto;
    padding-top: calc(var(--tn-header) + 62px);
    padding-bottom: 86px;
  }

  .hero-copy {
    max-width: none;
  }

  h1 {
    max-width: none;
    font-size: clamp(1.58rem, 6.8vw, 2.3rem);
    line-height: 1.13;
    white-space: normal;
  }

  h2 {
    font-size: clamp(1.68rem, 8.4vw, 2.65rem);
  }

  .concept-status {
    margin-bottom: 24px;
  }

  .hero-product-mark {
    gap: 14px;
    margin-bottom: 20px;
    font-size: 1rem;
  }

  .hero-actions {
    align-items: stretch;
  }

  .hero-actions .button {
    flex: 1 1 190px;
  }

  .hero-visual {
    min-height: 640px;
    margin-top: 38px;
  }

  .optics-lab {
    min-height: auto;
    padding-top: 96px;
    padding-bottom: 96px;
  }

  .optics-lab-heading {
    grid-template-columns: 1fr;
    gap: 24px;
    margin-bottom: 42px;
  }

  .optics-lab-heading h2,
  .optics-lab-heading > p:last-child {
    grid-column: 1;
  }


  .optics-toolbar {
    align-items: stretch;
    flex-direction: column;
    gap: 10px;
    padding: 16px;
  }

  .optics-toolbar button {
    justify-content: center;
    width: 100%;
  }

  .optics-stage {
    min-height: 280px;
  }

  .optics-readout {
    grid-template-columns: repeat(2, 1fr);
  }

  .optics-readout div {
    border-bottom: 1px solid var(--tn-line);
  }

  .optics-readout div:nth-child(2) {
    border-right: 0;
  }

  .optics-readout div:nth-last-child(-n + 2) {
    border-bottom: 0;
  }

  /* Sur telephone, le hero passe en flux : la scene reservait une hauteur fixe
     sous elle pour les commandes, ce qui ne pouvait pas tenir des que leur
     nombre a change — cinq curseurs empiles debordaient sur l'animation.
     En colonne, la hauteur s'ajuste d'elle-meme. */
  .hero-visual {
    display: flex;
    flex-direction: column;
    gap: 16px;
    min-height: 0;
  }

  .model-stage {
    position: relative;
    inset: auto;
    order: 2;
    width: 112%;
    margin-left: -6%;
    aspect-ratio: 1 / 1;
  }

  .model-version {
    position: relative;
    top: auto;
    left: auto;
    order: 1;
  }

  .model-controls {
    position: relative;
    right: auto;
    bottom: auto;
    left: auto;
    order: 3;
    grid-template-columns: 1fr;
    gap: 12px;
    padding: 18px 0 0;
  }

  .motion-toggle {
    position: relative;
    right: auto;
    bottom: auto;
    order: 4;
    align-self: flex-end;
  }

  .scroll-cue {
    display: none;
  }



  .team-grid li {
    min-height: 160px;
  }

  .crls-media {
    grid-row: 2;
  }

  .crls-brand {
    position: static;
    align-items: flex-start;
    flex-direction: column;
  }

  .crls-brand img {
    width: min(70%, 220px);
  }

  .crls-brand small {
    text-align: left;
  }

  .specs-list div {
    grid-template-columns: 1fr;
    gap: 7px;
  }

  .programme {
  }

  footer {
    align-items: flex-start;
    flex-direction: column;
    justify-content: center;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  *,
  *::before,
  *::after {
    scroll-behavior: auto !important;
    transition-duration: 0.01ms !important;
    animation-duration: 0.01ms !important;
    animation-iteration-count: 1 !important;
  }

  /* La regle generique ci-dessus ecraserait la chute en 0,01 ms — soit un
     sursaut, exactement ce que ce reglage cherche a eviter. Ici la marque ne
     tombe pas du tout : elle est deja posee, croix et mot compris. */
  .brand-pixels i,
  .brand-word span {
    animation: none !important;
  }
}

/* ==========================================================================
   Blocs restaures.

   Les classes ci-dessous existaient dans le markup sans aucune regle : elles
   ont ete emportees par des nettoyages regex successifs sur cette feuille.
   Le markup s'affichait donc brut — images a leur taille intrinseque (1200px
   de large pour la capture iPad), titres au style par defaut du navigateur.

   Aucun degrade ici : le contrat de smoke test les interdit dans toute la
   feuille, en aplats seulement.
   ========================================================================== */

/* --- Titres de sous-section ------------------------------------------- */

/* Aucune regle ne ciblait h3 : les sous-titres tombaient sur le gras par
   defaut du navigateur, hors de la rampe typographique du site. */
h3 {
  margin: 0 0 18px;
  font-family: "Silkscreen", monospace;
  font-size: clamp(1.05rem, 1.5vw, 1.35rem);
  font-weight: 400;
  line-height: 1.25;
  letter-spacing: 0;
}

/* --- Interface dediee Luminator --------------------------------------- */

/* `grid-column: 1 / -1` : la section parente a deux colonnes et trois enfants,
   ce qui laissait une cellule vide — le grand blanc avant cette sous-section. */
.luminator {
  grid-column: 1 / -1;
  display: grid;
  grid-template-columns: minmax(0, 0.76fr) minmax(0, 1.24fr);
  align-items: center;
  gap: clamp(22px, 2.6vw, 44px);
  margin-top: clamp(26px, 2.8vw, 40px);
  padding-top: clamp(22px, 2.4vw, 34px);
  border-top: 1px solid var(--tn-line);
}

/* Sans `min-width: 0` un element de grille refuse de passer sous sa largeur de
   contenu : la colonne des captures debordait par-dessus le texte. La regle
   vaut aussi pour les enfants de `.luminator-copy`, qui est lui-meme une
   grille — sinon le paragraphe et les pastilles gardent leur largeur de
   contenu et passent sous l'image. */
.luminator-copy,
.luminator-shots,
.luminator-copy > * {
  min-width: 0;
  max-width: 100%;
}

/* `.section-kicker` est concu comme enfant de grille (grid-column: 1 / -1) :
   sans grille parente il se comportait de travers et collait au titre. */
.luminator-copy {
  display: grid;
  gap: 12px;
  align-content: start;
}

.luminator-copy p:not(.section-kicker) {
  max-width: min(46ch, 100%);
  margin: 0;
  color: var(--tn-muted);
  font-size: clamp(0.95rem, 1.15vw, 1.05rem);
  line-height: 1.6;
}

.luminator-copy h3 {
  margin: 0;
}

.luminator-specs {
  display: flex;
  flex-wrap: wrap;
  gap: 8px;
  margin: 6px 0 0;
  padding: 0;
  list-style: none;
}

.luminator-specs li {
  padding: 7px 11px;
  border: 1px solid var(--tn-line-light);
  color: #d7d7d3;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.66rem;
  letter-spacing: 0.11em;
}

/* Les deux captures n'ont pas du tout le meme format — iPad 4:3 paysage
   (1200x900), iPhone 0.46 portrait (560x1217). Les poser cote a cote a
   hauteur egale ecraserait l'iPhone ; on cale donc la MEME hauteur de boite et
   on laisse chaque image tenir dedans a son propre ratio. */
/* Les deux captures n'ont pas le meme format — iPad 4:3 paysage, iPhone 0,46
   portrait. Elles sont donc calees sur une meme HAUTEUR et leurs largeurs
   suivent leur propre ratio, au lieu d'etre imposees en pourcentage : c'est ce
   qui faisait deborder puis rogner la capture telephone. `flex: 0 1 auto` avec
   `min-width: 0` les laisse retrecir ensemble quand la colonne se resserre. */
.luminator-shots {
  display: flex;
  align-items: flex-end;
  justify-content: center;
  gap: clamp(12px, 1.8vw, 24px);
  min-width: 0;
  max-width: 100%;
}

.luminator-shots img {
  display: block;
  flex: 0 1 auto;
  min-width: 0;
  width: auto;
  height: auto;
  max-width: 100%;
  max-height: clamp(220px, 26vw, 360px);
  border: 1px solid var(--tn-line-light);
  background: #050505;
  object-fit: contain;
}



/* --- Carte evenement (Objectif / Micro Salon) -------------------------- */

.event-card {
  margin: 0 0 30px;
  padding: 20px 22px;
  border: 1px solid var(--tn-line-light);
  border-left: 2px solid var(--tn-amber);
}

.event-card-name {
  margin: 0 0 16px;
  color: var(--tn-amber-light);
  font-family: "Silkscreen", monospace;
  font-size: 0.82rem;
  letter-spacing: 0.02em;
}

.event-card-facts {
  display: grid;
  gap: 10px;
  margin: 0;
}

.event-card-facts > div {
  display: grid;
  grid-template-columns: 90px minmax(0, 1fr);
  gap: 14px;
  align-items: baseline;
}

.event-card-facts dt {
  color: #7d7d78;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.62rem;
  letter-spacing: 0.12em;
}

.event-card-facts dd {
  margin: 0;
  color: #d7d7d3;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.68rem;
  letter-spacing: 0.08em;
}

/* La presence au salon n'est pas acquise : elle se lit comme une reserve, pas
   comme une annonce. */
.event-card-facts .is-pending {
  color: var(--tn-amber);
}

/* --- Dessin Tournesol 1 x 1 V1 ---------------------------------------- */

.tournesol-v1 {
  margin: 0;
  align-self: center;
  justify-self: center;
  width: min(100%, 440px);
}

.tournesol-v1 svg {
  display: block;
  width: 100%;
  height: auto;
}

.tournesol-v1 figcaption {
  margin-top: 16px;
  color: var(--tn-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.66rem;
  letter-spacing: 0.08em;
  line-height: 1.6;
}

.v1-line path,
.v1-line rect {
  fill: none;
  stroke: #8d8d85;
  stroke-width: 1.6;
  stroke-linejoin: round;
}

/* Les deux boitiers motorises sont ce que vend le dessin : eux seuls en ambre. */
.v1-motor rect,
.v1-motor path {
  fill: none;
  stroke: var(--tn-amber);
  stroke-width: 1.8;
  stroke-linejoin: round;
}

.v1-label text {
  fill: #8b8b82;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 11px;
  letter-spacing: 0.1em;
}

.v1-label .v1-axis {
  fill: var(--tn-amber);
}

.v1-label .v1-name {
  fill: var(--tn-amber-light);
  font-family: "Silkscreen", monospace;
  font-size: 13px;
  letter-spacing: 0.02em;
}

/* --- Inscription -------------------------------------------------------- */

.newsletter {
  width: min(100%, 520px);
  margin: 8px 0 0;
  padding: 22px;
  border: 1px solid var(--tn-line-light);
}

.newsletter-lead {
  margin: 0 0 18px;
  color: var(--tn-muted);
  font-size: 0.95rem;
  line-height: 1.65;
}

.newsletter-row {
  display: flex;
  flex-wrap: wrap;
  gap: 12px;
  align-items: flex-end;
}

.newsletter-field {
  display: grid;
  flex: 1 1 220px;
  gap: 8px;
  min-width: 0;
}

.newsletter-field > span {
  color: #7d7d78;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.62rem;
  letter-spacing: 0.12em;
}

.newsletter-field input {
  min-height: 44px;
  padding: 0 13px;
  border: 1px solid var(--tn-line-light);
  background: #050505;
  color: var(--tn-text);
  font: inherit;
  font-size: 0.95rem;
}

.newsletter-field input:focus-visible {
  border-color: var(--tn-amber);
  outline: none;
}

.newsletter-note {
  margin: 14px 0 0;
  color: #7d7d78;
  font-size: 0.78rem;
  line-height: 1.6;
}

.newsletter-status {
  margin: 12px 0 0;
  min-height: 1.2em;
  color: var(--tn-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.7rem;
  letter-spacing: 0.06em;
}

.newsletter-status[data-state="ok"] {
  color: var(--tn-amber-light);
}

.newsletter-status[data-state="error"] {
  color: #e0705a;
}

/* --- Divers ------------------------------------------------------------- */

.button-secondary {
  border-color: var(--tn-line-light);
  color: #d7d7d3;
}

.inline-link {
  border-bottom: 1px solid var(--tn-amber);
  color: var(--tn-amber-light);
}

/* La bascule en colonne unique se fait plus tot que le reste du site : a deux
   colonnes sous 1200px, la colonne de texte devient trop etroite pour la
   longueur du paragraphe et les trois pastilles. */
@media (max-width: 1200px) {
  .luminator {
    grid-template-columns: minmax(0, 1fr);
    gap: clamp(24px, 3vw, 38px);
  }

}

@media (max-width: 760px) {
  .luminator-shots {
    gap: 12px;
  }


  .event-card-facts > div {
    grid-template-columns: minmax(0, 1fr);
    gap: 3px;
  }

  .newsletter {
    padding: 18px;
  }
}

/* --- Carte de prix ------------------------------------------------------ */

/* La section reutilisait la liste de specs generique : une seule ligne perdue
   dans le vide, qui ne vendait rien. Le prix devient l'objet principal, avec
   ce qu'il comprend juste dessous. */
.price-card {
  align-self: center;
  width: min(100%, 460px);
  min-width: 0;
  padding: clamp(24px, 3vw, 34px);
  border: 1px solid var(--tn-line-light);
  border-top: 2px solid var(--tn-amber);
}

.price-name {
  margin: 0 0 18px;
  color: #8b8b82;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.66rem;
  letter-spacing: 0.12em;
}

.price-amount {
  display: flex;
  flex-wrap: wrap;
  gap: 10px;
  align-items: baseline;
  margin: 0 0 6px;
}

.price-value {
  color: var(--tn-amber-light);
  font-family: "Silkscreen", monospace;
  font-size: clamp(2rem, 3.6vw, 2.9rem);
  line-height: 1;
  letter-spacing: 0;
}

.price-unit {
  color: var(--tn-amber);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.68rem;
  letter-spacing: 0.12em;
}

.price-secondary {
  margin: 0 0 26px;
  color: var(--tn-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.72rem;
  letter-spacing: 0.06em;
}

.price-includes {
  margin: 0;
  padding: 22px 0 0;
  border-top: 1px solid var(--tn-line);
  list-style: none;
}

.price-includes li {
  position: relative;
  padding: 0 0 11px 20px;
  color: #d7d7d3;
  font-size: 0.92rem;
  line-height: 1.5;
}

/* Un carre plein plutot qu'une puce : meme vocabulaire que le reste du site. */
.price-includes li::before {
  position: absolute;
  top: 0.58em;
  left: 0;
  width: 5px;
  height: 5px;
  background: var(--tn-amber);
  content: "";
}

.price-note {
  margin: 12px 0 0;
  padding-top: 16px;
  border-top: 1px solid var(--tn-line);
  color: #7d7d78;
  font-size: 0.8rem;
  line-height: 1.55;
}

/* Pan et tilt ne sont plus des commandes : la machine les resout a partir de
   l'heure et de la cible. Ils se lisent donc comme une mesure. */
.axis-readout {
  display: flex;
  flex-wrap: wrap;
  gap: 6px 18px;
  align-items: baseline;
  margin: 2px 0 0;
  padding-top: 14px;
  border-top: 1px solid var(--tn-line);
  color: #7d7d78;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.62rem;
  letter-spacing: 0.12em;
}

.axis-readout b {
  color: var(--tn-amber);
  font-weight: 400;
  font-variant-numeric: tabular-nums;
}

/* --- Contacter les createurs ------------------------------------------- */

.contact {
  width: min(100%, 560px);
  margin: 26px 0 0;
  padding: clamp(20px, 2.6vw, 28px);
  border: 1px solid var(--tn-line-light);
  border-top: 2px solid var(--tn-amber);
}

.contact-lead {
  margin: 0 0 8px;
  color: var(--tn-amber-light);
  font-family: "Silkscreen", monospace;
  font-size: 0.92rem;
  letter-spacing: 0.02em;
}

.contact-note {
  margin: 0 0 20px;
  color: var(--tn-muted);
  font-size: 0.92rem;
  line-height: 1.6;
}

.contact-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
  gap: 14px;
  margin-bottom: 14px;
}

.contact-field {
  display: grid;
  gap: 8px;
  min-width: 0;
}

.contact-field-wide {
  margin-bottom: 18px;
}

.contact-field > span {
  color: #7d7d78;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.62rem;
  letter-spacing: 0.12em;
}

.contact-field input,
.contact-field textarea {
  min-height: 44px;
  padding: 11px 13px;
  border: 1px solid var(--tn-line-light);
  background: #050505;
  color: var(--tn-text);
  font: inherit;
  font-size: 0.95rem;
  resize: vertical;
}

.contact-field input:focus-visible,
.contact-field textarea:focus-visible {
  border-color: var(--tn-amber);
  outline: none;
}

/* Champ piege : hors flux et hors lecture d'ecran, mais rempli par les robots. */
.contact-trap {
  position: absolute;
  left: -9999px;
  width: 1px;
  height: 1px;
  overflow: hidden;
}

.contact-status {
  margin: 14px 0 0;
  min-height: 1.2em;
  color: var(--tn-muted);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.7rem;
  letter-spacing: 0.06em;
}

.contact-status[data-state="ok"] {
  color: var(--tn-amber-light);
}

.contact-status[data-state="error"] {
  color: #e0705a;
}

/* Sortie du mode manuel : la machine recalcule la visee vers la cible. */
.axis-aim {
  justify-self: start;
  margin-top: 4px;
  padding: 9px 14px;
  font-size: 0.66rem;
}

/* L'en-tete est fixe : sans cette marge le formulaire arrive sous la barre. */
#contact {
  scroll-margin-top: calc(var(--tn-header) + 24px);
}

/* Le banc optique deplace dans sa propre section : plus petit, a droite. */
.reflection-bench {
  min-width: 0;
  align-self: center;
}

.reflection-bench .optics-simulator {
  width: 100%;
}

/* Les deux schemas de la section de suivi partagent la colonne de droite : la
   fusion des sources au-dessus, le banc optique en dessous et plus petit.
   Regroupes dans un conteneur plutot que places par `grid-column`, qui aurait
   cree une colonne implicite hors ecran quand la grille passe sur une colonne. */
.tracking-media {
  display: grid;
  gap: clamp(20px, 2.6vw, 40px);
  min-width: 0;
}

.tracking-media .reflection-bench {
  width: min(100%, 520px);
  justify-self: center;
}

/* Reperes de bord : quand le soleil ou la cible sort du champ, une pastille se
   colle au bord de la scene et pointe vers eux. Le conteneur est deja en
   `position: absolute`, il sert donc de reference. */
.edge-cue {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 4;
  display: none;
  align-items: center;
  gap: 6px;
  padding: 4px 8px;
  border: 1px solid var(--tn-amber);
  background: rgba(0, 0, 0, 0.72);
  color: var(--tn-amber);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.58rem;
  letter-spacing: 0.12em;
  white-space: nowrap;
  pointer-events: none;
  translate: -50% -50%;
}

.edge-cue.is-visible {
  display: inline-flex;
}

/* La fleche tourne vers la position reelle ; le triangle pointe vers la droite
   au repos, l'angle est donc mesure depuis l'axe horizontal. */
.edge-cue i {
  width: 0;
  height: 0;
  border-top: 4px solid transparent;
  border-bottom: 4px solid transparent;
  border-left: 6px solid currentColor;
  rotate: var(--cue-angle, 0deg);
}

.edge-cue-target {
  border-color: #d7d7d3;
  color: #d7d7d3;
}

@media (max-width: 760px) {
  .edge-cue {
    font-size: 0.52rem;
  }
}

/* --- Section Objectif : des blocs nommes, pas un empilement ------------- */

.programme-block {
  width: 100%;
  min-width: 0;
  max-width: 560px;
  margin-top: clamp(26px, 3vw, 40px);
  padding-top: clamp(24px, 2.8vw, 36px);
  border-top: 1px solid var(--tn-line);
}

/* Le premier bloc suit le titre : il n'a pas besoin d'un trait de plus. */
.programme-block:first-of-type {
  margin-top: clamp(22px, 2.4vw, 32px);
  padding-top: 0;
  border-top: 0;
}

.programme-block h3 {
  margin-bottom: 14px;
}

.programme-block > p {
  max-width: 62ch;
  margin: 0;
  color: var(--tn-muted);
  font-size: clamp(1rem, 1.4vw, 1.2rem);
  line-height: 1.7;
}

.programme-block .event-card {
  margin-bottom: 22px;
}

/* Les formulaires portent deja leur propre cadre : pas de cadre dans un cadre. */
.programme-block .newsletter,
.programme-block .contact {
  width: 100%;
  margin-top: 0;
}

/* Le titre de la sous-section partenaire porte plus que les autres h3 : il
   ouvre un bloc entier, pas un simple paragraphe. */
.luminator-copy h3 {
  font-size: clamp(1.35rem, 2vw, 1.8rem);
  line-height: 1.18;
}

/* Le lien du sur-titre reste dans la graisse et la casse du sur-titre. */
.section-kicker .inline-link {
  color: inherit;
  border-bottom-color: currentColor;
}

/* Reperes horaires sur la course du soleil. Le point est dessine en 3D ; cette
   etiquette le nomme, decalee vers le haut pour ne pas le couvrir. */
.sun-anchor {
  position: absolute;
  top: 0;
  left: 0;
  z-index: 3;
  display: none;
  color: #9a8a52;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.54rem;
  letter-spacing: 0.1em;
  white-space: nowrap;
  pointer-events: none;
  translate: -50% -190%;
}

.sun-anchor.is-visible {
  display: block;
}

/* --- Agrandissement des captures ---------------------------------------- */

/* Le declencheur est un bouton : il doit perdre l'habillage par defaut sans
   perdre le focus visible. */
.shot {
  display: block;
  padding: 0;
  border: 0;
  background: none;
  cursor: zoom-in;
  min-width: 0;
}

.shot:focus-visible {
  outline: 2px solid var(--tn-amber-light);
  outline-offset: 4px;
}

.lightbox {
  position: fixed;
  inset: 0;
  z-index: 60;
  display: none;
  align-items: center;
  justify-content: center;
  padding: clamp(16px, 4vw, 56px);
  background: rgba(0, 0, 0, 0.94);
  cursor: zoom-out;
}

.lightbox.is-open {
  display: flex;
}

.lightbox img {
  max-width: 100%;
  max-height: 100%;
  border: 1px solid var(--tn-line-light);
  cursor: default;
}

.lightbox-close {
  position: absolute;
  top: clamp(10px, 2vw, 24px);
  right: clamp(10px, 2vw, 24px);
  width: 44px;
  height: 44px;
  border: 1px solid var(--tn-line-light);
  background: transparent;
  color: var(--tn-text);
  font-size: 1.4rem;
  line-height: 1;
  cursor: pointer;
}

.lightbox-close:hover {
  border-color: var(--tn-amber);
  color: var(--tn-amber);
}

/* La page ne defile plus derriere l'apercu. */
body.has-lightbox {
  overflow: hidden;
}

/* L'en-tete est fixe : l'ancre doit se poser sous elle, pas dessous. */
#prevenu {
  scroll-margin-top: calc(var(--tn-header) + 24px);
}

/* --- Équipe : deux fiches, plus une liste de noms ----------------------- */

.team-grid li {
  display: grid;
  grid-template-rows: auto auto auto 1fr auto;
  gap: 0;
  min-height: 0;
  padding: clamp(22px, 2.6vw, 32px);
}

.team-index {
  margin: 0 0 18px;
  color: var(--tn-amber);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.66rem;
  letter-spacing: 0.1em;
}

.team-grid h3 {
  margin: 0 0 8px;
  font-size: clamp(1rem, 1.7vw, 1.35rem);
}

.team-role {
  margin: 0 0 18px;
  color: var(--tn-amber-light);
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.62rem;
  letter-spacing: 0.12em;
}

.team-text {
  margin: 0 0 22px;
  color: var(--tn-muted);
  font-size: 0.95rem;
  line-height: 1.65;
}

/* Le métier de plateau ferme la fiche : c'est d'où vient la personne, pas ce
   qu'elle fait sur Tournesol. */
.team-job {
  margin: 0;
  padding-top: 14px;
  border-top: 1px solid var(--tn-line);
  color: #7d7d78;
  font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  font-size: 0.6rem;
  letter-spacing: 0.12em;
}

@media (max-width: 760px) {
  .team-grid {
    grid-template-columns: minmax(0, 1fr);
  }
}

/* Engagement sur les données, sous chaque formulaire : sans lui, laisser une
   adresse est un acte de foi. */
.contact-privacy {
  margin: 14px 0 0;
  color: #7d7d78;
  font-size: 0.78rem;
  line-height: 1.6;
}

/* La barre ne peut pas tenir sept liens sous 400 px : elle défile, mais rien ne
   le disait et trois liens dont « Contact » restaient invisibles. Un carré ambre
   collé au bord le signale — permanent et sans état, plutôt qu'un fondu piloté
   en JavaScript dont je n'ai pas pu vérifier le comportement réel.
   Pas de dégradé : le contrat de test les interdit. */
.site-header nav {
  position: relative;
  scrollbar-width: none;
}

.site-header nav::-webkit-scrollbar {
  display: none;
}

@media (max-width: 760px) {
  /* Le libellé le plus long prenait 128 px, deux fois le suivant. */
  .nav-long {
    display: none;
  }

  .site-header nav {
    gap: 14px;
  }

  /* `sticky` et non `absolute` : un élément absolu dans un conteneur qui défile
     part avec le contenu — celui-ci se posait à 442 px, hors écran, tout en se
     déclarant visible. Collant, il reste au bord de la zone vue. */
  .nav-scroll-cue {
    position: sticky;
    right: 0;
    z-index: 2;
    flex: 0 0 auto;
    align-self: center;
    width: 6px;
    height: 6px;
    margin-left: auto;
    background: var(--tn-amber);
    pointer-events: none;
  }
}

@media (min-width: 761px) {
  .nav-scroll-cue {
    display: none;
  }
}
