/*
 * アセンダーの絵。仕様（寸法・座標・命名）は doc/ascender-assets.md、定義は app/javascript/lib/ascenders.js。
 *
 * 絵の URL は CSS 変数に書く。Propshaft がダイジェスト付きの URL に変えるので、
 * JS（PixiJS での描画）もこの変数を読んで同じ URL を使う。
 * 変数名は「--ascender-<アセンダー>-<姿>」（全身）と「--ascender-<アセンダー>-<姿>-<表情>」（顔の差分。連れのまばたきは companion）。
 * ホーム画面の立ち姿（.home-page__ascender、menu.css）と、顔の絵（.ascender-portrait、menu.css）、
 * 対戦の開始前の VS の絵（.versus-intro、application.css）も、同じ変数から絵を読む。
 * 決着の絵は「--ascender-<アセンダー>-finale-<種類>」。結果の画面のポーズ（.battle-result__pose、application.css）も読む。
 */
.ascender-art-layer,
.home-page__ascender,
.ascender-portrait,
.versus-intro,
.ascension-cut-in,
.battle-result__pose {
  --ascender-sakuya-masked: url("/assets/ascenders/sakuya/masked-98aec0ee.webp");
  --ascender-sakuya-masked-blink: url("/assets/ascenders/sakuya/masked-blink-30e84c54.webp");
  --ascender-sakuya-masked-pain: url("/assets/ascenders/sakuya/masked-pain-1eddc0d5.webp");
  --ascender-sakuya-bare: url("/assets/ascenders/sakuya/bare-c22f56df.webp");
  --ascender-sakuya-bare-blink: url("/assets/ascenders/sakuya/bare-blink-b799d1aa.webp");
  --ascender-sakuya-bare-pain: url("/assets/ascenders/sakuya/bare-pain-2381c591.webp");
  --ascender-sakuya-critical: url("/assets/ascenders/sakuya/critical-419fa882.webp");
  --ascender-sakuya-finale-knockback: url("/assets/ascenders/sakuya/finale-knockback-36ad6db0.webp");
  --ascender-sakuya-finale-victory: url("/assets/ascenders/sakuya/finale-victory-27bb9ddf.webp");
  --ascender-sakuya-finale-defeat: url("/assets/ascenders/sakuya/finale-defeat-4feca374.webp");
  --ascender-sakuya-critical-blink: url("/assets/ascenders/sakuya/critical-blink-245d4096.webp");
  --ascender-sakuya-critical-pain: url("/assets/ascenders/sakuya/critical-pain-2381c591.webp");
  --ascender-sakuya-cloth-mask: url("/assets/ascenders/sakuya/cloth-mask-cc1d19e0.webp");
  --ascender-shuten-normal: url("/assets/ascenders/shuten/normal-4af46b49.webp");
  --ascender-shuten-normal-blink: url("/assets/ascenders/shuten/normal-blink-de54d8c6.webp");
  --ascender-shuten-normal-pain: url("/assets/ascenders/shuten/normal-pain-e8dfae1d.webp");
  --ascender-shuten-wounded: url("/assets/ascenders/shuten/wounded-4c2f89da.webp");
  --ascender-shuten-wounded-blink: url("/assets/ascenders/shuten/wounded-blink-45186892.webp");
  --ascender-shuten-wounded-pain: url("/assets/ascenders/shuten/wounded-pain-678f944d.webp");
  --ascender-shuten-critical: url("/assets/ascenders/shuten/critical-db4dd916.webp");
  --ascender-shuten-finale-knockback: url("/assets/ascenders/shuten/finale-knockback-c1b59a2c.webp");
  --ascender-shuten-finale-victory: url("/assets/ascenders/shuten/finale-victory-4a4825b6.webp");
  --ascender-shuten-finale-defeat: url("/assets/ascenders/shuten/finale-defeat-b713c05c.webp");
  --ascender-shuten-critical-blink: url("/assets/ascenders/shuten/critical-blink-45186892.webp");
  --ascender-shuten-critical-pain: url("/assets/ascenders/shuten/critical-pain-01ec220e.webp");
  --ascender-mumei-normal: url("/assets/ascenders/mumei/normal-f460e160.webp");
  --ascender-mumei-normal-blink: url("/assets/ascenders/mumei/normal-blink-af76e316.webp");
  --ascender-mumei-normal-pain: url("/assets/ascenders/mumei/normal-pain-eefe85eb.webp");
  --ascender-mumei-normal-companion: url("/assets/ascenders/mumei/normal-companion-d7ec2565.webp");
  --ascender-mumei-wounded: url("/assets/ascenders/mumei/wounded-193e60e5.webp");
  --ascender-mumei-wounded-blink: url("/assets/ascenders/mumei/wounded-blink-3a3ce361.webp");
  --ascender-mumei-wounded-pain: url("/assets/ascenders/mumei/wounded-pain-2927058d.webp");
  --ascender-mumei-wounded-companion: url("/assets/ascenders/mumei/wounded-companion-408c3d1a.webp");
  --ascender-mumei-critical: url("/assets/ascenders/mumei/critical-1483fe48.webp");
  --ascender-mumei-critical-blink: url("/assets/ascenders/mumei/critical-blink-3a3ce361.webp");
  --ascender-mumei-critical-pain: url("/assets/ascenders/mumei/critical-pain-e820c11e.webp");
  --ascender-mumei-critical-companion: url("/assets/ascenders/mumei/critical-companion-0bf9fa5a.webp");
}

/*
 * 盤面の中段（左右のアセンダーの列と盤面）を覆う層。盤面より下に描く。
 * 負の z-index で .battle-page のスタッキングコンテキストの中に置き、背景（-3〜-1）の上、
 * 通常フローの UI（盤面・数値・ヘッダー・手札）の下に来るようにする。同じ -1 の「直前の背景」
 * （.battle-backdrop__outgoing）より DOM が後なので、その上に重なる。
 * 位置の基準は .battle-page__layout（グリッドの領域を基準に絶対配置する）。
 */
.ascender-art-layer {
  /* 列の下端で絵を消していく長さ */
  --ascender-art-fade: clamp(2rem, 9dvh, 5rem);
  column-gap: var(--battle-gap);
  display: grid;
  /* 絶対配置のグリッド子要素は、終わりの線を省くとグリッドの端まで広がるので、両端を書く */
  grid-column: 1 / 4;
  grid-row: 2 / 3;
  /* 列は .battle-page__layout と同じ（application.css の --battle-columns） */
  grid-template-columns: var(--battle-columns);
  inset: 0;
  pointer-events: none;
  position: absolute;
  user-select: none;
  z-index: -1;
}

/*
 * 絵と、読み込めなかったときのアセンダー名を、列の中の同じ場所に重ねる。
 * 列の下端には HP・山札・墓地（.ascender-panel）を置くので、その高さ（--ascender-plate-space）を
 * 空けて描き、足元が板に重ならないようにする。
 */
.ascender-art-layer__figure {
  box-sizing: border-box;
  display: grid;
  padding-bottom: var(--ascender-plate-space, 0px);
  position: relative;
  grid-row: 1;
  min-height: 0;
  min-width: 0;
  place-items: center;
}

/*
 * 絵は上半身を大きく見せる。見せる範囲（ascenders.js の view）の幅を列の幅に合わせて拡大し、
 * 範囲の中心を列の真ん中、範囲の上端を列の上端に置く（動く表示の ascenderViewRect と同じ計算）。
 * 列からはみ出す左右はそのまま描き、列の下端（山札・墓地の手前）で消す。
 *
 * __clip は消す範囲を決める枠。左右へはみ出す分を描けるよう、列の3倍の幅を取る。
 * __window は列と同じ箱（動く表示は、この箱の位置と大きさを読む）。
 */
.ascender-art-layer__clip {
  bottom: var(--ascender-plate-space, 0px);
  left: -100%;
  mask-image: linear-gradient(to bottom, #000 calc(100% - var(--ascender-art-fade)), transparent);
  overflow: hidden;
  position: absolute;
  right: -100%;
  top: 0;
}

.ascender-art-layer__window {
  bottom: 0;
  left: calc(100% / 3);
  position: absolute;
  top: 0;
  width: calc(100% / 3);
}

/*
 * 幅・左・上の余白の割合は、どれも列の幅（__window の幅）に対するもの。
 * 反転は見せる範囲の中心を軸にするので、反転しても人物の中心は列の真ん中のまま。
 * アセンダー名の文字を反転しないよう、絵はアセンダー名と別の要素に描く。
 */
.ascender-art-layer__art {
  aspect-ratio: var(--ascender-image-width) / var(--ascender-image-height);
  background-repeat: no-repeat;
  background-size: 100% 100%;
  left: calc(50% - 100% * var(--ascender-view-center) / var(--ascender-view-width));
  margin-top: calc(-100% * var(--ascender-view-top) / var(--ascender-view-width));
  position: absolute;
  top: 0;
  transform-origin: calc(100% * var(--ascender-view-center) / var(--ascender-image-width)) 0;
  width: calc(100% * var(--ascender-image-width) / var(--ascender-view-width));
}

.ascender-art-layer__art[data-mirrored="true"] {
  transform: scaleX(-1);
}

/* 絵を読み込めなかったときに、絵の代わりに出すアセンダー名 */
.ascender-art-layer__name {
  font-size: 1.25em;
  padding: 0 0.5em;
  text-align: center;
  grid-area: 1 / 1;
  text-shadow: 0 0 0.25em #000, 0 0 0.5em #000;
}

.ascender-art-layer__figure--player {
  grid-column: 1;
}

.ascender-art-layer__figure--opponent {
  grid-column: 3;
}

.ascender-art-layer__figure[data-ascender="sakuya"][data-form="masked"] .ascender-art-layer__art {
  background-image: var(--ascender-sakuya-masked);
}

.ascender-art-layer__figure[data-ascender="sakuya"][data-form="bare"] .ascender-art-layer__art {
  background-image: var(--ascender-sakuya-bare);
}

.ascender-art-layer__figure[data-ascender="sakuya"][data-form="critical"] .ascender-art-layer__art {
  background-image: var(--ascender-sakuya-critical);
}

.ascender-art-layer__figure[data-ascender="shuten"][data-form="normal"] .ascender-art-layer__art {
  background-image: var(--ascender-shuten-normal);
}

.ascender-art-layer__figure[data-ascender="shuten"][data-form="wounded"] .ascender-art-layer__art {
  background-image: var(--ascender-shuten-wounded);
}

.ascender-art-layer__figure[data-ascender="shuten"][data-form="critical"] .ascender-art-layer__art {
  background-image: var(--ascender-shuten-critical);
}

.ascender-art-layer__figure[data-ascender="mumei"][data-form="normal"] .ascender-art-layer__art {
  background-image: var(--ascender-mumei-normal);
}

.ascender-art-layer__figure[data-ascender="mumei"][data-form="wounded"] .ascender-art-layer__art {
  background-image: var(--ascender-mumei-wounded);
}

.ascender-art-layer__figure[data-ascender="mumei"][data-form="critical"] .ascender-art-layer__art {
  background-image: var(--ascender-mumei-critical);
}

/*
 * 動く表示（PixiJS）のキャンバス。のけぞりや演出が列の外へはみ出す分だけ、層より広く取る。
 * 動く表示が描けた側は、動かない絵を隠す（アセンダー名は動かない絵の失敗時だけ出るので残す）。
 */
.ascender-art-layer__stage {
  inset: -3rem;
  /* 動かない表示と同じ高さ（列の下端。キャンバスは層より 3rem 広い）で、絵を消す */
  mask-image: linear-gradient(
    to bottom,
    #000 calc(100% - 3rem - var(--ascender-plate-space, 0px) - var(--ascender-art-fade)),
    transparent calc(100% - 3rem - var(--ascender-plate-space, 0px))
  );
  overflow: hidden;
  pointer-events: none;
  position: absolute;
}

.ascender-art-layer__canvas {
  display: block;
}

.ascender-art-layer__figure[data-vfx-ready="true"] .ascender-art-layer__art {
  visibility: hidden;
}

/*
 * 決着の吹っ飛び（AscenderArtLayer の knockback）。動きを減らす設定では、useResultReveal が吹っ飛びを作らない（この要素は出ない）。負けた側の吹っ飛びの絵が、暗転の中を画面の端の外から円弧を描いて
 * 反対側の端の外へ横切る。自分（左）が負けたら右から左、相手（右）が負けたら左から右（絵を左右反転する）。
 * 弧の高さは画面の高さの 3 割、体は軌道に沿って傾く。傾いた角を画面の端に残さないよう、出入りの一瞬で薄くする。
 * 絵・比率・入るまでの待ち・横切る長さは、要素の CSS 変数で受ける（時機は useResultReveal の定数）。
 * 位置は画面に固定する。重なり順は絵の層のまま（暗転の幕の上、盤面の下）。
 * 大きさは、弧のいちばん上でも画面の上で切れないよう、画面の高さでも抑える（2026-10-22、ユーザーが試作で決めた値）。
 */
.ascender-art-layer__knockback {
  animation: ascender-knockback-sweep-player var(--knockback-duration) linear var(--knockback-delay) both;
  aspect-ratio: var(--knockback-ratio);
  background-repeat: no-repeat;
  background-size: 100% 100%;
  left: 0;
  pointer-events: none;
  position: fixed;
  top: 65%;
  width: min(32vw, 46dvh);
  z-index: 1;
}

.ascender-art-layer__knockback--opponent {
  animation-name: ascender-knockback-sweep-opponent;
}

@keyframes ascender-knockback-sweep-player {
  0% {
    opacity: 0;
    transform: translate(calc(1.00 * 100vw - 0.00 * 100%), calc(-50% - 0.0000 * 30dvh)) rotate(24.0deg);
  }

  5% {
    opacity: 1;
    transform: translate(calc(0.95 * 100vw - 0.05 * 100%), calc(-50% - 0.1564 * 30dvh)) rotate(23.7deg);
  }

  10% {
    transform: translate(calc(0.90 * 100vw - 0.10 * 100%), calc(-50% - 0.3090 * 30dvh)) rotate(22.8deg);
  }

  15% {
    transform: translate(calc(0.85 * 100vw - 0.15 * 100%), calc(-50% - 0.4540 * 30dvh)) rotate(21.4deg);
  }

  20% {
    transform: translate(calc(0.80 * 100vw - 0.20 * 100%), calc(-50% - 0.5878 * 30dvh)) rotate(19.4deg);
  }

  25% {
    transform: translate(calc(0.75 * 100vw - 0.25 * 100%), calc(-50% - 0.7071 * 30dvh)) rotate(17.0deg);
  }

  30% {
    transform: translate(calc(0.70 * 100vw - 0.30 * 100%), calc(-50% - 0.8090 * 30dvh)) rotate(14.1deg);
  }

  35% {
    transform: translate(calc(0.65 * 100vw - 0.35 * 100%), calc(-50% - 0.8910 * 30dvh)) rotate(10.9deg);
  }

  40% {
    transform: translate(calc(0.60 * 100vw - 0.40 * 100%), calc(-50% - 0.9511 * 30dvh)) rotate(7.4deg);
  }

  45% {
    transform: translate(calc(0.55 * 100vw - 0.45 * 100%), calc(-50% - 0.9877 * 30dvh)) rotate(3.8deg);
  }

  50% {
    transform: translate(calc(0.50 * 100vw - 0.50 * 100%), calc(-50% - 1.0000 * 30dvh)) rotate(0.0deg);
  }

  55% {
    transform: translate(calc(0.45 * 100vw - 0.55 * 100%), calc(-50% - 0.9877 * 30dvh)) rotate(-3.8deg);
  }

  60% {
    transform: translate(calc(0.40 * 100vw - 0.60 * 100%), calc(-50% - 0.9511 * 30dvh)) rotate(-7.4deg);
  }

  65% {
    transform: translate(calc(0.35 * 100vw - 0.65 * 100%), calc(-50% - 0.8910 * 30dvh)) rotate(-10.9deg);
  }

  70% {
    transform: translate(calc(0.30 * 100vw - 0.70 * 100%), calc(-50% - 0.8090 * 30dvh)) rotate(-14.1deg);
  }

  75% {
    transform: translate(calc(0.25 * 100vw - 0.75 * 100%), calc(-50% - 0.7071 * 30dvh)) rotate(-17.0deg);
  }

  80% {
    transform: translate(calc(0.20 * 100vw - 0.80 * 100%), calc(-50% - 0.5878 * 30dvh)) rotate(-19.4deg);
  }

  85% {
    transform: translate(calc(0.15 * 100vw - 0.85 * 100%), calc(-50% - 0.4540 * 30dvh)) rotate(-21.4deg);
  }

  90% {
    transform: translate(calc(0.10 * 100vw - 0.90 * 100%), calc(-50% - 0.3090 * 30dvh)) rotate(-22.8deg);
  }

  95% {
    opacity: 1;
    transform: translate(calc(0.05 * 100vw - 0.95 * 100%), calc(-50% - 0.1564 * 30dvh)) rotate(-23.7deg);
  }

  100% {
    opacity: 0;
    transform: translate(calc(0.00 * 100vw - 1.00 * 100%), calc(-50% - 0.0000 * 30dvh)) rotate(-24.0deg);
  }
}

@keyframes ascender-knockback-sweep-opponent {
  0% {
    opacity: 0;
    transform: translate(calc(0.00 * 100vw - 1.00 * 100%), calc(-50% - 0.0000 * 30dvh)) rotate(-24.0deg) scaleX(-1);
  }

  5% {
    opacity: 1;
    transform: translate(calc(0.05 * 100vw - 0.95 * 100%), calc(-50% - 0.1564 * 30dvh)) rotate(-23.7deg) scaleX(-1);
  }

  10% {
    transform: translate(calc(0.10 * 100vw - 0.90 * 100%), calc(-50% - 0.3090 * 30dvh)) rotate(-22.8deg) scaleX(-1);
  }

  15% {
    transform: translate(calc(0.15 * 100vw - 0.85 * 100%), calc(-50% - 0.4540 * 30dvh)) rotate(-21.4deg) scaleX(-1);
  }

  20% {
    transform: translate(calc(0.20 * 100vw - 0.80 * 100%), calc(-50% - 0.5878 * 30dvh)) rotate(-19.4deg) scaleX(-1);
  }

  25% {
    transform: translate(calc(0.25 * 100vw - 0.75 * 100%), calc(-50% - 0.7071 * 30dvh)) rotate(-17.0deg) scaleX(-1);
  }

  30% {
    transform: translate(calc(0.30 * 100vw - 0.70 * 100%), calc(-50% - 0.8090 * 30dvh)) rotate(-14.1deg) scaleX(-1);
  }

  35% {
    transform: translate(calc(0.35 * 100vw - 0.65 * 100%), calc(-50% - 0.8910 * 30dvh)) rotate(-10.9deg) scaleX(-1);
  }

  40% {
    transform: translate(calc(0.40 * 100vw - 0.60 * 100%), calc(-50% - 0.9511 * 30dvh)) rotate(-7.4deg) scaleX(-1);
  }

  45% {
    transform: translate(calc(0.45 * 100vw - 0.55 * 100%), calc(-50% - 0.9877 * 30dvh)) rotate(-3.8deg) scaleX(-1);
  }

  50% {
    transform: translate(calc(0.50 * 100vw - 0.50 * 100%), calc(-50% - 1.0000 * 30dvh)) rotate(-0.0deg) scaleX(-1);
  }

  55% {
    transform: translate(calc(0.55 * 100vw - 0.45 * 100%), calc(-50% - 0.9877 * 30dvh)) rotate(3.8deg) scaleX(-1);
  }

  60% {
    transform: translate(calc(0.60 * 100vw - 0.40 * 100%), calc(-50% - 0.9511 * 30dvh)) rotate(7.4deg) scaleX(-1);
  }

  65% {
    transform: translate(calc(0.65 * 100vw - 0.35 * 100%), calc(-50% - 0.8910 * 30dvh)) rotate(10.9deg) scaleX(-1);
  }

  70% {
    transform: translate(calc(0.70 * 100vw - 0.30 * 100%), calc(-50% - 0.8090 * 30dvh)) rotate(14.1deg) scaleX(-1);
  }

  75% {
    transform: translate(calc(0.75 * 100vw - 0.25 * 100%), calc(-50% - 0.7071 * 30dvh)) rotate(17.0deg) scaleX(-1);
  }

  80% {
    transform: translate(calc(0.80 * 100vw - 0.20 * 100%), calc(-50% - 0.5878 * 30dvh)) rotate(19.4deg) scaleX(-1);
  }

  85% {
    transform: translate(calc(0.85 * 100vw - 0.15 * 100%), calc(-50% - 0.4540 * 30dvh)) rotate(21.4deg) scaleX(-1);
  }

  90% {
    transform: translate(calc(0.90 * 100vw - 0.10 * 100%), calc(-50% - 0.3090 * 30dvh)) rotate(22.8deg) scaleX(-1);
  }

  95% {
    opacity: 1;
    transform: translate(calc(0.95 * 100vw - 0.05 * 100%), calc(-50% - 0.1564 * 30dvh)) rotate(23.7deg) scaleX(-1);
  }

  100% {
    opacity: 0;
    transform: translate(calc(1.00 * 100vw - 0.00 * 100%), calc(-50% - 0.0000 * 30dvh)) rotate(24.0deg) scaleX(-1);
  }
}

/*
 * バトルの BGM（曲）。自分のアセンダーの曲を流す（useBattleBgm）。曲はどの部品が描かれているかに依らず読むので :root に置く。
 * 変数名は「--ascender-<アセンダー>-bgm」。曲を持つアセンダーだけ書き、定義（ascenders.js の battleBgm）とそろえる。
 * 置き場所・形式・出所の記録は doc/ascender-assets.md の「BGM」。
 */
:root {
  --ascender-sakuya-bgm: url("/assets/ascenders/sakuya/battle-56f80106.mp3");
  --ascender-shuten-bgm: url("/assets/ascenders/shuten/battle-acdd6567.mp3");
}

/*
 * アセンションの枠の窓の絵（.ascension-soul__window、application.css）。アセンションのキー（配信の ascension.key）ごとに 1 枚。
 * 仕様は doc/ascender-assets.md の「アセンションの絵」。
 */
.ascension-soul__window[data-ascension="kagemusubi-no-in"] {
  --ascension-art: url("/assets/ascensions/kagemusubi-no-in-acb8799a.webp");
}

.ascension-soul__window[data-ascension="kikoku-no-ketsuen"] {
  --ascension-art: url("/assets/ascensions/kikoku-no-ketsuen-c5fbaa53.webp");
}
