/* =============================================================================
   GLYPH — surfaces/login-stage.css  [P5-L1]
   =============================================================================
   THE LOGIN STAGE ENGINE'S OWN CSS, and nothing else. Extracted from
   `docs/redesign/exports/project-mirror/Glyph Login Stage.dc.html`
   md5 `b8eb34c58b06f136baefe370768d1381`, lines **28-29** (`@keyframes mark-breathe`)
   and **36-41** (the reduced-motion block). R17.1: copied, never re-typed.

   🔴 SCOPE. This sheet holds ONLY what the ENGINE MODULE
   (`public/js/surfaces/login/stage.js`) itself depends on:
     - `@keyframes mark-breathe` — the engine WRITES `animation: mark-breathe 4000ms …`
       onto `[data-static-mark]` in the STATIC tier. Without this rule that write is
       inert and the static tier silently stops breathing, which is the ONE thing that
       distinguishes it from the reduced tier.
     - the `@media (prefers-reduced-motion: reduce)` block — the SECOND of the engine's
       two reduced-motion mechanisms.
   The login page's own markup and chrome CSS are **P5-L3's** and are deliberately
   absent. The drawing's other three keyframes (`glyph-facet`, `stage-ignite`,
   `stage-attention`) are named by INLINE styles in the artboard's markup, not by the
   engine, so they belong to the lane that ships that markup. Measured, not assumed:
   `grep -c 'mark-breathe' stage.js` -> 1; the other three -> 0.

   🔴 BOTH REDUCED-MOTION MECHANISMS SHIP AND NEITHER SUBSTITUTES FOR THE OTHER.
   The JS half is `window.matchMedia('(prefers-reduced-motion: reduce)')` inside
   `_boot()`: it stops the rAF loop and holds the mark still. THIS half is the one that
   still works when the module never runs at all — script blocked, module fetch failed,
   an exception before `mount()`. A page that shipped only the JS half would animate at
   full tilt for a reduced-motion user in exactly the cases where something is already
   going wrong.

   🔴 `!important` IS THE DRAWING'S, AND IT IS RAISED AS A DESIGN ROW, NOT RESOLVED HERE.
   `REDESIGN-BUILD/LANE-CONTRACT.md` §5 says "No `!important`, ever", and the
   `css-ratchet` gate counts `declaration-no-important`. The DRAWING uses it, four times,
   at `Glyph Login Stage.dc.html:37-40`. Under R17.4 the drawing wins and a build-side
   actor never resolves such a conflict by judgment — so the bytes are the drawing's and
   the conflict is batched to the design round with the FILE named.
   🔴 EACH OF THE FOUR IS JUSTIFIED SEPARATELY, BY THE INLINE WRITE IT CONTESTS —
   not as a block (P5 supervisor, required). Measured on a JS-FREE fixture under forced
   reduced motion, each node carrying a CONTESTING inline declaration, with the sheet
   linked and then suppressed as the control
   (`EVIDENCE/P5/L1/raw/decl-{with,without}.json`):

     decl                                     with sheet   control    contests
     [data-stage-anim] animation: none        'none'       'stage-ignite'
         TWO elements in the DRAWING'S OWN MARKUP carry an inline `animation:`
         (`stage-ignite 760ms` on the success flourish, `stage-attention 560ms` on the
         error wash). LOAD-BEARING EVEN IF JAVASCRIPT NEVER RUNS — a reviewer who
         disables JS would otherwise conclude this one was unnecessary.
     [data-static-mark] opacity: 1            '1'          '0'
         BOTH `<img data-static-mark>` elements carry inline `opacity: 0` in the
         drawing's markup. LOAD-BEARING WITH JS OFF: without `!important` the mark
         stays invisible for a reduced-motion user on a page whose script failed.
     [data-particles] opacity: 0              '0'          '1'
         RUNTIME GROUND ONLY. Neither `<canvas data-particles>` carries an inline
         opacity in the markup, so a plain rule would win statically — but `_boot()`
         writes `cv.style.opacity = '1'` in the canvas tier.
     [data-word] opacity: 0                   '0'          '1'
         RUNTIME GROUND ONLY. The markup's inline is already `opacity: 0`, so there is
         no static contest — but the frame loop writes `wordEl.style.opacity` EVERY
         FRAME during the wordmark beat.

   The module makes **11** `style.opacity`, **2** `style.animation` and **1**
   `style.transform` inline writes (counted over the shipped file). An inline
   declaration beats every normal author declaration in every layer; only `!important`
   outranks one. `@layer` cannot help — layer order settles stylesheet-vs-stylesheet and
   never reaches inline. So NO declaration here is removable, and the ratchet's +4 is
   what the CASCADE REQUIRES rather than what the drawing happens to contain.
   ============================================================================= */

@layer surfaces {

  /* the static tier's breathing — scale only, never alpha */
  @keyframes mark-breathe { 0%, 100% { scale: 0.982; } 50% { scale: 1; } }

  @media (prefers-reduced-motion: reduce) {
    [data-stage-anim] { animation: none !important; }
    [data-static-mark] { opacity: 1 !important; }
    [data-particles] { opacity: 0 !important; }
    [data-word] { opacity: 0 !important; }
  }

}
