polish: fix padding and spacing across all sections to match Pencil design

- FeatureCard: px-7 pt-8 pb-8 (design: padding [32,28]), h-full for equal heights
- HeroSection: py-20 on mobile, gap-20 between columns, screenshot 380px
- PrivacyBanner: py-14, gap-20, stat items min-w-[100px]
- SeeItLiveSection: py-24, max-w-[640px] header, block img
- FeaturesSection: gap-[72px] section, flex wrapper for equal-height cards
- ScreenshotsSection: lg:h-[340px] images, px-6 py-5 info, gap-2
- HowItWorksSection: gap-20 columns, gap-10 steps, divide-y billing items, p-10 card
- SupportSection: py-24, gap-16, flex wrappers for equal-height cards
- ContactSection: py-20, gap-20, p-9 form card, gap-5 fields
- AppFooter: pt-14 pb-7, border-b [#1E293B], pt-5 bottom bar
This commit is contained in:
kevin-asprec
2026-03-17 04:31:21 +08:00
parent 2340ae58c6
commit 6199f78cfb
11 changed files with 139 additions and 136 deletions

View File

@@ -1,24 +1,22 @@
<script setup lang="ts">
import { Wrench, Zap, CircleCheck } from 'lucide-vue-next'
// Design: padding [96, 100], gap 80, layout horizontal
const steps = [
{
num: '1',
title: "We install TapTrack on your school's hardware",
description:
'Our team sets up the on-premises software and NFC reader. You pay a one-time implementation fee and you own the setup.',
description: 'Our team sets up the on-premises software and NFC reader. You pay a one-time implementation fee and you own the setup.',
},
{
num: '2',
title: 'We enrol your students and train your staff',
description:
'We import your student list, assign NFC ID cards, add parent numbers, and run a full walkthrough with your administrators.',
description: 'We import your student list, assign NFC ID cards, add parent numbers, and run a full walkthrough with your administrators.',
},
{
num: '3',
title: 'Top up SMS credits monthly as needed',
description:
'No recurring subscription. You purchase prepaid SMS credits when you need them. The system keeps sending alerts as long as your credits last.',
description: 'No recurring subscription. You purchase prepaid SMS credits when you need them. The system keeps sending alerts as long as your credits last.',
},
]
@@ -42,10 +40,12 @@ const billingItems = [
<template>
<section id="how-it-works" class="bg-[#F8FAFF]">
<div class="page-container flex flex-col lg:flex-row gap-16 xl:gap-20 py-24">
<div class="page-container flex flex-col lg:flex-row gap-20 py-24">
<!-- Left: Steps -->
<!-- Left column: gap 40 -->
<div v-reveal class="flex-1 flex flex-col gap-10 min-w-0">
<!-- Header: gap 10 -->
<div class="flex flex-col gap-2.5">
<span class="text-[#1D4ED8] font-semibold text-[11px] tracking-[2px] uppercase">
How It Works
@@ -58,16 +58,19 @@ const billingItems = [
</p>
</div>
<div class="flex flex-col gap-8">
<!-- Steps: gap 40, each step gap 20 -->
<div class="flex flex-col gap-10">
<div
v-for="(step, i) in steps"
:key="step.num"
v-reveal="{ delay: i * 100 }"
class="flex items-start gap-5"
>
<!-- Number bubble: 36×36, cornerRadius 18 -->
<div class="w-9 h-9 rounded-full bg-[#1D4ED8] flex items-center justify-center shrink-0 mt-0.5">
<span class="text-white font-bold text-[15px] leading-none">{{ step.num }}</span>
</div>
<!-- Step content: gap 6 -->
<div class="flex flex-col gap-1.5 min-w-0">
<h3 class="text-[#0F172A] font-semibold text-[15px] leading-snug">{{ step.title }}</h3>
<p class="text-[#64748B] text-[13px] leading-[1.6]">{{ step.description }}</p>
@@ -76,20 +79,22 @@ const billingItems = [
</div>
</div>
<!-- Right: Billing card -->
<!-- Right: Billing card, width 460, padding 40, gap 24, cornerRadius 20 -->
<div v-reveal="{ delay: 150 }" class="w-full lg:w-[460px] shrink-0">
<div class="bg-white border border-[#E2E8F0] rounded-[20px] p-8 lg:p-10 flex flex-col gap-6">
<h3 class="text-[#0F172A] font-bold text-xl">How billing works</h3>
<p class="text-[#64748B] text-[14px] leading-[1.6]">
Transparent, no surprises. You only pay for what you actually use.
</p>
<div class="bg-white border border-[#E2E8F0] rounded-[20px] p-10 flex flex-col gap-6 h-full">
<div class="flex flex-col gap-2">
<h3 class="text-[#0F172A] font-bold text-xl">How billing works</h3>
<p class="text-[#64748B] text-[14px] leading-[1.6]">
Transparent, no surprises. You only pay for what you actually use.
</p>
</div>
<div class="flex flex-col">
<!-- Billing items -->
<div class="flex flex-col divide-y divide-[#F1F5F9]">
<div
v-for="(item, i) in billingItems"
v-for="item in billingItems"
:key="item.title"
class="flex items-start gap-3.5 py-4"
:class="i === 0 ? 'border-b border-[#F1F5F9]' : ''"
class="flex items-start gap-3.5 py-4 first:pt-0 last:pb-0"
>
<div
class="w-9 h-9 rounded-lg flex items-center justify-center shrink-0"
@@ -97,13 +102,14 @@ const billingItems = [
>
<component :is="item.icon" :size="18" :stroke-width="1.75" :style="{ color: item.iconColor }" />
</div>
<div class="flex flex-col gap-0.5 min-w-0">
<div class="flex flex-col gap-1 min-w-0">
<span class="text-[#0F172A] font-semibold text-[14px]">{{ item.title }}</span>
<span class="text-[#64748B] text-[13px] leading-[1.5]">{{ item.description }}</span>
</div>
</div>
</div>
<!-- Note: fill #F0FDF4, cornerRadius 8, padding [12,14], gap 10 -->
<div class="flex items-start gap-2.5 bg-[#F0FDF4] rounded-lg px-3.5 py-3">
<CircleCheck :size="16" :stroke-width="2" class="text-[#16A34A] shrink-0 mt-0.5" />
<p class="text-[#15803D] text-[13px] leading-[1.5]">