/* ==========================================================================
   panel.css — THE OVERRIDE LAYER.

   READ THIS BEFORE EDITING EITHER THIS FILE OR site.css.

   Load order, always: tokens.css, site.css, THIS FILE LAST. This file is
   designed to win where it overlaps site.css — that is its whole contract —
   and build.py's check_nothing_hidden_without_a_revealer() asserts the order
   from the emitted <link> tags of every page, so an accidental reorder
   breaks the build rather than the design.

   ⚠️ EVERY CUSTOM PROPERTY BELOW IS ONE tokens.css ALREADY DEFINES. An
   undefined var() does not fall back — it deletes the whole declaration —
   so a private token invented here would silently strip the rule that uses
   it. Define new tokens in tokens.css, never here.

   THE ONLY THING THIS FILE HIDES: `.rise`, and ONLY when `html.js` is
   present (added by an inline script in build.py's page template BEFORE
   this stylesheet loads, so there is no flash of the wrong state on a
   JS-capable browser). Content-visible-by-default lives in site.css; this
   file is what turns that into a scroll reveal WHEN a script exists to
   un-hide it — assets/js/main.js's `rise()` behaviour adds `.in` on
   intersection. check_nothing_hidden_without_a_revealer() fails the build
   if this file ever hides a class with no matching revealer in assets/js/.
   ========================================================================== */

html.js .rise {
  opacity: 0;
  transform: translateY(16px);
  transition: opacity var(--dur-med) var(--ease), transform var(--dur-med) var(--ease);
}
html.js .rise.in {
  opacity: 1;
  transform: none;
}

/* prefers-reduced-motion: the reveal still happens (content is not gated
   behind scroll for a reduced-motion visitor), it just does not animate. */
@media (prefers-reduced-motion: reduce) {
  html.js .rise,
  html.js .rise.in {
    transition: none;
  }
}
