/* Page intro (resources/intro.js, owner request 2026-10-09).
 *
 * The inline head script marks <html data-intro="pending" data-intro-page="…"> before the first paint
 * when JavaScript runs and motion is allowed. Only under that marker are the entering elements hidden,
 * and only by opacity: their boxes, focus, pointer input and accessible names stay as they are. If the
 * script has not taken over 1 s after they were first styled (about the first paint: a CSS animation
 * delay counts from then), the failsafe animation reveals them (intro.js FAILSAFE_MS); the script
 * takes over on its first run (the cascade does not wait for fonts or the other scripts). Without
 * JavaScript or with reduced motion nothing is hidden at all.
 * Glass is never held (review round 2, 2026-10-09: a fading glass showed the Semax sculpture behind it
 * unfrosted for ~250 ms on narrow windows and phones): on a page with a scene (body[data-scene-page])
 * the Database table glass (.dbwrap) frosts the scene from the first paint and only the table inside
 * it is held, and the filter chips other than the active one and the filter input are glass too
 * (atlas.css, same selectors), so only their labels are held there — text colour and placeholder, for
 * the same 1 s (the hold animation is its own failsafe) — and intro.js fades the labels in. Without a
 * scene the table box is an opaque card, held and entering with its table as one piece (review
 * 2026-10-09 polish: drawn empty from the first frame, the page built up from the bottom). The Compound
 * tree's shell is glass over its scene the same way (page scenes 2026-10-10): there only the tree and the
 * status bar inside it are held; without a scene the shell card is held as one piece. */
@media (prefers-reduced-motion: no-preference) {
  :root[data-intro="pending"][data-intro-page="home"] .utility-hero :is(#home-title, .utility-kicker, .kicker,
    .utility-description, .utility-search, .search, .utility-routes, .utility-tools),
  :root[data-intro="pending"][data-intro-page="home"] main#main-content > .archive-content > section,
  :root[data-intro="pending"][data-intro-page="database"] main#main-content > :is(h1, .lede, #filter-count),
  :root[data-intro="pending"][data-intro-page="database"] body:not([data-scene-page]) main#main-content > :is(.filters, .filterq, .dbwrap),
  :root[data-intro="pending"][data-intro-page="database"] body[data-scene-page] main#main-content > .filters > button.on,
  :root[data-intro="pending"][data-intro-page="database"] body[data-scene-page] main#main-content > .dbwrap > table,
  :root[data-intro="pending"][data-intro-page="tree"] main#main-content > :is(.kicker, h1, .lede),
  :root[data-intro="pending"][data-intro-page="tree"] body:not([data-scene-page]) main#main-content > :is(.tree-shell),
  :root[data-intro="pending"][data-intro-page="tree"] body[data-scene-page] main#main-content > .tree-shell > :is(.tree, .treebar),
  :root[data-intro="pending"][data-intro-page="stacks"] main#main-content > :is(h1, .lede, .stackgrid) {
    opacity: 0;
    animation: rc-intro-failsafe 1ms linear 1s both;
  }
  :root[data-intro="pending"][data-intro-page="database"] body[data-scene-page] main#main-content > .filters > button:not(.on),
  :root[data-intro="pending"][data-intro-page="database"] body[data-scene-page] main#main-content > .filterq,
  :root[data-intro="pending"][data-intro-page="database"] body[data-scene-page] main#main-content > .filterq::placeholder {
    animation: rc-intro-hold-ink 1s linear;
  }
}
/* The Stacks page over its scene (page scenes 2026-10-10): the stack cards are glass there (atlas.css), so the grid
   is never held — only the cards' kicker, title and line are, for the same 1 s — and intro.js brings those in, in
   the cards' cascade (PAGES.stacks `inside`). Without a scene the grid is held as above and the cards enter whole. */
@media (prefers-reduced-motion: no-preference) {
  :root[data-intro="pending"][data-intro-page="stacks"] body[data-scene-page] main#main-content > .stackgrid {
    opacity: 1;
    animation: none;
  }
  :root[data-intro="pending"][data-intro-page="stacks"] body[data-scene-page] main#main-content > .stackgrid > .stackcard > :is(em, strong, span) {
    opacity: 0;
    animation: rc-intro-failsafe 1ms linear 1s both;
  }
}
@keyframes rc-intro-failsafe {
  from { opacity: 0; }
  to { opacity: 1; }
}
@keyframes rc-intro-hold-ink {
  from, to { color: transparent; }
}

/* The heading keeps its own text (layout box, accessible name) and paints it transparent while the
   aria-hidden overlay of positioned glyphs animates above it; both go as soon as its text is final (a
   typing caret then blinks and fades out by itself). The premium designs set every element's family
   with !important, so the overlay re-inherits the heading's. */
:root .rc-intro-relative { position: relative; }
:root .rc-intro-host { color: transparent !important; text-shadow: none !important; }
/* while the heading waits for its own font (intro.js, at most 450 ms): held like under the marker above */
:root .rc-intro-wait { opacity: 0 !important; }
:root .rc-intro-layer,
:root .rc-intro-layer * { font-family: inherit !important; }
.rc-intro-layer {
  position: absolute;
  top: 0;
  left: 0;
  width: 0;
  height: 0;
  pointer-events: none;
  user-select: none;
  white-space: pre;
}
.rc-intro-line,
.rc-intro-ch,
.rc-intro-ink,
.rc-intro-glyph { position: absolute; display: block; white-space: pre; }
.rc-intro-clip .rc-intro-line { overflow: hidden; }
.rc-intro-ch[data-ch]::before,
.rc-intro-ink::before,
.rc-intro-glyph::before { content: attr(data-ch); }
.rc-intro-ink { top: 0; left: 0; }
/* decode: other letters of the heading's own face, size and weight (capitals: one-letter element
   symbols), dimmed and centred in the box of the letter they resolve into, take turns until it locks
   (intro.js). Hidden unless an animation shows them, so the cut to the letter needs no crossfade
   (review round 2, 2026-10-09: small accent mono digits read as a numeric readout). intro.js picks
   glyphs no wider than the letter, and each is clipped to its letter's box at the sides (not above or
   below it): the neighbours' glyphs show at once at half ink, and wherever two overlapped (tight
   tracking makes a box narrower than its letter) their strokes added up into bright lenses and seams
   (review 2026-10-09 polish). */
.rc-intro-glyph {
  inset: 0;
  opacity: 0;
  color: color-mix(in srgb, currentColor 50%, transparent);
  text-shadow: none;
  letter-spacing: 0;
  text-align: center;
  clip-path: inset(-0.5em 0);
}
/* type: a thin text caret in the accent, cap height, leading the letters */
.rc-intro-caret {
  position: absolute;
  top: 0;
  left: 0;
  display: block;
  border-radius: 1px;
  background: var(--hero-accent, var(--blue, currentColor));
}
