/* ---------------------------------------------------------
   3D（りったい・v12.0）の 見た目と モーション。もとは tools/3d/motion.css（試作 v3）。ここが 正本。
   前半＝箱の 器（.v3scene > .v3fig > .v3hold > .v3）と 部品の 動き、さいご＝ゲームの 画面に 入れる ための きまり。

   3D の キャラ・モンスターの モーション（試作 v3）
   部品（.p）を かんせつで 回すだけ＝マイクラと 同じ。曲げない・のばさない。

   ならび： .fig（向き＝rotateY ±22deg） > .hold（大きさ scale3d） > .v3（体ごとの 動き） > .p（部品）
   部品：   .p--body > .p--head .p--armL .p--armR .p--wingL .p--wingR ／ .p--legA .p--legB（root の 直下）
   うで・あしは 上（かた・こし）が かんせつ。rotateX(+) で 下の 先が 手まえ（前）に 出る。
   体は 足もとが かんせつ。rotateX(−) で 前かがみ。

   クラス（.v3 に つける）
     mo-idle    … 主人公の 待機（うでが 小さく ゆれ、頭が ときどき かたむく）
     mo-menace  … モンスターの 待機（前かがみで 体を ゆすり、ときどき ぐっと ふみこむ フェイント）
     mo-walk    … 登場（歩いて 出て くる・0.6秒）
     mo-attack  … こうげき（主人公＝右うでを ふり下ろす／モンスター＝手まえに とびかかる・0.5秒）
     mo-hurt    … くらう（のけぞる・0.5秒）
     mo-fall    … たおれる（うしろに ばたん・1秒・そのまま）
     mo-win     … かち（ジャンプ＋両うでを 上げる・0.9秒）
     mo-lunge   … ため → 手まえに とび出す（モンスター・0.7秒）
   --------------------------------------------------------- */
.v3 { position: relative; transform-style: preserve-3d; }
.v3 .b { position: absolute; transform-style: preserve-3d; }
.v3 .f { position: absolute; left: 0; top: 0; }   /* backface-visibility: hidden は 使わない（vox.js ⑧・あごの 下に すきまが 出た） */
.v3 .p { position: absolute; left: 0; top: 0; width: 0; height: 0; transform-style: preserve-3d; }
.v3 .bx { position: relative; }
.v3 .bx i { position: absolute; display: block; image-rendering: pixelated; }

/* ---------- 待機（主人公） ---------- */
.mo-idle .p--armL { animation: moArmSwayL 3.2s ease-in-out infinite; }
.mo-idle .p--armR { animation: moArmSwayR 3.2s ease-in-out infinite; }
.mo-idle .p--head { animation: moHeadTilt 5.4s ease-in-out infinite; }
.mo-idle { animation: moBob 2.4s ease-in-out infinite; }
@keyframes moArmSwayL { 0%, 100% { transform: rotateX(5deg); } 50% { transform: rotateX(-5deg); } }
@keyframes moArmSwayR { 0%, 100% { transform: rotateX(-5deg); } 50% { transform: rotateX(5deg); } }
@keyframes moHeadTilt { 0%, 30%, 70%, 100% { transform: rotateZ(0); } 40% { transform: rotateZ(3deg) rotateX(-4deg); } 60% { transform: rotateZ(-2deg); } }
@keyframes moBob { 0%, 100% { transform: translateY(0); } 50% { transform: translateY(-3px); } }

/* ---------- 待機（モンスター＝いまにも おそって きそう） ---------- */
.mo-menace { animation: moMenace 3.4s ease-in-out infinite; }
.mo-menace .p--body { animation: moRock 2.3s ease-in-out infinite; }
.mo-menace .p--wingL { animation: moFlapL 1.1s ease-in-out infinite; }
.mo-menace .p--wingR { animation: moFlapR 1.1s ease-in-out infinite; }
.mo-menace .p--legA { animation: moShift 1.7s ease-in-out infinite; }
.mo-menace .p--legB { animation: moShift 1.7s ease-in-out .85s infinite; }
@keyframes moMenace {
  0%   { transform: translateY(0) rotateX(-6deg); }
  35%  { transform: translateY(-3px) rotateX(-9deg); }
  70%  { transform: translateY(0) rotateX(-6deg); }
  78%  { transform: translateY(-5px) translateZ(18px) rotateX(-15deg); }   /* フェイント：ぐっと ふみこむ */
  86%  { transform: translateY(0) translateZ(3px) rotateX(-7deg); }
  100% { transform: translateY(0) rotateX(-6deg); }
}
@keyframes moRock { 0%, 100% { transform: rotateZ(-1.5deg); } 50% { transform: rotateZ(1.5deg); } }
@keyframes moFlapL { 0%, 100% { transform: rotateY(22deg); } 50% { transform: rotateY(-22deg); } }
@keyframes moFlapR { 0%, 100% { transform: rotateY(-22deg); } 50% { transform: rotateY(22deg); } }
@keyframes moShift { 0%, 100% { transform: rotateX(0); } 50% { transform: rotateX(10deg); } }

/* ---------- 登場（歩いて 出て くる） ---------- */
.mo-walk { animation: moWalkIn .6s ease-out both; }
.mo-walk.v3--hero { animation-name: moWalkInHero; }
.mo-walk .p--legA { animation: moStepA .6s linear both; }
.mo-walk .p--legB { animation: moStepB .6s linear both; }
.mo-walk .p--armL { animation: moStepB .6s linear both; }
.mo-walk .p--armR { animation: moStepA .6s linear both; }
.mo-walk .p--wingL { animation: moFlapL .3s ease-in-out 2; }
.mo-walk .p--wingR { animation: moFlapR .3s ease-in-out 2; }
@keyframes moWalkIn {
  0%   { transform: translateX(120px) translateY(0); }
  25%  { transform: translateX(90px) translateY(-4px); }
  50%  { transform: translateX(60px) translateY(0); }
  75%  { transform: translateX(30px) translateY(-4px); }
  100% { transform: translateX(0) translateY(0); }
}
@keyframes moWalkInHero {
  0%   { transform: translateX(-120px) translateY(0); }
  25%  { transform: translateX(-90px) translateY(-4px); }
  50%  { transform: translateX(-60px) translateY(0); }
  75%  { transform: translateX(-30px) translateY(-4px); }
  100% { transform: translateX(0) translateY(0); }
}
@keyframes moStepA { 0%, 50%, 100% { transform: rotateX(0); } 25% { transform: rotateX(38deg); } 75% { transform: rotateX(-38deg); } }
@keyframes moStepB { 0%, 50%, 100% { transform: rotateX(0); } 25% { transform: rotateX(-38deg); } 75% { transform: rotateX(38deg); } }

/* ---------- こうげき ---------- */
/* 主人公：ふりかぶって けんを ふり下ろす */
.mo-attack.v3--hero .p--armR { animation: moSwing .5s ease-in-out both; }
.mo-attack.v3--hero .p--armL { animation: moCounterArm .5s ease-in-out both; }
.mo-attack.v3--hero .p--body { animation: moLeanAtk .5s ease-in-out both; }
.mo-attack.v3--hero .p--head { animation: moHeadAtk .5s ease-in-out both; }
.mo-attack.v3--hero .p--sword { animation: moSwordSwing .5s ease-in-out both; }   /* 手首：ふりかぶりで 刃を 上に（うでの 150° を 打ち消す）、ふり下ろしで 前へ */
@keyframes moSwordSwing { 0% { transform: rotateX(0); } 30% { transform: rotateX(-150deg); } 55% { transform: rotateX(-110deg); } 100% { transform: rotateX(0); } }
@keyframes moSwing { 0% { transform: rotateX(0); } 30% { transform: rotateX(150deg); } 55% { transform: rotateX(-25deg); } 100% { transform: rotateX(0); } }
@keyframes moCounterArm { 0%, 100% { transform: rotateX(0); } 30% { transform: rotateX(-40deg); } 55% { transform: rotateX(20deg); } }
@keyframes moLeanAtk { 0%, 100% { transform: rotateX(0); } 30% { transform: rotateX(7deg); } 55% { transform: rotateX(-14deg); } }
@keyframes moHeadAtk { 0%, 100% { transform: rotateX(0); } 55% { transform: rotateX(-10deg); } }
/* モンスター：しゃがんで → 手まえに とびかかる */
.mo-attack:not(.v3--hero) { animation: moPounce .5s ease-in-out both; }
.mo-attack:not(.v3--hero) .p--body { animation: moBodyPounce .5s ease-in-out both; }
.mo-attack:not(.v3--hero) .p--wingL { animation: moFlapBigL .5s ease-in-out both; }
.mo-attack:not(.v3--hero) .p--wingR { animation: moFlapBigR .5s ease-in-out both; }
.mo-attack:not(.v3--hero) .p--legA, .mo-attack:not(.v3--hero) .p--legB { animation: moCrouch .5s ease-in-out both; }
@keyframes moPounce { 0%, 100% { transform: translateZ(0) rotateX(-6deg); } 25% { transform: translateZ(-10px) translateY(3px) rotateX(4deg); } 55% { transform: translateZ(32px) translateY(-6px) rotateX(-18deg); } }
@keyframes moBodyPounce { 0%, 100% { transform: rotateX(0); } 55% { transform: rotateX(-6deg); } }
@keyframes moFlapBigL { 0%, 100% { transform: rotateY(0); } 25% { transform: rotateY(45deg); } 55% { transform: rotateY(-40deg); } }
@keyframes moFlapBigR { 0%, 100% { transform: rotateY(0); } 25% { transform: rotateY(-45deg); } 55% { transform: rotateY(40deg); } }
@keyframes moCrouch { 0%, 100% { transform: rotateX(0); } 25% { transform: rotateX(16deg); } 55% { transform: rotateX(-12deg); } }

/* ---------- くらう（のけぞる） ---------- */
.mo-hurt { animation: moKnock .5s ease-out both; }
.mo-hurt .p--body { animation: moBodyBack .5s ease-out both; }
.mo-hurt .p--head { animation: moHeadBack .5s ease-out both; }
.mo-hurt .p--armL, .mo-hurt .p--armR { animation: moArmFling .5s ease-out both; }
.mo-hurt .p--wingL { animation: moFlapBigL .5s ease-out both; }
.mo-hurt .p--wingR { animation: moFlapBigR .5s ease-out both; }
@keyframes moKnock { 0%, 100% { transform: translateZ(0) rotateX(0); } 30% { transform: translateZ(-16px) rotateX(12deg); } }
@keyframes moBodyBack { 0%, 100% { transform: rotateX(0); } 30% { transform: rotateX(14deg); } }
@keyframes moHeadBack { 0%, 100% { transform: rotateX(0); } 30% { transform: rotateX(28deg); } }
@keyframes moArmFling { 0%, 100% { transform: rotateX(0); } 30% { transform: rotateX(35deg); } }

/* ---------- たおれる（うしろに ばたん） ---------- */
/* モンスターは 主人公の ほう（左）へ ばたん。左下の かどを じくに すると 画面の 外へ 出ない。主人公は 右へ（ゲームでは 使わない） */
.mo-fall { animation: moFall 1s ease-in both; transform-origin: 0% 100%; }
.mo-fall.v3--hero { animation-name: moFallR; transform-origin: 100% 100%; }
.mo-fall .p--legA, .mo-fall .p--legB { animation: moLegFold 1s ease-in both; }
.mo-fall .p--armL, .mo-fall .p--armR { animation: moArmFling 1s ease-in both; }
.mo-fall .p--head { animation: moHeadBack 1s ease-in both; }
@keyframes moFall {
  0%   { transform: rotateZ(0) translateY(0); opacity: 1; }
  20%  { transform: rotateZ(6deg) translateY(-3px); opacity: 1; }         /* いちど 反対に かたむいて から */
  60%  { transform: rotateZ(-84deg) translateY(2px); opacity: 1; }        /* 左に ばたん */
  68%  { transform: rotateZ(-78deg) translateY(-3px); opacity: 1; }       /* はねる */
  76%  { transform: rotateZ(-86deg) translateY(2px); opacity: 1; }
  100% { transform: rotateZ(-86deg) translateY(6px); opacity: 0; }
}
@keyframes moFallR {
  0%   { transform: rotateZ(0) translateY(0); opacity: 1; }
  20%  { transform: rotateZ(-6deg) translateY(-3px); opacity: 1; }
  60%  { transform: rotateZ(84deg) translateY(2px); opacity: 1; }
  68%  { transform: rotateZ(78deg) translateY(-3px); opacity: 1; }
  76%  { transform: rotateZ(86deg) translateY(2px); opacity: 1; }
  100% { transform: rotateZ(86deg) translateY(6px); opacity: 0; }
}
@keyframes moLegFold { 0% { transform: rotateX(0); } 100% { transform: rotateX(-40deg); } }

/* ---------- かち（ジャンプ＋両うでを 上げる） ---------- */
.mo-win { animation: moJump .9s ease-out both; }
.mo-win .p--armL, .mo-win .p--armR { animation: moArmsUp .9s ease-out both; }
.mo-win .p--head { animation: moHeadUp .9s ease-out both; }
.mo-win .p--sword { animation: moSwordUp .9s ease-out both; }   /* けんを 高く かかげる（刃を 上に） */
@keyframes moSwordUp { 0% { transform: rotateX(0); } 30%, 80% { transform: rotateX(-170deg); } 100% { transform: rotateX(0); } }
.mo-win .p--legA, .mo-win .p--legB { animation: moLegTuck .9s ease-out both; }
@keyframes moJump { 0% { transform: translateY(0); } 35% { transform: translateY(-28px); } 60% { transform: translateY(0); } 75% { transform: translateY(-10px); } 100% { transform: translateY(0); } }
@keyframes moArmsUp { 0% { transform: rotateX(0); } 30%, 80% { transform: rotateX(170deg); } 100% { transform: rotateX(0); } }
@keyframes moHeadUp { 0%, 100% { transform: rotateX(0); } 30%, 80% { transform: rotateX(-12deg); } }
@keyframes moLegTuck { 0%, 60%, 100% { transform: rotateX(0); } 35% { transform: rotateX(30deg); } }

/* ---------- ため → 手まえに とび出す（モンスター） ---------- */
.mo-lunge { animation: moLunge .7s ease-in-out both; }
.mo-lunge .p--wingL { animation: moFlapBigL .7s ease-in-out both; }
.mo-lunge .p--wingR { animation: moFlapBigR .7s ease-in-out both; }
.mo-lunge .p--legA, .mo-lunge .p--legB { animation: moCrouch .7s ease-in-out both; }
@keyframes moLunge {
  0%   { transform: translateZ(0) rotateX(-6deg); }
  20%  { transform: translateZ(-8px) translateY(3px) rotateX(2deg); }
  45%  { transform: translateZ(40px) translateY(-8px) rotateX(-20deg); }
  62%  { transform: translateZ(34px) translateY(-6px) rotateX(-18deg); }
  100% { transform: translateZ(0) rotateX(-6deg); }
}

@media (prefers-reduced-motion: reduce) {
  .v3, .v3 .p { animation: none !important; }
}

/* ---------- タイトルの 待機（おそわない・やさしく ゆれる） ---------- */
.mo-title { animation: moBob 2.8s ease-in-out infinite; }
.mo-title .p--body { animation: moRock 3.1s ease-in-out infinite; }
.mo-title .p--wingL { animation: moFlapL 1.6s ease-in-out infinite; }
.mo-title .p--wingR { animation: moFlapR 1.6s ease-in-out infinite; }
.mo-title .p--legA { animation: moShift 2.4s ease-in-out infinite; }
.mo-title .p--legB { animation: moShift 2.4s ease-in-out 1.2s infinite; }

/* ---------- たからばこ（chest3d.js・2026-09-10） ----------
   部品： .p--base > .p--lid（ちょうつがい＝うしろの 上の へり・rotateX(+) で 前が 上がる） .p--coins（ふたの 中の 金貨）
   クラス（.v3--chest に つける）
     is-open        … ひらいた まま（タイトル）
     mo-chest       … バトルの 待機（ふわふわ＋ときどき ふたが ガタガタ＝「何か 入って いる！」）
     mo-chest-open  … ひらく（ため → ばっと ひらく → 少し もどる。金貨が とび出す・0.9秒）
     mo-chest-title … タイトルの 待機（ふわふわ・金貨が きらっと） */
.v3--chest .p--coins { opacity: 0; }
.v3--chest.is-open .p--lid { transform: rotateX(108deg); }
.v3--chest.is-open .p--coins { opacity: 1; }
.mo-chest { animation: moBob 2.6s ease-in-out infinite; }
.mo-chest .p--lid { animation: moLidRattle 3.2s ease-in-out infinite; }
@keyframes moLidRattle {
  0%, 68%, 100% { transform: rotateX(0); }
  72% { transform: rotateX(8deg); }
  76% { transform: rotateX(1deg); }
  80% { transform: rotateX(7deg); }
  84% { transform: rotateX(0); }
  88% { transform: rotateX(5deg); }
  92% { transform: rotateX(0); }
}
.mo-chest-open { animation: moChestHop .9s ease-out both; }
.mo-chest-open .p--lid { animation: moLidOpen .9s cubic-bezier(.3, 1.25, .5, 1) both; }
.mo-chest-open .p--coins { animation: moCoinsUp .9s ease-out both; }
@keyframes moChestHop { 0%, 30%, 100% { transform: translateY(0); } 45% { transform: translateY(-9px); } 62% { transform: translateY(0); } 72% { transform: translateY(-3px); } }
@keyframes moLidOpen { 0% { transform: rotateX(0); } 18% { transform: rotateX(6deg); } 30% { transform: rotateX(2deg); } 62% { transform: rotateX(124deg); } 82% { transform: rotateX(100deg); } 100% { transform: rotateX(108deg); } }
@keyframes moCoinsUp { 0%, 34% { opacity: 0; transform: translateY(10px); } 66% { opacity: 1; transform: translateY(-7px); } 100% { opacity: 1; transform: translateY(0); } }
.mo-chest-title { animation: moBob 3s ease-in-out infinite; }
/* 金貨に filter を かけない（filter は 3D を 平らに する）。きらめきは 2D の spark に まかせる */

/* ---------- v12 で 決めた 動き（2026-09-10・ユーザー「全部 おすすめで OK」） ----------
   ③登場＝1体めと ボスだけ 歩く（mo-walk）。2体めからは はねて 出る（mo-hop）
   ④こうげき＝0.42秒。主人公は **てきの 手まえまで 走って 斬って もどる**（ユーザー要望・mo-dash は 器の .v3scene に）
   ⑤ボスは くずれ落ちる（mo-crumble） */

/* 登場（はねて 出る・0.6秒）：右から 2回 はねて 着地。あしは ちぢめ・はねは ばたばた */
.mo-hop { animation: moHopIn .6s ease-out both; }
.mo-hop .p--legA, .mo-hop .p--legB { animation: moLegTuck .3s ease-out 2; }
.mo-hop .p--wingL { animation: moFlapL .3s ease-in-out 2; }
.mo-hop .p--wingR { animation: moFlapR .3s ease-in-out 2; }
@keyframes moHopIn {
  0%   { transform: translateX(120px) translateY(0) scale(1); }
  20%  { transform: translateX(90px) translateY(-26px) scale(1); }
  40%  { transform: translateX(60px) translateY(0) scale(1.08, .9); }
  48%  { transform: translateX(54px) translateY(0) scale(1); }
  72%  { transform: translateX(18px) translateY(-18px) scale(1); }
  92%  { transform: translateX(0) translateY(0) scale(1.08, .9); }
  100% { transform: translateX(0) translateY(0) scale(1); }
}

/* ダッシュ こうげき（主人公・0.42秒）：器（.v3scene）が てきの 手まえまで 走り（22%）、そこで 斬って（55%）、もどる。
   --dash＝きょり（demo3d.js が 画面から 測って 入れる。ゲームでは 主人公の 右はしから てきの 左はしまで） */
.mo-dash { animation: moDash .42s both; }
@keyframes moDash {
  0%   { transform: translateX(0); animation-timing-function: cubic-bezier(.2, .8, .3, 1); }
  22%  { transform: translateX(var(--dash, 160px)); animation-timing-function: linear; }
  66%  { transform: translateX(var(--dash, 160px)); animation-timing-function: ease-in-out; }
  100% { transform: translateX(0); }
}
/* 部品の 動きも 0.42秒に そろえる（ふりかぶりは 走って いる あいだ・斬るのは ついた あと） */
.mo-attack.v3--hero .p--armR, .mo-attack.v3--hero .p--armL, .mo-attack.v3--hero .p--body,
.mo-attack.v3--hero .p--head, .mo-attack.v3--hero .p--sword { animation-duration: .42s; }
.mo-attack.v3--hero .p--legA { animation: moDashLegA .42s ease-in-out both; }
.mo-attack.v3--hero .p--legB { animation: moDashLegB .42s ease-in-out both; }
@keyframes moDashLegA { 0%, 30%, 100% { transform: rotateX(0); } 10% { transform: rotateX(40deg); } 20% { transform: rotateX(-30deg); } 80% { transform: rotateX(25deg); } }
@keyframes moDashLegB { 0%, 30%, 100% { transform: rotateX(0); } 10% { transform: rotateX(-30deg); } 20% { transform: rotateX(40deg); } 80% { transform: rotateX(-25deg); } }

/* ボスが くずれ落ちる（1.1秒）：ぐらっと ゆれて → 前に ひざを つき → しずんで 消える。
   横に ばたん（mo-fall）は ザコ用。ボスは 大きい ので 横だと 画面から はみ出す */
.mo-crumble { animation: moCrumble 1.1s ease-in both; transform-origin: 50% 100%; }
.mo-crumble .p--body { animation: moCrumbleBody 1.1s ease-in both; }
.mo-crumble .p--legA { animation: moCrumbleLegA 1.1s ease-in both; }
.mo-crumble .p--legB { animation: moCrumbleLegB 1.1s ease-in both; }
.mo-crumble .p--wingL { animation: moCrumbleWingL 1.1s ease-in both; }
.mo-crumble .p--wingR { animation: moCrumbleWingR 1.1s ease-in both; }
@keyframes moCrumble {
  0%   { transform: translate(0, 0) scaleY(1); opacity: 1; }
  10%  { transform: translate(-3px, 0) scaleY(1); }
  20%  { transform: translate(3px, 0) scaleY(1); }
  30%  { transform: translate(-2px, -3px) scaleY(1); }
  50%  { transform: translate(0, 6px) scaleY(.9); opacity: 1; }
  75%  { transform: translate(0, 16px) scaleY(.7); opacity: 1; }
  100% { transform: translate(0, 32px) scaleY(.35) scaleX(1.12); opacity: 0; }
}
@keyframes moCrumbleBody { 0%, 30% { transform: rotateX(0); } 55% { transform: rotateX(-14deg); } 100% { transform: rotateX(-48deg); } }
@keyframes moCrumbleLegA { 0%, 30% { transform: rotateZ(0); } 100% { transform: rotateZ(-28deg); } }
@keyframes moCrumbleLegB { 0%, 30% { transform: rotateZ(0); } 100% { transform: rotateZ(28deg); } }
@keyframes moCrumbleWingL { 0%, 30% { transform: rotateZ(0); } 100% { transform: rotateZ(35deg); } }
@keyframes moCrumbleWingR { 0%, 30% { transform: rotateZ(0); } 100% { transform: rotateZ(-35deg); } }

/* ---------- タイトルの オープニング（v10.4）の あいだの 3D の 動き ----------
   とびこんで くるのは 外の 箱（.tmob・.title__hero・.title__chest）が 動く（style.css）。中の 3D は その あいだ
   はねを ばたばた・あしを ちぢめ、勇者は 両うでを 上げて 落ちて くる。たからばこは 着地の あと ふたが ひらく。 */
.title.is-opening .mo-title { animation: none; }
.title.is-opening .mo-title .p--wingL { animation: moFlapL .28s ease-in-out 5; }
.title.is-opening .mo-title .p--wingR { animation: moFlapR .28s ease-in-out 5; }
.title.is-opening .mo-title .p--legA, .title.is-opening .mo-title .p--legB { animation: moLegTuck .5s ease-out 2; }
.title.is-opening .v3--hero { animation: none; }
.title.is-opening .v3--hero .p--armL, .title.is-opening .v3--hero .p--armR { animation: moArmsUp 1.35s ease-out both; }
.title.is-opening .v3--hero .p--legA, .title.is-opening .v3--hero .p--legB { animation: moLegTuck 1.35s ease-out both; }
.title.is-opening .v3--chest .p--lid { animation: moLidOpen .7s cubic-bezier(.3, 1.25, .5, 1) 1s both; }
.title.is-opening .v3--chest .p--coins { animation: moCoinsUp .7s ease-out 1s both; }


/* =========================================================
   ゲームの 画面に 入れる ための きまり（v12.0）
   ========================================================= */
/* 器：.v3scene（perspective）> .v3fig（向き ±22°・カメラ 8°）> .v3hold（大きさ scale3d）> .v3 */
.v3scene { position: relative; }
.v3fig { position: absolute; left: 0; top: 0; transform-style: preserve-3d; }
.v3hold { position: absolute; transform-style: preserve-3d; transform-origin: center bottom; }
.hero__img3d, .enemy__img3d, .pal__img3d { pointer-events: none; }

/* 2D の 器を うごかす 動きは 3D では 止める（部品の 動き＝mo-* に おきかえる）。
   のこす もの：ひっさつの ふっとび（is-blast）・よける（is-dodge）・ガード（is-guard）・にげる（is-flee）・ぶんしん・よばれて とぶ */
.is-3d .hero.is-attack, .is-3d .hero.is-struck, .is-3d .hero.is-counter { animation: none !important; }
.is-3d .enemy.is-appear, .is-3d .enemy.is-lunge, .is-3d .enemy.is-hit { animation: none !important; }
/* たおれる：3D の 動き（横に ばたん／くずれ落ちる）の あとに 名前ごと 消える */
.is-3d .enemy.is-down { animation: v3Gone 1s ease-in forwards !important; }
.is-3d .enemy.is-bossdown { animation: v3Gone 1.3s ease-in forwards !important; }
@keyframes v3Gone { 0%, 80% { opacity: 1; } 100% { opacity: 0; } }
/* 2D の 影は 3D の 足もとの だ円に かわる */
.is-3d .shadow--hero, .is-3d .shadow--foe { display: none; }

/* タイトル：たからばこ（3D は 48マス×2＝96px の わく。箱の 左と 下が 2D の ときと 同じ 場所に なる ように） */
.title__chest.is-3d { left: 224px; bottom: -10px; width: 96px; filter: none; }
.v3scene--title { margin-left: -4px; }
.title__hero.is-3d .shadow--poster { display: none; }

/* =========================================================
   v12.2 ひっさつわざ ごとの 動き（2026-09-11・ユーザー決定「①＋②の セット」）
   8わざ ぜんぶ 同じ mo-attack（走って 1回 斬る）だった のを、わざごとに ちがう 動きに。
   正本は docs/v12.2わざモーション案.md の 表。

   きまり
   ・体・頭・あしには 背中の 面が ない（v12.1）→ 体ごと 1回転（rotateY 360）は しない。回すのは けん（p--sword）と 手首だけ。
   ・主人公の 器（.v3scene）の 走り方は mo-dash-sp／mo-dash-thru／mo-dash-jump／mo-rise。長さは --dms（JS が sp.ms を 入れる）。
   ・てきの やられ方 mo-hit-<id> は 当たる 前から つけて おき、animation-delay で 当たる 時間まで まつ
     （harness の freeze() は setTimeout を 止める ので、CSS の delay なら 止めて 撮っても 正しい 形に なる）。
   ・うで：rotateX(+)＝下の 先が 手まえに 出る（150°＝頭の 上に ふりかぶる）。rotateZ(-90)＝右うでを 右（てきの ほう）に のばす。
   ・けん：うでの 子。ふりかぶりでは うでの 角度を 打ち消す（-150°）と 刃が 上を むく。ふり下ろしは -110°。
   ========================================================= */

/* ---------- 器の 走り方（.v3scene に つける） ---------- */
/* ふつうの ダッシュと 同じ 形（22% で つく・66% まで いる・もどる）。長さだけ わざに 合わせる */
.mo-dash-sp { animation: moDash var(--dms, .95s) both; }
/* 突きぬける（こおりの やいば）：てきの 手まえで いちど ためて → てきの むこうまで 走りぬける */
.mo-dash-thru { animation: moDashThru var(--dms, 1s) both; }
@keyframes moDashThru {
  0%   { transform: translateX(0); animation-timing-function: cubic-bezier(.2, .8, .3, 1); }
  20%  { transform: translateX(calc(var(--dash, 160px) - 26px)); animation-timing-function: ease-in; }
  30%  { transform: translateX(calc(var(--dash, 160px) - 26px)); animation-timing-function: cubic-bezier(.1, .9, .2, 1); }
  38%  { transform: translateX(calc(var(--dash, 160px) + 24px)); animation-timing-function: linear; }
  64%  { transform: translateX(calc(var(--dash, 160px) + 24px)); animation-timing-function: ease-in-out; }
  100% { transform: translateX(0); }
}
/* 高く ジャンプして てきの 真上から 落ちる（いなずま おとし）：55% で 着地＝当たる */
.mo-dash-jump { animation: moDashJump var(--dms, 1.1s) both; }
@keyframes moDashJump {
  0%   { transform: translate(0, 0); animation-timing-function: ease-in; }
  18%  { transform: translate(0, 5px); animation-timing-function: cubic-bezier(.2, .8, .3, 1); }
  38%  { transform: translate(calc(var(--dash, 160px) * .6), -60px); animation-timing-function: ease-out; }
  47%  { transform: translate(var(--dash, 160px), -54px); animation-timing-function: cubic-bezier(.6, 0, 1, .4); }
  55%  { transform: translate(var(--dash, 160px), 0); animation-timing-function: ease-out; }
  59%  { transform: translate(var(--dash, 160px), -4px); }
  63%  { transform: translate(var(--dash, 160px), 0); }
  80%  { transform: translate(var(--dash, 160px), 0); animation-timing-function: ease-in-out; }
  100% { transform: translate(0, 0); }
}
/* その場で 空中に うかぶ（ぎんがの ビッグバン）：12〜26% うかんで → 30% で 落ちる＝ばくはつ */
.mo-rise { animation: moRise var(--dms, 1.9s) both; }
@keyframes moRise {
  0%   { transform: translateY(0); animation-timing-function: ease-out; }
  12%  { transform: translateY(-46px); animation-timing-function: ease-in-out; }
  26%  { transform: translateY(-52px); animation-timing-function: cubic-bezier(.6, 0, 1, .4); }
  30%  { transform: translateY(0); animation-timing-function: ease-out; }
  34%  { transform: translateY(-7px); }
  38%, 100% { transform: translateY(0); }
}

/* ---------- 5コンボ：ほのお ギリ（算数）＝とび上がって 落ちながら たてに 一閃（.95s・mo-dash-sp） ---------- */
.mo-sp-fire { animation: spFireRoot .95s ease-in-out both; }
.mo-sp-fire .p--armR { animation: spFireArm .95s ease-in-out both; }
.mo-sp-fire .p--sword { animation: spFireSword .95s ease-in-out both; }
.mo-sp-fire .p--armL { animation: spFireArmL .95s ease-in-out both; }
.mo-sp-fire .p--head { animation: spFireHead .95s ease-in-out both; }
.mo-sp-fire .p--legA, .mo-sp-fire .p--legB { animation: spLegTuck .95s ease-in-out both; }
@keyframes spFireRoot {
  0%, 18% { transform: translateY(0) rotateX(0); }
  24%  { transform: translateY(4px) rotateX(-6deg); }
  36%  { transform: translateY(-42px) rotateX(-10deg); }
  46%  { transform: translateY(-36px) rotateX(4deg); }
  55%  { transform: translateY(0) rotateX(12deg); }
  68%  { transform: translateY(0) rotateX(4deg); }
  100% { transform: translateY(0) rotateX(0); }
}
@keyframes spFireArm { 0%, 18% { transform: rotateX(0); } 30%, 46% { transform: rotateX(160deg); } 55%, 76% { transform: rotateX(-30deg); } 100% { transform: rotateX(0); } }
@keyframes spFireSword { 0%, 18% { transform: rotateX(0); } 30%, 46% { transform: rotateX(-160deg); } 55%, 76% { transform: rotateX(-110deg); } 100% { transform: rotateX(0); } }
@keyframes spFireArmL { 0%, 18% { transform: rotateX(0); } 36% { transform: rotateX(-40deg); } 55% { transform: rotateX(25deg); } 100% { transform: rotateX(0); } }
@keyframes spFireHead { 0%, 24% { transform: rotateX(0); } 40% { transform: rotateX(-8deg); } 55% { transform: rotateX(14deg); } 100% { transform: rotateX(0); } }
@keyframes spLegTuck { 0%, 24% { transform: rotateX(0); } 36%, 46% { transform: rotateX(34deg); } 55%, 100% { transform: rotateX(0); } }
/* やられ方：のけぞって しりもち */
.mo-hit-fire { animation: hitFire .55s ease-out .5s both; }
.mo-hit-fire .p--body { animation: hitBodyBack .55s ease-out .5s both; }
.mo-hit-fire .p--legA, .mo-hit-fire .p--legB { animation: hitLegFold .55s ease-out .5s both; }
.mo-hit-fire .p--wingL { animation: moFlapBigL .55s ease-out .5s both; }
.mo-hit-fire .p--wingR { animation: moFlapBigR .55s ease-out .5s both; }
@keyframes hitFire {
  0%   { transform: translateZ(0) translateY(0) rotateX(0); }
  25%  { transform: translateZ(-14px) translateY(-6px) rotateX(16deg); }
  55%  { transform: translateZ(-10px) translateY(10px) rotateX(24deg); }
  72%  { transform: translateZ(-8px) translateY(8px) rotateX(20deg); }
  100% { transform: translateZ(0) translateY(0) rotateX(0); }
}
@keyframes hitBodyBack { 0%, 100% { transform: rotateX(0); } 40% { transform: rotateX(14deg); } }
@keyframes hitLegFold { 0%, 100% { transform: rotateX(0); } 55% { transform: rotateX(-34deg); } }

/* ---------- 5コンボ：はっぱ カッター（国語）＝体を ひねって 左右に 2連斬り（.95s・mo-dash-sp） ---------- */
.mo-sp-leaf { animation: spLeafRoot .95s ease-in-out both; }
.mo-sp-leaf .p--armR { animation: spLeafArm .95s ease-in-out both; }
.mo-sp-leaf .p--armL { animation: spLeafArmL .95s ease-in-out both; }
.mo-sp-leaf .p--head { animation: spLeafHead .95s ease-in-out both; }
.mo-sp-leaf .p--legA { animation: moDashLegA .95s ease-in-out both; }
.mo-sp-leaf .p--legB { animation: moDashLegB .95s ease-in-out both; }
@keyframes spLeafRoot {
  0%, 20% { transform: rotateY(0) rotateX(0); }
  26%  { transform: rotateY(-24deg) rotateX(-4deg); }
  34%  { transform: rotateY(18deg) rotateX(6deg); }
  44%  { transform: rotateY(-22deg) rotateX(-4deg); }
  54%  { transform: rotateY(20deg) rotateX(8deg); }
  72%  { transform: rotateY(0) rotateX(0); }
  100% { transform: rotateY(0) rotateX(0); }
}
@keyframes spLeafArm {
  0%, 20% { transform: rotateZ(0); }
  26%  { transform: rotateZ(28deg) rotateX(20deg); }
  34%  { transform: rotateZ(-105deg) rotateX(10deg); }
  44%  { transform: rotateZ(28deg) rotateX(20deg); }
  54%  { transform: rotateZ(-105deg) rotateX(10deg); }
  72%  { transform: rotateZ(-40deg) rotateX(0); }
  100% { transform: rotateZ(0) rotateX(0); }
}
@keyframes spLeafArmL { 0%, 20% { transform: rotateZ(0); } 34% { transform: rotateZ(30deg); } 54% { transform: rotateZ(30deg); } 100% { transform: rotateZ(0); } }
@keyframes spLeafHead { 0%, 20% { transform: rotateY(0); } 34% { transform: rotateY(12deg); } 54% { transform: rotateY(12deg); } 100% { transform: rotateY(0); } }
/* やられ方：左右に 2回 ゆれる */
.mo-hit-leaf { animation: hitLeaf .6s ease-out .34s both; transform-origin: 50% 100%; }
.mo-hit-leaf .p--wingL { animation: moFlapBigL .6s ease-out .34s both; }
.mo-hit-leaf .p--wingR { animation: moFlapBigR .6s ease-out .34s both; }
@keyframes hitLeaf {
  0%   { transform: translateX(0) rotateZ(0); }
  18%  { transform: translateX(-8px) rotateZ(-12deg); }
  42%  { transform: translateX(7px) rotateZ(10deg); }
  64%  { transform: translateX(-4px) rotateZ(-6deg); }
  84%  { transform: translateX(2px) rotateZ(3deg); }
  100% { transform: translateX(0) rotateZ(0); }
}

/* ---------- 5コンボ：こおりの やいば（理科社会）＝けんを 前に かまえて 突きぬける（1s・mo-dash-thru） ---------- */
.mo-sp-ice { animation: spIceRoot 1s ease-in-out both; }
.mo-sp-ice .p--armR { animation: spIceArm 1s ease-in-out both; }
.mo-sp-ice .p--armL { animation: spIceArmL 1s ease-in-out both; }
.mo-sp-ice .p--head { animation: spIceHead 1s ease-in-out both; }
.mo-sp-ice .p--legA { animation: spIceLegA 1s ease-in-out both; }
.mo-sp-ice .p--legB { animation: spIceLegB 1s ease-in-out both; }
@keyframes spIceRoot { 0% { transform: rotateX(0); } 20%, 30% { transform: rotateX(-6deg) translateY(2px); } 38%, 64% { transform: rotateX(-16deg); } 100% { transform: rotateX(0); } }
@keyframes spIceArm { 0% { transform: rotateZ(0); } 16%, 30% { transform: rotateZ(-60deg) rotateX(8deg); } 38%, 64% { transform: rotateZ(-92deg) rotateX(0); } 100% { transform: rotateZ(0); } }
@keyframes spIceArmL { 0% { transform: rotateX(0); } 20%, 64% { transform: rotateX(40deg); } 100% { transform: rotateX(0); } }
@keyframes spIceHead { 0% { transform: rotateX(0); } 38%, 64% { transform: rotateX(-8deg); } 100% { transform: rotateX(0); } }
@keyframes spIceLegA { 0% { transform: rotateX(0); } 10% { transform: rotateX(30deg); } 20% { transform: rotateX(-20deg); } 38%, 64% { transform: rotateX(38deg); } 100% { transform: rotateX(0); } }
@keyframes spIceLegB { 0% { transform: rotateX(0); } 10% { transform: rotateX(-20deg); } 20% { transform: rotateX(30deg); } 38%, 64% { transform: rotateX(-36deg); } 100% { transform: rotateX(0); } }
/* やられ方：こおって 動きが 止まり → かたむく（あし・はねも 止める） */
.mo-hit-ice { animation: hitIce .6s ease-in .36s both; transform-origin: 50% 100%; }
.mo-hit-ice .p, .mo-hit-ice .p--body { animation: none; }
@keyframes hitIce {
  0%   { transform: translateX(0) rotateZ(0); }
  8%   { transform: translateX(2px) rotateZ(0); }
  16%  { transform: translateX(-2px) rotateZ(0); }
  24%  { transform: translateX(1px) rotateZ(0); }
  40%  { transform: translateX(0) rotateZ(0); }
  70%  { transform: translateX(0) rotateZ(-14deg); }
  100% { transform: translateX(0) rotateZ(-14deg); }
}

/* ---------- 5コンボ：かぜの たつまき（英語）＝空中で けんを ぐるぐる 回す（1s・mo-dash-sp） ---------- */
.mo-sp-wind { animation: spWindRoot 1s ease-in-out both; }
.mo-sp-wind .p--armR { animation: spWindArm 1s ease-in-out both; }
.mo-sp-wind .p--sword { animation: spWindSword 1s linear both; }
.mo-sp-wind .p--armL { animation: spFireArmL 1s ease-in-out both; }
.mo-sp-wind .p--legA, .mo-sp-wind .p--legB { animation: spWindLeg 1s ease-in-out both; }
@keyframes spWindRoot {
  0%, 18% { transform: translateY(0) rotateZ(0); }
  26%  { transform: translateY(-30px) rotateZ(-4deg); }
  40%  { transform: translateY(-34px) rotateZ(4deg); }
  54%  { transform: translateY(-32px) rotateZ(-4deg); }
  66%  { transform: translateY(-30px) rotateZ(3deg); }
  76%  { transform: translateY(0) rotateZ(0); }
  100% { transform: translateY(0) rotateZ(0); }
}
@keyframes spWindArm { 0%, 18% { transform: rotateZ(0); } 26%, 68% { transform: rotateZ(-92deg); } 82%, 100% { transform: rotateZ(0); } }
/* 手首：3回転（けんには 背中の 面が ある ので 回して よい） */
@keyframes spWindSword { 0%, 22% { transform: rotateZ(0); } 70% { transform: rotateZ(-1080deg); } 100% { transform: rotateZ(-1080deg); } }
@keyframes spWindLeg { 0%, 18% { transform: rotateX(0); } 26%, 66% { transform: rotateX(30deg); } 76%, 100% { transform: rotateX(0); } }
/* やられ方：くるっと 回されて ふらつく（左の 面が ない ので 右へ だけ 回す） */
.mo-hit-wind { animation: hitWind .62s ease-out .38s both; }
.mo-hit-wind .p--wingL { animation: moFlapL .2s ease-in-out .38s 3; }
.mo-hit-wind .p--wingR { animation: moFlapR .2s ease-in-out .38s 3; }
@keyframes hitWind {
  0%   { transform: translateX(0) translateY(0) rotateY(0) rotateZ(0); }
  30%  { transform: translateX(-8px) translateY(-10px) rotateY(58deg) rotateZ(-6deg); }
  52%  { transform: translateX(4px) translateY(0) rotateY(8deg) rotateZ(7deg); }
  72%  { transform: translateX(-3px) translateY(0) rotateY(0) rotateZ(-5deg); }
  88%  { transform: translateX(2px) translateY(0) rotateY(0) rotateZ(3deg); }
  100% { transform: translateX(0) translateY(0) rotateY(0) rotateZ(0); }
}

/* ---------- 8コンボ：いなずま おとし＝高く ジャンプ → 真上から 落下斬り（1.1s・mo-dash-jump・55% で 着地） ---------- */
.mo-sp-bolt { animation: spBoltRoot 1.1s ease-in-out both; }
.mo-sp-bolt .p--armR { animation: spBoltArm 1.1s ease-in-out both; }
.mo-sp-bolt .p--sword { animation: spBoltSword 1.1s ease-in-out both; }
.mo-sp-bolt .p--armL { animation: spBoltArmL 1.1s ease-in-out both; }
.mo-sp-bolt .p--head { animation: spBoltHead 1.1s ease-in-out both; }
.mo-sp-bolt .p--legA, .mo-sp-bolt .p--legB { animation: spBoltLeg 1.1s ease-in-out both; }
@keyframes spBoltRoot {
  0%   { transform: rotateX(0); }
  18%  { transform: rotateX(-10deg); }
  38%  { transform: rotateX(-6deg); }
  50%  { transform: rotateX(14deg); }
  55%  { transform: rotateX(16deg) translateY(2px); }
  66%  { transform: rotateX(6deg) translateY(0); }
  100% { transform: rotateX(0); }
}
@keyframes spBoltArm { 0%, 18% { transform: rotateX(0); } 34%, 48% { transform: rotateX(165deg); } 55%, 78% { transform: rotateX(-30deg); } 100% { transform: rotateX(0); } }
@keyframes spBoltSword { 0%, 18% { transform: rotateX(0); } 34%, 48% { transform: rotateX(-165deg); } 55%, 78% { transform: rotateX(-110deg); } 100% { transform: rotateX(0); } }
@keyframes spBoltArmL { 0%, 18% { transform: rotateX(0); } 38% { transform: rotateX(-50deg); } 55% { transform: rotateX(30deg); } 100% { transform: rotateX(0); } }
@keyframes spBoltHead { 0%, 18% { transform: rotateX(0); } 38% { transform: rotateX(-10deg); } 55% { transform: rotateX(16deg); } 100% { transform: rotateX(0); } }
@keyframes spBoltLeg { 0% { transform: rotateX(0); } 18% { transform: rotateX(20deg); } 34%, 48% { transform: rotateX(40deg); } 55% { transform: rotateX(-6deg); } 66%, 100% { transform: rotateX(0); } }
/* やられ方：ビリビリ ふるえる */
.mo-hit-bolt { animation: hitBolt .5s linear .6s both; }
.mo-hit-bolt .p--legA, .mo-hit-bolt .p--legB { animation: hitBoltLeg .5s linear .6s both; }
@keyframes hitBolt {
  0%   { transform: translateX(0) rotateZ(0) translateY(0); }
  8%   { transform: translateX(-4px) rotateZ(-3deg) translateY(-3px); }
  16%  { transform: translateX(4px) rotateZ(3deg) translateY(0); }
  24%  { transform: translateX(-4px) rotateZ(-3deg) translateY(-2px); }
  32%  { transform: translateX(4px) rotateZ(3deg) translateY(0); }
  40%  { transform: translateX(-3px) rotateZ(-2deg) translateY(-2px); }
  48%  { transform: translateX(3px) rotateZ(2deg) translateY(0); }
  56%  { transform: translateX(-3px) rotateZ(-2deg) translateY(-1px); }
  64%  { transform: translateX(3px) rotateZ(2deg) translateY(0); }
  72%  { transform: translateX(-2px) rotateZ(-1deg) translateY(0); }
  80%  { transform: translateX(2px) rotateZ(1deg) translateY(0); }
  100% { transform: translateX(0) rotateZ(0) translateY(0); }
}
@keyframes hitBoltLeg { 0%, 100% { transform: rotateX(0); } 10%, 30%, 50%, 70% { transform: rotateX(12deg); } 20%, 40%, 60%, 80% { transform: rotateX(-12deg); } }

/* ---------- 12コンボ：ひかりの メテオ＝しゃがんで ためる → けんを 天に かかげる → 見上げた まま（1.35s・その場） ---------- */
.mo-sp-star { animation: spStarRoot 1.35s ease-in-out both; }
.mo-sp-star .p--armR { animation: spStarArm 1.35s ease-in-out both; }
.mo-sp-star .p--sword { animation: spStarSword 1.35s ease-in-out both; }
.mo-sp-star .p--armL { animation: spStarArmL 1.35s ease-in-out both; }
.mo-sp-star .p--head { animation: spStarHead 1.35s ease-in-out both; }
.mo-sp-star .p--legA, .mo-sp-star .p--legB { animation: spStarLeg 1.35s ease-in-out both; }
@keyframes spStarRoot {
  0%   { transform: translateY(0) rotateX(0); }
  10%, 22% { transform: translateY(7px) rotateX(-10deg); }
  30%, 84% { transform: translateY(-4px) rotateX(6deg); }
  100% { transform: translateY(0) rotateX(0); }
}
@keyframes spStarArm { 0% { transform: rotateX(0); } 10%, 22% { transform: rotateX(20deg); } 30%, 84% { transform: rotateX(176deg); } 100% { transform: rotateX(0); } }
@keyframes spStarSword { 0% { transform: rotateX(0); } 10%, 22% { transform: rotateX(-20deg); } 30%, 84% { transform: rotateX(-176deg); } 100% { transform: rotateX(0); } }
@keyframes spStarArmL { 0% { transform: rotateX(0); } 10%, 22% { transform: rotateX(20deg); } 30%, 84% { transform: rotateX(-30deg); } 100% { transform: rotateX(0); } }
@keyframes spStarHead { 0% { transform: rotateX(0); } 10%, 22% { transform: rotateX(10deg); } 30%, 84% { transform: rotateX(-18deg); } 100% { transform: rotateX(0); } }
@keyframes spStarLeg { 0% { transform: rotateX(0); } 10%, 22% { transform: rotateX(32deg); } 30%, 100% { transform: rotateX(0); } }
/* やられ方：いん石に おされて ぺしゃんと つぶれる */
.mo-hit-star { animation: hitStar .55s ease-out .62s both; transform-origin: 50% 100%; }
.mo-hit-star .p--legA { animation: hitStarLegA .55s ease-out .62s both; }
.mo-hit-star .p--legB { animation: hitStarLegB .55s ease-out .62s both; }
.mo-hit-star .p--wingL { animation: moFlapBigL .55s ease-out .62s both; }
.mo-hit-star .p--wingR { animation: moFlapBigR .55s ease-out .62s both; }
@keyframes hitStar {
  0%   { transform: scale(1, 1); }
  28%  { transform: scale(1.28, .55); }
  52%  { transform: scale(1.08, .82); }
  72%  { transform: scale(1.2, .64); }
  100% { transform: scale(1, 1); }
}
@keyframes hitStarLegA { 0%, 100% { transform: rotateZ(0); } 30%, 70% { transform: rotateZ(-26deg); } }
@keyframes hitStarLegB { 0%, 100% { transform: rotateZ(0); } 30%, 70% { transform: rotateZ(26deg); } }

/* ---------- 16コンボ：ぎんがの ビッグバン＝空中に うかんで 両うでを 広げる → 落下と 同時に 爆発（1.9s・mo-rise・30% で 落ちる） ---------- */
.mo-sp-nova { animation: spNovaRoot 1.9s ease-in-out both; }
.mo-sp-nova .p--armR { animation: spNovaArm 1.9s ease-in-out both; }
.mo-sp-nova .p--sword { animation: spNovaSword 1.9s ease-in-out both; }
.mo-sp-nova .p--armL { animation: spNovaArmL 1.9s ease-in-out both; }
.mo-sp-nova .p--head { animation: spNovaHead 1.9s ease-in-out both; }
.mo-sp-nova .p--legA, .mo-sp-nova .p--legB { animation: spNovaLeg 1.9s ease-in-out both; }
@keyframes spNovaRoot {
  0%   { transform: rotateX(0); }
  12%, 26% { transform: rotateX(-8deg); }
  30%  { transform: rotateX(14deg) translateY(2px); }
  40%  { transform: rotateX(4deg) translateY(0); }
  100% { transform: rotateX(0); }
}
@keyframes spNovaArm { 0% { transform: rotateZ(0) rotateX(0); } 12%, 26% { transform: rotateZ(-84deg) rotateX(0); } 30%, 46% { transform: rotateZ(0) rotateX(-30deg); } 100% { transform: rotateZ(0) rotateX(0); } }
@keyframes spNovaSword { 0% { transform: rotateX(0); } 12%, 26% { transform: rotateX(0); } 30%, 46% { transform: rotateX(-110deg); } 100% { transform: rotateX(0); } }
@keyframes spNovaArmL { 0% { transform: rotateZ(0); } 12%, 26% { transform: rotateZ(84deg); } 30%, 46% { transform: rotateZ(0) rotateX(20deg); } 100% { transform: rotateZ(0); } }
@keyframes spNovaHead { 0% { transform: rotateX(0); } 12%, 26% { transform: rotateX(-16deg); } 30% { transform: rotateX(12deg); } 100% { transform: rotateX(0); } }
@keyframes spNovaLeg { 0% { transform: rotateX(0); } 12%, 26% { transform: rotateX(-16deg); } 30% { transform: rotateX(20deg); } 40%, 100% { transform: rotateX(0); } }
/* やられ方：すいこまれて 小さく なり → 大きく ふっとぶ */
.mo-hit-nova { animation: hitNova .7s ease-in-out .55s both; }
.mo-hit-nova .p--legA, .mo-hit-nova .p--legB { animation: hitLegFold .7s ease-in-out .55s both; }
.mo-hit-nova .p--wingL { animation: moFlapBigL .7s ease-in-out .55s both; }
.mo-hit-nova .p--wingR { animation: moFlapBigR .7s ease-in-out .55s both; }
@keyframes hitNova {
  0%   { transform: translate(0, 0) scale(1) rotateZ(0); }
  22%  { transform: translate(-16px, 4px) scale(.82) rotateZ(-8deg); }
  36%  { transform: translate(-10px, 6px) scale(.72) rotateZ(-4deg); }
  52%  { transform: translate(34px, -26px) scale(1.12) rotateZ(16deg); }
  74%  { transform: translate(24px, -10px) scale(1.05) rotateZ(10deg); }
  100% { transform: translate(0, 0) scale(1) rotateZ(0); }
}

/* ---------- 20コンボ：スターバースト ストライク＝高速の 連続 突き ×6 → さいごに 大きく 一閃（2.1s・mo-dash-sp） ----------
   22%（0.46秒）で つく → 24〜52% で 0.1秒ごとに 6回 突く → 56% ふりかぶり → 62%（1.3秒）大きく 一閃 */
.mo-sp-starburst { animation: spBurstRoot 2.1s ease-in-out both; }
.mo-sp-starburst .p--armR { animation: spBurstArm 2.1s linear both; }
.mo-sp-starburst .p--sword { animation: spBurstSword 2.1s ease-in-out both; }
.mo-sp-starburst .p--armL { animation: spBurstArmL 2.1s ease-in-out both; }
.mo-sp-starburst .p--head { animation: spBurstHead 2.1s ease-in-out both; }
.mo-sp-starburst .p--legA { animation: spBurstLegA 2.1s ease-in-out both; }
.mo-sp-starburst .p--legB { animation: spBurstLegB 2.1s ease-in-out both; }
@keyframes spBurstRoot {
  0%, 20% { transform: rotateX(0); }
  24%, 52% { transform: rotateX(-12deg); }
  56%  { transform: rotateX(-4deg) translateY(-6px); }
  62%  { transform: rotateX(14deg) translateY(0); }
  76%  { transform: rotateX(4deg); }
  100% { transform: rotateX(0); }
}
@keyframes spBurstArm {
  0%, 20% { transform: rotateZ(0) rotateX(0); }
  22%  { transform: rotateZ(-30deg) rotateX(0); }
  24%  { transform: rotateZ(-98deg); } 26.5% { transform: rotateZ(-38deg); }
  29%  { transform: rotateZ(-98deg); } 31.5% { transform: rotateZ(-38deg); }
  34%  { transform: rotateZ(-98deg); } 36.5% { transform: rotateZ(-38deg); }
  39%  { transform: rotateZ(-98deg); } 41.5% { transform: rotateZ(-38deg); }
  44%  { transform: rotateZ(-98deg); } 46.5% { transform: rotateZ(-38deg); }
  49%  { transform: rotateZ(-98deg); } 52%   { transform: rotateZ(-30deg); }
  56%, 58% { transform: rotateZ(0) rotateX(165deg); }
  62%, 78% { transform: rotateZ(0) rotateX(-30deg); }
  100% { transform: rotateZ(0) rotateX(0); }
}
@keyframes spBurstSword { 0%, 52% { transform: rotateX(0); } 56%, 58% { transform: rotateX(-165deg); } 62%, 78% { transform: rotateX(-110deg); } 100% { transform: rotateX(0); } }
@keyframes spBurstArmL { 0%, 20% { transform: rotateX(0); } 24%, 52% { transform: rotateX(36deg); } 58% { transform: rotateX(-40deg); } 62% { transform: rotateX(24deg); } 100% { transform: rotateX(0); } }
@keyframes spBurstHead { 0%, 20% { transform: rotateX(0); } 24%, 52% { transform: rotateX(-6deg); } 58% { transform: rotateX(-10deg); } 62% { transform: rotateX(14deg); } 100% { transform: rotateX(0); } }
@keyframes spBurstLegA { 0% { transform: rotateX(0); } 8% { transform: rotateX(40deg); } 16% { transform: rotateX(-30deg); } 24%, 52% { transform: rotateX(36deg); } 62%, 100% { transform: rotateX(0); } }
@keyframes spBurstLegB { 0% { transform: rotateX(0); } 8% { transform: rotateX(-30deg); } 16% { transform: rotateX(40deg); } 24%, 52% { transform: rotateX(-34deg); } 62%, 100% { transform: rotateX(0); } }
/* やられ方：突かれる たびに はねる（6回・0.1秒ごと）→ さいごの 一閃で 大きく のけぞる（1.4秒・0.5秒 あとから） */
.mo-hit-starburst { animation: hitBurst 1.4s linear .5s both; }
.mo-hit-starburst .p--body { animation: hitBurstBody 1.4s linear .5s both; }
.mo-hit-starburst .p--wingL { animation: moFlapL .12s ease-in-out .5s 5; }
.mo-hit-starburst .p--wingR { animation: moFlapR .12s ease-in-out .5s 5; }
@keyframes hitBurst {
  0%    { transform: translate(0, 0) rotateZ(0) rotateX(0); }
  3.5%  { transform: translate(5px, -7px) rotateZ(4deg) rotateX(0); }  7%   { transform: translate(1px, 0) rotateZ(0) rotateX(0); }
  10.5% { transform: translate(5px, -7px) rotateZ(-4deg) rotateX(0); } 14%  { transform: translate(1px, 0) rotateZ(0) rotateX(0); }
  17.5% { transform: translate(6px, -8px) rotateZ(4deg) rotateX(0); }  21%  { transform: translate(1px, 0) rotateZ(0) rotateX(0); }
  24.5% { transform: translate(6px, -8px) rotateZ(-4deg) rotateX(0); } 28%  { transform: translate(1px, 0) rotateZ(0) rotateX(0); }
  31.5% { transform: translate(7px, -9px) rotateZ(4deg) rotateX(0); }  35%  { transform: translate(1px, 0) rotateZ(0) rotateX(0); }
  38.5% { transform: translate(7px, -9px) rotateZ(-4deg) rotateX(0); } 42%  { transform: translate(2px, 0) rotateZ(0) rotateX(0); }
  57%   { transform: translate(2px, 0) rotateZ(0) rotateX(0); }
  62%   { transform: translate(26px, -14px) rotateZ(10deg) rotateX(22deg); }
  80%   { transform: translate(18px, 0) rotateZ(6deg) rotateX(14deg); }
  100%  { transform: translate(0, 0) rotateZ(0) rotateX(0); }
}
@keyframes hitBurstBody { 0%, 57% { transform: rotateX(0); } 62%, 80% { transform: rotateX(16deg); } 100% { transform: rotateX(0); } }

/* v12.2：3D の ときは 2D の「大きく とびこむ」（specialbigfx＝.hero を 36px 右へ・1.3倍）を 止める。
   走る・とぶ は 器（mo-dash-*）と 部品の 動きで 見せる。うしろの オーラ（::before）は のこす */
.is-3d .hero.is-special { animation: none !important; }

/* ---------- v12.2.1 ③ 相棒も わざに 合わせる（2026-09-11） ----------
   器（.pal の .v3scene）：mo-pal-follow＝主人公の うしろを ついて 走る（1秒・35% で つく・70% まで いて もどる）
                          mo-pal-flank ＝てきの 右がわに とんで はさみうち（1.2秒・48% で 着地）
   体（.v3）：mo-pal-sp＝走る あいだ はね・あしを ばたばた、--phit の 時間に 手まえへ とび出す（モンスターの こうげきと 同じ moPounce）
   --pdash／--pdelay／--phit は battle.js の palJoin() が 入れる */
.mo-pal-follow { animation: palFollow 1s cubic-bezier(.2, .8, .3, 1) var(--pdelay, 0ms) both; }
@keyframes palFollow {
  0%   { transform: translateX(0); }
  35%  { transform: translateX(var(--pdash, 120px)); animation-timing-function: linear; }
  70%  { transform: translateX(var(--pdash, 120px)); animation-timing-function: ease-in-out; }
  100% { transform: translateX(0); }
}
.mo-pal-flank { animation: palFlank 1.2s ease-in-out var(--pdelay, 0ms) both; }
@keyframes palFlank {
  0%   { transform: translate(0, 0); animation-timing-function: ease-out; }
  20%  { transform: translate(calc(var(--pdash, 200px) * .5), -56px); animation-timing-function: ease-in-out; }
  42%  { transform: translate(var(--pdash, 200px), -30px); animation-timing-function: ease-in; }
  48%  { transform: translate(var(--pdash, 200px), 0); }
  52%  { transform: translate(var(--pdash, 200px), -3px); }
  56%, 72% { transform: translate(var(--pdash, 200px), 0); animation-timing-function: ease-in-out; }
  100% { transform: translate(0, 0); }
}
.mo-pal-sp { animation: moPounce .5s ease-in-out var(--phit, .4s) both; }
.mo-pal-sp .p--body { animation: moBodyPounce .5s ease-in-out var(--phit, .4s) both; }
.mo-pal-sp .p--wingL { animation: moFlapL .22s ease-in-out 6; }
.mo-pal-sp .p--wingR { animation: moFlapR .22s ease-in-out 6; }
.mo-pal-sp .p--legA { animation: moShift .2s ease-in-out 6; }
.mo-pal-sp .p--legB { animation: moShift .2s ease-in-out .1s 6; }

/* ---------- v13.6 主人公の まばたき（ユーザー「主人公も 瞬き するように。オープニングでもね」） ----------
   vox.js が 頭の 前の 面に まぶた（.v3lid）を 2まい おく。ふだんは scaleY 0（見えない）。
   動くのは バトル（.arena）と タイトル（.title）の 中だけ（モンスターの まばたき .bx__eye と 同じ きまり）。5.2秒に 1回・130ms 閉じる */
.v3lid { position: absolute; display: block; pointer-events: none; }
.v3lid i { position: absolute; left: -4%; right: -4%; top: 0; bottom: 0; display: block; transform-origin: 50% 0; transform: scaleY(0); }
.v3lid i::after { content: ''; position: absolute; left: 0; right: 0; bottom: 0; height: 18%; background: rgba(92,52,40,.92); }
.arena .v3lid i, .title .v3lid i { animation: v3blink 5.2s steps(1, end) infinite; animation-delay: var(--bw, 0s); }
@keyframes v3blink { 0%, 95.5% { transform: scaleY(0); } 96%, 98% { transform: scaleY(1); } 98.5%, 100% { transform: scaleY(0); } }
@media (prefers-reduced-motion: reduce) { .arena .v3lid i, .title .v3lid i { animation: none; } }
