/* light-ring.css — the stage the one ring lives on.

   Everything here is geometry for js/light.js, and the one line of text it can
   show. Nothing here is a glow: the glow is a gradient the script bakes and
   sets on each orb, so there is no filter and no blur anywhere in this file,
   and nothing for the compositor to recompute while the orbs move. */

/* Fixed, over the page and under the navbar (chrome.css gives it 1000).
   pointer-events: none is what lets a click reach the download button
   through the ring. (The one exception is the disc-sized target on the buttons
   of a list that wants the orbs, further down.)

   The stage is a point, not a surface: zero by zero at the corner, with the
   orbs overflowing from it. The site records session replays, and a replay
   records every style change on every node it can see — eight orbs rewritten
   sixty times a second is a flood the recorder has to rate-limit and
   complain about. While the ring moves, the script marks the stage
   ph-no-capture, the class that keeps an area out of the recording
   (js/site-analytics.js). A blocked area is replayed as a placeholder of its
   own size, so a stage the size of the screen would replay as a screen-sized
   placeholder laid over the page. A point replays as nothing. A fixed box's
   overflow never makes the page scroll sideways, which is why it needs no clip. */
.light-stage {
  position: fixed;
  left: 0;
  top: 0;
  width: 0;
  height: 0;
  z-index: 10;
  pointer-events: none;
}

/* For a reader who asked for no motion the ring is the top of the page, not a
   fixture on the screen: it scrolls away with the text instead of staying
   pinned above it, which needs no script running while they scroll. Nothing
   moves, so there is nothing for a replay to log and the ring is recorded like
   the rest of the page. Unlike a fixed box, an absolute one does widen the
   page when a 264px sprite hangs past the edge of a phone, so this one is the
   width of the screen and clips sideways.

   It does not clip downward. The orbs this ring lends to a figure sit on the
   page, where the figure is, and that is below the first screen; a figure is
   always inside the document, so an orb hanging below the box adds no length
   to it. */
.light-stage.is-still {
  position: absolute;
  inset: 0;
  width: auto;
  height: auto;
  overflow-x: clip;
  overflow-y: visible;
}

/* The orb is a square wide enough that its gradient reaches alpha 0 before the
   edge, so the box itself is never visible. The script sizes it and moves it;
   only transform and opacity ever change.

   The glow is a layer of its own, and an orb has two: its own colour and the
   colour of the place it has been lent to, traded one for the other as it
   goes. Fading one layer and not the disc is also how a glow can be dimmer
   than the disc it surrounds. */
.light-orb {
  position: absolute;
  left: 0;
  top: 0;
  will-change: transform, opacity;
}

.light-glow {
  position: absolute;
  inset: 0;
  background-repeat: no-repeat;
}

/* The disc is white. Always. Its colour is the glow around it, not its fill. */
.light-core {
  position: absolute;
  left: 50%;
  top: 50%;
  border-radius: 50%;
  background: #fff;
  transform: translate(-50%, -50%);
}

/* The band: the room at the top of the column that the ring is drawn in.

   The stylesheet opens it, not the script. A band the script opened would be
   missing from the first paint and shove the whole first screen down 140 to
   225px when the module ran, which measured 0.12 to 0.20 of layout shift on a
   phone and a tablet. So it is in the CSS, and three conditions keep it from
   ever being empty:

   - (scripting: enabled): a reader without scripts has no ring to put in it,
     so for them the page starts where it always did.
   - screen: paper has no ring either.
   - html.has-ring: markup puts the class on <html>, and js/light.js takes it
     off again if it throws, so a ring that fails gives the room back. A ring
     that never arrives cannot do that, so the script tag does it: every page's
     tag for light.js has an onerror that takes the class off and says
     data-light-ready="failed", which fires when the file or anything it
     imports is missing (a 404 on glow.js does it as well as one on light.js).
     The script also checks for scripting itself and draws nothing in a browser
     that does not know the feature.

   html.has-ring main is 0,1,2. That beats main.read (0,1,1) and the
   .editorial-main and .guides-main rules (0,1,0) that set this padding on the
   three kinds of page, without !important. The phone rule below comes second
   and has the same weight, so it wins by order. */
@media screen and (scripting: enabled) {
  html.has-ring main { padding-top: 34vh; }
}
@media screen and (scripting: enabled) and (max-width: 767.98px) {
  html.has-ring main { padding-top: 26vh; }
}

/* The scrim: where a line of text ends when the ring is holding the band.

   The ring keeps the top of the screen while the reader goes down, so the
   words arrive under it. Without this they meet it at full brightness and the
   orbs read as dots dropped on a paragraph. This is the page's own black,
   solid where the band begins and gone where it ends, so a line fades out as
   it slides under the ring rather than being cut off by it.

   Not a filter and not a blur: one fixed layer whose only changing property is
   opacity, which is what lets the compositor keep it. It is the ring's, not
   the page's — js/light.js builds it, sizes it to the band and fades it with
   the ring, so a page whose ring never arrives has no dark strip at the top.
   It sits under the stage's z-index 10 and over the text, and takes no
   pointer: a click goes through it to the words. */
.light-scrim {
  position: fixed;
  left: 0;
  top: 0;
  width: 100%;
  z-index: 9;
  pointer-events: none;
  background: linear-gradient(
    to bottom,
    var(--bg, #000) 0%,
    var(--bg, #000) 38%,
    rgba(0, 0, 0, 0.72) 62%,
    rgba(0, 0, 0, 0) 100%);
}
