Files
gameno-front/src/views/ClassRegistrationView.vue
T
kavehhn 6d76a90d9b style: polish registration flow layout and spacing.
Use a unified card with stepper, clearer payment options, and consistent padding on both steps.
2026-08-16 08:46:30 +03:30

953 lines
25 KiB
Vue
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<div class="registration-page">
<div class="container">
<header class="page-head">
<RouterLink to="/" class="back-link">
<span aria-hidden="true"></span>
بازگشت به صفحه اصلی
</RouterLink>
<p class="page-eyebrow">{{ isClassRequest ? 'درخواست تشکیل کلاس' : 'ثبت‌نام در کلاس' }}</p>
<h1>{{ pageTitle }}</h1>
<p v-if="cls" class="page-lead">{{ cls.course?.title || cls.name }}</p>
</header>
<div v-if="loading" class="state-card loading-block">
<div class="spinner" aria-label="در حال بارگذاری"></div>
</div>
<div v-else-if="loadError" class="state-card alert" role="alert">{{ loadError }}</div>
<div v-else-if="cls" class="registration-card">
<aside class="summary-panel">
<div class="summary-inner">
<p class="summary-label">خلاصه کلاس</p>
<h2 class="summary-title">{{ cls.name }}</h2>
<dl class="summary-list">
<div v-if="cls.professor" class="summary-item">
<dt>استاد</dt>
<dd>{{ cls.professor.name }} {{ cls.professor.surname || '' }}</dd>
</div>
<div v-if="cls.startDate" class="summary-item">
<dt>شروع</dt>
<dd>{{ formatJalali(cls.startDate) }}</dd>
</div>
<div class="summary-item">
<dt>شهریه</dt>
<dd>{{ formatPrice(pricing.tuitionFee) }}</dd>
</div>
</dl>
<div v-if="step === 2" class="summary-total">
<span>مبلغ این مرحله</span>
<strong>{{ formatPrice(activePricing.amountDueNow) }}</strong>
</div>
</div>
</aside>
<section class="form-panel">
<nav class="stepper" aria-label="مراحل ثبت‌نام">
<div class="stepper-item" :class="{ active: step === 1, done: step > 1 }">
<span class="stepper-dot">{{ step > 1 ? '✓' : '۱' }}</span>
<span class="stepper-label">اطلاعات شما</span>
</div>
<span class="stepper-line" aria-hidden="true"></span>
<div class="stepper-item" :class="{ active: step === 2 }">
<span class="stepper-dot">۲</span>
<span class="stepper-label">پرداخت</span>
</div>
</nav>
<!-- Step 1 -->
<div v-if="step === 1" class="step-content">
<div class="step-header">
<h2>اطلاعات تماس</h2>
<p>
برای ادامه، مشخصات خود را وارد کنید. اگر حساب کاربری ندارید، بهصورت خودکار ساخته
میشود و نام کاربری و رمز عبور از طریق پیامک برایتان ارسال میگردد.
</p>
</div>
<div v-if="formError" class="alert" role="alert">{{ formError }}</div>
<form class="reg-form" novalidate @submit.prevent="handleInfoSubmit">
<div class="fields-grid">
<div class="field">
<label for="reg-name">نام <span class="req">*</span></label>
<input
id="reg-name"
v-model.trim="form.name"
type="text"
autocomplete="given-name"
placeholder="نام"
/>
<span v-if="errors.name" class="field-error">{{ errors.name }}</span>
</div>
<div class="field">
<label for="reg-surname">نام خانوادگی <span class="req">*</span></label>
<input
id="reg-surname"
v-model.trim="form.surname"
type="text"
autocomplete="family-name"
placeholder="نام خانوادگی"
/>
<span v-if="errors.surname" class="field-error">{{ errors.surname }}</span>
</div>
<div class="field">
<label for="reg-national-id">کد ملی <span class="req">*</span></label>
<input
id="reg-national-id"
v-model.trim="form.nationalIdCode"
type="text"
inputmode="numeric"
maxlength="10"
autocomplete="off"
placeholder="۱۰ رقم"
dir="ltr"
class="input-ltr"
/>
<span v-if="errors.nationalIdCode" class="field-error">{{ errors.nationalIdCode }}</span>
</div>
<div class="field">
<label for="reg-phone">شماره موبایل <span class="req">*</span></label>
<input
id="reg-phone"
v-model.trim="form.phoneNumber"
type="tel"
inputmode="tel"
autocomplete="tel"
placeholder="۰۹۱۲۱۲۳۴۵۶۷"
dir="ltr"
class="input-ltr"
/>
<span v-if="errors.phoneNumber" class="field-error">{{ errors.phoneNumber }}</span>
</div>
<div class="field field-wide">
<label for="reg-email">ایمیل <span class="optional">(اختیاری)</span></label>
<input
id="reg-email"
v-model.trim="form.email"
type="email"
autocomplete="email"
placeholder="example@email.com"
dir="ltr"
class="input-ltr"
/>
<span v-if="errors.email" class="field-error">{{ errors.email }}</span>
</div>
</div>
<div class="form-actions">
<button class="btn btn-ink btn-block" type="submit" :disabled="infoSubmitting">
<span v-if="infoSubmitting" class="spinner" aria-hidden="true"></span>
{{ infoSubmitting ? 'در حال ثبت…' : 'ادامه به پرداخت' }}
</button>
</div>
</form>
</div>
<!-- Step 2 -->
<div v-else class="step-content">
<div class="step-header">
<h2>{{ isClassRequest ? 'پرداخت بیعانه' : 'انتخاب روش پرداخت' }}</h2>
<p v-if="!isClassRequest">
یکی از روش‌های زیر را انتخاب کنید. پرداخت یک‌جا شامل
{{ formatPrice(FULL_PAYMENT_DISCOUNT) }} تخفیف است.
</p>
<p v-else>
برای ثبت درخواست تشکیل کلاس جدید، بیعانه پرداخت کنید. این مبلغ تا زمان تأیید
نهایی قطعی نیست.
</p>
</div>
<div v-if="!isClassRequest" class="plan-options" role="radiogroup" aria-label="روش پرداخت">
<label class="plan-card" :class="{ selected: paymentPlan === 'full' }">
<input v-model="paymentPlan" type="radio" value="full" />
<span class="plan-radio" aria-hidden="true"></span>
<div class="plan-content">
<div class="plan-top">
<strong>پرداخت یکجا</strong>
<span class="plan-badge">پیشنهادی</span>
</div>
<p>
با پرداخت کامل شهریه،
<span class="highlight">{{ formatPrice(FULL_PAYMENT_DISCOUNT) }}</span>
تخفیف دریافت میکنید.
</p>
<div class="plan-footer">
<span class="plan-price">{{ formatPrice(fullPricing.totalAmount) }}</span>
</div>
</div>
</label>
<label class="plan-card" :class="{ selected: paymentPlan === 'installments' }">
<input v-model="paymentPlan" type="radio" value="installments" />
<span class="plan-radio" aria-hidden="true"></span>
<div class="plan-content">
<div class="plan-top">
<strong>پرداخت دو قسطی</strong>
</div>
<p>
شهریه کامل بدون تخفیف. نیمی از مبلغ اکنون و قسط دوم در
{{ secondInstallmentDueLabel }} سررسید میشود.
</p>
<div class="plan-footer">
<span class="plan-price">{{ formatPrice(installmentPricing.amountDueNow) }}</span>
<span class="plan-note">اکنون · باقیمانده {{ formatPrice(installmentPricing.secondInstallmentAmount) }}</span>
</div>
</div>
</label>
</div>
<div v-else class="terms-box">
<h3>شرایط درخواست</h3>
<ul>
<li>
بیعانه معادل
{{ toPersianDigits(Math.round(CLASS_REQUEST_DEPOSIT_RATE * 100)) }}٪ شهریه:
<strong>{{ formatPrice(requestPricing.amountDueNow) }}</strong>
</li>
<li>اگر تا یک ماه آینده کلاس تشکیل نشود، کل بیعانه بدون کسر بازگردانده میشود.</li>
<li>در صورت انصراف شخصی، بخشی از بیعانه (طبق قوانین آموزشگاه) کسر میشود.</li>
<li>تا زمان تأیید نهایی توسط آموزشگاه، ثبتنام قطعی نیست.</li>
</ul>
</div>
<div class="checkout-box">
<div class="checkout-row checkout-row--total">
<span>مبلغ قابل پرداخت</span>
<strong>{{ formatPrice(activePricing.amountDueNow) }}</strong>
</div>
<div v-if="!isClassRequest && paymentPlan === 'full'" class="checkout-row">
<span>تخفیف پرداخت یکجا</span>
<span class="checkout-discount"> {{ formatPrice(activePricing.paymentDiscount) }}</span>
</div>
<div v-if="!isClassRequest && paymentPlan === 'installments'" class="checkout-row">
<span>قسط دوم · {{ secondInstallmentDueLabel }}</span>
<span>{{ formatPrice(activePricing.secondInstallmentAmount) }}</span>
</div>
</div>
<div class="gateway-banner">
<span class="gateway-icon" aria-hidden="true"></span>
<p>درگاه پرداخت بهزودی فعال میشود. پس از پرداخت، درخواست شما برای بررسی ثبت میشود.</p>
</div>
<div class="form-actions form-actions--split">
<button class="btn btn-ghost" type="button" @click="step = 1">بازگشت</button>
<button
class="btn btn-ink"
type="button"
disabled
title="درگاه پرداخت به‌زودی فعال می‌شود"
>
پرداخت {{ formatPrice(activePricing.amountDueNow) }}
</button>
</div>
</div>
</section>
</div>
</div>
</div>
</template>
<script setup>
import { computed, onMounted, reactive, ref } from 'vue'
import { RouterLink, useRoute } from 'vue-router'
import { registrationApi } from '@/api/registrationApi'
import {
CLASS_REQUEST_DEPOSIT_RATE,
FULL_PAYMENT_DISCOUNT,
calculateClassRequestPricing,
calculateEnrollmentPricing
} from '@/utils/registrationPricing'
import { formatJalali, formatPrice, getApiErrorMessage, toPersianDigits } from '@/utils/format'
const route = useRoute()
const isClassRequest = computed(() => route.meta.registrationType === 'class_request')
const pageTitle = computed(() =>
isClassRequest.value ? 'درخواست تشکیل کلاس جدید' : 'ثبت‌نام در کلاس پیش‌رو'
)
const cls = ref(null)
const loading = ref(true)
const loadError = ref('')
const step = ref(1)
const paymentPlan = ref('full')
const userId = ref(null)
const infoSubmitting = ref(false)
const formError = ref('')
const form = reactive({
name: '',
surname: '',
nationalIdCode: '',
phoneNumber: '',
email: ''
})
const errors = reactive({
name: '',
surname: '',
nationalIdCode: '',
phoneNumber: '',
email: ''
})
const fullPricing = computed(() =>
calculateEnrollmentPricing(cls.value || {}, cls.value?.course || {}, 'full')
)
const installmentPricing = computed(() =>
calculateEnrollmentPricing(cls.value || {}, cls.value?.course || {}, 'installments')
)
const requestPricing = computed(() => calculateClassRequestPricing(cls.value || {}))
const activePricing = computed(() => {
if (isClassRequest.value) return requestPricing.value
return paymentPlan.value === 'installments' ? installmentPricing.value : fullPricing.value
})
const pricing = computed(() => activePricing.value)
const secondInstallmentDueLabel = computed(() => {
const due = installmentPricing.value.secondInstallmentDueDate
return due ? formatJalali(due) : 'میانه دوره'
})
function normalizePhone(value) {
const phone = String(value || '').replace(/[\s\-()]/g, '').trim()
if (phone.startsWith('+98')) return `0${phone.slice(3)}`
if (/^9\d{9}$/.test(phone)) return `0${phone}`
return phone
}
function validateInfo() {
errors.name = form.name ? '' : 'نام الزامی است'
errors.surname = form.surname ? '' : 'نام خانوادگی الزامی است'
errors.nationalIdCode = form.nationalIdCode ? '' : 'کد ملی الزامی است'
errors.phoneNumber = form.phoneNumber ? '' : 'شماره موبایل الزامی است'
if (form.nationalIdCode && !/^\d{10}$/.test(form.nationalIdCode)) {
errors.nationalIdCode = 'کد ملی باید ۱۰ رقم باشد'
}
const phone = normalizePhone(form.phoneNumber)
if (form.phoneNumber && !/^09\d{9}$/.test(phone)) {
errors.phoneNumber = 'شماره موبایل معتبر نیست'
}
if (form.email && !/^\w+([.-]?\w+)*@\w+([.-]?\w+)*(\.\w{2,3})+$/.test(form.email)) {
errors.email = 'ایمیل معتبر نیست'
}
return !Object.values(errors).some(Boolean)
}
async function handleInfoSubmit() {
formError.value = ''
if (!validateInfo()) return
infoSubmitting.value = true
try {
const res = await registrationApi.ensureUser({
name: form.name,
surname: form.surname,
nationalIdCode: form.nationalIdCode,
phoneNumber: normalizePhone(form.phoneNumber),
email: form.email || undefined
})
userId.value = res.data?.data?.user?._id || res.data?.user?._id
step.value = 2
} catch (error) {
const details = error?.response?.data?.error?.details
if (details && typeof details === 'object') {
Object.entries(details).forEach(([key, value]) => {
if (key in errors) errors[key] = String(value)
})
}
formError.value = getApiErrorMessage(error, 'ثبت اطلاعات ناموفق بود.')
} finally {
infoSubmitting.value = false
}
}
onMounted(async () => {
const classId = route.params.classId
if (!classId) {
loadError.value = 'کلاس یافت نشد.'
loading.value = false
return
}
try {
const res = await registrationApi.getClass(classId)
cls.value = res.data?.data || res.data
} catch (error) {
loadError.value = getApiErrorMessage(error, 'بارگذاری اطلاعات کلاس ناموفق بود.')
} finally {
loading.value = false
}
})
</script>
<style scoped>
.registration-page {
min-height: 100vh;
padding: calc(var(--header-h) + 2rem) 0 3.5rem;
background:
radial-gradient(circle at 12% 0%, rgba(45, 106, 79, 0.1), transparent 42%),
radial-gradient(circle at 88% 8%, rgba(232, 163, 23, 0.1), transparent 38%),
linear-gradient(180deg, var(--canvas) 0%, var(--canvas-deep) 100%);
}
.page-head {
max-width: 42rem;
margin-bottom: 2rem;
}
.back-link {
display: inline-flex;
align-items: center;
gap: 0.35rem;
margin-bottom: 1rem;
font-size: 0.875rem;
font-weight: 600;
color: var(--ink-soft);
transition: color 0.2s ease;
}
.back-link:hover {
color: var(--leaf);
}
.page-eyebrow {
font-size: 0.8rem;
font-weight: 800;
letter-spacing: 0.02em;
color: var(--saffron-deep);
margin-bottom: 0.5rem;
}
.page-head h1 {
font-family: var(--font-display);
font-size: clamp(1.75rem, 3.2vw, 2.25rem);
margin-bottom: 0.5rem;
}
.page-lead {
font-size: 1.05rem;
color: var(--ink-soft);
}
.state-card {
background: var(--chalk);
border: 1px solid rgba(20, 53, 43, 0.08);
border-radius: 1.25rem;
padding: 2.5rem;
box-shadow: var(--shadow);
}
.registration-card {
display: grid;
grid-template-columns: minmax(240px, 300px) 1fr;
gap: 0;
max-width: 960px;
margin-inline: auto;
border-radius: 1.5rem;
overflow: hidden;
border: 1px solid rgba(20, 53, 43, 0.08);
box-shadow: var(--shadow);
background: var(--chalk);
}
.summary-panel {
background:
linear-gradient(165deg, rgba(45, 106, 79, 0.08) 0%, rgba(45, 106, 79, 0.02) 100%);
border-left: 1px solid rgba(20, 53, 43, 0.06);
}
.summary-inner {
padding: 2rem 1.75rem;
position: sticky;
top: calc(var(--header-h) + 1.5rem);
}
.summary-label {
font-size: 0.75rem;
font-weight: 800;
text-transform: uppercase;
letter-spacing: 0.04em;
color: var(--leaf);
margin-bottom: 0.65rem;
}
.summary-title {
font-size: 1.15rem;
line-height: 1.45;
margin-bottom: 1.5rem;
}
.summary-list {
margin: 0;
display: grid;
gap: 1rem;
}
.summary-item {
display: grid;
gap: 0.2rem;
}
.summary-item dt {
font-size: 0.78rem;
font-weight: 600;
color: var(--ink-soft);
}
.summary-item dd {
margin: 0;
font-size: 0.95rem;
font-weight: 700;
}
.summary-total {
margin-top: 1.75rem;
padding-top: 1.25rem;
border-top: 1px solid rgba(20, 53, 43, 0.1);
display: grid;
gap: 0.35rem;
}
.summary-total span {
font-size: 0.82rem;
color: var(--ink-soft);
}
.summary-total strong {
font-size: 1.2rem;
color: var(--leaf);
}
.form-panel {
padding: 2rem 2.25rem 2.25rem;
}
.stepper {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 2rem;
padding-bottom: 1.5rem;
border-bottom: 1px solid rgba(20, 53, 43, 0.08);
}
.stepper-item {
display: flex;
align-items: center;
gap: 0.55rem;
color: var(--ink-soft);
font-size: 0.875rem;
font-weight: 600;
}
.stepper-item.active {
color: var(--ink);
}
.stepper-item.done {
color: var(--leaf);
}
.stepper-dot {
width: 1.75rem;
height: 1.75rem;
border-radius: 50%;
display: grid;
place-items: center;
font-size: 0.78rem;
font-weight: 800;
background: rgba(20, 53, 43, 0.06);
flex-shrink: 0;
}
.stepper-item.active .stepper-dot {
background: var(--leaf);
color: var(--chalk);
}
.stepper-item.done .stepper-dot {
background: rgba(45, 106, 79, 0.15);
color: var(--leaf);
}
.stepper-line {
flex: 1;
height: 2px;
background: rgba(20, 53, 43, 0.1);
border-radius: 1px;
}
.step-header {
margin-bottom: 1.75rem;
}
.step-header h2 {
font-size: 1.25rem;
margin-bottom: 0.5rem;
}
.step-header p {
color: var(--ink-soft);
font-size: 0.925rem;
line-height: 1.75;
max-width: 36rem;
}
.fields-grid {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 1.25rem 1.5rem;
}
.field-wide {
grid-column: 1 / -1;
}
.field label {
display: block;
font-size: 0.875rem;
font-weight: 700;
margin-bottom: 0.45rem;
color: var(--ink);
}
.req {
color: var(--saffron-deep);
}
.optional {
font-weight: 500;
color: var(--ink-soft);
font-size: 0.8rem;
}
.field input {
width: 100%;
border: 1px solid rgba(20, 53, 43, 0.14);
border-radius: 0.75rem;
padding: 0.75rem 1rem;
background: #fff;
transition: border-color 0.2s ease, box-shadow 0.2s ease;
}
.field input:focus {
outline: none;
border-color: var(--leaf);
box-shadow: 0 0 0 3px rgba(45, 106, 79, 0.12);
}
.input-ltr {
text-align: left;
}
.field-error {
display: block;
margin-top: 0.35rem;
font-size: 0.8rem;
color: var(--danger);
}
.form-actions {
margin-top: 2rem;
padding-top: 0.25rem;
}
.form-actions--split {
display: flex;
align-items: center;
justify-content: space-between;
gap: 1rem;
flex-wrap: wrap;
}
.plan-options {
display: grid;
gap: 1rem;
margin-bottom: 1.5rem;
}
.plan-card {
position: relative;
display: flex;
align-items: flex-start;
gap: 1rem;
padding: 1.25rem 1.35rem;
border: 2px solid rgba(20, 53, 43, 0.1);
border-radius: 1rem;
cursor: pointer;
transition: border-color 0.2s ease, background 0.2s ease, box-shadow 0.2s ease;
}
.plan-card:hover {
border-color: rgba(45, 106, 79, 0.35);
}
.plan-card.selected {
border-color: var(--leaf);
background: rgba(45, 106, 79, 0.04);
box-shadow: 0 0 0 1px rgba(45, 106, 79, 0.15);
}
.plan-card input {
position: absolute;
opacity: 0;
pointer-events: none;
}
.plan-radio {
width: 1.25rem;
height: 1.25rem;
border-radius: 50%;
border: 2px solid rgba(20, 53, 43, 0.25);
flex-shrink: 0;
margin-top: 0.15rem;
position: relative;
}
.plan-card.selected .plan-radio {
border-color: var(--leaf);
}
.plan-card.selected .plan-radio::after {
content: '';
position: absolute;
inset: 3px;
border-radius: 50%;
background: var(--leaf);
}
.plan-content {
flex: 1;
min-width: 0;
}
.plan-top {
display: flex;
align-items: center;
gap: 0.6rem;
margin-bottom: 0.4rem;
}
.plan-top strong {
font-size: 1rem;
}
.plan-badge {
font-size: 0.7rem;
font-weight: 800;
padding: 0.15rem 0.5rem;
border-radius: 999px;
background: rgba(232, 163, 23, 0.18);
color: var(--saffron-deep);
}
.plan-content p {
margin: 0 0 0.85rem;
font-size: 0.875rem;
color: var(--ink-soft);
line-height: 1.7;
}
.highlight {
color: var(--saffron-deep);
font-weight: 800;
}
.plan-footer {
display: flex;
align-items: baseline;
flex-wrap: wrap;
gap: 0.5rem 1rem;
}
.plan-price {
font-size: 1.05rem;
font-weight: 800;
color: var(--ink);
}
.plan-note {
font-size: 0.8rem;
color: var(--ink-soft);
}
.terms-box {
margin-bottom: 1.5rem;
padding: 1.25rem 1.35rem;
border-radius: 1rem;
background: rgba(232, 163, 23, 0.07);
border: 1px solid rgba(232, 163, 23, 0.2);
}
.terms-box h3 {
font-size: 0.95rem;
margin-bottom: 0.75rem;
}
.terms-box ul {
margin: 0;
padding-right: 1.15rem;
color: var(--ink-soft);
font-size: 0.875rem;
line-height: 1.8;
}
.checkout-box {
padding: 1.25rem 1.35rem;
border-radius: 1rem;
background: rgba(20, 53, 43, 0.03);
border: 1px solid rgba(20, 53, 43, 0.08);
margin-bottom: 1.25rem;
}
.checkout-row {
display: flex;
justify-content: space-between;
align-items: center;
gap: 1rem;
padding: 0.4rem 0;
font-size: 0.9rem;
color: var(--ink-soft);
}
.checkout-row--total {
padding-bottom: 0.75rem;
margin-bottom: 0.5rem;
border-bottom: 1px dashed rgba(20, 53, 43, 0.12);
font-size: 1rem;
color: var(--ink);
}
.checkout-row--total strong {
font-size: 1.15rem;
color: var(--leaf);
}
.checkout-discount {
color: var(--saffron-deep);
font-weight: 700;
}
.gateway-banner {
display: flex;
align-items: flex-start;
gap: 0.75rem;
padding: 1rem 1.15rem;
margin-bottom: 1.75rem;
border-radius: 0.85rem;
background: rgba(45, 106, 79, 0.06);
border: 1px solid rgba(45, 106, 79, 0.12);
}
.gateway-icon {
font-size: 1.1rem;
line-height: 1.4;
}
.gateway-banner p {
font-size: 0.85rem;
color: var(--ink-soft);
line-height: 1.65;
}
.alert {
margin-bottom: 1.25rem;
padding: 0.85rem 1.1rem;
border-radius: 0.75rem;
background: rgba(180, 35, 24, 0.08);
color: #7a1a12;
font-size: 0.9rem;
}
.loading-block {
display: grid;
place-items: center;
min-height: 10rem;
}
@media (max-width: 820px) {
.registration-card {
grid-template-columns: 1fr;
max-width: 520px;
}
.summary-panel {
border-left: none;
border-bottom: 1px solid rgba(20, 53, 43, 0.08);
}
.summary-inner {
position: static;
padding: 1.5rem 1.75rem 1.25rem;
}
.summary-title {
margin-bottom: 1rem;
}
.summary-list {
grid-template-columns: repeat(3, 1fr);
gap: 0.75rem;
}
.summary-total {
margin-top: 1.25rem;
padding-top: 1rem;
}
.form-panel {
padding: 1.75rem 1.5rem 2rem;
}
.stepper-label {
font-size: 0.8rem;
}
}
@media (max-width: 560px) {
.registration-page {
padding-top: calc(var(--header-h) + 1.25rem);
}
.page-head {
margin-bottom: 1.5rem;
}
.fields-grid {
grid-template-columns: 1fr;
gap: 1.1rem;
}
.summary-list {
grid-template-columns: 1fr;
}
.form-actions--split {
flex-direction: column-reverse;
align-items: stretch;
}
.form-actions--split .btn {
width: 100%;
justify-content: center;
}
.stepper {
gap: 0.5rem;
}
.stepper-label {
display: none;
}
}
</style>