/* Opening sequence. Overlay only: the page content sits in the HTML from
   the start and is never hidden by this. The overlay simply covers it. */

#opening {
  position: fixed;
  inset: 0;
  z-index: 50;
  pointer-events: none;
}
#opening:not(.playing) { display: none; }

/* op-pending is set by the inline script in <head>, before the body is parsed,
   so the cover is up on the very first paint rather than a frame or two later.
   opening.js removes the class when the sequence ends or is skipped. */
html.op-pending #opening { display: block; }

/* While it is up, the overlay swallows clicks, and scrolling is held. There is
   no skip any more, so nothing underneath should be reachable for the few
   seconds it plays. Both are released when opening.js drops .op-pending. */
html.op-pending #opening,
#opening.playing { pointer-events: auto; }

html.op-pending, html.op-pending body { overflow: hidden; }

html.op-pending #opening::before,
#opening.playing::before {
  content: '';
  position: absolute;
  inset: 0;
  background: var(--bg);
  opacity: 1;
  transition: opacity 300ms ease-out;
}
/* Ground holds until the wordmark lands. The page arrives at that moment,
   not during the flight. */
#opening.playing.clearing::before { opacity: 0; }

/* The wordmark starts huge and centred, then flies to the eyebrow slot.
   It is positioned on top of the real eyebrow and inverted with a
   transform, so it lands exactly on it with no measuring drift. */
/* Font, weight, tracking and case are all copied from the real eyebrow at
   runtime so the two can never drift apart. Origin is top left: the mark is
   rendered at full size and scaled DOWN to the eyebrow, which keeps the type
   crisp. Scaling a small base up rasterises at the small size and blurs. */
.op-mark {
  position: fixed;
  z-index: 2;
  color: var(--y);
  white-space: nowrap;
  opacity: 0;
  transform-origin: left top;
  will-change: transform, opacity;
}
/* The flight itself is driven by the Web Animations API in opening.js.
   It has to be: the starting transform is an inline style, and only an
   animation outranks that. A class rule setting `transform` here would be
   silently ignored. */
.op-mark.in { opacity: 1; transition: opacity 300ms ease-out; }
/* Hand over to the real eyebrow with a short dissolve. Glyphs rasterised at
   175px and scaled down are not identical to natively rendered 12px text, so
   this absorbs any hairline difference instead of snapping. */
.op-mark.out { opacity: 0; transition: opacity 170ms linear; }

.op-field { position: absolute; inset: 0; }

.op-snip {
  position: absolute;
  white-space: nowrap;
  color: rgba(240,240,240,0.26);
  font-family: var(--sans);
  opacity: 0;
  transform: translateY(3px);
  animation: op-pop 220ms ease-out forwards;
  transition: color 900ms linear;
}
.op-snip span { color: var(--y); font-weight: 700; }

/* Late phase: the grey recedes, the dashes are what is left standing. */
.op-field.dashes .op-snip { color: rgba(240,240,240,0.035); }

@keyframes op-pop { to { opacity: 1; transform: none; } }

/* The field is erased progressively from the left, tracking the sweep, so
   the dashes disappear as it passes over them rather than all at once. */
.op-field.wiping { animation: op-wipe 1100ms cubic-bezier(.45,0,.25,1) forwards; }

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

.op-sweep {
  position: absolute;
  top: -10%;
  bottom: -10%;
  width: 22%;
  left: -30%;
  opacity: 0;
  transform: skewX(-9deg);
  background: linear-gradient(90deg, transparent, rgba(255,214,0,0.10),
    rgba(255,214,0,0.9), #fff8dc, rgba(255,214,0,0.10), transparent);
}
.op-sweep.on { animation: op-sweep 1100ms cubic-bezier(.45,0,.25,1) forwards; }

@keyframes op-sweep {
  0%   { left: -30%; opacity: 0; }
  10%  { opacity: 1; }
  90%  { opacity: 1; }
  100% { left: 108%; opacity: 0; }
}

@media (prefers-reduced-motion: reduce) {
  #opening { display: none !important; }
}
