/**
 * dud-motion.css
 * DUD® Motion System — CSS Transition Layer
 * Version: 11.0.0
 *
 * ─── OWNERSHIP CONTRACT ───────────────────────────────────────────────────
 *   CSS OWNS:
 *     • All visual transitions (opacity, transform)
 *     • Initial hidden states (.dud-entrance--[type])
 *     • Revealed state (.dud-revealed) — opacity: 1, transform: none
 *     • in-flight guard (.dud-in-flight)
 *     • Easing, duration, distance — consumed from CSS custom properties
 *
 *   JS SUPPLIES (via el.style.setProperty()):
 *     --dud-reveal-duration   — computed from token × intensity multiplier
 *     --dud-reveal-easing     — easing cubic-bezier string
 *     --dud-entrance-dist     — entrance offset distance in px
 *
 *   JS NEVER WRITES:
 *     • opacity inline
 *     • transform inline
 *     • Any layout property (top, left, width, height)
 *
 * ─── TWO-PHASE REVEAL GUARANTEE ──────────────────────────────────────────
 *   Phase 1 (JS sets props + adds entrance class):
 *     The entrance class applies initial transform + opacity: 0.
 *     The element is now in its hidden/offset starting position.
 *   Phase 2 (JS adds .dud-revealed in next RAF frame):
 *     The transition defined here fires, animating from the entrance
 *     state to the revealed state (opacity: 1, transform: none).
 *
 * ─── OLED SAFETY ─────────────────────────────────────────────────────────
 *   Pure obsidian (#000000) site requirement.
 *   All entrance states set opacity: 0 — never partially transparent on
 *   black. No intermediate opacity values that could cause a visible
 *   "flash" against an OLED black background.
 *   The .dud-in-flight guard prevents .dud-revealed from being present
 *   simultaneously with an entrance class in the same frame.
 *
 * ─── GPU COMPOSITING ─────────────────────────────────────────────────────
 *   Only transform and opacity are animated — both are compositor-only
 *   properties on all modern browsers. No layout-triggering properties
 *   (top, left, width, height, margin) are animated under any condition.
 *   will-change is applied sparingly and only to entrance states.
 *
 * ─── REDUCED MOTION ──────────────────────────────────────────────────────
 *   prefers-reduced-motion: reduce completely disables all transitions.
 *   JS also calls drainImmediate() on this condition, but CSS provides
 *   the redundant safety layer regardless of JS execution state.
 */

/* ═══════════════════════════════════════════════════════════════════════════
   SECTION 1 — CSS CUSTOM PROPERTY DEFAULTS
   ═══════════════════════════════════════════════════════════════════════════
   These are the fallback values. JS overwrites per-element before reveal.
   The fallbacks ensure correct behavior if JS is slow or fails silently. */

:root {
  --dud-reveal-duration:   600ms;
  --dud-reveal-easing:     cubic-bezier(0.25, 0.46, 0.45, 0.94);
  --dud-entrance-dist:     24px;
}

/* ═══════════════════════════════════════════════════════════════════════════
   SECTION 2 — IN-FLIGHT GUARD
   ═══════════════════════════════════════════════════════════════════════════
   Applied by JS in Phase 1 frame. Removed in Phase 2 frame just before
   .dud-revealed is added. Prevents a frame where both entrance class and
   .dud-revealed are present simultaneously — which would cause a zero-frame
   "flash" from the entrance offset directly to the revealed state. */

.dud-in-flight {
  /* No visual effect — purely a structural guard class.
     Do not add opacity or transform here; entrance class handles that. */
  pointer-events: none;
}

/* ═══════════════════════════════════════════════════════════════════════════
   SECTION 3 — ENTRANCE TYPE CLASSES (HIDDEN/OFFSET INITIAL STATE)
   ═══════════════════════════════════════════════════════════════════════════
   Each entrance class defines WHERE an element starts before reveal.
   The transition FROM this state to .dud-revealed is defined in Section 4.
   will-change on entrance state only — removed when .dud-revealed is present. */

/* fade-up: primary DUD entrance — rises from below with fade.
   Used by ARRIVAL and DESCENT chapters. */
.dud-entrance--fade-up {
  opacity: 0;
  transform: translateY(var(--dud-entrance-dist));
  will-change: opacity, transform;
}

/* fade: pure opacity reveal — no movement.
   Used by REVEAL and COMMERCE chapters. */
.dud-entrance--fade {
  opacity: 0;
  will-change: opacity;
}

/* rise: elevated upward entry with greater distance — used by TENSION chapter.
   Stronger offset creates heightened anticipation vs. fade-up. */
.dud-entrance--rise {
  opacity: 0;
  transform: translateY(var(--dud-entrance-dist));
  will-change: opacity, transform;
}

/* emerge: subtle scale + fade — for hero elements, primary callouts.
   Scale starts just below 1 for a "materialization" quality. */
.dud-entrance--emerge {
  opacity: 0;
  transform: scale(0.97);
  will-change: opacity, transform;
}

/* ═══════════════════════════════════════════════════════════════════════════
   SECTION 4 — REVEALED STATE TRANSITIONS
   ═══════════════════════════════════════════════════════════════════════════
   .dud-revealed is the single shared destination state for ALL entrance types.
   When JS adds .dud-revealed in Phase 2, CSS transitions fire from whatever
   entrance state the element was in to opacity:1 / transform:none.
   will-change is NOT present on .dud-revealed — element is permanently still
   after reveal. No hover transforms, no follow-on animation, no looping. */

.dud-entrance--fade-up.dud-revealed {
  opacity: 1;
  transform: none;
  will-change: auto;
  transition:
    opacity   var(--dud-reveal-duration) var(--dud-reveal-easing),
    transform var(--dud-reveal-duration) var(--dud-reveal-easing);
}

.dud-entrance--fade.dud-revealed {
  opacity: 1;
  will-change: auto;
  transition:
    opacity var(--dud-reveal-duration) var(--dud-reveal-easing);
}

.dud-entrance--rise.dud-revealed {
  opacity: 1;
  transform: none;
  will-change: auto;
  transition:
    opacity   var(--dud-reveal-duration) var(--dud-reveal-easing),
    transform var(--dud-reveal-duration) var(--dud-reveal-easing);
}

.dud-entrance--emerge.dud-revealed {
  opacity: 1;
  transform: none;
  will-change: auto;
  transition:
    opacity   var(--dud-reveal-duration) var(--dud-reveal-easing),
    transform var(--dud-reveal-duration) var(--dud-reveal-easing);
}

/* ═══════════════════════════════════════════════════════════════════════════
   SECTION 5 — STANDALONE REVEALED STATE
   ═══════════════════════════════════════════════════════════════════════════
   Applied to elements that were never assigned an entrance class
   (e.g. sanctuary elements, immediate reveals, elements revealed before
   JS ran). Ensures they are unconditionally visible. No transition fires. */

.dud-revealed:not(.dud-entrance--fade-up):not(.dud-entrance--fade):not(.dud-entrance--rise):not(.dud-entrance--emerge) {
  opacity: 1;
  transform: none;
}

/* ═══════════════════════════════════════════════════════════════════════════
   SECTION 6 — POST-REVEAL STILLNESS CONTRACT
   ═══════════════════════════════════════════════════════════════════════════
   After an element reaches .dud-revealed, it is permanently still.
   No hover animation, no looping, no follow-on motion.
   This is intentional: luxury editorial stillness after arrival. */

.dud-revealed {
  /* Post-reveal: element is at rest. Pointer events restored. */
  pointer-events: auto;
}

/* ═══════════════════════════════════════════════════════════════════════════
   SECTION 7 — BREATH SANCTUARY BASELINE
   ═══════════════════════════════════════════════════════════════════════════
   All elements within a BREATH chapter container are revealed immediately
   (JS enforces this at boot). This rule provides a CSS-layer fallback
   ensuring BREATH elements are visible even if JS fails silently.
   This is a defensive rule — under normal operation JS handles it. */

[data-dud-chapter="BREATH"] [data-dud-entrance],
[data-dud-chapter="BREATH"] [data-dud-stagger] {
  opacity: 1 !important;
  transform: none !important;
  transition: none !important;
}

/* ═══════════════════════════════════════════════════════════════════════════
   SECTION 8 — PREFERS-REDUCED-MOTION OVERRIDE
   ═══════════════════════════════════════════════════════════════════════════
   Hard override: ALL entrance transitions are disabled at the CSS layer.
   This is the redundant safety layer; JS also calls drainImmediate().
   These rules fire regardless of JS state — CSS-only guarantee. */

@media (prefers-reduced-motion: reduce) {
  .dud-entrance--fade-up,
  .dud-entrance--fade,
  .dud-entrance--rise,
  .dud-entrance--emerge {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    will-change: auto !important;
  }

  .dud-entrance--fade-up.dud-revealed,
  .dud-entrance--fade.dud-revealed,
  .dud-entrance--rise.dud-revealed,
  .dud-entrance--emerge.dud-revealed {
    opacity: 1;
    transform: none;
    transition: none !important;
  }
}

/* ═══════════════════════════════════════════════════════════════════════════
   SECTION 8b — ALIAS ENTRANCE TYPES
   Template authors may use data-dud-entrance="slide-up" or "scale-in" as
   semantic aliases. The engine falls back to 'fade' BASE_TOKENS for unknown
   types (correct timing/easing), so these rules only need to supply the
   initial hidden state that the engine's class addition expects.
   • slide-up  → directional vertical entrance (alias for fade-up behaviour)
   • scale-in  → subtle scale materialisation (alias for emerge behaviour)
   ═══════════════════════════════════════════════════════════════════════════ */

.dud-entrance--slide-up {
  opacity: 0;
  transform: translateY(var(--dud-entrance-dist, 24px));
  will-change: opacity, transform;
}

.dud-entrance--slide-up.dud-revealed {
  opacity: 1;
  transform: translateY(0);
  transition:
    opacity   var(--dud-reveal-duration, 600ms) var(--dud-reveal-easing, cubic-bezier(0.25, 0.46, 0.45, 0.94)),
    transform var(--dud-reveal-duration, 600ms) var(--dud-reveal-easing, cubic-bezier(0.25, 0.46, 0.45, 0.94));
}

.dud-entrance--scale-in {
  opacity: 0;
  transform: scale(0.97);
  will-change: opacity, transform;
}

.dud-entrance--scale-in.dud-revealed {
  opacity: 1;
  transform: scale(1);
  transition:
    opacity   var(--dud-reveal-duration, 800ms) var(--dud-reveal-easing, cubic-bezier(0.16, 1.0, 0.3, 1.0)),
    transform var(--dud-reveal-duration, 800ms) var(--dud-reveal-easing, cubic-bezier(0.16, 1.0, 0.3, 1.0));
}

/* Reduced motion — aliases resolve identically to primary types */
@media (prefers-reduced-motion: reduce) {
  .dud-entrance--slide-up,
  .dud-entrance--scale-in {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    will-change: auto !important;
  }
}


/* ═══════════════════════════════════════════════════════════════════════════
   SECTION 9 — PRINT MEDIA OVERRIDE
   ═══════════════════════════════════════════════════════════════════════════
   All entrance states resolved immediately for print. No hidden content
   in printed output regardless of reveal state. */

@media print {
  .dud-entrance--fade-up,
  .dud-entrance--fade,
  .dud-entrance--rise,
  .dud-entrance--emerge,
  .dud-entrance--slide-up,
  .dud-entrance--scale-in,
  .dud-in-flight {
    opacity: 1 !important;
    transform: none !important;
    transition: none !important;
    will-change: auto !important;
  }
}
