@charset "utf-8";

/* ==========================================================================
   ページ単位で上書きしたいときは body のクラスを使う（index=.page-index）。
   ========================================================================== */

:root {
  --panel-color: #0000ab;
  /* Figma 1440px幅の背景領域。各段の高さも画面幅に追従。 */
  --background-step: calc(100vw / 9);
  --page-background: #10002e;
  --content-width: 1294px;
  /* 入力欄・確認値・注意書き用。DotGothic16のドット体と混ざらないようにする。 */
  --font-system: system-ui, -apple-system, "Hiragino Kaku Gothic ProN", "Hiragino Sans", "Yu Gothic", Meiryo, sans-serif;
  /* モーションの最小単位。フェード・点滅・幕の開閉はすべてこの倍数で組む。 */
  --step: 125ms;
}

html {
  scroll-behavior: smooth;
}

body {
  margin: 0;
  background: var(--page-background);
  color: #fff;
  font-family: "DotGothic16", sans-serif;
  font-size: 18px;
  line-height: 1.75;
  letter-spacing: .05em;
}

body {
  isolation: isolate;
}

/* emの継承で本文サイズに固定されないよう、各要素の文字サイズを基準に5%を適用。 */
:where(body *) {
  letter-spacing: .05em;
}

/* 背景。SPのURLバー開閉で高さが変わらないよう最大ビューポート高で固定する。
   実体の<img>にしてあるのは、読み込み完了をローディング側から素直に検知するため。 */
picture {
  display: contents;
}

.page-background {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100vh;
  height: 100lvh;
  z-index: -1;
  object-fit: cover;
  pointer-events: none;
  user-select: none;
}

.loading {
  position: fixed;
  inset: 0;
  z-index: 1000;
  display: grid;
  place-items: center;
  background: #000;
  transition: opacity .5s steps(4, jump-none), visibility 0s .5s;
}

.is-loaded .loading {
  opacity: 0;
  visibility: hidden;
}

.is-loaded .loading-text {
  display: none;
}

/* 幕が出ている間はスクロールを止める。 */
.page-index:not(.is-loaded) {
  overflow: hidden;
}

.loading-text {
  font-size: 24px;
}

/* 表示幅を伸ばして点が増えていくように見せる。 */
.loading-text::after {
  content: "...";
  display: inline-block;
  width: 0;
  overflow: hidden;
  vertical-align: bottom;
  animation: loading-dots 1s steps(4, jump-none) infinite;
}

@keyframes loading-dots {
  from {
    width: 0;
  }
  to {
    width: 3ch;
  }
}

*, *::before, *::after {
  box-sizing: border-box;
}

/* 意味の切れ目でのみ改行させるための単位。 */
.wrap-unit {
  display: inline-block;
}

.section-hero, .section-intro, footer {
  width: 100%;
  margin: 0;
  padding: 0;
}

.background-steps {
  height: calc(var(--background-step) * 4);
  background: linear-gradient(to bottom, rgb(0 0 0 / 15%) 0% 25%, rgb(0 0 0 / 30%) 25% 50%, rgb(0 0 0 / 45%) 50% 75%, rgb(0 0 0 / 60%) 75% 100%);
}

section {
  width: min(var(--content-width), calc(100% - 48px));
  margin-inline: auto;
}

:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 4px;
}

@media (max-width: 575px) {
  body {
    font-size: 16px;
  }
  section {
    width: calc(100% - 32px);
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }
  .loading {
    transition: none;
  }
  .loading-text::after {
    animation: none;
    width: 3ch;
  }
}

/* ==========================================================================
   hero・告知メッセージ・footer
   ========================================================================== */

/* 1440×810のデザインを基準に、ロゴ類は固有の比率で伸縮する。 */
.section-hero {
  /* 画像差し替え時はHTMLのwidth・heightと、ここの寸法を合わせる。 */
  --hero-logo-width: 1547;
  --hero-logo-height: 1093;
  --hero-schedule-width: 1552;
  --hero-schedule-height: 142;
  --hero-slide-width: 960;
  --hero-slide-height: 864;
  /* 画面の高さの単位。svh未対応のブラウザではvhで代替する。
     height:100vh; height:100svh; の二段重ねはここでは使えない。
     var()の置換に失敗した宣言は前の宣言に戻らず、高さがautoに潰れるため。 */
  --hero-vunit: 1vh;
  /* MVの高さ。横持ちでは2:1より横長にしない。画面が低いときは50vwが勝ち、
     heightにmax()を入れているのでmin-heightと同じ効き方になる。
     縦並びの下限は下のメディアクエリで上書きする。
     余白もイラストの幅もこの値から引くので、下限が効いたときに
     余白だけ伸びてイラストが伸びない、ということにならない。 */
  --hero-h: max(calc(var(--hero-vunit) * 100), 50vw);
  --hero-edge-gap: calc(var(--hero-h) * .05);
  --hero-title-gap: min(3.75vw, calc(var(--hero-h) / 15));
  /* 落下距離。ロゴ自身の高さに対する割合なので、レイアウトと画像を問わず
     見た目の移動量が揃う。画面外までは動かさず、stepフェードが見える範囲に留める。
     16フレームで割り切る前提の値。フレーム数を変えるならここも振り直すこと。 */
  --hero-drop-from: -32.6087%;
  /* MVの出だしの明るさ。0で真っ黒、1で元の色。ロゴ・日程・イラストの初回登場と、
     イラストの入れ替えが全部これを見る。どれも濃度と同じ尺・刻みで戻す。 */
  --hero-light-from: 0;
  /* イラストの上昇距離。ロゴの落下と見た目の移動量を揃えてある。
     どちらも自身の高さに対する割合だが、イラストの枠はロゴのおよそ1.9倍の高さなので、
     同じ数字にすると倍動いてしまう。--hero-drop-from をその比で割った値が入っている。
     高さの比はPC・ワイド・縦画面のどれでも1.87〜1.92倍に収まるので、
     この1つの値で全レイアウトの移動量が揃う。
     ロゴの落下と同じく1コマ＝2フレーム、8コマ＝16フレームで15段ぶん。 */
  --hero-rise-from: 17%;
  position: relative;
  height: var(--hero-h);
  overflow: hidden;
}

@supports (height: 1svh) {
  .section-hero {
    --hero-vunit: 1svh;
  }
}

.hero-inner {
  position: relative;
  width: min(100%, calc(var(--hero-h) * 1.777778));
  height: 100%;
  margin-inline: auto;
}

.hero-title {
  position: absolute;
  z-index: 1;
  top: 50%;
  left: 7.63889%;
  /* 縦長のロゴでも上下の余白を確保する幅に制限する。 */
  width: min(40.27778%, calc(
    (var(--hero-h) - var(--hero-edge-gap) * 2 - var(--hero-title-gap))
    / (var(--hero-logo-height) / var(--hero-logo-width)
      + var(--hero-schedule-height) / var(--hero-schedule-width))
  ));
  display: flex;
  flex-direction: column;
  gap: var(--hero-title-gap);
  transform: translateY(-50%);
}

.hero-title img,
.footer-logo {
  display: block;
  width: 100%;
  height: auto;
}

.hero-slider {
  /* 枠自体を画像と同じ縦横比にする。上端から下端までの帯に収まる大きさで、
     帯の中心（左右は従来の枠の中心）に置くので、見た目の位置は変わらない。 */
  position: absolute;
  top: calc(var(--hero-edge-gap) + (var(--hero-h) - var(--hero-edge-gap)) / 2);
  left: 71.52778%;
  width: min(50%, calc(
    (var(--hero-h) - var(--hero-edge-gap))
    * var(--hero-slide-width) / var(--hero-slide-height)
  ));
  height: auto;
  aspect-ratio: var(--hero-slide-width) / var(--hero-slide-height);
  transform: translate(-50%, -50%);
}

.hero-slide {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: contain;
  object-position: center;
  opacity: 0;
  filter: brightness(var(--hero-light-from));
  /* 消える側。4コマで落とし切る。濃度と明るさは同じ刻みで一緒に落とす。 */
  transition:
    opacity calc(var(--step) * 4) steps(4),
    filter calc(var(--step) * 4) steps(4);
}

.hero-slide.is-active {
  opacity: 1;
  filter: brightness(1);
  /* 出る側。前の絵が消え切ってから2コマ空ける。消える側は4コマで0になり、
     出る側は6コマ目から動き出すので、間に何も映っていないコマが2つ入る。
     2コマなのは初回登場でキャラが着地してから黒が抜け始めるまでと同じ長さで、
     MVの中で「待ち」に使っている単位がこれだけだから。
     そこは初回登場と同じ2段構えだが、こちらは黒抜きを2コマ前倒しして濃度に被せる。
     出切るのを待たずに色が乗り始めるので、初回登場より軽い。
     明るさのディレイが濃度より2コマ後ろなのはそのため。
     黒抜きは初回登場と同じ6コマ掛ける。濃度の4コマより長いので、
     絵が出切ったあとも色だけがゆっくり戻り続ける。
     空ける長さを変えるなら濃度と明るさのディレイを同じ数だけ増減すること。 */
  transition:
    opacity calc(var(--step) * 4) steps(4, jump-start) calc(var(--step) * 6),
    filter calc(var(--step) * 6) steps(6, jump-start) calc(var(--step) * 8);
}

/* MV：幕が消え切って1コマ後の5コマ（625ms）でロゴとイラストのモーションを開始。
   移動・フェードは8コマ、日程とイラストの明度変化は15コマから6コマ。
   全体は21コマ（2.625秒）で出揃う。stepsのため最初の点灯は6コマ目。
   複数枚の場合の初回切り替えはdata-start-delayで指定する。 */
.hero-schedule,
.hero-slider {
  opacity: 0;
}

.is-loaded .hero-title h1 {
  animation:
    logo-drop calc(var(--step) * 8) steps(16, jump-none) calc(var(--step) * 5) both,
    step-fade-in calc(var(--step) * 8) steps(8, jump-none) calc(var(--step) * 5) both,
    step-light-up calc(var(--step) * 8) steps(8, jump-none) calc(var(--step) * 5) both;
}

.is-loaded .hero-schedule {
  animation:
    step-fade-in calc(var(--step) * 6) steps(6, jump-none) calc(var(--step) * 15) both,
    step-light-up calc(var(--step) * 6) steps(6, jump-none) calc(var(--step) * 15) both;
}

.is-loaded .hero-slider {
  animation:
    step-fade-in calc(var(--step) * 8) steps(8, jump-none) calc(var(--step) * 5) both,
    slide-rise calc(var(--step) * 8) steps(16, jump-none) calc(var(--step) * 5) both,
    step-light-up calc(var(--step) * 6) steps(6, jump-none) calc(var(--step) * 15) both;
}

/* 上から等速で降りてきて止まる。イージングも跳ね返りもなし。
   16fps＝62.5msごとに1回動く。8コマ＝1秒で16フレーム。
   13コマで止まり、日程のアニメーションは15コマから開始する。
   尺を変えるときは steps() のフレーム数も 1コマ＝2フレーム で合わせ、
   --hero-drop-from も振り直すこと。
   距離は --hero-drop-from。 */
@keyframes logo-drop {
  from {
    transform: translateY(var(--hero-drop-from));
  }

  to {
    transform: translateY(0);
  }
}

/* 暗く落とした状態から元の色に戻る。ロゴ・日程・イラストの初回登場で使う。
   イラストだけは濃度と別のディレイを持たせて、出切ってから色を戻す。
   呼び出し側で濃度と同じディレイ・尺・刻みを指定するので、
   濃くなるのと明るくなるのが必ず同じコマで進む。
   イラストは枠に掛ける。2枚目以降の入れ替えは各スライド側のtransitionで同じことをする。
   段数は呼び出し側の指定に従う（ロゴ8段、日程とイラスト6段）。
   暗さは --hero-light-from。 */
@keyframes step-light-up {
  from {
    filter: brightness(var(--hero-light-from));
  }

  to {
    filter: brightness(1);
  }
}

/* 下から持ち上がって止まる。ロゴの落下と同じで等速、イージングなし。
   ディレイも尺も刻みもロゴの落下と揃えてあるので、両方が同じコマで動いて同じコマで止まる。
   距離は --hero-rise-from。 */
@keyframes slide-rise {
  from {
    translate: 0 var(--hero-rise-from);
  }

  to {
    translate: 0 0;
  }
}

/* 段数は呼び出し側で決める。ロゴは8コマ8段、日程とイラストは6コマ6段。
   jump-noneで揃えてあるので、どれも黒（透明）から全開までを段数ぶんで割る。
   尺とsteps()は必ず同じ数にすること。1段＝--stepの125msが崩れる。 */
@keyframes step-fade-in {
  from {
    opacity: 0;
  }

  to {
    opacity: 1;
  }
}

/* pre固有エリア */
.section-pre-announcement {
  width: 100%;
  margin: 0;
  display: grid;
  place-items: center;
  padding: 120px 24px;
  background: rgb(0 0 0 / 70%);
}

.pre-message-frame {
  padding: 40px 80px;
  border: 3px solid #fff;
  border-radius: 8px;
  background: var(--panel-color);
}

.pre-message {
  font-size: 48px;
  font-weight: 400;
  text-align: center;
}

/* footer-bgを背景として内包し、専用classで着脱できる。 */
.site-footer {
  background: rgb(0 0 0 / 70%);
}

/* 一番下が背面のグラデーション。元はfooter-bg.pngに焼き込まれていたもので、
   色はfooter-bg-gradation.svgから。フッター全面に敷き、70%で単色になり切る。 */
.footer--scenery {
  background:
    linear-gradient(rgb(0 0 0 / 70%), rgb(0 0 0 / 70%)),
    url("../img/footer-bg.png") center bottom / 100% auto no-repeat,
    linear-gradient(rgb(13 0 46 / 0), #210994 70%);
}

.footer-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 80px;
  padding: 80px 24px;
}

.footer-logo {
  width: min(400px, 100%);
}

.footer-related {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 48px;
  width: 100%;
}

.footer-related h2 {
  font-size: 32px;
  font-weight: 400;
}

.footer-banners {
  display: grid;
  gap: 16px;
  width: min(320px, 100%);
}

/* imgを半透明にしたときに透ける下地。 */
.footer-banners a {
  display: block;
  background: #fff;
}

/* 幅は枠いっぱい、高さは画像の比率なり。バナーごとに縦横比が違う。 */
.footer-banners img {
  display: block;
  width: 100%;
  height: auto;
}

@media (hover: hover) and (pointer: fine) {
  .footer-banners a:hover img {
    opacity: .81;
    animation: banner-blink calc(var(--step) * 2) steps(1, end) forwards;
  }
}

/* 上のホバー指定より後ろに置くこと。同じ詳細度なので、前に置くと後勝ちされて効かない。 */
@media (prefers-reduced-motion: reduce) {
  .footer-banners a:hover img {
    animation: none;
  }
}

/* 薄くなって戻るを2往復し、最後は薄いまま残す。
   全体で2コマ＝250ms、1段はその4分の1の62.5msで、移動アニメと同じフレーム幅。 */
@keyframes banner-blink {
  0%, 50% {
    opacity: .81;
  }

  25%, 75% {
    opacity: 1;
  }

  100% {
    opacity: .81;
  }
}

.copyright {
  font: 400 12px/1.75 var(--font-system);
  text-align: center;
}

.copyright, .copyright p {
  letter-spacing: normal;
}

.copyright p + p {
  margin-top: 16px;
  letter-spacing: .05em;
}

/* コピーライト表記だけ注意書きより1px大きく。emで取るのでPCの12px、SPの11px
   どちらに対しても+1pxになる。投票画面側の.copyrightには当てない。 */
.site-footer .copyright p + p {
  font-size: calc(1em + 1px);
}

@media (max-aspect-ratio: 1/1) and (max-width: 575px) {
  .section-hero {
    /* イラストの幅は「残りの高さ÷画像の縦横比」と92vwの小さい方なので、
       高さが足りないと92vwに届かず細くなる。逆算すると画面幅の180.95倍の
       高さがあれば必ず届くので、丸めて181vwを下限にしている。
       画面の縦横比が1:1.81より縦長ならほぼ画面の高さが勝つので従来どおり画面ぴったり。
       ロゴの比率や余白、画像の縦横比を変えたらこの181vwも逆算し直すこと。 */
    --hero-h: max(calc(var(--hero-vunit) * 100), 181vw);
  }
}

/* MVだけは画面幅ではなく縦横比で切り替える。
   細長い縦画面ではロゴ・日程・キャラクター全体を中央に置く。 */
@media (max-aspect-ratio: 1/1) {
  .hero-inner {
    /* svh基準ではなく、上の--hero-hを基準にする。下限が効いたときも
       余白・ロゴ・イラストが同じ比率のまま一緒に伸びる。 */
    --hero-title-width: min(76vw, calc(var(--hero-h) * .42));
    --hero-padding-top: calc(var(--hero-h) * .05);
    --hero-title-gap: calc(var(--hero-h) * .025);
    --hero-content-gap: calc(var(--hero-h) * .03);
    --hero-available-height: calc(
      var(--hero-h) - var(--hero-padding-top) - var(--hero-title-gap) - var(--hero-content-gap)
    );
    width: 100%;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding-top: var(--hero-padding-top);
    gap: var(--hero-content-gap);
  }

  .hero-title {
    position: relative;
    top: auto;
    left: auto;
    width: var(--hero-title-width);
    gap: var(--hero-title-gap);
    transform: none;
    flex-shrink: 0;
  }

  .hero-slider {
    position: relative;
    top: auto;
    left: auto;
    /* 余白とタイトルの高さを引き、残りの高さに収まる幅を求める。 */
    width: min(92vw, calc(
      (var(--hero-available-height)
        - var(--hero-title-width) * var(--hero-logo-height) / var(--hero-logo-width)
        - var(--hero-title-width) * var(--hero-schedule-height) / var(--hero-schedule-width))
      * var(--hero-slide-width) / var(--hero-slide-height)
    ));
    height: auto;
    aspect-ratio: var(--hero-slide-width) / var(--hero-slide-height);
    transform: none;
    flex-shrink: 0;
  }
}

/* MV以外は従来の幅によるレスポンシブを維持。 */
@media (max-width: 767px) and (orientation: portrait) {
  .section-pre-announcement {
    padding-block: 80px;
  }

  .pre-message-frame {
    padding: 28px 36px;
  }

  .pre-message {
    font-size: 28px;
  }

  .footer-content {
    gap: 56px;
    padding-block: 64px 40px;
  }

  .footer-logo {
    width: min(280px, 85%);
  }

  .footer-related {
    gap: 32px;
  }

  .footer-related h2 {
    font-size: 24px;
  }

  /* 投票画面側の.copyrightに当てないよう、フッター内に限定する。 */
  .site-footer .copyright {
    font-size: 11px;
  }

  .footer--scenery {
    background-size: auto, auto 100%, auto;
  }
}

@media (prefers-reduced-motion: reduce) {
  html {
    scroll-behavior: auto;
  }

  .loading,
  .hero-slide,
  .hero-slide.is-active {
    transition: none;
  }

  .loading-text::after {
    animation: none;
    width: 3ch;
  }

  .is-loaded .hero-title h1,
  .is-loaded .hero-schedule,
  .is-loaded .hero-slider {
    opacity: 1;
    animation: none;
  }
}

/* 告知メッセージ：AOS初期化後、枠はフェード、文字は点滅で表示する。 */
.section-pre-announcement [data-aos="fade"].aos-init {
  opacity: 0;
  transition: opacity .5s steps(4, jump-none);
}

.section-pre-announcement [data-aos="fade"].aos-animate {
  opacity: 1;
}

.section-pre-announcement .pre-message-frame.aos-init .pre-message {
  opacity: 0;
}

.section-pre-announcement .pre-message-frame.aos-animate .pre-message {
  /* 枠のフェード4コマのあと2コマ置いてから点灯させる。 */
  animation: blink-in calc(var(--step) * 5) steps(1, end) calc(var(--step) * 6) forwards;
}

/* 1コマずつ点いて消えてを2往復し、5コマ目で点いたまま残す。 */
@keyframes blink-in {
  0%, 40%, 80%, 100% {
    opacity: 1;
  }

  20%, 60% {
    opacity: 0;
  }
}

/* フッターロゴのstepフェード。MVのロゴと同じ8コマ8段。
   尺もstepsも同じ数にすること。1段＝--stepの125msが崩れる。 */
.site-footer [data-aos="fade"].aos-init {
  opacity: 0;
  transition: opacity calc(var(--step) * 8) steps(8, jump-none);
}

.site-footer [data-aos="fade"].aos-animate {
  opacity: 1;
}

@media (prefers-reduced-motion: reduce) {
  .section-pre-announcement [data-aos="fade"].aos-init,
  .section-pre-announcement .pre-message-frame.aos-init .pre-message,
  .site-footer [data-aos="fade"].aos-init {
    opacity: 1;
    transition: none;
    animation: none;
  }
}

/* 最新コミックス：Figma 208:623。 */
.section-comics {
  width: 100%;
  margin: 0;
  padding: 120px 24px;
  background: rgb(0 0 0 / 70%);
}

.comics-inner {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 48px;
  max-width: 658px;
  margin-inline: auto;
}

.comics-heading {
  font-size: 48px;
  font-weight: 400;
  text-align: center;
}

.comics-content {
  display: grid;
  grid-template-columns: repeat(2, minmax(0, 1fr));
  align-items: start;
  gap: 48px;
  width: 100%;
}

.comics-cover {
  display: block;
  width: 100%;
  height: auto;
  aspect-ratio: 305 / 480;
  object-fit: cover;
}

.comics-description {
  display: flex;
  flex-direction: column;
  gap: 32px;
  min-width: 0;
}

.comics-info {
  font-size: 24px;
}

.comics-summary {
  font-size: 20px;
}

.comics-link {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  gap: 16px;
  max-width: 100%;
  padding: 16px 48px;
  border: 3px solid #fff;
  border-radius: 80px;
  background: #ef2b2b;
  font-size: 24px;
  text-align: center;
}

.comics-link-arrow {
  flex: 0 0 20px;
  width: 20px;
  height: 20px;
  font-size: 20px;
  line-height: 1;
  transform: rotate(90deg);
}

.comics-link:focus-visible {
  outline: 3px solid #fff;
  outline-offset: 5px;
}

/* 本番の送信ボタンと同じ、背景を残して文字色だけを明滅させる演出。 */
@keyframes retro-blink-text {
  0% {
    color: rgb(255 255 255 / 60%);
  }

  50% {
    color: rgb(255 255 255 / 100%);
  }
}

@media (hover: hover) and (pointer: fine) {
  .comics-link:hover {
    animation: retro-blink-text calc(var(--step) * 4) step-end infinite;
  }
}

@media (prefers-reduced-motion: reduce) {
  .comics-link:hover {
    animation: none;
  }
}

@media (max-width: 767px) {
  .section-comics {
    padding-block: 80px;
  }

  .comics-inner {
    gap: 32px;
  }

  .comics-heading {
    font-size: 28px;
  }

  .comics-content {
    grid-template-columns: minmax(0, 1fr);
    gap: 32px;
    max-width: 360px;
  }

  .comics-cover {
    aspect-ratio: 1 / 1;
    object-fit: contain;
    object-position: center;
  }

  .comics-description {
    gap: 24px;
  }

  .comics-info {
    font-size: 20px;
    text-align: center;
  }

  .comics-summary {
    font-size: 16px;
  }

  .comics-link {
    padding: 16px 24px;
    font-size: 20px;
  }
}
