/* TT-SITE-CSS-002 · motion.css · r8 · Lane D2 · 2026-09-15 · Tacit Tessera — MOTION ONLY.
   (r6 was Lane M; every r6 rule below is carried unchanged. r8 adds §13–§16.)

   Linked AFTER tt.css (orchestrator adds the <link> in templates/page.html).
   Touches no class Lane D owns; every hook here is either an existing class
   already in tt.css/the HTML, or a new `m-` prefixed class/attribute added by
   tt.js at runtime. Nothing in this file hides anything without script: every
   rule below lives inside `@media(prefers-reduced-motion:no-preference)` and
   is additionally gated on `html.rv-armed` or an `html.rv-armed …[.m-go/.in]`
   state that only tt.js adds — so no-script and reduced-motion readers see
   the page exactly as tt.css alone paints it.

   SECTIONS
     1 tokens              5 the plates (hover/sheen)   9 header condensing
     2 hero choreography   6 drawn figures (.fig)       10 photo parallax
     3 reveal tuning       7 the section marker (.mk)   11 the Book wall
     4 h2 hairline         8 the scan line (ambient)     12 reduced-motion catch-all
     r8: 13 the More plate · 14 the transaction chain's connectors ·
         15 the stack's rail · 16 the Manifest readout · 17 the path plates

   Deviation from the brief, noted here per RULES.md ("what you wanted to do
   but…"): the hero's photograph settles to scale(1) exactly, as specified —
   so it carries NO scroll parallax (a scale(1) image has no overscan to pan
   within without exposing an edge). Parallax (§10) runs on `.sec.frame` and
   `.sec.shot` bands only, which are not part of the load entrance and can
   safely carry a small permanent overscan. See M_motion-r6.md §7. */

/* ==== 1 · TOKENS ========================================================= */
:root{
  --m-ease:cubic-bezier(.22,.61,.36,1);     /* settle — used for entrances, sheens, ticks */
  --m-ease2:cubic-bezier(.16,.7,.24,1);     /* the reveal system's own curve, retuned */
  --m-fast:.28s;
  --m-med:.6s;
  --m-slow:1.2s;
}

@media(prefers-reduced-motion:no-preference){

/* ==== 2 · HERO CHOREOGRAPHY (on load, not on scroll) ===================== */
/* tt.js marks the lab line / h1 / lede / sm2 / rack as .m-beat (and the tiles
   inside the rack as .m-beat-sub), each with its own transition-delay, then
   adds .m-go to .hero.shot two frames later. The hero is excluded from the
   general .rv system (tt.js) so this is the only treatment it gets. */
html.rv-armed .hero.shot .m-beat{opacity:0;transform:translateY(20px);
  transition:opacity .7s var(--m-ease),transform .7s var(--m-ease);will-change:transform,opacity}
html.rv-armed .hero.shot.m-go .m-beat{opacity:1;transform:none}
html.rv-armed .hero.shot .m-beat-sub{opacity:0;transform:translateY(14px);
  transition:opacity .6s var(--m-ease),transform .6s var(--m-ease)}
html.rv-armed .hero.shot.m-go .m-beat-sub{opacity:1;transform:none}
/* a beat that is ALSO a .pl (verify.html's result plate is both) must still be
   able to lift on hover once settled — .m-go's settled transform:none above
   outranks .pl:hover on specificity alone, so it needs its own override */
@media(hover:hover){
  html.rv-armed .hero.shot.m-go .m-beat.pl:hover{transform:translateY(-3px)}
}
html.rv-armed .hero.shot.m-go .m-beat.pl:focus-within{transform:translateY(-3px)}
/* the photograph: a slight zoom-out settle, never a permanent overscan */
html.rv-armed .hero.shot .media img{transform:scale(1.04);
  transition:transform 1.6s var(--m-ease);will-change:transform}
html.rv-armed .hero.shot.m-go .media img{transform:scale(1)}

/* ==== 3 · REVEAL TUNING (overrides tt.css §16, later in the cascade) ==== */
/* smaller travel + a two-axis ease (a faint diagonal, not a straight lift) */
html.rv-armed .rv{transition:opacity .62s var(--m-ease2),transform .62s var(--m-ease2)}
html.rv-armed .rv:not(.in):not(.rv-fade){transform:translate(-3px,14px)}
html.rv-armed .rv.rv-soft{transition-duration:.52s}
html.rv-armed .rv.rv-soft:not(.in):not(.rv-fade){transform:translate(-2px,7px)}

/* ==== 4 · H2 HAIRLINE (draws in under a heading as it enters) =========== */
main .w>h2.rv::after,main .narrow>h2.rv::after{content:"";display:block;height:2px;width:0;
  margin-top:12px;background:linear-gradient(90deg,var(--red-hi),transparent);
  transition:width .5s var(--m-ease) .16s}
main .w>h2.rv.in::after,main .narrow>h2.rv.in::after{width:64px}

/* ==== 5 · THE PLATES — hover/focus lift + one machined sheen sweep ====== */
.tile-fig a{position:relative;transition:transform var(--m-fast) var(--m-ease),filter var(--m-fast) var(--m-ease)}
.tile-fig a::after{content:"";position:absolute;inset:0;pointer-events:none;opacity:0;
  clip-path:polygon(0 0,86.25% 0,100% 22%,100% 100%,13.75% 100%,0 78%);
  background:linear-gradient(115deg,transparent 42%,rgba(255,255,255,.14) 49%,rgba(255,255,255,.26) 50%,rgba(255,255,255,.14) 51%,transparent 58%);
  background-size:240% 240%;background-position:-60% -60%}
.pl{transition:transform var(--m-fast) var(--m-ease),filter var(--m-fast) var(--m-ease)}
.pl::after{content:"";position:absolute;inset:0;pointer-events:none;opacity:0;
  background:linear-gradient(115deg,transparent 42%,rgba(255,255,255,.12) 49%,rgba(255,255,255,.22) 50%,rgba(255,255,255,.12) 51%,transparent 58%);
  background-size:240% 240%;background-position:-60% -60%}
@media(hover:hover){
  .tile-fig a:hover,.pl:hover{transform:translateY(-3px);filter:drop-shadow(0 10px 22px rgba(0,0,0,.5));will-change:transform}
  .tile-fig a:hover::after,.pl:hover::after{opacity:1;animation:m-sheen .85s var(--m-ease)}
}
.tile-fig a:focus-visible,.pl:focus-within{transform:translateY(-3px);filter:drop-shadow(0 10px 22px rgba(0,0,0,.5))}
.tile-fig a:focus-visible::after,.pl:focus-within::after{opacity:1;animation:m-sheen .85s var(--m-ease)}
@keyframes m-sheen{from{background-position:-60% -60%}to{background-position:160% 160%}}

/* ==== 6 · DRAWN FIGURES COME TO LIFE (figure.fig svg, never .tile-fig) ==
   tt.js sets --m-len (the path's own getTotalLength()) inline per element;
   dasharray/dashoffset both read it here, in the stylesheet, on purpose —
   an inline stroke-dashoffset would outrank .m-fig-in below and never move. */
figure.fig svg.m-fig-go :is(path,line,polyline,rect,circle){
  stroke-dasharray:var(--m-len,0);stroke-dashoffset:var(--m-len,0);
  transition:stroke-dashoffset 1.2s var(--m-ease)}
figure.fig svg.m-fig-go.m-fig-in :is(path,line,polyline,rect,circle){stroke-dashoffset:0}
figure.fig svg .m-fig-text{opacity:0;transition:opacity .5s ease-out}
figure.fig svg.m-fig-in .m-fig-text{opacity:1;transition-delay:1.05s}

/* ==== 7 · THE SECTION MARKER (.mk) — tick grows, label slides =========== */
.mk{position:relative}
.mk::before{content:"";position:absolute;left:-4px;top:0;bottom:0;width:4px;
  background:var(--red-hi);transform:scaleY(0);transform-origin:top;
  transition:transform .6s var(--m-ease) .05s}
.mk.in::before{transform:scaleY(1)}
.mk span{display:inline-block;transition:transform .5s var(--m-ease) .12s}
.mk:not(.in) span{transform:translateX(-6px)}

/* ==== 8 · THE SCAN LINE — one signature ambient sweep, hero only ======== */
.hero.shot.m-go::after{content:"";position:absolute;inset:0;z-index:3;pointer-events:none;
  background-image:linear-gradient(90deg,transparent,rgba(255,91,95,.6) 35%,rgba(255,91,95,.92) 50%,rgba(255,91,95,.6) 65%,transparent);
  background-repeat:no-repeat;background-size:100% 2px;background-position:0 -2px;opacity:0;
  animation:m-scan 2.4s cubic-bezier(.4,0,.2,1) .55s 1 both}
@keyframes m-scan{0%{background-position:0 0%;opacity:0}10%{opacity:1}85%{opacity:1}100%{background-position:0 100%;opacity:0}}

/* ==== 9 · HEADER CONDENSING — transition hooks only; Lane D sets values = */
header.site{transition:background var(--m-fast) ease,box-shadow var(--m-fast) ease,
  padding-block var(--m-fast) ease,backdrop-filter var(--m-fast) ease}
html.scrolled header.site{backdrop-filter:blur(10px) saturate(1.15);-webkit-backdrop-filter:blur(10px) saturate(1.15);
  background:linear-gradient(rgba(30,30,30,.9),rgba(21,21,21,.9));box-shadow:0 1px 0 rgba(255,255,255,.06),0 8px 22px rgba(0,0,0,.35)}

/* ==== 10 · PHOTOGRAPH BANDS — gentle parallax (JS-driven, see §7 note) == */
@media(min-width:760px){
  .sec.frame .media img,.sec.shot .media img{transform:scale(1.06);will-change:transform}
}

/* ==== 11 · THE BOOK WALL — animated hide/show on filter (logic intact) = */
[data-wall]>li{transition:opacity var(--m-fast) ease,transform var(--m-fast) ease}
[data-wall]>li.m-out{opacity:0;transform:scale(.94)}


/* ==== 13 · r8 · THE "MORE" PLATE — it drops, it does not appear ========= */
/* Desktop only: below 1240 the panel is a static block inside the open menu
   and the burger's own opening is the movement. <details> needs no class. */
@media(min-width:1240px){
  nav.site details.more[open] .morepanel{animation:m-drop .26s var(--m-ease) both}
}
@keyframes m-drop{from{opacity:0;transform:translateY(-7px)}to{opacity:1;transform:none}}

/* ==== 14 · r8 · THE TRANSACTION CHAIN — the rail draws between plates == */
/* Each step is its own .rv (tt.js HARD), staggered by sibling position, so
   the connector and its head belong to the plate they arrive at. */
html.rv-armed ol.chain-tx>li+li::before{
  transform:translateY(-.5px) scaleX(0);transform-origin:left center;
  transition:transform .42s var(--m-ease) .10s}
html.rv-armed ol.chain-tx>li+li.in::before{transform:translateY(-.5px) scaleX(1)}
html.rv-armed ol.chain-tx>li+li::after{opacity:0;transition:opacity .30s var(--m-ease) .34s}
html.rv-armed ol.chain-tx>li+li.in::after{opacity:1}
@media(max-width:1079px){
  html.rv-armed ol.chain-tx>li+li::before{transform:scaleY(0);transform-origin:top center}
  html.rv-armed ol.chain-tx>li+li.in::before{transform:scaleY(1)}
}

/* ==== 15 · r8 · THE STACK — the node seats, then the spur reaches out === */
html.rv-armed ol.stack>li::before{transform:scale(0);transition:transform .38s var(--m-ease) .08s}
html.rv-armed ol.stack>li.in::before{transform:scale(1)}
html.rv-armed ol.stack>li::after{transform:scaleX(0);transform-origin:left center;
  transition:transform .36s var(--m-ease) .18s}
html.rv-armed ol.stack>li.in::after{transform:scaleX(1)}

/* ==== 16 · r8 · THE MANIFEST — the readout drops out of the plate ======= */
/* Only ever runs under html.rv-armed, which tt.js adds; with no script the
   panel is open from the start and this never applies. */
html.rv-armed .mfwrap:not([hidden]){animation:m-readout .34s var(--m-ease) both}
@keyframes m-readout{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:none}}

/* ==== 17 · r8 · THE PATH PLATES — the same machined sheen as .pl ======== */
ul.paths a{position:relative}
ul.paths a::after{content:"";position:absolute;inset:0;pointer-events:none;opacity:0;
  background:linear-gradient(115deg,transparent 42%,rgba(255,255,255,.12) 49%,rgba(255,255,255,.22) 50%,rgba(255,255,255,.12) 51%,transparent 58%);
  background-size:240% 240%;background-position:-60% -60%}
@media(hover:hover){
  ul.paths a:hover::after{opacity:1;animation:m-sheen .85s var(--m-ease)}
}
ul.paths a:focus-visible::after{opacity:1;animation:m-sheen .85s var(--m-ease)}

} /* end prefers-reduced-motion:no-preference */

/* ==== 12 · REDUCED-MOTION CATCH-ALL ===================================== */
/* Belt-and-braces alongside every @media guard above: if anything here ever
   runs outside that guard (a future edit, a browser quirk), this wins last
   and turns it off. Nothing this file adds is content — every element stays
   visible with it switched off. */
@media(prefers-reduced-motion:reduce){
  .hero.shot .m-beat,.hero.shot .m-beat-sub,.hero.shot .media img,
  .tile-fig a,.tile-fig a::after,.pl,.pl::after,
  figure.fig svg :is(path,line,polyline,rect,circle),figure.fig svg .m-fig-text,
  .mk::before,.mk span,main h2.rv::after,
  header.site,.sec.frame .media img,.sec.shot .media img,[data-wall]>li,
  nav.site .morepanel,ol.chain-tx>li::before,ol.chain-tx>li::after,
  ol.stack>li::before,ol.stack>li::after,.mfwrap,ul.paths a,ul.paths a::after{
    transition:none!important;animation:none!important;transform:none!important;
    opacity:1!important;stroke-dashoffset:0!important;backdrop-filter:none!important}
  .hero.shot.m-go::after{display:none!important}
  main h2.rv::after{width:0!important;display:none!important}
  /* r8: the arrow heads and chevrons are DRAWN with a rotate — the blanket
     transform:none above would flatten them into a bare corner, so the
     resting geometry is restored here (it is shape, not movement). */
  ol.chain-tx>li+li::before{transform:translateY(-.5px)!important}
  ol.chain-tx>li+li::after{transform:translateY(-50%) rotate(45deg)!important;opacity:1!important}
  ol.stack>li::before{transform:none!important}
  ol.stack>li::after{transform:none!important}
  nav.site details.more>summary::after{transform:translateY(-2px) rotate(45deg)!important}
  nav.site details.more[open]>summary::after{transform:translateY(1px) rotate(-135deg)!important}
  button.mftoggle::after{transform:translateY(-2px) rotate(45deg)!important}
  button.mftoggle[aria-expanded="true"]::after{transform:translateY(1px) rotate(-135deg)!important}
  .btn::after{transform:translateY(-1px) rotate(-45deg)!important}
  ul.paths .go::after{transform:translateY(-1px) rotate(-45deg)!important}
  ul.states>li::before{transform:none!important}
  @media(max-width:1079px){
    ol.chain-tx>li+li::before{transform:none!important}
    ol.chain-tx>li+li::after{transform:rotate(135deg)!important}
  }
}
