Remove cmd-k-btn (search) from floating action buttons - search now only
lives in the action bar. Recalculated positions for 7-button (desktop)
and 6-button (mobile without shortcuts) layouts using fluid clamp() sizing.
- Add aria-labels to menu action buttons (PDF, Print, Contact)
- Add aria-labelledby to toggle checkboxes (desktop + mobile)
- Add -webkit-user-select prefix for Safari compatibility
- Add DynamicCacheControl middleware for HTML pages
- Add accessibility test suite (60-accessibility.test.mjs)
- Add comprehensive accessibility documentation (21-ACCESSIBILITY.md)
- Update Modern Web Techniques doc to mark audit complete
Implement a command palette accessible via CMD+K/Ctrl+K using the ninja-keys
web component. Features include:
- New /api/cmd-k endpoint serving dynamic CV entries (experiences, projects, courses)
- Language-aware responses with 1-hour cache headers
- Scroll-to-section functionality for quick navigation
- Enhanced keyboard shortcuts modal with CMD+K documentation
- Comprehensive test coverage for API and UI interactions
Also includes cleanup of deprecated debug test files and various UI polish
improvements to contact form, themes, and action bar components.
Remove hardcoded width/height HTML attributes from iconify-icon elements
that were overriding CSS sizing. The iconify-icon component uses HTML
attributes for SVG rendering, ignoring CSS width/height.
- Remove width="28" height="28" from 8 button templates
- Remove conflicting 768px media query from _buttons.css
- Add default desktop icon sizes (24px) in _scroll-behavior.css
- Icons now scale via clamp() from 18px (380px) to 24px (900px)
Plain text endpoint:
- Add /text route for plain text CV (for curl/AI crawlers)
- Use k3a/html2text library for HTML-to-text conversion
- Add Plain Text button to hamburger menu with UI translations
Contact form feature:
- Add ContactHandler with proper email service integration
- Add CSRF protection middleware
- Add rate limiting (5 submissions/hour per IP)
- Add honeypot and timing-based bot protection
- Add input validation with detailed error messages
- Add security logging middleware
- Add browser-only middleware for API protection
Code quality:
- Fix all golangci-lint errcheck warnings for w.Write calls
- Remove duplicate getClientIP functions
- Wire up ContactHandler in routes.Setup
- Delete orphaned CSS files (color-theme.css, logo-toggle.css,
skeleton.css, main.new.css) - replaced by modular equivalents
- Delete 08-contexts/_print.css - wrongly created during modularization
- Remove 08-contexts folder (now empty)
- Add print.css as standalone with media="print" in HTML
- Update stale comments referencing old file names
- Remove _print.css import from main.css
print.css remains standalone and will NOT be bundled, as it's a
special case loaded only when printing (media="print").
On mobile, the info modal fonts were too large and causing content overflow.
All text elements have been proportionally reduced for better mobile UX.
Changes for mobile (≤768px):
- Modal padding: 2rem → 1.5rem (vertical), 1.5rem → 1rem (horizontal)
- Close button: 40px → 32px, icon 24px → 20px
- Title: 1.5rem → 1.05rem (30% reduction)
- CV title: 0.95rem
- Photo: 50px × 67px → 30px × 40px
- Description: 0.95rem → 0.85rem
- Tech items: 0.9rem → 0.8rem, icons 32px → 24px
- GitHub button: 0.875rem, icon 24px → 20px
- Tech grid: Single column layout
- Reduced spacing throughout
Result:
- All content fits comfortably within mobile viewport
- No text overflow or coverage issues
- Improved readability and visual hierarchy
- Better use of limited mobile screen space
Tests created but have Playwright API compatibility issues (non-blocking)
The menu was showing light gray text in dark theme, creating poor contrast
against the white menu background. Menu text must always be dark since
the menu background is always white regardless of theme.
Changes:
- Added dark theme overrides for .navigation-menu and .submenu-content
- Force --text-dark to #1a1a1a (dark text) in dark theme for menu
- Force --text-gray to #333333 (dark gray) in dark theme for menu icons
- Applied same fix for auto theme when system preference is dark
Result:
- Menu text: Dark/black (rgb(26, 26, 26)) in all themes
- Menu icons: Dark gray (rgb(51, 51, 51)) in all themes
- Menu background: White (rgb(255, 255, 255)) in all themes
- Proper contrast and readability restored
Test created: 68-menu-colors-dark-theme-test.mjs
Screenshots: menu-light-theme.png, menu-dark-theme.png
Changed zoom button color from #9b59b6 to #5c59b6 for better visual appeal.
The new shade is more blue-tinted, creating a vibrant indigo/periwinkle appearance
that remains distinct from the info button blue.
Changes:
- Updated zoom-toggle-btn background: rgba(92, 89, 182, 0.7)
- Updated hover state: #5c59b6
- Updated at-bottom state: #5c59b6
- Updated test output to reflect correct hex code
Test verified: All buttons visible and colors distinct at all viewports.
Issues fixed:
1. Zoom button now uses purple color (rgba(155, 89, 182, 0.7)) instead of blue
2. Info button keeps blue color (rgba(52, 152, 219, 0.7))
3. Both buttons now show distinct colors in default state, not just on hover
4. Device detection now considers viewport width, not just user agent
5. Buttons no longer hide in responsive mode at desktop viewport sizes
Changes:
- Updated zoom-toggle-btn to use purple background color
- Updated info-button to use blue background color (explicit, not var)
- Modified device-detection.js to check viewport width (≤900px) in addition to UA
- Added resize listener to update device class dynamically
- Created test (67-button-colors-and-visibility-test.mjs) to verify fixes
Testing:
- Desktop (1278px): All buttons visible with distinct colors
- Mobile (375px): Zoom/shortcuts hidden, core buttons visible
- Device detection now viewport-aware (prevents hiding at desktop sizes)
Fixes info modal positioning to be perfectly centered on mobile devices
in all orientations.
ISSUE:
- Info modal was not centered on mobile viewports
- User reported "pop-up of information in mobile it is not centered"
- Modal positioning relied on inset:0 + margin:auto which doesn't
work consistently on mobile devices
FIX:
- Added explicit mobile centering using transform translate(-50%, -50%)
- Position: top: 50%, left: 50% with transform centering
- Applied to all modals: info, keyboard shortcuts, and PDF download
- Added mobile-specific fade-in animation preserving centering
- Constrained modal to viewport with calc(100vw - 2rem) width/height
Files modified:
- static/css/04-interactive/_modals.css - Mobile centering for all modals
- tests/mjs/58-modal-centering-test.mjs - Validation test
Test results:
✅ Portrait (375×667): Perfect center - 0px offset
✅ Landscape (667×375): Perfect center - 0px offset
✅ Modal center matches viewport center exactly
Fixes three critical mobile UI issues:
1. Theme Button Transparency (FIXED)
- Changed theme button from 50% to full opacity on mobile
- Updated _themes.css with rgba(x, y, z, 1) for all theme modes
- Added opacity: 1 !important to mobile media query
2. Info Button Color Differentiation (FIXED)
- Changed info button from green (#27ae60) to blue (#3498db)
- Now visually distinct from green back-to-top button
- Updated all states: default, hover, at-bottom
3. Button Layout Reorganization (FIXED)
- Added .is-mobile-device rules for 5-button layout (no shortcuts)
- Buttons centered without gap: Download, Print, Theme, Info, Back-to-top
- Total width: 290px (5 buttons + 4 gaps) vs 350px (6 buttons)
Files modified:
- static/css/01-foundation/_themes.css - Primary theme button fix
- static/css/04-interactive/_scroll-behavior.css - Info color + layout
- static/css/color-theme.css - Mobile device positioning sync
- tests/mjs/53-final-mobile-fixes-test.mjs - Comprehensive validation
Test results:
✅ Shortcuts hidden on real mobile (iPhone user agent)
✅ 5 buttons evenly spaced with no gap (60px spacing)
✅ Info button blue (52, 152, 219) vs back-to-top green (39, 174, 96)
✅ Theme button full opacity (alpha: 1, opacity: 1)
Issue 1: Blur bar compatibility (Android doesn't always show at bottom)
✅ Solution: Wrap blur bar in @supports query for backdrop-filter
- Only shows on devices that support backdrop-filter (primarily iOS)
- Android devices without support won't see the bar
- Prevents layout issues on non-iOS devices
Issue 2: Keyboard shortcuts button on real mobile (no physical keyboard)
✅ Solution: Device detection + conditional hiding
- Added device-detection.js: Detects real mobile vs desktop browser
- Checks user agent (Android, iPhone, iPad, etc.) + touch support
- Adds 'is-mobile-device' or 'is-desktop' class to <html>
- CSS hides shortcuts button only on real mobile devices
- Desktop browser in mobile view: shortcuts button still visible (for testing)
Implementation Details:
1. Device Detection (static/js/device-detection.js):
- User agent detection: /Android|iPhone|iPad|etc./
- Touch support check: ontouchstart + maxTouchPoints
- Class added to <html>: is-mobile-device or is-desktop
2. Blur Bar (@supports query):
- Detects backdrop-filter support before applying
- iOS: Shows blur bar with backdrop-filter
- Android (most): No blur bar (no backdrop-filter support)
- Prevents empty/broken bar on incompatible devices
3. CSS Hiding Rules:
- .is-mobile-device .shortcuts-btn { display: none !important; }
- Also hides zoom-toggle-btn and zoom-control on real mobile
- Desktop mobile view: shortcuts button remains visible
Files Modified:
- static/js/device-detection.js: NEW - Device detection logic
- templates/index.html: Load device-detection.js early
- static/css/05-responsive/_breakpoints.css: @supports wrapper for blur bar
- static/css/04-interactive/_scroll-behavior.css: Hide shortcuts on real mobile
- tests/mjs/52-mobile-device-detection-test.mjs: Comprehensive device detection test
Test Results:
✅ iPhone (real mobile): is-mobile-device class, shortcuts hidden
✅ Desktop browser (mobile view): is-desktop class, shortcuts visible
✅ Blur bar: Only shows on devices with backdrop-filter support
Fixed two critical mobile view issues:
1. Extended CV Sidebar Accordion:
- Updated sidebar.html to use native <details> element (was div with onclick)
- Styled accordion header to match CV title badges dark theme (#303030)
- Applied consistent styling: dark gray background, light text, uppercase, no spacing
- Result: Sidebars now collapse/expand properly with native HTML functionality
2. PDF Download Modal Centering:
- Added JavaScript-based centering for mobile viewports (≤768px)
- Uses inline styles with !important flag to override browser defaults
- Updated download button to call openPdfModal() function
- Result: Modal is perfectly centered on mobile (0px offset)
Technical notes:
- Modal centering required setProperty() with 'important' flag
- Accordion matches cv-title-badges-header style exactly
- All tests passing: accordion toggle, modal centering
Files modified:
- templates/partials/cv/sidebar.html
- static/css/05-responsive/_breakpoints.css
- static/js/main.js
- templates/partials/widgets/download-button.html
Tests added:
- tests/mjs/43-mobile-accordion-and-modal-test.mjs
- tests/mjs/46-visual-accordion-style-test.mjs
The theme switcher and info button tooltips were appearing on the RIGHT
in mobile view instead of on TOP (like macOS Dock style) because they
didn't have the .fixed-btn class and weren't included in the mobile
media query rules.
Changes:
- static/css/04-interactive/_tooltips.css: Add .color-theme-switcher and
.info-button selectors to mobile @media (max-width: 900px) rules
- Now tooltips appear ABOVE these buttons on mobile with bottom: calc(100% + 8px)
Testing:
- Added mobile tooltip position test
- Verified theme switcher and info tooltips now positioned on top on mobile
- Desktop behavior unchanged (tooltips still on right)
Mobile tooltip positioning now consistent across ALL buttons:
✅ All bottom dock buttons show tooltips on TOP (macOS Dock style)
- Remove tooltip-left class from zoom and shortcuts buttons (all left-side buttons show tooltips on RIGHT)
- Add mobile CSS rules for fixed-btn tooltips to appear on TOP (like macOS Dock)
- Update button template comments to reflect correct positioning
- Mobile: All fixed buttons now show tooltips above (top position)
- Desktop: All left-side fixed buttons show tooltips on right
- Document PDF loading modal with animated spinner and time estimates
- Document soft shadow optimization process (3 iterations to 0.06 opacity)
- Document border removal strategy for clean, modern design
- Document enhanced server startup logs with emoji icons
- Improve PDF modal estimate text spacing (1.5rem top margin)
- Update technique count from 10+ to 16+ major optimizations
- Mark Phase 10 as complete (November 2025)
- Center download button text with justify-content
- Set header text to solid black (#000) for better visibility
- Darken close button background for better contrast
- Remove any disabled appearance on mobile
Fixes grayed-out/disabled look and left-aligned button text on mobile.
- Hide subtitle on mobile to save vertical space
- Reduce all font sizes (header: 1.25rem, titles: 0.9rem, text: 0.75rem)
- Decrease modal padding from 2.5rem to 1.5rem 1rem
- Shrink page badges from 60×60px to 50×50px
- Reduce card padding from 16px to 12px
- Decrease gaps from 12px to 10px throughout
- Compact footer and button spacing
- Make download button smaller with 0.9rem font
Significantly reduces modal height for better mobile UX on small screens (iPhone 13 Mini, Samsung S24).
- Scale recommended card 12% larger on desktop for emphasis
- Add subtle golden border to Default CV (full opacity when selected)
- Pre-select Default CV by default with download button enabled
- Fix double border issue: exclude recommended card from red selection border
- Remove red focus outline for recommended card (transparent)
- Reduce modal height: thumbnail 280px→220px, padding 16px→12px
- Redesign mobile layout as compact button-style cards
- Hide full thumbnails on mobile, show page count badges instead
- Horizontal layout on mobile with left-aligned text
- Reduce mobile gap from 24px to 12px for better space efficiency
Improves visual hierarchy and mobile usability on small screens (iPhone 13 Mini, Samsung S24).
Simplified PDF download UX to use only the modal loading overlay,
removing the redundant toast notification that appeared when the modal
was closed during download. Updated tests to reflect the new behavior.
Changes:
- Removed toast trigger logic from PDF modal download function
- Removed modal close event listener for toast display
- Updated toast notification test expectations
- Fixed recommended card outline styling
**Issue 1: URL corruption in "See this CV in..." links**
- Bug: replaceYearPlaceholder used fmt.Sprintf on ALL URLs
- URLs like "/?lang=es" were corrupted to "/?lang=es%!(EXTRA string=2025)"
- Fix: Changed to strings.ReplaceAll("{{YEAR}}", year)
- Result: Only replaces actual {{YEAR}} placeholders, leaves other URLs intact
**Issue 2: Download filename not respected**
- Bug: Shortcut URLs (cv-jamr-2025-en.pdf) redirected with HTTP 301
- Browsers used original URL filename instead of Content-Disposition header
- Fix: Generate PDF directly in DefaultCVShortcut handler
- Result: Returns PDF with correct filename in Content-Disposition header
Files changed:
- internal/models/cv.go: Fixed replaceYearPlaceholder function
- internal/handlers/cv.go: Changed redirect to direct PDF generation
Both fixes verified:
- "See this CV in Spanish" link: href="/?lang=es" ✓
- Download link: filename=cv-jamr-2025-en.pdf ✓
UX Improvement:
- Added visual feedback during PDF generation process
- Users now see immediate response when clicking download button
- Clear communication about what's happening during the wait
New Features:
- Loading overlay with animated spinner
- Format-specific estimated generation times (Short: ~3s, Default: ~4s, Long: ~8s)
- Blur effect on modal background during loading
- Bilingual support (English/Spanish)
- Automatic modal close after download completes
CSS Updates (static/css/04-interactive/_modals.css):
- Added .pdf-loading-overlay with glassmorphism effect
- Spinning animation for loader (1s linear infinite)
- Fade-in animation (300ms)
- Accessibility: respects prefers-reduced-motion
- Background blur when loading active
HTML Updates (templates/partials/modals/pdf-modal.html):
- Loading overlay structure with spinner
- Dynamic loading messages based on selected format
- Enhanced downloadPDF() function with timing logic
Before: Click → silence → download appears
After: Click → overlay + spinner + estimate → download appears
Problem: Inline icons embedded in responsibilities, courses, and
projects had explicit width='60' height='60' attributes that made
them too large (60px instead of ~16px).
Solution:
- Added CSS with !important to override inline width/height attributes
- Targeted inline icons in:
* Course responsibilities and descriptions
* Project descriptions and technologies
* Experience responsibilities (within divs)
- Preserved large icons (80px) for main company/course/project logos
Changes:
- static/css/03-components/_courses.css: Override to 1.2em
- static/css/03-components/_projects.css: Override to 1.2em
- static/css/03-components/_cv-section.css: Override to 1.2em
Test Results:
✅ 7 course inline icons: 16px × 16px
✅ Main company icons: 80px × 80px (preserved)