/* ---- What a screen shows while it is finding out ----
   Why only the list screens have one, and why there is one shape and not five,
   is in src/views/skeleton.ts. This is the drawing, and there is very little of
   it: the arrangement borrows .cb-table from the real screen, so padding, row
   heights, borders and radii are inherited rather than copied. Only the shapes
   belong to this file. */

/* THE GRACE PERIOD IS THIS RULE, and it is the whole anti-flicker mechanism.

   A stand-in fades in after --cbc-grace rather than appearing with the request.
   Almost every call this console makes comes back inside that window, so almost
   every stand-in is never seen at all: the element is in the document, holding
   its space, at opacity zero, and the real content replaces it before the
   animation's delay is up. What used to happen instead was one frame of grey on
   every navigation, which read as the page breaking rather than as it loading.

   BACKWARDS, NOT BOTH. The fill has to hold opacity 0 BEFORE the animation
   starts, which is what backwards does and what makes the delay a grace period
   rather than a flash followed by a fade. `both` would also pin the end value
   and outrank everything else on the element for the rest of its life. */
.cb-stand-in {
  display: grid;
  gap: var(--cb-space-2xl);
  animation: cbc-fade var(--cb-motion-base) var(--cb-motion-ease) backwards;
  animation-delay: var(--cbc-grace);
}
/* A grid item will not shrink below its contents without this, and one of the
   things put inside a stand-in is a table. The submissions stand-in pushed its
   own last two columns off the side of the card until this was here. */
.cb-stand-in > * {
  min-inline-size: 0;
}

/* ---- One shape ----
   A line. There is nothing else, and nothing carries a size that means
   "heading" or "badge": see skeleton.ts for why those went.

   FLAT NEUTRAL GREY (--cbc-stand, console-theme.css). No hue, low contrast. A
   skeleton is the absence of content, and the moment it carries a colour it
   starts reading as content of its own.

   THIN. A shape the height of a line of type reads as type that failed to
   render. A thin rule in the same place reads as a place where type is going,
   which is the difference between a mockup and a broken page.

   THE NAME IS cb-stand-mark RATHER THAN cb-bar because .cb-bar was already the
   scoring weight meter in console-panels.css, fixed at 320px wide and 8px tall.
   Reusing it silently gave every shape those exact dimensions.

   ---- The sheen ----

   THE ONE GRADIENT IN THIS CONSOLE. docs/10 is otherwise off them; a sweep is
   the exception because it is how every application anybody would compare this
   to says "still working" without words.

   ONE SURFACE, NOT THIRTY. The band is a repeating tile of a FIXED WIDTH, so
   its highlight travels the same distance in the same time on a shape of any
   length: a table row and a card body sweep at one speed, and a screenful reads
   as a single surface being scanned. The recipe everybody publishes is a
   two-hundred-percent gradient animated across each element, and it is wrong
   for exactly this reason: percentages are of the element, so a short shape
   sweeps fast, a long one crawls, and the page reads as thirty things each
   doing its own thing.

   AND ONLY ON THE SHAPES. An overlay on the container would sweep a band
   across the gaps between them too, which is a searchlight passing over the
   page rather than a surface waking up.

   A PASS, THEN A BEAT, rather than a band crawling round forever at one speed.

   Linear was the first answer and the reasoning was sound as far as it went: a
   sweep that eases looks like it stops at each end, and this one has no ends,
   because the tile is exactly as wide as the distance travelled. What that
   argument misses is that a highlight moving at a constant speed with no pause
   in it is a conveyor belt. Nothing in the physical world that sweeps does it
   at one speed and immediately again.

   So the band waits, crosses quickly, and settles: the tile holds at its start
   for the first fifth of the loop and then travels the whole width on the
   board's own settling curve. The loop is still seamless, because it still
   moves exactly one tile, and the hold is invisible as a jump for the same
   reason: the picture at rest and the picture at the end of the pass are the
   same picture.

   WHITE IN BOTH THEMES. The resting grey is tuned per theme and the two are
   different numbers (console-theme.css); the band is not, because a highlight
   adds light whichever way round the page is. On the dark ground it lifts a
   mark further off the page and on white it washes one toward it, and both of
   those read as a shine crossing a surface. */
.cb-stand-mark {
  display: block;
  inline-size: var(--w, 100%);
  block-size: var(--cb-space-md);
  border-radius: var(--cb-radius-full);
  background-color: var(--cbc-stand);
  /* A band with flat either side of it, not a hump filling the tile. Spread
     across the whole 640 the highlight is a slow swell with no edges and reads
     as the shape changing brightness; held inside the middle third it is an
     object passing along it, which is the thing being said. */
  background-image: linear-gradient(90deg, transparent 34%, var(--cbc-sheen) 50%, transparent 66%);
  background-repeat: repeat-x;
  /* Wider than most shapes, so what crosses a row is one band and not stripes. */
  background-size: var(--cb-width-lg) 100%;
  animation: cbc-sheen var(--cbc-loop-calm) var(--cbc-spring) infinite;
}
/* The tile moves by exactly its own width, so the loop is seamless: the frame
   before it restarts and the frame after it are the same picture. The first
   fifth is the beat between passes. */
@keyframes cbc-sheen {
  0%,
  20% {
    background-position-x: 0;
  }
  100% {
    background-position-x: var(--cb-width-lg);
  }
}

/* ---- Inside a table ----
   The shape is a span in a cell, so it sits on the middle of the line the row
   is built around rather than on the bottom of its line box. */
.cb-table td .cb-stand-mark {
  display: inline-block;
  vertical-align: middle;
}

/* ---- Asked to stop ----
   THE SHEEN HAS TO BE TAKEN OFF RATHER THAN SPED UP. The global reduce rule in
   console-theme.css cuts every duration to a millisecond, which for a sweep
   does not stop it: it freezes the tile wherever the first frame left it, and
   every shape on the screen is then a gradient with a bright patch stuck
   somewhere along it. The image goes entirely and the flat grey is what
   remains, which is what the shape is for.

   That global rule also cuts every delay to nothing, which has one consequence
   worth saying out loud: with no delay there is no grace period, so somebody
   who asked for less motion sees the stand-in immediately on every load rather
   than only on the slow ones. That is the right trade. The alternative is
   holding an empty screen for a quarter of a second and calling it calm, and a
   person who cannot see the fade has no way to tell that from nothing at all. */
@media (prefers-reduced-motion: reduce) {
  .cb-stand-mark {
    background-image: none;
  }
}
/* And the console's own switch, which is a separate question from the system's:
   somebody may want their photos to animate and their work tool to sit still. */
:root[data-motion="reduced"] .cb-stand-mark {
  background-image: none;
}

/* ---- A line of writing, in a row the height of the type that goes there ----
   (`row()` in views/skeleton.ts.) The mark stays the same thin line every other
   piece of writing gets; what changes is the room held open around it. Without
   this a heading set in the large face was stood in for by eight pixels of
   grey, and everything below it sat twenty pixels too high until the real
   screen landed and pushed it all down. Same argument as the tile rows above,
   generalised so no other arrangement has to make it again. */
.cb-stand-line {
  display: flex;
  align-items: center;
  inline-size: 100%;
}
.cb-stand-line[data-size="xs"] {
  block-size: var(--cb-type-xs-line-height);
}
.cb-stand-line[data-size="sm"] {
  block-size: var(--cb-type-sm-line-height);
}
.cb-stand-line[data-size="base"] {
  block-size: var(--cb-type-base-line-height);
}
.cb-stand-line[data-size="lg"] {
  block-size: var(--cb-type-lg-line-height);
}

/* ---- Standing in for a list screen (views/list-standin.ts) ----
   Three blocks in the real screen's own containers: the summary ladder, the
   toolbar, then the card. The gap is the page flow's rather than the stand-in's
   default, or the three blocks would sit closer together than the three they
   are standing in for and the whole screen would shift as it landed. */
.cb-stand-in:has(> .cb-funnel) {
  gap: var(--cbc-flow-gap);
}
/* The split bar under the ladder. It is a mark like any other; what it takes
   from the bar is its height and the room it fills. */
.cb-stand-spread {
  flex: 1 1 var(--cb-width-xxs);
  block-size: var(--cb-space-lg);
}
/* A mark in a flex row has no width of its own to be a share of, so the three
   that sit in one are told how much to take. Roughly what the words they stand
   in for take, which is all a promise about a toolbar has to be. */
.cb-stand-in .cb-listbar-views .cb-stand-line {
  inline-size: var(--cb-space-9xl);
}
.cb-stand-in .cb-listbar > .cb-filters .cb-stand-line {
  inline-size: var(--cb-space-10xl);
}
.cb-stand-in .cb-listbar > .cb-count .cb-stand-line {
  inline-size: var(--cb-space-8xl);
}
/* The pager's own line sits at its start rather than being stretched across it. */
.cb-stand-in .cb-pager .cb-stand-line {
  inline-size: var(--cb-space-11xl);
}
