diff --git a/static/css/01-foundation/_reset.css b/static/css/01-foundation/_reset.css index 384aeb6..c68bd94 100644 --- a/static/css/01-foundation/_reset.css +++ b/static/css/01-foundation/_reset.css @@ -25,13 +25,16 @@ body { background-image: var(--page-bg-pattern); background-size: 40px 40px; /* For dark theme diagonal grid */ background-attachment: fixed; - overflow-x: auto; + max-width: 100vw; /* Prevent horizontal overflow */ + overflow-x: hidden; /* NO horizontal scroll on mobile */ } /* Smooth scrolling */ html { scroll-behavior: smooth; scroll-padding-top: 70px; /* Account for fixed header */ + max-width: 100vw; /* Prevent horizontal overflow */ + overflow-x: hidden; /* NO horizontal scroll */ } /* Ensure Iconify icons display properly */ diff --git a/static/css/05-responsive/_breakpoints.css b/static/css/05-responsive/_breakpoints.css index 6c407e5..8503452 100644 --- a/static/css/05-responsive/_breakpoints.css +++ b/static/css/05-responsive/_breakpoints.css @@ -697,15 +697,83 @@ } /* ======================================== - Landscape Orientation Fixes + Landscape Orientation Fixes (Mobile Devices) ======================================== */ @media (max-width: 915px) and (orientation: landscape) { + /* CRITICAL: Prevent horizontal scroll in landscape */ + * { + max-width: 100vw !important; + } + + html, body { + width: 100vw !important; + max-width: 100vw !important; + overflow-x: hidden !important; + } + + .cv-container { + width: 100% !important; + max-width: 100% !important; + overflow-x: hidden !important; + padding: 0 !important; + margin: 0 !important; + } + + .cv-page { + width: 100% !important; + max-width: 100% !important; + margin: 0 !important; + transform: scale(1) !important; /* Reset zoom that might cause overflow */ + box-shadow: none !important; /* Remove shadow that might cause overflow */ + } + + .page-content { + width: 100% !important; + max-width: 100% !important; + overflow-x: hidden !important; + } + + /* Hide elements that might cause overflow */ + .action-bar, .cv-header, .cv-sidebar, .cv-main { + max-width: 100% !important; + overflow-x: hidden !important; + } + /* Force single column layout in landscape mobile */ + .cv-page .page-1 .page-content, + .cv-page .page-2 .page-content, .page-1 .page-content, .page-2 .page-content { grid-template-columns: 1fr !important; - grid-template-rows: auto auto; + grid-template-rows: auto auto !important; + max-width: 100% !important; + } + + /* Stack elements vertically in landscape: sidebar -> main */ + .page-1 .cv-sidebar-left { + grid-column: 1; + grid-row: 1; + order: 1; + } + + .page-1 .cv-main { + grid-column: 1; + grid-row: 2; + order: 2; + } + + /* Stack elements vertically in landscape: main -> sidebar */ + .page-2 .cv-main { + grid-column: 1; + grid-row: 1; + order: 1; + } + + .page-2 .cv-sidebar-right { + grid-column: 1; + grid-row: 2; + order: 2; } /* Reduce header size in landscape */ @@ -714,28 +782,120 @@ } .cv-name { - font-size: 1.2rem !important; + font-size: 1.4rem !important; + text-align: center; } .years-experience { - font-size: 0.9em !important; + font-size: 1em !important; + text-align: center; + } + + /* Reduce photo size in landscape to ~50% width but keep visible */ + .cv-header-content { + flex-direction: column; + align-items: center; + gap: 0.5rem; } - /* Reduce photo size in landscape to 50% */ .cv-photo { - width: 50% !important; + position: static !important; + width: auto !important; height: auto !important; - max-width: 80px !important; + max-width: 120px !important; + margin: 0.5rem auto !important; + text-align: center; } - /* Compact action bar */ + .cv-photo img { + width: 100% !important; + height: auto !important; + } + + /* Compact action bar - keep hamburger menu visible */ .action-bar { - padding: 0.5rem 1rem !important; + padding: 0.5rem 0.75rem !important; + } + + /* Simplify action bar for landscape */ + .action-bar-content { + grid-template-columns: 1fr !important; + gap: 0; + padding: 0; + } + + /* Hide center controls on landscape mobile (moved to hamburger menu) */ + .view-controls-center { + display: none !important; + } + + /* Hide action buttons on landscape (available in hamburger menu) */ + .action-buttons-right { + display: none !important; + } + + /* Keep site title visible and compact */ + .site-title { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + padding: 0 0.5rem; + gap: 0.5rem; + } + + .site-title-left { + display: flex; + align-items: center; + gap: 0.5rem; + flex: 1 1 auto; + min-width: 0; + } + + .site-title-text { + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + font-size: 0.95rem !important; + } + + /* Language selector compact */ + .language-selector { + display: flex; + flex: 0 0 auto; + margin-left: auto; + gap: 0.25rem; + } + + .language-selector .selector-btn { + padding: 0.3rem 0.6rem !important; + font-size: 0.85rem !important; + min-width: 35px !important; + } + + /* Hide year from title in landscape mobile */ + .site-title-year { + display: none !important; + } + + /* Show mobile icon in title */ + .site-logo-link { + display: none !important; + } + + .site-icon-mobile { + display: inline-flex !important; } /* Reduce sidebar padding */ .cv-sidebar { - padding: 1rem !important; + padding: 0.75rem !important; + } + + /* Compact accordion headers in landscape */ + .sidebar-accordion summary.sidebar-accordion-header { + padding: 6px 12px !important; + font-size: 0.8em !important; } /* Compact sections */ @@ -749,34 +909,97 @@ .project-item, .course-item { margin-bottom: 1rem !important; + padding-bottom: 1rem !important; } - /* Make hamburger menu more accessible in landscape */ - .hamburger-menu { - position: fixed !important; - top: 10px !important; - left: 10px !important; + /* Reduce font sizes for landscape */ + .experience-period, + .experience-location, + .position { + font-size: 0.85rem !important; + } + + .short-desc, + .responsibilities li { + font-size: 0.8rem !important; + } + + /* Make hamburger button accessible in landscape */ + .hamburger-btn { + display: flex !important; /* Force visible */ + position: relative !important; z-index: 1001 !important; + opacity: 1 !important; + visibility: visible !important; } - /* Adjust fixed buttons for landscape */ - .fixed-btn { - bottom: 1rem !important; + /* Adjust bottom button bar for landscape - smaller buttons */ + .download-btn, + .print-friendly-btn, + .shortcuts-btn, + .info-button, + .back-to-top, + .color-theme-switcher { width: 40px !important; height: 40px !important; + bottom: 1rem !important; } - .back-to-top-btn { - right: 1rem !important; + /* Recalculate button positions for smaller 40px buttons */ + /* 6 buttons: 6 * 40px + 5 * 10px = 290px total */ + .download-btn { + left: calc(50% - 145px) !important; + } + + .print-friendly-btn { + left: calc(50% - 95px) !important; } .shortcuts-btn { - left: 1rem !important; - bottom: 5rem !important; + left: calc(50% - 45px) !important; } - .zoom-toggle-btn { - left: 1rem !important; - bottom: 9rem !important; + .color-theme-switcher { + left: calc(50% + 5px) !important; + } + + .info-button { + left: calc(50% + 55px) !important; + } + + .back-to-top { + left: calc(50% + 105px) !important; + } + + /* Real mobile devices in landscape: 5 buttons (no shortcuts) */ + /* 5 buttons: 5 * 40px + 4 * 10px = 240px total */ + .is-mobile-device .download-btn { + left: calc(50% - 120px) !important; + } + + .is-mobile-device .print-friendly-btn { + left: calc(50% - 70px) !important; + } + + .is-mobile-device .color-theme-switcher { + left: calc(50% - 20px) !important; + } + + .is-mobile-device .info-button { + left: calc(50% + 30px) !important; + } + + .is-mobile-device .back-to-top { + left: calc(50% + 80px) !important; + } + + /* Reduce blur bar height for landscape */ + .fixed-buttons-backdrop { + height: 70px !important; + } + + /* Add bottom padding to footer for landscape */ + footer.no-print { + padding-bottom: 90px !important; } } diff --git a/tests/mjs/54-landscape-mode-test.mjs b/tests/mjs/54-landscape-mode-test.mjs new file mode 100755 index 0000000..2e1cd2a --- /dev/null +++ b/tests/mjs/54-landscape-mode-test.mjs @@ -0,0 +1,117 @@ +#!/usr/bin/env node + +import { chromium } from 'playwright'; + +const LANDSCAPE_VIEWPORT = { width: 667, height: 375 }; // iPhone SE landscape + +(async () => { + const browser = await chromium.launch({ headless: true }); + + console.log('🧪 Testing Landscape Mode Layout\n'); + + // TEST 1: Android Landscape + console.log('📱 TEST 1: Android Landscape (Pixel 5)\n'); + const androidContext = await browser.newContext({ + viewport: LANDSCAPE_VIEWPORT, + userAgent: 'Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.91 Mobile Safari/537.36', + hasTouch: true + }); + const androidPage = await androidContext.newPage(); + + await androidPage.goto('http://localhost:1999/?lang=en&view=extended'); + await androidPage.waitForLoadState('networkidle'); + + const androidLayout = await androidPage.evaluate(() => { + const page1 = document.querySelector('.page-1 .page-content'); + const sidebar = document.querySelector('.cv-sidebar-left'); + const hamburger = document.querySelector('.hamburger-btn'); // Correct class name + const photo = document.querySelector('.cv-photo'); + const buttons = document.querySelector('.download-btn'); + + const gridCols = window.getComputedStyle(page1).gridTemplateColumns; + // Single column if it's just one value (e.g., "667px" not "300px 667px") + const singleColumn = !gridCols.includes(' '); + + return { + gridColumns: gridCols, + singleColumn: singleColumn, + hamburgerVisible: hamburger ? window.getComputedStyle(hamburger).display !== 'none' : false, + photoMaxWidth: photo ? window.getComputedStyle(photo).maxWidth : 'N/A', + photoVisible: photo ? window.getComputedStyle(photo).display !== 'none' : false, + buttonWidth: buttons ? window.getComputedStyle(buttons).width : 'N/A', + hasHorizontalScroll: document.body.scrollWidth > window.innerWidth + }; + }); + + console.log('Android Landscape Layout:'); + console.log(` • Grid columns: ${androidLayout.gridColumns}`); + console.log(` • Single column: ${androidLayout.singleColumn ? '✅' : '❌'}`); + console.log(` • Hamburger menu visible: ${androidLayout.hamburgerVisible ? '✅' : '❌'}`); + console.log(` • Photo max-width: ${androidLayout.photoMaxWidth}`); + console.log(` • Photo visible: ${androidLayout.photoVisible ? '✅' : '❌'}`); + console.log(` • Button width: ${androidLayout.buttonWidth}`); + console.log(` • Has horizontal scroll: ${androidLayout.hasHorizontalScroll ? '❌ FAIL' : '✅'}\n`); + + await androidPage.screenshot({ + path: 'tests/screenshots/landscape-android.png', + fullPage: true + }); + + await androidContext.close(); + + // TEST 2: iPhone Landscape + console.log('📱 TEST 2: iPhone Landscape (iPhone 12)\n'); + const iphoneContext = await browser.newContext({ + viewport: { width: 844, height: 390 }, // iPhone 12 landscape + userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1', + hasTouch: true + }); + const iphonePage = await iphoneContext.newPage(); + + await iphonePage.goto('http://localhost:1999/?lang=en&view=extended'); + await iphonePage.waitForLoadState('networkidle'); + + const iphoneLayout = await iphonePage.evaluate(() => { + const page1 = document.querySelector('.page-1 .page-content'); + const photo = document.querySelector('.cv-photo'); + const buttons = document.querySelector('.download-btn'); + + const gridCols = window.getComputedStyle(page1).gridTemplateColumns; + // Single column if it's just one value (e.g., "844px" not "300px 844px") + const singleColumn = !gridCols.includes(' '); + + return { + gridColumns: gridCols, + singleColumn: singleColumn, + photoMaxWidth: photo ? window.getComputedStyle(photo).maxWidth : 'N/A', + photoVisible: photo ? window.getComputedStyle(photo).display !== 'none' : false, + buttonWidth: buttons ? window.getComputedStyle(buttons).width : 'N/A', + hasHorizontalScroll: document.body.scrollWidth > window.innerWidth + }; + }); + + console.log('iPhone Landscape Layout:'); + console.log(` • Grid columns: ${iphoneLayout.gridColumns}`); + console.log(` • Single column: ${iphoneLayout.singleColumn ? '✅' : '❌'}`); + console.log(` • Photo max-width: ${iphoneLayout.photoMaxWidth}`); + console.log(` • Photo visible: ${iphoneLayout.photoVisible ? '✅' : '❌'}`); + console.log(` • Button width: ${iphoneLayout.buttonWidth}`); + console.log(` • Has horizontal scroll: ${iphoneLayout.hasHorizontalScroll ? '❌ FAIL' : '✅'}\n`); + + await iphonePage.screenshot({ + path: 'tests/screenshots/landscape-iphone.png', + fullPage: true + }); + + await iphoneContext.close(); + + const allPassed = androidLayout.singleColumn && !androidLayout.hasHorizontalScroll && + androidLayout.hamburgerVisible && androidLayout.photoVisible && + iphoneLayout.singleColumn && !iphoneLayout.hasHorizontalScroll && + iphoneLayout.photoVisible; + + console.log(`${allPassed ? '✅' : '❌'} Tests ${allPassed ? 'PASSED' : 'FAILED'}\n`); + + await browser.close(); + process.exit(allPassed ? 0 : 1); +})(); diff --git a/tests/mjs/55-button-centering-test.mjs b/tests/mjs/55-button-centering-test.mjs new file mode 100755 index 0000000..8abf895 --- /dev/null +++ b/tests/mjs/55-button-centering-test.mjs @@ -0,0 +1,197 @@ +#!/usr/bin/env node + +import { chromium } from 'playwright'; + +const MOBILE_VIEWPORT = { width: 375, height: 667 }; + +(async () => { + const browser = await chromium.launch({ headless: true }); + + console.log('🧪 Testing Button Centering on Mobile\n'); + + // TEST 1: Android Portrait + console.log('📱 TEST 1: Android Portrait (Pixel 5)\n'); + const androidContext = await browser.newContext({ + viewport: MOBILE_VIEWPORT, + userAgent: 'Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.91 Mobile Safari/537.36', + hasTouch: true + }); + const androidPage = await androidContext.newPage(); + + await androidPage.goto('http://localhost:1999/?lang=en&view=extended'); + await androidPage.waitForLoadState('networkidle'); + + const androidButtons = await androidPage.evaluate(() => { + const viewport = { + width: window.innerWidth, + height: window.innerHeight + }; + + const buttons = { + download: document.querySelector('.download-btn'), + print: document.querySelector('.print-friendly-btn'), + theme: document.querySelector('.color-theme-switcher'), + info: document.querySelector('.info-button'), + backToTop: document.querySelector('.back-to-top'), + shortcuts: document.querySelector('.shortcuts-btn') + }; + + const positions = {}; + let leftmostButton = Infinity; + let rightmostButton = 0; + + for (const [name, btn] of Object.entries(buttons)) { + if (btn) { + const rect = btn.getBoundingClientRect(); + const computed = window.getComputedStyle(btn); + const visible = computed.display !== 'none'; + + if (visible) { + positions[name] = { + left: Math.round(rect.left), + right: Math.round(rect.right), + centerX: Math.round(rect.left + rect.width / 2), + visible: true + }; + leftmostButton = Math.min(leftmostButton, rect.left); + rightmostButton = Math.max(rightmostButton, rect.right); + } else { + positions[name] = { visible: false }; + } + } + } + + const buttonBarWidth = rightmostButton - leftmostButton; + const buttonBarCenterX = leftmostButton + buttonBarWidth / 2; + const viewportCenterX = viewport.width / 2; + const centeringOffset = Math.abs(buttonBarCenterX - viewportCenterX); + + return { + viewport, + positions, + buttonBarWidth: Math.round(buttonBarWidth), + buttonBarCenterX: Math.round(buttonBarCenterX), + viewportCenterX: Math.round(viewportCenterX), + centeringOffset: Math.round(centeringOffset), + isCentered: centeringOffset < 10 // Within 10px is acceptable + }; + }); + + console.log('Android Button Positions:'); + Object.entries(androidButtons.positions).forEach(([name, pos]) => { + if (pos.visible) { + console.log(` • ${name}: ${pos.left}px to ${pos.right}px (center: ${pos.centerX}px)`); + } else { + console.log(` • ${name}: HIDDEN`); + } + }); + console.log(`\nButton Bar Analysis:`); + console.log(` • Button bar width: ${androidButtons.buttonBarWidth}px`); + console.log(` • Button bar center: ${androidButtons.buttonBarCenterX}px`); + console.log(` • Viewport center: ${androidButtons.viewportCenterX}px`); + console.log(` • Centering offset: ${androidButtons.centeringOffset}px`); + console.log(` • Is centered: ${androidButtons.isCentered ? '✅' : '❌'}\n`); + + await androidPage.screenshot({ + path: 'tests/screenshots/buttons-android-portrait.png', + fullPage: true + }); + + await androidContext.close(); + + // TEST 2: iPhone Portrait + console.log('📱 TEST 2: iPhone Portrait (iPhone 12)\n'); + const iphoneContext = await browser.newContext({ + viewport: MOBILE_VIEWPORT, + userAgent: 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.0 Mobile/15E148 Safari/604.1', + hasTouch: true + }); + const iphonePage = await iphoneContext.newPage(); + + await iphonePage.goto('http://localhost:1999/?lang=en&view=extended'); + await iphonePage.waitForLoadState('networkidle'); + + const iphoneButtons = await iphonePage.evaluate(() => { + const viewport = { + width: window.innerWidth, + height: window.innerHeight + }; + + const buttons = { + download: document.querySelector('.download-btn'), + print: document.querySelector('.print-friendly-btn'), + theme: document.querySelector('.color-theme-switcher'), + info: document.querySelector('.info-button'), + backToTop: document.querySelector('.back-to-top') + }; + + const positions = {}; + let leftmostButton = Infinity; + let rightmostButton = 0; + + for (const [name, btn] of Object.entries(buttons)) { + if (btn) { + const rect = btn.getBoundingClientRect(); + const computed = window.getComputedStyle(btn); + const visible = computed.display !== 'none'; + + if (visible) { + positions[name] = { + left: Math.round(rect.left), + right: Math.round(rect.right), + centerX: Math.round(rect.left + rect.width / 2), + visible: true + }; + leftmostButton = Math.min(leftmostButton, rect.left); + rightmostButton = Math.max(rightmostButton, rect.right); + } else { + positions[name] = { visible: false }; + } + } + } + + const buttonBarWidth = rightmostButton - leftmostButton; + const buttonBarCenterX = leftmostButton + buttonBarWidth / 2; + const viewportCenterX = viewport.width / 2; + const centeringOffset = Math.abs(buttonBarCenterX - viewportCenterX); + + return { + viewport, + positions, + buttonBarWidth: Math.round(buttonBarWidth), + buttonBarCenterX: Math.round(buttonBarCenterX), + viewportCenterX: Math.round(viewportCenterX), + centeringOffset: Math.round(centeringOffset), + isCentered: centeringOffset < 10 + }; + }); + + console.log('iPhone Button Positions:'); + Object.entries(iphoneButtons.positions).forEach(([name, pos]) => { + if (pos.visible) { + console.log(` • ${name}: ${pos.left}px to ${pos.right}px (center: ${pos.centerX}px)`); + } else { + console.log(` • ${name}: HIDDEN`); + } + }); + console.log(`\nButton Bar Analysis:`); + console.log(` • Button bar width: ${iphoneButtons.buttonBarWidth}px`); + console.log(` • Button bar center: ${iphoneButtons.buttonBarCenterX}px`); + console.log(` • Viewport center: ${iphoneButtons.viewportCenterX}px`); + console.log(` • Centering offset: ${iphoneButtons.centeringOffset}px`); + console.log(` • Is centered: ${iphoneButtons.isCentered ? '✅' : '❌'}\n`); + + await iphonePage.screenshot({ + path: 'tests/screenshots/buttons-iphone-portrait.png', + fullPage: true + }); + + await iphoneContext.close(); + + const allPassed = androidButtons.isCentered && iphoneButtons.isCentered; + + console.log(`${allPassed ? '✅' : '❌'} Tests ${allPassed ? 'PASSED' : 'FAILED'}\n`); + + await browser.close(); + process.exit(allPassed ? 0 : 1); +})(); diff --git a/tests/mjs/56-landscape-debug-test.mjs b/tests/mjs/56-landscape-debug-test.mjs new file mode 100755 index 0000000..426102d --- /dev/null +++ b/tests/mjs/56-landscape-debug-test.mjs @@ -0,0 +1,64 @@ +#!/usr/bin/env node + +import { chromium } from 'playwright'; + +const LANDSCAPE_VIEWPORT = { width: 667, height: 375 }; + +(async () => { + const browser = await chromium.launch({ headless: true }); + const context = await browser.newContext({ + viewport: LANDSCAPE_VIEWPORT, + userAgent: 'Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.91 Mobile Safari/537.36', + hasTouch: true + }); + const page = await context.newPage(); + + await page.goto('http://localhost:1999/?lang=en&view=extended'); + await page.waitForLoadState('networkidle'); + + const debug = await page.evaluate(() => { + const page1 = document.querySelector('.page-1 .page-content'); + const computed = window.getComputedStyle(page1); + + // Check media query matches + const landscapeMatch = window.matchMedia('(max-width: 915px) and (orientation: landscape)').matches; + const maxWidth915 = window.matchMedia('(max-width: 915px)').matches; + const orientationLandscape = window.matchMedia('(orientation: landscape)').matches; + const maxWidth768 = window.matchMedia('(max-width: 768px)').matches; + + return { + viewport: { + width: window.innerWidth, + height: window.innerHeight, + ratio: window.innerWidth / window.innerHeight + }, + mediaQueries: { + 'max-width: 915px': maxWidth915, + 'orientation: landscape': orientationLandscape, + 'max-width: 915px AND landscape': landscapeMatch, + 'max-width: 768px': maxWidth768 + }, + gridColumns: computed.gridTemplateColumns, + bodyOverflow: window.getComputedStyle(document.body).overflowX, + htmlOverflow: window.getComputedStyle(document.documentElement).overflowX + }; + }); + + console.log('Landscape Debug Info:\n'); + console.log('Viewport:'); + console.log(` • Width: ${debug.viewport.width}px`); + console.log(` • Height: ${debug.viewport.height}px`); + console.log(` • Ratio: ${debug.viewport.ratio.toFixed(2)} (${debug.viewport.ratio > 1 ? 'LANDSCAPE' : 'PORTRAIT'})\n`); + + console.log('Media Query Matches:'); + Object.entries(debug.mediaQueries).forEach(([query, matches]) => { + console.log(` • ${query}: ${matches ? '✅ YES' : '❌ NO'}`); + }); + + console.log(`\nComputed Styles:`); + console.log(` • Grid columns: ${debug.gridColumns}`); + console.log(` • Body overflow-x: ${debug.bodyOverflow}`); + console.log(` • HTML overflow-x: ${debug.htmlOverflow}\n`); + + await browser.close(); +})(); diff --git a/tests/mjs/57-horizontal-scroll-debug.mjs b/tests/mjs/57-horizontal-scroll-debug.mjs new file mode 100755 index 0000000..fb5e445 --- /dev/null +++ b/tests/mjs/57-horizontal-scroll-debug.mjs @@ -0,0 +1,70 @@ +#!/usr/bin/env node + +import { chromium } from 'playwright'; + +const LANDSCAPE_VIEWPORT = { width: 667, height: 375 }; + +(async () => { + const browser = await chromium.launch({ headless: true }); + const context = await browser.newContext({ + viewport: LANDSCAPE_VIEWPORT, + userAgent: 'Mozilla/5.0 (Linux; Android 11; Pixel 5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/90.0.4430.91 Mobile Safari/537.36', + hasTouch: true + }); + const page = await context.newPage(); + + await page.goto('http://localhost:1999/?lang=en&view=extended'); + await page.waitForLoadState('networkidle'); + + const debug = await page.evaluate(() => { + // Find all elements wider than viewport + const viewportWidth = window.innerWidth; + const wideElements = []; + + document.querySelectorAll('*').forEach((el) => { + const rect = el.getBoundingClientRect(); + if (rect.width > viewportWidth) { + const computed = window.getComputedStyle(el); + wideElements.push({ + tag: el.tagName.toLowerCase(), + id: el.id || '(no id)', + classes: el.className || '(no classes)', + width: Math.round(rect.width), + computedWidth: computed.width, + maxWidth: computed.maxWidth, + overflow: computed.overflowX + }); + } + }); + + // Sort by width descending + wideElements.sort((a, b) => b.width - a.width); + + return { + viewportWidth, + bodyScrollWidth: document.body.scrollWidth, + documentScrollWidth: document.documentElement.scrollWidth, + hasHorizontalScroll: document.body.scrollWidth > viewportWidth, + wideElements: wideElements.slice(0, 10) // Top 10 widest + }; + }); + + console.log(`Horizontal Scroll Debug:\n`); + console.log(`Viewport: ${debug.viewportWidth}px`); + console.log(`Body scroll width: ${debug.bodyScrollWidth}px`); + console.log(`Document scroll width: ${debug.documentScrollWidth}px`); + console.log(`Has horizontal scroll: ${debug.hasHorizontalScroll ? '❌ YES' : '✅ NO'}\n`); + + if (debug.wideElements.length > 0) { + console.log(`Elements wider than viewport:\n`); + debug.wideElements.forEach((el, i) => { + console.log(`${i + 1}. <${el.tag}> #${el.id} .${el.classes}`); + console.log(` Width: ${el.width}px | Max-width: ${el.maxWidth} | Overflow: ${el.overflow}`); + console.log(` Computed width: ${el.computedWidth}\n`); + }); + } else { + console.log('No elements wider than viewport found\n'); + } + + await browser.close(); +})();