/* ═══════════════════════════════════════════════════════════════════════════
   CORVEXAL — THE SCROLLBAR

   Kevin: *"still this ugly-ass scroll bar"*, and what he asked for instead:
   *"a semi-transparent pill on the right that disappears when stagnant and
   appears on hover."*

   ═══ THE THUMB IS MOVED BY CSS, NOT BY JAVASCRIPT ═════════════════════════

   `animation-timeline: scroll(root block)` binds a keyframe to the document
   scroller, so the pill's position is computed by the compositor and never
   by a handler. That matters here more than usual: gate.sh check 6 forbids
   every scroll, wheel and touchmove listener in this project, and it is right
   to — a handler that runs ahead of paint is how a page starts to feel heavy.
   The first version of this file used a passive `wheel` listener and a
   requestAnimationFrame loop. The gate failed it, and the gate was correct;
   the timeline version has no listener at all and no main-thread work.

   It is the same mechanism the sticky stack already uses (`view()` rather
   than `scroll()`), so this file makes no new assumption about support. Where
   the timeline is unsupported, scrollbar.js never adds the `sbar-on` class,
   the native scrollbar is never hidden, and nothing below applies.

   ═══ WHY IT IS 6px AND ITS TARGET IS 22px ═════════════════════════════════

   A 6px drag target is unpleasant regardless of what the specification
   permits. The pill is what you see; the invisible column beside it is what
   you hit.

   ═══ ONLY THE DOCUMENT SCROLLER ══════════════════════════════════════════

   `scrollbar-width: none` is scoped to <html> and nothing else. Inner scroll
   containers — the licence table's .spec-wrap, the code blocks — keep their
   native bars, because there the scrollbar is the only signal that the region
   scrolls at all.
   ═══════════════════════════════════════════════════════════════════════════ */

/* Every duration, easing and dimension. This block declares nothing but
   custom properties, which is what lets tools/css-code.cjs blank it before
   checks 1, 2 and 9 read the file — the sanctioned way to write a raw value
   in this project is to write it once, here, and never again. */
:root {
  --sbar-w:      6px;
  --sbar-w-on:   9px;
  --sbar-hit:    22px;
  /* THE RESTING HEIGHT, AND IT IS NOT DECORATION. scrollbar.js overwrites
     this on :root with the measured value, so at runtime it is always the
     real one. It is declared here because tools/token-audit.mjs pointed out
     that if the script never runs — no hover pointer, no scroll-timeline
     support, a parse error upstream — then var(--sbar-h) resolves to nothing,
     calc(100vh - nothing) is invalid, and the ENTIRE transform declaration in
     the keyframe is dropped rather than falling back. A thumb with no travel.
     An undefined token does not degrade; it deletes. */
  --sbar-h:      40px;
  --sbar-inset:  6px;
  --sbar-fade:   260ms;
  --sbar-grow:   160ms;
  --sbar-ease:   cubic-bezier(.4, 0, .2, 1);
  --sbar-rest:   rgba(18, 24, 32, .28);
  --sbar-hot:    rgba(18, 24, 32, .46);
  --sbar-rest-i: rgba(244, 241, 234, .30);
  --sbar-hot-i:  rgba(244, 241, 234, .52);
}

html.sbar-on {
  scrollbar-width: none;
  -ms-overflow-style: none;
}
html.sbar-on::-webkit-scrollbar { width: 0; height: 0; }

.sbar {
  position: fixed;
  top: 0; right: 0; bottom: 0;
  width: var(--sbar-hit);
  /* Above the content, above the nav's own 100, because a fixed nav would
     otherwise sit over the top of the track. */
  z-index: 120;
  pointer-events: none;
  opacity: 0;
  transition: opacity var(--sbar-fade) var(--sbar-ease);
}

/* Three independent reasons to be visible, one class each, so that releasing
   the thumb mid-scroll cannot make it vanish under the cursor. */
.sbar.is-live,
.sbar.is-near,
.sbar.is-drag { opacity: 1; }

/* translate3d, not translateY, and the budget is right to insist: the 2D
   form can be handled without a compositor layer, and a thumb that repaints
   on the main thread every frame is exactly the cost this file exists to
   avoid. tools/parallax-budget.mjs fails the build on the 2D form. */
@keyframes sbar-travel {
  from { transform: translate3d(0, 0, 0); }
  to   { transform: translate3d(0, calc(100vh - var(--sbar-h, 40px)), 0); }
}

.sbar__thumb {
  position: absolute;
  top: 0;
  right: var(--sbar-inset);
  width: var(--sbar-w);
  height: var(--sbar-h, 40px);
  border-radius: 100px;
  background: var(--sbar-rest);
  pointer-events: auto;
  transition: background var(--sbar-grow) linear,
              width var(--sbar-grow) var(--sbar-ease),
              right var(--sbar-grow) var(--sbar-ease);
  animation: sbar-travel linear both;
  animation-timeline: scroll(root block);
}

.sbar:hover .sbar__thumb,
.sbar.is-drag .sbar__thumb {
  background: var(--sbar-hot);
  width: var(--sbar-w-on);
  right: calc(var(--sbar-inset) - 1px);   /* grows about its own centre */
}

/* The ground under the pill decides its colour. This site changes ground
   eight times down a single page — cream, sand, sheet, ink — so one value is
   wrong for half of it and no media query can see the difference. The class
   is set from JS by asking what is actually painted behind the thumb. */
.sbar.on-ink .sbar__thumb { background: var(--sbar-rest-i); }
.sbar.on-ink:hover .sbar__thumb,
.sbar.on-ink.is-drag .sbar__thumb { background: var(--sbar-hot-i); }

/* A pointer that cannot hover has no way to summon this and no need of it:
   touch scrolls the content directly and every mobile OS already draws its
   own transient indicator. */
@media (hover: none) {
  .sbar { display: none; }
  html.sbar-on { scrollbar-width: auto; -ms-overflow-style: auto; }
  html.sbar-on::-webkit-scrollbar { width: initial; height: initial; }
}

@media (prefers-reduced-motion: reduce) {
  .sbar, .sbar__thumb { transition: none; }
}

/* ══ THE INNER SCROLLBARS ══════════════════════════════════════════════════
   Kevin: "the scroll for the different things, it's a little outdated.
   Everything else is high-tech, and this is the scroll... it should be just a
   bar without the white frame around it."

   The PAGE scrollbar is the custom overlay above. These are the other ones —
   the station rail, the spec tables, the code panels, the control plane on a
   phone — and they were still the platform default: a light track, a grey
   thumb, and a hairline border around both. On a burgundy wall or a dark code
   plate that track reads as a strip of somebody else's UI.

   So the track goes transparent and the thumb becomes a rounded bar in the
   ink already in use, with no border at all. currentColor is deliberate: the
   same rule then works on cream, on sage, on burgundy and on the dark plates
   without a variant per room, because every one of those already sets a text
   colour that contrasts with itself.

   scrollbar-width: thin covers Firefox, which has no ::-webkit- pseudo.    */

.rail__track, .spec-wrap, .diag, .term__body, .g-grid, .gp__gridwrap,
.web__branch, [data-scroll], .stations {
  scrollbar-width: thin;
  scrollbar-color: color-mix(in srgb, currentColor 34%, transparent) transparent;
}
.rail__track::-webkit-scrollbar,
.spec-wrap::-webkit-scrollbar,
.diag::-webkit-scrollbar,
.term__body::-webkit-scrollbar,
.g-grid::-webkit-scrollbar,
.gp__gridwrap::-webkit-scrollbar,
.web__branch::-webkit-scrollbar,
[data-scroll]::-webkit-scrollbar,
.stations::-webkit-scrollbar { width: 9px; height: 9px; }

.rail__track::-webkit-scrollbar-track,
.spec-wrap::-webkit-scrollbar-track,
.diag::-webkit-scrollbar-track,
.term__body::-webkit-scrollbar-track,
.g-grid::-webkit-scrollbar-track,
.gp__gridwrap::-webkit-scrollbar-track,
.web__branch::-webkit-scrollbar-track,
[data-scroll]::-webkit-scrollbar-track,
.stations::-webkit-scrollbar-track { background: transparent; border: 0; }

.rail__track::-webkit-scrollbar-thumb,
.spec-wrap::-webkit-scrollbar-thumb,
.diag::-webkit-scrollbar-thumb,
.term__body::-webkit-scrollbar-thumb,
.g-grid::-webkit-scrollbar-thumb,
.gp__gridwrap::-webkit-scrollbar-thumb,
.web__branch::-webkit-scrollbar-thumb,
[data-scroll]::-webkit-scrollbar-thumb,
.stations::-webkit-scrollbar-thumb {
  background: color-mix(in srgb, currentColor 30%, transparent);
  border-radius: 100px;
  border: 0;
}
.rail__track::-webkit-scrollbar-thumb:hover,
.spec-wrap::-webkit-scrollbar-thumb:hover,
.diag::-webkit-scrollbar-thumb:hover,
.term__body::-webkit-scrollbar-thumb:hover,
.g-grid::-webkit-scrollbar-thumb:hover,
.gp__gridwrap::-webkit-scrollbar-thumb:hover,
.web__branch::-webkit-scrollbar-thumb:hover,
[data-scroll]::-webkit-scrollbar-thumb:hover,
.stations::-webkit-scrollbar-thumb:hover {
  background: color-mix(in srgb, currentColor 52%, transparent);
}
/* the corner where two bars meet is its own element and defaults to the
   track colour, which puts a small pale square back in the corner */
::-webkit-scrollbar-corner { background: transparent; }
