/*
 * Honeycomb rail (static/js/sections.js): a quiet section indicator fixed at the right edge of index.html and
 * theory.html. One flat-topped hexagonal cell per section, stacked in a slight honeycomb zigzag, like the cells of
 * the logo: the section being read fills with honey from the bottom as the reader moves through it, the sections
 * above it keep a light fill and the sections below stay outlines. A section's short name glides out of its cell
 * when the reader enters it, where only margin lies beside the cell, and fades soon after; hovering the rail, or
 * reaching it with the keyboard, shows every name, or only the one under the pointer or focus where the margin is
 * too narrow for all (.is-tight). The script shows the rail only where it fits beside the widest container (.is-fit,
 * from a window about 1408 px wide), and only once the title has mostly scrolled away (.is-revealed). Uses the
 * tokens of index.css.
 */

.hx-rail {
  /* The logo's honey (static/images/logo.svg): --hx-ours at the bottom of a cell, through amber, to gold at the top. */
  --hx-rail-honey-mid: #e8945a;
  --hx-rail-honey-top: #f5be62;
  /* Each cell's link is a square of this size, so the rail's pitch is the smallest comfortable pointer target. */
  --hx-rail-size: 24px;
  /* Every other cell steps this far toward the page, the zigzag of a honeycomb's column. */
  --hx-rail-zigzag: 5px;
  /* Cells rest at this opacity and come to full strength while the rail is hovered or focused. */
  --hx-rail-idle: 0.55;
  position: fixed;
  top: 50%;
  right: var(--hx-rail-right, 16px);
  z-index: 30;
  display: none;
  opacity: 0;
  pointer-events: none;
  transform: translateY(-50%);
  transition: opacity 0.35s ease;
}

.hx-rail.is-fit {
  display: block;
}

/* Hidden while the title is on screen, but its links stay in the tab order: keyboard focus brings it back.
   The :has() rules stand alone throughout, so a browser without it still keeps the others. */
.hx-rail.is-revealed {
  opacity: 1;
  pointer-events: auto;
}

.hx-rail:has(.hx-rail-link:focus-visible) {
  opacity: 1;
  pointer-events: auto;
}

/* The gradient and clip path the cells share; an SVG without size, since a hidden one may not paint them. */
.hx-rail-defs {
  position: absolute;
  width: 0;
  height: 0;
  overflow: hidden;
}

.hx-rail-list {
  margin: 0;
  padding: 0;
  list-style: none;
}

.hx-rail-item {
  position: relative;
  margin: 0;
}

.hx-rail-link {
  position: relative;
  display: grid;
  place-items: center;
  width: var(--hx-rail-size);
  height: var(--hx-rail-size);
  color: var(--hx-muted);
  -webkit-tap-highlight-color: transparent;
}

/* The hexagonal ring of the cell marks keyboard focus instead of the page's square outline. */
.hx-rail-link:focus-visible {
  outline: none;
}

/* ---------- Cells ---------- */

.hx-rail-cell {
  display: block;
  width: 20px;
  height: 20px;
  overflow: visible;
  opacity: var(--hx-rail-idle);
  transition: opacity 0.2s ease;
}

.hx-rail-item:nth-child(even) .hx-rail-cell {
  translate: calc(-1 * var(--hx-rail-zigzag)) 0;
}

.hx-rail-body {
  fill: var(--hx-surface);
}

.hx-rail-edge {
  fill: none;
  stroke: var(--hx-muted);
  stroke-width: 1;
  transition: stroke 0.25s ease, stroke-opacity 0.25s ease;
}

/* The honey rises from the bottom of the cell; --hx-rail-fill (0 to 1) is the reader's progress through the section. */
.hx-rail-honey {
  opacity: 0;
  transform: scaleY(0);
  transform-box: fill-box;
  transform-origin: 50% 100%;
  transition: transform 0.2s ease-out, opacity 0.3s ease;
}

.hx-rail-honey-stop-bottom {
  stop-color: var(--hx-ours);
}

.hx-rail-honey-stop-middle {
  stop-color: var(--hx-rail-honey-mid);
}

.hx-rail-honey-stop-top {
  stop-color: var(--hx-rail-honey-top);
}

.hx-rail-link[data-state="current"] .hx-rail-honey {
  opacity: 1;
  transform: scaleY(var(--hx-rail-fill, 0));
}

.hx-rail-link[data-state="current"] .hx-rail-edge {
  stroke: var(--hx-ours);
}

/* The cell being read stays at full strength, so the reader's place shows at a glance. */
.hx-rail-link[data-state="current"] .hx-rail-cell {
  opacity: 1;
}

.hx-rail-link[data-state="read"] .hx-rail-honey {
  opacity: 0.35;
  transform: none;
}

.hx-rail-link[data-state="read"] .hx-rail-edge {
  stroke: var(--hx-ours);
  stroke-opacity: 0.55;
}

.hx-rail-ring {
  fill: none;
  stroke: var(--hx-select);
  stroke-width: 2;
  opacity: 0;
}

.hx-rail-link:focus-visible .hx-rail-ring {
  opacity: 1;
}

/* ---------- Names ---------- */

/* Each name sits on a white tag shaped like a stretched cell, its point toward its own cell. On white the tag
   disappears; over a grey band or a figure it keeps the name legible. Hidden, the tag is rolled up against its
   cell; shown, it unrolls to the left. */
.hx-rail-label {
  /* The unrolled tag: pointed ends with the 120 degree corners of a hexagon. */
  --hx-rail-tip: 6px;
  --hx-rail-tag: polygon(0 50%, var(--hx-rail-tip) 0, calc(100% - var(--hx-rail-tip)) 0, 100% 50%,
    calc(100% - var(--hx-rail-tip)) 100%, var(--hx-rail-tip) 100%);
  position: absolute;
  top: 50%;
  right: calc(100% + 1px);
  padding: 0.1rem calc(0.3rem + var(--hx-rail-tip));
  background: rgba(255, 255, 255, 0.95);
  color: var(--hx-muted);
  font-family: var(--hx-font-title);
  font-size: 0.75rem;
  line-height: 1.5;
  white-space: nowrap;
  opacity: 0;
  pointer-events: none;
  clip-path: polygon(100% 50%, 100% 0, 100% 0, 100% 50%, 100% 100%, 100% 100%);
  transform: translate(12px, -50%);
  /* Leaving, a name fades where it stands and only then rolls back up. */
  transition: opacity 0.5s ease, clip-path 0s linear 0.5s, transform 0s linear 0.5s, color 0.2s ease;
}

.hx-rail-item:nth-child(even) .hx-rail-label {
  margin-right: var(--hx-rail-zigzag);
}

.hx-rail-link[aria-current] .hx-rail-label {
  color: var(--hx-ink);
}

/* Entering a section: its name glides out of the cell (sections.js removes the class after about 1.5 s). */
.hx-rail-item.is-announced .hx-rail-label {
  opacity: 1;
  clip-path: var(--hx-rail-tag);
  transform: translate(0, -50%);
  transition: opacity 0.25s ease, clip-path 0.5s cubic-bezier(0.2, 0.8, 0.2, 1),
    transform 0.5s cubic-bezier(0.2, 0.8, 0.2, 1), color 0.2s ease;
}

/* Hovering the rail unrolls every name, top to bottom, after a short pause, so a pointer passing by does not
   flash them. Where the margin cannot hold every name beside the content (.is-tight, set by sections.js), only the
   name of the cell under the pointer unrolls, like a tooltip. */
@media (hover: hover) {
  .hx-rail:hover .hx-rail-cell {
    opacity: 1;
  }

  .hx-rail:not(.is-tight):hover .hx-rail-label,
  .hx-rail.is-tight .hx-rail-link:hover .hx-rail-label {
    --hx-rail-delay: calc(80ms + var(--hx-rail-index, 0) * 15ms);
    opacity: 1;
    pointer-events: auto;
    clip-path: var(--hx-rail-tag);
    transform: translate(0, -50%);
    transition: opacity 0.2s ease var(--hx-rail-delay), clip-path 0.4s cubic-bezier(0.2, 0.8, 0.2, 1) var(--hx-rail-delay),
      transform 0.4s cubic-bezier(0.2, 0.8, 0.2, 1) var(--hx-rail-delay), color 0.2s ease;
  }

  .hx-rail.is-tight .hx-rail-link:hover .hx-rail-label {
    --hx-rail-delay: 80ms;
  }

  .hx-rail-link:hover .hx-rail-label {
    color: var(--hx-ink);
  }

  .hx-rail-link:hover .hx-rail-edge {
    stroke-opacity: 1;
  }
}

.hx-rail:has(.hx-rail-link:focus-visible) .hx-rail-cell {
  opacity: 1;
}

.hx-rail:not(.is-tight):has(.hx-rail-link:focus-visible) .hx-rail-label {
  opacity: 1;
  pointer-events: auto;
  clip-path: var(--hx-rail-tag);
  transform: translate(0, -50%);
  transition: opacity 0.2s ease, clip-path 0.3s cubic-bezier(0.2, 0.8, 0.2, 1),
    transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1), color 0.2s ease;
}

/* With a tight margin, the keyboard focus shows only its own cell's name. */
.hx-rail.is-tight .hx-rail-link:focus-visible .hx-rail-label {
  opacity: 1;
  pointer-events: auto;
  clip-path: var(--hx-rail-tag);
  transform: translate(0, -50%);
  transition: opacity 0.2s ease, clip-path 0.3s cubic-bezier(0.2, 0.8, 0.2, 1),
    transform 0.3s cubic-bezier(0.2, 0.8, 0.2, 1), color 0.2s ease;
}

.hx-rail-link:focus-visible .hx-rail-label {
  color: var(--hx-ink);
  text-decoration: underline;
  text-underline-offset: 2px;
}

/* ---------- Opening ---------- */

/* Each time the rail appears, its cells grow into place one after another, top to bottom. */
@media (prefers-reduced-motion: no-preference) {
  .hx-rail.is-revealed .hx-rail-cell {
    animation: hx-rail-grow 0.45s cubic-bezier(0.3, 1.3, 0.5, 1) both;
    animation-delay: calc(var(--hx-rail-index, 0) * 30ms);
  }
}

@keyframes hx-rail-grow {
  from { scale: 0.25; }
  to { scale: 1; }
}

/* Reduced motion: states and names change at once, with no glide, fill or opening animation. */
@media (prefers-reduced-motion: reduce) {
  .hx-rail,
  .hx-rail * {
    transition: none !important;
    animation: none !important;
  }
}

/* Phones, tablets and print never show the rail; on wider screens the script decides whether it fits. */
@media print, screen and (max-width: 1023px) {
  .hx-rail {
    display: none !important;
  }
}

@media (forced-colors: active) {
  .hx-rail-body {
    fill: Canvas;
  }

  .hx-rail-edge,
  .hx-rail-link[data-state] .hx-rail-edge {
    stroke: CanvasText;
    stroke-opacity: 1;
  }

  .hx-rail-honey {
    fill: Highlight;
  }

  .hx-rail-ring {
    stroke: Highlight;
  }

  .hx-rail-label {
    background: Canvas;
    color: CanvasText;
  }
}
