<script setup lang="ts">
import { computed, onBeforeUnmount, onMounted, shallowRef, watch } from 'vue'
import { onBeforeRouteLeave, useRoute, useRouter } from 'vue-router'
import { ElMessage, ElMessageBox } from 'element-plus'
import { ArrowLeft, ArrowRight, Finished, Grid, House } from '@element-plus/icons-vue'
import { masterWrongQuestion } from '@/api/quiz'
import { useQuizStore } from '@/stores/quiz'

const route = useRoute()
const router = useRouter()
const quiz = useQuizStore()
const selected = shallowRef<Array<number | string>>([])
const blankAnswer = shallowRef('')
const sheetOpen = shallowRef(false)
const now = shallowRef(Date.now())
const startedAt = shallowRef(Date.now())
const autoSubmitting = shallowRef(false)
const loadingAttempt = shallowRef(true)
const touchStartX = shallowRef(0)
const touchStartY = shallowRef(0)
const slideName = shallowRef('slide-next')
let timer: number | undefined
let positionTimer: number | undefined

const item = computed(() => quiz.currentItem)
const isMultiple = computed(() => item.value?.question.type === 'multiple')
const isBlank = computed(() => item.value?.question.type === 'blank')
const showAnswer = computed(() => quiz.attempt?.mode === 'memorize' || item.value?.is_correct !== null)
const remainingSeconds = computed(() => {
  if (!quiz.attempt?.expires_at || quiz.attempt.status !== 'in_progress') return null
  return Math.max(0, Math.floor((new Date(quiz.attempt.expires_at).getTime() - now.value) / 1000))
})
const remainingLabel = computed(() => {
  if (remainingSeconds.value === null) return '不限时'
  const minutes = Math.floor(remainingSeconds.value / 60)
  const seconds = remainingSeconds.value % 60
  return `${String(minutes).padStart(2, '0')}:${String(seconds).padStart(2, '0')}`
})
const typeLabel = computed(() => {
  const labels: Record<string, string> = { single: '单选', multiple: '多选', judge: '判断', blank: '填空' }
  return item.value ? labels[item.value.question.type] : ''
})
const displaySelected = computed(() => {
  if (!item.value || quiz.attempt?.mode !== 'memorize') return selected.value
  return item.value.question.options
    .filter((option) => option.is_correct)
    .map((option) => option.id)
})
const singleDisplaySelected = computed(() => displaySelected.value[0])
const showConfirmAnswer = computed(() => quiz.attempt?.status === 'in_progress' && (isMultiple.value || isBlank.value) && !showAnswer.value)
const optionsLocked = computed(() => quiz.attempt?.status !== 'in_progress' || showAnswer.value)
const isFirstQuestion = computed(() => quiz.currentIndex === 0)
const isLastQuestion = computed(() => !quiz.attempt || quiz.currentIndex >= quiz.attempt.items.length - 1)
const isWrongReview = computed(() => quiz.attempt?.mode === 'wrong_practice')
const isReadonlyReview = computed(() => quiz.attempt?.status === 'submitted')
const isAnsweredWrong = computed(() => item.value?.is_correct === false)
const answerPanelClass = computed(() => ({
  'answer-panel--wrong': isAnsweredWrong.value,
}))
const slideStyle = computed(() => ({
  '--quiz-slide-duration': `${quiz.animationDuration}ms`,
  '--quiz-slide-opacity-duration': `${Math.max(0, Math.round(quiz.animationDuration * 0.8))}ms`,
}))
const quizPageClass = computed(() => ({
  'quiz-page--no-motion': quiz.animationDuration === 0,
}))
const selectedOptionLabels = computed(() => optionLabels(selected.value))
const correctOptionLabels = computed(() => {
  if (!item.value) return []

  return item.value.question.options
    .filter((option) => option.is_correct)
    .map((option) => optionLabelById(option.id))
})
const selectedAnswerText = computed(() => selectedOptionLabels.value.length > 0 ? selectedOptionLabels.value.join('、') : '未选择')
const correctAnswerText = computed(() => {
  if (!item.value) return ''
  if (item.value.question.type === 'blank') return item.value.question.answers?.join('、') || '暂无标准答案'

  return correctOptionLabels.value.join('、') || '暂无标准答案'
})

function optionClass(option: { id: number; is_correct: boolean }) {
  if (!showAnswer.value) return ''
  const selectedIds = selected.value.map(String)
  const isSelected = selectedIds.includes(String(option.id))
  if (option.is_correct) return 'option--right'
  if (isMultiple.value && isSelected) return 'option--picked-wrong'
  if (isSelected) return 'option--wrong'
  return ''
}

function optionLabelById(optionId: number | string) {
  const optionIndex = item.value?.question.options.findIndex((option) => String(option.id) === String(optionId)) ?? -1
  if (optionIndex < 0) return String(optionId)

  return optionLabelByIndex(optionIndex)
}

function optionLabels(values: Array<number | string>) {
  if (!item.value) return values.map(String)

  const selectedIds = new Set(values.map(String))
  const orderedLabels = item.value.question.options
    .map((option, index) => ({ option, index }))
    .filter(({ option }) => selectedIds.has(String(option.id)))
    .map(({ index }) => optionLabelByIndex(index))

  const knownIds = new Set(item.value.question.options.map((option) => String(option.id)))
  const unknownLabels = values.filter((value) => !knownIds.has(String(value))).map(String)

  return [...orderedLabels, ...unknownLabels]
}

function optionLabelByIndex(index: number) {
  return String.fromCharCode(65 + index)
}

function syncLocalAnswer() {
  selected.value = (quiz.currentItem?.answer ?? []) as Array<number | string>
  blankAnswer.value = String(selected.value[0] ?? '')
  startedAt.value = Date.now()
}

function updateSelected(value: Array<number | string>) {
  if (optionsLocked.value || quiz.attempt?.mode === 'memorize') return
  selected.value = value
}

async function submitAnswer() {
  if (quiz.attempt?.status !== 'in_progress' || showAnswer.value && !isBlank.value) return
  const answer = isBlank.value ? [blankAnswer.value] : selected.value
  if (answer.length === 0 || answer.every((value) => String(value).trim() === '')) {
    ElMessage.warning('请先作答')
    return
  }
  await quiz.answer(answer, Math.max(0, Math.floor((Date.now() - startedAt.value) / 1000)))
  syncLocalAnswer()
  if (quiz.autoNextOnCorrect && item.value?.is_correct === true && !isLastQuestion.value) {
    window.setTimeout(() => {
      void go(quiz.currentIndex + 1)
    }, Math.max(80, quiz.animationDuration))
  }
}

async function selectSingle(optionId: number) {
  if (optionsLocked.value) return
  selected.value = [optionId]
  await submitAnswer()
}

async function go(index: number) {
  if (!quiz.attempt || index < 0 || index >= quiz.attempt.items.length) return
  slideName.value = index > quiz.currentIndex ? 'slide-next' : 'slide-prev'
  quiz.setPosition(index)
  syncLocalAnswer()
  sheetOpen.value = false
}

function isEditableTarget(target: EventTarget | null) {
  if (!(target instanceof HTMLElement)) return false

  return Boolean(target.closest('input, textarea, select, [contenteditable="true"], .el-input, .el-textarea, .el-select'))
}

function handleKeyboardNavigation(event: KeyboardEvent) {
  if (event.altKey || event.ctrlKey || event.metaKey || event.shiftKey || sheetOpen.value || isEditableTarget(event.target)) return

  const previousKeys = ['ArrowLeft', '[', ',']
  const nextKeys = ['ArrowRight', ']', '.']
  if (previousKeys.includes(event.key)) {
    event.preventDefault()
    void go(quiz.currentIndex - 1)
    return
  }
  if (nextKeys.includes(event.key)) {
    event.preventDefault()
    void go(quiz.currentIndex + 1)
  }
}

function handleTouchStart(event: TouchEvent) {
  const target = event.target as HTMLElement | null
  if (target?.closest('input, textarea, .el-drawer, .quiz-footer')) return
  const touch = event.touches[0]
  touchStartX.value = touch.clientX
  touchStartY.value = touch.clientY
}

function handleTouchEnd(event: TouchEvent) {
  if (!touchStartX.value || !touchStartY.value || !quiz.attempt) return
  const touch = event.changedTouches[0]
  const deltaX = touch.clientX - touchStartX.value
  const deltaY = touch.clientY - touchStartY.value
  touchStartX.value = 0
  touchStartY.value = 0

  if (Math.abs(deltaX) < 64 || Math.abs(deltaX) < Math.abs(deltaY) * 1.25) return
  const nextIndex = deltaX < 0 ? quiz.currentIndex + 1 : quiz.currentIndex - 1
  void go(nextIndex)
}

async function submitPaper(auto = false) {
  if (!quiz.attempt || quiz.attempt.status !== 'in_progress') return
  if (!auto) {
    try {
      await ElMessageBox.confirm('提交后将完成本次练习，确认提交吗？', '提交确认', {
        type: 'warning',
        confirmButtonText: '确认提交',
        cancelButtonText: '取消',
      })
    } catch {
      return
    }
  }
  await quiz.savePosition(quiz.currentIndex, true).catch(() => undefined)
  await quiz.submit()
  ElMessage.success(auto ? '时间到，已自动完成' : '练习已完成')
}

async function markCurrentMastered() {
  const wrongQuestionId = item.value?.wrong_question_id
  if (!wrongQuestionId) {
    ElMessage.warning('没有找到这道错题的记录')
    return
  }

  await masterWrongQuestion(wrongQuestionId)
  await quiz.removeCurrentWrongQuestion()
  ElMessage.success('已移出错题')

  if (!quiz.currentItem) {
    await router.replace('/quiz')
    return
  }

  syncLocalAnswer()
}

function savePositionOnUnload() {
  quiz.savePositionOnUnload()
}

onMounted(async () => {
  quiz.clear()
  loadingAttempt.value = true
  try {
    await quiz.resume(Number(route.params.attemptId))
    syncLocalAnswer()
    timer = window.setInterval(() => {
      now.value = Date.now()
    }, 1000)
    positionTimer = window.setInterval(() => {
      void quiz.savePosition()
    }, 10000)
    window.addEventListener('beforeunload', savePositionOnUnload)
    window.addEventListener('pagehide', savePositionOnUnload)
    window.addEventListener('keydown', handleKeyboardNavigation)
  } finally {
    loadingAttempt.value = false
  }
})

onBeforeUnmount(() => {
  if (timer !== undefined) {
    window.clearInterval(timer)
  }
  if (positionTimer !== undefined) {
    window.clearInterval(positionTimer)
  }
  window.removeEventListener('beforeunload', savePositionOnUnload)
  window.removeEventListener('pagehide', savePositionOnUnload)
  window.removeEventListener('keydown', handleKeyboardNavigation)
})

onBeforeRouteLeave(async () => {
  await quiz.savePosition(quiz.currentIndex, true).catch(() => undefined)
})

watch(remainingSeconds, async (value) => {
  if (value !== 0 || autoSubmitting.value || quiz.attempt?.status !== 'in_progress') return
  autoSubmitting.value = true
  try {
    await submitPaper(true)
  } finally {
    autoSubmitting.value = false
  }
})
</script>

<template>
  <main class="quiz-page" v-if="!loadingAttempt && quiz.attempt && item" :class="quizPageClass" :style="slideStyle">
    <section class="question-panel" @touchstart.passive="handleTouchStart" @touchend.passive="handleTouchEnd">
      <Transition :name="slideName" mode="out-in">
        <article :key="item.id" class="question-slide">
          <div class="question-meta">
            <div class="meta-left">
              <ElTag>{{ typeLabel }}</ElTag>
              <span>{{ quiz.currentIndex + 1 }} / {{ quiz.attempt.total_questions }}</span>
            </div>
            <div class="timer" :class="{ 'timer--danger': remainingSeconds !== null && remainingSeconds <= 60 }">
              {{ remainingLabel }}
            </div>
          </div>
          <h1>{{ item.question.content }}</h1>

          <ElCheckboxGroup v-if="isMultiple" :model-value="displaySelected" class="option-list" @change="updateSelected">
            <ElCheckbox
              v-for="(option, optionIndex) in item.question.options"
              :key="option.id"
              :value="option.id"
              :class="optionClass(option)"
              :disabled="optionsLocked"
              border
            >
              <span class="option-index">{{ optionLabelByIndex(optionIndex) }}</span>
              <span class="option-content">{{ option.content }}</span>
            </ElCheckbox>
          </ElCheckboxGroup>
          <ElInput
            v-else-if="isBlank"
            v-model="blankAnswer"
            class="blank-input"
            type="textarea"
            :rows="4"
            :disabled="optionsLocked"
            placeholder="请输入答案"
          />
          <ElRadioGroup v-else :model-value="singleDisplaySelected" class="option-list">
            <ElRadio
              v-for="(option, optionIndex) in item.question.options"
              :key="option.id"
              :value="option.id"
              :class="optionClass(option)"
              :disabled="optionsLocked"
              border
              @click="selectSingle(option.id)"
            >
              <span class="option-index">{{ optionLabelByIndex(optionIndex) }}</span>
              <span class="option-content">{{ option.content }}</span>
            </ElRadio>
          </ElRadioGroup>

          <section v-if="showAnswer" class="answer-panel" :class="answerPanelClass">
            <strong>答案与解析</strong>
            <p v-if="item.question.type !== 'blank'" class="answer-summary">
              你选的：{{ selectedAnswerText }}，正确答案是 {{ correctAnswerText }}
            </p>
            <p v-else class="answer-summary">
              你填的：{{ blankAnswer || '未填写' }}
            </p>
            <p v-if="item.question.type === 'blank'">正确答案：{{ item.question.answers?.join('、') || '暂无标准答案' }}</p>
            <p>{{ item.question.explanation || '暂无解析' }}</p>
          </section>
        </article>
      </Transition>
    </section>

    <footer class="quiz-footer">
      <div class="footer-inner" :class="{ 'footer-inner--wrong-review': isWrongReview }">
        <div class="footer-group footer-group--left">
          <ElButton class="footer-icon footer-home" :icon="House" circle @click="router.push('/quiz')" />
          <ElButton class="footer-nav footer-prev" :icon="ArrowLeft" :disabled="isFirstQuestion" @click="go(quiz.currentIndex - 1)">
            上一题
          </ElButton>
        </div>
        <div class="footer-group footer-group--center">
          <ElButton v-if="isWrongReview" class="footer-mastered" type="warning" plain @click="markCurrentMastered">
            已掌握
          </ElButton>
        </div>
        <div class="footer-group footer-group--right">
          <ElButton class="footer-nav footer-next" type="primary" plain :disabled="isLastQuestion" @click="go(quiz.currentIndex + 1)">
            下一题
            <ElIcon class="footer-nav-icon"><ArrowRight /></ElIcon>
          </ElButton>
          <ElButton v-if="showConfirmAnswer" class="footer-primary" type="primary" @click="submitAnswer">
            确认本题
          </ElButton>
          <ElButton
            v-if="!isReadonlyReview && !isWrongReview"
            class="footer-finish"
            :class="{ 'footer-finish--defer': showConfirmAnswer }"
            :icon="Finished"
            :disabled="quiz.attempt.status !== 'in_progress'"
            @click="submitPaper(false)"
          >
            {{ quiz.attempt.status === 'submitted' ? '已提交' : '提交' }}
          </ElButton>
          <ElButton class="footer-icon footer-sheet" :icon="Grid" circle @click="sheetOpen = true" />
        </div>
      </div>
    </footer>

    <ElDrawer v-model="sheetOpen" title="答题卡" direction="btt" size="48%">
      <div class="answer-sheet">
        <button
          v-for="(answerItem, index) in quiz.attempt.items"
          :key="answerItem.id"
          class="sheet-cell"
          :class="{
            'sheet-cell--active': index === quiz.currentIndex,
            'sheet-cell--done': answerItem.answer && answerItem.answer.length > 0,
            'sheet-cell--wrong': answerItem.is_correct === false,
            'sheet-cell--right': answerItem.is_correct === true,
          }"
          @click="go(index)"
        >
          {{ index + 1 }}
        </button>
      </div>
    </ElDrawer>
  </main>
  <main v-else class="quiz-page quiz-page--loading" v-loading="loadingAttempt" />
</template>

<style scoped>
.quiz-page {
  min-height: calc(100vh - 56px);
  display: grid;
  grid-template-rows: 1fr auto;
}

.quiz-page--loading {
  display: block;
}

.question-panel {
  width: min(860px, 100%);
  margin: 0 auto;
  padding: 24px 16px 120px;
  touch-action: pan-y;
  overflow: hidden;
}

.question-slide {
  min-height: 360px;
}

.question-meta {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 14px;
  color: var(--qq-muted);
}

.meta-left {
  display: flex;
  align-items: center;
  gap: 10px;
}

.timer {
  padding: 6px 10px;
  border: 1px solid var(--qq-line);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.52);
  color: var(--qq-ink);
  font-variant-numeric: tabular-nums;
  font-weight: 750;
}

.timer--danger {
  border-color: rgba(201, 133, 34, 0.55);
  color: #9a5f10;
  background: rgba(201, 133, 34, 0.1);
}

.question-panel h1 {
  margin: 0 0 22px;
  font-size: 24px;
  line-height: 1.45;
}

.option-list {
  display: grid;
  gap: 12px;
}

.blank-input {
  width: 100%;
}

.option-list :deep(.el-radio),
.option-list :deep(.el-checkbox) {
  width: 100%;
  height: auto;
  min-height: 48px;
  margin-right: 0;
  display: flex;
  align-items: center;
  white-space: normal;
}

.option-list :deep(.el-checkbox__input),
.option-list :deep(.el-radio__input) {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  opacity: 0;
  pointer-events: none;
}

.option-list :deep(.el-radio.is-disabled),
.option-list :deep(.el-checkbox.is-disabled) {
  cursor: default;
  opacity: 1;
}

.option-list :deep(.el-radio.is-disabled .el-radio__label),
.option-list :deep(.el-checkbox.is-disabled .el-checkbox__label) {
  color: var(--qq-ink);
}

.option-list :deep(.el-radio__label),
.option-list :deep(.el-checkbox__label) {
  display: flex;
  align-items: center;
  min-width: 0;
  white-space: normal;
}

.option-index {
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: 24px;
  min-width: 24px;
  height: 24px;
  margin-right: 8px;
  border-radius: 8px;
  background: rgba(31, 111, 91, 0.08);
  color: var(--qq-moss);
  font-weight: 800;
  font-size: 13px;
}

.option-content {
  flex: 1;
  min-width: 0;
  line-height: 1.55;
}

.option-list :deep(.option--right) {
  border-color: rgba(31, 111, 91, 0.58);
  background: rgba(31, 111, 91, 0.1);
}

.option-list :deep(.option--right .el-radio__label),
.option-list :deep(.option--right .el-checkbox__label) {
  color: #1f6f5b;
  font-weight: 700;
}

.option-list :deep(.option--wrong),
.option-list :deep(.option--picked-wrong) {
  border-color: rgba(201, 133, 34, 0.58);
  background: rgba(201, 133, 34, 0.1);
}

.option-list :deep(.option--wrong .el-radio__label),
.option-list :deep(.option--wrong .el-checkbox__label),
.option-list :deep(.option--picked-wrong .el-checkbox__label) {
  color: #9a5f10;
  font-weight: 700;
}

.answer-panel {
  margin-top: 18px;
  padding: 16px;
  border-radius: 8px;
  border: 1px solid rgba(31, 111, 91, 0.28);
  background: rgba(31, 111, 91, 0.07);
}

.answer-panel--wrong {
  border-color: rgba(201, 133, 34, 0.42);
  background: rgba(201, 133, 34, 0.12);
}

.answer-panel p {
  margin: 8px 0 0;
}

.answer-summary {
  color: var(--qq-ink);
  font-weight: 650;
}

.quiz-footer {
  position: fixed;
  left: 0;
  right: 0;
  bottom: 0;
  padding: 10px 12px calc(10px + env(safe-area-inset-bottom));
  border-top: 1px solid var(--qq-line);
  background: rgba(247, 248, 244, 0.9);
  backdrop-filter: blur(10px);
}

.footer-inner {
  width: fit-content;
  max-width: 100%;
  min-height: 52px;
  margin: 0 auto;
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 10px;
  padding: 8px;
  border: 1px solid rgba(223, 229, 221, 0.9);
  border-radius: 16px;
  background: rgba(255, 255, 255, 0.48);
  box-shadow: 0 10px 28px rgba(23, 33, 27, 0.08);
}

.footer-inner :deep(.el-button),
.footer-group :deep(.el-button) {
  margin-left: 0;
}

.footer-group {
  display: flex;
  align-items: center;
  gap: 10px;
}

.footer-icon {
  width: 44px;
  height: 44px;
  background: rgba(255, 255, 255, 0.62);
}

.footer-nav,
.footer-primary,
.footer-finish,
.footer-mastered {
  height: 44px;
  border-radius: 8px;
  font-weight: 700;
}

.footer-nav {
  width: 138px;
}

.footer-primary {
  width: 132px;
}

.footer-finish {
  width: 96px;
}

.footer-mastered {
  width: 108px;
}

.footer-primary {
  box-shadow: 0 8px 18px rgba(31, 111, 91, 0.18);
}

.footer-finish {
  background: rgba(255, 255, 255, 0.62);
}

.footer-nav-icon {
  margin-left: 4px;
}

.slide-next-enter-active,
.slide-next-leave-active,
.slide-prev-enter-active,
.slide-prev-leave-active {
  transition:
    transform var(--quiz-slide-duration, 160ms) ease,
    opacity var(--quiz-slide-opacity-duration, 130ms) ease;
}

.slide-next-enter-from,
.slide-prev-leave-to {
  opacity: 0;
  transform: translateX(42px);
}

.slide-next-leave-to,
.slide-prev-enter-from {
  opacity: 0;
  transform: translateX(-42px);
}

.quiz-page--no-motion .slide-next-enter-active,
.quiz-page--no-motion .slide-next-leave-active,
.quiz-page--no-motion .slide-prev-enter-active,
.quiz-page--no-motion .slide-prev-leave-active {
  transition: none;
}

.quiz-page--no-motion .slide-next-enter-from,
.quiz-page--no-motion .slide-prev-leave-to,
.quiz-page--no-motion .slide-next-leave-to,
.quiz-page--no-motion .slide-prev-enter-from {
  opacity: 1;
  transform: none;
}

.answer-sheet {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(42px, 1fr));
  gap: 10px;
}

.sheet-cell {
  height: 42px;
  border: 1px solid var(--qq-line);
  border-radius: 8px;
  background: rgba(255, 255, 255, 0.68);
}

.sheet-cell--done {
  border-color: var(--qq-moss);
  background: rgba(31, 111, 91, 0.12);
}

.sheet-cell--active {
  outline: 2px solid rgba(65, 87, 199, 0.28);
}

.sheet-cell--right {
  border-color: var(--qq-moss);
  background: rgba(31, 111, 91, 0.16);
}

.sheet-cell--wrong {
  border-color: rgba(201, 133, 34, 0.7);
  background: rgba(201, 133, 34, 0.14);
}

@media (max-width: 640px) {
  .question-panel {
    padding: 18px 12px 132px;
  }

  .question-panel h1 {
    font-size: 20px;
  }

  .quiz-footer {
    padding: 8px 10px calc(8px + env(safe-area-inset-bottom));
  }

  .footer-inner {
    width: 100%;
    display: grid;
    grid-template-columns: 42px minmax(0, 1fr) minmax(0, 1fr) 42px;
    grid-template-areas:
      "home prev next sheet"
      "finish finish finish finish";
    gap: 8px;
    padding: 0;
    border: 0;
    border-radius: 0;
    background: transparent;
    box-shadow: none;
  }

  .footer-inner--wrong-review {
    grid-template-columns: 42px minmax(0, 1fr) minmax(0, 1fr) minmax(0, 1fr) 42px;
    grid-template-areas:
      "home prev mastered next sheet"
      "confirm confirm confirm confirm confirm";
  }

  .footer-group {
    display: contents;
  }

  .footer-icon {
    width: 42px;
    height: 42px;
  }

  .footer-home {
    grid-area: home;
  }

  .footer-sheet {
    grid-area: sheet;
  }

  .footer-nav {
    width: 100%;
    height: 42px;
  }

  .footer-prev {
    grid-area: prev;
  }

  .footer-next {
    grid-area: next;
  }

  .footer-primary {
    grid-area: finish;
    width: 100%;
    height: 42px;
    min-width: 0;
    padding-inline: 10px;
  }

  .footer-inner--wrong-review .footer-primary {
    grid-area: confirm;
  }

  .footer-finish {
    grid-area: finish;
    width: 100%;
    height: 40px;
  }

  .footer-mastered {
    grid-area: mastered;
    width: 100%;
    height: 42px;
  }

  .footer-finish--defer {
    display: none;
  }
}

@media (prefers-reduced-motion: reduce) {
  .slide-next-enter-active,
  .slide-next-leave-active,
  .slide-prev-enter-active,
  .slide-prev-leave-active {
    transition: none;
  }
}
</style>
