/* ==============================================================================================
   The opening. A navy field with the company mark in white at its centre; scrolling parts the
   field along the mark's own cuts and uncovers the page that was behind it all along.

   The field is four blades that meet on the centre lines of the mark's three cuts, carried out to
   the edges of the screen. Each blade holds one piece of the mark. shared/opening.js builds them,
   sizes them in real pixels and moves them; this file is their resting state.
   ============================================================================================== */

:root {
  --opening-navy: #004362;
  --opening-ink: #ffffff;
  --opening-run: 0px;                 /* scroll distance the opening takes; set by the script */
}

/* Before the script has built the field: paint navy, show nothing of the page. Set in <head>,
   cleared by the script (or by its own timer if the script never arrives). */
html.opening-pending {
  background: var(--opening-navy);
}

html.opening-pending body {
  visibility: hidden;
}

/* For as long as the field covers the page, what lies around the page is navy as well: the canvas
   (the body paints its own paper over it, so this shows only where the body does not: while the
   kit still holds the first paint, and where the browser lets the page be pulled past its edge)
   and the track of a scrollbar that is always on show. */
html.opening-cover {
  background: var(--opening-navy);
}

@supports (scrollbar-color: auto) {
  html.opening-cover {
    scrollbar-color: rgba(255, 255, 255, 0.35) var(--opening-navy);
  }
}

/* ---------------------------------------------------------------------------------- the pin */

/* The whole page stands still behind the field while it opens: the shell sticks to the top of the
   screen for exactly the length of the run, then scrolls as it always did. Nothing else moves it,
   so the browser's own compositor holds it and there is no script in the way of the scroll. It
   carries the page's paper, so the layer it makes is opaque and text keeps its rendering. */
.opening-shell {
  position: sticky;
  top: 0;
  background: var(--paper, transparent);
}

/* The run is measured by the script while the field is closed and written here in pixels, so it
   does not follow a phone's toolbar or a window being resized under a reader further down. */
.opening-run {
  height: var(--opening-run);
}

/* On every other page there is no opening: no run, and nothing held. */
html.opening-off .opening-run {
  display: none;
}

html.opening-off .opening-shell {
  position: static;
  background: none;
}

/* ---------------------------------------------------------------------------------- the field */

/* The field itself is not there for the pointer; its navy is (see the panel). */
.opening {
  position: fixed;
  left: 0;
  top: 0;
  z-index: 900;
  width: 100%;
  height: 100vh;
  height: 100lvh;
  overflow: hidden;
  overflow: clip;
  pointer-events: none;
  -webkit-user-select: none;
  user-select: none;
  contain: strict;
}

.opening[hidden],
html.opening-off .opening {
  display: none;
}

/* The height a phone shows while its bars are out. The script reads it to place the mark. */
.opening__probe {
  position: absolute;
  left: 0;
  top: 0;
  width: 0;
  height: 100vh;
  height: 100svh;
  visibility: hidden;
}

/* A blade has no box of its own, only what it carries: its navy and its piece of the mark. */
.opening__blade {
  position: absolute;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  will-change: transform;
}

/* A blade's navy. The script gives it a box and, inside that, its outline as a polygon. A blade
   reaches past the screen wherever its far side would otherwise slide into view, so the page is
   only ever uncovered along the cuts, never at the edge of the screen. What is painted is what the
   pointer meets: the page behind cannot be hovered, clicked or selected through the navy, and is
   live exactly where it has been uncovered. Wheel and touch still scroll the document. */
.opening__panel {
  position: absolute;
  background: var(--opening-navy);
  pointer-events: auto;
  cursor: default;
}

.opening__panel[hidden] {
  display: none;
}

/* One piece of the mark, placed by the script where the whole mark would sit. */
.opening__piece {
  position: absolute;
  display: block;
  overflow: visible;
  will-change: transform;
}

.opening__piece svg {
  display: block;
  width: 100%;
  height: 100%;
  overflow: visible;
}

.opening__piece path {
  fill: var(--opening-ink);
}

/* ---------------------------------------------------------------------------------- the cue */

/* A word and a hairline under the mark, on the line of the mark's upright cut (the script sets
   `left`). The box is one pixel wide, which is the hairline; the word is centred on it. The outer
   box fades with the scroll; the inner one fades in once the mark has arrived. It hangs from the
   foot of the small viewport, so a phone's toolbar does not stand over it. */
.opening__cue {
  position: absolute;
  left: 50%;
  bottom: max(2.25rem, env(safe-area-inset-bottom, 0px) + 1.5rem);
  width: 1px;
  color: var(--opening-ink);
}

@supports (height: 100svh) {
  .opening__cue {
    bottom: calc(100lvh - 100svh + max(2.25rem, env(safe-area-inset-bottom, 0px) + 1.5rem));
  }
}

.opening__cue-in {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 0.9rem;
  opacity: 0;
}

.opening__cue-word {
  flex: none;
  font-family: var(--font-sans, system-ui, -apple-system, "Helvetica Neue", Arial, sans-serif);
  font-size: 0.6875rem;
  font-weight: 500;
  line-height: 1;
  letter-spacing: 0.18em;
  text-indent: 0.18em;                /* the tracking after the last letter, given back in front */
  text-transform: uppercase;
  white-space: nowrap;
  opacity: 0.82;
}

/* Drawn here and not written in the page, so the word cannot be found, selected or copied. */
.opening__cue-word::before {
  content: "Scroll";
}

/* The hairline is as long as the screen has room for: full length from 600px of height, shorter
   below that, so the air between the mark and the word does not close. */
.opening__cue-line {
  position: relative;
  flex: none;
  width: 1px;
  height: 2.75rem;
  height: clamp(1rem, 22vh - 5.5rem, 2.75rem);
  height: clamp(1rem, 22svh - 5.5rem, 2.75rem);
  overflow: hidden;
  background: rgba(255, 255, 255, 0.26);
}

/* A short stroke that runs down the line three times and then rests: an invitation, not a loop.
   It starts when the mark does (the script sets is-in as the arrival begins). */
.opening__cue-line::after {
  content: "";
  position: absolute;
  inset: 0;
  background: var(--opening-ink);
  transform: translateY(-101%);
}

.opening.is-in .opening__cue-line::after {
  animation: opening-cue 2100ms cubic-bezier(0.625, 0.05, 0, 1) 2100ms 3 both;
}

@keyframes opening-cue {
  0% { transform: translateY(-101%); }
  55%, 100% { transform: translateY(101%); }
}

/* A screen too short for both: the word alone, nearer the foot. */
@media (max-height: 30rem) {
  .opening__cue-line {
    display: none;
  }

  .opening__cue {
    bottom: max(1.25rem, env(safe-area-inset-bottom, 0px) + 0.75rem);
  }

  @supports (height: 100svh) {
    .opening__cue {
      bottom: calc(100lvh - 100svh + max(1.25rem, env(safe-area-inset-bottom, 0px) + 0.75rem));
    }
  }
}

/* ---------------------------------------------------------------------------------- around it */

/* While the field still covers the page, the review bar stays out of the picture. */
html.opening-on .rtc-bar {
  transition: opacity 500ms cubic-bezier(0.22, 1, 0.36, 1), visibility 0s linear 0s;
}

html.opening-cover .rtc-bar {
  visibility: hidden;
  opacity: 0;
  transition: opacity 200ms linear, visibility 0s linear 200ms;
}

/* The skip link is the first thing the Tab key finds. Fixed, it is shown where the reader is
   instead of taking the scroll back to the top of the document, which would close the field. */
html.opening-on .rtc-skip {
  position: fixed;
}

/* ---------------------------------------------------------------------------------- stillness */

/* Reduced motion: the same first sight, held still, and a plain fade when the reader moves on. */
.opening--still {
  transition: opacity 240ms linear;
}

.opening--still.is-leaving {
  opacity: 0;
}

@media (prefers-reduced-motion: reduce) {
  .opening__cue-line::after,
  .opening.is-in .opening__cue-line::after {
    animation: none;
    transform: none;
    opacity: 0.6;
  }
}

@media print {
  .opening {
    display: none;
  }

  .opening-run {
    display: none;
  }

  .opening-shell {
    position: static;
    background: none;
    transform: none !important;
    will-change: auto !important;
  }
}
