:root {
  --bg: #0b0b1a;
  --fg: #f4f4ff;
  --fg-dim: #8a8ab0;
  /* 枠線は文字より薄くてよい（非テキストの 3:1）。--fg-dim と一緒に明るくするとネオンの締まりが弱まる */
  --line: #6d6d96;
  --accent: #2ef2ff;
  --accent-glow: rgb(46 242 255 / 0.55);
  --hot: #ff3fa4;
  /* 脳汁タンクの液体の濃さ。--bg に重ねても --fg-dim が 4.5:1 を割らない値（test/contrast.test.js） */
  --tank-opacity: 0.2;
  --joke: #ff3b3b;
  --gold: #ffd23f;
  --time-extra: #9b5cff;
  --time-bonus: #8ffcff;
  --done: #2ef2ff;
  --kb-bg: #131329;
  --key: #26264a;
  --key-pressed: #3a3a6e;
  --key-side: #1c1c38;
  --key-shadow: #0a0a18;
  --popup: #1c1c3a;
  --miss: rgb(255 40 80 / 0.45);
  --key-h: 46px;
  --key-hint-shift: 6px;
  --kb-pad-left: 8px;
  --kb-pad-right: 8px;
  --font-display: 'Dela Gothic One', 'M PLUS Rounded 1c', system-ui, sans-serif;
  --font-body: 'M PLUS Rounded 1c', system-ui, -apple-system, 'Hiragino Maru Gothic ProN', sans-serif;
  --text-xs: 11px;
  --text-sm: 12px;
  --text-md: 14px;
  --text-lg: 16px;
  --text-xl: 18px;
  --text-2xl: 22px;
  --space-1: 2px;
  --space-2: 4px;
  --space-3: 6px;
  --space-4: 8px;
  --space-5: 10px;
  --space-6: 12px;
  --space-7: 16px;
  --space-8: 24px;
}

* {
  box-sizing: border-box;
}

html,
body {
  height: 100%;
  margin: 0;
  overflow: hidden;
  overscroll-behavior: none;
  background: var(--bg);
  color: var(--fg);
}

body {
  font-family: var(--font-body);
  -webkit-user-select: none;
  user-select: none;
  -webkit-touch-callout: none;
  -webkit-tap-highlight-color: transparent;
  /* auto にするとダブルタップで拡大する。パンは要らないので、拡大だけ許す */
  touch-action: pinch-zoom;
}

/* 拡大すると、キーの位置がずれて遊べなくなる */
#screen-game {
  touch-action: none;
}

button {
  font-family: inherit;
  cursor: pointer;
}

#app {
  position: fixed;
  inset: 0;
  z-index: 1;
  display: flex;
  flex-direction: column;
  max-width: 520px;
  margin: 0 auto;
  padding: env(safe-area-inset-top) env(safe-area-inset-right) env(safe-area-inset-bottom) env(safe-area-inset-left);
}

/* --status-bar-inset は viewport.js の statusBarInset。横向きの iPhone はステータスバーを出さないので縦だけ */
@media (orientation: portrait) {
  #app {
    padding-top: max(env(safe-area-inset-top), var(--status-bar-inset, 0px));
  }
}

.screen {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-height: 0;
}

.screen[hidden] {
  display: none;
}

/* safe を付けて、中身が画面より高いときは上端から並べてスクロールできるようにする */
.screen--center {
  align-items: center;
  justify-content: safe center;
  gap: var(--space-7);
  padding: var(--space-8) var(--space-7);
  text-align: center;
}

/* ---------- overlay layers ---------- */

#fx,
#fx-back,
#float-layer,
#sweep-layer,
#flash,
#glare,
#fever-bg {
  position: fixed;
  inset: 0;
  pointer-events: none;
}

#fx {
  z-index: 50;
  width: 100%;
  height: 100%;
}

/* 超ド派手の 4 隅から噴き出す粒。#sweep-layer と同じ奥の層で、#app より奥なのでキーボードの字を隠さない */
#fx-back {
  z-index: 0;
  width: 100%;
  height: 100%;
}

#float-layer {
  z-index: 60;
}

/* #fever-bg と同じ奥の層で、DOM の順で背景の虹より手前に描く。#app（z-index: 1）より奥なので、お題と HUD は文字の手前に出る */
#sweep-layer {
  z-index: 0;
  overflow: hidden;
}

#float-layer.is-frozen > *,
#sweep-layer.is-frozen > * {
  animation-play-state: paused;
}

#flash {
  z-index: 40;
  opacity: 0;
  background: radial-gradient(circle, transparent 40%, var(--miss));
}

#flash.is-flash {
  animation: flash 0.3s ease-out;
}

/* 超ド派手の level 上昇とゴーストを抜いたときの閃光。ミスの赤と見分けられるよう金色にする */
#glare {
  z-index: 40;
  opacity: 0;
  background: radial-gradient(circle, transparent 35%, rgb(255 210 63 / 0.55));
}

#glare.is-glare {
  animation: flash 0.3s ease-out;
}

/* FEVER に入った瞬間に、下にあるものの色を反転する。高さは play-fx-view.js がキーボードの上端に合わせる */
.impact {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  z-index: 45;
  opacity: 0;
  pointer-events: none;
  -webkit-backdrop-filter: invert(1);
  backdrop-filter: invert(1);
}

.impact.is-on {
  animation: impact var(--impact-ms, 120ms) steps(1, end);
}

#fever-bg {
  z-index: 0;
  opacity: 0;
  background: linear-gradient(135deg, #ff3fa4, #ffd23f, #2ef2ff, #9b5cff, #ff3fa4);
  background-size: 400% 400%;
  transition: opacity 0.3s;
}

/* 色と濃さは FEVER の先の段（climb-tiers.js）で変わる。--climb-* は play-fx-view.js の setTier が body に置き、--climb-power は FEVER が 0。
   流れる速さは段で変えない。光の過敏への配慮で、上の段ほど色の移り変わりを速くしない */
.is-fever #fever-bg {
  opacity: calc(0.28 + 0.04 * var(--climb-power, 0));
  background-image: var(--climb-bg, linear-gradient(135deg, #ff3fa4, #ffd23f, #2ef2ff, #9b5cff, #ff3fa4));
  animation: fever-flow 1.6s linear infinite;
}

/* ---------- start / result ---------- */

.title {
  position: relative;
  margin: 0;
  font-family: var(--font-display);
  font-size: clamp(44px, 14vw, 72px);
  font-weight: 400;
  line-height: 1.05;
  filter: drop-shadow(0 0 18px rgb(255 63 164 / 0.45));
}

/* 行ごとに虹色を流し、鼓動を少しずつずらして波打たせる。字の切り抜きは行ごとに持つ（親で切り抜くと子の変形に付いてこない） */
.title__line {
  display: inline-block;
  background: linear-gradient(90deg, var(--hot), var(--gold), var(--accent), #9b5cff, var(--hot));
  background-size: 300% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  animation: title-flow 4s linear infinite, title-beat 1.6s ease-out infinite;
}

.title__line:nth-of-type(2) {
  animation-delay: -0.5s, 0.08s;
}

.title__line:nth-of-type(3) {
  animation-delay: -1s, 0.16s;
}

/* 開いたときに 1 字ずつフリックで打ち込むように出す（title-typing-view.js）。打っているあいだは白い字で、
   行の虹色は外して流れと鼓動も止める。親の切り抜きは子の変形に付いてこないので、虹色は打ち終えて字が定位置に戻ってから見せる */
.title__char {
  transition: -webkit-text-fill-color 0.15s ease-out;
}

.title.is-typing .title__line {
  background: none;
  animation: none;
}

.title.is-typing .title__char {
  display: inline-block;
  opacity: 0;
  -webkit-text-fill-color: #fff;
  /* 白にするのは一瞬で、打ち終えて外したときだけ虹色へぼかす */
  transition: none;
}

/* 字の大きさの割合で、フリックの向きから弾かれて入る。中央のタップは大きく出て縮む */
.title__char[data-dir='up'] { --from-y: -0.7em; }
.title__char[data-dir='down'] { --from-y: 0.7em; }
.title__char[data-dir='left'] { --from-x: -0.7em; }
.title__char[data-dir='right'] { --from-x: 0.7em; }
.title__char[data-dir='center'] { --from-scale: 1.8; }

.title.is-typed .title__char {
  animation: title-char-in 0.14s ease-out var(--type-delay) both;
}

.title.is-landed {
  animation: title-land 0.4s ease-out;
}

.is-wild-motion .title.is-landed {
  animation: title-land-wild 0.5s ease-out;
}

/* タイトルの周りのきらめき */
.title::before,
.title::after {
  content: '✦';
  position: absolute;
  color: var(--gold);
  font-family: var(--font-body);
  font-size: 0.4em;
  line-height: 1;
  text-shadow: 0 0 12px var(--gold);
  pointer-events: none;
  animation: twinkle 2.4s ease-in-out infinite;
}

.title::before {
  top: 2%;
  left: -6%;
}

.title::after {
  right: -4%;
  bottom: 30%;
  color: var(--accent);
  text-shadow: 0 0 12px var(--accent);
  animation-delay: -1.2s;
}

.tagline {
  margin: 0;
  color: var(--fg-dim);
  font-weight: 800;
}

.tagline__hot {
  display: inline-block;
  color: var(--gold);
  text-shadow: 0 0 10px rgb(255 210 63 / 0.5);
  animation: tagline-hop 1.6s ease-out infinite;
}

/* タイトルの背景。#app の重なりの中で中身より奥に、画面全体へ敷く。#screen-start ごと隠れると止まる */
.start-bg {
  /* スクロールの奥行き（#316、start-bg-view.js）。--bg-scroll は #start-scroll の scrollTop（px）。
     ずらすのは --bg-cap までのスクロールの分だけにし、長いタブの下のほうでも背景が画面の外へ抜けきらないようにする */
  --bg-scroll: 0px;
  --bg-cap: 120px;
  --bg-glow-rate: 0.2;
  --bg-bubble-rate: 0.5;
  /* 泡の層をいちばんずらしたときの量。層はその分だけ画面より下へ伸ばし、下端に泡の湧かない帯を空けない */
  --bg-reach: calc(var(--bg-cap) * var(--bg-bubble-rate));
  position: fixed;
  inset: 0;
  z-index: -1;
  overflow: hidden;
  pointer-events: none;
}

/* 光と泡はそれぞれ transform のアニメーションを持つので、ずらすのは包む層の translate にしてぶつけない */
.start-bg__layer {
  position: absolute;
  inset: 0;
  will-change: translate;
}

.start-bg__layer--glow {
  translate: 0 calc(min(var(--bg-scroll), var(--bg-cap)) * var(--bg-glow-rate) * -1);
}

.start-bg__layer--bubble {
  bottom: calc(var(--bg-reach) * -1);
  translate: 0 calc(min(var(--bg-scroll), var(--bg-cap)) * var(--bg-bubble-rate) * -1);
}

/* 薄い字（--fg-dim）が読めるよう、色は脳汁タンクの液体（--tank-opacity）より薄く重ねる */
.start-bg__glow {
  position: absolute;
  width: 70vmax;
  height: 70vmax;
  border-radius: 50%;
  opacity: 0.16;
  animation: glow-drift 14s ease-in-out infinite alternate;
}

.start-bg__glow--hot {
  top: -25vmax;
  left: -25vmax;
  background: radial-gradient(circle, var(--hot), transparent 65%);
}

.start-bg__glow--cyan {
  top: 30%;
  right: -35vmax;
  opacity: 0.1;
  background: radial-gradient(circle, var(--accent), transparent 65%);
  animation-duration: 17s;
  animation-delay: -6s;
}

.start-bg__glow--violet {
  bottom: -35vmax;
  left: -10vmax;
  background: radial-gradient(circle, #9b5cff, transparent 65%);
  animation-duration: 19s;
  animation-delay: -11s;
}

.start-bg__bubble {
  --x: 50%;
  --size: 10px;
  --dur: 9s;
  --delay: 0s;
  --sway: 16px;
  --color: var(--hot);
  position: absolute;
  bottom: -40px;
  left: var(--x);
  width: var(--size);
  height: var(--size);
  opacity: 0;
  animation: bubble-rise var(--dur) linear var(--delay) infinite;
}

.start-bg__bubble:nth-child(1) { --x: 6%; --size: 14px; --dur: 11s; --delay: -2s; }
.start-bg__bubble:nth-child(2) { --x: 18%; --size: 8px; --dur: 8s; --delay: -6s; --color: var(--gold); --sway: -12px; }
.start-bg__bubble:nth-child(3) { --x: 30%; --size: 18px; --dur: 13s; --delay: -9s; --color: var(--accent); }
.start-bg__bubble:nth-child(4) { --x: 44%; --size: 10px; --dur: 10s; --delay: -1s; --color: #9b5cff; --sway: -20px; }
.start-bg__bubble:nth-child(5) { --x: 57%; --size: 7px; --dur: 7s; --delay: -4s; --color: var(--gold); }
.start-bg__bubble:nth-child(6) { --x: 68%; --size: 16px; --dur: 12s; --delay: -7s; --sway: -14px; }
.start-bg__bubble:nth-child(7) { --x: 80%; --size: 9px; --dur: 9s; --delay: -3s; --color: var(--accent); }
.start-bg__bubble:nth-child(8) { --x: 91%; --size: 13px; --dur: 11s; --delay: -8s; --color: #7dff9b; --sway: -18px; }
.start-bg__bubble:nth-child(9) { --x: 36%; --size: 6px; --dur: 8s; --delay: -5s; --color: #7dff9b; }
.start-bg__bubble:nth-child(10) { --x: 74%; --size: 6px; --dur: 7s; --delay: -2.5s; --color: #9b5cff; --sway: 10px; }
.start-bg__bubble:nth-child(11) { --x: 12%; --size: 20px; --dur: 6s; --delay: -1.5s; --color: var(--gold); }
.start-bg__bubble:nth-child(12) { --x: 25%; --size: 9px; --dur: 5s; --delay: -3.5s; --sway: -24px; }
.start-bg__bubble:nth-child(13) { --x: 50%; --size: 15px; --dur: 6s; --delay: -0.5s; --color: var(--accent); }
.start-bg__bubble:nth-child(14) { --x: 62%; --size: 11px; --dur: 5.5s; --delay: -4.5s; --color: #7dff9b; --sway: 22px; }
.start-bg__bubble:nth-child(15) { --x: 86%; --size: 18px; --dur: 6.5s; --delay: -2s; --color: #9b5cff; }
.start-bg__bubble:nth-child(16) { --x: 96%; --size: 8px; --dur: 5s; --delay: -1s; --color: var(--gold); --sway: -16px; }

.start-bg__bubble:nth-child(n + 11) {
  display: none;
}

/* 横に弾いたときの揺れ（#316、start-fx-view.js の shakeStart）。最初に弾いた向き（--shake-dir）へ振れ、左右に揺れながら収まる。
   背景の層は translate を視差に使うので、揺れは transform で重ねる */
#screen-start.is-swipe-shake > .start-scroll,
#screen-start.is-swipe-shake > .home-tabbar,
#screen-start.is-swipe-shake .start-bg__layer {
  animation: swipe-shake 0.55s ease-out;
}

/* 背景の層は奥にあるので小さく揺らす */
#screen-start.is-swipe-shake .start-bg__layer {
  --shake-amp: 10px;
}

.is-wild-motion #screen-start {
  --shake-amp: 32px;
}

.is-wild-motion #screen-start.is-swipe-shake .start-bg__layer {
  --shake-amp: 18px;
}

/* 泡の輪は疑似要素に描き、本体は位置と昇るアニメーションだけを持つ（膨らみの理由は .is-popped） */
.start-bg__bubble::before,
.start-bg__hold-bubble::before {
  content: '';
  position: absolute;
  inset: 0;
  border: 2px solid var(--color);
  border-radius: 50%;
  box-shadow: 0 0 10px var(--color), inset 0 0 6px var(--color);
}

/* 横に弾いたときに割れる泡（#316、start-bg-view.js）。opacity と transform は昇るアニメーションが持つので、消すのは filter で付ける。
   本体に個別の scale を付けると transform の外側に掛かり、昇った量まで 1.8 倍にして泡が上へ飛ぶ（#508）。
   疑似要素の scale は本体の transform の内側で掛かるので、膨らみは ::before に付ける。外したときは transition を付けず、すぐ戻す */
.start-bg__bubble.is-popped {
  filter: opacity(0);
  transition: filter 0.2s ease-out;
}

.start-bg__bubble.is-popped::before {
  scale: 1.8;
  transition: scale 0.2s ease-out;
}

/* 空いた所をタップしたときの波紋（#465、start-bg-view.js の createRippler）。--hue は着せ替えの光跡の色相。
   小さい輪では指を離した直後に気づきにくかったので、画面の幅を越えるくらいまで広げ、少し遅れてもう 1 つの輪を追わせる */
.start-bg__ripple,
.start-bg__ripple::after {
  position: absolute;
  border-radius: 50%;
  opacity: 0;
}

.start-bg__ripple {
  --hue: 190;
  width: 360px;
  height: 360px;
  margin: -180px 0 0 -180px;
  border: 5px solid hsl(var(--hue) 100% 65%);
  box-shadow: 0 0 24px hsl(var(--hue) 100% 60%), inset 0 0 18px hsl(var(--hue) 100% 60%);
  animation: tap-ripple 0.8s ease-out;
}

.start-bg__ripple::after {
  content: '';
  inset: 20%;
  border: 3px solid hsl(var(--hue) 100% 75%);
  box-shadow: 0 0 14px hsl(var(--hue) 100% 60%);
  animation: tap-ripple 0.8s ease-out 0.12s;
}

/* 長押しのあいだ湧く泡（#465、createHoldBubbles）。背景の泡と同じ見た目で、短く昇りきって消える。
   left は画面の下の全幅から JS が決める */
.start-bg__hold {
  position: absolute;
  inset: 0;
}

.start-bg__hold-bubble {
  --size: 10px;
  --dur: 3s;
  --sway: 16px;
  --color: var(--hot);
  position: absolute;
  bottom: -40px;
  width: var(--size);
  height: var(--size);
  margin-left: calc(var(--size) / -2);
  opacity: 0;
  animation: hold-rise var(--dur) ease-out forwards, hold-sway var(--dur) ease-in-out forwards;
}

/* 離したときに割れる泡は背景の泡（.start-bg__bubble.is-popped）と同じく、::before で膨らんで本体の filter で消える */
.start-bg__hold-bubble.is-popped {
  filter: opacity(0);
  transition: filter 0.2s ease-out;
}

.start-bg__hold-bubble.is-popped::before {
  scale: 1.8;
  transition: scale 0.2s ease-out;
}

/* コースは 1 行に 1 つ、並びは HTML の順で固定する。説明はボタンの外の下の行に出す */
.difficulty {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-6);
  width: min(100%, 320px);
  margin-top: var(--space-7);
}

.btn-big {
  width: min(100%, 320px);
  padding: var(--space-7) 0;
  border: 0;
  border-radius: 999px;
  background: linear-gradient(90deg, var(--hot), var(--gold));
  color: #1a0b1a;
  font-family: var(--font-display);
  font-size: 28px;
  box-shadow: 0 6px 0 #8a1d57, 0 0 30px rgb(255 63 164 / 0.5);
}

/* 結果画面の「もう1回」と、初めての人の「はじめる」は脈打つ */
#btn-retry,
.is-first-visit .course--normal .btn-big {
  animation: pulse 1.1s ease-in-out infinite;
}

.course {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  width: 100%;
}

/* 4 つ並べても連続日数とミッションを押し出しすぎないよう、名前と BEST を 1 行に収めて低くする */
.difficulty .btn-big {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-6);
  width: 100%;
  padding: var(--space-4) var(--space-8);
  font-size: var(--text-2xl);
  box-shadow: 0 4px 0 rgb(0 0 0 / 0.4);
}

.difficulty .btn-big:active {
  transform: translateY(3px) scale(0.97);
  box-shadow: 0 1px 0 rgb(0 0 0 / 0.4);
}

/* 開くたびに上から順に弾んで出て、光の筋が上から順に走り抜ける。大きさは変えない（4 つとも脈打たせない） */
.difficulty .btn-big {
  position: relative;
  overflow: hidden;
  animation: course-in 0.5s cubic-bezier(0.3, 1.6, 0.5, 1) backwards;
}

.difficulty .btn-big::after {
  content: '';
  position: absolute;
  top: 0;
  bottom: 0;
  left: 0;
  width: 40%;
  background: linear-gradient(100deg, transparent, rgb(255 255 255 / 0.65), transparent);
  transform: translateX(-120%) skewX(-20deg);
  pointer-events: none;
  animation: course-shine 3.2s ease-in-out 0.6s infinite;
}

.difficulty .btn-big > * {
  position: relative;
  z-index: 1;
}

.difficulty > :nth-child(2) .btn-big { animation-delay: 0.07s; }
.difficulty > :nth-child(3) .btn-big { animation-delay: 0.14s; }
.difficulty > :nth-child(4) .btn-big { animation-delay: 0.21s; }
.difficulty > :nth-child(2) .btn-big::after { animation-delay: 0.75s; }
.difficulty > :nth-child(3) .btn-big::after { animation-delay: 0.9s; }
.difficulty > :nth-child(4) .btn-big::after { animation-delay: 1.05s; }

.difficulty .btn-big small {
  margin-top: 0;
  white-space: nowrap;
}

/* 数え上げるあいだに字の幅で BEST の文字が揺れないよう、数字の幅を揃える */
.best-count {
  font-variant-numeric: tabular-nums;
}

/* ベストを更新したコースだけ、数え終わった瞬間に金色に光らせる。大きさは変えない */
.best-count.is-best-glow {
  animation: best-glow 0.8s ease-out;
}

/* 数え上げる数字は aria-hidden にし、読み上げにはこちらの最終の値を読ませる */
.visually-hidden {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip-path: inset(50%);
  white-space: nowrap;
}

.course__note {
  margin: 0;
  color: var(--fg-dim);
  font-size: var(--text-sm);
  font-weight: 800;
  text-align: center;
}

.btn-big__first,
.is-first-visit .btn-big__name,
.is-first-visit .difficulty .btn-big small {
  display: none;
}

.is-first-visit .btn-big__first {
  display: inline;
}

/* 初めての人の「はじめる」は今までどおり大きく出す */
.is-first-visit .course--normal .btn-big {
  justify-content: center;
  padding: var(--space-7) 0;
  font-size: 28px;
  box-shadow: 0 6px 0 #8a1d57, 0 0 30px rgb(255 63 164 / 0.5);
}

.is-first-visit .course--normal .btn-big:active {
  box-shadow: 0 2px 0 #8a1d57;
}

/* 初めての人には「はじめる」1 つだけ見せる。挑戦状・PC の QR・更新の案内と、BGM を切れる設定のボタンは残す */
.is-first-visit .difficulty > :not(.course--normal),
.is-first-visit .course__note,
.is-first-visit .other-modes,
.is-first-visit .install-guide,
.is-first-visit #btn-share,
.is-first-visit .home-tabbar {
  display: none;
}

/* 「はじめる」と並べて目を引かないよう、薄い文字のボタンにする */
.first-skip {
  display: none;
  margin-top: var(--space-6);
  padding: var(--space-4);
  border: none;
  background: transparent;
  color: var(--fg-dim);
  font-size: var(--text-sm);
  text-decoration: underline;
  cursor: pointer;
}

.is-first-visit .first-skip {
  display: block;
}

.btn-big small {
  display: block;
  margin-top: var(--space-2);
  font-family: var(--font-body);
  font-size: var(--text-md);
  font-weight: 800;
}

.btn-big--easy {
  background: linear-gradient(90deg, #7dff9b, var(--accent));
}

.btn-big--hard {
  background: linear-gradient(90deg, #9b5cff, var(--accent));
}

.btn-big--daily {
  background: linear-gradient(90deg, var(--gold), #7dff9b);
}

.btn-big:active {
  transform: translateY(4px);
  box-shadow: 0 2px 0 #8a1d57;
}

.update-banner {
  padding: var(--space-5) var(--space-7);
  border: 0;
  border-radius: 999px;
  background: var(--accent);
  color: var(--bg);
  font-size: var(--text-md);
  font-weight: 800;
  box-shadow: 0 0 18px var(--accent-glow);
}

.update-banner[hidden] {
  display: none;
}

/* PC で開いた人に、スマホで遊ぶ案内を上の帯で出す。低い画面では QR を小さくして、375×667 でも先頭のコースのボタンまで収める */
.pc-qr {
  display: flex;
  align-self: stretch;
  align-items: center;
  gap: var(--space-6);
  padding: var(--space-4);
  border: 1px solid var(--accent);
  border-radius: 12px;
  background: var(--kb-bg);
  text-align: left;
}

.pc-qr[hidden] {
  display: none;
}

.pc-qr__img {
  flex: none;
  width: 72px;
  height: 72px;
  border-radius: 6px;
  background: #fff;
}

.pc-qr__text {
  flex: 1;
  margin: 0;
  text-wrap: balance;
  font-size: var(--text-md);
  font-weight: 800;
}

.pc-qr__text small {
  display: block;
  margin-top: var(--space-1);
  color: var(--fg-dim);
  font-size: var(--text-xs);
  font-weight: 500;
}

.pc-qr__close {
  align-self: flex-start;
  padding: var(--space-2) var(--space-5);
  border: 0;
  background: transparent;
  color: var(--fg-dim);
  font-size: var(--text-xl);
  line-height: 1;
}

@media (max-height: 700px) {
  .pc-qr__img {
    width: 56px;
    height: 56px;
  }
}

/* 幅が広い窓では、ゲームの列の外の右上に置いてタイトルの並びに影響させない */
@media (min-width: 960px) {
  .pc-qr {
    position: fixed;
    top: 16px;
    right: 16px;
    z-index: 10;
    flex-direction: column;
    width: 200px;
    padding: var(--space-7);
    text-align: center;
  }

  .pc-qr__img,
  .pc-qr__text {
    flex: none;
  }

  .pc-qr__img {
    width: 144px;
    height: 144px;
  }

  .pc-qr__close {
    position: absolute;
    top: 4px;
    right: 4px;
  }
}

/* 今動いている版を見分けるためのもの。遊ぶ邪魔にならないよう隅に小さく出す */
.app-version {
  margin: 0;
  color: var(--fg-dim);
  font-size: var(--text-xs);
  font-family: ui-monospace, monospace;
}

/* 文字は中身の左端に揃えたまま、padding のぶんだけ押せる範囲を広げる */
.x-link {
  margin-left: -8px;
  padding: var(--space-4);
  color: var(--fg-dim);
  font-size: var(--text-sm);
  text-decoration: none;
}

.btn-small {
  padding: var(--space-4) var(--space-7);
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  color: var(--fg);
  font-size: var(--text-md);
  text-decoration: none;
}

/* 本文だけをスクロールさせ、「もう1回」と共有は中身の量によらず下段の同じ位置で押せるようにする */
.result__body {
  display: flex;
  flex: 1;
  flex-direction: column;
  min-height: 0;
  /* overflow-y: auto（.screen--scroll）で横も auto になり、拡大したランク（rank-in と rank-fresh）のぶん横にスクロールできてしまう */
  overflow-x: hidden;
  padding-top: var(--space-7);
  padding-bottom: var(--space-6);
}

.result__actions {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-5);
  padding: var(--space-2) var(--space-7) var(--space-6);
  text-align: center;
  transition: opacity 0.2s;
}

.result__actions.is-locked {
  opacity: 0.4;
}

/* 固定の段は「もう1回」とこの 1 行だけにする。外に出す手段は「共有」のシートにまとめる */
.result__sub-actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  align-items: center;
  gap: var(--space-4);
}

.result__share-open {
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 800;
}

.result__home {
  padding: var(--space-4) var(--space-6);
  border-color: transparent;
  color: var(--fg-dim);
  font-size: var(--text-md);
}

.result__difficulty {
  margin: 0;
  font-weight: 800;
  color: var(--fg-dim);
}

/* 点数の下の行は点数の注なので、画面の段の間隔より近づけてランクと点数と 1 つの塊に見せる */
.result__tally {
  margin: calc(-1 * var(--space-6)) 0 0;
  color: var(--fg-dim);
  font-size: var(--text-md);
  font-weight: 800;
}

.result__survived {
  margin: 0;
  font-weight: 800;
  color: var(--gold);
}

.result__rank {
  font-family: var(--font-display);
  /* いちばん幅のある S10 などの 3 字は 140px で約 340px あり、幅 360px の端末で左右の余白にはみ出すので、幅に合わせて縮める */
  font-size: min(140px, 36vw);
  line-height: 1;
  background: linear-gradient(180deg, var(--gold), var(--hot));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* 点数に合わせてランクを登る（main.js の climbStep）。普通の段は小さく弾み、初めてのランクは光って弾み、登り切ったら入場する */
.result__rank.is-step {
  animation: rank-step 0.12s ease-out;
}

.result__rank.is-fresh {
  animation: rank-fresh 0.35s ease-out;
}

.result__rank.is-landed {
  animation: rank-in 0.6s cubic-bezier(0.2, 1.8, 0.4, 1);
}

/* 順に出す段まで隠す。場所は取ったままなので、出ても配置がずれない */
.is-concealed {
  visibility: hidden;
}

.result__score {
  font-family: var(--font-display);
  font-size: 48px;
  color: var(--accent);
  text-shadow: 0 0 20px var(--accent-glow);
}

.new-record {
  margin: 0;
  color: var(--gold);
  font-family: var(--font-display);
  font-size: 24px;
  animation: blink 0.5s steps(2) infinite;
}

.new-record[hidden] {
  display: none;
}

.rank-promotion {
  margin: 0;
  color: var(--gold);
  font-family: var(--font-display);
  font-size: clamp(20px, 6vw, 28px);
  text-align: center;
}

.rank-promotion.is-promoted {
  animation: promote-in 0.7s cubic-bezier(0.2, 1.8, 0.4, 1);
}

.rank-promotion[hidden] {
  display: none;
}

.stats {
  display: grid;
  grid-template-columns: repeat(6, 1fr);
  gap: var(--space-4);
  width: 100%;
  margin: 0;
}

/* 1 行目の 3 欄を 2 列ずつ、2 行目の速さ 2 欄を 3 列ずつにして、5 欄でも空きを出さない */
.stats div {
  grid-column: span 2;
  padding: var(--space-5) var(--space-2);
  border-radius: 12px;
  background: var(--kb-bg);
}

.stats div:nth-child(n + 4) {
  grid-column: span 3;
}

.stats dt {
  color: var(--fg-dim);
  font-size: var(--text-xs);
}

.stats dd {
  margin: var(--space-2) 0 0;
  font-family: var(--font-display);
  font-size: var(--text-2xl);
}

/* 受け取った挑戦状の案内。ボタンの列の上に置くので、遊ぶ入口より目立たせすぎない */
.challenge {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-2);
  max-width: 100%;
  padding: var(--space-6) var(--space-7);
  border: 1px solid var(--hot);
  border-radius: 16px;
  background: var(--kb-bg);
}

.challenge[hidden] {
  display: none;
}

.challenge__title,
.challenge__detail,
.challenge__note {
  max-width: 100%;
  margin: 0;
  overflow-wrap: anywhere;
}

.challenge__title {
  color: var(--hot);
  font-weight: 800;
}

.challenge__detail {
  font-size: var(--text-md);
  font-weight: 800;
}

.challenge__note {
  color: var(--fg-dim);
  font-size: var(--text-sm);
}

.challenge__title:empty,
.challenge__detail:empty,
.challenge__note:empty {
  display: none;
}

.challenge__accept {
  margin-top: var(--space-2);
  border-color: var(--hot);
  color: var(--hot);
  font-weight: 800;
}

/* ミッションタブの段。見出しを付けた枠に分け、何が並んでいるかを見出しで追えるようにする */
.today-card {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  width: min(100%, 343px);
  margin: 0;
  padding: var(--space-7);
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--kb-bg);
  text-align: left;
}

.today-card[hidden] {
  display: none;
}

.today-card__head {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-6);
}

.today-card__title {
  margin: 0;
  color: var(--fg-dim);
  font-size: var(--text-sm);
  font-weight: 800;
}

.today-card__side {
  color: var(--fg-dim);
  font-size: var(--text-sm);
  font-weight: 800;
}

.today-card__side.is-done {
  color: var(--gold);
}

/* 空のときも文の行とスタンプの行の分だけ高さを取り、描いたときにほかの要素が動かないようにする */
.start-streak {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  min-height: calc(1.4em + var(--space-5) + 28px);
  margin: 0;
}

.start-board {
  min-height: 1.4em;
  margin: 0;
  line-height: 1.4;
  color: var(--fg-dim);
  font-size: var(--text-sm);
}

.final-rank {
  border-color: var(--accent);
  color: var(--accent);
  font-size: var(--text-md);
  font-weight: 800;
}

.start-streak__text {
  min-height: 1.4em;
  margin: 0;
  color: var(--gold);
  font-size: var(--text-xl);
  font-weight: 800;
  line-height: 1.4;
}

.start-streak__stamps {
  display: flex;
  justify-content: space-between;
  margin: 0;
  padding: 0;
  list-style: none;
}

.start-streak__stamps .stamp {
  width: 28px;
  height: 28px;
  font-size: var(--text-sm);
}

/* 親指のレベルは連続日数とは別の数なので、線で区切った下の行にする */
.start-streak__thumb {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  gap: var(--space-6);
  margin: 0;
  padding-top: var(--space-5);
  border-top: 1px solid var(--line);
}

.start-streak__level {
  font-size: var(--text-lg);
  font-weight: 800;
}

.start-streak__next {
  color: var(--fg-dim);
  font-size: var(--text-sm);
  font-weight: 700;
}

.stamp {
  display: grid;
  place-items: center;
  width: 20px;
  height: 20px;
  border: 1px solid var(--line);
  border-radius: 50%;
  color: var(--fg-dim);
  font-size: var(--text-xs);
  font-weight: 800;
  line-height: 1;
}

.stamp.is-future {
  border-style: dashed;
  opacity: 0.6;
}

.stamp.is-played {
  border-color: var(--gold);
  background: var(--gold);
  color: var(--bg);
  opacity: 1;
}

.stamp.is-today {
  box-shadow: 0 0 0 2px var(--bg), 0 0 0 3px var(--accent);
}

/* 1〜2 行の小さな帯。コースのボタンより下に置くので、高さが足りないときは下のボタンの側がスクロールに回る。
   ほかのお知らせ（.pc-qr、.challenge）と同じ暗い地と色の枠にする。塗りつぶすとすぐ上のコースのボタンに見える */
.install-guide {
  display: flex;
  align-items: center;
  gap: var(--space-4);
  width: 100%;
  max-width: 343px;
  padding: var(--space-3) var(--space-2) var(--space-3) var(--space-4);
  border: 1px solid var(--gold);
  border-radius: 12px;
  background: var(--kb-bg);
  font-size: var(--text-sm);
  line-height: 1.4;
  text-align: left;
}

.install-guide[hidden] {
  display: none;
}

.install-guide__icon {
  flex: none;
  width: 24px;
  height: 24px;
  fill: none;
  stroke: var(--gold);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.install-guide__text {
  flex: 1;
  margin: 0;
}

.install-guide__text span {
  display: block;
}

.install-guide__btn {
  padding: var(--space-3) var(--space-6);
  border: 0;
  border-radius: 999px;
  background: var(--accent);
  color: var(--bg);
  font-size: var(--text-sm);
  font-weight: 800;
}

.install-guide__close {
  width: 32px;
  height: 32px;
  border: 0;
  background: transparent;
  color: var(--fg-dim);
  font-size: var(--text-xl);
  line-height: 1;
}

.install-dialog__lead {
  margin: 0;
  font-size: var(--text-md);
  line-height: 1.5;
  text-align: left;
}

/* 手順は押す場所の絵と文を並べる。番号は ol の並びで読み上げに任せ、見た目は絵で追う */
.install-dialog__steps {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
  counter-reset: install-step;
}

.install-dialog__step {
  display: flex;
  align-items: center;
  gap: var(--space-6);
  font-size: var(--text-md);
  font-weight: 700;
  line-height: 1.4;
  text-align: left;
  counter-increment: install-step;
}

.install-dialog__step::before {
  content: counter(install-step);
  flex: none;
  width: 1.2em;
  color: var(--fg-dim);
  font-weight: 800;
  text-align: right;
}

.install-dialog__icon {
  flex: none;
  width: 36px;
  height: 36px;
  padding: var(--space-3);
  border: 1px solid var(--line);
  border-radius: 10px;
  fill: none;
  stroke: var(--accent);
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

/* 点だけの絵は線を太くしないと見えない */
.install-dialog__icon--dots {
  stroke-width: 4;
}

.install-dialog__add {
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 800;
}

/* コピーのボタンが別にあるので、ここは長押しで選べるだけの文にする */
.share-dialog__url.install-dialog__url {
  cursor: text;
  text-decoration: none;
}

.share-dialog__url.install-dialog__url::after {
  content: none;
}

.start-missions__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.start-missions__item {
  display: flex;
  align-items: center;
  gap: var(--space-5);
  font-size: var(--text-md);
  font-weight: 700;
}

.start-missions__check {
  display: grid;
  flex: none;
  place-items: center;
  width: 22px;
  height: 22px;
  border: 1px solid var(--line);
  border-radius: 50%;
  font-size: var(--text-sm);
  font-weight: 800;
  line-height: 1;
}

.start-missions__item.is-done {
  color: var(--gold);
}

.start-missions__item.is-done .start-missions__check {
  border-color: var(--gold);
  background: var(--gold);
  color: var(--bg);
}

.start-missions__note {
  margin: 0;
  color: var(--fg-dim);
  font-size: var(--text-xs);
  font-weight: 700;
}

/* おみくじ（omikuji-view.js）。結果画面と同じ札と筒を、見出しを付けた段に出す */
.start-omikuji {
  display: flex;
  justify-content: center;
}

.omikuji-button {
  min-height: 44px;
  padding: var(--space-5) var(--space-8);
  border-color: var(--gold);
  color: var(--gold);
  font-size: var(--text-lg);
  font-weight: 800;
}

/* 補足は見出しの横に並べると狭い画面で 2 行に折れるので、見出しの下の行に分ける */
.omikuji-button__note {
  display: block;
  margin-top: var(--space-2);
  color: var(--fg-dim);
  font-size: var(--text-sm);
  font-weight: 700;
}

.omikuji-card {
  width: min(100%, 320px);
  padding: var(--space-6) var(--space-7);
  border: 1px solid var(--gold);
  border-radius: 12px;
  background: rgb(255 210 63 / 0.06);
  text-align: center;
}

.omikuji-card__face > p {
  margin: 0;
}

.omikuji-card__label {
  color: var(--fg-dim);
  font-size: var(--text-sm);
}

.omikuji-card__fortune {
  font-size: 32px;
  font-weight: 900;
  line-height: 1.3;
}

.omikuji-card__fortune.is-prize {
  color: var(--gold);
}

.omikuji-card__message {
  font-size: var(--text-md);
}

.omikuji-card__face > .omikuji-card__prize {
  margin-top: var(--space-4);
  color: var(--gold);
  font-size: var(--text-md);
  font-weight: 800;
}

.omikuji-card__face > .omikuji-card__wear {
  margin-top: var(--space-4);
  border-color: var(--gold);
  color: var(--gold);
}

.omikuji-card__face > .omikuji-card__worn {
  margin-top: var(--space-4);
  color: var(--fg-dim);
  font-size: var(--text-sm);
  font-weight: 800;
}

/* 今日まだ遊んでいなくて引けないとき */
.omikuji-wait {
  text-align: center;
}

.omikuji-wait > p {
  margin: 0;
}

.omikuji-wait__lead {
  font-size: var(--text-lg);
  font-weight: 800;
}

.omikuji-wait__note {
  margin-top: var(--space-2);
  color: var(--fg-dim);
  font-size: var(--text-sm);
  font-weight: 700;
}

.omikuji-next {
  margin: 0;
  color: var(--fg-dim);
  font-size: var(--text-sm);
  font-weight: 700;
  text-align: center;
}

.omikuji-missions {
  align-self: center;
}

/* 大吉だけの金色の札。中吉の is-prize（金の字）はそのまま、札の地と枠と字の光で差を付ける。
   地の金は字の --fg と運勢の字が沈まない暗さにとどめる */
.omikuji-card.is-daikichi {
  border: 2px solid var(--gold);
  background:
    radial-gradient(120% 90% at 50% 0%, rgb(255 210 63 / 0.32), transparent 70%),
    linear-gradient(160deg, #4a3b14, #2a2008);
  box-shadow: 0 0 18px rgb(255 210 63 / 0.45), inset 0 0 12px rgb(255 210 63 / 0.25);
}

.omikuji-card__fortune.is-daikichi {
  background: linear-gradient(180deg, #fff3b0, var(--gold) 55%, #e8a800);
  background-clip: text;
  -webkit-background-clip: text;
  color: transparent;
  font-size: 40px;
  filter: drop-shadow(0 0 6px rgb(255 210 63 / 0.6));
}

.omikuji-card.is-daikichi .omikuji-card__label,
.omikuji-card.is-daikichi .omikuji-card__worn {
  color: #e8dcb0;
}

/* 超ド派手の大吉は札の箱を揺らす（札は開くアニメーションを持つので箱に掛ける） */
.is-wild-motion .start-omikuji.is-quake {
  animation: quake 0.5s linear;
}

/* 折りたたんだ札が開く（1s は OPEN_MS）。筒から引いた細い紙が浮かび、中央から左右に広がって字が出る。
   開き切った瞬間に音と粒を出す。fill を付けないのは、終わったあとも clip-path が残ると大吉の札の光が切れるため */
.omikuji-card.is-opening {
  animation: omikuji-open 1s ease-out;
}

.omikuji-card.is-opening > .omikuji-card__face {
  animation: omikuji-face 1s ease-in;
}

@keyframes omikuji-open {
  0% { clip-path: inset(0 46% round 12px); opacity: 0; transform: translateY(16px); }
  25% { clip-path: inset(0 46% round 12px); opacity: 1; transform: translateY(0); }
  100% { clip-path: inset(0 0 round 12px); }
}

@keyframes omikuji-face {
  0%, 50% { opacity: 0; }
  100% { opacity: 1; }
}

/* 札の前の溜め（omikuji-view.js の drawing）。筒を振り、出た棒の先の色で運勢をほのめかす。
   高さは札に近づけ、入れ替わるときの段差を小さくする */
.omikuji-draw {
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: flex-end;
  gap: var(--space-3);
  min-height: 212px;
  cursor: pointer;
  --stick-rise: -54px;
}

/* 棒は筒より先に置き、筒の後ろに伏せる。上の余白は余白の段ではなく、棒が出る高さ（--stick-rise）に合わせた寸法 */
.omikuji-draw__shaker {
  position: relative;
  padding-top: 56px;
  transform-origin: 50% 100%;
}

.omikuji-draw__tube {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  width: 80px;
  height: 124px;
  border: 2px solid var(--gold);
  border-radius: 6px;
  background: linear-gradient(90deg, #5a1d14, #8a2c1e 50%, #5a1d14);
  color: var(--gold);
  font-size: var(--text-xl);
  font-weight: 900;
  writing-mode: vertical-rl;
}

.omikuji-draw__stick {
  position: absolute;
  top: 68px;
  left: calc(50% - 5px);
  width: 10px;
  height: 72px;
  border-radius: 2px;
  background: #d9b779;
}

/* 棒の先。前ぶれの段で色が付く */
.omikuji-draw__stick::before {
  content: '';
  position: absolute;
  inset: 0 0 auto;
  height: 30%;
  border-radius: 2px 2px 0 0;
  background: #b89a62;
}

.omikuji-draw.is-omen-color .omikuji-draw__stick::before {
  background: #ff8fc6;
  box-shadow: 0 0 8px rgb(255 143 198 / 0.8);
}

.omikuji-draw.is-omen-gold .omikuji-draw__stick::before {
  background: var(--gold);
  box-shadow: 0 0 14px 2px rgb(255 210 63 / 0.9);
}

.omikuji-draw__caption {
  color: var(--fg-dim);
  font-size: var(--text-lg);
  font-weight: 700;
}

.omikuji-draw.is-omen-color .omikuji-draw__caption {
  color: #ff8fc6;
}

.omikuji-draw.is-omen-gold .omikuji-draw__caption {
  color: var(--gold);
}

/* 揺れの 3s は SHAKE_MS、棒が出る 0.6s は PULL_MS。金の光の 0.4s は、棒が出切ってから STICK_MS の残りに収める。
   揺れは往復をだんだん速く大きくしてピタッと止め、HOLD_MS の間を置いてから棒を引く */
.omikuji-draw__shaker.is-shaking {
  animation: omikuji-shake 3s linear both;
}

/* 超ド派手は大きく揺らし、横にも振る */
.is-wild-motion .omikuji-draw__shaker.is-shaking {
  animation-name: omikuji-shake-wild;
}

.omikuji-draw__shaker.is-rising > .omikuji-draw__stick {
  animation: omikuji-stick 0.6s ease-out both;
}

.omikuji-draw.is-omen-gold .omikuji-draw__shaker.is-rising {
  animation: omikuji-glow 0.4s ease-in-out both;
}

@keyframes omikuji-shake {
  0%, 100% { transform: rotate(0); }
  8% { transform: rotate(-6deg); }
  15.5% { transform: rotate(7deg); }
  22.4% { transform: rotate(-8deg); }
  28.9% { transform: rotate(9deg); }
  34.9% { transform: rotate(-10deg); }
  40.5% { transform: rotate(11deg); }
  45.8% { transform: rotate(-12deg); }
  50.7% { transform: rotate(13deg); }
  55.2% { transform: rotate(-14deg); }
  59.5% { transform: rotate(15deg); }
  63.4% { transform: rotate(-16deg); }
  67.1% { transform: rotate(18deg); }
  70.6% { transform: rotate(-19deg); }
  73.8% { transform: rotate(20deg); }
  76.7% { transform: rotate(-21deg); }
  79.5% { transform: rotate(22deg); }
  82.1% { transform: rotate(-23deg); }
  84.5% { transform: rotate(24deg); }
  86.9% { transform: rotate(-25deg); }
  89.2% { transform: rotate(26deg); }
  91.5% { transform: rotate(-27deg); }
  93.9% { transform: rotate(28deg); }
}

@keyframes omikuji-shake-wild {
  0%, 100% { transform: translateX(0) rotate(0); }
  8% { transform: translateX(-4px) rotate(-10deg); }
  15.5% { transform: translateX(5px) rotate(11deg); }
  22.4% { transform: translateX(-5px) rotate(-13deg); }
  28.9% { transform: translateX(6px) rotate(14deg); }
  34.9% { transform: translateX(-6px) rotate(-16deg); }
  40.5% { transform: translateX(7px) rotate(17deg); }
  45.8% { transform: translateX(-7px) rotate(-19deg); }
  50.7% { transform: translateX(8px) rotate(20deg); }
  55.2% { transform: translateX(-9px) rotate(-21deg); }
  59.5% { transform: translateX(9px) rotate(23deg); }
  63.4% { transform: translateX(-10px) rotate(-24deg); }
  67.1% { transform: translateX(10px) rotate(26deg); }
  70.6% { transform: translateX(-11px) rotate(-27deg); }
  73.8% { transform: translateX(11px) rotate(29deg); }
  76.7% { transform: translateX(-12px) rotate(-30deg); }
  79.5% { transform: translateX(13px) rotate(31deg); }
  82.1% { transform: translateX(-13px) rotate(-33deg); }
  84.5% { transform: translateX(14px) rotate(34deg); }
  86.9% { transform: translateX(-14px) rotate(-36deg); }
  89.2% { transform: translateX(15px) rotate(37deg); }
  91.5% { transform: translateX(-15px) rotate(-39deg); }
  93.9% { transform: translateX(16px) rotate(40deg); }
}

@keyframes omikuji-stick {
  from { transform: translateY(0); }
  to { transform: translateY(var(--stick-rise)); }
}

@keyframes omikuji-glow {
  from { filter: drop-shadow(0 0 0 transparent); }
  to { filter: drop-shadow(0 0 10px rgb(255 210 63 / 0.7)); }
}

/* ---------- title tabs ---------- */

/* タイトル画面は、上のスクロールする中身と下のタブバーに分ける。タブバーは流れの最後に置くので、中身を隠さない */
.start-scroll {
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: center;
  gap: var(--space-7);
  min-height: 0;
  padding: var(--space-4) var(--space-7) 0;
  text-align: center;
}

/* 上端から引っ張る（#315、pull-view.js）。引いているあいだは指に付いてくるよう transition を付けず、離したら戻す。
   動かすのは translate と scale の個別の指定にし、入場や揺れの transform のアニメーションとぶつけない */
#screen-start {
  position: relative;
}

.start-scroll.is-pulling > *,
.start-scroll.is-pull-back > * {
  translate: 0 var(--pull-y, 0px);
}

.start-scroll.is-pulling .start-panel--play > .title,
.start-scroll.is-pull-back .start-panel--play > .title {
  scale: 1 var(--pull-scale, 1);
  transform-origin: 50% 0;
}

/* タイトルが伸びた分だけ、その下を下げる。scale は配置を動かさないので、下げないとコースのボタンに重なる */
.start-scroll.is-pulling .start-panel--play > .title ~ *,
.start-scroll.is-pull-back .start-panel--play > .title ~ * {
  translate: 0 var(--pull-extra, 0px);
}

/* ぷるんと縮んで戻る。行き過ぎて戻る曲線にする */
.start-scroll.is-pull-back > *,
.start-scroll.is-pull-back .start-panel--play > .title,
.start-scroll.is-pull-back .start-panel--play > .title ~ * {
  transition: translate 0.5s cubic-bezier(0.34, 1.56, 0.64, 1), scale 0.5s cubic-bezier(0.34, 1.56, 0.64, 1);
}

/* 脳汁は行き過ぎずに、上端の向こうへ吸い込まれる（初めはゆっくり、だんだん速く） */
.pull.is-pull-back .pull__drop,
.pull.is-pull-back::before {
  transition: translate 0.4s cubic-bezier(0.5, 0, 0.75, 0);
}

/* 満タンで離したときは、滴が上端から切れて落ちる。縮みながら先のほうへ丸まり、薄くなって、先ではじける粒につなぐ。
   帯だけは上へ吸い込む。--pull-y は離したときの長さのまま残してある（pull-view.js） */
.pull.is-falling::before {
  translate: 0 -100%;
}

.pull.is-falling .pull__drop {
  opacity: 0;
  scale: 0.6 0.15;
  transform-origin: 50% 100%;
  translate: -50% calc(var(--pull-y, 0px) * var(--k) - 100% + 160px);
  transition: translate 0.5s cubic-bezier(0.55, 0, 1, 0.45), scale 0.5s ease-out, opacity 0.5s ease-in;
}

/* 満タンで離したとき、超ド派手はドパるタブを揺らす。タイトルは打ち直して着地で弾むので、タイトルに掛けると animation を取り合う */
.is-wild-motion .start-panel--play.is-quake {
  animation: quake 0.5s linear;
}

/* 垂れる脳汁。上端から下がる帯と、長さの違う滴。指は下の中身に届かせる。
   上端より上は切り取る。iOS 26 の Safari は #app の上にステータスバーの分の余白（--status-bar-inset）を足すので、
   切らないと、上へ畳んだ帯がその余白に四角く残る */
.pull {
  position: absolute;
  inset: 0;
  z-index: 1;
  overflow: hidden;
  pointer-events: none;
  visibility: hidden;
}

/* 待っているあいだは上端より上に畳んである。動いているときだけ出す */
.pull.is-pulling,
.pull.is-pull-back {
  visibility: visible;
}

/* 色は着せ替えの光跡の色。--pull-hue は main.js の applySkins が入れ、色見本（skins.js の swatchOf）と同じ彩度と明るさで塗る */
.pull {
  --pull-color: hsl(var(--pull-hue, 328) 100% 62%);
  --pull-light: hsl(var(--pull-hue, 328) 100% 82%);
}

.pull::before,
.pull__drop {
  position: absolute;
  top: 0;
  background: var(--pull-color);
  filter: drop-shadow(0 0 10px hsl(var(--pull-hue, 328) 100% 62% / 0.6));
}

.pull::before {
  content: '';
  right: 0;
  left: 0;
  height: 400px;
  translate: 0 calc(min(var(--pull-y, 0px), 24px) - 100%);
}

.pull__drop {
  left: var(--x);
  width: var(--w);
  height: 600px;
  border-radius: 0 0 999px 999px;
  translate: -50% calc(var(--pull-y, 0px) * var(--k) - 100%);
}

.pull__drop:nth-child(1) { --x: 10%; --w: 18px; --k: 0.7; }
.pull__drop:nth-child(2) { --x: 29%; --w: 26px; --k: 1.05; }
.pull__drop:nth-child(3) { --x: 50%; --w: 22px; --k: 0.85; }
.pull__drop:nth-child(4) { --x: 70%; --w: 30px; --k: 1.15; }
.pull__drop:nth-child(5) { --x: 90%; --w: 16px; --k: 0.75; }

/* 満タン。ゲーム中の FEVER の虹色と分け、同じ色のまま明るく光らせて、表面を光が流れ落ちる */
.pull.is-full::before,
.pull.is-full .pull__drop {
  background: linear-gradient(180deg, var(--pull-color) 0%, var(--pull-light) 45%, var(--pull-color) 55%, var(--pull-color) 100%);
  background-size: 100% 300%;
  filter: drop-shadow(0 0 16px hsl(var(--pull-hue, 328) 100% 62% / 0.95)) drop-shadow(0 0 32px hsl(var(--pull-hue, 328) 100% 62% / 0.6)) brightness(1.15);
  animation: pull-shine 0.7s linear infinite;
}

/* 満タンに届いた瞬間、滴がぷくっと膨らむ。位置は translate で動かしているので scale で膨らませる */
.pull.is-full-pop .pull__drop {
  animation: pull-shine 0.7s linear infinite, pull-swell 0.35s ease-out;
}

@keyframes pull-shine {
  0% { background-position: 0 100%; }
  100% { background-position: 0 0; }
}

@keyframes pull-swell {
  0% { scale: 1; }
  40% { scale: 1.6 1.08; }
  100% { scale: 1; }
}

/* 動きひかえめは引っ張りの見た目を出さない（離したときの更新だけ走る） */
.is-reduced-motion .pull {
  display: none;
}

/* 中身が画面より高いとき、縮めずにスクロールさせる。縮めると連続日数の行がスタンプの行に重なる */
.start-scroll > *,
.start-panel > * {
  flex-shrink: 0;
}

/* 設定と友達に教える。どのタブでも右上に出す。流れの中に置くので、幅が狭いときの PC の QR の帯とも重ならない */
.start-header {
  display: flex;
  align-self: stretch;
  justify-content: flex-end;
  gap: var(--space-4);
}

.icon-button {
  display: grid;
  place-items: center;
  width: 40px;
  height: 40px;
  padding: 0;
  border: 1px solid var(--line);
  border-radius: 50%;
  background: transparent;
  color: var(--fg);
  font-size: var(--text-xl);
  line-height: 1;
}

.icon-button__svg {
  width: 20px;
  height: 20px;
  fill: none;
  stroke: currentColor;
  stroke-width: 2;
  stroke-linecap: round;
  stroke-linejoin: round;
}

.start-panel {
  display: flex;
  flex: 1 0 auto;
  flex-direction: column;
  align-items: center;
  gap: var(--space-7);
  width: 100%;
  padding-bottom: var(--space-7);
}

.start-panel[hidden] {
  display: none;
}

/* 記録は今までの画面と同じく左に揃えて読む */
.start-panel--records {
  align-items: stretch;
  text-align: left;
}

.start-panel__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: 400;
}

/* 下の余白は、最後の行のリンク自身の padding が兼ねる */
.start-panel--play {
  padding-bottom: 0;
}

/* 遊び方として見えるよう、小さいボタンではなくコースの幅のカードにする */
.other-modes {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  width: min(100%, 320px);
}

.other-modes__title {
  margin: var(--space-4) 0 0;
  color: var(--fg-dim);
  font-size: var(--text-md);
}

.mode-card {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: var(--space-1) var(--space-6);
  align-items: baseline;
  width: 100%;
  padding: var(--space-6) var(--space-7);
  border: 1px solid var(--line);
  border-radius: 16px;
  background: var(--kb-bg);
  color: var(--fg);
  text-align: left;
}

.mode-card:active:not(:disabled) {
  border-color: var(--accent);
  transform: scale(0.98);
}

.other-modes > * {
  animation: course-in 0.5s cubic-bezier(0.3, 1.6, 0.5, 1) backwards;
}

.other-modes > :nth-child(2) { animation-delay: 0.28s; }
.other-modes > :nth-child(3) { animation-delay: 0.35s; }
.other-modes > :nth-child(4) { animation-delay: 0.42s; }

.mode-card__name {
  font-size: var(--text-lg);
  font-weight: 800;
}

.mode-card__status {
  grid-row: 1;
  grid-column: 2;
  color: var(--gold);
  font-size: var(--text-sm);
  font-weight: 800;
  text-align: right;
  white-space: nowrap;
}

.mode-card__note {
  grid-column: 1 / -1;
  color: var(--fg-dim);
  font-size: var(--text-sm);
}

/* 鍵のカードは押せないことを見せつつ、条件は読めるように文字は薄くしすぎない */
.mode-card.is-locked {
  border-style: dashed;
  background: transparent;
  cursor: default;
}

.mode-card.is-locked .mode-card__name {
  color: var(--fg-dim);
}

.mode-card.is-locked .mode-card__status {
  grid-row: 3;
  grid-column: 1 / -1;
  color: var(--fg-dim);
  text-align: left;
  white-space: normal;
}

.mode-card.is-locked .mode-card__status::before {
  content: '🔒 ';
}

/* 親指の届く下端に置く。背景を safe-area の下まで伸ばし、ボタンはホームバーの上に残す */
.home-tabbar {
  display: grid;
  flex: none;
  grid-template-columns: repeat(5, 1fr);
  margin-bottom: calc(-1 * env(safe-area-inset-bottom));
  padding-bottom: env(safe-area-inset-bottom);
  border-top: 1px solid var(--key);
  background: var(--kb-bg);
}

.home-tab {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  min-height: 56px;
  padding: var(--space-3) 0;
  border: 0;
  background: transparent;
  color: var(--fg-dim);
  font-size: var(--text-xs);
  font-weight: 800;
}

.home-tab__icon {
  font-size: var(--text-2xl);
  line-height: 1;
  filter: grayscale(0.7);
  opacity: 0.75;
}

.home-tab[aria-selected='true'] {
  color: var(--accent);
}

.home-tab[aria-selected='true'] .home-tab__icon {
  filter: none;
  opacity: 1;
}

/* 未読の印。前の日の最終順位とまだ引けるおみくじ */
.home-tab.has-mark::after {
  content: '';
  position: absolute;
  top: var(--space-3);
  left: calc(50% + var(--space-6));
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--hot);
  box-shadow: 0 0 6px var(--hot);
}

/* ドパるのタブの ❤️ は開いているあいだ鼓動を打つ。押したときの弾みは transform ではなく scale で掛け、鼓動と重ねる */
#tab-play[aria-selected='true'] .home-tab__icon {
  position: relative;
  animation: heartbeat 1.2s ease-in-out infinite;
}

#tab-play.is-pop[aria-selected='true'] .home-tab__icon {
  animation: heartbeat 1.2s ease-in-out infinite, heart-pop 0.45s ease-out;
}

/* 超ド派手は、1 打目の鼓動に合わせて光の輪を広げる */
.is-wild-motion #tab-play[aria-selected='true'] .home-tab__icon::after {
  content: '';
  position: absolute;
  inset: 0;
  border-radius: 50%;
  box-shadow: 0 0 0 2px var(--hot), 0 0 12px var(--hot);
  opacity: 0;
  animation: heart-ring 1.2s ease-out infinite;
  pointer-events: none;
}

/* リンクと版の行。中身が画面に収まるときは画面の下端に、収まらないときは中身の最後に置く */
.start-footer {
  display: flex;
  align-self: stretch;
  align-items: baseline;
  justify-content: space-between;
  margin-top: auto;
}

/* 検索向けの説明。コースのボタンより目立たないよう小さく暗くし、余った高さで画面の下へ寄せる */
.start-about {
  width: 100%;
  max-width: 520px;
  margin: auto auto 0;
  color: var(--fg-dim);
  font-size: var(--text-sm);
  line-height: 1.6;
  text-align: left;
}

.start-about__title {
  margin: 0 0 var(--space-2);
  font-size: var(--text-md);
}

.start-about p {
  margin: 0 0 var(--space-3);
}

.start-about p:last-child {
  margin-bottom: 0;
}

.start-about + .start-footer {
  margin-top: 0;
}

/* ドパるタブは、余った高さを中身の上とリンクと版の行（説明の節があればその上）の上で等分し、中身を中央に置く */
.start-panel--play > .title {
  margin-top: auto;
}

.settings-dialog__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
  width: 100%;
}

.settings-dialog__item {
  width: 100%;
}

.settings-dialog__group {
  display: flex;
  flex-direction: column;
  gap: var(--space-5);
}

/* 見出しとその下のボタンのあいだは、group の gap から引いてボタン同士より詰める */
.settings-dialog__heading {
  margin: var(--space-4) 0 calc(var(--space-3) - var(--space-5));
  font-size: var(--text-sm);
  font-weight: 700;
  text-align: left;
  color: var(--fg-dim);
}

/* ダイアログの題とは share-dialog の gap で離れているので、高さを 1 画面に収めるため最初の見出しの上は空けない */
.settings-dialog__group:first-child > .settings-dialog__heading {
  margin-top: 0;
}

.settings-dialog__row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: var(--space-4);
}

.settings-dialog__row--3 {
  grid-template-columns: repeat(3, 1fr);
}

/* 今選んでいる値のボタン。結果画面の目標の選択と同じ見せ方 */
.settings-dialog__item[aria-pressed="true"] {
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 800;
}

/* 幅 320px の画面で「稼ぎ方のルール ›」が 1 行に入るよう、横並びだけ左右の余白を詰める */
.settings-dialog__row > .settings-dialog__item {
  padding-inline: var(--space-3);
  white-space: nowrap;
}

/* 別の画面を開くボタンに付け、値を切り替えるボタンと見分ける。/ '' で読み上げから外し、読めないブラウザには 1 つ目の content を残す */
.settings-dialog__item[data-closes-settings]::after {
  content: '›';
  content: '›' / '';
  margin-left: var(--space-1);
}

.pause-dialog__note {
  margin: 0;
  font-size: var(--text-xs);
  color: var(--fg-dim);
}

.settings-dialog__notice {
  margin: -4px 0 0;
  font-size: var(--text-md);
  font-weight: 800;
  text-align: center;
  color: var(--gold);
}

/* 共有のシートの「X でポスト」はリンクなので、ボタンと同じ幅の塊にする */
a.settings-dialog__item {
  display: block;
}

.settings-dialog__item:disabled {
  opacity: 0.5;
}

.rules-dialog__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--text-md);
  font-weight: 800;
  line-height: 1.5;
  text-align: left;
  text-wrap: balance;
}

/* スクロールするので pan-y、拡大できるように pinch-zoom を付ける。auto にするとダブルタップで拡大する */
.share-dialog {
  width: min(calc(100vw - 32px), 360px);
  max-height: calc(100dvh - 32px);
  overflow-y: auto;
  overscroll-behavior: contain;
  touch-action: pan-y pinch-zoom;
  padding: var(--space-7);
  border: 1px solid var(--line);
  border-radius: 20px;
  background: var(--kb-bg);
  color: var(--fg);
  text-align: center;
}

.share-dialog[open] {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-6);
}

.share-dialog::backdrop {
  background: rgb(0 0 0 / 0.7);
}

.share-dialog__title {
  margin: 0;
  font-family: var(--font-display);
  font-size: var(--text-2xl);
  font-weight: 400;
}

/* 暗い背景に直接置くとカメラが読み取れないので、白地と余白（quiet zone）を付ける */
.share-dialog__qr {
  width: 200px;
  height: 200px;
  padding: var(--space-4);
  border-radius: 12px;
  background: #fff;
}

.share-dialog__send {
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 800;
}

.share-dialog__status {
  min-height: 1.4em;
  margin: 0;
  color: var(--gold);
  font-size: var(--text-md);
  font-weight: 800;
}

/* タップでコピーする。body の user-select: none を打ち消し、コピーできない環境でも長押しして選べるようにする */
.share-dialog__url {
  margin: 0;
  font-family: ui-monospace, monospace;
  font-size: var(--text-md);
  word-break: break-all;
  -webkit-user-select: text;
  user-select: text;
  -webkit-touch-callout: default;
  cursor: pointer;
  text-decoration: underline dotted;
  text-underline-offset: 3px;
}

/* タップでコピーできることを示す */
.share-dialog__url::after {
  content: ' 📋';
  text-decoration: none;
}

/* 比べる行、連続日数、解禁は種類の違う短い文が何行も並ぶので、中央揃えにせず行頭を揃えて 1 つの枠にまとめる */
.result__progress {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  width: 100%;
  padding: var(--space-5) var(--space-7);
  border-radius: 12px;
  background: var(--kb-bg);
  text-align: left;
}

.result__progress[hidden] {
  display: none;
}

.result__compare {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--fg);
  font-size: var(--text-md);
  font-weight: 700;
  line-height: 1.4;
}

.result__compare:empty {
  display: none;
}

.result__compare li {
  display: flex;
  gap: var(--space-4);
}

.result__compare li::before {
  content: '';
  flex-shrink: 0;
  width: 6px;
  height: 6px;
  margin-top: 0.5em;
  border-radius: 50%;
  background: var(--accent);
}

.result__goal {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
}

.result__goal[hidden] {
  display: none;
}

.result__goal-label {
  margin: 0;
  color: var(--fg-dim);
  font-size: var(--text-sm);
  font-weight: 800;
}

.result__goal-options {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-3);
}

.result__goal-option {
  padding: var(--space-3) var(--space-6);
  font-size: var(--text-md);
}

.result__goal-option[aria-pressed="true"] {
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 800;
}

.result__versus {
  max-width: 100%;
  margin: 0;
  color: var(--hot);
  font-size: var(--text-lg);
  font-weight: 800;
  overflow-wrap: anywhere;
}

.result__versus[hidden] {
  display: none;
}

.result__challenge {
  border-color: var(--hot);
  color: var(--hot);
  font-weight: 800;
}

.result__play-style {
  display: flex;
  flex-direction: column;
  align-items: center;
  max-width: 100%;
  margin: 0;
  padding: var(--space-3) var(--space-7);
  border: 1px solid var(--accent);
  border-radius: 12px;
  color: var(--accent);
  text-align: center;
  overflow-wrap: anywhere;
}

.result__play-style[hidden] {
  display: none;
}

.result__play-style-name {
  font-size: var(--text-lg);
  font-weight: 800;
}

.result__play-style-detail {
  color: var(--fg);
  font-size: var(--text-md);
}

.result__highlights {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  margin: 0;
  padding: 0;
  list-style: none;
  color: var(--gold);
  font-size: var(--text-lg);
  font-weight: 800;
}

.result__highlights:empty {
  display: none;
}

.result__streak {
  margin: 0;
  color: var(--gold);
  font-size: var(--text-md);
  font-weight: 800;
}

.result__compare:not(:empty) + .result__streak {
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}

.result__streak:empty {
  display: none;
}

/* iOS の古い版は共有シートに画像を渡せないので、画像を出して長押しで保存してもらう。
   body の user-select: none と touch-callout: none を打ち消す */
.result__image {
  width: 100%;
  max-width: 320px;
  border-radius: 12px;
  -webkit-user-select: auto;
  user-select: auto;
  -webkit-touch-callout: default;
}

.result__image[hidden] {
  display: none;
}

/* 録っているあいだと録れたあとに、動画の中身を小さく見せる */
.result__video {
  width: 100%;
  max-width: 200px;
  aspect-ratio: 9 / 16;
  border-radius: 12px;
}

.result__video[hidden] {
  display: none;
}

/* 共有もコピーもできないときは共有する文をここに出し、長押しで選べるようにする。
   長い文は高さを抑えてこの中だけでスクロールさせる */
.result__share-status {
  /* 共有のシートは縦に流れる flex なので、overflow を持つこの行が 0 の高さまで縮まないようにする */
  flex-shrink: 0;
  max-height: 7.5em;
  margin: 0;
  overflow-y: auto;
  overscroll-behavior: contain;
  touch-action: pan-y pinch-zoom;
  color: var(--gold);
  font-size: var(--text-md);
  font-weight: 800;
  white-space: pre-line;
  -webkit-user-select: text;
  user-select: text;
}

.result__share-status:empty {
  display: none;
}

.result__ranking {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-3);
}

.result__ranking[hidden] {
  display: none;
}

.result__ranking-status {
  margin: 0;
  color: var(--accent);
  font-size: var(--text-lg);
  font-weight: 800;
}

.result__ranking-status:empty {
  display: none;
}

.ranking-dialog__note {
  margin: 0;
  color: var(--fg-dim);
  font-size: var(--text-md);
  line-height: 1.5;
}

.board__tabs {
  display: flex;
  gap: var(--space-4);
}

.board__tabs[hidden] {
  display: none;
}

.board__tab {
  padding: var(--space-3) var(--space-7);
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  color: var(--fg-dim);
  font-size: var(--text-md);
  font-weight: 800;
}

.board__tab[aria-selected='true'] {
  border-color: var(--gold);
  color: var(--gold);
}

.board__tab--sub {
  padding: var(--space-3) var(--space-6);
  font-size: var(--text-sm);
}

/* 8 日を 1 列に収め、狭い端末では横に送る（今日は右端なので、開いたら右端に寄せる） */
.board__days {
  display: flex;
  gap: var(--space-2);
  width: 100%;
  max-width: 360px;
  overflow-x: auto;
  scrollbar-width: none;
}

.board__days[hidden] {
  display: none;
}

.board__day {
  display: flex;
  flex: 1 0 36px;
  flex-direction: column;
  align-items: center;
  gap: var(--space-1);
  padding: var(--space-3) 0;
  border: 1px solid var(--line);
  border-radius: 10px;
  background: transparent;
  color: var(--fg-dim);
}

.board__day[aria-selected='true'] {
  border-color: var(--gold);
  color: var(--gold);
}

.board__day-date {
  font-size: var(--text-lg);
  font-weight: 800;
  line-height: 1;
}

.board__day-weekday {
  font-size: var(--text-xs);
  line-height: 1;
}

.board__summary {
  margin: 0;
  color: var(--fg-dim);
  font-size: var(--text-md);
}

.board-entry {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-5);
  width: 100%;
  padding: var(--space-6) var(--space-7);
  border: 1px solid var(--line);
  border-radius: 12px;
  box-sizing: border-box;
}

.board-entry__text {
  margin: 0;
  line-height: 1.5;
  text-align: center;
  color: var(--fg-dim);
  font-size: var(--text-md);
  overflow-wrap: anywhere;
}

.board-entry__name {
  color: var(--fg);
  font-weight: 800;
}

.board-entry__actions {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: var(--space-4);
}

.board-entry__daily {
  border-color: var(--accent);
  color: var(--accent);
  font-weight: 800;
}

.board__me {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  justify-content: center;
  gap: var(--space-2) var(--space-4);
  width: 100%;
  padding: var(--space-5) var(--space-6);
  border: 1px solid var(--accent);
  border-radius: 12px;
  box-sizing: border-box;
}

.board__me-label {
  color: var(--fg-dim);
  font-size: var(--text-md);
}

.board__me-score {
  color: var(--gold);
  font-size: var(--text-2xl);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

.board__me-rank {
  flex-basis: 100%;
  color: var(--accent);
  font-size: var(--text-md);
  font-weight: 800;
}

.board__foot {
  margin: 0;
  color: var(--fg-dim);
  font-size: var(--text-sm);
  line-height: 1.5;
}

.board__foot[hidden] {
  display: none;
}

.board__status {
  margin: 0;
  color: var(--gold);
  font-size: var(--text-md);
  font-weight: 800;
}

.board__summary:empty,
.board__status:empty,
.board__me:empty,
.board__list:empty {
  display: none;
}

.board__list {
  width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
  font-size: var(--text-md);
  font-variant-numeric: tabular-nums;
}

.board__row {
  display: flex;
  align-items: baseline;
  gap: var(--space-5);
  padding: var(--space-3) var(--space-2);
  border-bottom: 1px solid var(--key);
}

.board__rank {
  flex: none;
  width: 3.2em;
  color: var(--gold);
  font-weight: 800;
  text-align: center;
}

/* 名前は他人が入れた文字列で、10 字の英字や絵文字でも 1 行に収まらないことがある。2 行までは折り返して見せる */
.board__name {
  display: -webkit-box;
  flex: 1;
  min-width: 0;
  overflow: hidden;
  -webkit-box-orient: vertical;
  -webkit-line-clamp: 2;
  line-clamp: 2;
  overflow-wrap: anywhere;
  text-align: left;
}

.board__score {
  flex: none;
  font-weight: 800;
}

/* 人の行より控えめにして、サーバが混ぜた CPU だと見分ける */
.board__row--cpu .board__name,
.board__row--cpu .board__score {
  color: var(--fg-dim);
}

.board__row--top {
  padding-block: var(--space-5);
}

/* 字を大きくしても名前の列が他の行と揃うよう、幅を 3.2em（--text-md のとき）と同じ長さにする */
.board__row--top .board__rank {
  width: calc(3.2em * 14 / 18);
  font-size: var(--text-xl);
}

.board__row--top .board__score {
  font-size: var(--text-lg);
}

.board__row--cpu .board__rank {
  opacity: 0.6;
}

.board__row--me {
  border-radius: 8px;
  background: rgb(46 242 255 / 0.14);
  box-shadow: inset 3px 0 0 var(--accent);
}

.board__row--me .board__name {
  color: var(--accent);
  font-weight: 800;
}

.board__gap {
  padding: var(--space-1) 0;
  color: var(--fg-dim);
  text-align: center;
}

/* 「閉じる」と同じ形のボタンに並べると閉じるだけに見えるので、控えめな文字のリンクにして下に離す */
.ranking-dialog__leave {
  padding: var(--space-4);
  border: none;
  background: transparent;
  color: var(--fg-dim);
  font-size: var(--text-sm);
  text-decoration: underline;
  text-underline-offset: 3px;
}

.ranking-dialog__form {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-5);
  width: 100%;
}

/* iOS は 16px 未満の入力欄にフォーカスすると画面を拡大する。body の user-select: none も打ち消して文字を選べるようにする */
.ranking-dialog__name {
  box-sizing: border-box;
  width: 100%;
  padding: var(--space-5) var(--space-6);
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--bg);
  color: var(--fg);
  font-size: var(--text-lg);
  -webkit-user-select: text;
  user-select: text;
  touch-action: auto;
}

/* 解禁は押せないので、ボタンと見分けられるよう丸いバッジにせず、種類の列と名前の列に揃えた一覧にする */
.result__unlocks {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.result__compare:not(:empty) ~ .result__unlocks,
.result__streak:not(:empty) ~ .result__unlocks {
  padding-top: var(--space-4);
  border-top: 1px solid var(--line);
}

.result__unlocks[hidden] {
  display: none;
}

.result__skins {
  align-self: center;
  border-color: var(--gold);
  color: var(--gold);
  font-weight: 800;
}

.result__skins[hidden] {
  display: none;
}

.unlock {
  display: flex;
  align-items: baseline;
  gap: var(--space-4);
  color: var(--gold);
  font-size: var(--text-md);
  font-weight: 800;
  line-height: 1.4;
}

/* 行は枠いっぱいの幅なので、バッジのころの rank-in（3 倍から縮む）を掛けると枠からはみ出す。拡大せずに下から弾ませる */
.result__progress.is-revealed .unlock {
  animation: unlock-in 0.5s cubic-bezier(0.2, 1.8, 0.4, 1) backwards;
}

.unlock--bonus {
  color: var(--joke);
}

/* 種類の列は、いちばん長い「着せ替え解禁」の 6 字ぶんの幅にそろえる */
.unlock::before {
  content: '実績';
  flex-shrink: 0;
  min-width: 6em;
  color: var(--fg-dim);
  font-size: var(--text-xs);
  font-weight: 700;
}

.unlock--mission::before {
  content: 'ミッション';
}

.unlock--skin::before {
  content: '着せ替え解禁';
}

.skin-swatch {
  display: inline-block;
  width: 10px;
  height: 10px;
  margin-right: var(--space-3);
  border-radius: 3px;
  box-shadow: 0 0 0 1px var(--line);
  vertical-align: -1px;
}

.mistakes {
  width: 100%;
  padding: var(--space-5) var(--space-6);
  border-radius: 12px;
  background: var(--kb-bg);
  text-align: left;
}

.mistakes[hidden],
.mistakes__more[hidden] {
  display: none;
}

.mistakes__title {
  margin: 0 0 var(--space-3);
  color: var(--fg-dim);
  font-size: var(--text-xs);
}

.mistakes__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-2);
  margin: 0;
  padding: 0;
  list-style: none;
}

.mistake {
  display: flex;
  align-items: baseline;
  gap: var(--space-4);
  min-width: 0;
}

.mistake__reading {
  flex-shrink: 0;
  font-size: var(--text-xl);
  font-weight: 800;
}

.mistake__miss {
  color: var(--hot);
  text-decoration: underline 2px;
  text-underline-offset: 4px;
}

.mistake__display {
  overflow: hidden;
  color: var(--fg-dim);
  font-size: var(--text-sm);
  text-overflow: ellipsis;
  white-space: nowrap;
}

.mistakes__more summary {
  margin-top: var(--space-3);
  color: var(--fg-dim);
  font-size: var(--text-sm);
  cursor: pointer;
}

.mistakes__more .mistakes__list {
  margin-top: var(--space-2);
}

.mistakes__practice {
  margin-top: var(--space-5);
}

.result__more {
  width: 100%;
}

.result__more-label {
  width: fit-content;
  margin: 0 auto;
  padding: var(--space-5) var(--space-8);
  border: 1px solid var(--line);
  border-radius: 999px;
  background: var(--kb-bg);
  color: var(--fg-dim);
  font-size: var(--text-md);
  list-style: none;
  cursor: pointer;
}

.result__more-label::-webkit-details-marker {
  display: none;
}

/* 開閉は summary が読み上げるので、矢印は読ませない（代替テキストの書き方を知らないブラウザは前の宣言を使う） */
.result__more-label::after {
  content: ' ▾';
  content: ' ▾' / '';
}

.result__more[open] > .result__more-label {
  margin-bottom: var(--space-6);
}

.result__more[open] > .result__more-label::after {
  content: ' ▴';
  content: ' ▴' / '';
}

.result__more > .mistakes {
  margin-top: var(--space-6);
}

/* ---------- records ---------- */

.screen--scroll {
  overflow-y: auto;
  overscroll-behavior: contain;
  touch-action: pan-y pinch-zoom;
  -webkit-overflow-scrolling: touch;
}

@media (max-height: 700px) {
  .screen--center {
    gap: var(--space-5);
  }

  /* 375×667 で、タイトルと先頭のコースのボタンがスクロールなしに収まるようにする */
  .start-scroll {
    padding-top: var(--space-2);
  }

  .start-scroll,
  .start-panel {
    gap: var(--space-5);
  }

  .title {
    font-size: clamp(34px, 10.5vw, 44px);
  }
}

.records-tiles {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-4);
  margin: var(--space-7) 0 0;
}

.records-tile {
  display: flex;
  flex-direction: column-reverse;
  padding: var(--space-5) var(--space-2);
  border-radius: 12px;
  background: var(--kb-bg);
  text-align: center;
}

/* 3 列で 1 つだけ余った行は、空きを残さず横いっぱいに広げる */
.records-tile:last-child:nth-child(3n + 1) {
  grid-column: 1 / -1;
}

.records-tile__label {
  color: var(--fg-dim);
  font-size: var(--text-xs);
}

.records-tile__value {
  margin: 0 0 var(--space-1);
  font-family: var(--font-display);
  font-size: var(--text-xl);
}

.records-heading {
  margin: var(--space-7) 0 var(--space-4);
  color: var(--fg-dim);
  font-size: var(--text-md);
}

.records-tabs {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-3);
  margin-bottom: var(--space-4);
}

.records-tab {
  padding: var(--space-4) var(--space-5);
  border: 1px solid var(--line);
  border-radius: 999px;
  background: transparent;
  color: var(--fg-dim);
  font-size: var(--text-sm);
}

.records-tab[aria-selected='true'] {
  border-color: var(--accent);
  color: var(--accent);
}

.records-stats {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-6);
  margin: 0 0 var(--space-4);
  font-size: var(--text-md);
  font-weight: 800;
}

.records-note {
  margin: 0 0 var(--space-4);
  color: var(--fg-dim);
  font-size: var(--text-sm);
}

.records-chart {
  display: flex;
  align-items: flex-end;
  gap: var(--space-2);
  height: 100px;
  padding: var(--space-4);
  border-radius: 12px;
  background: var(--kb-bg);
}

/* 記録が少ないうちに棒が横に広がらないよう、常に20本分の幅で左から詰めて描く。
   押す範囲は棒の高さによらず1列ぶんにして、細い棒でも指で押せるようにする */
.records-bar {
  display: flex;
  flex: 0 0 calc((100% - 19 * var(--space-2)) / 20);
  align-items: flex-end;
  height: 100%;
  padding: 0;
  border: 0;
  background: transparent;
}

.records-bar__fill {
  width: 100%;
  border-radius: 3px 3px 0 0;
  background: var(--hot);
}

.records-bar--easy .records-bar__fill {
  background: #7dff9b;
}

.records-bar--hard .records-bar__fill {
  background: #9b5cff;
}

.records-bar--daily .records-bar__fill {
  background: var(--gold);
}

.records-bar.is-selected .records-bar__fill {
  box-shadow: 0 0 0 2px var(--fg);
}

.records-detail {
  margin-top: var(--space-4);
  padding: var(--space-4) var(--space-6);
  border-radius: 12px;
  background: var(--kb-bg);
  font-size: var(--text-md);
}

.records-detail__line,
.records-detail__hint {
  margin: var(--space-1) 0;
}

.records-detail__hint {
  color: var(--fg-dim);
  font-size: var(--text-sm);
}

.backup__note {
  margin: 0 0 var(--space-4);
  color: var(--fg-dim);
  font-size: var(--text-sm);
  line-height: 1.5;
}

/* body の user-select: none を打ち消し、貼り付けと長押しでの選択をできるようにする */
.backup__text {
  box-sizing: border-box;
  width: 100%;
  padding: var(--space-4);
  border: 1px solid var(--line);
  border-radius: 12px;
  background: var(--kb-bg);
  color: var(--fg);
  font-family: ui-monospace, monospace;
  font-size: var(--text-lg);
  word-break: break-all;
  resize: vertical;
  -webkit-user-select: text;
  user-select: text;
  -webkit-touch-callout: default;
  touch-action: auto;
}

.backup__actions {
  display: flex;
  gap: var(--space-5);
  margin-top: var(--space-4);
}

.backup__status {
  min-height: 1.4em;
  margin: var(--space-4) 0 0;
  color: var(--gold);
  font-size: var(--text-md);
  font-weight: 800;
}

.records-sudden {
  margin: 0;
  font-weight: 800;
  color: var(--fg);
}

.records-empty {
  margin: auto;
  color: var(--fg-dim);
  font-size: var(--text-md);
}

.weak-chars {
  display: flex;
  flex-direction: column;
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.weak-char {
  display: flex;
  align-items: baseline;
  gap: var(--space-6);
  padding: var(--space-4) var(--space-6);
  border-radius: 12px;
  background: var(--kb-bg);
}

.weak-char__ch {
  min-width: 1.5em;
  font-family: var(--font-display);
  font-size: 24px;
  color: var(--hot);
}

.weak-char__count {
  font-weight: 800;
}

.weak-char__rate {
  color: var(--fg-dim);
  font-size: var(--text-md);
}

.weak-char__typed {
  margin-left: auto;
  color: var(--fg-dim);
  font-size: var(--text-md);
}

.thumb-map__legend {
  display: flex;
  flex-wrap: wrap;
  gap: var(--space-2) var(--space-6);
  margin: 0 0 var(--space-4);
  font-size: var(--text-md);
}

.thumb-map__count {
  display: inline-flex;
  align-items: center;
  gap: var(--space-2);
}

.thumb-map__swatch {
  width: 12px;
  height: 12px;
  border-radius: 3px;
  background: var(--tier-bg);
}

.thumb-map {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: var(--space-3);
}

.thumb-key {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: repeat(3, 1fr);
  gap: var(--space-1);
  padding: var(--space-2);
  border-radius: 12px;
  background: var(--kb-bg);
}

.thumb-key.is-mod {
  display: flex;
  align-items: center;
  justify-content: center;
  color: var(--fg-dim);
  font-size: var(--text-md);
}

/* 升は配列と同じ十字に置く。字の並びは DIR_NAMES（中央、左、上、右、下） */
.thumb-cell--center { grid-area: 2 / 2; }
.thumb-cell--left { grid-area: 2 / 1; }
.thumb-cell--up { grid-area: 1 / 2; }
.thumb-cell--right { grid-area: 2 / 3; }
.thumb-cell--down { grid-area: 3 / 2; }

.thumb-cell {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  min-height: 26px;
  border-radius: 6px;
  background: var(--tier-bg);
  color: var(--tier-fg);
  font-size: var(--text-md);
  font-weight: 800;
  line-height: 1;
}

.thumb-cell.is-blank {
  background: none;
}

.tier-none {
  --tier-bg: var(--key);
  /* --fg-dim は --key の上で 4.5:1 に届かないので、升の字だけ少し明るくする */
  --tier-fg: #a0a0c6;
}

.tier-bronze {
  --tier-bg: #c9824a;
  --tier-fg: #0b0b1a;
}

.tier-silver {
  --tier-bg: #c8d2e6;
  --tier-fg: #0b0b1a;
}

.tier-gold {
  --tier-bg: var(--gold);
  --tier-fg: #0b0b1a;
}

.thumb-map__slow-mark {
  color: var(--hot);
}

.thumb-cell.is-slow::after {
  content: '';
  position: absolute;
  top: 2px;
  right: 2px;
  width: 8px;
  height: 8px;
  border-radius: 50%;
  background: var(--hot);
  /* 銅の升とは色が近いので、暗い縁取りで升から浮かせる */
  box-shadow: 0 0 0 2px var(--bg);
}

.flick-rates {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.flick-rate {
  display: flex;
  flex-direction: column;
  padding: var(--space-5) var(--space-1);
  border-radius: 12px;
  background: var(--kb-bg);
  text-align: center;
}

.flick-rate.is-empty {
  opacity: 0.5;
}

.flick-rate__value {
  font-weight: 800;
}

.flick-rate__label {
  color: var(--fg-dim);
  font-size: var(--text-xs);
}

.flick-rates__note {
  margin: var(--space-4) 0 0;
  color: var(--hot);
  font-size: var(--text-md);
}

.achievements {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-4);
  margin: 0;
  padding: 0;
  list-style: none;
}

.achievement {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-5);
  border-radius: 12px;
  background: var(--kb-bg);
  opacity: 0.45;
}

.achievement.is-unlocked {
  opacity: 1;
  box-shadow: inset 0 0 0 1px var(--gold);
}

.achievement__title {
  font-weight: 800;
  font-size: var(--text-md);
}

.achievement.is-unlocked .achievement__title {
  color: var(--gold);
}

.achievement--bonus.is-unlocked {
  box-shadow: inset 0 0 0 1px var(--joke);
}

.achievement--bonus.is-unlocked .achievement__title {
  color: var(--joke);
}

.achievement__desc {
  color: var(--fg-dim);
  font-size: var(--text-xs);
}

.rank-book__hint {
  margin: var(--space-5) 0 var(--space-4);
  color: var(--fg-dim);
  font-size: var(--text-sm);
}

.rank-book {
  display: grid;
  grid-template-columns: repeat(2, 1fr);
  gap: var(--space-3);
  margin: 0;
  padding: 0;
  list-style: none;
}

.rank-book__row {
  display: flex;
  min-height: 40px;
  border-radius: 12px;
  background: var(--kb-bg);
  color: var(--fg-dim);
  font-size: var(--text-md);
}

.rank-book__row:not(.is-reached) {
  align-items: center;
  padding: 0 var(--space-5);
}

.rank-book__button {
  display: flex;
  flex: 1;
  flex-direction: column;
  justify-content: center;
  gap: var(--space-1);
  padding: var(--space-3) var(--space-5);
  border: 0;
  border-radius: inherit;
  background: none;
  color: var(--fg);
  font: inherit;
  text-align: left;
  cursor: pointer;
}

.rank-book__row.is-selected {
  box-shadow: inset 0 0 0 1px var(--gold);
}

.rank-book__row.is-selected .rank-book__label {
  color: var(--gold);
}

.skin-book__locked {
  display: flex;
  flex-direction: column;
  gap: var(--space-1);
  padding: var(--space-3) 0;
}

.skin-book__unlock {
  font-size: var(--text-xs);
}

/* ごほうびタブの着せ替え（skins-view.js）。段の gap を見出しの余白が受け持つので、最初の見出しの上は空けない */
.reward-skins__list > .skin-book__heading:first-child {
  margin-top: 0;
}

.reward-skins__hint {
  margin: 0;
  color: var(--fg-dim);
  font-size: var(--text-sm);
}

/* 行の地の色は段の地（--kb-bg）と同じなので、少し明るくして枠を見せる */
.reward-skins__list .rank-book__row {
  background: rgb(255 255 255 / 0.06);
}

.reward-skins__try {
  align-self: center;
}

.reward-skins__preview {
  display: block;
  width: 100%;
  height: 64px;
  border-radius: 12px;
  background: rgb(0 0 0 / 0.25);
}

.skin-book__heading {
  margin: var(--space-6) 0 var(--space-3);
  color: var(--fg-dim);
  font-size: var(--text-sm);
  font-weight: 800;
}

.rank-book__mark {
  color: var(--gold);
  font-size: var(--text-xs);
}

/* 進み具合のある実績は目標として見えるよう、取得済み以外の薄さを少し戻す */
.achievement.has-progress {
  opacity: 0.75;
}

.achievement__progress {
  color: var(--fg);
  font-size: var(--text-sm);
  font-weight: 800;
  font-variant-numeric: tabular-nums;
}

/* ---------- HUD ---------- */

.hud {
  padding: 10px 16px 0;
}

.hud__top {
  display: flex;
  align-items: center;
  gap: 8px;
}

.hud__top .timebar {
  flex: 1;
}

/* iOS は ⏸ を絵文字の絵で描いて color が効かないので、HTML で U+FE0E を付けて字として描かせる。
   押しやすい大きさにしつつ、上下は負の余白で時間バーの高さに収め、お題の段を狭めない */
.hud__pause {
  flex: none;
  width: 32px;
  height: 32px;
  margin: -9px -8px -9px 0;
  padding: 0;
  border: 0;
  background: none;
  color: var(--fg);
  font-size: 20px;
  line-height: 1;
}

.hud__pause:disabled {
  opacity: 0.3;
  cursor: default;
}

/* 始まる前と止めているあいだはお題を隠し、数えながら先読みできないようにする。数え終えたら戻す */
#screen-game.is-paused .word-display,
#screen-game.is-paused .word-reading,
#screen-game.is-paused .word-count {
  visibility: hidden;
}

.timebar {
  position: relative;
  height: 14px;
  overflow: hidden;
  border-radius: 999px;
  background: var(--kb-bg);
}

/* 読んでいて残り時間が止まっているあいだの、止めておける残り。残り時間の層の上に斜線で重ねて同じ向きに縮め、
   消えたら時間が減り始めることを見せる。色を抜いて薄くするだけでは、止まっているのか使えないのかが伝わらなかった */
.timebar__read {
  position: absolute;
  inset: 0;
  background: repeating-linear-gradient(-45deg, rgb(255 255 255 / 0.6) 0 3px, transparent 3px 7px);
  clip-path: inset(0 100% 0 0);
}

.timebar.is-reading .timebar__num::before {
  content: '⏸︎ ';
}

/* 通常分は単色にして、上に重ねるボーナス分のシアンと見分けやすくする */
.timebar__fill {
  height: 100%;
  background: var(--gold);
  transform-origin: left center;
}

.timebar__extra {
  position: absolute;
  inset: 0;
  background: var(--time-extra);
  transform: scaleX(0);
  transform-origin: left center;
}

/* ボーナスで延びた秒数の区間。30 秒の尺度の層にだけ重ね、延長分の層はその色のまま上に描く */
.timebar__bonus {
  position: absolute;
  inset: 0;
  background: var(--time-bonus);
  transform: scaleX(0);
  transform-origin: left center;
}

.timebar__num {
  position: absolute;
  top: 50%;
  right: 8px;
  transform: translateY(-50%);
  font-size: 11px;
  font-weight: 800;
  color: var(--bg);
  mix-blend-mode: difference;
  filter: invert(1);
}

.timebar.is-low .timebar__fill {
  background: var(--hot);
  animation: blink 0.4s steps(2) infinite;
}

/* 開始からの合計の上限に届き、もう延びない。縁を残して、+1 秒の出ない理由をバーで見せる */
.timebar.is-capped {
  box-shadow: 0 0 0 2px var(--fg-dim);
}

.timebar.is-maxed {
  animation: timebar-max 0.6s ease-out;
}

/* ノーミスを続けるとボーナス分が残り時間のほとんどを占め、上に重ねた色で残りわずかの赤い点滅が隠れる */
.timebar.is-low .timebar__bonus {
  display: none;
}

.timebar__num.is-bump {
  animation: time-bump 0.35s ease-out;
}

.hud__row {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  margin-top: 6px;
}

.hud__score {
  font-family: var(--font-display);
  font-size: 30px;
  white-space: nowrap;
}

.hud__score-unit {
  margin-left: 2px;
  font-size: 13px;
}

/* ライバルとの差。点数と倍率のあいだはお題へ戻る視線の通り道なので、右上の語の数（.word-count）と対にステージの左上へ置く。
   幅は右上の語の数（3 桁で約 60px）に届く手前までにする。抜いたときの弾みは左端を軸にして、画面の左へはみ出さない */
.hud__ghost {
  position: absolute;
  top: 26px;
  left: 16px;
  display: flex;
  max-width: calc(100% - 112px);
  font-size: 13px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--fg-dim);
  white-space: nowrap;
  transform-origin: left center;
  pointer-events: none;
}

.hud__ghost[hidden] {
  display: none;
}

.hud__ghost-name {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
}

.hud__ghost-diff {
  flex: none;
  margin-left: 0.3em;
}

.hud__ghost.is-ahead {
  color: var(--accent);
}

.hud__ghost.is-behind {
  color: var(--hot);
}

.hud__ghost.is-overtake {
  animation: ghost-overtake 0.45s ease-out;
}

/* 次の 1 回の目標。点数の行と同じ左端に置き、右の「あと N」の行（絶対配置）とは重ならない幅の文だけにする */
.hud__goal {
  margin-top: 4px;
  font-size: 12px;
  font-weight: 800;
  font-variant-numeric: tabular-nums;
  color: var(--fg-dim);
}

.hud__goal.is-reached {
  color: var(--gold);
}

.hud__goal.is-pop {
  transform-origin: left center;
  animation: pop 0.25s ease-out;
}

.hud__mult {
  font-family: var(--font-display);
  font-size: 22px;
  color: var(--gold);
}

.hud__level {
  position: relative;
  display: flex;
  flex-direction: column;
  align-items: flex-end;
  gap: 4px;
}

.level-gauge {
  width: 64px;
  height: 4px;
  overflow: hidden;
  border-radius: 999px;
  background: var(--kb-bg);
}

.level-gauge__fill {
  height: 100%;
  background: var(--gold);
  transform: scaleX(0);
  transform-origin: left center;
  transition: transform 0.12s ease-out;
}

.is-fever .level-gauge__fill {
  background: var(--climb-color, var(--hot));
}

/* FEVER の盾。倍率の左に絶対配置で出し、出入りで倍率の位置を動かさない */
.hud__shield {
  position: absolute;
  top: 0;
  right: 100%;
  margin-right: 6px;
  font-size: 20px;
  line-height: 1.3;
}

.hud__shield.is-pop {
  animation: pop 0.25s ease-out;
}

/* 一発勝負は点数ではなく語の数を競うので、倍率は出さない。並びが動かないよう場所は残す */
.is-sudden .hud__mult {
  visibility: hidden;
}

/* 上の段ほど光彩を広げる */
.is-fever .hud__mult {
  color: var(--climb-color, var(--hot));
  text-shadow: 0 0 calc(6px * var(--climb-power, 0)) var(--climb-color, var(--hot));
  animation: blink 0.3s steps(2) infinite;
}

/* 次の倍率までの打数をゲージの下に出す。FEVER の直前はゲージを FEVER と同じ色にして点滅させる。
   行は絶対配置にして、出入りで HUD の高さを動かさない */
.hud__level.is-notice .level-gauge__fill {
  background: var(--hot);
  animation: blink 0.3s steps(2) infinite;
}

.hud__notice {
  position: absolute;
  top: 100%;
  right: 0;
  margin-top: 2px;
  white-space: nowrap;
  font-size: 11px;
  font-weight: 800;
  color: var(--fg-dim);
  transform-origin: right center;
}

.hud__notice.is-urgent,
.is-fever .hud__notice {
  color: var(--climb-color, var(--hot));
}

.hud__notice.is-pop {
  animation: pop 0.25s ease-out;
}

/* FEVER から落ちたミス。FEVER の色から、ふつうの倍率の色へ 1 回だけ落とす */
.hud__mult.is-fever-end {
  animation: fever-end 0.8s ease-out;
}

/* 倍率が上がった打鍵。右端を軸にふくらませ、画面の右へはみ出さないようにする */
.hud__mult.is-level-up {
  transform-origin: right center;
  animation: level-up 0.35s ease-out;
}

/* FEVER 中に上がったときは、点滅を止めないよう並べて付ける */
.is-fever .hud__mult.is-level-up {
  animation: level-up 0.35s ease-out, blink 0.3s steps(2) infinite;
}

/* ---------- tutorial ---------- */

.tutorial {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: 8px;
  padding: 16px 16px 0;
  text-align: center;
}

.tutorial[hidden],
.hud[hidden] {
  display: none;
}

.tutorial__label {
  margin: 0;
  color: var(--fg-dim);
  font-size: 12px;
  font-weight: 800;
  letter-spacing: 0.1em;
}

.tutorial__guide {
  margin: 0;
  min-height: 3em;
  color: var(--gold);
  font-size: 16px;
  font-weight: 800;
  line-height: 1.5;
}

/* ---------- stage ---------- */

.stage {
  position: relative;
  /* 脳汁タンクを z-index: -1 で .stage の中の最背面に置く */
  isolation: isolate;
  display: flex;
  flex: 1;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  gap: 8px;
  min-height: 0;
  padding: 0 16px;
}

/* 脳汁タンク（#172）。液面と線は transform だけで動かす */
.tank {
  position: absolute;
  inset: 0;
  z-index: -1;
  display: none;
  overflow: hidden;
  pointer-events: none;
}

.has-tank .tank {
  display: block;
}

.tank__level {
  position: absolute;
  inset: 0;
  opacity: var(--tank-opacity);
  transform: translateY(100%);
  transition: transform 0.15s ease-out;
}

/* はねる（is-splash）ときに液体ごと持ち上げても底に隙間が開かないよう、下へ余分に伸ばして .tank で切る */
.tank__liquid {
  position: absolute;
  inset: 0 0 -16px;
  background: var(--hot);
}

.tank__liquid.is-splash {
  animation: tank-splash 0.35s ease-out;
}

.is-fever .tank__liquid {
  background: linear-gradient(135deg, #ff3fa4, #ffd23f, #2ef2ff, #9b5cff, #ff3fa4);
  background-size: 400% 400%;
  animation: fever-flow 1.6s linear infinite;
}

.is-fever .tank__liquid.is-splash {
  animation: tank-splash 0.35s ease-out, fever-flow 1.6s linear infinite;
}

/* 液面の波。幅 2 倍の帯を横に流し、半分ずらしたところで継ぎ目なく巻き戻す */
.tank__wave {
  position: absolute;
  left: 0;
  bottom: 100%;
  width: 200%;
  height: 10px;
  background: inherit;
  -webkit-mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 80 10' preserveAspectRatio='none'%3E%3Cpath d='M0 10V5Q20 0 40 5T80 5V10Z'/%3E%3C/svg%3E") repeat-x 0 0 / 80px 100%;
  mask: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 80 10' preserveAspectRatio='none'%3E%3Cpath d='M0 10V5Q20 0 40 5T80 5V10Z'/%3E%3C/svg%3E") repeat-x 0 0 / 80px 100%;
  animation: tank-wave 1.8s linear infinite;
}

.tank__bubble {
  position: absolute;
  bottom: 0;
  left: calc(var(--x) * 100%);
  width: 8px;
  height: 8px;
  border: 2px solid var(--fg);
  border-radius: 50%;
  animation: tank-bubble var(--d) linear var(--delay) infinite;
}

.tank__bubble[hidden] {
  display: none;
}

.tank.is-full .tank__bubble {
  animation-duration: calc(var(--d) * 0.6);
}

/* 相手の線は液面の比べる先を示すだけで、お題より前に出ないよう細く薄くする。抜いた瞬間だけ光らせる */
.tank__mark {
  position: absolute;
  inset: 0;
  border-top: 1px dashed var(--fg);
  opacity: 0.3;
  transform: translateY(100%);
}

.tank__mark[hidden] {
  display: none;
}

.tank__mark.is-glow {
  animation: tank-glow 0.6s ease-out;
}

/* 液体を敷いても読めるよう、字の周りを暗くする */
.has-tank .word-display,
.has-tank .word-reading,
.has-tank .word-count,
.has-tank .hud__ghost,
.has-tank .combo {
  text-shadow: 0 0 6px var(--bg), 0 0 2px var(--bg);
}

/* 虹色の語は字の形に背景を切り抜いて透明な字にしているので、影を付けると影が字の上に透けて暗くなる */
.has-tank .word-display.is-special {
  text-shadow: none;
}

.word-display,
.word-reading {
  transition: filter 0.15s;
}

/* 横切る「FEVER」が奥を抜けるあいだ、お題と読みを暗い影で浮かせる（play-fx-view.js の guardWordFromSweep）。
   text-shadow は虹色の語（透明な字）の上に透けるので、字の形に沿う drop-shadow にする */
.stage.is-sweeping .word-display,
.stage.is-sweeping .word-reading {
  filter: drop-shadow(0 0 2px rgb(0 0 0 / 0.95)) drop-shadow(0 0 8px rgb(0 0 0 / 0.85));
}

.stage.is-sweeping .word-display.is-special {
  filter: drop-shadow(0 0 2px rgb(0 0 0 / 0.95)) drop-shadow(0 0 8px rgb(0 0 0 / 0.85)) drop-shadow(0 0 10px rgb(255 63 164 / 0.6));
}

/* 打ち切った語の数。読みの真下は語のボーナスの浮き文字が通るので、並びの外の右上に置く。
   top は、倍率の下から #hud の外へはみ出す「あと N 打」（.hud__notice）の下に来るように取る */
.word-count {
  position: absolute;
  top: 26px;
  right: 16px;
  color: var(--fg-dim);
  font-size: 16px;
  font-weight: 800;
  pointer-events: none;
}

.word-count .hud__score-unit {
  font-size: 11px;
}

.combo {
  display: flex;
  align-items: baseline;
  gap: 6px;
  min-height: 48px;
  color: var(--gold);
  font-family: var(--font-display);
}

.combo.is-empty {
  visibility: hidden;
}

.combo__num {
  font-size: 44px;
  line-height: 1;
}

.combo__label {
  font-size: 14px;
  letter-spacing: 0.15em;
}

.combo.is-pop {
  animation: pop 0.18s ease-out;
}

.is-fever .combo {
  color: var(--hot);
  text-shadow: 0 0 16px var(--hot);
}

.word-display {
  font-family: var(--font-display);
  font-size: clamp(34px, 11vw, 56px);
  line-height: 1.1;
  text-align: center;
}

.word-display.is-enter {
  animation: word-in 0.22s cubic-bezier(0.2, 1.6, 0.4, 1);
}

/* FEVER 中に割り込む特別な語。#fever-bg と同じ虹色を字に流す */
.word-display.is-special {
  background: linear-gradient(90deg, #ff3fa4, #ffd23f, #2ef2ff, #9b5cff, #ff3fa4);
  background-size: 400% 100%;
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
  filter: drop-shadow(0 0 10px rgb(255 63 164 / 0.6));
  animation: fever-flow 1.6s linear infinite;
}

.word-display.is-special.is-enter {
  animation: word-in 0.22s cubic-bezier(0.2, 1.6, 0.4, 1), fever-flow 1.6s linear infinite;
}

.word-reading {
  display: flex;
  flex-wrap: wrap;
  justify-content: center;
  gap: 2px;
  font-size: clamp(22px, 7vw, 32px);
  font-weight: 800;
}

.char {
  min-width: 1em;
  text-align: center;
  border-bottom: 3px solid transparent;
}

.char.is-done {
  color: var(--done);
  text-shadow: 0 0 10px var(--accent-glow);
}

.char.is-rest {
  color: var(--fg-dim);
  font-weight: 500;
}

.char.is-current {
  border-bottom-color: var(--accent);
}

.char.is-current.is-miss {
  animation: none;
  color: var(--hot);
  border-bottom-color: var(--hot);
}

.char.is-pending {
  color: var(--gold);
  border-bottom-color: var(--gold);
  animation: blink 0.35s steps(2) infinite;
}

/* 練習の「つ→っ」。点滅は今の字だけにし、矢印と変える先は薄く添えて、組ごと下線で 1 字ぶんに見せる。
   変える先まで小さくすると「o→O」の大文字が小文字と見分けられないので、小さくするのは矢印だけ */
.char.is-pair {
  display: inline-flex;
  align-items: baseline;
  padding: 0 2px;
  animation: none;
}

.char__from {
  animation: blink 0.35s steps(2) infinite;
}

.char__arrow,
.char__to {
  color: var(--fg-dim);
  font-weight: 500;
}

.char__arrow {
  margin: 0 2px;
  font-size: 0.6em;
}

.is-reduced-motion .char__from {
  animation: none;
}

.toast {
  position: absolute;
  top: 8%;
  left: 50%;
  opacity: 0;
  transform: translateX(-50%);
  white-space: nowrap;
  pointer-events: none;
  font-family: var(--font-display);
  font-size: 40px;
  background: linear-gradient(90deg, var(--gold), var(--hot));
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

.toast.is-show {
  animation: toast 0.9s ease-out;
}

/* 40px の大きな字では「拡大を戻してください」が画面に収まらず、0.9 秒では読めない */
.toast--notice {
  font-size: 20px;
}

.toast--notice.is-show {
  animation-duration: 2.4s;
}

/* left に中心の x を入れるので、幅の上限は x から画面の右端までしかない。
   「PERFECT +120」のような長い文が折り返して背が倍になり、ほかの表示に重なるのを防ぐ */
.float-text {
  position: absolute;
  transform: translate(-50%, -50%);
  white-space: nowrap;
  font-family: var(--font-display);
  font-size: 26px;
  color: var(--fg);
  text-shadow: 0 0 12px var(--accent-glow);
  animation: float-up 0.8s ease-out forwards;
}

/* ドパるのタブの ❤️ を押したときに飛ぶハート。ずらして飛ばすので、飛ぶ前は隠しておく */
.float-text--heart {
  font-size: 16px;
  color: var(--hot);
  text-shadow: 0 0 8px var(--hot);
  animation-fill-mode: both;
}

.float-text--heart-1 {
  font-size: 12px;
  animation-delay: 0.08s;
}

.float-text--heart-2 {
  font-size: 14px;
  animation-delay: 0.16s;
}

/* 語のボーナス。top は読みの行の下端で、float-up-short の縦の translate は箱の上端のずれ。
   読みの 24px 下から 4px 下まで上がって消え、拡大した瞬間も上端が読みに届かない */
.float-text--word {
  animation-name: float-up-short;
}

.float-text--perfect {
  color: var(--gold);
  text-shadow: 0 0 14px rgb(255 210 63 / 0.7);
}

.float-text--special {
  color: var(--hot);
  text-shadow: 0 0 14px rgb(255 63 164 / 0.8);
}

.float-text--time {
  font-size: 18px;
  color: var(--accent);
}

/* 上限で 1 秒も延びなかった語の MAX。+1 秒のシアンと分けて、光らせない白にする */
.float-text--blocked {
  color: var(--fg);
  text-shadow: none;
}

/* ミスで減った残り時間。+1 秒の青と分けて赤にする */
.float-text--penalty {
  font-size: 18px;
  color: rgb(255 72 96);
  text-shadow: 0 0 12px rgb(255 40 80 / 0.7);
}

/* ミスで押したキーの上に出す印。色を見なくても形でミスと分かるようにする */
.float-text--miss {
  font-size: 30px;
  color: var(--fg);
  text-shadow: 0 0 6px var(--hot), 0 0 14px var(--hot);
  animation: miss-mark 0.4s ease-out forwards;
}

.shatter {
  position: absolute;
  display: grid;
  transform: translate(-50%, -50%);
  font-family: var(--font-display);
  color: var(--gold);
  pointer-events: none;
  animation: shatter-life 0.5s linear forwards;
}

.is-fever .shatter {
  color: var(--hot);
}

.shatter__half {
  grid-area: 1 / 1;
  font-size: 44px;
  line-height: 1;
}

.shatter__half--left {
  clip-path: inset(0 50% 0 0);
  animation: shatter-left 0.45s cubic-bezier(0.5, 0, 1, 0.6) forwards;
}

.shatter__half--right {
  clip-path: inset(0 0 0 50%);
  animation: shatter-right 0.45s cubic-bezier(0.5, 0, 1, 0.6) forwards;
}

.shatter__label {
  position: absolute;
  top: 100%;
  left: 50%;
  white-space: nowrap;
  font-size: 16px;
  color: rgb(255 80 110);
  animation: shatter-label 0.5s ease-out forwards;
}

.sweep-text {
  position: absolute;
  left: 0;
  width: 100%;
  text-align: center;
  white-space: nowrap;
  font-family: var(--font-display);
  animation: sweep 0.7s cubic-bezier(0.2, 0.8, 0.8, 0.2) forwards;
}

/* 光彩の filter は字の span ではなく外の箱に付ける。background-clip: text と同じ要素に付けると、Chrome で切り抜きが外れて箱ごと塗られる */
.sweep-text--fever {
  font-size: 88px;
  font-style: italic;
  filter: drop-shadow(0 0 12px rgb(255 63 164 / 0.8));
}

.sweep-text--fever > span {
  background: linear-gradient(90deg, #ff3fa4, #ffd23f, #2ef2ff, #9b5cff);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

/* FEVER の先の段の名前。その段の色で流し、上の段ほど大きくする */
.sweep-text--tier {
  font-size: calc(88px + 8px * var(--climb-power, 0));
  filter: drop-shadow(0 0 calc(12px + 4px * var(--climb-power, 0)) var(--climb-color, #ff3fa4));
}

.sweep-text--tier > span {
  background-image: var(--climb-bg, linear-gradient(90deg, #ff3fa4, #ffd23f, #2ef2ff, #9b5cff));
}

.float-text--overtake {
  font-size: 22px;
  color: var(--gold);
  text-shadow: 0 0 14px rgb(255 210 63 / 0.7);
}

.countdown {
  position: absolute;
  inset: 0;
  z-index: 30;
  display: grid;
  place-items: center;
  font-family: var(--font-display);
  font-size: 120px;
  color: var(--gold);
  text-shadow: 0 0 30px var(--hot);
  pointer-events: none;
}

.countdown[hidden] {
  display: none;
}

.countdown.is-zoom {
  animation: zoom var(--count-step, 0.45s) ease-out;
}

#app.is-shake {
  animation: shake 0.25s linear;
}

/* ---------- keyboard ---------- */

.keyboard {
  display: grid;
  grid-template-columns: repeat(5, 1fr);
  /* 標準の高さは iOS 標準のフリックキーボードに合わせてある。大きさは設定の keyboardSize で変わる */
  grid-template-rows: repeat(4, var(--key-h));
  gap: 8px 7px;
  /* #app の下の余白ぶん引き下げ、背景を画面の下端まで届かせる。
     ホームバーがあるときだけ、iOS 標準で地球儀とマイクが並ぶ 30px を足す（min() で 0 か 30px になる） */
  margin-bottom: calc(-1 * env(safe-area-inset-bottom));
  padding: 8px var(--kb-pad-right) calc(8px + env(safe-area-inset-bottom) + min(30px, env(safe-area-inset-bottom) * 100)) var(--kb-pad-left);
  background: var(--kb-bg);
  touch-action: none;
}

/* 大きさは行の高さだけで変える。transform: scale() だと吹き出しと指の位置の対応とフリックのしきい値の実寸が変わる */
body[data-keyboard-size='small'] {
  --key-h: 40px;
  --key-hint-shift: 8px;
}

body[data-keyboard-size='large'] {
  --key-h: 52px;
}

/* 片手寄せは幅と背景を変えず、反対側の余白を増やして格子だけを寄せる。幅を狭めると背景が片側で切れ、下の safe-area の帯と合わない */
body[data-keyboard-side='left'] {
  --kb-pad-right: calc(8px + 18%);
}

body[data-keyboard-side='right'] {
  --kb-pad-left: calc(8px + 18%);
}

/* 縦が短い端末で大にすると、キーのぶん舞台が低くなり、中央に寄せた中身の上端と上から出る節目のトーストが重なる。
   コンボの数字と間を詰め、トーストを上げて重なりを減らす */
@media (max-height: 700px) {
  body[data-keyboard-size='large'] .stage {
    gap: 4px;
  }

  body[data-keyboard-size='large'] .combo {
    min-height: 40px;
  }

  body[data-keyboard-size='large'] .combo__num {
    font-size: 36px;
  }

  body[data-keyboard-size='large'] .toast {
    top: 2%;
  }
}

/* iOS のホーム画面アプリはページを 100dvh までしか描かず、それは画面の高さ（100lvh）よりステータスバーのぶん短い。
   キーを iOS 標準と同じ高さに置くため、描かれない差のぶん下の余白を減らす。差がなくなれば通常の余白に戻る */
@media (display-mode: standalone), (display-mode: fullscreen) {
  .keyboard {
    padding-bottom: max(8px, calc(8px + env(safe-area-inset-bottom) + min(30px, env(safe-area-inset-bottom) * 100) - (100lvh - 100dvh)));
  }
}

/* 着せ替えのキーボードの色（skins.js の keys-*）。字の --fg とヒントの --accent の枠がどの色でも浮くよう、暗い地にとどめる。
   記録画面などほかの --key の使い道は変えないよう、キーボードの中だけで差し替える */
body[data-key-skin='keys-forest'] .keyboard {
  --key: #1f3d33;
  --key-pressed: #2f5a4b;
  --key-side: #17302a;
  --key-shadow: #08140f;
}

body[data-key-skin='keys-ink'] .keyboard {
  --key: #2e2e33;
  --key-pressed: #45454c;
  --key-side: #232327;
  --key-shadow: #0c0c0e;
}

body[data-key-skin='keys-grape'] .keyboard {
  --key: #3b2350;
  --key-pressed: #553372;
  --key-side: #2c1a3c;
  --key-shadow: #120a18;
}

body[data-key-skin='keys-shu'] .keyboard {
  --key: #4a2320;
  --key-pressed: #6a332e;
  --key-side: #381a18;
  --key-shadow: #170a09;
}

body[data-key-skin='keys-ai'] .keyboard {
  --key: #1d2a4a;
  --key-pressed: #2c3e6a;
  --key-side: #151f38;
  --key-shadow: #070b16;
}

body[data-key-skin='keys-sakuranezu'] .keyboard {
  --key: #3d2f36;
  --key-pressed: #57444e;
  --key-side: #2e2329;
  --key-shadow: #120d10;
}

/* 大吉でしか当たらない金茶。金に寄せると字の --fg が沈むので、明るさは朱と同じくらいの暗い地にとどめる */
body[data-key-skin='keys-kincha'] .keyboard {
  --key: #4a3b14;
  --key-pressed: #6a5520;
  --key-side: #382c0f;
  --key-shadow: #171205;
}

/* 透けたアクリルの部品（水晶、ソーダ、ラムネ）。キーの地を半透明にし、キーボードの背面に敷いた模様がキー越しに透けて見えるようにする。
   --key は透けた地を背面に重ねたときの色で、吹き出しの枠と図鑑の色見本に使う。地と縁の色は部品ごとに --acrylic-* で差し替える。
   backdrop-filter のぼかしは、20 個のキーに掛けると古い iPhone で押した見た目が遅れるので使わない */
body[data-key-skin='keys-suisho'] .keyboard {
  --key: #22304a;
  --key-pressed: #34507a;
  --key-side: #1a2438;
  --key-shadow: #070b16;
  --acrylic-face: linear-gradient(to bottom, rgb(255 255 255 / 0.16), rgb(255 255 255 / 0.04) 50%, rgb(160 210 255 / 0.07));
  --acrylic-side: linear-gradient(to bottom, rgb(255 255 255 / 0.08), rgb(160 210 255 / 0.03));
  --acrylic-pressed: linear-gradient(to bottom, rgb(200 230 255 / 0.3), rgb(160 210 255 / 0.14));
  --acrylic-edge: rgb(190 225 255 / 0.4);
  --acrylic-shine: rgb(255 255 255 / 0.5);
  --acrylic-pressed-edge: rgb(210 235 255 / 0.8);
  --acrylic-glow: rgb(160 210 255 / 0.45);
  background:
    repeating-linear-gradient(60deg, rgb(140 200 255 / 0.08) 0 1px, transparent 1px 22px),
    repeating-linear-gradient(-60deg, rgb(140 200 255 / 0.08) 0 1px, transparent 1px 22px),
    radial-gradient(ellipse at 50% 0%, rgb(120 180 255 / 0.16), transparent 70%),
    var(--kb-bg);
}

/* ソーダとラムネは、キーボードの背面に部品ごとの模様（--acrylic-pattern）を敷き、色の付いたキー越しに透けて見せる。
   模様は白の薄い線の SVG で、タイルの端で線がつながるように描く。部品ごとの色はその上に重ねた --acrylic-tint で付ける */
:is(body[data-key-skin='keys-soda'], body[data-key-skin='keys-ramune']) .keyboard {
  background:
    var(--acrylic-tint),
    var(--acrylic-pattern),
    var(--kb-bg);
}

/* ランク S5 で解禁するソーダ。色の濃い青のアクリルで、背面の模様は大きさの違う泡。字の --fg が沈まないよう、地の濃さは透けた青が背面の暗さに負ける程度にとどめる */
body[data-key-skin='keys-soda'] .keyboard {
  --key: #1e3a90;
  --key-pressed: #2c54bc;
  --key-side: #16285e;
  --key-shadow: #040a26;
  --acrylic-face: linear-gradient(to bottom, rgb(140 185 255 / 0.5), rgb(40 100 255 / 0.3) 35%, rgb(30 80 255 / 0.26) 70%, rgb(20 60 235 / 0.4));
  --acrylic-side: linear-gradient(to bottom, rgb(110 160 255 / 0.28), rgb(30 80 230 / 0.2));
  --acrylic-pressed: linear-gradient(to bottom, rgb(150 195 255 / 0.6), rgb(60 120 255 / 0.45));
  --acrylic-edge: rgb(150 195 255 / 0.75);
  --acrylic-shine: rgb(235 243 255 / 0.9);
  --acrylic-pressed-edge: rgb(190 215 255 / 0.9);
  --acrylic-glow: rgb(80 140 255 / 0.55);
  --acrylic-pattern: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='96' height='120' fill='none' stroke='white' stroke-opacity='.22' stroke-width='1.5'%3E%3Ccircle cx='14' cy='18' r='7'/%3E%3Ccircle cx='58' cy='10' r='3'/%3E%3Ccircle cx='76' cy='40' r='10'/%3E%3Ccircle cx='30' cy='56' r='4'/%3E%3Ccircle cx='8' cy='92' r='5'/%3E%3Ccircle cx='50' cy='86' r='12'/%3E%3Ccircle cx='86' cy='104' r='3'/%3E%3Ccircle cx='38' cy='112' r='2'/%3E%3Cpath d='M71 34a6 6 0 0 1 5-3M45 79a8 8 0 0 1 6-4M10 14a4 4 0 0 1 3-2' stroke-opacity='.4'/%3E%3C/svg%3E") 0 0 / 96px 120px;
  --acrylic-tint:
    radial-gradient(ellipse at 30% 0%, rgb(60 120 255 / 0.3), transparent 60%),
    radial-gradient(ellipse at 80% 100%, rgb(30 80 255 / 0.22), transparent 60%);
}

/* ランク S10 で解禁するラムネ。水色のアクリルで、背面の模様は瓶のガラスのような波。ヒントの --accent（シアン）と紛れないよう、緑に寄せた水色にする */
body[data-key-skin='keys-ramune'] .keyboard {
  --key: #23595c;
  --key-pressed: #2f7a78;
  --key-side: #173a3c;
  --key-shadow: #041615;
  --acrylic-face: linear-gradient(to bottom, rgb(150 255 235 / 0.42), rgb(60 220 200 / 0.24) 35%, rgb(50 215 200 / 0.2) 70%, rgb(25 180 175 / 0.34));
  --acrylic-side: linear-gradient(to bottom, rgb(120 240 220 / 0.2), rgb(40 190 175 / 0.15));
  --acrylic-pressed: linear-gradient(to bottom, rgb(170 255 235 / 0.5), rgb(80 230 200 / 0.36));
  --acrylic-edge: rgb(170 255 235 / 0.7);
  --acrylic-shine: rgb(240 255 252 / 0.9);
  --acrylic-pressed-edge: rgb(200 255 240 / 0.9);
  --acrylic-glow: rgb(100 240 205 / 0.5);
  --acrylic-pattern: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='80' height='40' fill='none' stroke='white' stroke-opacity='.18' stroke-width='1.5'%3E%3Cpath d='M0 10Q20 4 40 10T80 10M-20 30Q0 24 20 30T60 30T100 30'/%3E%3C/svg%3E") 0 0 / 80px 40px;
  --acrylic-tint:
    radial-gradient(ellipse at 50% 0%, rgb(80 230 200 / 0.24), transparent 65%),
    radial-gradient(ellipse at 15% 100%, rgb(40 200 180 / 0.16), transparent 55%);
}

/* 下の規則はどれも .key の既定（.key--side、.is-pressed、.is-hint、.key--spacer）より強いので、その状態ごとに書き直す */
:is(body[data-key-skin='keys-suisho'], body[data-key-skin='keys-soda'], body[data-key-skin='keys-ramune']) .key {
  background: var(--acrylic-face);
  box-shadow: inset 0 0 0 1px var(--acrylic-edge), inset 0 1px 0 var(--acrylic-shine), 0 3px 0 var(--key-shadow);
}

:is(body[data-key-skin='keys-suisho'], body[data-key-skin='keys-soda'], body[data-key-skin='keys-ramune']) .key--side {
  background: var(--acrylic-side);
}

:is(body[data-key-skin='keys-suisho'], body[data-key-skin='keys-soda'], body[data-key-skin='keys-ramune']) .key.is-pressed {
  background: var(--acrylic-pressed);
  box-shadow: inset 0 0 0 1px var(--acrylic-pressed-edge), 0 0 14px var(--acrylic-glow), 0 1px 0 var(--key-shadow);
}

:is(body[data-key-skin='keys-suisho'], body[data-key-skin='keys-soda'], body[data-key-skin='keys-ramune']) .key.is-hint {
  box-shadow: inset 0 0 0 1px var(--acrylic-edge), 0 3px 0 var(--key-shadow), 0 0 0 2px var(--accent), 0 0 18px var(--accent-glow);
}

:is(body[data-key-skin='keys-suisho'], body[data-key-skin='keys-soda'], body[data-key-skin='keys-ramune']) .key--spacer {
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--acrylic-edge);
}

.key {
  position: relative;
  padding: 0;
  border: 0;
  border-radius: 12px;
  background: var(--key);
  color: var(--fg);
  font-size: 22px;
  /* 800 だと太い丸ゴシックで「ぬ／め」「ね／れ／わ」の細部が潰れる。M PLUS Rounded 1c に 600 は無いので 700。
     吹き出しの字（.flick-cell）とヒントの字もこの太さを継ぐ */
  font-weight: 700;
  box-shadow: 0 3px 0 var(--key-shadow);
  touch-action: none;
}

.key--mod,
.key--long {
  font-size: 13px;
}

.key--side {
  background: var(--key-side);
  font-size: 13px;
}

.key--side.is-active {
  color: var(--accent);
}

/* 押しても何も起きないキー。影と地の色を外し、押せるキーと形で見分けられるようにする */
.key--spacer {
  background: transparent;
  box-shadow: inset 0 0 0 1px var(--key-side);
  /* 押せないことを薄さで示すので、--fg-dim を上げても高コントラストでも今の薄さを保つ */
  color: #6d6d96;
  opacity: 0.5;
  cursor: default;
}

/* 練習で途中の字があるときの小゛゜（a/A）の吹き出し。キーの子に置いて上のキーへはみ出させ、押せないので当たり判定は変えない。
   押下中のキーの吹き出し（.flick-popup、押下中のキーは z-index: 5）より奥に描く */
.key-bubble {
  position: absolute;
  bottom: calc(100% + 8px);
  left: 50%;
  z-index: 4;
  padding: 4px 10px;
  border-radius: 10px;
  background: var(--gold);
  color: var(--bg);
  font-size: 14px;
  font-weight: 800;
  line-height: 1.2;
  white-space: nowrap;
  transform: translateX(-50%);
  box-shadow: 0 2px 8px rgba(0, 0, 0, 0.45);
  pointer-events: none;
}

.key-bubble::after {
  position: absolute;
  top: 100%;
  left: 50%;
  border: 6px solid transparent;
  border-top-color: var(--gold);
  transform: translateX(-50%);
  content: '';
}

/* transform で stacking context ができるため、押下中のキーを前に出して吹き出しを隣のキーより上に描く */
.key.is-pressed {
  z-index: 5;
  background: var(--key-pressed);
  box-shadow: 0 1px 0 var(--key-shadow);
  transform: translateY(2px);
}

.key.is-hint {
  box-shadow: 0 3px 0 var(--key-shadow), 0 0 0 2px var(--accent), 0 0 18px var(--accent-glow);
}

.key.is-hint::after {
  position: absolute;
  color: var(--accent);
  font-size: 14px;
  content: attr(data-hint-char);
}

.key[data-hint-dir='center']::after {
  content: none;
}

.key[data-hint-dir='left']::after {
  top: 50%;
  left: 8px;
  transform: translateY(-50%);
}

.key[data-hint-dir='right']::after {
  top: 50%;
  right: 8px;
  transform: translateY(-50%);
}

.key[data-hint-dir='up']::after {
  top: 1px;
  left: 50%;
  transform: translateX(-50%);
}

.key[data-hint-dir='down']::after {
  bottom: 1px;
  left: 50%;
  transform: translateX(-50%);
}

/* キーが低く上下のヒントと字が重なるので、字をヒントの反対側へ寄せる */
.key[data-hint-dir='up'] .key__label {
  display: inline-block;
  transform: translateY(var(--key-hint-shift));
}

.key[data-hint-dir='down'] .key__label {
  display: inline-block;
  transform: translateY(calc(-1 * var(--key-hint-shift)));
}

.flick-popup {
  position: absolute;
  inset: 0;
  z-index: 10;
  pointer-events: none;
}

.flick-cell {
  position: absolute;
  inset: 0;
  display: grid;
  place-items: center;
  border-radius: 12px;
  background: var(--popup);
  color: var(--fg-dim);
  font-size: 28px;
  box-shadow: inset 0 0 0 1px var(--key);
  /* 十字は押したまま止めたときだけ出す。速く弾く人に、隣のキーを覆う十字が一瞬だけ見えてちらつかないように */
  animation: flick-guide-delay 0.15s;
}

@keyframes flick-guide-delay {
  from,
  to {
    visibility: hidden;
  }
}

.flick-popup.is-flicked .flick-cell:not(.is-selected) {
  visibility: hidden;
}

.flick-cell--left {
  transform: translateX(-100%);
}

.flick-cell--right {
  transform: translateX(100%);
}

.flick-cell--up {
  transform: translateY(-100%);
}

.flick-cell--down {
  transform: translateY(100%);
}

.flick-cell.is-selected {
  z-index: 1;
  background: var(--accent);
  color: var(--bg);
  opacity: 1;
  box-shadow: 0 0 20px var(--accent-glow);
  animation: none;
}

/* ---------- reduced motion ---------- */

.is-reduced-motion .btn-big,
.is-reduced-motion .difficulty .btn-big::after,
.is-reduced-motion .title__line,
.is-reduced-motion .title::before,
.is-reduced-motion .title::after,
.is-reduced-motion .tagline__hot,
.is-reduced-motion .start-bg__glow,
.is-reduced-motion .other-modes > *,
.is-reduced-motion #btn-retry,
.is-reduced-motion .course--normal .btn-big,
.is-reduced-motion.is-fever #fever-bg,
.is-reduced-motion .timebar.is-low .timebar__fill,
.is-reduced-motion.is-fever .hud__mult,
.is-reduced-motion .hud__mult.is-level-up,
.is-reduced-motion .hud__level.is-notice .level-gauge__fill,
.is-reduced-motion .hud__notice.is-pop,
.is-reduced-motion .hud__goal.is-pop,
.is-reduced-motion .hud__shield.is-pop,
.is-reduced-motion .char.is-pending,
.is-reduced-motion .new-record,
.is-reduced-motion .rank-promotion,
.is-reduced-motion .countdown.is-zoom,
.is-reduced-motion .timebar__num.is-bump,
.is-reduced-motion .timebar.is-maxed,
.is-reduced-motion .result__rank,
.is-reduced-motion .combo.is-pop,
.is-reduced-motion .word-display.is-enter,
.is-reduced-motion .result__unlocks .unlock,
.is-reduced-motion .tank__wave,
.is-reduced-motion .tank__bubble,
.is-reduced-motion .tank__liquid.is-splash,
.is-reduced-motion .tank__mark.is-glow,
.is-reduced-motion #tab-play .home-tab__icon,
.is-reduced-motion #tab-play .home-tab__icon::after,
.is-reduced-motion.is-fever .tank__liquid {
  animation: none;
}

.is-reduced-motion.is-fever #fever-bg {
  opacity: calc(0.15 + 0.03 * var(--climb-power, 0));
}

.is-reduced-motion .start-bg__bubble {
  display: none;
}

.is-reduced-motion .start-bg {
  --bg-glow-rate: 0;
  --bg-bubble-rate: 0;
}

.is-reduced-motion .start-bg__layer {
  will-change: auto;
}

/* 動きひかえめでもミスの印は出す。大きさは変えず、出て消えるだけにする */
.is-reduced-motion .float-text--miss {
  animation-name: miss-mark-fade;
}

.is-reduced-motion .impact,
.is-reduced-motion .sweep-text,
.is-reduced-motion .shatter {
  display: none;
}

/* ---------- 超ド派手（is-wild-motion）。ふつうの演出に上乗せする ---------- */

/* タイトルは泡を倍にし、鼓動を強めて光の筋を速く回す */
.is-wild-motion .start-bg__bubble:nth-child(n + 11) {
  display: block;
}

.is-wild-motion .start-bg {
  --bg-cap: 180px;
  --bg-glow-rate: 0.3;
  --bg-bubble-rate: 0.75;
}

.is-wild-motion .title__line {
  animation-name: title-flow, title-beat-wild;
  animation-duration: 2s, 1.2s;
}

.is-wild-motion .difficulty .btn-big::after {
  animation-duration: 2s;
}

.is-wild-motion .start-bg__glow {
  opacity: 0.2;
  animation-duration: 6s;
}

.is-wild-motion .combo.is-pop {
  animation: pop-wild 0.26s ease-out;
}

/* 点数はふつうでは弾まない。超ド派手だけ main.js が hud-view.js の popScore で is-pop を付ける */
.is-wild-motion .hud__score.is-pop {
  transform-origin: left center;
  animation: pop-wild 0.26s ease-out;
}

.is-wild-motion .hud__mult.is-level-up {
  animation: level-up-wild 0.45s ease-out;
}

.is-wild-motion.is-fever .hud__mult.is-level-up {
  animation: level-up-wild 0.45s ease-out, blink 0.3s steps(2) infinite;
}

/* 脈は 1 秒に 1 往復で、閃光の上限（1 秒に 3 回）より遅い */
.is-wild-motion.is-fever #fever-bg {
  animation: fever-flow 0.8s linear infinite, fever-pulse 0.5s ease-in-out infinite alternate;
}

/* 揺らすのは HUD とお題の段だけ。キーボードを動かすと指の下のキーがずれ、フリックの向きの判定が崩れる */
.is-wild-motion .hud.is-quake,
.is-wild-motion .stage.is-quake {
  animation: quake 0.5s linear;
}

/* 超ド派手の上下の 2 本。逆向きに、小さく薄く奥を走らせ、真ん中の 1 本を主役に残す */
.sweep-text--echo {
  font-size: 56px;
  opacity: 0.4;
  animation-name: sweep-reverse;
}

/* ---------- keyframes ---------- */

@keyframes title-flow {
  to { background-position: 150% 0; }
}

/* ドクッ、ドクッと 2 回打って休む */
@keyframes title-char-in {
  from {
    opacity: 0;
    transform: translate(var(--from-x, 0), var(--from-y, 0)) scale(var(--from-scale, 0.6));
  }
  60% {
    opacity: 1;
    transform: translate(calc(var(--from-x, 0em) * -0.1), calc(var(--from-y, 0em) * -0.1)) scale(1.1);
  }
  to {
    opacity: 1;
    transform: none;
  }
}

/* 打ち終えた瞬間にタイトル全体を 1 回だけ弾ませる */
@keyframes title-land {
  0%, 100% { transform: scale(1); }
  35% { transform: scale(1.06); }
  65% { transform: scale(0.98); }
}

@keyframes title-land-wild {
  0%, 100% { transform: scale(1); }
  30% { transform: scale(1.16) rotate(-2deg); }
  60% { transform: scale(0.95) rotate(1deg); }
}

@keyframes title-beat {
  0%, 40%, 100% { transform: scale(1); }
  10% { transform: scale(1.07); }
  25% { transform: scale(1.03) rotate(-1deg); }
}

@keyframes title-beat-wild {
  0%, 40%, 100% { transform: scale(1); }
  10% { transform: scale(1.14) rotate(2deg); }
  25% { transform: scale(1.06) rotate(-3deg); }
}

@keyframes twinkle {
  0%, 100% { opacity: 0.2; transform: scale(0.6) rotate(0); }
  50% { opacity: 1; transform: scale(1.2) rotate(90deg); }
}

@keyframes tagline-hop {
  0%, 40%, 100% { transform: translateY(0); }
  10% { transform: translateY(-3px); }
}

@keyframes glow-drift {
  from { transform: translate(0, 0) scale(1); }
  to { transform: translate(12vmax, 8vmax) scale(1.25); }
}

/* 泡の層は --bg-reach だけ画面より下へ伸ばしてあるので、昇る長さもその分足して上端まで届かせる */
@keyframes bubble-rise {
  0% { opacity: 0; transform: translate(0, 0) scale(0.6); }
  10% { opacity: 0.7; }
  50% { transform: translate(var(--sway), calc(-55vh - var(--bg-reach) / 2)) scale(1); }
  85% { opacity: 0.5; }
  100% { opacity: 0; transform: translate(0, calc(-110vh - var(--bg-reach))) scale(1.1); }
}

@keyframes tap-ripple {
  0% { opacity: 1; transform: scale(0.05); }
  100% { opacity: 0; transform: scale(1); }
}

/* タイミング関数はキーフレームの区間ごとに掛かるので、transform を途中のキーフレームに置くと ease-out がそこで速さを 0 に落とし、
   泡が止まって見える。昇る動きは始点と終点だけにして全体で 1 回減速させ、横の揺れは hold-sway の translate に分ける */
@keyframes hold-rise {
  0% { opacity: 0; transform: translateY(0) scale(0.6); }
  8% { opacity: 0.85; }
  80% { opacity: 0.6; }
  100% { opacity: 0; transform: translateY(calc(-100vh - 40px)) scale(1.1); }
}

@keyframes hold-sway {
  0% { translate: 0; }
  50% { translate: var(--sway) 0; }
  100% { translate: 0; }
}

@keyframes course-in {
  from { opacity: 0; transform: translateY(16px) scale(0.85); }
}

@keyframes best-glow {
  0%, 30% { color: #ffd84a; text-shadow: 0 0 6px #ffd84a, 0 0 14px rgb(255 200 40 / 0.8); }
  100% { text-shadow: 0 0 0 transparent; }
}

@keyframes course-shine {
  0% { transform: translateX(-120%) skewX(-20deg); }
  35%, 100% { transform: translateX(320%) skewX(-20deg); }
}

@keyframes pop-wild {
  0% { transform: scale(2.2) rotate(-6deg); }
  60% { transform: scale(0.92) rotate(1deg); }
  100% { transform: scale(1) rotate(0); }
}

@keyframes level-up-wild {
  0% { transform: scale(2.2); text-shadow: 0 0 28px currentColor; }
  100% { transform: scale(1); text-shadow: none; }
}

@keyframes fever-pulse {
  0% { opacity: calc(0.28 + 0.04 * var(--climb-power, 0)); }
  100% { opacity: calc(0.45 + 0.04 * var(--climb-power, 0)); }
}

@keyframes swipe-shake {
  0%, 100% { transform: translateX(0); }
  15% { transform: translateX(calc(var(--shake-amp, 20px) * var(--shake-dir, 1))); }
  32% { transform: translateX(calc(var(--shake-amp, 20px) * var(--shake-dir, 1) * -0.7)); }
  50% { transform: translateX(calc(var(--shake-amp, 20px) * var(--shake-dir, 1) * 0.45)); }
  68% { transform: translateX(calc(var(--shake-amp, 20px) * var(--shake-dir, 1) * -0.25)); }
  84% { transform: translateX(calc(var(--shake-amp, 20px) * var(--shake-dir, 1) * 0.1)); }
}

@keyframes quake {
  0%, 100% { transform: translate(0, 0) rotate(0); }
  10% { transform: translate(-18px, 6px) rotate(-1.5deg); }
  20% { transform: translate(14px, -8px) rotate(1.2deg); }
  35% { transform: translate(-12px, 4px) rotate(-1deg); }
  50% { transform: translate(10px, -4px) rotate(0.8deg); }
  65% { transform: translate(-6px, 2px) rotate(-0.4deg); }
  80% { transform: translate(4px, -2px) rotate(0.2deg); }
}

@keyframes sweep-reverse {
  0% { transform: translate(110%, -50%) skewX(12deg); }
  100% { transform: translate(-110%, -50%) skewX(12deg); }
}

@keyframes pop {
  0% { transform: scale(1.5); }
  100% { transform: scale(1); }
}

@keyframes level-up {
  0% { transform: scale(1.5); text-shadow: 0 0 16px currentColor; }
  100% { transform: scale(1); text-shadow: none; }
}

@keyframes timebar-max {
  0% { box-shadow: 0 0 0 2px var(--fg), 0 0 18px 6px var(--fg); }
  100% { box-shadow: 0 0 0 2px var(--fg-dim), 0 0 0 0 transparent; }
}

@keyframes time-bump {
  0% { transform: translateY(-50%) scale(1.35); }
  100% { transform: translateY(-50%) scale(1); }
}

@keyframes ghost-overtake {
  0% { transform: scale(1.6); }
  100% { transform: scale(1); }
}

@keyframes fever-end {
  0% { color: var(--hot); }
  100% { color: var(--gold); }
}

@keyframes word-in {
  0% { opacity: 0; transform: scale(0.6); }
  100% { opacity: 1; transform: scale(1); }
}

@keyframes shake {
  0%, 100% { transform: translateX(0); }
  20% { transform: translateX(-10px); }
  40% { transform: translateX(8px); }
  60% { transform: translateX(-6px); }
  80% { transform: translateX(4px); }
}

@keyframes shatter-life {
  0%, 100% { opacity: 1; }
}

@keyframes shatter-left {
  0% { opacity: 1; transform: translate(0, 0) rotate(0); }
  100% { opacity: 0; transform: translate(-18px, 70px) rotate(-24deg); }
}

@keyframes shatter-right {
  0% { opacity: 1; transform: translate(0, 0) rotate(0); }
  100% { opacity: 0; transform: translate(18px, 80px) rotate(28deg); }
}

@keyframes shatter-label {
  0% { opacity: 0; transform: translate(-50%, 0) scale(1.4); }
  20%, 70% { opacity: 1; transform: translate(-50%, 0) scale(1); }
  100% { opacity: 0; transform: translate(-50%, 0) scale(1); }
}

@keyframes impact {
  0% { opacity: 1; }
  100% { opacity: 0; }
}

@keyframes sweep {
  0% { transform: translate(-110%, -50%) skewX(-12deg); }
  100% { transform: translate(110%, -50%) skewX(-12deg); }
}

@keyframes flash {
  0% { opacity: 1; }
  100% { opacity: 0; }
}

@keyframes toast {
  0% { opacity: 0; transform: translateX(-50%) scale(0.4); }
  20% { opacity: 1; transform: translateX(-50%) scale(1.15); }
  70% { opacity: 1; transform: translateX(-50%) scale(1); }
  100% { opacity: 0; transform: translateX(-50%) translateY(-20px); }
}

@keyframes float-up {
  0% { opacity: 1; transform: translate(-50%, -50%) scale(0.8); }
  30% { transform: translate(-50%, -80%) scale(1.2); }
  100% { opacity: 0; transform: translate(-50%, -220%) scale(1); }
}

@keyframes heartbeat {
  0%, 52%, 100% { transform: scale(1); }
  12% { transform: scale(1.25); }
  24% { transform: scale(1); }
  36% { transform: scale(1.15); }
}

@keyframes heart-pop {
  0%, 100% { scale: 1; }
  35% { scale: 1.5; }
}

@keyframes heart-ring {
  0% { opacity: 0.8; transform: scale(0.8); }
  45%, 100% { opacity: 0; transform: scale(2.2); }
}

@keyframes miss-mark {
  0% { opacity: 1; transform: translate(-50%, -50%) scale(1.3); }
  25% { transform: translate(-50%, -50%) scale(1); }
  100% { opacity: 0; transform: translate(-50%, -50%) scale(1); }
}

@keyframes miss-mark-fade {
  0%, 25% { opacity: 1; }
  100% { opacity: 0; }
}

@keyframes float-up-short {
  0% { opacity: 1; transform: translate(-50%, 24px) scale(0.8); }
  30% { transform: translate(-50%, 16px) scale(1.2); }
  100% { opacity: 0; transform: translate(-50%, 4px) scale(1); }
}

@keyframes zoom {
  0% { opacity: 0; transform: scale(2.2); }
  40% { opacity: 1; transform: scale(1); }
  100% { opacity: 0.2; transform: scale(0.9); }
}

@keyframes pulse {
  0%, 100% { transform: scale(1); }
  50% { transform: scale(1.05); }
}

@keyframes blink {
  0% { opacity: 1; }
  100% { opacity: 0.35; }
}

@keyframes rank-in {
  0% { opacity: 0; transform: scale(3) rotate(-20deg); }
  100% { opacity: 1; transform: scale(1) rotate(0); }
}

@keyframes unlock-in {
  0% { opacity: 0; transform: translateY(12px); }
  100% { opacity: 1; transform: translateY(0); }
}

@keyframes tank-wave {
  from { transform: translateX(0); }
  to { transform: translateX(-50%); }
}

@keyframes tank-bubble {
  from { transform: translateY(0); opacity: 0.8; }
  to { transform: translateY(-60vh); opacity: 0; }
}

@keyframes tank-splash {
  0% { transform: translateY(0); }
  30% { transform: translateY(-12px); }
  100% { transform: translateY(0); }
}

@keyframes tank-glow {
  0% { opacity: 1; border-top-color: #fff; box-shadow: 0 -4px 16px var(--gold); }
  100% { opacity: 0.3; }
}

@keyframes rank-step {
  0% { transform: scale(1.12); }
  100% { transform: scale(1); }
}

@keyframes rank-fresh {
  0% { transform: scale(1.3); filter: brightness(2.5) drop-shadow(0 0 16px #fff); }
  100% { transform: scale(1); }
}

@keyframes promote-in {
  0% { opacity: 0; transform: scale(0.3); }
  100% { opacity: 1; transform: scale(1); }
}

@keyframes fever-flow {
  0% { background-position: 0% 50%; }
  100% { background-position: 400% 50%; }
}

/* ベストの回。再生できない回は理由を行の下に回す */
.best-replays {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  margin: 0 0 var(--space-7);
  padding: 0;
  list-style: none;
}

.best-replay {
  display: flex;
  flex-wrap: wrap;
  align-items: center;
  gap: var(--space-2) var(--space-6);
  font-variant-numeric: tabular-nums;
}

.best-replay__label {
  font-weight: 800;
}

.best-replay__score {
  flex: 1;
  color: var(--accent);
  font-weight: 800;
}

.best-replay__note {
  width: 100%;
  color: var(--fg-dim);
  font-size: var(--text-sm);
}

/* 720×1280 で描いたコマを、ダイアログの中で縦が収まる大きさに縮める */
.replay-dialog__canvas {
  width: min(100%, calc((100dvh - 200px) * 9 / 16));
  aspect-ratio: 9 / 16;
  border-radius: 12px;
}

.replay-dialog__actions {
  display: flex;
  gap: var(--space-6);
}

.past__list {
  display: flex;
  flex-direction: column;
  gap: var(--space-4);
  width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
}

.past__list:empty {
  display: none;
}

.past__day {
  display: flex;
  align-items: baseline;
  justify-content: space-between;
  width: 100%;
  font-variant-numeric: tabular-nums;
}

.past__best {
  color: var(--fg-dim);
  font-size: var(--text-md);
}

/* OS でコントラストを上げている人には、薄い字と枠を 1 段明るくする。光彩や背景の演出は変えない */
@media (prefers-contrast: more) {
  :root {
    --fg-dim: #b0b0d4;
    --line: #8a8ab0;
  }
}
