/* ---------------------------------------------------------------------------
   manifesto — Paper artboard "Manifesto V7 — mono/display" (1440 x 8340)
   Source of truth for form is Paper; the tokens come from styles.css and are
   never redefined here. Page-scoped on purpose: everything hangs off
   .manifesto so nothing can leak back onto the landing.

   Une feuille blanche, deux colonnes centrees ensemble : le sommaire collant
   dans la gouttiere gauche, la colonne de lecture au milieu. Deux familles,
   deux roles : Inter affirme (ouverture, titres, declarations), JetBrains
   Mono argumente (le corps, 16/28, mesure courte). Aucun filet, aucune
   micro-capitale decorative, aucun numero de section.
   --------------------------------------------------------------------------- */
.manifesto {
  --col-x: var(--page-inset);
  --wide: 1128px;             /* la mesure large : ouverture et planches */

  /* Paper's three measures. Wide is exactly what the sheet leaves at 1440
     (1440 − 264 − 48), so display type breaks the same way it does in Paper. */
  /* Le mono est chasse fixe : a 16px un signe fait 9.6px, donc 640 donne des
     lignes de 66 signes, la mesure de lecture classique. Le reste s'aligne
     dessus au lieu de trois largeurs sans rapport. */
  --measure-wide: 100%;
  --measure-title: 100%;
  --measure-copy: 640px;

  /* ink — one colour, three strengths. What asserts is full navy, what argues
     is 66%, what is already past is 38%. Aucune couleur d'accent : le jaune
     signal n'a rien a faire ici. */
  --ink: var(--color-paper);
  --ink-argue: rgb(10 36 104 / 66%);
  /* 38% mesurait 2.27:1 sur la feuille — trois echecs WCAG AA, dont une
     vraie phrase du manifesto. Sous 65% l'encre navy sur craie ne passe plus
     le seuil de 4.5, donc l'effet "deja passe" ne peut PAS venir de
     l'opacite : il vient du poids et de la position. Ici on garde juste ce
     qu'il faut de retrait pour distinguer l'entree inactive du sommaire de
     l'entree courante, qui est a pleine encre. */
  --ink-past: rgb(10 36 104 / 65%);

  /* the rhythm, read off the artboard's y coordinates and expressed as a
     share of the 1440 sheet so it compresses with the page */
  --gap-caption: clamp(12px, 1.1vw, 16px);
  --gap-copy: clamp(16px, 1.4vw, 20px);
  --gap-title: clamp(14px, 1.3vw, 18px);
  --gap-front: clamp(28px, 2.8vw, 40px);
  --gap-chapter: clamp(40px, 4vw, 56px);
  --gap-breath: clamp(48px, 4.8vw, 68px);
  --gap-open: clamp(56px, 5.6vw, 80px);
  --gap-strip: clamp(28px, 2.8vw, 40px);

  color: var(--ink);
}

/* ---------------------------------------------------------------------------
   the sheet
   --------------------------------------------------------------------------- */
/* Trois colonnes, et c'est la colonne du MILIEU qui est centree sur la page,
   pas le groupe. Le texte tombe donc pile au centre optique, et le sommaire
   occupe la marge gauche qui reste. C'est ce que permet le texte justifie :
   les deux bords de la colonne sont droits, donc la centrer se voit. */
.sheet {
  position: relative;
  display: grid;
  grid-template-columns: [rail] 1fr [main] minmax(0, var(--measure-copy)) [edge] 1fr;
  justify-content: center;
  padding: calc(var(--bandeau-clear) + var(--gap-chapter)) var(--page-inset)
    clamp(72px, 8.3vw, 120px);
}

/* L'ouverture et les planches gardent leur mesure large, centree elle aussi :
   trois registres, mais chacun cale sur le meme axe — la marginalia a gauche,
   les planches en large, la lecture au centre. */
.opening,
.strip {
  grid-column: rail / -1;
  width: 100%;
  max-width: var(--wide);
  margin-inline: auto;
}

/* Le sommaire vit dans la marge que laisse la colonne centree. Cette marge
   retrecit avec la fenetre : sans gouttiere imposee il finissait colle au
   texte entre 1024 et 1180 — mesure a 0px. */
.toc {
  grid-column: rail;
  justify-self: start;
  padding-right: 48px;
}
.sheet__body { grid-column: main; }

/* ---------------------------------------------------------------------------
   le sommaire — il suit la lecture au lieu de la precede. Aucune ligne pour
   le separer du texte : c'est le blanc de la gouttiere qui separe, et
   l'entree courante qui passe a pleine encre pour dire ou on en est.
   --------------------------------------------------------------------------- */
.toc {
  position: sticky;
  top: calc(var(--bandeau-clear) + var(--gap-chapter));
  /* il ne demarre pas au meme fil que le corps : un cran plus bas, il se lit
     comme un appareil de navigation et non comme un premier paragraphe */
  margin-top: var(--gap-breath);
  width: 100%;
  max-width: 232px;
  align-self: start;
  max-height: calc(100vh - var(--bandeau-clear) - var(--gap-chapter) * 2);
  overflow-y: auto;
  scrollbar-width: none;
}

.toc::-webkit-scrollbar { display: none; }

.toc__label {
  margin: 0 0 var(--gap-title);
  font-size: var(--text-xs);
  font-weight: var(--font-weight-medium);
  letter-spacing: var(--tracking-caps);
  text-transform: uppercase;
  color: var(--ink-past);
}

.toc__list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.toc__list li + li { margin-top: 14px; }

.toc__link {
  display: block;
  font-family: var(--font-mono);
  font-size: var(--text-xs);
  line-height: 1.6;
  color: var(--ink-past);
  text-decoration: none;
  transition: color 180ms ease;
}

.toc__link:hover,
.toc__link[aria-current="true"] { color: var(--ink); }

.sheet__body { min-width: 0; }

/* Sous 1024 le sommaire couterait plus de place qu'il n'en fait gagner :
   la page redevient une colonne, centree elle aussi. */
/* Sous 1280 la marge ne peut plus loger le sommaire sans etouffer la colonne :
   la page redevient une seule colonne, centree elle aussi. */
@media (max-width: 1279px) {
  .sheet {
    grid-template-columns: minmax(0, var(--measure-copy));
    justify-content: center;
  }

  /* En une colonne, les lignes nommees "rail" n'existent plus : sans cette
     remise a plat, le grid-column: rail / -1 de l'ouverture fabrique une
     colonne implicite et la page deborde. */
  .opening,
  .strip,
  .sheet__body { grid-column: 1; }

  .toc { display: none; }
}

/* Paper node D8R-0: a grain wash at 13% over the whole artboard. No flat white
   on this brand — the sheet has to read as paper. Two layers, both fixed so
   the light stays put while the text travels: a cyanotype wash for the ground,
   the house grain (same recipe as .contact::after) for the tooth. They sit
   under the content, never over it, so nothing dirties the type. */
.sheet::before,
.sheet::after {
  content: "";
  position: fixed;
  inset: 0;
  z-index: 0;
  pointer-events: none;
}

.sheet::before {
  background-image:
    radial-gradient(
      ellipse 68% 58% at 86% -8% in oklab,
      oklab(45% -0.02 -0.14 / 11%) 0%,
      oklab(45% -0.02 -0.14 / 0%) 72%
    ),
    linear-gradient(
      in oklab 180deg,
      oklab(45% -0.02 -0.14 / 5%) 0%,
      oklab(45% -0.02 -0.14 / 0%) 46%
    );
}

.sheet::after {
  /* Paper node D8R-0 sits at 13% — same figure here, multiplied into the
     white so the tooth darkens the sheet instead of tinting it */
  opacity: 0.13;
  mix-blend-mode: multiply;
  background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='240' height='240'%3E%3Cfilter id='n'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3CfeColorMatrix type='saturate' values='0'/%3E%3C/filter%3E%3Crect width='240' height='240' filter='url(%23n)'/%3E%3C/svg%3E");
}

/* Le contenu passe au-dessus du lavis et du grain, qui sont fixes derriere.
   Pas de position: relative ici : les enfants d'une grille prennent leur
   z-index sans etre positionnes, et forcer relative tuerait le sticky du
   sommaire. */
.sheet > * { z-index: 1; }

@media (max-width: 1023px) {
    /* the indent only ever existed to leave room for these; with them gone it
     is dead width, and the mono measure needs every pixel it can get */
  .manifesto { --col-x: var(--page-inset); }
}

/* ---------------------------------------------------------------------------
   the opening — Paper D7B-0 + D7C-0. One block, 96/96 on the wide measure:
   the claim in full ink, the consequence already fading.
   --------------------------------------------------------------------------- */
.opening {
  position: relative;
}

/* Le chiffre et sa phrase partagent une ligne de base. L'ecart d'echelle est
   volontairement brutal — c'est le seul endroit de la page qui hausse la voix
   par la taille plutot que par la mesure. */
/* Paper DS8-0 et DS9-0, releves : le chiffre a 243/203, la phrase a 602/250.
   Elle n'est donc PAS sur sa ligne de base — son bloc tient dans la hauteur du
   chiffre, decale de 47 sur 160, soit 0.294. Alignes par la base, les deux
   lignes pendaient sous le chiffre et laissaient un vide en haut a droite. */
.opening__stat {
  --fig: clamp(72px, 11.1vw, 160px);
  display: grid;
  /* Paper donne au chiffre une boite de 330 pour 160 de corps, soit 2.0625,
     puis 29 de gouttiere. En laissant la colonne se dimensionner sur le
     contenu on perdait 33px et la phrase remontait vers la gauche. */
  grid-template-columns: calc(var(--fig) * 2.0625 - 5px) minmax(0, var(--measure-copy));
  column-gap: calc(var(--fig) * 0.18);
  align-items: start;
  margin: 0 0 calc(var(--fig) * 0.31);
}

/* Paper DS8-0, releve au pixel : le chiffre n'est pas navy plein, c'est une
   FENETRE sur la trame. Les lettres decoupent une photo halftone. Poids 530,
   pas 700 — un gras plein bouche les contreformes et la trame ne se lit plus.
   line-height 125 sur 160, soit 0.78. */
.opening__figure {
  font-family: var(--font-display);
  font-size: var(--fig);
  font-weight: 530;
  font-variation-settings: "wght" 530, "opsz" 32;
  letter-spacing: -0.045em;
  line-height: 0.78;
  color: transparent;
  background-image: url("/img/figure-fill.jpg");
  background-size: cover;
  background-position: 50%;
  -webkit-background-clip: text;
  background-clip: text;
  /* meme precaution que .chalk-text : la boite de peinture doit couvrir les
     glyphes, sinon les hauts et les jambages ne recoivent aucune encre. */
  padding-block: 0.1em;
  /* Paper pose le chiffre a 243 quand le reste de la page est a 248 : les
     5px compensent l'approche a gauche du "7". */
  margin: -0.1em 0 -0.1em -5px;
}

@supports not ((background-clip: text) or (-webkit-background-clip: text)) {
  .opening__figure { color: var(--ink); background-image: none; }
}

.opening__rest {
  /* 47 sur 160 chez Paper, moins les 0.1em dont la marge negative du chiffre
     remonte la rangee. */
  margin-top: calc(var(--fig) * 0.194);
  font-family: var(--font-display);
  font-size: clamp(19px, 2.22vw, 32px);
  font-weight: var(--font-weight-bold);
  letter-spacing: var(--tracking-display);
  line-height: 1.2;
}

.opening__line {
  margin: 0;
  font-size: clamp(24px, 3.05vw, 44px);
  font-family: var(--font-display);
  letter-spacing: var(--tracking-display);
  font-weight: var(--font-weight-bold);
  line-height: 1.32;
}

/* ---------------------------------------------------------------------------
   the strip — Paper D7D/D7G/D7J: three 376x252 frames, flush, no gutter. The
   seam between them is the white hairline each frame draws inside its own
   edge; it separates by material, not by a line drawn between them.
   --------------------------------------------------------------------------- */
.strip {
  /* Ni max-width ni raccourci margin ici : la regle groupee plus haut pose
     --wide et margin-inline: auto, et un `margin: X 0 0` remet les marges
     laterales a zero — la bande repartait collee a gauche. */
  margin-block-start: var(--gap-strip);
}

/* Ecartees, mais ALIGNEES : c'est ce que dit Paper (y=550/549/549), et Paper
   fait foi. L'escalier etait un ajout de code, jamais valide. L'ecart entre
   les cadres suffit a les separer sans les mettre en desordre. */
.strip__frames {
  display: grid;
  grid-template-columns: repeat(3, minmax(0, 1fr));
  gap: clamp(12px, 2.2vw, 40px);
  align-items: start;
}



.strip__frame {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 376 / 252;
  object-fit: cover;
}

/* ---------------------------------------------------------------------------
   the chapters — a title in bold, then the argument in regular. The only thing
   that opens a chapter is the white above it.
   --------------------------------------------------------------------------- */
.chapter { margin-top: var(--gap-chapter); }

.chapter__title {
  max-width: var(--measure-title);
  margin: 0 0 var(--gap-title);
  font-size: clamp(17px, 1.39vw, 20px);
  font-family: var(--font-display);
  letter-spacing: var(--tracking-display);
  font-weight: var(--font-weight-bold);
  line-height: 1.5;
}

/* the two fronts — Paper D80-0 / D82-0, one step under the chapter title */
.chapter__front {
  max-width: var(--measure-copy);
  margin: var(--gap-front) 0 var(--gap-copy);
  font-size: var(--text-sm);
  font-family: var(--font-display);
  letter-spacing: var(--tracking-display);
  font-weight: var(--font-weight-bold);
  line-height: 1.75;
}

/* Le corps est en mono, mesure courte : c'est ce qui argumente, et le mono
   compte large, d'ou les 16 sur 28 de Paper. */
.copy {
  max-width: var(--measure-copy);
  margin: var(--gap-copy) 0 0;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-regular);
  line-height: 1.75;                   /* 28 / 16, per Paper */
  color: var(--ink-argue);
}

/* the sentence a chapter turns on: same size, same measure, full ink */
.copy--lead { color: var(--ink); }

.chapter__title + .copy,
.chapter__front + .copy { margin-top: 0; }

/* ---------------------------------------------------------------------------
   the lines that assert — they break out to the wide measure, which is the
   only way this page raises its voice.
   --------------------------------------------------------------------------- */
.statement-line {
  max-width: var(--measure-wide);
  margin: var(--gap-breath) 0 var(--gap-chapter);
  font-size: clamp(20px, 2.22vw, 32px);
  font-family: var(--font-display);
  letter-spacing: var(--tracking-display);
  font-weight: var(--font-weight-bold);
  line-height: 1.4;
}

/* Paper D7V-0: the verdict on what came before — display size, wide measure,
   but faded, because it is the past tense. */
/* La mise en place de "Today, nothing has to." : meme corps que l'argument,
   mais a pleine encre et seule sur sa ligne. Le contraste se fait par la
   position, plus par la taille. */
.verdict {
  max-width: var(--measure-copy);
  margin: var(--gap-chapter) 0 0;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  font-weight: var(--font-weight-bold);
  line-height: 1.75;
  color: var(--ink-past);
}

/* a chapter that opens on a statement takes the breath at the section level,
   otherwise the title's own margin and the chapter's would stack twice */
.chapter > .statement-line:first-child { margin-top: 0; }
.chapter:has(> .statement-line:first-child) { margin-top: var(--gap-breath); }

/* ---------------------------------------------------------------------------
   the close — Paper D8J-0 and D8K-0. One line, one address. Pas de plaque :
   sur fond craie l'action est typographique.
   --------------------------------------------------------------------------- */
.closing {
  position: relative;
  margin-top: var(--gap-open);
}

.closing__line {
  max-width: var(--measure-wide);
  margin: 0;
  font-size: clamp(18px, 1.67vw, 24px);
  font-family: var(--font-display);
  letter-spacing: var(--tracking-display);
  font-weight: var(--font-weight-bold);
  line-height: 1.5;
}

.closing__mail {
  margin: clamp(72px, 11.1vw, 160px) 0 0;
  font-family: var(--font-mono);
  font-size: var(--text-sm);
  line-height: 1.75;
}

.closing__mail a {
  color: var(--ink);
  text-decoration: underline 1px;
  text-underline-offset: 6px;
  transition: opacity 160ms ease;
}

.closing__mail a:hover { opacity: 0.66; }

/* ---------------------------------------------------------------------------
   the bandeau on a white sheet
   The bar is the landing's, unchanged, but there is no photograph under it
   here: undocked it draws chalk marks on white paper and disappears. So it
   arrives already docked and stays that way — dock.js keeps toggling the
   attribute, both states simply look the same.
   --------------------------------------------------------------------------- */
/* focus lands on navy ink over the sheet, chalk over the bar and the menu */
.manifesto a:focus-visible {
  outline: 1px solid var(--color-paper);
  outline-offset: 6px;
}

.manifesto .bandeau a:focus-visible,
.manifesto .menu a:focus-visible,
.manifesto .bandeau__burger:focus-visible {
  outline: 1px solid var(--color-ink);
  outline-offset: 4px;
}

@media (prefers-reduced-motion: reduce) {
  .closing__mail a { transition: none; }
}

/* ---------------------------------------------------------------------------
   la bande de cloture — c'est celle de la landing, meme classe, meme shader.
   Deux differences : elle est plus basse, parce qu'ici elle ferme une lecture
   au lieu d'occuper un ecran de scroll, et son contenu est centre au lieu
   d'etre cale sur la composition Paper de la section 155-0.
   --------------------------------------------------------------------------- */
.manifesto .closing-band {
  height: auto;
  min-height: clamp(340px, 38vw, 520px);
  align-items: center;
  padding-top: clamp(64px, 7vw, 104px);
  padding-bottom: clamp(64px, 7vw, 104px);
}

.manifesto .closing-band .statement {
  max-width: 1344px;
  margin-inline: auto;
}

/* La feuille n'a plus a menager de blanc en pied : la bande prend le relais. */
.manifesto .sheet { padding-bottom: clamp(56px, 6vw, 88px); }

/* ---------------------------------------------------------------------------
   la page dataset — meme feuille, meme bandeau, meme bande de cloture, mais
   sans sommaire tant qu'il n'y a pas de chapitres a lister. Sans le rail, la
   grille retombe sur une colonne centree ; des qu'Arthur aura livre le fond,
   il suffira de reposer le <nav class="toc"> et de retirer cette regle.
   --------------------------------------------------------------------------- */
.dataset-page .sheet {
  grid-template-columns: minmax(0, var(--measure-copy));
  justify-content: center;
}

.dataset-page .opening,
.dataset-page .strip,
.dataset-page .sheet__body { grid-column: 1; }


/* Deux lignes au format portrait : sans equilibrage, "to." reste veuf sous
   "Today, nothing has". Balance ne s'applique qu'ici — la bande de cloture
   de la landing garde sa casse Paper. */
.manifesto .pivot-band .statement__line { text-wrap: balance; }

/* La bande appartient a ce qui la suit : la reprise se tient un cran plus
   pres d'elle que la feuille qui la precede. Sans quoi le premier chapitre
   empile sa propre respiration sur celle de la feuille. */
.sheet--resume .chapter:first-child { margin-top: 0; }

/* ---------------------------------------------------------------------------
   la matiere de la feuille — le shader paperTexture (voir shader.js) remplace
   le grain feTurbulence de .sheet::after, qui etait quasi invisible. L'hote
   est fixe comme l'etaient les pseudo-elements : la lumiere reste en place,
   le texte voyage dessus. z-index -1 le met sous tout le contenu ; il faut
   alors rendre le body transparent, sinon son fond blanc le recouvre (le
   blanc de html reste derriere en filet de securite).
   --------------------------------------------------------------------------- */
.paper-ground {
  position: fixed;
  inset: 0;
  z-index: -1;
  pointer-events: none;
}

body.paper-live { background: transparent; }
body.paper-live .sheet::after { content: none; }
