From 3a3ff55893cf3c762f657ed586f2b4c22acf396f Mon Sep 17 00:00:00 2001 From: Christopher Mayor Date: Tue, 28 Apr 2026 21:37:33 -0700 Subject: [PATCH] [#1+#7] Mobile-first redesign + accessibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Bottom tab bar on mobile (≤640px), top tabs on desktop - Name modal → bottom sheet on mobile with drag handle - Larger tap targets (72px cards, 44px touch areas) - Arrow hint (›) on clickable option cards - Touch feedback with :active scale animation - ARIA roles: tablist/tab/tabpanel, aria-selected, aria-live=polite - Keyboard: Arrow keys navigate tabs, 1-5 number keys switch tabs - Skip-to-content link for screen readers - Visible :focus-visible ring - Desktop body padding reset for bottom tabs --- public/index.html | 189 ++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 181 insertions(+), 8 deletions(-) diff --git a/public/index.html b/public/index.html index c1f1a0b..92ad49c 100644 --- a/public/index.html +++ b/public/index.html @@ -40,6 +40,26 @@ a { color: var(--accent); text-decoration: none; } a:hover { text-decoration: underline; } + /* Skip to content */ + .skip-link { + position: absolute; + top: -40px; + left: 0; + background: var(--accent); + color: var(--bg); + padding: 8px 16px; + z-index: 9999; + font-weight: 700; + border-radius: 0 0 8px 0; + } + .skip-link:focus { top: 0; } + + /* Visible focus ring for accessibility */ + :focus-visible { + outline: 2px solid var(--accent); + outline-offset: 2px; + } + /* ── Header ─────────────────────────────────────────────── */ header { background: linear-gradient(135deg, #13161f 0%, #1a1e2a 100%); @@ -97,6 +117,10 @@ width: 360px; text-align: center; box-shadow: 0 20px 60px rgba(0,0,0,0.5); + position: relative; + } + .modal .drag-handle { + display: none; } .modal h2 { font-size: 1.3rem; margin-bottom: 6px; color: var(--accent); } .modal p { color: var(--text-muted); font-size: 0.85rem; margin-bottom: 20px; } @@ -405,20 +429,134 @@ } .empty-state .empty-emoji { font-size: 2rem; margin-bottom: 10px; } - /* ── Mobile ──────────────────────────────────────────────── */ - @media (max-width: 480px) { - header { flex-direction: column; gap: 6px; align-items: flex-start; } - .meta { text-align: left; } - main { padding: 12px; } - .tab { min-width: 70px; font-size: 0.68rem; } + /* ── Bottom tab bar (mobile ≤640px) ──────────────────────── */ + @media (max-width: 640px) { + body { padding-bottom: 68px; } + + /* Compact sticky header */ + header { + padding: 8px 14px; + gap: 4px; + } + header h1 { font-size: 0.95rem; } + header .meta { font-size: 0.72rem; } + + /* Bottom tab bar */ + .tabs { + position: fixed; + bottom: 0; + left: 0; + right: 0; + top: auto; + border-bottom: none; + border-top: 1px solid var(--border); + background: var(--surface); + z-index: 100; + display: flex; + padding-bottom: env(safe-area-inset-bottom); + /* hide scroll — show all 5 tabs in a row */ + overflow-x: auto; + scrollbar-width: none; + box-shadow: 0 -4px 20px rgba(0,0,0,0.4); + } + .tabs::-webkit-scrollbar { display: none; } + .tab { + flex: 1; + min-width: 0; + padding: 8px 4px 10px; + border-bottom: none; + border-top: 3px solid transparent; + border-radius: 0; + font-size: 0.6rem; + display: flex; + flex-direction: column; + align-items: center; + gap: 3px; + } + .tab.active { + border-top-color: var(--accent); + background: rgba(0,212,255,0.08); + color: var(--accent); + } + .tab .tab-emoji { font-size: 1.2rem; } + .tab .tab-count { + position: absolute; + top: 4px; + right: 6px; + font-size: 0.55rem; + padding: 0 4px; + } + + /* Main adjusts for bottom tabs */ + main { padding: 12px; max-width: 100%; } + + /* Option cards — larger tap targets */ + .option-card { min-height: 72px; padding: 14px 16px; } + .option-name { font-size: 0.92rem; } + .option-desc { font-size: 0.76rem; } + + /* Add arrow hint to cards */ + .option-card::after { + content: '›'; + position: absolute; + right: 14px; + top: 50%; + transform: translateY(-50%); + color: var(--text-muted); + font-size: 1.2rem; + opacity: 0.4; + } + .option-card.voted::after { display: none; } + + /* Touch feedback */ + .option-card:active { transform: scale(0.98); opacity: 0.9; } } + + /* ── Desktop (≥641px) ──────────────────────────────────── */ + @media (min-width: 641px) { + body { padding-bottom: 0; } + } + + /* ── Mobile bottom sheet modal ───────────────────────────── */ + @media (max-width: 640px) { + .modal-overlay { align-items: flex-end; justify-content: stretch; padding: 0; } + .modal { + width: 100%; + border-radius: 20px 20px 0 0; + padding: 12px 24px 32px; + max-height: 85vh; + overflow-y: auto; + box-shadow: 0 -8px 40px rgba(0,0,0,0.6); + animation: slideUp 0.3s ease-out; + } + @keyframes slideUp { + from { transform: translateY(100%); } + to { transform: translateY(0); } + } + .modal .drag-handle { + display: block; + width: 40px; + height: 4px; + background: var(--border); + border-radius: 2px; + margin: 0 auto 14px; + } + .modal h2 { font-size: 1.15rem; } + .modal p { font-size: 0.8rem; margin-bottom: 14px; } + .modal input, .modal button { margin-bottom: 10px; } + } + + /* Touch highlight */ + .option-card { -webkit-tap-highlight-color: rgba(0,212,255,0.12); } +