/* TOC scroll-spy: a numbered side index built from an article's headings. The entry for the section you're
   reading lights up, the index scrolls itself to keep that entry in view, and clicking an entry glides the page
   to its heading (100px clear of the top). Under a breakpoint it folds into a sticky bar that drops the list.

   Markup (part.js fills the list):
     <aside class="tocs" data-tocs data-tocs-source="#doc">
       <button class="tocs__head" type="button"><span class="tocs__title">Contents</span>
         <span class="tocs__now"></span><span class="tocs__count"></span><span class="tocs__chev" aria-hidden="true"></span></button>
       <nav class="tocs__list" aria-label="Contents"></nav>
     </aside>
     <article id="doc"> <h2>1. First section</h2> ... </article>
   .tocs__now (optional) shows the current entry in the folded bar; .tocs__count gets "[14]". */
.tocs {
  --tocs-ink: #1d1d1b;
  --tocs-ink-dim: rgba(29, 29, 27, .72);   /* resting entries (Heron: ink at 72%) */
  --tocs-num: rgba(29, 29, 27, .72);
  --tocs-line: rgba(29, 29, 27, .22);      /* dashed rule between entries */
  --tocs-line-hover: rgba(29, 29, 27, .8); /* the rule under a hovered entry */
  --tocs-bg: #f2f1ec;                      /* folded bar + dropped list ground */
  --tocs-bar-bg: rgba(29, 29, 27, .04);
  --tocs-dash: 5px;                        /* dash length */
  --tocs-gap-dash: 4px;                    /* gap between dashes */
  --tocs-dur: .4s;                         /* colour, square, rule (Heron .4s) */
  --tocs-pad: 17px 42px 17px 20px;         /* entry padding (Heron 2rem 5rem 2rem 2.4rem at 1440) */
  --tocs-dot: 6px;                         /* active square (Heron .6rem) */
  --tocs-dot-right: 25px;
  --tocs-top: 0px;                         /* sticky offset of the index (a fixed header's height) */
  --tocs-drop-max: 50vh;                   /* folded list height cap (Heron 50vh) */

  position: sticky;
  top: var(--tocs-top);
  display: flex;
  flex-direction: column;
  min-width: 0;
  color: var(--tocs-ink);
}
.tocs__head {
  all: unset;
  box-sizing: border-box;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 20px;
  border-bottom: 1px solid var(--tocs-line);
  cursor: default;
}
.tocs__title { font-weight: 650; font-size: 20px; line-height: 1.1; letter-spacing: -.02em; text-transform: uppercase; }
.tocs__count, .tocs__num { font: 500 11px/1.2 ui-monospace, SFMono-Regular, Menlo, monospace; letter-spacing: .02em; }
.tocs__count { color: var(--tocs-num); margin-left: auto; }
.tocs__now, .tocs__chev { display: none; }

.tocs__list {
  overflow: auto;
  overscroll-behavior: contain;
  scrollbar-width: thin;
}
.tocs__list ol { list-style: none; margin: 0; padding: 0; }
.tocs__link {
  position: relative;
  display: flex;
  align-items: baseline;
  gap: 10px;
  padding: var(--tocs-pad);
  color: var(--tocs-ink-dim);
  text-decoration: none;
  font-size: 14px;
  line-height: 1.35;
  transition: color var(--tocs-dur);
  /* the dashed rule (Heron draws it with a dashed SVG border) */
  background: repeating-linear-gradient(90deg, var(--tocs-line) 0 var(--tocs-dash), transparent var(--tocs-dash) calc(var(--tocs-dash) + var(--tocs-gap-dash))) left bottom / 100% 1px no-repeat;
}
.tocs__link::after {   /* darker rule fades in under the hovered entry */
  content: "";
  position: absolute;
  left: 0; right: 0; bottom: 0;
  height: 1px;
  background: repeating-linear-gradient(90deg, var(--tocs-line-hover) 0 var(--tocs-dash), transparent var(--tocs-dash) calc(var(--tocs-dash) + var(--tocs-gap-dash)));
  opacity: 0;
  transition: opacity var(--tocs-dur);
}
.tocs__num { flex: none; color: var(--tocs-num); transition: color var(--tocs-dur); }
.tocs__txt { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.tocs__dot {   /* the active square (Heron: opacity 0 + scale .9 -> 1, .4s) */
  position: absolute;
  right: var(--tocs-dot-right);
  top: 50%;
  width: var(--tocs-dot);
  height: var(--tocs-dot);
  margin-top: calc(var(--tocs-dot) / -2);
  background: var(--tocs-ink);
  opacity: 0;
  transform: scale(.9);
  transition: opacity var(--tocs-dur), transform var(--tocs-dur);
}
.tocs__link:hover, .tocs__link:focus-visible, .tocs__link.is-active { color: var(--tocs-ink); }
.tocs__link:hover .tocs__num, .tocs__link.is-active .tocs__num { color: var(--tocs-ink); }
.tocs__link:hover::after { opacity: 1; }
.tocs__link.is-active .tocs__dot { opacity: 1; transform: none; }
.tocs__link:focus-visible { outline: 2px solid var(--tocs-ink); outline-offset: -2px; }
/* long titles: one line + a tooltip with the full title on hover (Heron .has-tooltip) */
.tocs__link.has-tip::before {
  content: attr(data-full);
  position: absolute;
  z-index: 3;
  left: 50%;
  bottom: calc(100% - 6px);
  width: max-content;
  max-width: min(320px, 90%);
  transform: translateX(-50%);
  padding: 9px 12px;
  background: var(--tocs-ink);
  color: var(--tocs-bg);
  font-size: 13px;
  line-height: 1.35;
  white-space: normal;
  opacity: 0;
  pointer-events: none;
  transition: opacity var(--tocs-dur);
}
.tocs__link.has-tip:hover::before { opacity: 1; }

/* folded (part.js adds .is-folded under data-tocs-fold px): a sticky bar that drops the list */
.tocs.is-folded { z-index: 20; background: var(--tocs-bg); }
.tocs.is-folded .tocs__head { cursor: pointer; padding: 13px 16px; background: var(--tocs-bar-bg); border-bottom: 1px solid var(--tocs-line); }
.tocs.is-folded .tocs__title { font-size: 14px; }
.tocs.is-folded .tocs__now { display: block; min-width: 0; flex: 1; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 13px; color: var(--tocs-ink-dim); }
.tocs.is-folded .tocs__count { margin-left: 0; }
.tocs.is-folded .tocs__chev {
  display: block; flex: none; width: 8px; height: 8px; margin: -4px 2px 0 4px;
  border-right: 1.5px solid currentColor; border-bottom: 1.5px solid currentColor;
  transform: rotate(45deg); transition: transform var(--tocs-dur), margin var(--tocs-dur);
}
.tocs.is-folded.is-dropped .tocs__chev { transform: rotate(225deg); margin-top: 4px; }
.tocs.is-folded .tocs__head:focus-visible { outline: 2px solid var(--tocs-ink); outline-offset: -2px; }
.tocs.is-folded .tocs__list {
  position: absolute;
  top: 100%;
  left: 0;
  right: 0;
  max-height: var(--tocs-drop-max);
  background: var(--tocs-bg);
  border-bottom: 1px solid var(--tocs-line);
}
.tocs.is-folded .tocs__list[hidden] { display: none; }
.tocs.is-folded .tocs__link { padding: 14px 16px; }
.tocs.is-folded .tocs__dot { right: 16px; }
.tocs.is-folded .tocs__link.has-tip::before { display: none; }

@media (prefers-reduced-motion: reduce) {
  .tocs { --tocs-dur: 0s; }
}
