/* The opener's heading and the rest of the page form two grid rows. The
   server-rendered spine spans the second row, so title wrapping and fonts
   position it on the very first paint without JavaScript measurements. */
.rail-layout {
  display: grid;
  grid-template-columns: minmax(0, 1fr);
  grid-template-rows: auto auto;
  position: relative;
}

.page-open-heading {
  grid-row: 1;
  margin-top: 2rem;
  padding-bottom: 1.5rem;
}

.rail-body {
  grid-row: 2;
  min-width: 0;
}

.rail-body > .page-open,
.rail-body > .page-open > .page-open-trace {
  margin-top: 0;
}

.rail-pad {
  display: none;
}

@media (min-width: 1100px) {
  /* Heading-local pads are present before hydration. Their first-line
     position matches the interactive index, which takes over after sync. */
  .rail-layout .subnav-target .section-label > .rail-pad {
    display: block;
    position: absolute;
    top: 0.5lh;
    left: calc(-1 * var(--rail-reach) + 1.5px);
    transform: translate(-50%, -50%);
    box-sizing: border-box;
    width: 13px;
    height: 13px;
    border: 3px solid var(--red);
    border-radius: 50%;
    background: var(--white);
    pointer-events: none;
  }

  .rail-interactive .rail-pad {
    visibility: hidden;
  }

  .rail-layout > .static-spine {
    position: absolute;
    grid-column: 1;
    grid-row: 2;
    top: var(--rail-corner);
    bottom: 0;
    left: calc(-1 * var(--rail-reach) - 2.25rem);
    margin: 0;
  }

  /* The whole trace waits for the page's scripts, which on some pages write
     half of what it runs down. Then src/lib/trace-draw.js draws it from one
     circle: the pad under the title lands, the stub runs out of it to the
     corner, the corner turns, and the trace carries on down the margin, each
     section's pad landing as the line reaches it. The stub is a background
     anchored at the pad, so it can grow out of it.

     Held only where scripts run (data-js, set in the head by
     src/components/BodyLayout.tsx), and never for long: if the page's
     scripts fail and it is never marked ready, the trace shows anyway. */
  .rail-layout .page-open-trace {
    background: linear-gradient(var(--red), var(--red)) right center / 100% 100% no-repeat;
  }

  html[data-js]:not([data-cssic-ready]) .rail-layout .page-open-trace {
    background-size: 0 100%;
    animation: trace-failsafe-stub 0s 4s forwards;
  }

  html[data-js]:not([data-cssic-ready]) .rail-layout .page-open-trace::before,
  html[data-js]:not([data-cssic-ready]) .rail-layout .page-open-trace::after,
  html[data-js]:not([data-cssic-ready]) .rail-layout > .static-spine,
  html[data-js]:not([data-cssic-ready]) .rail-layout .rail-pad,
  html[data-js]:not([data-cssic-ready]) .with-rail .section-nav-list {
    visibility: hidden;
    animation: trace-failsafe 0s 4s forwards;
  }

  /* Arriving from another page of the site (src/components/BodyLayout.tsx)
     the trace is already there: the view transition has slid it from where it
     was on the last page to where it sits on this one. Only the section pads
     land, down the line, once the page is built. The survey page is at least
     the window's height from the start, so a trace shown before it has
     written its questions does not stop short in view. */
  .rail-layout .page-open-trace {
    view-transition-name: rail-open;
  }

  .rail-layout > .static-spine {
    view-transition-name: rail-spine;
  }

  .survey-page .rail-layout .rail-body {
    min-height: 100vh;
  }

  html[data-cssic-arrive="carry"]:not([data-cssic-ready]) .rail-layout .page-open-trace {
    background-size: 100% 100%;
    animation: none;
  }

  html[data-cssic-arrive="carry"]:not([data-cssic-ready]) .rail-layout .page-open-trace::before,
  html[data-cssic-arrive="carry"]:not([data-cssic-ready]) .rail-layout .page-open-trace::after,
  html[data-cssic-arrive="carry"]:not([data-cssic-ready]) .rail-layout > .static-spine {
    visibility: visible;
    animation: none;
  }

  html[data-cssic-arrive="carry"] .with-rail.is-drawing .page-open-trace,
  html[data-cssic-arrive="carry"] .with-rail.is-drawing .page-open-trace::before,
  html[data-cssic-arrive="carry"] .with-rail.is-drawing .page-open-trace::after {
    animation: none;
  }

  .with-rail.is-drawing .page-open-trace::after {
    animation: open-pad-land 0.16s ease-out backwards;
  }

  .with-rail.is-drawing .page-open-trace {
    animation: stub-draw 90ms 80ms linear backwards;
  }

  .with-rail.is-drawing .page-open-trace::before {
    animation: corner-draw 60ms 170ms linear backwards;
  }

  /* The run itself is clipped frame by frame by src/lib/trace-draw.js; its
     pads wait, shrunk to nothing, until the edge reaches them. */
  .with-rail.is-drawing .section-nav-item:not(.is-landed) .section-nav-link::before {
    transform: translate(50%, -50%) scale(0);
  }

  .with-rail .section-nav-item.is-landed .section-nav-link::before {
    animation: pad-land 0.26s ease-out;
  }
}

@keyframes open-pad-land {
  from { transform: translateY(-50%) scale(0); }
  60% { transform: translateY(-50%) scale(1.3); }
  to { transform: translateY(-50%) scale(1); }
}

@keyframes stub-draw {
  from { background-size: 0 100%; }
  to { background-size: 100% 100%; }
}

@keyframes corner-draw {
  from { clip-path: inset(0 0 0 100%); }
  to { clip-path: inset(0 0 0 0); }
}

@keyframes trace-failsafe {
  to { visibility: visible; }
}

@keyframes trace-failsafe-stub {
  to { background-size: 100% 100%; }
}

@keyframes pad-land {
  from { transform: translate(50%, -50%) scale(0); }
  60% { transform: translate(50%, -50%) scale(1.3); }
  to { transform: translate(50%, -50%) scale(1); }
}
