/* ==========================================================================
   判 HAN — 朱印帳 / le carnet de tampons. Page de garde uniquement (Phase 29).
   Palette et matières tirées d'objets réels :
     washi (papier kozo)  · sumi (encre de Chine, jamais noir pur)
     shu   (朱肉, cinabre) · kin (砂子, poudre d'or projetée)
     kon   (紺, la toile indigo de la couverture)
     wakaba(若葉, l'érable vert de mai — 青もみじ)
   Adapté du prototype validé par l'utilisateur — voir ROADMAP.md, Phase 29.
   ========================================================================== */

@property --brush { syntax: '<percentage>'; inherits: false; initial-value: 0%; }
/* Phase 98 : cette variable d'animation s'appelait `--ink`, comme le token de
   COULEUR du site défini dans style.css. `@property` enregistre un nom pour tout le
   document : sur les pages qui chargent ce fichier, `--ink` devenait un <number> et
   `light-dark(#1e1a15, …)` n'était plus une valeur valide — le texte retombait sur
   l'initial-value 0, donc du noir pur au lieu du noir chaud de la palette. Trois pages
   étaient touchées (/, /digest, /thematiques). Renommée `--encre` : une variable
   d'opacité et un token de couleur ne peuvent pas partager un nom. */
@property --encre   { syntax: '<number>';     inherits: true;  initial-value: 0; }

/* Phase 64 : un seul jeu de tokens, décliné clair/sombre par light-dark() (voir la note
   détaillée en tête de style.css). */
:root {
  color-scheme: light dark;

  --washi:      light-dark(#ece3cf, #1c1815);
  --washi-hi:   light-dark(#f5eedd, #262019);
  --washi-lo:   light-dark(#ded2b8, #332b21);
  --sumi:       light-dark(#1e1a15, #ece0c8);
  --sumi-2:     light-dark(#4a4133, #c9bc9e);
  /* Phase 66 : #948968 initial ne tenait que 2,73:1 sur --washi (#ece3cf) -- illisible pour
     du texte de label à 10-12px (contrôlé : "準備中 · VERROUILLÉE" sur les pages non atteintes).
     Assombri à 4,57:1, la teinte encre-diluée reste lisible au premier coup d'œil. */
  /* Phase 95 : --usuzumi est désormais défini dans style.css, avec des valeurs qui tiennent
     4,5:1 sur tous les fonds du site — y compris ce bandeau --kon, plus contrasté que --washi,
     où les anciennes valeurs tombaient à 3,00:1 (clair) et 4,30:1 (sombre). On ne le
     redéfinit plus ici : deux définitions pour une même encre, c'était la garantie qu'une
     des deux dérive. */
  --shu:        light-dark(#c23c28, #d9553d);
  --shu-deep:   light-dark(#97281a, #f0846c);
  --shu-pale:   light-dark(#e3b8ab, #4a271d);
  --kin:        light-dark(#b0904c, #d4b06a);
  --kin-hi:     light-dark(#dcc07a, #e8cf9a);
  --wakaba:     light-dark(#7f9c46, #8bb06a);
  --wakaba-deep:light-dark(#5d7733, #628a49);

  /* Phase 65 : couverture désormais thémée elle aussi (retour utilisateur -- "en light mode
     le background devrait aussi être clair"). Toile indigo en sombre, toile 金襴 (brocart
     doré) en clair : deux vraies étoffes de reliure plutôt qu'une couverture figée qui
     ignorait le thème. Les couleurs de texte du bandeau (.gosho-nav, .daisen) qui vivent sur
     cette toile suivent le même changement plus bas dans ce fichier. */
  --kon:        light-dark(#cfb87c, #1a2133);
  --kon-hi:     light-dark(#e7d7a3, #2b3550);

  --mincho: "Shippori Mincho", "Hiragino Mincho ProN", "Yu Mincho", "YuMincho", "Iowan Old Style", Palatino, serif;
  --gothic: "Zen Kaku Gothic New", "Hiragino Sans", "Hiragino Kaku Gothic ProN", "Yu Gothic", -apple-system, "Segoe UI", sans-serif;

  --page-w: 1080px;
}

/* mix-blend-mode: multiply ne fonctionne QUE pour une encre plus SOMBRE que le papier
   (clair × sombre = sombre, correct en thème clair). En thème sombre l'encre est plus
   claire que le papier -- le même multiply écrase le texte vers le noir, illisible.
   Désactivé sur les éléments de texte concernés (pas sur .washi-tex, la texture de grain,
   qui reste correcte en multiply dans les deux thèmes puisque ce n'est pas du texte).

   Seul bloc encore dupliqué du fichier : mix-blend-mode n'est pas une couleur, donc
   light-dark() ne s'y applique pas. Les couleurs associées, elles, sont passées en
   light-dark() directement dans leurs règles d'origine (voir .page.is-blank plus bas). */
:root[data-theme="dark"] :is(.page__title, .page__title-jp, .page__brushdate) {
  mix-blend-mode: normal;
}
@media (prefers-color-scheme: dark) {
  :root:not([data-theme="light"]) :is(.page__title, .page__title-jp, .page__brushdate) {
    mix-blend-mode: normal;
  }
}

/* --------------------------------------------------------------------------
   紺 — la toile de couverture du carnet, tissée. Uniquement sur body.gosho
   (page de garde) : le reste du site garde le papier clair habituel.
   -------------------------------------------------------------------------- */

body.gosho {
  font-family: var(--gothic);
  color: var(--sumi);
  background-color: var(--kon);
  /* Trame du tissage : sur la toile dorée claire, un fil sombre dominant lit comme du relief ;
     sur l'indigo sombre, c'est l'inverse (fil clair = brillance) -- les deux repeating-gradient
     échangent leurs rôles via light-dark() plutôt que de garder un réglage calibré pour un
     seul sens. */
  background-image:
    repeating-linear-gradient(90deg, light-dark(rgba(60,44,10,.05), rgba(255,255,255,.030)) 0 1px, transparent 1px 3px),
    repeating-linear-gradient(0deg,  light-dark(rgba(255,255,255,.28), rgba(0,0,0,.22)) 0 1px, transparent 1px 3px),
    radial-gradient(120% 70% at 50% -10%, var(--kon-hi), transparent 60%);
}

/* fils d'or du 金襴 (brocart) de la couverture, très rares -- en clair la toile EST déjà dorée,
   les fils redeviennent visibles en fils plus sombres (bronze) plutôt qu'en filaments d'or. */
body.gosho::before {
  content: "";
  position: fixed;
  inset: 0;
  pointer-events: none;
  z-index: 0;
  background-image:
    radial-gradient(circle at 12% 22%, light-dark(rgba(120,88,24,.28), rgba(220,192,122,.30)) 0 1px, transparent 1.6px),
    radial-gradient(circle at 78% 8%,  light-dark(rgba(120,88,24,.22), rgba(220,192,122,.22)) 0 1px, transparent 1.6px),
    radial-gradient(circle at 34% 71%, light-dark(rgba(120,88,24,.20), rgba(220,192,122,.20)) 0 1px, transparent 1.6px),
    radial-gradient(circle at 91% 58%, light-dark(rgba(120,88,24,.24), rgba(220,192,122,.24)) 0 1px, transparent 1.6px),
    radial-gradient(circle at 58% 91%, light-dark(rgba(120,88,24,.18), rgba(220,192,122,.18)) 0 1px, transparent 1.6px);
  background-size: 260px 240px, 310px 290px, 210px 330px, 380px 260px, 290px 210px;
}

/* hors échelle, et assumé : 90px est la respiration de pied de couverture (DIRECTION §3.3). */
body.gosho main { padding-bottom: 90px; }

/* --------------------------------------------------------------------------
   Bandeau : 題箋 (daisen, l'étiquette collée sur la couverture) + navigation
   -------------------------------------------------------------------------- */

.masthead {
  position: relative;
  z-index: 3;
  max-width: var(--page-w);
  margin: 0 auto;
  padding: 34px 26px 26px;
  display: flex;
  align-items: flex-start;
  justify-content: space-between;
  gap: 28px;
}

/* L'étiquette de titre était le seul aplat du site à porter du texte thémé sur un papier
   FIGÉ (#f7f2e4 → #ebe2cd). En thème sombre, --sumi devient une encre crème : crème sur
   crème, le titre du carnet tombait à 1,17:1 — il ne s'affaiblissait pas, il disparaissait.
   Le papier passe donc aux tokens de washi, qui basculent avec le thème comme l'encre.
   Même raison pour le filet et le relief : un contour noir à 22 % et un blanc à 50 %,
   calibrés pour du papier clair, ne se voient plus sur du papier sombre. */
.daisen {
  background: linear-gradient(180deg, var(--washi-hi), var(--washi-lo));
  color: var(--sumi);
  padding: var(--esp-4) var(--esp-3) var(--esp-4);
  border: 1px solid light-dark(rgba(30,26,21,.22), rgba(236,224,200,.24));
  box-shadow: 0 6px 18px light-dark(rgba(70,52,14,.28), rgba(0,0,0,.45)),
              inset 0 0 0 3px light-dark(rgba(255,255,255,.5), rgba(255,255,255,.06));
  writing-mode: vertical-rl;
  text-orientation: mixed;
  font-family: var(--mincho);
  font-size: var(--fs-400);
  letter-spacing: .34em;
  line-height: 1.9;
  display: flex;
  gap: 3px;
  transform: rotate(-.5deg);
  flex: none;
}
.daisen .daisen__title { font-weight: 600; font-size: var(--fs-500); }
.daisen .daisen__sub   { color: var(--usuzumi); font-size: var(--fs-100); letter-spacing: .28em; }

.gosho-nav {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: 4px;
  padding-top: 6px;
}
.gosho-nav a {
  position: relative;
  font-family: var(--mincho);
  font-size: var(--fs-300);
  letter-spacing: .13em;
  /* Calibré pour lire sur --kon : encre sombre sur la toile dorée claire, presque blanc
     sur l'indigo sombre -- comme le reste du bandeau, ces teintes suivent la toile. */
  color: light-dark(#4a3a1a, #b9c0d4);
  text-decoration: none;
  padding: 7px 15px 9px;
  display: inline-flex;
  align-items: baseline;
  gap: 8px;
}
.gosho-nav a .nav-jp {
  font-size: var(--fs-100);
  letter-spacing: .2em;
  /* Phase 66 avait corrigé le clair (#7a6636 → 2,86:1) mais pas le sombre, resté à
     3,74:1 sur --kon et 2,84:1 sur --kon-hi. Phase 95 : les deux passent maintenant. */
  color: light-dark(#594921, #969eb2);
}
.gosho-nav a::after {
  content: "";
  position: absolute;
  left: 12px; right: 12px; bottom: 5px;
  height: 1.5px;
  background: var(--kin-hi);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform .38s cubic-bezier(.2,.8,.25,1);
}
.gosho-nav a:hover::after, .gosho-nav a:focus-visible::after { transform: scaleX(1); }
.gosho-nav a:hover, .gosho-nav a:focus-visible { color: light-dark(#241c0c, #f3ecd9); }
.gosho-nav a[aria-current="page"] { color: light-dark(#1c1608, #f7f0dd); }
/* 落款 : le petit carré vermillon qui signe l'onglet actif */
.gosho-nav a[aria-current="page"]::before {
  content: "";
  position: absolute;
  left: 1px; top: 50%;
  width: 7px; height: 7px;
  margin-top: -3px;
  background: var(--shu);
  box-shadow: 0 0 0 1px light-dark(rgba(0,0,0,.14), rgba(255,255,255,.18));
}

/* --------------------------------------------------------------------------
   Le bloc-papier : le carnet lui-même
   -------------------------------------------------------------------------- */

.book {
  position: relative;
  z-index: 2;
  max-width: var(--page-w);
  margin: 0 auto;
  background: var(--washi);
  box-shadow:
    0 34px 70px rgba(0,0,0,.55),
    0 3px 0 rgba(0,0,0,.35),
    inset 0 0 90px rgba(160,132,80,.16);
  border-radius: 2px;
  overflow: hidden;
}

/* tranche du 蛇腹 (reliure accordéon) vue par la gauche */
.book::before {
  content: "";
  position: absolute;
  left: 0; top: 0; bottom: 0;
  width: 13px;
  z-index: 5;
  pointer-events: none;
  background:
    linear-gradient(90deg, rgba(30,20,8,.30), rgba(30,20,8,.06) 55%, transparent),
    repeating-linear-gradient(0deg, rgba(120,96,52,.18) 0 2px, transparent 2px 5px);
}

/* texture washi : grain + fibres de kozo, en SVG inline (pas de data-URI) */
.washi-tex {
  position: absolute;
  inset: 0;
  width: 100%; height: 100%;
  z-index: 1;
  pointer-events: none;
  mix-blend-mode: multiply;
}

/* 砂子 : poudre d'or projetée, dense en haut de page comme sur un papier décoré */
.sunago {
  position: absolute;
  inset: 0;
  z-index: 1;
  pointer-events: none;
  background-image:
    radial-gradient(circle at 18% 12%, rgba(176,144,76,.55) 0 1.1px, transparent 2px),
    radial-gradient(circle at 63% 4%,  rgba(176,144,76,.45) 0 1.4px, transparent 2.4px),
    radial-gradient(circle at 87% 26%, rgba(176,144,76,.40) 0 1px,   transparent 1.8px),
    radial-gradient(circle at 41% 33%, rgba(176,144,76,.35) 0 1.2px, transparent 2.2px),
    radial-gradient(circle at 6%  46%, rgba(176,144,76,.30) 0 1px,   transparent 1.8px);
  background-size: 190px 170px, 240px 210px, 160px 190px, 280px 230px, 210px 260px;
  -webkit-mask-image: linear-gradient(180deg, #000 0%, rgba(0,0,0,.35) 26%, transparent 52%);
          mask-image: linear-gradient(180deg, #000 0%, rgba(0,0,0,.35) 26%, transparent 52%);
}

.book > section,
.book > article,
.book > .fold { position: relative; z-index: 2; }

/* pli d'accordéon entre deux pages */
.fold {
  height: 18px;
  position: relative;
  z-index: 3;
  background:
    linear-gradient(180deg,
      rgba(90,70,34,.14) 0%,
      rgba(90,70,34,.05) 34%,
      rgba(255,252,242,.85) 50%,
      rgba(90,70,34,.07) 66%,
      rgba(90,70,34,.03) 100%);
}
.fold::after {
  content: "";
  position: absolute;
  left: 0; right: 0; top: 50%;
  height: 1px;
  background: rgba(120,96,52,.30);
}

/* --------------------------------------------------------------------------
   En-tête du carnet
   -------------------------------------------------------------------------- */

.hero {
  display: grid;
  grid-template-columns: 62px 1fr 260px;
  gap: 0 var(--esp-6);
  /* hors échelle, et assumé : 54/46/40px sont la respiration de la couverture, réglée à
     l'œil sur la marge du papier. Les arrondir à 48/32 resserrerait la seule page du site
     qui a le droit de respirer — voir DIRECTION §3.3. */
  padding: 54px 46px 46px 40px;
  align-items: start;
}

.hero__date {
  writing-mode: vertical-rl;
  font-family: var(--mincho);
  font-size: var(--fs-500);
  letter-spacing: .32em;
  color: var(--sumi-2);
  justify-self: center;
  padding-top: 4px;
  -webkit-mask-image: linear-gradient(180deg, #000 var(--brush), transparent calc(var(--brush) + 8%));
          mask-image: linear-gradient(180deg, #000 var(--brush), transparent calc(var(--brush) + 8%));
}
.hero__date .sm { font-size: var(--fs-200); color: var(--usuzumi); letter-spacing: .26em; }

.hero__title {
  font-family: var(--mincho);
  font-weight: 700;
  /* Une des deux exceptions fluides prévues par la DIRECTION §3.1 : le titre de couverture.
     Le plancher est le h1 du site ; le plafond de 50px est hors échelle et assumé — c'est
     le seul titre du site qui doive se lire comme une couverture de livre. */
  font-size: clamp(var(--fs-700), 4.4vw, 50px);
  line-height: var(--lh-serre);
  letter-spacing: -.005em;
  margin: 2px 0 var(--esp-5);
  text-wrap: balance;
  -webkit-mask-image: linear-gradient(100deg, #000 var(--brush), transparent calc(var(--brush) + 9%));
          mask-image: linear-gradient(100deg, #000 var(--brush), transparent calc(var(--brush) + 9%));
}
.hero__lede {
  font-size: var(--fs-400);
  line-height: var(--lh-lecture);
  color: var(--sumi-2);
  /* La colonne éditoriale de la couverture : la seule du site à 46ch (DIRECTION §3.5). */
  max-width: var(--mesure-etroite);
  margin: 0 0 var(--esp-5);
}
.hero__meta {
  display: flex;
  align-items: center;
  gap: var(--esp-4);
  font-size: var(--fs-200);
  letter-spacing: .1em;
  color: var(--usuzumi);
  text-transform: uppercase;
}
.hero__meta .rule { flex: 1; height: 1px; background: rgba(120,96,52,.35); max-width: 180px; }
.hero__meta b { color: var(--shu-deep); font-weight: 700; }

/* le kanji 旅 tracé au pinceau, ordre des traits */
.kanji {
  width: 100%;
  max-width: 240px;
  aspect-ratio: 1;
  justify-self: end;
  color: var(--sumi);
  overflow: visible;
}
.kanji text { font-family: var(--mincho); }
.kanji .sweep {
  fill: none;
  stroke: #fff;
  stroke-width: 13;
  stroke-linecap: round;
  stroke-linejoin: round;
  stroke-dasharray: 1;
  stroke-dashoffset: 1;
}
.kanji__caption {
  font-family: var(--mincho);
  font-size: var(--fs-100);
  letter-spacing: .24em;
  fill: var(--usuzumi);
}

/* --------------------------------------------------------------------------
   Une page = une étape
   -------------------------------------------------------------------------- */

.page {
  position: relative;
  padding: 40px 46px 44px 40px;
  display: grid;
  grid-template-columns: 62px 1fr;
  gap: 0 30px;
  min-height: 216px;
}

/* colonne de gauche : le sceau de numéro (第一 / 第二 / …), style 番号印 */
.page__num {
  justify-self: center;
  width: 42px; height: 52px;
  display: grid;
  place-items: center;
  font-family: var(--mincho);
  font-size: 15px;
  line-height: 1.05;
  letter-spacing: .05em;
  writing-mode: vertical-rl;
  color: var(--shu);
  border: 1.6px solid var(--shu);
  box-shadow: inset 0 0 0 2.5px transparent, inset 0 0 0 3.5px rgba(194,60,40,.5);
  transform: rotate(-2deg);
  margin-top: 4px;
  filter: url(#rough);
}

/* 空押し : la page verrouillée porte un sceau gaufré, pressé mais sans encre */
.page.is-blank .page__num {
  color: transparent;
  border-color: rgba(0,0,0,.06);
  box-shadow:
    inset 0 0 0 2.5px transparent,
    inset 0 0 0 3.5px rgba(0,0,0,.045),
    1px 1px 0 rgba(255,255,255,.75),
    -1px -1px 1px rgba(120,96,52,.22);
  filter: none;
}
.page.is-blank .page__num::after {
  content: attr(data-num);
  writing-mode: vertical-rl;
  color: rgba(90,72,40,.20);
  text-shadow: 0 1px 0 rgba(255,255,255,.8);
}

.page__state {
  display: inline-flex;
  align-items: center;
  gap: 9px;
  font-family: var(--mincho);
  font-size: 12px;
  letter-spacing: .26em;
  margin: 0 0 8px;
  color: var(--usuzumi);
}
.page__state .fr {
  font-family: var(--gothic);
  font-size: 10px;
  letter-spacing: .12em;
  text-transform: uppercase;
  color: var(--usuzumi);
}
.page.is-stamped .page__state { color: var(--shu-deep); }
.page.is-current .page__state { color: var(--shu); }
/* 受付中 : la pastille qui bat, comme l'enseigne « guichet ouvert » */
.page.is-current .page__state::before {
  content: "";
  width: 7px; height: 7px;
  border-radius: 50%;
  background: var(--shu);
  animation: uketsuke 2.4s ease-in-out infinite;
}

@keyframes uketsuke {
  0%, 100% { box-shadow: 0 0 0 0 rgba(194,60,40,.45); opacity: 1; }
  55%      { box-shadow: 0 0 0 7px rgba(194,60,40,0); opacity: .55; }
}

.page__title {
  font-family: var(--mincho);
  font-weight: 600;
  font-size: clamp(24px, 3vw, 34px);
  line-height: 1.2;
  margin: 0 0 4px;
  position: relative;
  z-index: 4;
  mix-blend-mode: multiply;
  display: inline-block;
  -webkit-mask-image: linear-gradient(100deg, #000 var(--brush), transparent calc(var(--brush) + 10%));
          mask-image: linear-gradient(100deg, #000 var(--brush), transparent calc(var(--brush) + 10%));
}
.page__title a { color: inherit; text-decoration: none; }
.page__title-jp {
  display: block;
  font-family: var(--mincho);
  font-size: 15px;
  letter-spacing: .3em;
  color: var(--sumi-2);
  margin: 0 0 14px;
  position: relative;
  z-index: 4;
  mix-blend-mode: multiply;
  -webkit-mask-image: linear-gradient(100deg, #000 var(--brush), transparent calc(var(--brush) + 12%));
          mask-image: linear-gradient(100deg, #000 var(--brush), transparent calc(var(--brush) + 12%));
}
.page__q {
  font-size: 14.5px;
  color: var(--sumi-2);
  max-width: 52ch;
  margin: 0 0 12px;
  position: relative;
  z-index: 4;
}
.page__done-note {
  font-size: 12.5px;
  color: var(--usuzumi);
  max-width: 52ch;
  margin: 0 0 20px;
  position: relative;
  z-index: 4;
}
.page__cta {
  display: inline-block;
  font-family: var(--mincho);
  font-size: 13px;
  letter-spacing: .1em;
  color: var(--shu-deep);
  text-decoration: none;
  border-bottom: 1px solid currentColor;
  padding-bottom: 1px;
  position: relative;
  z-index: 4;
  margin-top: 4px;
}
.page__cta:hover { color: var(--shu); }

/* Phase 66 : .42 ne tenait que 2,05:1 sur --washi -- remonté à .72 (~4:1) pour la même
   raison que --usuzumi ci-dessus. Le titre d'une page verrouillée reste nettement plus
   pâle qu'une page atteinte (var(--sumi) plein), mais redevient lisible. */
.page.is-blank .page__title,
.page.is-blank .page__title-jp,
.page.is-blank .page__q { color: light-dark(rgba(74,65,51,.72), rgba(236,224,200,.45)); }

/* la date manuscrite verticale de la page tamponnée */
.page__brushdate {
  position: absolute;
  right: 46px;
  top: 40px;
  writing-mode: vertical-rl;
  font-family: var(--mincho);
  font-size: 16px;
  letter-spacing: .3em;
  color: var(--sumi-2);
  z-index: 4;
  mix-blend-mode: multiply;
  -webkit-mask-image: linear-gradient(180deg, #000 var(--brush), transparent calc(var(--brush) + 10%));
          mask-image: linear-gradient(180deg, #000 var(--brush), transparent calc(var(--brush) + 10%));
}

/* --------------------------------------------------------------------------
   印 — le sceau. Composant partagé.
   -------------------------------------------------------------------------- */

.seal {
  position: relative;
  display: inline-grid;
  place-items: center;
  width: var(--sz, 96px);
  height: var(--sz, 96px);
  flex: none;
}

.seal__body {
  grid-area: 1 / 1;
  position: relative;
  width: 100%; height: 100%;
  display: grid;
  place-items: center;
  color: var(--shu);
  border: 3px solid currentColor;
  box-shadow: inset 0 0 0 3px transparent, inset 0 0 0 4.5px currentColor;
  filter: url(#rough);
  opacity: var(--encre);
}
.seal--round .seal__body { border-radius: 50%; }

/* l'encre du 朱肉 n'est jamais uniforme : masque moucheté */
.seal__body::after {
  content: "";
  position: absolute;
  inset: -6px;
  background: rgba(240,232,213,.42);
  mix-blend-mode: screen;
  -webkit-mask-image: radial-gradient(circle at 31% 37%, #000 0 .55px, transparent 1.1px),
                      radial-gradient(circle at 68% 64%, #000 0 .45px, transparent .9px),
                      radial-gradient(circle at 54% 15%, #000 0 .4px,  transparent .8px);
  -webkit-mask-size: 9px 8px, 11px 13px, 7px 12px;
          mask-image: radial-gradient(circle at 31% 37%, #000 0 .55px, transparent 1.1px),
                      radial-gradient(circle at 68% 64%, #000 0 .45px, transparent .9px),
                      radial-gradient(circle at 54% 15%, #000 0 .4px,  transparent .8px);
          mask-size: 9px 8px, 11px 13px, 7px 12px;
  pointer-events: none;
}

.seal__glyph {
  font-family: var(--mincho);
  font-weight: 600;
  font-size: calc(var(--sz, 96px) * .52);
  line-height: 1;
  letter-spacing: .02em;
  color: currentColor;
}
/* hanko personnel : katakana en colonnes, de droite à gauche — la vraie mise en page */
.seal__kana {
  display: flex;
  flex-direction: row-reverse;
  gap: 1px;
  font-family: var(--mincho);
  font-weight: 600;
  line-height: 1.0;
  font-size: calc(var(--sz, 60px) * .25);
  letter-spacing: .02em;
  color: currentColor;
}
.seal__kana span { writing-mode: vertical-rl; text-orientation: upright; }
.seal__kana:has(span:only-child) { font-size: calc(var(--sz, 60px) * .34); }

/* diffusion de l'encre dans les fibres */
.seal__bleed {
  grid-area: 1 / 1;
  width: 118%; height: 118%;
  border-radius: 50%;
  background: radial-gradient(circle, rgba(194,60,40,.28), rgba(194,60,40,.08) 55%, transparent 72%);
  opacity: 0;
  pointer-events: none;
}
/* onde de contact sur le papier */
.seal__ring {
  grid-area: 1 / 1;
  width: 100%; height: 100%;
  border: 1px solid rgba(194,60,40,.6);
  border-radius: 4px;
  opacity: 0;
  pointer-events: none;
}
.seal--round .seal__ring { border-radius: 50%; }

/* poussière de papier soulevée à l'impact */
.seal__dust { grid-area: 1 / 1; position: relative; width: 100%; height: 100%; pointer-events: none; }
.seal__dust i {
  position: absolute;
  left: 50%; top: 50%;
  width: 3px; height: 3px;
  margin: -1.5px 0 0 -1.5px;
  border-radius: 50%;
  background: rgba(151,40,26,.55);
  opacity: 0;
}

/* --- le grand sceau carré de la page terminée --- */
.page__seal {
  --sz: 116px;
  position: absolute;
  left: 470px;
  top: 6px;
  z-index: 2;                 /* SOUS le texte : au Japon on écrit par-dessus le sceau */
  transform: rotate(-6deg);
  background: none;
  border: 0;
  padding: 0;
  cursor: pointer;
  opacity: 0;
}
.page__seal:focus-visible {
  outline: 2px dashed var(--shu-deep);
  outline-offset: 8px;
}

/* --------------------------------------------------------------------------
   押印欄 — la grille de tampons de l'étape en cours (carte de stamp rally)
   -------------------------------------------------------------------------- */

/* Phase 64 : le fond était un blanc chaud figé (rgba(255,251,240,.42)) qui ne suivait pas
   le thème -- en mode sombre ça donnait du texte beige clair sur un fond clair, illisible.
   Rebranché sur les tokens comme toutes les autres surfaces. */
.ranbox {
  position: relative;
  z-index: 4;
  border: 1.5px solid light-dark(rgba(120,96,52,.42), rgba(200,176,120,.30));
  padding: 15px 18px 17px;
  max-width: 560px;
  background: light-dark(rgba(255,251,240,.42), rgba(255,246,225,.05));
}
.ranbox__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: 12px;
  margin-bottom: 13px;
  padding-bottom: 9px;
  border-bottom: 1px dashed rgba(120,96,52,.35);
}
.ranbox__label {
  font-family: var(--mincho);
  font-size: 12.5px;
  letter-spacing: .3em;
  color: var(--sumi-2);
}
.ranbox__hint {
  font-size: 11px;
  letter-spacing: .05em;
  color: var(--usuzumi);
}

.slots { display: flex; gap: 10px; flex-wrap: wrap; }

.slot {
  flex: 1 1 108px;
  background: none;
  border: 0;
  padding: 6px 4px 8px;
  font: inherit;
  color: inherit;
  cursor: pointer;
  display: grid;
  justify-items: center;
  gap: 6px;
  border-radius: 3px;
  transition: background .25s ease;
}
.slot:hover { background: radial-gradient(60% 50% at 50% 38%, rgba(194,60,40,.07), transparent 70%); }
.slot:focus-visible { outline: 2px dashed var(--shu-deep); outline-offset: 2px; }

.slot__disc {
  position: relative;
  width: 62px; height: 62px;
  display: grid;
  place-items: center;
}
/* l'emplacement vide : cercle en pointillés, comme sur un carnet de stamp rally */
.slot__disc::before {
  content: "";
  position: absolute;
  inset: 0;
  border-radius: 50%;
  border: 1.5px dashed rgba(120,96,52,.5);
  transition: opacity .3s ease;
}
.slot.is-stamped .slot__disc::before { opacity: 0; }

.slot .seal { --sz: 62px; grid-area: 1 / 1; opacity: 0; }
.slot__name {
  font-size: 12.5px;
  font-weight: 600;
  letter-spacing: .01em;
}
.slot__count {
  font-family: var(--mincho);
  font-size: 11.5px;
  letter-spacing: .08em;
  color: var(--usuzumi);
}
.slot.is-stamped .slot__count { color: var(--shu-deep); }

/* survol d'un emplacement vide : le hanko flotte au-dessus du papier avant d'être pressé */
.slot:not(.is-stamped) .seal { transition: opacity .3s ease, transform .3s ease; }
.slot:not(.is-stamped):hover .seal,
.slot:not(.is-stamped):focus-visible .seal {
  opacity: .3;
  transform: translateY(-9px) scale(1.12);
}
.slot:not(.is-stamped) .seal { --encre: 1; }

/* --------------------------------------------------------------------------
   結果欄 — quand il n'y a pas de total net (ex. Digest), juste des comptes
   -------------------------------------------------------------------------- */

.tallybox {
  position: relative;
  z-index: 4;
  display: flex;
  flex-wrap: wrap;
  gap: 8px 18px;
  margin: 0 0 20px;
  font-size: 12.5px;
  color: var(--sumi-2);
}
.tallybox b { color: var(--shu-deep); font-family: var(--mincho); }

/* --------------------------------------------------------------------------
   栞 — le marque-page : une feuille d'érable vert (青もみじ), la saison de mai
   -------------------------------------------------------------------------- */

.shiori {
  position: absolute;
  right: 26px;
  top: -30px;
  width: 42px;
  color: var(--wakaba);
  z-index: 6;
  transform-origin: 50% 8%;
  filter: drop-shadow(0 4px 5px rgba(40,50,20,.28));
}
.shiori__stem {
  position: absolute;
  left: 50%;
  top: -34px;
  width: 1.5px;
  height: 44px;
  margin-left: -.75px;
  background: linear-gradient(180deg, transparent, var(--wakaba-deep));
}
.shiori__leaf { display: block; width: 100%; }

/* --------------------------------------------------------------------------
   pied de page
   -------------------------------------------------------------------------- */

/* Phase 66 : comme .gosho-nav, ce texte vit directement sur --kon (la toile de couverture,
   pas le papier du carnet) -- calibré à l'origine pour l'indigo sombre uniquement, illisible
   depuis que la Phase 65 a rendu la couverture claire en thème clair. */
.colophon {
  position: relative;
  z-index: 2;
  max-width: var(--page-w);
  margin: var(--esp-5) auto 0;
  padding: 0 var(--esp-5);
  color: light-dark(#4a3a1a, #9aa3bd);
  font-size: var(--fs-200);
  line-height: var(--lh-lecture);
  display: flex;
  gap: var(--esp-5);
  align-items: flex-start;
  justify-content: space-between;
  flex-wrap: wrap;
}
.colophon p { margin: 0; max-width: var(--mesure); }
.colophon a { color: light-dark(#2e2210, #c3cbe0); }
/* Phase 95 : 4,43:1 sur --kon clair, 3,9:1 sur --kon sombre — sous le seuil de 4,5. */
.colophon .jp { font-family: var(--mincho); letter-spacing: .2em; color: light-dark(#594921, #969eb2); }

/* ==========================================================================
   ANIMATIONS
   ========================================================================== */

@keyframes brushIn { from { --brush: 0%; } to { --brush: 112%; } }
@keyframes brushDown { from { --brush: 0%; } to { --brush: 112%; } }

@keyframes press {
  0%   { transform: rotate(var(--rot,-6deg)) translateY(-64px) scale(1.42); opacity: 0; filter: blur(2px); }
  30%  { opacity: 1; filter: blur(.6px); }
  46%  { transform: rotate(var(--rot,-6deg)) translateY(0) scale(1); opacity: 1; filter: blur(0); }
  54%  { transform: rotate(var(--rot,-6deg)) translateY(3px) scale(1.045, .955); }
  70%  { transform: rotate(var(--rot,-6deg)) translateY(-9px) scale(1.015); }
  86%  { transform: rotate(var(--rot,-6deg)) translateY(1px) scale(.998); }
  100% { transform: rotate(var(--rot,-6deg)) translateY(0) scale(1); opacity: 1; }
}
@keyframes soak {
  0%, 44%  { --encre: 0; }
  50%      { --encre: .45; }
  68%      { --encre: .92; }
  100%     { --encre: 1; }
}
@keyframes soakBlur {
  0%, 44%  { filter: url(#rough) blur(2.4px); }
  62%      { filter: url(#rough) blur(.7px); }
  100%     { filter: url(#rough) blur(0); }
}
@keyframes bleed {
  0%, 45% { opacity: 0; transform: scale(.55); }
  55%     { opacity: .95; transform: scale(1); }
  100%    { opacity: 0; transform: scale(1.45); }
}
@keyframes shock {
  0%, 45% { opacity: 0; transform: scale(.82); }
  52%     { opacity: .8;  transform: scale(1.02); }
  100%    { opacity: 0;  transform: scale(1.75); }
}
@keyframes dust {
  0%, 45% { opacity: 0; transform: rotate(var(--a)) translateX(6px) scale(1); }
  56%     { opacity: .8; }
  100%    { opacity: 0; transform: rotate(var(--a)) translateX(var(--d, 46px)) scale(.2); }
}
@keyframes draw { to { stroke-dashoffset: 0; } }
@keyframes settle {
  from { opacity: 0; transform: translateY(16px); }
  to   { opacity: 1; transform: none; }
}
@keyframes sway {
  0%, 100% { transform: rotate(-3.5deg); }
  50%      { transform: rotate(3.5deg); }
}
@keyframes stick {
  from { opacity: 0; transform: rotate(-6deg) translateY(-22px); }
  to   { opacity: 1; transform: rotate(-.5deg) translateY(0); }
}

/* --- état initial (JS actif uniquement) --- */
.js .anim-brush { --brush: 0%; }
.js .anim-settle { opacity: 0; }
.js .daisen { opacity: 0; }
.js .kanji .sweep { stroke-dashoffset: 1; }

/* --- déclenchement --- */
.js .daisen.in { animation: stick .9s cubic-bezier(.2,.9,.3,1) both; }

.js .in .anim-brush,
.js .anim-brush.in {
  animation: brushIn var(--dur, 1s) cubic-bezier(.55,.05,.3,1) var(--delay, 0ms) both;
}
.js .in .anim-brush.vertical,
.js .anim-brush.vertical.in {
  animation-name: brushDown;
}
.js .in .anim-settle,
.js .anim-settle.in {
  animation: settle .8s cubic-bezier(.2,.8,.3,1) var(--delay, 0ms) both;
}
.js .in .kanji .sweep {
  animation: draw var(--dur, 2.6s) cubic-bezier(.6,.02,.4,1) var(--delay, 300ms) both;
}

/* le sceau : lancé par une classe, pour pouvoir le rejouer */
.stamping .seal__body { animation: soak 1.15s linear both, soakBlur 1.15s linear both; }
.stamping .seal__bleed { animation: bleed 1.5s cubic-bezier(.2,.7,.3,1) both; }
.stamping .seal__ring  { animation: shock 1.1s cubic-bezier(.15,.75,.3,1) both; }
.stamping .seal__dust i { animation: dust 1.1s cubic-bezier(.1,.8,.3,1) both; }
.page__seal.stamping   { animation: press 1.15s cubic-bezier(.3,1.4,.5,1) both; }
.slot.is-stamped .seal { opacity: 1; --encre: 1; }
.slot .seal.stamping   { animation: press 1s cubic-bezier(.3,1.4,.5,1) both; opacity: 1; }
.page__seal.is-stamped { opacity: 1; --encre: 1; }

.js .shiori { animation: sway 7s ease-in-out infinite; }

/* --------------------------------------------------------------------------
   Responsive
   -------------------------------------------------------------------------- */

@media (max-width: 900px) {
  .hero { grid-template-columns: 48px 1fr; padding: 40px 26px 34px 22px; }
  .kanji { grid-column: 2; justify-self: start; max-width: 150px; margin-top: 8px; }
  .page { grid-template-columns: 48px 1fr; padding: 32px 22px 34px 22px; }
  .page__seal { left: auto; right: 14px; top: 8px; --sz: 84px; }
  .page__brushdate {
    position: static;
    grid-column: 2;
    writing-mode: horizontal-tb;
    font-size: 12.5px;
    letter-spacing: .22em;
    color: var(--usuzumi);
    margin: 16px 0 0;
    -webkit-mask-image: linear-gradient(100deg, #000 var(--brush), transparent calc(var(--brush) + 10%));
            mask-image: linear-gradient(100deg, #000 var(--brush), transparent calc(var(--brush) + 10%));
  }
  .ranbox { max-width: none; }
  .ranbox__head { flex-direction: column; gap: 2px; }
  .ranbox__label { white-space: nowrap; }
  .masthead { flex-direction: column; gap: 18px; padding: 24px 20px 20px; }
  .daisen { writing-mode: horizontal-tb; flex-direction: row-reverse; align-items: baseline; gap: 12px; letter-spacing: .22em; padding: 9px 15px; }
  .gosho-nav { padding-top: 0; margin-left: -12px; }
}
@media (max-width: 560px) {
  .slot { flex: 1 1 40%; }
  .page__seal { --sz: 76px; }
}

/* --------------------------------------------------------------------------
   Mouvement réduit : tout est déjà posé, l'encre est sèche.
   -------------------------------------------------------------------------- */

@media (prefers-reduced-motion: reduce) {
  .js .anim-brush,
  .js .anim-brush.in,
  .js .in .anim-brush { --brush: 120%; animation: none !important; }
  .js .anim-settle,
  .js .anim-settle.in,
  .js .in .anim-settle { opacity: 1; transform: none; animation: none !important; }
  .js .daisen, .js .daisen.in { opacity: 1; transform: rotate(-.5deg); animation: none !important; }
  .js .kanji .sweep, .js .in .kanji .sweep { stroke-dashoffset: 0; animation: none !important; }
  .js .shiori { animation: none !important; transform: rotate(-3deg); }
  .page.is-current .page__state::before { animation: none !important; }
  .seal__body { --encre: 1; filter: url(#rough) !important; }
  .page__seal { opacity: 1 !important; --encre: 1; }
  /* les cases non tamponnées le restent : personne ne doit lire un faux tampon */
  .slot.is-stamped .seal      { opacity: 1; --encre: 1; }
  .slot:not(.is-stamped) .seal { opacity: 0; }
  .slot:not(.is-stamped):hover .seal,
  .slot:not(.is-stamped):focus-visible .seal { opacity: .3; }
  .seal__bleed, .seal__ring, .seal__dust { display: none !important; }
  *, *::before, *::after { animation-duration: .001ms !important; transition-duration: .001ms !important; }
}

/* ===========================================================================
   Phase 69 — Adaptation mobile de la page de garde
   =========================================================================== */

/* ---------------------------------------------------------------------------
   Phase 71 — le contenu ne doit JAMAIS dépendre d'une animation pour être lisible.

   Constaté sur iPhone : les titres n'affichaient qu'un caractère (« V », « Q »). La classe
   `.js`, posée dès le <head>, masque les titres derrière `mask-image` avec `--brush: 0%` ;
   seul le JS (IntersectionObserver -> classe `.in`) les révèle. Si cette révélation échoue --
   pour n'importe quelle raison propre à l'appareil ou au navigateur -- le texte reste
   invisible **définitivement**. C'est un contenu essentiel rendu otage d'un effet décoratif.

   Sur téléphone l'effet de pinceau est de toute façon peu perceptible (titres courts, écran
   étroit) : on le désactive et le texte est posé d'emblée. Même motif que le bloc
   `prefers-reduced-motion` plus bas dans ce fichier, qui résout déjà ce problème pour un
   autre motif -- l'échappatoire existait, elle ne couvrait simplement pas ce cas.
   --------------------------------------------------------------------------- */
@media (max-width: 900px) {
  .js .anim-brush,
  .js .anim-brush.in,
  .js .in .anim-brush { --brush: 120%; animation: none !important; }
  .js .anim-settle,
  .js .anim-settle.in,
  .js .in .anim-settle { opacity: 1; transform: none; animation: none !important; }
  .js .kanji .sweep, .js .in .kanji .sweep { stroke-dashoffset: 0; animation: none !important; }
}

@media (max-width: 430px) {
  /* `min-height: 216px` n'était surchargé nulle part : chaque bloc de page faisait au moins
     216px de haut même quasi vide, ce qui allongeait inutilement le carnet sur téléphone. */
  .page { min-height: 0; padding: 26px 16px 28px 16px; gap: 0 16px; grid-template-columns: 40px 1fr; }
  .page__num { width: 36px; height: 44px; font-size: 13px; }

  /* Le sceau est en `position: absolute` dans le coin haut-droit du bloc : il ne participe
     pas au flux, donc rien ne l'empêche de recouvrir le titre. Resserrer le padding de .page
     ci-dessus a élargi la colonne de texte jusque sous le sceau -- le titre passait dessous
     (mesuré : 67x29px de recouvrement à 390px, aucun à partir de 500px).
     Deux mesures conjointes : un sceau plus petit, adapté à l'écran, et une réserve
     horizontale sur les deux lignes de titre, qui sont les seules à sa hauteur. */
  .page__seal { --sz: 58px; right: 8px; top: 4px; }
  .page__title, .page__title-jp { padding-right: 68px; }
  .hero { padding: 32px 16px 28px 16px; gap: 0 16px; grid-template-columns: 40px 1fr; }
  .masthead { padding: 18px 14px 14px; gap: 12px; }
  .colophon { padding: 0 var(--esp-4); font-size: var(--fs-200); gap: var(--esp-4); }
  body.gosho main { padding-bottom: 96px; } /* le bouton de thème flotte au-dessus */

  /* La nav de la page de garde a son propre style (elle ne passe pas par .topbar) : elle
     prenait 3 lignes et ~200px de haut avant même d'arriver au carnet. Le suffixe kanji est
     un ornement qui double la largeur de chaque lien -- retiré ici comme dans le bandeau. */
  .gosho-nav { gap: 2px; }
  .gosho-nav a { font-size: var(--fs-200); padding: 6px 9px 8px; letter-spacing: .07em; }
  .gosho-nav a .nav-jp { display: none; }
}

/* ===========================================================================
   Phase 73 — Coût de rendu sur téléphone

   Symptômes signalés : défilement saccadé ET « chargement long » alors que le
   serveur répond en 78 ms et que la page ne pèse que 110 Ko. Quand les octets
   arrivent vite mais que la page paraît lente, ce n'est plus du réseau : c'est
   le coût de DESSIN. Les deux symptômes ont ici la même cause.

   Le poste principal est `.washi-tex` : un SVG qui couvre tout le carnet
   (environ 390 x 3000px sur téléphone) et contient DEUX rectangles pleine
   taille filtrés par `feTurbulence` -- du bruit de Perlin calculé pixel par
   pixel sur 4 octaves, deux fois, soit ~9 millions d'évaluations de bruit --
   le tout composé en `mix-blend-mode: multiply`, qui force en plus un calque
   de composition séparé pour toute la hauteur du carnet.

   S'y ajoutent 8 sceaux de numéro et les tampons, chacun filtré par `#rough`
   (encore du `feTurbulence`, en déplacement de contours cette fois).

   Sur téléphone, ces textures sont de toute façon quasi imperceptibles : la
   densité de pixels les écrase et l'écran est petit. On les retire donc sous
   900px. Le papier garde sa couleur, ses fibres via .sunago (de simples
   dégradés, eux peu coûteux) et ses ombres : l'esprit reste, le coût part.
   =========================================================================== */

@media (max-width: 900px) {
  /* Le poste le plus lourd : deux feTurbulence pleine page + un calque de fusion. */
  .washi-tex { display: none; }

  /* feTurbulence de déplacement, une instance par sceau de numéro et par tampon. */
  .page__num,
  .seal__body,
  .stamping .seal__body { filter: none !important; }

  /* Le grain d'or reste (dégradés simples), mais son masque force lui aussi un
     calque : sur mobile on le laisse sans masque, il est déjà très discret. */
  .sunago { -webkit-mask-image: none; mask-image: none; opacity: .5; }
}

/* Phase 85 : l'entrée dans le carnet, depuis le colophon de la page de garde.
   Traitée comme un objet et non comme un lien de navigation. */
.colophon-carnet {
  margin: 0 0 var(--esp-4);
  padding: var(--esp-3) var(--esp-4);
  /* Le fond suivait déjà le thème, pas le filet : un brun à 38 % posé sur l'indigo sombre
     tombait à 1,35:1, l'encadré n'avait plus de contour. Le couple correct existait depuis
     la phase 64 juste au-dessus, sur .ranbox — il n'avait jamais été propagé ici. */
  border: 1px solid light-dark(rgba(120, 96, 52, .38), rgba(200, 176, 120, .30));
  background: light-dark(rgba(255, 252, 242, .42), rgba(255, 252, 242, .05));
}
.colophon-carnet a { color: var(--shu-deep); text-decoration: none; font-size: var(--fs-300); }
.colophon-carnet a:hover { text-decoration: underline; }
.colophon-carnet .colophon-carnet__action { display:inline-block; font-size:var(--fs-400); font-weight:700; }
.colophon-carnet .jp { font-family: var(--mincho); letter-spacing: .22em; margin-right: var(--esp-2); }
.colophon-carnet__note {
  display: block;
  margin-top: var(--esp-1);
  font-size: var(--fs-200);
  line-height: var(--lh-lecture);
  color: var(--usuzumi);
  max-width: var(--mesure-etroite);
}
