Optimize PK page responsive layout

This commit is contained in:
2026-06-30 16:22:55 +08:00
parent a5a35272fe
commit 68bc72ff2a
2 changed files with 356 additions and 43 deletions
+310
View File
@@ -46,7 +46,317 @@
@layer utilities { @layer utilities {
.pk-start-stage,
.pk-end-stage,
.pk-game-stage {
overflow-x: hidden;
}
.pk-game-stage {
display: grid;
place-items: center;
}
.pk-game-card {
display: flex;
flex-direction: column;
justify-content: center;
width: 100%;
}
.cursor-hammer {
--hammer-cursor: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 32 32'%3E%3Cg transform='rotate(-36 16 16)'%3E%3Crect x='14' y='9' width='4' height='20' rx='2' fill='%23815a2f'/%3E%3Crect x='13' y='8' width='6' height='3' rx='1.5' fill='%236b4220'/%3E%3Cpath d='M8 5h14c1.7 0 3 1.3 3 3v4c0 1.7-1.3 3-3 3H8c-1.7 0-3-1.3-3-3V8c0-1.7 1.3-3 3-3Z' fill='%23f2b84b'/%3E%3Cpath d='M8 5h5v10H8c-1.7 0-3-1.3-3-3V8c0-1.7 1.3-3 3-3Z' fill='%23d78a2a'/%3E%3Cpath d='M19 5h3c1.7 0 3 1.3 3 3v4c0 1.7-1.3 3-3 3h-3V5Z' fill='%23999'/%3E%3Cpath d='M19 5h3c1.7 0 3 1.3 3 3v1h-6V5Z' fill='%23c9c9c9'/%3E%3C/g%3E%3C/svg%3E") 10 26, auto;
cursor: var(--hammer-cursor);
}
.cursor-hammer * {
cursor: var(--hammer-cursor) !important;
}
.text-balance { .text-balance {
text-wrap: balance; text-wrap: balance;
} }
@media (max-height: 820px) and (min-width: 768px) {
.pk-start-stage,
.pk-end-stage {
padding-block: 0.75rem !important;
}
.pk-start-card,
.pk-end-card {
border-radius: 1.25rem !important;
padding: clamp(14px, 2.25vw, 28px) !important;
}
.pk-start-visual {
font-size: clamp(46px, 11vh, 78px) !important;
margin-bottom: 0.25rem !important;
}
.pk-start-title {
font-size: clamp(26px, 5.2vh, 38px) !important;
}
.pk-start-subtitle {
font-size: clamp(14px, 2.3vh, 17px) !important;
margin-top: 0.375rem !important;
}
.pk-start-panel {
gap: 0.65rem !important;
margin-top: 1rem !important;
padding: 0.85rem !important;
}
.pk-start-choice {
font-size: 0.95rem !important;
padding-block: 0.55rem !important;
}
.pk-start-summary {
font-size: 0.8rem !important;
padding-block: 0.45rem !important;
}
.pk-start-warning {
margin-top: 0.65rem !important;
}
.pk-start-button {
font-size: 1.05rem !important;
margin-top: 1rem !important;
padding: 0.65rem 2rem !important;
}
.pk-end-visual {
font-size: clamp(54px, 11vh, 86px) !important;
margin-bottom: 0.5rem !important;
}
.pk-end-title {
font-size: clamp(28px, 5.2vh, 42px) !important;
}
.pk-end-result {
font-size: clamp(24px, 4.8vh, 36px) !important;
margin-top: 0.5rem !important;
}
.pk-end-score-grid {
margin-top: 1rem !important;
}
.pk-end-score-card {
padding: 1rem !important;
}
.pk-end-score {
font-size: 2rem !important;
}
.pk-end-button {
margin-top: 1rem !important;
padding: 0.75rem 2rem !important;
}
.pk-game-stage {
padding-block: 0.5rem !important;
}
.pk-game-card {
border-radius: 1.25rem !important;
min-height: calc(100svh - 56px - 1rem) !important;
padding: clamp(10px, 1.6vw, 18px) !important;
}
.pk-game-header {
margin-bottom: 0.5rem !important;
}
.pk-game-title {
font-size: clamp(24px, 4.2vh, 30px) !important;
}
.pk-game-meta {
font-size: 0.8rem !important;
margin-top: 0.15rem !important;
}
.pk-game-grid {
gap: clamp(10px, 1.6vw, 18px) !important;
}
.pk-team-card {
border-width: 3px !important;
padding: 0.5rem !important;
}
.pk-team-label {
font-size: clamp(14px, 2.4vh, 18px) !important;
}
.pk-team-score {
font-size: clamp(26px, 5vh, 40px) !important;
}
.pk-current-turn {
font-size: clamp(16px, 2.8vh, 20px) !important;
margin-top: 0.55rem !important;
padding-block: 0.45rem !important;
}
.pk-listen-area {
padding-block: clamp(8px, 2vh, 18px) !important;
}
.pk-speak-button {
height: clamp(50px, 8vh, 62px) !important;
margin-top: 0.4rem !important;
width: clamp(50px, 8vh, 62px) !important;
}
.pk-word-text-hero {
margin-top: 0.5rem !important;
text-shadow: 2px 2px 0 #dbeafe !important;
}
.pk-word-text-hero.pk-word-size-large {
font-size: clamp(38px, 7.4vh, 56px) !important;
}
.pk-word-text-hero.pk-word-size-medium {
font-size: clamp(32px, 6.4vh, 48px) !important;
}
.pk-word-text-hero.pk-word-size-small {
font-size: clamp(23px, 5vh, 34px) !important;
}
.pk-answer-grid {
gap: 0.65rem !important;
}
.pk-option-button {
border-radius: 1rem !important;
min-height: clamp(82px, 13.5vh, 118px) !important;
padding: 0.6rem !important;
}
.pk-word-image {
height: clamp(40px, 7vh, 60px) !important;
width: clamp(40px, 7vh, 60px) !important;
}
.pk-word-emoji {
font-size: clamp(34px, 6.8vh, 54px) !important;
}
.pk-word-text-option {
margin-top: 0.35rem !important;
}
.pk-word-text-option.pk-word-size-large {
font-size: clamp(23px, 4.2vh, 32px) !important;
}
.pk-word-text-option.pk-word-size-medium {
font-size: clamp(20px, 3.8vh, 28px) !important;
}
.pk-word-text-option.pk-word-size-small {
font-size: clamp(17px, 3.3vh, 24px) !important;
}
.pk-answer-feedback {
font-size: clamp(14px, 2.7vh, 18px) !important;
gap: 0.5rem !important;
padding: 0.65rem 1rem !important;
}
}
@media (max-height: 700px) and (min-width: 768px) {
.pk-start-stage,
.pk-end-stage,
.pk-game-stage {
place-items: start center !important;
padding-block: 0.5rem !important;
}
.pk-start-card,
.pk-end-card,
.pk-game-card {
box-shadow: 0 10px 28px rgba(15, 23, 42, 0.1) !important;
min-height: auto !important;
padding: 0.75rem !important;
}
.pk-start-visual {
font-size: clamp(38px, 9vh, 58px) !important;
}
.pk-start-title {
font-size: clamp(24px, 5vh, 32px) !important;
}
.pk-start-subtitle {
font-size: 0.9rem !important;
}
.pk-start-panel {
gap: 0.5rem !important;
margin-top: 0.75rem !important;
padding: 0.65rem !important;
}
.pk-start-choice {
padding-block: 0.45rem !important;
}
.pk-start-summary {
font-size: 0.75rem !important;
}
.pk-start-button {
margin-top: 0.75rem !important;
padding: 0.55rem 1.75rem !important;
}
.pk-end-visual {
font-size: clamp(42px, 9vh, 64px) !important;
}
.pk-end-result,
.pk-end-score-grid,
.pk-end-button {
margin-top: 0.75rem !important;
}
.pk-game-title {
font-size: clamp(22px, 4.8vh, 28px) !important;
}
.pk-current-turn {
margin-top: 0.5rem !important;
padding-block: 0.45rem !important;
}
.pk-listen-area {
padding-block: 0.5rem !important;
}
.pk-option-button {
min-height: clamp(78px, 14vh, 108px) !important;
}
}
@media (max-height: 560px), (max-width: 767px) {
.pk-start-stage,
.pk-end-stage,
.pk-game-stage {
align-items: start !important;
overflow-y: auto;
padding-block: 0.75rem !important;
}
}
} }
+46 -43
View File
@@ -35,6 +35,7 @@ type AppSettings = {
}; };
const grades: Grade[] = ["小班", "中班", "大班"]; const grades: Grade[] = ["小班", "中班", "大班"];
const pkPageCursorClass = "cursor-hammer";
function shuffleArray<T>(array: T[]) { function shuffleArray<T>(array: T[]) {
const next = [...array]; const next = [...array];
@@ -58,14 +59,14 @@ function TeamCard({
return ( return (
<div <div
className={cn( className={cn(
"flex-1 rounded-lg border-4 p-[clamp(10px,1.6vw,16px)] text-center transition", "pk-team-card flex-1 rounded-lg border-4 p-[clamp(10px,1.6vw,16px)] text-center transition",
red ? "bg-red-50 text-red-700" : "bg-blue-50 text-blue-700", red ? "bg-red-50 text-red-700" : "bg-blue-50 text-blue-700",
active && (red ? "border-red-400 shadow-lg" : "border-blue-400 shadow-lg"), active && (red ? "border-red-400 shadow-lg" : "border-blue-400 shadow-lg"),
!active && "border-transparent", !active && "border-transparent",
)} )}
> >
<div className="text-[clamp(16px,1.8vw,22px)] font-bold">{red ? "🔴 红队" : "🔵 蓝队"}</div> <div className="pk-team-label text-[clamp(16px,1.8vw,22px)] font-bold">{red ? "🔴 红队" : "🔵 蓝队"}</div>
<div className="text-[clamp(30px,4vw,48px)] font-black leading-tight">{score}</div> <div className="pk-team-score text-[clamp(30px,4vw,48px)] font-black leading-tight">{score}</div>
</div> </div>
); );
} }
@@ -292,25 +293,25 @@ export default function PkPage() {
if (!started) { if (!started) {
return ( return (
<main className="mx-auto grid min-h-[calc(100vh-56px)] max-w-5xl place-items-center px-4 py-8"> <main className={cn(pkPageCursorClass, "pk-start-stage mx-auto grid min-h-[calc(100vh-56px)] max-w-5xl place-items-center px-4 py-4")}>
<section className="w-full rounded-[28px] bg-white p-[clamp(24px,5vw,64px)] text-center shadow-soft"> <section className="pk-start-card w-full rounded-[24px] bg-white p-[clamp(18px,3vw,36px)] text-center shadow-soft">
<div className="mb-5 text-[clamp(72px,11vw,126px)] leading-none">🦊 VS 🦓</div> <div className="pk-start-visual mb-2 text-[clamp(54px,8vw,92px)] leading-none">🦊 VS 🦓</div>
<h1 className="text-balance text-[clamp(32px,5vw,56px)] font-black text-rose-500">PK赛</h1> <h1 className="pk-start-title text-balance text-[clamp(28px,4vw,44px)] font-black text-rose-500">PK赛</h1>
<p className="mt-4 text-[clamp(17px,2vw,22px)] text-slate-600"> <p className="pk-start-subtitle mt-2 text-[clamp(15px,1.6vw,19px)] text-slate-600">
{settings.scorePerCorrect} {settings.scorePerCorrect}
{settings.scorePerWrong > 0 ? `,答错扣${settings.scorePerWrong}分。` : ",答错不扣分。"} {settings.scorePerWrong > 0 ? `,答错扣${settings.scorePerWrong}分。` : ",答错不扣分。"}
</p> </p>
<div className="mx-auto mt-8 grid max-w-3xl gap-5 rounded-2xl border bg-slate-50 p-5 text-left sm:p-6"> <div className="pk-start-panel mx-auto mt-5 grid max-w-3xl gap-3 rounded-2xl border bg-slate-50 p-4 text-left">
<div> <div>
<div className="mb-3 text-sm font-semibold text-slate-600"></div> <div className="mb-2 text-xs font-semibold text-slate-600"></div>
<div className="grid grid-cols-3 gap-3"> <div className="grid grid-cols-3 gap-3">
{grades.map((grade) => ( {grades.map((grade) => (
<button <button
key={grade} key={grade}
onClick={() => setSelectedGrade(grade)} onClick={() => setSelectedGrade(grade)}
className={cn( className={cn(
"rounded-lg border bg-white px-4 py-3 text-center text-base font-bold transition hover:border-rose-300", "pk-start-choice rounded-lg border bg-white px-4 py-2.5 text-center text-base font-bold transition hover:border-rose-300",
selectedGrade === grade && "border-rose-500 bg-rose-50 text-rose-700 shadow-sm", selectedGrade === grade && "border-rose-500 bg-rose-50 text-rose-700 shadow-sm",
)} )}
> >
@@ -321,14 +322,14 @@ export default function PkPage() {
</div> </div>
<div> <div>
<div className="mb-3 text-sm font-semibold text-slate-600"></div> <div className="mb-2 text-xs font-semibold text-slate-600"></div>
<div className="grid grid-cols-1 gap-3 sm:grid-cols-3"> <div className="grid grid-cols-1 gap-3 sm:grid-cols-3">
{classTypes.map((classType) => ( {classTypes.map((classType) => (
<button <button
key={classType.id} key={classType.id}
onClick={() => setSelectedClassTypeId(classType.id)} onClick={() => setSelectedClassTypeId(classType.id)}
className={cn( className={cn(
"rounded-lg border bg-white px-4 py-3 text-center text-base font-bold transition hover:border-blue-300", "pk-start-choice rounded-lg border bg-white px-4 py-2.5 text-center text-base font-bold transition hover:border-blue-300",
selectedClassTypeId === classType.id && "border-blue-500 bg-blue-50 text-blue-700 shadow-sm", selectedClassTypeId === classType.id && "border-blue-500 bg-blue-50 text-blue-700 shadow-sm",
)} )}
> >
@@ -338,7 +339,7 @@ export default function PkPage() {
</div> </div>
</div> </div>
<div className="rounded-lg bg-white px-4 py-3 text-center text-sm text-slate-600"> <div className="pk-start-summary rounded-lg bg-white px-4 py-2 text-center text-sm text-slate-600">
<span className="font-bold text-slate-900">{selectedGrade}</span> <span className="font-bold text-slate-900">{selectedGrade}</span>
<span className="mx-2 text-slate-300">/</span> <span className="mx-2 text-slate-300">/</span>
<span className="font-bold text-slate-900">{selectedClassType?.name ?? "未选择班型"}</span> <span className="font-bold text-slate-900">{selectedClassType?.name ?? "未选择班型"}</span>
@@ -350,13 +351,13 @@ export default function PkPage() {
</div> </div>
{!loadingSetup && availableWords.length === 0 && ( {!loadingSetup && availableWords.length === 0 && (
<p className="mt-4 text-sm font-medium text-red-500"></p> <p className="pk-start-warning mt-4 text-sm font-medium text-red-500"></p>
)} )}
<button <button
onClick={startGame} onClick={startGame}
disabled={loadingSetup || availableWords.length === 0} disabled={loadingSetup || availableWords.length === 0}
className="mt-8 rounded-full bg-rose-500 px-12 py-4 text-[clamp(18px,2vw,24px)] font-bold text-white shadow-lg transition hover:bg-rose-600 disabled:cursor-not-allowed disabled:bg-slate-300 disabled:shadow-none" className="pk-start-button mt-5 rounded-full bg-rose-500 px-10 py-3 text-[clamp(17px,1.8vw,21px)] font-bold text-white shadow-lg transition hover:bg-rose-600 disabled:cursor-not-allowed disabled:bg-slate-300 disabled:shadow-none"
> >
{loadingSetup ? "加载中..." : "开始PK"} {loadingSetup ? "加载中..." : "开始PK"}
</button> </button>
@@ -367,13 +368,13 @@ export default function PkPage() {
if (ended) { if (ended) {
return ( return (
<main className="mx-auto grid min-h-[calc(100vh-56px)] max-w-5xl place-items-center px-4 py-8"> <main className={cn(pkPageCursorClass, "pk-end-stage mx-auto grid min-h-[calc(100vh-56px)] max-w-5xl place-items-center px-4 py-8")}>
<section className="w-full rounded-[28px] bg-white p-[clamp(28px,6vw,72px)] text-center shadow-soft"> <section className="pk-end-card w-full rounded-[28px] bg-white p-[clamp(28px,6vw,72px)] text-center shadow-soft">
<div className="mb-5 text-[clamp(72px,10vw,118px)] leading-none">{winner === "draw" ? "🤝" : "🏆"}</div> <div className="pk-end-visual mb-5 text-[clamp(72px,10vw,118px)] leading-none">{winner === "draw" ? "🤝" : "🏆"}</div>
<h1 className="text-[clamp(32px,5vw,54px)] font-black text-rose-500">PK结束</h1> <h1 className="pk-end-title text-[clamp(32px,5vw,54px)] font-black text-rose-500">PK结束</h1>
<p <p
className={cn( className={cn(
"mt-4 text-[clamp(26px,4vw,44px)] font-black", "pk-end-result mt-4 text-[clamp(26px,4vw,44px)] font-black",
winner === "red" && "text-red-600", winner === "red" && "text-red-600",
winner === "blue" && "text-blue-600", winner === "blue" && "text-blue-600",
winner === "draw" && "text-amber-500", winner === "draw" && "text-amber-500",
@@ -381,19 +382,19 @@ export default function PkPage() {
> >
{winner === "red" ? "🔴 红队获胜!" : winner === "blue" ? "🔵 蓝队获胜!" : "平局!势均力敌!"} {winner === "red" ? "🔴 红队获胜!" : winner === "blue" ? "🔵 蓝队获胜!" : "平局!势均力敌!"}
</p> </p>
<div className="mx-auto mt-8 grid max-w-lg grid-cols-2 gap-4"> <div className="pk-end-score-grid mx-auto mt-8 grid max-w-lg grid-cols-2 gap-4">
<div className="rounded-lg bg-red-50 p-5 text-red-700"> <div className="pk-end-score-card rounded-lg bg-red-50 p-5 text-red-700">
<div className="font-bold"></div> <div className="font-bold"></div>
<div className="text-4xl font-black">{scoreRed}</div> <div className="pk-end-score text-4xl font-black">{scoreRed}</div>
</div> </div>
<div className="rounded-lg bg-blue-50 p-5 text-blue-700"> <div className="pk-end-score-card rounded-lg bg-blue-50 p-5 text-blue-700">
<div className="font-bold"></div> <div className="font-bold"></div>
<div className="text-4xl font-black">{scoreBlue}</div> <div className="pk-end-score text-4xl font-black">{scoreBlue}</div>
</div> </div>
</div> </div>
<button <button
onClick={startGame} onClick={startGame}
className="mt-8 inline-flex items-center gap-2 rounded-full bg-rose-500 px-10 py-4 text-lg font-bold text-white shadow-lg transition hover:bg-rose-600" className="pk-end-button mt-8 inline-flex items-center gap-2 rounded-full bg-rose-500 px-10 py-4 text-lg font-bold text-white shadow-lg transition hover:bg-rose-600"
> >
<RotateCcw className="size-5" /> <RotateCcw className="size-5" />
@@ -404,12 +405,12 @@ export default function PkPage() {
} }
return ( return (
<main className="mx-auto min-h-[calc(100vh-56px)] max-w-7xl px-4 py-5 sm:px-6 sm:py-8"> <main className={cn(pkPageCursorClass, "pk-game-stage mx-auto min-h-[calc(100vh-56px)] max-w-7xl px-4 py-5 sm:px-6 sm:py-8")}>
<section className="relative overflow-hidden rounded-[28px] bg-white p-[clamp(18px,3vw,34px)] shadow-soft"> <section className="pk-game-card relative overflow-hidden rounded-[28px] bg-white p-[clamp(18px,3vw,34px)] shadow-soft">
{answerState !== "idle" && ( {answerState !== "idle" && (
<div <div
className={cn( className={cn(
"z-10 mb-4 flex flex-col items-center gap-3 rounded-lg border bg-white/95 px-4 py-3 text-center text-[clamp(16px,1.8vw,22px)] font-black shadow-lg backdrop-blur md:absolute md:right-[clamp(18px,3vw,34px)] md:top-[clamp(18px,3vw,34px)] md:mb-0 md:max-w-[360px]", "pk-answer-feedback z-10 mb-4 flex flex-col items-center gap-3 rounded-lg border bg-white/95 px-4 py-3 text-center text-[clamp(16px,1.8vw,22px)] font-black shadow-lg backdrop-blur md:absolute md:right-[clamp(18px,3vw,34px)] md:top-[clamp(18px,3vw,34px)] md:mb-0 md:max-w-[360px]",
answerState === "correct" && "border-emerald-100 text-emerald-600", answerState === "correct" && "border-emerald-100 text-emerald-600",
answerState === "wrong" && "border-red-100 text-red-500", answerState === "wrong" && "border-red-100 text-red-500",
)} )}
@@ -431,14 +432,14 @@ export default function PkPage() {
</div> </div>
)} )}
<div className="mb-[clamp(12px,2vw,22px)] text-center"> <div className="pk-game-header mb-[clamp(12px,2vw,22px)] text-center">
<h1 className="text-[clamp(26px,3vw,38px)] font-black text-rose-500">PK大作战</h1> <h1 className="pk-game-title text-[clamp(26px,3vw,38px)] font-black text-rose-500">PK大作战</h1>
<p className="mt-2 text-sm font-medium text-slate-500"> <p className="pk-game-meta mt-2 text-sm font-medium text-slate-500">
{selectedGrade} / {selectedClassType?.name ?? "班型"} / {roundWords.length} {selectedGrade} / {selectedClassType?.name ?? "班型"} / {roundWords.length}
</p> </p>
</div> </div>
<div className="grid gap-[clamp(18px,3vw,34px)] lg:grid-cols-[minmax(300px,0.9fr)_minmax(420px,1.25fr)]"> <div className="pk-game-grid grid gap-[clamp(18px,3vw,34px)] lg:grid-cols-[minmax(300px,0.9fr)_minmax(420px,1.25fr)]">
<div className="flex min-w-0 flex-col"> <div className="flex min-w-0 flex-col">
<div className="flex items-center gap-[clamp(10px,1.8vw,18px)]"> <div className="flex items-center gap-[clamp(10px,1.8vw,18px)]">
<TeamCard team="red" active={currentTeam === "red"} score={scoreRed} /> <TeamCard team="red" active={currentTeam === "red"} score={scoreRed} />
@@ -448,7 +449,7 @@ export default function PkPage() {
<div <div
className={cn( className={cn(
"mt-4 rounded-lg px-4 py-3 text-center text-[clamp(18px,2vw,23px)] font-black", "pk-current-turn mt-4 rounded-lg px-4 py-3 text-center text-[clamp(18px,2vw,23px)] font-black",
currentTeam === "red" ? "bg-red-50 text-red-700" : "bg-blue-50 text-blue-700", currentTeam === "red" ? "bg-red-50 text-red-700" : "bg-blue-50 text-blue-700",
)} )}
> >
@@ -459,11 +460,11 @@ export default function PkPage() {
<div className="h-full rounded-full bg-emerald-500 transition-all" style={{ width: `${progress}%` }} /> <div className="h-full rounded-full bg-emerald-500 transition-all" style={{ width: `${progress}%` }} />
</div> </div>
<div className="flex flex-1 flex-col items-center justify-center py-[clamp(24px,5vw,70px)] text-center"> <div className="pk-listen-area flex flex-1 flex-col items-center justify-center py-[clamp(24px,5vw,70px)] text-center">
<p className="text-[clamp(16px,1.7vw,20px)] text-slate-600"></p> <p className="text-[clamp(16px,1.7vw,20px)] text-slate-600"></p>
<button <button
onClick={() => void speakWord(currentWord)} onClick={() => void speakWord(currentWord)}
className="mt-4 grid size-[clamp(62px,6vw,80px)] place-items-center rounded-full bg-rose-400 text-white shadow-lg transition hover:scale-105 hover:bg-rose-500" className="pk-speak-button mt-4 grid size-[clamp(62px,6vw,80px)] place-items-center rounded-full bg-rose-400 text-white shadow-lg transition hover:scale-105 hover:bg-rose-500"
aria-label="重新朗读当前单词" aria-label="重新朗读当前单词"
> >
<Volume2 className="size-[clamp(28px,3vw,36px)]" /> <Volume2 className="size-[clamp(28px,3vw,36px)]" />
@@ -476,7 +477,7 @@ export default function PkPage() {
<div className="flex min-w-0 flex-col justify-center"> <div className="flex min-w-0 flex-col justify-center">
<div <div
className={cn( className={cn(
"grid grid-cols-1 gap-[clamp(14px,2vw,22px)] sm:grid-cols-2", "pk-answer-grid grid grid-cols-1 gap-[clamp(14px,2vw,22px)] sm:grid-cols-2",
optionCount >= 6 && "xl:grid-cols-3", optionCount >= 6 && "xl:grid-cols-3",
)} )}
> >
@@ -489,7 +490,7 @@ export default function PkPage() {
key={option.id} key={option.id}
onClick={() => checkAnswer(option)} onClick={() => checkAnswer(option)}
className={cn( className={cn(
"flex min-h-[clamp(104px,18vh,188px)] flex-col items-center justify-center rounded-[20px] border-4 bg-white p-4 text-[clamp(22px,3vw,34px)] font-black transition hover:-translate-y-1 hover:border-sky-300 hover:shadow-lg", "pk-option-button flex min-h-[clamp(104px,18vh,188px)] flex-col items-center justify-center rounded-[20px] border-4 bg-white p-4 text-[clamp(22px,3vw,34px)] font-black transition hover:-translate-y-1 hover:border-sky-300 hover:shadow-lg",
answerState === "idle" && "border-slate-200", answerState === "idle" && "border-slate-200",
revealCorrect && "border-emerald-400 bg-emerald-50 text-emerald-700", revealCorrect && "border-emerald-400 bg-emerald-50 text-emerald-700",
selected && answerState === "wrong" && "border-red-400 bg-red-50 text-red-700", selected && answerState === "wrong" && "border-red-400 bg-red-50 text-red-700",
@@ -537,8 +538,10 @@ function AdaptiveWordText({ text, variant }: { text: string; variant: "hero" | "
<span <span
className={cn( className={cn(
"mx-auto block max-w-full whitespace-pre-line text-center font-black leading-[1.05] tracking-normal", "mx-auto block max-w-full whitespace-pre-line text-center font-black leading-[1.05] tracking-normal",
variant === "hero" && "mt-4 text-blue-500 [text-shadow:3px_3px_0_#dbeafe]", "pk-word-text",
variant === "option" && "mt-3 text-slate-900", variant === "hero" && "pk-word-text-hero mt-4 text-blue-500 [text-shadow:3px_3px_0_#dbeafe]",
variant === "option" && "pk-word-text-option mt-3 text-slate-900",
`pk-word-size-${size}`,
sizeClass, sizeClass,
isVeryLongSingleWord && "max-w-[min(100%,14ch)] [overflow-wrap:anywhere]", isVeryLongSingleWord && "max-w-[min(100%,14ch)] [overflow-wrap:anywhere]",
)} )}
@@ -608,10 +611,10 @@ function WordImage({ value, label }: { value: string; label: string }) {
<img <img
src={value} src={value}
alt={label} alt={label}
className="size-[clamp(54px,7vw,92px)] rounded-lg object-contain" className="pk-word-image size-[clamp(54px,7vw,92px)] rounded-lg object-contain"
/> />
); );
} }
return <span className="text-[clamp(44px,6vw,76px)] leading-none">{value}</span>; return <span className="pk-word-emoji text-[clamp(44px,6vw,76px)] leading-none">{value}</span>;
} }