/* motion.css — lev4ig.ru v2 · «Приводка / In Register»
   One orchestrated moment on load, then stillness.
   Transform + opacity only. No scroll-linked anything. Load AFTER site.css. */

:root{
  --m-in:  cubic-bezier(.2,.7,.3,1);   /* plates arriving */
  --m-set: cubic-bezier(.2,.8,.2,1);   /* the moment of register */
  --m-tw:  60ms;                       /* misregistration twitch */
  --m-swap:140ms;                      /* language patches */
  --m-rev: 200ms;                      /* tile reveal */
}

/* ---------------------------------------------------------------- 1. LOAD
   Authored state = final composition: plates in register, name at full
   density, sweep invisible, bars grown. The animation moves AWAY from the
   authored state and back to it, so no-JS and reduced-motion ship correct. */

.plate{ transform-box:fill-box; transform-origin:50% 50%; }
.reg-sweep{ transform-box:view-box; opacity:0; }

html.is-registering .plate--tech{ animation:reg-t 900ms both; }
html.is-registering .plate--mech{ animation:reg-m 780ms 120ms both; }
html.is-registering .plate--comm{ animation:reg-c 660ms 240ms both; }

@keyframes reg-t{
  0%  { opacity:0; transform:translate(-14px,-6px) rotate(-.6deg); animation-timing-function:var(--m-in); }
  29% { opacity:1; transform:translate(-8px,-3px) rotate(-.34deg); animation-timing-function:linear; }
  62% { opacity:1; transform:translate(-8px,-3px) rotate(-.34deg); animation-timing-function:var(--m-set); }
  100%{ opacity:1; transform:none; }
}
@keyframes reg-m{
  0%  { opacity:0; transform:translate(11px,8px) rotate(.4deg); animation-timing-function:var(--m-in); }
  33% { opacity:1; transform:translate(6px,4px) rotate(.22deg); animation-timing-function:linear; }
  56% { opacity:1; transform:translate(6px,4px) rotate(.22deg); animation-timing-function:var(--m-set); }
  100%{ opacity:1; transform:none; }
}
@keyframes reg-c{
  0%  { opacity:0; transform:translate(-6px,13px) rotate(-.3deg); animation-timing-function:var(--m-in); }
  42% { opacity:1; transform:translate(-3px,7px) rotate(-.17deg); animation-timing-function:linear; }
  48% { opacity:1; transform:translate(-3px,7px) rotate(-.17deg); animation-timing-function:var(--m-set); }
  100%{ opacity:1; transform:none; }
}

/* 900ms — the impression is pulled: density jumps, one knockout line sweeps */
html.is-registering .reg-name{ animation:reg-n 1ms 900ms steps(1,end) both; }
@keyframes reg-n{ from{ opacity:.4 } to{ opacity:1 } }

html.is-registering .reg-sweep{ animation:reg-s 180ms 900ms linear both; }
@keyframes reg-s{
  0%  { opacity:0;   transform:translateX(-3%); }
  12% { opacity:.85; }
  88% { opacity:.85; }
  100%{ opacity:0;   transform:translateX(100%); }
}

/* 900–1200 — each plate plays its own data once */
html.is-registering [data-grow]{
  transform-box:fill-box; transform-origin:50% 100%;
  animation:reg-g 300ms 900ms ease-out both;
}
@keyframes reg-g{ from{ transform:scaleY(.04) } to{ transform:none } }

html.is-registering [data-draw]{
  stroke-dasharray:var(--len,900);
  animation:reg-d 300ms 900ms ease-out both;
}
@keyframes reg-d{ from{ stroke-dashoffset:var(--len,900) } to{ stroke-dashoffset:0 } }

/* --d is each tick's own latency, rescaled: the auction actually runs */
html.is-registering [data-ms]{
  transform-box:fill-box; transform-origin:50% 100%;
  animation:reg-p 160ms ease-out both; animation-delay:calc(900ms + var(--d,0ms));
}
@keyframes reg-p{ from{ opacity:0; transform:scaleY(.2) } to{ opacity:1; transform:none } }

/* 1200 — the first waterfall tag types in, then the grid takes over */
html.is-registering .type-in{ animation:reg-y 220ms 1200ms steps(var(--n,15),end) both; }
@keyframes reg-y{ from{ clip-path:inset(0 100% 0 0) } to{ clip-path:inset(0 0 0 0) } }

/* ------------------------------------------------------ 2. TILE REVEAL
   Class added by JS only once the observer exists, so a JS failure can
   never leave the sheet blank. --sd is the per-column stagger. */

html.motion-reveal :is(.tile,.reveal){ opacity:0; transform:translate3d(0,10px,0); }
html.motion-reveal :is(.tile,.reveal).is-in{
  opacity:1; transform:none;
  transition:opacity var(--m-rev) ease-out var(--sd,0ms),
             transform var(--m-rev) ease-out var(--sd,0ms);
}

/* ------------------------------------------- 3. MICRO-INTERACTIONS (three)
   All keyed off one switch var, so hover and focus stay identical.
   No scale, no lift, no shadow, anywhere on the page. */

.tile{ --on:0; --tag-c:var(--tint); background-color:var(--tile-bg,var(--tile)); position:relative;
       transition:background-color 120ms linear; }
@media (hover:hover){ .tile:hover{ --on:1; --tag-c:var(--text); --tile-bg:var(--tile-2); } }
.tile:focus-within{ --on:1; --tag-c:var(--text); --tile-bg:var(--tile-2); }

/* the ink layer twitches out of register and settles */
.tile .ink{ transform-box:fill-box; transform-origin:50% 50%;
  transform:translate(calc(var(--on)*2px),calc(var(--on)*-2px));
  transition:transform var(--m-tw) var(--m-set); }
.tile .ink .plate--mech{ transform:translate(calc(var(--on)*-2px),calc(var(--on)*2px));
  transition:transform var(--m-tw) var(--m-set); }

.tile .tag-bid{ color:var(--tag-c); transition:color 120ms linear; }

/* 1px rule drawn along the 12px chamfer cut */
.tile::after{ content:""; position:absolute; top:0; right:0; width:17px; height:1px;
  background:var(--rule); transform-origin:0 50%; pointer-events:none;
  transform:translate(4.3px,.7px) rotate(45deg) scaleX(var(--on));
  transition:transform 120ms var(--m-in); }

/* focus reads as a registration mark: square, MECH red, never removed */
:where(a,button,[tabindex]):focus-visible{
  outline:2px solid var(--focus,var(--mech)); outline-offset:3px; border-radius:0; }

/* ------------------------------------------------------ 4. LANGUAGE SWAP
   Both languages are pre-rendered; this is an ink re-pull, not a page load.
   90ms out · swap · 90ms in — never a white flash, never a reflow jump. */

body [lang]{ transition:opacity 90ms linear, transform 90ms var(--m-in); }
html.lang-swap body [lang]{ opacity:0; transform:translateX(-3px); }

.lang-btn{ transition:background-color var(--m-swap) linear, color var(--m-swap) linear,
                      opacity var(--m-swap) linear, transform var(--m-swap) var(--m-in); }
html.lang-swap .lang-btn{ opacity:.55; transform:translateX(3px); }

/* ------------------------------------------------------- 5. REDUCED MOTION
   Not "everything off": the same design, communicating by state instead of
   movement. Plates are already in register, the name already at full
   density, tiles already present. Hover still answers — surface steps to
   --tile-2, the BID tag goes to --text, the chamfer rule appears — it just
   appears instead of drawing. Focus ring is untouched. */

@media (prefers-reduced-motion:reduce){
  html.is-registering :is(.plate--tech,.plate--mech,.plate--comm,.reg-name,
    .reg-sweep,[data-grow],[data-draw],[data-ms],.type-in){
    animation:none !important; stroke-dasharray:none; clip-path:none; }
  html.motion-reveal :is(.tile,.reveal){ opacity:1; transform:none; }
  html.motion-reveal :is(.tile,.reveal).is-in{ transition:none; }
  .tile .ink,.tile .ink .plate--mech{ transform:none; transition:none; }
  .tile::after{ transform:translate(4.3px,.7px) rotate(45deg) scaleX(var(--on)); transition:none; }
  .tile,.tile .tag-bid,.lang-btn,body [lang]{ transition:none; }
  html.lang-swap body [lang]{ opacity:1; transform:none; }
  html.lang-swap .lang-btn{ opacity:1; transform:none; }
}
