/* scroll-timeline.css — keep the pack's scroll-driven animations alive.
 *
 * WHAT BREAKS THEM. `animation-timeline: view()` measures an element's progress
 * inside its nearest *scroll container*. Any ancestor with `overflow` set to
 * hidden, auto or scroll is one — including an ancestor that never actually
 * scrolls. When that happens the element's position inside that box never
 * changes, progress is constant, and the animation sits frozen at one frame
 * with `both` fill. Nothing errors. It simply stops moving.
 *
 * That is not hypothetical. Two separate instances were measured on this site:
 *
 *   1. `body{overflow-x:hidden}` in the pack's reset. Setting one overflow axis
 *      to hidden forces the other to compute to `auto`, so body became a scroll
 *      container — one that never scrolls, because the page scrolls on <html>.
 *      Every reveal, pop and draw on every page was pinned. 852 effects.
 *
 *   2. The section wrappers, which set `overflow:hidden` inline to clip
 *      decorations against their rounded edges. With body fixed, these became
 *      the nearest scroll container for the 135 effects inside them.
 *
 * THE FIX is `overflow: clip`. It clips identically — same box, same rounded
 * corners — but is explicitly NOT a scroll container, so `view()` walks past it
 * to the real one. It is also stricter than hidden: the box cannot be scrolled
 * programmatically either, which quietly fixes the "focusing an off-screen
 * child scrolls a hidden overflow" bug.
 *
 * WHY A SEPARATE STYLESHEET rather than editing the pack. `body.html` and
 * `design.css` are generated by `npm run convert:design`, and the redesign that
 * §8 of CLAUDE.md is waiting on will arrive with `overflow:hidden` written back
 * into every section. A rule here survives that; an edit to the pack does not.
 *
 * WHY IT IS NARROW. The selector only touches elements whose *inline* style
 * says `overflow:hidden` AND that actually contain a scroll-driven effect. A
 * genuine scroller — the mobile nav drawer, the campus day rail, the CAPE pin —
 * declares `overflow-x:auto` or `overflow-y:auto` and is never matched. The
 * `!important` is needed only because the declaration it overrides is inline.
 *
 * THE ONE REAL DIFFERENCE between hidden and clip is that clip does not
 * establish a block formatting context, so a child's vertical margin can
 * escape through the top of the box where hidden used to trap it. That is not
 * theoretical either: measuring every top-level block on 27 pages caught
 * /programs/pre-k rising 8px and /visit dropping 8px. `display: flow-root`
 * gives back the formatting context on its own, with none of the overflow
 * semantics that caused the original problem.
 *
 * `flow-root` is deliberately NOT !important. Several of these sections set
 * `display:grid` or `display:flex` in their inline style, and an inline
 * declaration beats an ordinary stylesheet one — so those keep their own
 * layout and only plain block sections take the flow-root. (Grid and flex
 * containers already establish an independent formatting context, so there is
 * nothing to restore for them.) `overflow` does need !important, because the
 * declaration it has to beat is inline too.
 *
 * With both, every one of the 344 blocks measured across 27 pages lands on the
 * same pixel it did before. See WORK_COMPLETED.md.
 */

body { overflow-x: clip; }

.page [style*="overflow:hidden"]:has([data-rv], [data-draw], [data-pop]) {
  overflow: clip !important;
  display: flow-root;
}
