/* Formist · the side index: the ticks at the right edge which name a page's chapters. One file for every page which carries an index
   (R1.9.37, 11 Nov 2026). Until then each page held its own copy, and the copies had drifted apart.

   Rest: ticks only, the current one in ink.
   Arrival: the chapter's own name slides out from its tick and back.
   Reach for it (hover or focus with a mouse or keyboard, press and hold with a finger, and once per visit as an introduction):
   every name slides out in a short cascade, then slides back.

   Each name stands on its own small ground in the page's color, so it reads over the work. Nothing stands behind the list as a
   whole in any state: no panel, no block, no veil (founder, 11 Nov, superseding the block of 7 Nov).

   Smooth by construction: every name is always laid out beside its tick and only fades and slides, so nothing reflows, and an
   interrupted motion reverses from where it is. The script is /fs/snv.js; a page supplies only its list of chapters. */

.snv{ --snv-hl:#7A463E; position:fixed; z-index:29; top:0; bottom:0; right:calc(env(safe-area-inset-right, 0px) + 6px); height:fit-content; margin:auto 0; display:none;
  transition:opacity .3s ease, visibility 0s linear 0s; }
@media (prefers-color-scheme:dark){ :root:not([data-theme="light"]) .snv{ --snv-hl:#BC8A8C; } }
:root[data-theme="dark"] .snv{ --snv-hl:#BC8A8C; }
@media (min-width:768px) and (hover:hover) and (pointer:fine){ .snv{ display:block; } }
.snv.out{ opacity:0; visibility:hidden; transition:opacity .3s ease, visibility 0s linear .3s; }
html:has(#menu:not([hidden])) .snv, html:has(dialog[open]) .snv{ display:none; }

.snv ol{ list-style:none; margin:0; padding:6px 0; display:flex; flex-direction:column; align-items:stretch; }
.snv li{ display:block; }
.snv a{ position:relative; display:flex; align-items:center; justify-content:flex-end; gap:14px; min-height:24px; min-width:40px;
  padding:0 10px 0 12px; box-sizing:border-box; color:var(--quiet); text-decoration:none;
  font:400 13px/1.25 var(--font); letter-spacing:.005em; white-space:nowrap; transition:color .18s ease; }
/* each tick is as long as its chapter is, relative to the longest (the script sets --w) */
.snv a i{ flex:none; display:block; width:var(--w, 12px); height:1px; background:currentColor; transition:height .18s ease; }
/* on a phone the ticks keep to the gutter, clear of the work's right edge: 4 px of padding, and the ticks at two thirds of
   their length (founder, 8 Nov) */
@media (max-width:767px){ .snv a{ padding-right:4px; } .snv a i{ width:calc(var(--w, 12px) * 2 / 3); } }
.snv a[aria-current]{ color:var(--ink); }
.snv a[aria-current] i{ height:2px; }
/* The index says where the reader is, not how far: the current chapter's tick is filled in ink and the others rest in quiet, at full
   strength, so each tick reads at better than 3:1 on the page's ground in both color modes. (Until R1.9.37 the homepage's resting ticks
   stood at 55 percent, a leftover of an earlier design which a later rule meant to undo and did not; that read at about 2.3:1.)
   Progress within a section is the header's rule alone, so the page never shows two progress signals for one section. */
.snv:hover a, .snv:focus-within a, .snv.peek a{ color:var(--quiet); }
.snv:hover a[aria-current], .snv:focus-within a[aria-current], .snv.peek a[aria-current]{ color:var(--ink); }
.snv a:focus-visible{ outline:1px solid currentColor; outline-offset:-1px; }
[data-snv-t]:focus{ outline:none; }
@media (prefers-reduced-motion:reduce){ .snv, .snv.out, .snv a, .snv a i{ transition:none; } }

/* touch screens carry the same ticks: tap a tick to jump; press, hold, and slide to scrub */
@media (hover:none), (pointer:coarse){
  .snv{ display:block; }
  .snv a{ -webkit-touch-callout:none; -webkit-user-select:none; user-select:none; -webkit-tap-highlight-color:transparent; min-height:30px; }
}

/* the names. Rest, and the way back: ease in, last name first (the script numbers the names with --i and counts them with --n) */
.snv a span, .snv:hover a span, .snv:focus-within a span, .snv.peek a span, .snv.scrub a span, .snv.closing a span{
  position:absolute; right:calc(10px + var(--w, 12px) + 8px); top:50%; width:auto; height:28px; margin:-14px 0 0; overflow:visible; clip:auto; clip-path:none;
  display:flex; align-items:center; padding:0 8px; background:var(--ground); white-space:nowrap; pointer-events:none; animation:none;
  opacity:0; transform:translate3d(8px, 0, 0);
  transition:opacity .2s cubic-bezier(.5, 0, .75, 0) calc((var(--n, 6) - var(--i, 0)) * 16ms), transform .24s cubic-bezier(.5, 0, .75, 0) calc((var(--n, 6) - var(--i, 0)) * 16ms), color .18s ease, font-size .3s ease; }
/* open: ease out, first name first */
.snv.peek a span, .snv.scrub a span{ opacity:1; transform:none; pointer-events:auto;
  transition:opacity .3s cubic-bezier(.22, 1, .36, 1) calc(var(--i, 0) * 28ms), transform .46s cubic-bezier(.22, 1, .36, 1) calc(var(--i, 0) * 28ms), color .18s ease; }
@media (hover:hover) and (pointer:fine){
  .snv:hover a span, .snv:focus-within a span{ opacity:1; transform:none; pointer-events:auto;
    transition:opacity .3s cubic-bezier(.22, 1, .36, 1) calc(var(--i, 0) * 28ms), transform .46s cubic-bezier(.22, 1, .36, 1) calc(var(--i, 0) * 28ms), color .18s ease; }
  /* a steady hover zone the width of the longest name, so the cursor can travel across the names without the list closing */
  .snv:hover ol, .snv:focus-within ol, .snv.peek ol{ padding:6px 0 6px 180px; }
}
.snv:not(:hover) ol, .snv.scrub ol, .snv.closing ol{ padding:6px 0; }

/* arrival: one name; it fades back without a stagger */
.snv.flash a.lbl span{ opacity:1; transform:none; color:var(--ink);
  transition:opacity .3s cubic-bezier(.22, 1, .36, 1), transform .46s cubic-bezier(.22, 1, .36, 1), color .18s ease; }
.snv.flash.fo a.lbl span{ opacity:0; transform:translate3d(8px, 0, 0);
  transition:opacity .2s cubic-bezier(.5, 0, .75, 0), transform .24s cubic-bezier(.5, 0, .75, 0); }
.snv.flash a{ color:var(--quiet); } .snv.flash a[aria-current]{ color:var(--ink); }

/* while the names slide back the list keeps its open colors, so they never change color mid-fade */
.snv.closing a, .snv.scrub a{ color:var(--quiet); }
.snv.closing a[aria-current], .snv.scrub a[aria-current]{ color:var(--ink); }
.snv.scrub a.hot i{ height:2px; }

@media (prefers-reduced-motion:reduce){ .snv a span{ transition:none !important; transform:none !important; } }
/* the introduction: each name's openness comes from the scroll (see the script), so no transitions here */
.snv.intro a{ color:var(--quiet); }
.snv.intro a span{ opacity:var(--o, 0); transform:translate3d(calc((1 - var(--o, 0)) * 10px), 0, 0); transition:color .18s ease, font-size .3s ease; }

/* where you are: the current section's name and tick in pink, its name a step larger, whenever the names show.
   Where you point (hover, or the tick under your finger) reads in full ink. */
.snv.intro a[aria-current], .snv.flash a[aria-current], .snv.peek a[aria-current], .snv.scrub a[aria-current], .snv.closing a[aria-current]{ color:var(--snv-hl); }
.snv.flash a.lbl span{ color:var(--snv-hl); }
.snv a[aria-current] span{ font-size:15px; letter-spacing:-.005em; }
.snv a:hover, .snv:hover a:hover, .snv a:focus-visible, .snv.scrub a.hot{ color:var(--ink); }
.snv.scrub a.hot[aria-current]{ color:var(--snv-hl); }
@media (hover:hover) and (pointer:fine){ .snv:hover a[aria-current], .snv:focus-within a[aria-current]{ color:var(--snv-hl); } .snv:hover a[aria-current]:hover{ color:var(--snv-hl); } }
@media (prefers-reduced-motion:reduce){ .snv.intro a span{ transform:none !important; } }
/* At rest the index is ticks only, the current one in ink. The current chapter's name shows while the reader scrolls, where the
   right margin can hold it, and the other names arrive when reached for, as above. */
.snv a{ color:var(--quiet); } .snv a[aria-current]{ color:var(--ink); }
.snv.live a[aria-current] span{ opacity:1; transform:none; color:var(--ink); }
@media not all and (min-width:1280px) and (hover:hover) and (pointer:fine){ .snv.live a[aria-current] span{ opacity:0; } }
/* where the index would sit over the footer it steps aside (the script also takes it out of the tab order and the accessibility tree) */
.snv.aside{ visibility:hidden; opacity:0; pointer-events:none; }
@media (prefers-reduced-motion:reduce){ .snv a span, .snv.live a span{ transition:none !important; } }
/* a finger has no hover, and iOS keeps :hover on the tick you tapped: the hover state must never show on touch */
@media (hover:none), (pointer:coarse){
  .snv:hover:not(.scrub):not(.peek):not(.closing):not(.flash) a, .snv:focus-within:not(.scrub):not(.peek):not(.closing):not(.flash) a{ color:var(--quiet); }
  .snv:hover:not(.scrub):not(.peek):not(.closing):not(.flash) a[aria-current], .snv:focus-within:not(.scrub):not(.peek):not(.closing):not(.flash) a[aria-current]{ color:var(--ink); }
}
/* nothing animates while the page loads: the names arrive hidden, and motion starts two frames after the script runs */
.snv:not(.ready) a span{ transition:none !important; }
/* Escape puts away names which hover or focus opened, without the reader moving the pointer or the focus (WCAG 1.4.13); they return when the
   reader reaches for the list again (the script sets and clears .shut) */
.snv.shut a span{ opacity:0 !important; pointer-events:none !important; }

/* Two page options, both for pages where the work fills the screen.
   .inpin, set by the page's own script while the index, or the name it would show, lies over a picture, a film, a device, or a
   drawing: the index keeps to ticks there, so no name lands on the work unless the reader reaches for it. */
.snv.inpin:not(:hover):not(:focus-within):not(.scrub):not(.peek) a span{ opacity:0 !important; }
@media (hover:none), (pointer:coarse){ .snv.inpin:not(.scrub):not(.peek) a span{ opacity:0 !important; } }
/* data-rest on the nav: on touch the index keeps the reader company while they move and steps aside once they rest, so it never
   holds a place over the work */
@media (hover:none), (pointer:coarse){ .snv.rest:not(:focus-within){ opacity:0; pointer-events:none; transition:opacity .45s ease; } }
