/* The page index ("on this page"), in the wireframe language.
   ============================================================
   Loaded by layouts/base.njk wherever a page sets `toc: true` — the same
   flag that emits the markup in layouts/page.njk and loads js/toc.js, so a
   page cannot have the index without its sheet and its hand.

   It has its own prefix for the reason docs/WIREFRAME-LANGUAGE.md §1 gives:
   the index appears on twelve pages that belong to three different families
   — eight reading pages carry `wp`, the four implementation examples carry
   examples.css and no palette at all — and none of them should have to load
   a sheet it has no other use for to get a drawn box. Same shape as
   next-paths.css, which is the band at the foot of a page for the same
   reason. The values are the language's, restated; §1 is where they live.

   It is a plate at both widths — paper, a drawn edge, a hard offset cast —
   because it is one component and the reader meets it in one place or the
   other, never both. A margin rule above the breakpoint and a box below it
   would be two designs sharing a name, and the width at which somebody reads
   a page is not a fact about what the index *is*. It is also what keeps the
   ink honest: the edge is generated once, at load, and is on screen from
   then on, rather than being drawn for a width and hidden at another.

   What it is not, at either width, is a tinted well with a soft radius. */

.page-toc {
  --pi-ink: #55555f;
  --pi-faint: #bab7b0;
  --pi-paper: #fffefb;
  --pi-cast: rgba(60, 50, 40, 0.16);
  --pi-accent: #5a5ad1;
  --pi-soft: #3f3f46;
  --pi-strong: #111118;
  --pi-mono: "Roboto Mono", ui-monospace, Menlo, Consolas, monospace;
}
html.dark-mode .page-toc {
  --pi-ink: #a8a8b4;
  --pi-faint: #4b4b5a;
  --pi-paper: #15151e;
  --pi-cast: rgba(226, 226, 255, 0.09);
  --pi-accent: #8a8aff;
  --pi-soft: #b3b3bc;
  --pi-strong: #f1f1f5;
}

/* ---- whether there is an index at all ----
   The entries are built by js/toc.js from the article's own headings, so
   until it has run there is nothing in the box — and a heading over an empty
   plate is the drawn version of a button that does nothing
   (WIREFRAME-LANGUAGE.md §2.3). The index is therefore hidden until the
   script has built it and the article runs the full width, which is what a
   page without an index looks like anyway. The script sets the class after
   appending the list and before inking, so the box has a size to be drawn
   at; it never sets it on a page whose headings it found none of. */
.page-toc { display: none; }
html.pi-on .page-toc { display: block; }

/* ---- the layout the index sits in ----
   Content left, index right, the index sticky beside it. */
.page-with-toc { display: block; }
html.pi-on .page-with-toc {
  display: grid;
  grid-template-areas: "content toc";
  /* 16rem rather than the 14.5 the margin rule used, because the plate spends
     about 45px of it on padding and its own edge and the entries would
     otherwise lose that much room. The gap gives the 1.5rem back, so the
     index and the gutter together occupy exactly the 18rem they did before
     and the article's measure does not move — the plate has its own edge to
     separate it, which a bare margin rule did not. */
  grid-template-columns: minmax(0, 1fr) 16rem;
  gap: 0 2rem;
  align-items: start;
}
.page-with-toc > .page-content { grid-area: content; }

/* The plate. Sticky beside the article, in the flow of the page below the
   breakpoint, and the same box in both places.

   `position` is what carries the ink: hand-ink puts an absolutely positioned
   SVG inside this element, so the element has to be its containing block.
   Sticky is one; static is not, and a static box would resolve the ink
   against whatever is positioned above it and land the edge somewhere else
   on the page entirely (WIREFRAME-LANGUAGE.md §2.1). That is why the narrow
   form below sets `relative` rather than letting it fall back to static.

   The plate itself never scrolls, and cannot: the edge overshoots the box by
   seven pixels at every corner and a scroll container clips exactly that.
   Where an index is too long for the window — /terms has eighteen entries,
   /privacy sixteen, and both pass the bottom of a short laptop screen — the
   list inside the plate scrolls and the plate stays whole. */
.page-toc {
  grid-area: toc;
  position: sticky;
  top: calc(var(--banner-h) + 32px);
  background: var(--pi-paper);
  border: 1.5px solid var(--pi-ink);
  border-radius: 5px;
  box-shadow: 3px 3px 0 var(--pi-cast);
  padding: 1rem 1.1rem 0.9rem;
}
/* What the window leaves, less the banner, the plate's own padding and edge,
   the label above the list, and 32px of air top and bottom. */
.page-toc > nav {
  max-height: calc(100vh - var(--banner-h) - 64px - 4.3rem);
  overflow-y: auto;
  overscroll-behavior: contain;
}

/* Its label, which is a label: mono, uppercase, tracked — the eyebrow every
   other sheet puts over a block. In ink rather than the accent, because the
   accent has a job inside this box already: it marks the section the reader
   is in. Two accents in one small box and neither is pointing at anything. */
.page-toc-title {
  font-family: var(--pi-mono);
  font-weight: 500;
  font-size: 0.7rem;
  letter-spacing: 0.22em;
  text-transform: uppercase;
  color: var(--pi-strong);
  margin: 0 0 12px;
}

.page-toc ul { list-style: none; margin: 0; padding: 0; }
.page-toc li { margin: 0; }

/* Mono, because every one of these is a heading restated and every heading
   on the page is mono (site.css). An index set in the body face reads as
   prose about the page rather than as the page's own outline. Smaller than
   the headings it names, and a little tighter, because mono at this size in
   a 14.5rem column is close to its limit — the tracking is what buys the
   longest entry its second line rather than its third. */
.page-toc a {
  display: block;
  padding: 4px 0;
  font-family: var(--pi-mono);
  font-weight: 400;
  font-size: 0.72rem;
  line-height: 1.55;
  letter-spacing: -0.02em;
  color: var(--pi-soft);
  text-decoration: none;
}
.page-toc li.toc-sub a { padding-left: 16px; }
.page-toc a:hover { color: var(--pi-accent); }

/* The section you are in. The accent points at it and nothing else in the
   box moves — no rule appears beside it, no row fills. */
.page-toc a.toc-active {
  color: var(--pi-accent);
  font-weight: 500;
}
.page-toc a:focus-visible {
  outline: 2px solid var(--pi-accent);
  outline-offset: 2px;
}

/* ---- above the article ----
   The grid unstacks and the same plate arrives in the flow of the page. Only
   three things change: it stops sticking, it takes the margins a block in a
   column needs, and it keeps a containing block for its ink — `relative`
   rather than the static it would otherwise fall back to, with `top` reset
   so the sticky offset above does not slide it down the page. */
@media (max-width: 1100px) {
  html.pi-on .page-with-toc { display: block; }
  .page-toc {
    position: relative;
    top: auto;
    padding: 1rem 1.2rem 0.95rem;
    margin: 1.7rem 0 1.5rem;
  }
  /* Nothing is stuck here, so nothing has a window's worth of room to fit
     into: the index is as tall as it is and the page scrolls past it. */
  .page-toc > nav { max-height: none; overflow: visible; }
}

/* ---- the drawn edge ----
   js/toc.js replaces the plate's border with generated strokes
   (js/hand-ink.js) and sets html.pi-ink, which is what takes that border
   off. A reader with no JavaScript keeps the ruled box, which is the same
   design a shade quieter.

   The ink goes on solid, at load, and never animates: the index is on the
   page when the page is, so as far as the reader is concerned it has never
   come into being (WIREFRAME-LANGUAGE.md §3). There is no reveal class here
   and nothing holds a stroke back. Crossing the breakpoint changes the box's
   size, and hand-ink's own ResizeObserver redraws the same seeded geometry
   at the new size — the shape of the line, not where the line sits. */
html.pi-ink .page-toc.hi-box {
  border-color: transparent;
  /* The generated outline has square corners, and a rounded fill under it
     shows through where the strokes cross. */
  border-radius: 0;
}
.page-toc > .hi-ink {
  position: absolute;
  left: -7px;
  top: -7px;
  overflow: visible;
  pointer-events: none;
  fill: none;
  z-index: 1;
}
.page-toc > .hi-ink path {
  stroke: var(--pi-ink);
  stroke-width: 1.15;
  stroke-linecap: round;
  vector-effect: non-scaling-stroke;
}
/* The second pass over an edge is lighter, as a real second pass is. */
.page-toc > .hi-ink path.hi-p2 { stroke-width: 0.85; stroke-opacity: 0.5; }

