Mobile polish, release validation script, bump to v4.1.2

Mobile-responsive CSS improvements:
- Larger touch targets for drop zones and buttons (56px min)
- Touch feedback with active states for touch devices
- Camera hint text on mobile ("Tap to take photo or choose file")
- Mode buttons stack vertically on small screens
- Full-width download buttons on mobile
- Navbar doesn't stick on mobile to save screen space

Release validation script (scripts/validate-release.sh):
- Automated pre-release checks: ruff, imports, encode/decode sanity
- Optional Docker build/test (--docker flag)
- Optional Pi smoke test via SSH (--pi flag)
- Pass/fail summary with exit codes

Other:
- Version bump to 4.1.2 (pyproject.toml, constants.py, __init__.py)
- Fixed ruff import sorting in cli.py
- Updated PLAN-4.1.2.md (all 9 features complete)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Aaron D. Lee
2026-01-05 20:34:23 -05:00
parent 2d3ed8a79a
commit 6c3bc995f1
8 changed files with 577 additions and 9 deletions

View File

@@ -1442,3 +1442,260 @@ footer {
padding: 0.35rem 0.75rem;
background: rgba(0, 0, 0, 0.1);
}
/* ============================================================================
MOBILE RESPONSIVE IMPROVEMENTS
============================================================================ */
/* Mobile-specific drop zone improvements */
@media (max-width: 768px) {
/* Larger drop zones on mobile for easier touch targets */
.drop-zone {
padding: 2rem 1.5rem;
min-height: 140px;
}
/* Larger touch target for upload icons */
.drop-zone-label i {
font-size: 2.5rem !important;
}
/* Touch feedback - active state */
.drop-zone:active {
border-color: var(--gradient-start);
background: rgba(102, 126, 234, 0.15);
transform: scale(0.98);
}
/* Mode buttons - stack vertically on very small screens */
.d-flex.gap-2:has(.mode-btn) {
flex-direction: column;
}
.mode-btn {
padding: 1rem;
min-height: 56px; /* iOS touch target minimum */
}
/* Full-width primary buttons */
.btn-primary.btn-lg {
padding: 1rem 1.5rem;
font-size: 1.1rem;
min-height: 56px;
}
/* Security factor boxes - more padding for touch */
.security-box {
padding: 1.25rem;
}
/* Form controls - larger for touch */
.form-control,
.form-select {
padding: 0.75rem 1rem;
font-size: 1rem;
min-height: 48px;
}
/* Input groups - consistent sizing */
.input-group .form-control {
min-height: 48px;
}
.input-group .btn {
min-width: 48px;
padding: 0.75rem;
}
/* Password toggle button - easier to tap */
[data-toggle-password] {
min-width: 52px;
}
/* PIN input - larger on mobile */
.pin-input-container .form-control {
font-size: 1.4rem;
letter-spacing: 4px;
padding: 0.875rem 1rem;
}
/* Passphrase input - comfortable mobile size */
.passphrase-input {
font-size: 1rem !important;
padding: 0.875rem 1rem !important;
}
/* Card headers - compact on mobile */
.card-header h5 {
font-size: 1.1rem;
}
/* Alert info panel - readable text */
.alert.small {
font-size: 0.9rem;
}
/* Bottom info icons - larger tap targets */
.row.text-center .col-4 {
padding: 0.5rem;
}
.row.text-center .col-4 i {
font-size: 2rem !important;
}
/* Capacity panel badges - easier to read */
#capacityPanel .badge {
font-size: 0.8rem;
padding: 0.4rem 0.6rem;
}
/* Payload type toggle - full width buttons */
.btn-group[role="group"] {
flex-direction: row;
}
.btn-group .btn {
padding: 0.75rem 0.5rem;
font-size: 0.95rem;
}
/* Textarea - comfortable height */
textarea.form-control {
min-height: 120px;
}
/* Channel select - full width */
#channelSelect {
font-size: 1rem;
}
}
/* Very small screens (iPhone SE, etc.) */
@media (max-width: 375px) {
.drop-zone {
padding: 1.5rem 1rem;
}
.mode-btn {
padding: 0.875rem;
font-size: 0.9rem;
}
.mode-btn .text-muted {
display: none; /* Hide secondary text on tiny screens */
}
.card-header h5 {
font-size: 1rem;
}
/* Stack security factor row */
.row:has(.security-box) > .col-md-6 {
margin-bottom: 1rem;
}
}
/* Touch device optimizations */
@media (hover: none) and (pointer: coarse) {
/* Remove hover effects that don't work on touch */
.btn-primary:hover {
transform: none;
}
.feature-card:hover {
transform: none;
}
.card-link:hover .feature-card {
transform: none;
}
/* Add active states instead */
.btn-primary:active {
transform: scale(0.98);
box-shadow: 0 2px 10px rgba(102, 126, 234, 0.3);
}
.feature-card:active {
transform: scale(0.98);
}
/* Drop zone active feedback */
.drop-zone:active {
border-color: var(--gradient-start);
background: rgba(102, 126, 234, 0.1);
}
/* Mode button active state */
.mode-btn:active {
background: rgba(255, 255, 255, 0.12);
border-color: var(--gradient-start);
}
}
/* Camera hint for mobile - shows on file inputs */
@media (max-width: 768px) {
.drop-zone-label span.text-muted {
display: block;
}
/* Add camera icon hint on mobile */
.drop-zone-label::after {
content: "Tap to take photo or choose file";
display: block;
font-size: 0.75rem;
color: rgba(255, 255, 255, 0.4);
margin-top: 0.5rem;
}
/* Hide the default text and show mobile version */
.drop-zone-label > span.text-muted {
display: none;
}
}
/* Navbar mobile adjustments */
@media (max-width: 768px) {
.navbar {
padding: 0.5rem 1rem;
}
.navbar-brand img {
height: 32px;
}
/* Sticky header shouldn't eat too much space */
.navbar.sticky-top {
position: relative; /* Don't stick on mobile - saves screen space */
}
}
/* Results page mobile adjustments */
@media (max-width: 768px) {
/* Download button - full width on mobile */
.btn-success.btn-lg,
a.btn-success.btn-lg {
width: 100%;
padding: 1rem;
font-size: 1.1rem;
}
/* QR codes - appropriate sizing */
.qr-scan-container {
max-width: 280px;
margin: 0 auto;
}
/* Message display - readable on mobile */
.alert-message {
font-size: 0.9rem;
padding: 1rem;
word-break: break-word;
}
/* Result icon - slightly smaller on mobile */
.result-icon {
font-size: 3rem;
}
}