/* ====================================================================
   CROSS-DOCUMENT VIEW TRANSITIONS  —  marketing pages only
   Added 2026-07-30.
   ====================================================================
   This is the browser doing the page transition properly: it snapshots
   the old document, loads the new one, and animates between the two. No
   JS, no navigation delay we impose ourselves, and — the part the
   hand-rolled veil could never do — the header can be declared as the
   SAME element on both pages, so it stays put while the content beneath
   it changes. That is what makes it read as one site rather than as a
   sequence of page loads.

   WHY IT IS ITS OWN FILE AND NOT PART style.css. `@view-transition` is a
   document-level at-rule: it cannot be scoped to a selector, so putting
   it in the shared stylesheet would switch it on for the signed-in app
   too. The app deliberately has no transitions — a wipe between tools is
   a delay paid on every click, and CLAUDE.md records that as a decision,
   not an omission. Link this file from a marketing page only.

   THE FALLBACK. js/page-transition.js still plays its gold scan-line veil
   in browsers with no cross-document support, and stands down where this
   works, so the two never run at once. A browser that reports the
   same-document API but lacks the cross-document one gets neither: an
   ordinary, instant navigation. That is a real if narrow gap, and it is
   the right way round — the failure mode is "no flourish", never "no
   navigation".

   DURATIONS. 300ms out / 380ms in, in the same range as the veil it
   replaces and for the same reason: this sits between a click and the
   page somebody actually asked for.  */

@view-transition { navigation: auto; }

/* The old page falls back and dims; the new one rises into place. Both
   are transform+opacity only, which is what keeps this on the compositor
   — a transition that drops frames is worse than no transition. */
@keyframes pt-vt-old {
  from { opacity: 1; transform: none; }
  to   { opacity: 0; transform: translateY(-10px) scale(0.994); }
}
@keyframes pt-vt-new {
  from { opacity: 0; transform: translateY(14px) scale(0.996); }
  to   { opacity: 1; transform: none; }
}

::view-transition-old(root) {
  animation: pt-vt-old 300ms cubic-bezier(.4,0,.7,.2) both;
}
::view-transition-new(root) {
  animation: pt-vt-new 380ms cubic-bezier(.2,.8,.3,1) both;
}

/* The chrome that should NOT move. Naming an element on both pages makes
   the browser treat the two as one thing and hold it still (or tween it,
   if it moved) instead of cross-fading it with the page. A header that
   fades out and back in on every click is the tell that a "transition"
   is really just a fade of two screenshots.

   Every name here must be unique within a page — one header, one footer
   mark, one progress line, so all three are safe. */
/* `.site-head`, not `header:not(.app-head)`. Same correction as the
   stylesheet: naming everything-except-one is a claim about every other
   <header> in the codebase, and admin.html alone has 34 of them. It is
   worse here than anywhere else, because `view-transition-name` MUST BE
   UNIQUE within a page — two elements sharing one name makes the browser
   abandon the whole transition, so a single extra <header> on a marketing
   page would silently turn the feature off site-wide. */
/* ==== THE HEADER IS NOT NAMED, AND THAT IS THE GLASS BUG =============
   `header.site-head { view-transition-name: site-header }` lived here from
   2026-07-30. It is why the dock had NO BLUR on every device, for weeks,
   through four separate attempts to fix "the glass".

   AN ELEMENT WITH A view-transition-name IS CAPTURED INDEPENDENTLY, WHICH
   MAKES IT A BACKDROP ROOT. `backdrop-filter` filters what is painted
   behind the element WITHIN its backdrop root — and for anything inside a
   named element, that root is the named element itself. There is nothing
   behind it in there. So the filter runs against an empty backdrop and
   produces exactly nothing: not a weak frost, no frost, on every engine
   that supports view transitions.

   PROVEN BY A/B, because three previous explanations for this were wrong.
   Two pages identical in every respect — same stylesheet, same island
   markup, same js/main.js, a large sharp headline behind the dock —
   differing only in whether the header carried a view-transition-name:

     named   -> the headline reads perfectly sharp THROUGH all three
                islands. This reproduces the reported screenshots exactly.
     unnamed -> the same headline is smeared to an unreadable wash inside
                the islands and stays sharp one pixel outside them.

   WHY REMOVING IT IS THE RIGHT TRADE. The name existed so the header held
   still while the page changed underneath it, which is worth about 380ms
   of polish on each internal navigation. Unnamed, the header cross-fades
   with the page — and since it is identical and in the same place on both
   pages, that fade is very close to invisible. The glass, by contrast, is
   on screen the entire time somebody is on the site. A permanent effect
   beats a transient one.

   DO NOT PUT A view-transition-name BACK ON THE HEADER, or on `nav.wrap`,
   or on any other ancestor of the islands, to get the stillness back. It
   will take the blur with it and the symptom will look like a CSS problem
   in the stylesheet, which is where the last four attempts went looking.

   `.scroll-progress` keeps its name: it is a 2px bar with no
   backdrop-filter anywhere inside it, so it has nothing to lose. */
.scroll-progress { view-transition-name: site-progress; }

/* Hold it completely still rather than letting the default group
   animation tween a 1px difference into a visible twitch. */
::view-transition-group(site-progress) { animation-duration: 0s; }
::view-transition-new(site-progress) { animation: none; mix-blend-mode: normal; }

/* ==== THE OLD SNAPSHOT IS DISCARDED, NOT HELD STILL (2026-08-06) ======
   Old and new were both given `animation:none`, which does NOT mean "show
   one of them" — neither animates away, so BOTH paint, one over the other,
   for the whole transition. On opaque chrome that is invisible and can sit
   there for months; on a translucent pane it composites the tint twice.

   THE `site-header` RULES THAT USED TO SIT HERE ARE GONE WITH THE NAME.
   The note they carried is worth keeping, though, because it turned out to
   be the whole bug in miniature and I did not notice: it already said that
   "a view-transition snapshot cannot carry backdrop-filter — the element is
   painted into an isolated layer with no backdrop to sample". That was
   written about the ~380ms of a navigation. The same sentence is true of a
   named element ALL THE TIME, which is why the dock never blurred at all.
   The observation was correct and its scope was wrong. */
::view-transition-old(site-progress) { display: none; }

/* Reduced motion: the transition is switched off at the source rather
   than given a 0s duration, so no snapshot is taken and nothing can be
   left half-composited. */
@media (prefers-reduced-motion: reduce) {
  @view-transition { navigation: none; }
}
