/* =====================================================================
   Trail
   A contents rail for long pages, measured in reading time, and the
   reading line across the page. Reads exilinar III tokens only:
   paper, raised, ink, ink-2 to ink-4, a5, a35, line-4, accent-glyph,
   e2, px, r-row, font, fs-12, lh-12, tracking.

   Host rules:
   1. The rail's container needs a z-index above the text, or text
      faded by Dim, which gets its own stacking context, paints over
      the panel and the settings.
   2. Give the rail a sticky container; Trail keeps its length inside
      the room below the sticky top.

   Collapsed, one tick per equal share of the reading time, a longer
   tick where a section starts, ticks behind the dot one step darker,
   and the tick below the dot filling as the dot moves towards it
   (sweep). Open, the tick beside each title is as long as that
   section's reading time (bars), a long list fades at the ends that
   have more (fade), and with the pointer on the collapsed rail the
   section under it is named (skim).
   Every tick is a base in the unread colour with an ::after in the
   read colour, scaled by --f, 0 to 1.
   JS writes: --x (0 closed, 1 open), --hc, --ho, --to, --trail-row,
   --trail-open-w, --trail-closed-w, per row --yc --yo (and --len --dur
   on heading rows), --f on the current row and the row being swept,
   --ft --fb on the list, data-read, data-hl, data-skimming, data-open,
   data-ready.
   ===================================================================== */

/* the React wrapper: the landmark and the outline rendered on the server */
.trail-host{ display: block; position: relative; width: var(--trail-width, 26px) }
.trail__ssr{
  position: absolute; width: 1px; height: 1px; margin: -1px; padding: 0;
  overflow: hidden; clip-path: inset(50%); white-space: nowrap; border: 0;
}

.trail{
  display: block;
  --trail-row: 8px;             /* tick pitch; integer so 1px ticks land on whole pixels */
  --trail-row-open: 24px;       /* open row height, the WCAG 2.2 minimum target size */
  --trail-head-h: 24px;         /* open panel: space for the time left line */
  --trail-tick: 1px;
  --trail-tick-active: 1.5px;
  --trail-tick-h2: 12px;        /* collapsed: tick length shows the heading level */
  --trail-tick-h3: 8px;
  --trail-tick-body: 4px;
  --trail-tick-open: .55;       /* heading tick scale when open, without bars */
  --trail-bar-min: 2;           /* open, with bars: tick length is reading time, px */
  --trail-bar-max: 24;
  --trail-bar-h: 2px;           /* bar thickness when open */
  --trail-tick-x: 12px;         /* left edge of the ticks, closed and open */
  --trail-tick-x-open: 17px;
  --trail-dot: 5px;
  --trail-dot-x: 4.5px;         /* centre of the dot lane, closed and open */
  --trail-dot-x-open: 10.5px;
  --trail-label-x: 32px;
  --trail-width: 26px;          /* footprint in the layout */
  --trail-pad: 10px;
  --trail-bottom: 24px;         /* space kept below the rail */
  --trail-fade: 48px;           /* longest edge fade on a scrolling list, two rows */
  --trail-skim-h: 24px;
  --trail-skim-gap: 6px;

  --trail-body: var(--line-4);          /* unread, between headings */
  --trail-body-read: var(--a35);
  --trail-head: var(--a35);             /* unread heading */
  --trail-head-read: var(--ink-4);
  --trail-current: var(--ink);
  --trail-dot-color: var(--accent-glyph);

  --x: 0;
  --hc: 200px; --ho: 200px; --to: 200px;
  --trail-open-w: 240px;
  --tx: calc(var(--trail-tick-x) + (var(--trail-tick-x-open) - var(--trail-tick-x)) * var(--x));
  --ts: calc(1 - (1 - var(--trail-tick-open)) * var(--x));

  position: relative;
  width: var(--trail-width);
  height: var(--hc);
  font: 400 var(--fs-12)/var(--lh-12) var(--font);
  letter-spacing: var(--tracking);
}
.trail[data-bars]{ --trail-label-x: 50px }   /* room for the longest bar */
@media (prefers-color-scheme:dark){ :root:not([data-theme="light"]) .trail{ --trail-head-read: var(--ink-3) } }
:root[data-theme="dark"] .trail{ --trail-head-read: var(--ink-3) }

.trail__panel{
  position: absolute; left: 0; top: 0; z-index: 20;
  width: calc(var(--trail-closed-w, var(--trail-width)) + (var(--trail-open-w) - var(--trail-closed-w, var(--trail-width))) * var(--x));
  height: calc(var(--hc) + (var(--ho) - var(--hc)) * var(--x));
  cursor: default;
}
.trail__bg{
  position: absolute; inset: 0;
  background: var(--raised);
  border-radius: var(--r-row);
  box-shadow: inset 0 0 0 var(--px) var(--line-4), var(--e2);
  opacity: var(--x);
  pointer-events: none;
}
.trail__head{
  position: absolute; left: var(--trail-label-x); right: 8px; top: calc(var(--trail-pad) - 4px);
  height: 24px; display: flex; align-items: center; justify-content: space-between; gap: 8px;
  opacity: clamp(0, calc(var(--x) * 2 - 1), 1);
}
.trail:not([data-open]) .trail__head{ pointer-events: none }
.trail__meta{
  font: 450 11px/16px var(--font); letter-spacing: .01em;
  color: var(--ink-3);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}
.trail__gear{
  appearance: none; border: 0; background: none; padding: 0;
  width: 24px; height: 24px; border-radius: var(--r-press); display: grid; place-items: center;
  color: var(--ink-4); cursor: default; transition: color 120ms, background-color 120ms;
}
.trail__gear:hover, .trail__gear[aria-expanded="true"]{ color: var(--ink); background: var(--a5) }
.trail__gear:focus-visible{ outline: 1px solid var(--accent-glyph); outline-offset: -1px }
.trail__gear svg{ width: 14px; height: 14px; display: block }

/* settings: a card beside the open panel */
/* hidden always wins over the display values below */
.trail [hidden], .trail-line[hidden]{ display: none !important }
/* the settings only show beside a fully open panel */
.trail:not([data-open]) .trail__menu{ display: none }
.trail__menu{
  position: absolute; top: 0; z-index: 22;
  left: calc(var(--trail-open-w) + 8px); width: 236px;
  display: grid; gap: 10px; padding: 12px;
  background: var(--raised); border-radius: var(--r-contain);
  box-shadow: inset 0 0 0 var(--px) var(--line-4), var(--e2);
  font: 400 12px/17px var(--font); letter-spacing: var(--tracking); color: var(--ink);
  transform-origin: 0 0; animation: trail-menu-in 160ms cubic-bezier(.2,.7,.2,1);
}
@keyframes trail-menu-in{ from{ opacity: 0; transform: translateX(-4px) } }
.trail__mh{ font: 450 11px/16px var(--font); letter-spacing: .01em; color: var(--ink-3) }
.trail__seg{ display: grid; grid-template-columns: repeat(3, 1fr); gap: 2px; padding: 2px; border-radius: var(--r-press); background: var(--a5) }
.trail__seg button{
  appearance: none; border: 0; background: none; border-radius: var(--r-press); padding: 5px 0;
  font: 500 12px/16px var(--font); color: var(--ink-3); cursor: default;
}
.trail__seg button[aria-pressed="true"]{ background: var(--raised); color: var(--ink); box-shadow: inset 0 0 0 var(--px) var(--line-4) }
.trail__mcap{ margin: -4px 0 0; font-size: 11px; line-height: 16px; color: var(--ink-4) }
.trail__mparts{ display: grid; gap: 2px; margin: 0 -6px }
.trail__menu[data-off] .trail__mparts{ opacity: .5 }
.trail__mrow{
  appearance: none; border: 0; background: none; text-align: left; cursor: default;
  display: flex; align-items: center; justify-content: space-between; gap: 12px;
  padding: 5px 6px; border-radius: var(--r-row); color: inherit; font: inherit;
}
.trail__mrow:hover{ background: var(--a5) }
.trail__mtext{ display: grid }
.trail__mtext small{ font-size: 11px; line-height: 15px; color: var(--ink-4) }
.trail__sw{
  flex: none; position: relative; width: 26px; height: 16px; border-radius: var(--r-press);
  background: var(--line-4); transition: background-color 160ms;
}
.trail__sw::after{
  content: ''; position: absolute; left: 2px; top: 2px; width: 12px; height: 12px; border-radius: var(--r-press);
  background: var(--raised); box-shadow: 0 1px 2px rgb(0 0 0 / .18); transition: transform 160ms cubic-bezier(.2,.7,.2,1);
}
.trail__mrow[aria-checked="true"] .trail__sw{ background: var(--ink) }
.trail__mrow[aria-checked="true"] .trail__sw::after{ transform: translateX(10px) }
.trail__mreset{
  appearance: none; border: 0; background: none; padding: 0; justify-self: start; cursor: default;
  font: 450 11px/16px var(--font); color: var(--ink-3);
}
.trail__mreset:hover{ color: var(--ink); text-decoration: underline; text-underline-offset: 2px }
.trail__seg button:focus-visible, .trail__mrow:focus-visible, .trail__mreset:focus-visible{ outline: 1px solid var(--accent-glyph); outline-offset: -1px }
@media (prefers-reduced-motion: reduce){ .trail__menu{ animation: none } .trail__sw, .trail__sw::after{ transition: none } }
.trail__scroll{
  --ft: 0px; --fb: 0px;
  position: absolute; left: 0; right: 0; bottom: 0;
  top: calc(var(--trail-head-h) * var(--x));
  overflow: hidden;
  border-radius: var(--r-row);
  scrollbar-width: none;       /* the edge fade shows that the list scrolls */
  overscroll-behavior: contain;
}
.trail[data-fade] .trail__scroll{
  /* eased: the outer third is almost gone, the inner third almost full */
  -webkit-mask-image: linear-gradient(to bottom, transparent 0, rgb(0 0 0 / .1) calc(var(--ft) * .3), rgb(0 0 0 / .4) calc(var(--ft) * .6), rgb(0 0 0 / .8) calc(var(--ft) * .85), #000 var(--ft), #000 calc(100% - var(--fb)), rgb(0 0 0 / .8) calc(100% - var(--fb) * .85), rgb(0 0 0 / .4) calc(100% - var(--fb) * .6), rgb(0 0 0 / .1) calc(100% - var(--fb) * .3), transparent 100%);
          mask-image: linear-gradient(to bottom, transparent 0, rgb(0 0 0 / .1) calc(var(--ft) * .3), rgb(0 0 0 / .4) calc(var(--ft) * .6), rgb(0 0 0 / .8) calc(var(--ft) * .85), #000 var(--ft), #000 calc(100% - var(--fb)), rgb(0 0 0 / .8) calc(100% - var(--fb) * .85), rgb(0 0 0 / .4) calc(100% - var(--fb) * .6), rgb(0 0 0 / .1) calc(100% - var(--fb) * .3), transparent 100%);
}
.trail[data-open] .trail__scroll{ overflow-y: auto }
.trail__scroll::-webkit-scrollbar{ display: none; width: 0; height: 0 }
.trail__track{ position: relative; height: calc(var(--hc) + (var(--to) - var(--hc)) * var(--x)) }
.trail__list{ list-style: none; margin: 0; padding: 0 }

/* heading rows */
.trail__item{
  --h: calc(var(--trail-row) + (var(--trail-row-open) - var(--trail-row)) * var(--x));
  position: absolute; left: 0; right: 0;
  top: calc(var(--yc) + (var(--yo) - var(--yc)) * var(--x) - var(--h) / 2);
  height: var(--h);
}
.trail__link{
  position: absolute; inset: 0 4px;
  display: block; color: inherit; text-decoration: none;
  border-radius: var(--r-key);
  outline: none;
}
.trail__link:focus-visible{ box-shadow: inset 0 0 0 1px var(--accent-glyph) }

/* ticks: a base in the unread colour and an ::after in the read colour, scaled by --f */
.trail__tick,
.trail__fill{
  position: absolute;
  height: var(--trail-tick);
  transform-origin: 0 50%;
  transition: background-color 120ms;
}
.trail__tick::after,
.trail__fill::after{
  content: ''; position: absolute; inset: 0;
  transform-origin: 0 50%;
  transform: scaleX(var(--f, 0));
  transition: background-color 120ms;
}
.trail:not([data-sweep]) .trail__link:not([aria-current]) .trail__tick::after,
.trail:not([data-sweep]) .trail__fill::after{ transition: background-color 120ms, transform 180ms }
.trail__item[data-read],
.trail__fill[data-read]{ --f: 1 }

.trail__tick{
  left: calc(var(--tx) - 4px); top: 50%;
  width: calc(var(--len) * 1px);
  background: var(--trail-head);
  transform: translateY(-50%) scaleX(var(--ts));
}
.trail__tick::after{ background: var(--trail-head-read) }
.trail[data-bars] .trail__tick{
  height: calc(var(--trail-tick) + (var(--trail-bar-h) - var(--trail-tick)) * var(--x));
  border-radius: calc(var(--trail-bar-h) / 2 * var(--x));
  transform: translateY(-50%) scaleX(calc(1 + (var(--dur) / var(--len) - 1) * var(--x)));
}
.trail[data-bars] .trail__tick::after{ border-radius: inherit }
.trail[data-bars] .trail__link[aria-current] .trail__tick{
  height: calc(var(--trail-tick-active) + (var(--trail-bar-h) - var(--trail-tick-active)) * var(--x));
}

/* rows between headings */
.trail__fill{
  left: var(--tx);
  top: calc(var(--yc) + (var(--yo) - var(--yc)) * var(--x));
  width: var(--trail-tick-body);
  background: var(--trail-body);
  transform: translateY(-50%) scaleX(var(--ts));
  opacity: calc(1 - var(--x) * 1.5);
  pointer-events: none;
}
.trail__fill::after{ background: var(--trail-body-read) }

/* skim: the section under the pointer, one step up */
.trail__fill[data-hl]{ background: var(--trail-body-read) }
.trail__fill[data-hl]::after{ background: var(--trail-head-read) }
.trail__item[data-hl] .trail__tick{ background: var(--trail-head-read) }
.trail__item[data-hl] .trail__tick::after{ background: var(--ink-2) }

/* the section being read */
.trail__link[aria-current] .trail__tick{ height: var(--trail-tick-active) }
.trail__link[aria-current] .trail__tick::after{ background: var(--trail-current) }

.trail__label{
  --a: clamp(0, calc(var(--x) * 1.6 - var(--s)), 1);   /* --s: stagger 0 to .35, top to bottom */
  position: absolute; left: calc(var(--trail-label-x) - 4px); top: 50%;
  max-width: calc(var(--trail-open-w) - var(--trail-label-x) - 14px);
  overflow: hidden; white-space: nowrap; text-overflow: ellipsis;
  color: var(--ink-3);
  opacity: var(--a);
  transform: translate(calc((1 - var(--a)) * -6px), -50%);
  transition: color 120ms;
}
.trail__item[data-level="3"] .trail__label{ padding-left: 10px }
.trail__link:hover .trail__label{ color: var(--ink-2) }
.trail__link[aria-current] .trail__label{ color: var(--ink) }
.trail__dot{
  position: absolute; left: 0; top: 0;
  width: var(--trail-dot); height: var(--trail-dot);
  border-radius: var(--r-mark);
  background: var(--trail-dot-color);
  pointer-events: none;
  will-change: transform;
}

/* skim label */
.trail__skim{
  position: absolute; top: 0; z-index: 21;
  left: calc(var(--trail-closed-w, var(--trail-width)) + var(--trail-skim-gap));
  display: flex; align-items: center; gap: 8px;
  height: var(--trail-skim-h); padding: 0 9px;
  border-radius: var(--r-row);
  background: var(--raised);
  box-shadow: inset 0 0 0 var(--px) var(--line-4), var(--e2);
  color: var(--ink);
  white-space: nowrap;
  pointer-events: none;
  opacity: 0;
  translate: -4px 0;
  transition: opacity 120ms, translate 160ms cubic-bezier(.2,.7,.2,1);
  will-change: transform;
}
.trail[data-skimming] .trail__skim{ opacity: 1; translate: 0 0 }
.trail__skim-time{ color: var(--ink-4); font-variant-numeric: tabular-nums }

/* =====================================================================
   READING LINE
   The line where Trail decides what is being read, 15 percent down the
   window unless the reader moves it. Five parts, each optional:
   motion (shows while scrolling), mark (flashes when a heading crosses
   it), fill (grows across the text column through the current
   section), drag (a handle moves the line), dim (text above it fades).
   JS writes: --lp (position, 0 to 1), --lx --lw (text column), --lf
   (share of the section read), data-shown, data-flash, data-dragging,
   and data-trail-passed on blocks of the article above the line.
   ===================================================================== */
.trail-line{
  position: fixed; left: 0; right: 0; top: calc(var(--lp, .15) * 100%);
  height: 0; z-index: 24; pointer-events: none;
}
.trail-line__rule{ position: absolute; inset: 0; transition: opacity 160ms ease }
.trail-line[data-motion] .trail-line__rule{ opacity: 0; transition-duration: 600ms }
.trail-line[data-motion][data-shown] .trail-line__rule,
.trail-line[data-motion][data-dragging] .trail-line__rule{ opacity: 1; transition-duration: 160ms }
.trail-line__base,
.trail-line__fill,
.trail-line__flash{ position: absolute; top: 0; height: var(--px); background: var(--accent-glyph) }
.trail-line__base{ left: 0; right: 0; opacity: .4 }
.trail-line[data-fill] .trail-line__base{ opacity: .2 }
.trail-line__fill{
  display: none; left: var(--lx, 0); width: var(--lw, 0); height: 1px; top: -.25px;
  transform-origin: 0 50%; transform: scaleX(var(--lf, 0));
}
.trail-line[data-fill] .trail-line__fill{ display: block }
.trail-line__flash{ left: 0; right: 0; height: 1px; opacity: 0 }
.trail-line[data-flash] .trail-line__flash{ animation: trail-flash 900ms cubic-bezier(.2,.7,.2,1) both }
@keyframes trail-flash{ 0%{ opacity: .95 } 100%{ opacity: 0 } }

.trail-line__knob{
  display: none; position: absolute; right: 20px; top: -12px; width: 24px; height: 24px;
  pointer-events: auto; cursor: ns-resize; border-radius: var(--r-press); outline: none; touch-action: none;
}
.trail-line[data-drag] .trail-line__knob{ display: block }
.trail-line__knob::before{
  content: ''; position: absolute; left: 50%; top: 50%;
  width: 9px; height: 9px; margin: -4.5px 0 0 -4.5px; border-radius: var(--r-mark);
  background: var(--paper); box-shadow: inset 0 0 0 1.5px var(--accent-glyph);
  transition: transform 160ms cubic-bezier(.2,.7,.2,1);
}
.trail-line__knob:hover::before,
.trail-line[data-dragging] .trail-line__knob::before{ transform: scale(1.3) }
.trail-line__knob:focus-visible::before{ box-shadow: inset 0 0 0 1.5px var(--accent-glyph), 0 0 0 3px var(--a5) }
.trail-line__tag{
  position: absolute; right: 32px; top: 50%; transform: translateY(-50%);
  padding: 3px 8px; border-radius: var(--r-row); white-space: nowrap;
  background: var(--raised); box-shadow: inset 0 0 0 var(--px) var(--line-4), var(--e2);
  font: 450 11px/16px var(--font); letter-spacing: .01em; font-variant-numeric: tabular-nums; color: var(--ink-3);
  opacity: 0; transition: opacity 120ms; pointer-events: none;
}
.trail-line__knob:hover .trail-line__tag,
.trail-line__knob:focus-visible .trail-line__tag,
.trail-line[data-dragging] .trail-line__tag{ opacity: 1 }

:where([data-trail-block]){ transition: opacity 420ms ease }
[data-trail-passed]{ opacity: .36 }
@media (prefers-reduced-motion: reduce){
  .trail-line[data-flash] .trail-line__flash{ animation: none }
  :where([data-trail-block]){ transition: none }
}
