diff --git a/playwright-report/index.html b/playwright-report/index.html index 1d7ebd8..71a4977 100644 --- a/playwright-report/index.html +++ b/playwright-report/index.html @@ -82,4 +82,4 @@ Error generating stack: `+n.message+`
- \ No newline at end of file + \ No newline at end of file diff --git a/src/components/App.tsx b/src/components/App.tsx index 12e03c8..86a562c 100644 --- a/src/components/App.tsx +++ b/src/components/App.tsx @@ -1,5 +1,5 @@ import { h } from 'preact'; -import { useEffect, useCallback } from 'preact/hooks'; +import { useCallback } from 'preact/hooks'; import { useGameState, @@ -35,51 +35,6 @@ export default function App() { const validationModal = useValidationModal(); const completionModal = useCompletionModal(); - // Keep layout height stable when the virtual keyboard opens on cheap Android tablets. - useEffect(() => { - const root = document.documentElement; - let rafId = 0; - let orientationTimer1 = 0; - let orientationTimer2 = 0; - - const updateViewportVars = () => { - cancelAnimationFrame(rafId); - rafId = requestAnimationFrame(() => { - const viewport = window.visualViewport; - const layoutHeight = window.innerHeight; - const appHeight = viewport?.height ?? layoutHeight; - const keyboardOffset = viewport - ? Math.max(0, layoutHeight - viewport.height - viewport.offsetTop) - : 0; - - root.style.setProperty('--app-height', `${Math.round(appHeight)}px`); - root.style.setProperty('--keyboard-offset', `${Math.round(keyboardOffset)}px`); - }); - }; - - const handleOrientationChange = () => { - updateViewportVars(); - orientationTimer1 = window.setTimeout(updateViewportVars, 100); - orientationTimer2 = window.setTimeout(updateViewportVars, 350); - }; - - updateViewportVars(); - window.addEventListener('resize', updateViewportVars); - window.addEventListener('orientationchange', handleOrientationChange); - window.visualViewport?.addEventListener('resize', updateViewportVars); - window.visualViewport?.addEventListener('scroll', updateViewportVars); - - return () => { - cancelAnimationFrame(rafId); - window.clearTimeout(orientationTimer1); - window.clearTimeout(orientationTimer2); - window.removeEventListener('resize', updateViewportVars); - window.removeEventListener('orientationchange', handleOrientationChange); - window.visualViewport?.removeEventListener('resize', updateViewportVars); - window.visualViewport?.removeEventListener('scroll', updateViewportVars); - }; - }, []); - // Game lifecycle handlers const handleCreateGame = useCallback(async (gameData: any) => { try { diff --git a/src/components/FullscreenToggle.module.css b/src/components/FullscreenToggle.module.css index 8fb1cdf..32aa876 100644 --- a/src/components/FullscreenToggle.module.css +++ b/src/components/FullscreenToggle.module.css @@ -1,6 +1,6 @@ /* FullscreenToggle — top-right keeps bottom controls clear on scoreboard */ .fullscreenToggle { - position: fixed; + position: absolute; top: calc(var(--space-md) + var(--safe-area-top)); right: calc(var(--space-md) + var(--safe-area-right)); width: var(--touch-target-comfortable); diff --git a/src/components/FullscreenToggle.tsx b/src/components/FullscreenToggle.tsx index 21cd193..96ec403 100644 --- a/src/components/FullscreenToggle.tsx +++ b/src/components/FullscreenToggle.tsx @@ -10,9 +10,9 @@ const FullscreenToggle = () => { // Toggle fullscreen mode for the document const handleToggle = useCallback(() => { if (!document.fullscreenElement) { - document.documentElement.requestFullscreen(); + document.documentElement.requestFullscreen().catch(() => {}); } else { - document.exitFullscreen(); + document.exitFullscreen().catch(() => {}); } }, []); diff --git a/src/lib/features/game-detail/GameDetail.module.css b/src/lib/features/game-detail/GameDetail.module.css index 1c428fd..e24291e 100644 --- a/src/lib/features/game-detail/GameDetail.module.css +++ b/src/lib/features/game-detail/GameDetail.module.css @@ -3,8 +3,7 @@ .gameDetail { display: flex; flex-direction: column; - height: 100%; - min-height: 0; + min-height: 100%; padding: var(--space-md); padding-bottom: calc(var(--space-md) + var(--safe-area-bottom)); user-select: none; @@ -35,16 +34,15 @@ width: 40px; height: 40px; border-radius: var(--radius-md); - background: linear-gradient(135deg, var(--color-primary) 0%, #e65100 100%); + background: var(--color-primary); color: #1a1a1a; font-size: var(--font-size-xs); font-weight: 900; letter-spacing: 0.08em; - box-shadow: 0 0 12px rgba(255, 152, 0, 0.35); } .gameTitle { - font-size: clamp(1rem, 2.5vh, 1.5rem); + font-size: 1rem; color: var(--color-text); font-weight: 700; letter-spacing: 0.06em; @@ -68,15 +66,13 @@ .scoresContainer { display: flex; - flex: 1; - justify-content: stretch; - align-items: stretch; + flex: 1 1 auto; gap: var(--space-md); - min-height: 0; + min-height: 200px; } .playerScore { - flex: 1; + flex: 1 1 auto; display: flex; flex-direction: column; align-items: stretch; @@ -84,26 +80,25 @@ padding: var(--space-lg) var(--space-md); border-radius: var(--radius-xl); position: relative; - box-shadow: var(--shadow-lg), inset 0 1px 0 rgba(255, 255, 255, 0.08); min-width: 0; - min-height: 0; + min-height: 140px; border: 3px solid transparent; - transition: border-color var(--transition-base), transform var(--transition-fast); + transition: border-color var(--transition-base); overflow: hidden; cursor: pointer; touch-action: manipulation; } .player1 { - background: linear-gradient(180deg, #3a5a3d 0%, var(--color-player-1) 100%); + background: var(--color-player-1); } .player2 { - background: linear-gradient(180deg, #354d6a 0%, var(--color-player-2) 100%); + background: var(--color-player-2); } .player3 { - background: linear-gradient(180deg, #444 0%, var(--color-player-3) 100%); + background: var(--color-player-3); } .playerScore.completed { @@ -117,12 +112,11 @@ } .playerScore:active:not([aria-disabled="true"]) { - transform: scale(0.99); + opacity: 0.95; } .playerScore.winner { border-color: var(--color-primary); - box-shadow: 0 0 0 3px var(--color-primary), 0 0 28px rgba(255, 152, 0, 0.45), var(--shadow-lg); } .playerScore.winner .playerName { @@ -140,10 +134,9 @@ } .playerName { - font-size: clamp(1.1rem, 3vh, 1.75rem); + font-size: 1.1rem; font-weight: 700; color: #fff; - text-shadow: 0 2px 4px rgba(0, 0, 0, 0.4); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; @@ -154,30 +147,16 @@ .breakIndicator { display: inline-block; - width: clamp(14px, 2.5vh, 22px); - height: clamp(14px, 2.5vh, 22px); + width: 16px; + height: 16px; border-radius: 50%; background: #fff; flex-shrink: 0; - box-shadow: 0 0 6px rgba(255, 255, 255, 0.6); - animation: breakPulse 2s ease-in-out infinite; -} - -@keyframes breakPulse { - 0%, 100% { - opacity: 1; - box-shadow: 0 0 6px rgba(255, 255, 255, 0.8); - } - 50% { - opacity: 0.65; - box-shadow: 0 0 14px rgba(255, 255, 255, 0.95), 0 0 20px rgba(255, 152, 0, 0.4); - } } .winnerBadge { - font-size: clamp(1rem, 2.5vh, 1.5rem); + font-size: 1rem; color: var(--color-primary); - text-shadow: 0 1px 2px rgba(0, 0, 0, 0.5); flex-shrink: 0; } @@ -195,67 +174,32 @@ height: 100%; background: rgba(255, 255, 255, 0.9); border-radius: var(--radius-sm); - transition: width var(--transition-slow); } .score { - font-size: clamp(4.5rem, 30vh, 14rem); + font-size: 3.5rem; font-weight: 900; line-height: 1; color: #fff; - text-shadow: 0 4px 12px rgba(0, 0, 0, 0.5); text-align: center; display: flex; align-items: center; justify-content: center; - flex: 1 1 0; + flex: 1 1 auto; width: 100%; min-height: 0; border-radius: var(--radius-lg); padding: var(--space-xs); font-variant-numeric: tabular-nums; - position: relative; pointer-events: none; } -.score::after { - content: ''; - position: absolute; - inset: 0; - border-radius: inherit; - background: radial-gradient(circle at center, rgba(255, 255, 255, 0.35) 0%, transparent 70%); - opacity: 0; - transform: scale(0.5); - pointer-events: none; -} - -.scoreTap::after { - animation: scoreRipple 0.35s ease-out forwards; -} - -.scoreBump { - animation: scoreBump 0.25s ease-out; -} - -@keyframes scoreRipple { - 0% { opacity: 0.6; transform: scale(0.4); } - 100% { opacity: 0; transform: scale(1.4); } -} - -@keyframes scoreBump { - 0% { transform: scale(1); } - 40% { transform: scale(1.12); } - 100% { transform: scale(1); } -} - - .gameDetailControls { display: flex; flex-direction: row; flex-wrap: wrap; gap: var(--space-md); margin-top: var(--space-lg); - padding-bottom: calc(var(--space-md) + var(--keyboard-offset)); width: 100%; justify-content: center; flex-shrink: 0; @@ -263,7 +207,7 @@ .gameDetailControls > * { flex: 1; - min-width: min(160px, 100%); + min-width: 120px; max-width: 280px; } @@ -288,15 +232,42 @@ } } +/* Larger screens */ +@media (min-width: 480px) { + .score { + font-size: 4.5rem; + } +} + +@media (min-width: 768px) { + .gameTitle { + font-size: 1.25rem; + } + + .playerName { + font-size: 1.5rem; + } + + .winnerBadge { + font-size: 1.25rem; + } + + .score { + font-size: 6rem; + } +} + +@media (min-width: 1024px) { + .score { + font-size: 7rem; + } +} + /* Narrow portrait — stack players */ @media (max-width: 600px) { .scoresContainer { flex-direction: column; } - - .score { - font-size: clamp(3rem, 20vw, 6rem); - } } /* Landscape phone — keep scores readable, compact chrome */ @@ -317,18 +288,17 @@ } .gameTitle { - font-size: clamp(0.85rem, 2.2vh, 1.1rem); + font-size: 0.85rem; } .scoresContainer { flex-direction: row; gap: var(--space-xs); - flex: 1 1 0; - min-height: 0; } .playerScore { padding: var(--space-xs); + min-height: 100px; } .playerNameRow { @@ -336,7 +306,7 @@ } .playerName { - font-size: clamp(0.75rem, 2.2vh, 1rem); + font-size: 0.75rem; } .progressBar { @@ -346,15 +316,12 @@ } .score { - font-size: clamp(2rem, min(36vh, 24vw), 4.5rem); - padding: 0; - flex: 1 1 0; + font-size: 2rem; } .gameDetailControls { margin-top: var(--space-xs); gap: var(--space-xs); - padding-bottom: calc(var(--space-xs) + var(--keyboard-offset)); } .gameDetailControls > * { @@ -363,14 +330,3 @@ flex: 1; } } - -@media (prefers-reduced-motion: reduce) { - .breakIndicator { - animation: none; - } - - .scoreTap::after, - .scoreBump { - animation: none; - } -} diff --git a/src/lib/features/game-detail/GameDetail.tsx b/src/lib/features/game-detail/GameDetail.tsx index baddfef..11a405a 100644 --- a/src/lib/features/game-detail/GameDetail.tsx +++ b/src/lib/features/game-detail/GameDetail.tsx @@ -1,5 +1,5 @@ import { h } from 'preact'; -import { useEffect, useRef, useState } from 'preact/hooks'; +import { useState } from 'preact/hooks'; import styles from './GameDetail.module.css'; import { Button } from '@lib/ui/Button'; import { getGameWinner, isStandardGame } from '@lib/domain/gameUtils'; @@ -18,42 +18,10 @@ interface GameDetailProps { onUpdateGameSetup?: (setupData: GameSetupData) => void; } -interface AnimatedScoreProps { - value: number; - tapping: boolean; -} - -function AnimatedScore({ value, tapping }: AnimatedScoreProps) { - const [bumping, setBumping] = useState(false); - const prevValue = useRef(value); - - useEffect(() => { - if (prevValue.current !== value) { - setBumping(true); - const timer = window.setTimeout(() => setBumping(false), 250); - prevValue.current = value; - return () => window.clearTimeout(timer); - } - }, [value]); - - const className = [ - styles.score, - tapping ? styles.scoreTap : '', - bumping ? styles.scoreBump : '', - ].filter(Boolean).join(' '); - - return ( - - ); -} - /** * Game detail view for a single game. */ const GameDetail = ({ game, onFinishGame, onUpdateScore, onUndo, onBack, onUpdateGameSetup }: GameDetailProps) => { - const [tappingPlayer, setTappingPlayer] = useState(null); const [setupOpen, setSetupOpen] = useState(false); if (!game || !isStandardGame(game)) return null; @@ -107,8 +75,6 @@ const GameDetail = ({ game, onFinishGame, onUpdateScore, onUndo, onBack, onUpdat const handleScore = () => { if (isCompleted) return; - setTappingPlayer(idx); - window.setTimeout(() => setTappingPlayer((current) => (current === idx ? null : current)), 350); onUpdateScore(idx + 1, 1); }; @@ -152,7 +118,9 @@ const GameDetail = ({ game, onFinishGame, onUpdateScore, onUndo, onBack, onUpdat )} - + ); })} diff --git a/src/lib/features/game-detail/GameSetupModal.module.css b/src/lib/features/game-detail/GameSetupModal.module.css index 45a25cd..dc61a0c 100644 --- a/src/lib/features/game-detail/GameSetupModal.module.css +++ b/src/lib/features/game-detail/GameSetupModal.module.css @@ -1,6 +1,5 @@ .modalContent { - width: min(560px, 100%); - max-height: calc(var(--app-height) - var(--space-xl) * 2); + /* Inherits width/max-width/max-height/scroll from base Modal.module.css */ } .section { diff --git a/src/lib/features/game-detail/SetupButton.module.css b/src/lib/features/game-detail/SetupButton.module.css index 6832f40..22cbbd4 100644 --- a/src/lib/features/game-detail/SetupButton.module.css +++ b/src/lib/features/game-detail/SetupButton.module.css @@ -1,6 +1,6 @@ /* SetupButton — bottom-left; mirrors FullscreenToggle placement */ .setupButton { - position: fixed; + position: absolute; bottom: calc(var(--space-md) + var(--safe-area-bottom)); left: calc(var(--space-md) + var(--safe-area-left)); width: var(--touch-target-comfortable); diff --git a/src/lib/features/game-lifecycle/GameCompletionModal.module.css b/src/lib/features/game-lifecycle/GameCompletionModal.module.css index 14538a9..8411035 100644 --- a/src/lib/features/game-lifecycle/GameCompletionModal.module.css +++ b/src/lib/features/game-lifecycle/GameCompletionModal.module.css @@ -5,7 +5,10 @@ .confetti { position: absolute; - inset: 0; + top: 0; + left: 0; + width: 100%; + height: 100%; pointer-events: none; overflow: hidden; z-index: 1; @@ -18,8 +21,6 @@ height: 8px; border-radius: 2px; opacity: 0; - animation: confettiFall 1.5s ease-out forwards; - animation-delay: calc(var(--i, 0) * 0.06s); left: calc(8% + var(--i, 0) * 7%); } @@ -38,7 +39,6 @@ @keyframes confettiFall { 0% { opacity: 1; - transform: translateY(0) rotate(0deg) scale(1); } 100% { opacity: 0; @@ -81,7 +81,7 @@ } .finalScore .score { - font-size: clamp(1.75rem, 5vw, 2.5rem); + font-size: 1.75rem; font-weight: 800; color: var(--color-primary); font-variant-numeric: tabular-nums; @@ -91,33 +91,22 @@ text-align: center; margin-top: var(--space-lg); padding: var(--space-xl) var(--space-lg); - background: linear-gradient(135deg, var(--color-primary) 0%, var(--color-primary-hover) 100%); + background: var(--color-primary); border-radius: var(--radius-lg); color: #1a1a1a; font-weight: 700; - box-shadow: var(--shadow-md), 0 0 24px rgba(255, 152, 0, 0.35); + box-shadow: var(--shadow-md); position: relative; z-index: 2; - animation: winnerGlow 2s ease-in-out infinite; -} - -@keyframes winnerGlow { - 0%, 100% { - box-shadow: var(--shadow-md), 0 0 20px rgba(255, 152, 0, 0.3); - } - 50% { - box-shadow: var(--shadow-md), 0 0 32px rgba(255, 152, 0, 0.55); - } } .winnerAnnouncement h3 { margin: 0; - font-size: clamp(1.1rem, 3vw, 1.6rem); + font-size: 1.1rem; color: #1a1a1a; text-align: center; font-weight: 800; line-height: 1.3; - text-shadow: 0 1px 0 rgba(255, 255, 255, 0.2); } .modalActions { @@ -139,14 +128,18 @@ flex: 1; min-width: 120px; } + + .finalScore .score { + font-size: 2.5rem; + } + + .winnerAnnouncement h3 { + font-size: 1.6rem; + } } @media (prefers-reduced-motion: reduce) { .confettiPiece { display: none; } - - .winnerAnnouncement { - animation: none; - } } diff --git a/src/lib/features/game-list/GameList.module.css b/src/lib/features/game-list/GameList.module.css index 65caeaa..00690f1 100644 --- a/src/lib/features/game-list/GameList.module.css +++ b/src/lib/features/game-list/GameList.module.css @@ -2,7 +2,6 @@ width: 100%; display: flex; flex-direction: column; - min-height: 0; flex: 1; } @@ -21,7 +20,7 @@ .filterButtons > * { flex: 1 1 auto; - min-width: min(160px, calc(50% - var(--space-sm))); + min-width: 120px; min-height: var(--touch-target-large); } @@ -31,10 +30,8 @@ flex-direction: column; gap: var(--space-md); flex: 1; - overflow-y: auto; - overflow-x: hidden; + overflow: visible; min-height: 0; - padding-bottom: calc(var(--space-md) + var(--keyboard-offset)); -webkit-overflow-scrolling: touch; } @@ -49,7 +46,7 @@ } .gameItem:active { - transform: scale(0.99); + opacity: 0.92; } .gameItem.active { @@ -103,12 +100,6 @@ height: 10px; border-radius: 50%; background: #fff; - animation: livePulse 1.5s ease-in-out infinite; -} - -@keyframes livePulse { - 0%, 100% { opacity: 1; transform: scale(1); } - 50% { opacity: 0.5; transform: scale(0.85); } } .statusActive { @@ -162,7 +153,7 @@ padding: var(--space-xxl) var(--space-lg); color: var(--color-text-muted); font-size: var(--font-size-lg); - background: linear-gradient(180deg, #2a2a2a 0%, var(--color-surface) 100%); + background: var(--color-surface); border-radius: var(--radius-lg); border: 2px dashed var(--color-border); width: 100%; @@ -172,7 +163,6 @@ font-size: 3rem; line-height: 1; margin-bottom: var(--space-md); - filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.4)); } .emptyHint { @@ -211,7 +201,7 @@ } .filterButtons > * { - min-width: calc(33% - var(--space-sm)); + min-width: 100px; } .deleteWrapper { @@ -222,13 +212,3 @@ width: 100% !important; } } - -@media (prefers-reduced-motion: reduce) { - .liveDot { - animation: none; - } - - .gameItem:active { - transform: none; - } -} diff --git a/src/lib/features/new-game/NewGame.module.css b/src/lib/features/new-game/NewGame.module.css index 5110d24..859bd17 100644 --- a/src/lib/features/new-game/NewGame.module.css +++ b/src/lib/features/new-game/NewGame.module.css @@ -1,42 +1,22 @@ /* NewGame-specific styles only. Shared utility classes are now in global CSS. */ -.screen { - position: absolute; - top: 0; - left: 0; - width: 100%; - min-height: var(--app-height); - display: none; - opacity: 0; - transform: translateX(100%); - transition: transform var(--transition-slow), opacity var(--transition-slow); -} -.screen-content { - display: flex; - flex-direction: column; - height: 100%; - padding: var(--space-lg); - overflow-y: auto; - overflow-x: hidden; - -webkit-overflow-scrolling: touch; - min-height: 0; -} + .screen-title { - font-size: clamp(1.25rem, 3vh, 1.5rem); + font-size: 1.25rem; font-weight: 700; color: var(--color-text); - margin-bottom: clamp(0.5rem, 2vh, 2rem); + margin-bottom: 1rem; letter-spacing: 0.5px; text-align: center; } + .player-inputs { display: flex; flex-direction: column; gap: var(--space-lg); width: 100%; margin-bottom: var(--space-xl); - flex-shrink: 1; - min-height: 0; } + .player-input { background: var(--color-background); border-radius: var(--radius-md); @@ -45,25 +25,28 @@ transition: border-color var(--transition-base); position: relative; flex-shrink: 1; - min-height: 0; overflow: hidden; } + .player-input:focus-within { border-color: var(--color-primary); box-shadow: 0 0 0 3px var(--color-primary-light); } + .player-input label { display: block; - margin-bottom: clamp(0.5rem, 2vh, 1rem); + margin-bottom: var(--space-md); color: var(--color-text); - font-size: clamp(1rem, 2.5vh, 1.125rem); + font-size: var(--font-size-base); font-weight: 600; } + .name-input-container { display: flex; gap: var(--space-md); position: relative; } + .name-input { flex: 1; padding: var(--space-md); @@ -73,21 +56,25 @@ font-size: var(--font-size-base); min-height: var(--touch-target-comfortable); border-radius: var(--radius-md); - transition: all var(--transition-base); + transition: border-color var(--transition-base); } + .name-input:focus { outline: none; border-color: var(--color-primary); box-shadow: 0 0 0 3px var(--color-primary-light); } + .game-settings { margin-top: 0; width: 100%; margin-bottom: var(--space-xl); } + .setting-group { margin-bottom: var(--space-lg); } + .setting-group label { display: block; margin-bottom: var(--space-md); @@ -95,6 +82,7 @@ font-size: var(--font-size-lg); font-weight: 600; } + .setting-group select, .setting-group input { width: 100%; padding: var(--space-md); @@ -106,11 +94,13 @@ border-radius: var(--radius-md); transition: border-color var(--transition-base); } + .setting-group input:focus, .setting-group select:focus { outline: none; border-color: var(--color-primary); box-shadow: 0 0 0 3px var(--color-primary-light); } + .validation-error { color: var(--color-danger); background: var(--color-surface); @@ -122,128 +112,51 @@ text-align: center; font-weight: 500; } -/* NewGame-specific styles only. Shared utility classes are now in global CSS. */ + .wizardShell { - flex: 1; - display: flex; - align-items: stretch; - justify-content: center; + display: block; width: 100%; - min-height: 0; - max-height: 100%; - overflow: hidden; padding: var(--space-sm) 0; } .new-game-form { - width: min(94vw, 720px); - max-height: 100%; + width: 100%; + max-width: 720px; margin: 0 auto; - background: linear-gradient(180deg, #2a2a2a 0%, var(--color-surface) 100%); + background: var(--color-surface); border-radius: var(--radius-xl); - box-shadow: var(--shadow-lg), inset 0 1px 0 rgba(255, 255, 255, 0.06); + border: 1px solid var(--color-border); padding: 0; display: flex; flex-direction: column; - border: 1px solid var(--color-border); - flex-shrink: 1; - min-height: 0; - overflow: hidden; - animation: wizardStepIn var(--transition-slow) ease-out; } -/* Per-step wizard backgrounds — visually distinct per step */ -.new-game-form.step-player1 { - background: linear-gradient(180deg, #3a5a3d 0%, #2e4631 100%); - border-color: rgba(255, 255, 255, 0.12); -} - -.new-game-form.step-player2 { - background: linear-gradient(180deg, #354d6a 0%, #2a3b52 100%); - border-color: rgba(255, 255, 255, 0.12); -} - -.new-game-form.step-player3 { - background: linear-gradient(180deg, #444 0%, #333 100%); - border-color: rgba(255, 255, 255, 0.12); -} - -.new-game-form.step-gameType { - background: linear-gradient(180deg, #5a2323 0%, #4a1c1c 100%); - border-color: rgba(255, 255, 255, 0.12); -} - -.new-game-form.step-raceTo { - background: linear-gradient(180deg, #3d245e 0%, #2d1b4e 100%); - border-color: rgba(255, 255, 255, 0.12); -} - -.new-game-form.step-breakRule { - background: linear-gradient(180deg, #3a3a3a 0%, #2a2a2a 100%); - border-color: rgba(255, 255, 255, 0.12); -} - -.new-game-form.step-breakOrder { - background: linear-gradient(180deg, #5a3a10 0%, #3d260a 100%); - border-color: rgba(255, 152, 0, 0.25); -} - -.new-game-form[class*="step-"] .form-footer { - background: rgba(0, 0, 0, 0.35); - border-top-color: rgba(255, 255, 255, 0.12); -} - -.new-game-form[class*="step-"] .wizard-summary { - background: rgba(0, 0, 0, 0.35); - border-color: rgba(255, 255, 255, 0.15); -} - -.new-game-form[class*="step-"] .screen-title { - color: #fff; - text-shadow: 0 1px 3px rgba(0, 0, 0, 0.4); -} - -.new-game-form[class*="step-"] .player-input { - background: rgba(0, 0, 0, 0.25); - border-color: rgba(255, 255, 255, 0.15); -} - -.new-game-form[class*="step-"] .name-input, -.new-game-form[class*="step-"] .game-type-btn, -.new-game-form[class*="step-"] .race-to-btn, -.new-game-form[class*="step-"] .quick-pick-btn { - background: rgba(0, 0, 0, 0.3); - border-color: rgba(255, 255, 255, 0.15); -} - -@keyframes wizardStepIn { - from { - opacity: 0; - transform: translateX(12px); - } - to { - opacity: 1; - transform: translateX(0); - } -} +/* Step class placeholders are kept so NewGameScreen can still pass them. */ +.step-player1 {} +.step-player2 {} +.step-player3 {} +.step-gameType {} +.step-raceTo {} +.step-breakRule {} +.step-breakOrder {} .form-header { flex-shrink: 0; - padding: clamp(0.4rem, 1.5vh, 1.25rem) var(--space-lg) clamp(0.2rem, 0.8vh, 0.75rem) var(--space-lg); + padding: var(--space-sm) var(--space-lg); } .wizard-summary { - margin-top: clamp(0.25rem, 0.8vh, 0.5rem); - margin-bottom: clamp(0.25rem, 0.8vh, 0.5rem); - padding: clamp(0.5rem, 1.2vh, 0.75rem) var(--space-md); - background: rgba(0, 0, 0, 0.25); + margin-top: var(--space-xs); + margin-bottom: var(--space-xs); + padding: var(--space-sm) var(--space-md); + background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-md); } .wizard-summary-hint { margin: 0; - font-size: clamp(0.85rem, 2.2vw, 0.95rem); + font-size: var(--font-size-sm); line-height: 1.35; color: var(--color-text-muted, #aaa); } @@ -252,7 +165,7 @@ margin: 0; display: flex; flex-direction: column; - gap: clamp(0.2rem, 0.6vh, 0.35rem); + gap: var(--space-xs); } .wizard-summary-row { @@ -266,7 +179,7 @@ .wizard-summary-label { margin: 0; flex: 0 0 auto; - font-size: clamp(0.8rem, 2vw, 0.9rem); + font-size: var(--font-size-sm); font-weight: 600; color: var(--color-text-muted, #aaa); text-transform: none; @@ -275,7 +188,7 @@ .wizard-summary-value { margin: 0; flex: 1 1 auto; - font-size: clamp(0.95rem, 2.5vw, 1.05rem); + font-size: var(--font-size-base); line-height: 1.35; color: var(--color-text, #eee); font-weight: 500; @@ -283,51 +196,49 @@ .form-content { flex: 1; - overflow-y: auto; - overscroll-behavior: contain; + overflow: visible; padding: 0 var(--space-lg); padding-bottom: var(--space-sm); - min-height: 0; display: flex; flex-direction: column; } .form-footer { flex-shrink: 0; - position: sticky; - bottom: 0; - z-index: 2; + position: static; background: var(--color-surface); - padding: var(--space-sm) var(--space-lg) calc(var(--space-sm) + var(--safe-area-bottom) + var(--keyboard-offset)) var(--space-lg); + padding: var(--space-sm) var(--space-lg) calc(var(--space-sm) + var(--safe-area-bottom)); border-top: 1px solid var(--color-border); } + .progress-indicator { display: flex; justify-content: center; align-items: center; - gap: clamp(0.5rem, 1.5vw, 1rem); - margin-bottom: clamp(0.5rem, 2vh, 1.5rem); + gap: var(--space-sm); + margin-bottom: var(--space-md); } + .progress-dot { - width: clamp(12px, 2vh, 18px); - height: clamp(12px, 2vh, 18px); + width: 14px; + height: 14px; border-radius: 50%; background: var(--color-border); opacity: 0.4; - transition: background var(--transition-slow), opacity var(--transition-slow), transform var(--transition-slow), box-shadow var(--transition-slow); + transition: background var(--transition-slow), opacity var(--transition-slow); position: relative; } + .progress-dot.completed { background: var(--color-primary); opacity: 0.55; - transform: scale(0.9); } + .progress-dot.active { background: var(--color-primary); opacity: 1; - transform: scale(1.25); - box-shadow: 0 0 0 4px var(--color-primary-light), 0 0 12px rgba(255, 152, 0, 0.4); } + .quick-pick-container { flex: 1; overflow: hidden; @@ -346,27 +257,26 @@ border: 2px solid var(--color-border); cursor: pointer; padding: var(--space-md) var(--space-lg); - transition: border-color var(--transition-base), background-color var(--transition-base), transform var(--transition-fast), box-shadow var(--transition-base); + transition: border-color var(--transition-base), background-color var(--transition-base); font-weight: 600; font-family: inherit; flex-shrink: 0; touch-action: manipulation; } -.quick-pick-btn:active:not(.selected) { - transform: scale(0.97); -} .quick-pick-btn:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; border-color: var(--color-primary); } + .choice-btn { min-width: 160px; min-height: var(--touch-target-large); font-size: var(--font-size-lg); flex: 1; } + .arrow-nav { display: flex; justify-content: space-between; @@ -375,11 +285,13 @@ width: 100%; gap: var(--space-sm); } + .arrow-nav-actions { display: flex; align-items: center; gap: var(--space-md); } + .arrow-btn { font-size: 28px; width: var(--touch-target-comfortable); @@ -399,18 +311,22 @@ touch-action: manipulation; flex-shrink: 0; } + .arrow-btn:disabled { opacity: 0.45; cursor: not-allowed; } + .arrow-btn:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; border-color: var(--color-primary); } + .arrow-btn:active:not(:disabled) { background: var(--color-secondary-hover); } + .clear-input-btn { position: absolute; right: var(--space-sm); @@ -431,6 +347,7 @@ align-items: center; justify-content: center; } + .clear-input-btn:focus-visible { color: var(--color-text); background: var(--color-secondary); @@ -442,26 +359,31 @@ color: var(--color-text); background: var(--color-secondary-hover); } + .name-input-wrapper { position: relative; width: 100%; } + .character-counter { font-size: 0.875rem; margin-top: 4px; text-align: right; } + .quick-picks-row { display: flex; flex-wrap: wrap; gap: 8px; margin-top: 4px; } + .quick-pick-action-btn { background: var(--color-primary); border-color: var(--color-primary); color: #fff; } + .quick-pick-action-btn:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; @@ -471,19 +393,23 @@ background: var(--color-primary-hover); border-color: var(--color-primary-hover); } + .quick-pick-actions-separator { width: 10px; height: 1px; margin: 0 4px; } + .choice-heading { margin-top: 24px; margin-bottom: 16px; font-weight: 600; } + .choice-heading:first-child { margin-top: 0; } + .game-type-selection { display: grid; grid-template-columns: 1fr 1fr; @@ -491,6 +417,7 @@ width: 100%; margin: var(--space-md) 0; } + .game-type-btn { background: var(--color-background); border: 2px solid var(--color-border); @@ -501,33 +428,37 @@ border-radius: var(--radius-lg); cursor: pointer; text-align: center; - transition: border-color var(--transition-base), background-color var(--transition-base), transform var(--transition-fast), box-shadow var(--transition-base); + transition: border-color var(--transition-base), background-color var(--transition-base); min-height: var(--touch-target-large); font-family: inherit; touch-action: manipulation; } -.game-type-btn:active:not(.selected) { - transform: scale(0.97); -} .game-type-btn:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; } + .game-type-btn.selected { background: var(--color-primary); border-color: var(--color-primary); color: #fff; box-shadow: var(--shadow-md), 0 0 0 3px var(--color-primary-light); - transform: scale(1.03); } + .race-to-selection { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(80px, 1fr)); + display: flex; + flex-wrap: wrap; gap: var(--space-md); width: 100%; margin: var(--space-md) 0; } + +.race-to-selection .race-to-btn { + flex: 1 1 calc(25% - var(--space-md)); + min-width: 72px; +} + .race-to-btn { background: var(--color-background); border: 2px solid var(--color-border); @@ -538,7 +469,7 @@ border-radius: var(--radius-lg); cursor: pointer; text-align: center; - transition: border-color var(--transition-base), background-color var(--transition-base), transform var(--transition-fast), box-shadow var(--transition-base); + transition: border-color var(--transition-base), background-color var(--transition-base); min-height: var(--touch-target-large); display: flex; align-items: center; @@ -546,21 +477,19 @@ font-family: inherit; touch-action: manipulation; } -.race-to-btn:active:not(.selected) { - transform: scale(0.97); -} .race-to-btn:focus-visible { outline: 2px solid var(--color-primary); outline-offset: 2px; } + .race-to-btn.selected { background: var(--color-primary); border-color: var(--color-primary); color: #fff; box-shadow: var(--shadow-md), 0 0 0 3px var(--color-primary-light); - transform: scale(1.03); } + /* Match selected styling for quick pick buttons used in BreakRuleStep */ .quick-pick-btn.selected { background: var(--color-primary); @@ -568,88 +497,88 @@ color: #fff; box-shadow: var(--shadow-md), 0 0 0 3px var(--color-primary-light); font-weight: 700; - transform: scale(1.02); } + .custom-race-to { display: flex; gap: var(--space-md); margin-top: var(--space-lg); align-items: center; } + .custom-race-to input { flex-grow: 1; } + .custom-race-to .arrow-btn { width: 60px; height: 60px; font-size: 32px; flex-shrink: 0; } + .endlos-container { width: 100%; margin-bottom: 12px; } + .endlos-btn { width: 100%; } + .player1-input.player-input, .player2-input.player-input, .player3-input.player-input { border-color: var(--color-border); background: var(--color-surface); } + @media (min-width: 768px) and (max-width: 1024px) { .wizardShell { padding: var(--space-md) 0; } - .new-game-form { - min-height: min(82vh, 680px); - max-height: 100%; - } + .screen-title { font-size: var(--font-size-xxxl); } + .arrow-btn { width: 56px; height: 56px; font-size: 34px; } + .game-type-btn, .race-to-btn { padding: var(--space-xl); font-size: var(--font-size-xl); min-height: var(--touch-target-comfortable); } + .quick-pick-btn { min-height: var(--touch-target-comfortable); font-size: var(--font-size-lg); padding: var(--space-md) var(--space-lg); } } -@media (min-height: 720px) { - .new-game-form { - min-height: min(88vh, 720px); - } -} + @media (max-width: 767px) { .wizardShell { padding: var(--space-xs) 0; - align-items: stretch; - } - .new-game-form { - width: min(96vw, 720px); - min-height: 0; - max-height: 100%; } + .game-type-selection { grid-template-columns: 1fr; } + .race-to-selection { grid-template-columns: repeat(3, 1fr); } + .arrow-nav { gap: var(--space-md); } + .arrow-btn { width: var(--touch-target-min); height: var(--touch-target-min); @@ -657,60 +586,50 @@ } } -@media (prefers-reduced-motion: reduce) { - .new-game-form { - animation: none; - } - .game-type-btn.selected, - .race-to-btn.selected, - .quick-pick-btn.selected { - transform: none; - } -} - @media (max-height: 560px) { .screen-title { margin-bottom: 0.35rem; } + .progress-indicator { margin-bottom: 0.35rem; } + .wizard-summary { padding: 0.35rem var(--space-sm); margin-bottom: 0.25rem; } + .wizard-summary-value { - font-size: clamp(0.9rem, 2.2vw, 1rem); + font-size: var(--font-size-base); } + .player-input { padding: var(--space-sm); } + .form-header { padding-top: 0.4rem; padding-bottom: 0.3rem; } + .form-footer { padding-top: 0.3rem; - padding-bottom: calc(0.35rem + var(--safe-area-bottom) + var(--keyboard-offset)); + padding-bottom: calc(0.35rem + var(--safe-area-bottom)); } } + @media (max-height: 500px) { .wizardShell { padding: 0; } - .new-game-form { - min-height: 0; - max-height: 100%; - width: min(98vw, 720px); - } - .form-header { - padding: var(--space-xs) var(--space-md) var(--space-xs); + padding: var(--space-xs) var(--space-md); } .screen-title { - font-size: clamp(1rem, 3.5vh, 1.25rem); + font-size: 1rem; margin-bottom: 0.25rem; } @@ -723,7 +642,7 @@ .choice-heading { margin-top: 0.5rem; margin-bottom: 0.35rem; - font-size: clamp(0.95rem, 3vh, 1.1rem); + font-size: 1rem; } .quick-picks-row { @@ -737,6 +656,6 @@ } .form-footer { - padding: var(--space-xs) var(--space-md) calc(var(--space-xs) + var(--safe-area-bottom) + var(--keyboard-offset)); + padding: var(--space-xs) var(--space-md) calc(var(--space-xs) + var(--safe-area-bottom)); } } diff --git a/src/lib/features/new-game/PlayerSelectModal.module.css b/src/lib/features/new-game/PlayerSelectModal.module.css index f5f9393..7229bca 100644 --- a/src/lib/features/new-game/PlayerSelectModal.module.css +++ b/src/lib/features/new-game/PlayerSelectModal.module.css @@ -1,6 +1,9 @@ .modalOverlay { - position: fixed; - inset: 0; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; background: rgba(0, 0, 0, 0.8); display: flex; align-items: center; @@ -9,18 +12,23 @@ padding: var(--space-lg); padding-top: calc(var(--space-lg) + var(--safe-area-top)); padding-bottom: calc(var(--space-lg) + var(--safe-area-bottom)); + padding-left: calc(var(--space-lg) + var(--safe-area-left)); + padding-right: calc(var(--space-lg) + var(--safe-area-right)); + overflow: hidden; } .modalContent { background: var(--color-surface); padding: var(--space-xl); border-radius: var(--radius-xl); - width: min(480px, 100%); - max-height: calc(var(--app-height) - var(--space-xl) * 2); + width: 100%; + max-width: 480px; + max-height: 90%; box-shadow: var(--shadow-lg); display: flex; flex-direction: column; border: 1px solid var(--color-border); + overflow: hidden; } .modalHeader { @@ -60,7 +68,7 @@ } .playerList { - max-height: 60vh; + max-height: 400px; overflow-y: auto; display: flex; flex-direction: column; diff --git a/src/lib/features/new-game/components/NameEntryModal.module.css b/src/lib/features/new-game/components/NameEntryModal.module.css index 39a23f9..5fde6ee 100644 --- a/src/lib/features/new-game/components/NameEntryModal.module.css +++ b/src/lib/features/new-game/components/NameEntryModal.module.css @@ -1,6 +1,9 @@ .modalOverlay { - position: fixed; - inset: 0; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; background: rgba(0, 0, 0, 0.8); display: flex; align-items: center; @@ -9,18 +12,25 @@ padding: var(--space-lg); padding-top: calc(var(--space-lg) + var(--safe-area-top)); padding-bottom: calc(var(--space-lg) + var(--safe-area-bottom)); + padding-left: calc(var(--space-lg) + var(--safe-area-left)); + padding-right: calc(var(--space-lg) + var(--safe-area-right)); + overflow: hidden; } .modalContent { - width: min(420px, 100%); - background: linear-gradient(180deg, #2a2a2a 0%, var(--color-surface) 100%); + width: 100%; + max-width: 420px; + background: var(--color-surface); border: 1px solid var(--color-border); border-radius: var(--radius-xl); - box-shadow: var(--shadow-lg), inset 0 1px 0 rgba(255, 255, 255, 0.06); + box-shadow: var(--shadow-lg); padding: var(--space-xl); display: flex; flex-direction: column; gap: var(--space-md); + max-height: 90%; + overflow-y: auto; + -webkit-overflow-scrolling: touch; } .modalTitle { @@ -33,7 +43,7 @@ .modalInput { width: 100%; min-height: var(--touch-target-comfortable); - font-size: max(16px, var(--font-size-base)); + font-size: 16px; } .modalActions { diff --git a/src/lib/ui/Button.module.css b/src/lib/ui/Button.module.css index 53ca6f7..8460643 100644 --- a/src/lib/ui/Button.module.css +++ b/src/lib/ui/Button.module.css @@ -4,7 +4,7 @@ cursor: pointer; font-weight: 600; font-family: inherit; - transition: background-color var(--transition-base), box-shadow var(--transition-base), transform var(--transition-fast), opacity var(--transition-base); + transition: background-color var(--transition-base), box-shadow var(--transition-base), opacity var(--transition-base); touch-action: manipulation; display: inline-flex; align-items: center; @@ -14,7 +14,7 @@ user-select: none; -webkit-user-select: none; width: 100%; - box-shadow: var(--shadow-sm), inset 0 1px 0 rgba(255, 255, 255, 0.08); + box-shadow: var(--shadow-sm); } .button:focus-visible { @@ -23,15 +23,13 @@ } .button:active:not(.disabled) { - transform: scale(0.97); opacity: 0.92; } /* Variants */ .primary { - background: linear-gradient(180deg, #ffb74d 0%, var(--color-primary) 100%); + background: var(--color-primary); color: #fff; - box-shadow: var(--shadow-sm), 0 0 0 1px rgba(255, 152, 0, 0.4), inset 0 1px 0 rgba(255, 255, 255, 0.2); } .primary:not(.disabled):active { @@ -39,7 +37,7 @@ } .secondary { - background: linear-gradient(180deg, #3a3a3a 0%, var(--color-secondary) 100%); + background: var(--color-secondary); color: var(--color-text); border: 2px solid var(--color-border); } @@ -49,7 +47,7 @@ } .danger { - background: linear-gradient(180deg, #ef5350 0%, var(--color-danger) 100%); + background: var(--color-danger); color: #fff; } @@ -106,9 +104,3 @@ opacity: 0.45; cursor: not-allowed; } - -@media (prefers-reduced-motion: reduce) { - .button:active:not(.disabled) { - transform: none; - } -} diff --git a/src/lib/ui/Card.module.css b/src/lib/ui/Card.module.css index c617482..d25a855 100644 --- a/src/lib/ui/Card.module.css +++ b/src/lib/ui/Card.module.css @@ -1,8 +1,7 @@ .card { border-radius: var(--radius-lg); - transition: border-color var(--transition-base), box-shadow var(--transition-base), transform var(--transition-fast); - background: linear-gradient(180deg, #2a2a2a 0%, var(--color-surface) 100%); - box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.05); + transition: border-color var(--transition-base), box-shadow var(--transition-base); + background: var(--color-surface); } .default { @@ -11,7 +10,7 @@ .elevated { border: 1px solid var(--color-border); - box-shadow: var(--shadow-md), inset 0 1px 0 rgba(255, 255, 255, 0.06); + box-shadow: var(--shadow-md); } .outlined { @@ -29,7 +28,7 @@ } .clickable:active { - transform: scale(0.99); + opacity: 0.92; } .clickable:focus-visible { @@ -52,9 +51,3 @@ .padding-large { padding: var(--space-lg); } - -@media (prefers-reduced-motion: reduce) { - .clickable:active { - transform: none; - } -} diff --git a/src/lib/ui/Layout.module.css b/src/lib/ui/Layout.module.css index ae14071..e88b329 100644 --- a/src/lib/ui/Layout.module.css +++ b/src/lib/ui/Layout.module.css @@ -1,14 +1,20 @@ .layout { - height: var(--app-height); + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; overflow: hidden; background-color: var(--color-background); color: var(--color-text); - display: flex; - flex-direction: column; } .content { - flex: 1; + flex: 1 1 auto; + overflow-y: auto; + -webkit-overflow-scrolling: touch; max-width: 1100px; margin: 0 auto; padding: var(--space-md); @@ -16,33 +22,13 @@ width: 100%; display: flex; flex-direction: column; - overflow: hidden; - min-height: 0; } .screen { width: 100%; - height: 100%; + min-height: 100%; display: flex; flex-direction: column; - overflow: hidden; - min-height: 0; - animation: screenFadeIn var(--transition-slow) ease-out; -} - -@keyframes screenFadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -@media (prefers-reduced-motion: reduce) { - .screen { - animation: none; - } } @media (min-width: 768px) { diff --git a/src/lib/ui/Modal.module.css b/src/lib/ui/Modal.module.css index e96c570..d859edb 100644 --- a/src/lib/ui/Modal.module.css +++ b/src/lib/ui/Modal.module.css @@ -1,8 +1,11 @@ -/* Consolidated modal styles */ +/* Consolidated modal styles — viewport-bound, scrollable content */ .modal { display: none; - position: fixed; - inset: 0; + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; background-color: rgba(0, 0, 0, 0.8); z-index: 1000; padding: var(--space-lg); @@ -22,9 +25,11 @@ background-color: var(--color-surface); padding: var(--space-xl); border-radius: var(--radius-xl); - width: min(500px, 100%); - max-height: calc(var(--app-height) - var(--space-xl) * 2); + width: 100%; + max-width: 500px; + max-height: 100%; overflow-y: auto; + -webkit-overflow-scrolling: touch; position: relative; border: 1px solid var(--color-border); box-shadow: var(--shadow-lg); @@ -36,6 +41,7 @@ align-items: center; margin-bottom: var(--space-lg); gap: var(--space-md); + flex-shrink: 0; } .modal-title { @@ -82,6 +88,7 @@ flex-direction: column; justify-content: stretch; gap: var(--space-md); + flex-shrink: 0; } @media (min-width: 480px) { @@ -95,11 +102,10 @@ .modal-button { min-height: var(--touch-target-large); padding: var(--space-md) var(--space-xl); - font-size: var(--font-size-lg); + font-size: var(--font-size-base); border: none; border-radius: var(--radius-md); cursor: pointer; - font-size: var(--font-size-base); font-weight: 600; font-family: inherit; touch-action: manipulation; diff --git a/src/pages/index.astro b/src/pages/index.astro index e13e99a..a7f724d 100644 --- a/src/pages/index.astro +++ b/src/pages/index.astro @@ -7,7 +7,7 @@ import App from "../components/App"; - + BSC Score – Live-Scoring am Billardtisch @@ -25,8 +25,11 @@ import App from "../components/App"; @@ -34,6 +37,11 @@ import App from "../components/App";
+
- \ No newline at end of file + diff --git a/src/styles/index.css b/src/styles/index.css index 8d5dcb6..2112f1d 100644 --- a/src/styles/index.css +++ b/src/styles/index.css @@ -8,15 +8,19 @@ -webkit-tap-highlight-color: transparent; } -/* Design system tokens */ +/* Design system tokens + Keep values plain; avoid CSS calc() in variable defaults where old parsers choke. */ :root { - --app-height: 100dvh; --keyboard-offset: 0px; - /* Safe area insets */ + /* Safe area insets — env() with literal px fallback */ + --safe-area-top: 0px; --safe-area-top: env(safe-area-inset-top, 0px); + --safe-area-right: 0px; --safe-area-right: env(safe-area-inset-right, 0px); + --safe-area-bottom: 0px; --safe-area-bottom: env(safe-area-inset-bottom, 0px); + --safe-area-left: 0px; --safe-area-left: env(safe-area-inset-left, 0px); /* Colors */ @@ -110,10 +114,19 @@ } html, -body, +body { + height: 100%; + overflow: hidden; +} + #app-root { - height: var(--app-height, 100dvh); - min-height: var(--app-height, 100dvh); + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + overflow: hidden; + background-color: var(--color-background); } body { @@ -127,14 +140,6 @@ body { padding-top: var(--safe-area-top); padding-left: var(--safe-area-left); padding-right: var(--safe-area-right); - overflow: hidden; -} - -#app-root { - width: 100%; - overflow: hidden; - display: flex; - flex-direction: column; } /* Interactive elements — touch-friendly */ @@ -170,7 +175,7 @@ button, input, select { min-height: var(--touch-target-comfortable); padding: var(--space-md); - font-size: max(16px, var(--font-size-base)); + font-size: 16px; font-family: inherit; border: 2px solid var(--color-border); border-radius: var(--radius-md); @@ -227,7 +232,6 @@ input:focus-visible, select:focus-visible { .btn:active:not(:disabled) { opacity: 0.9; - transform: scale(0.98); } .btn-primary:active:not(:disabled) { diff --git a/test-results/.last-run.json b/test-results/.last-run.json index bd06337..cbcc1fb 100644 --- a/test-results/.last-run.json +++ b/test-results/.last-run.json @@ -1,7 +1,4 @@ { - "status": "failed", - "failedTests": [ - "b5da854a7c119c37c9d5-8782df6f17e49724b9a2", - "1012373defdfca68178e-d28214002c7ecee79090" - ] + "status": "passed", + "failedTests": [] } \ No newline at end of file