This is really an HTML/CSS issue, there is nothing specific in py4web. I asked chatGPT to build me a layout.html for small devices and it came up with the following (I did not try it)
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>[[=globals().get('title','') or 'py4web app']]</title>
[[block page_head]]
<style>
/* Mobile-first, minimalist responsive layout */
* { box-sizing: border-box; }
body { margin: 0; font: 16px/1.4 system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif; }
a { color: inherit; }
.wrap { max-width: 960px; margin: 0 auto; padding: 12px; }
header, main, aside, footer {
border: 1px solid #ddd;
border-radius: 10px;
padding: 12px;
}
header {
display: grid;
gap: 12px;
}
.brand { font-weight: 700; }
nav a {
display: inline-block;
padding: 8px 10px;
text-decoration: none;
border: 1px solid #ddd;
border-radius: 999px;
margin: 4px 6px 0 0;
}
.grid { display: grid; gap: 12px; grid-template-columns: 1fr; }
img { max-width: 100%; height: auto; display: block; border-radius: 10px; }
/* Wider screens: header becomes a row, and we get a sidebar */
@media (min-width: 720px) {
header { grid-auto-flow: column; align-items: center; justify-content: space-between; }
.grid { grid-template-columns: 2fr 1fr; }
}
@media (prefers-reduced-motion: reduce) { * { scroll-behavior: auto; } }
</style>
[[end]]
</head>
<body>
<div class="wrap">
<header>
<div class="brand">
[[=globals().get('app_name','My App')]]
</div>
<nav>
[[block page_menu]]
<!-- Minimal default menu; override in child templates if you want -->
<a href="[[=URL('index')]]">Home</a>
[[end]]
</nav>
</header>
<div class="grid" style="margin-top:12px;">
<main>
[[block content]][[end]]
</main>
<aside>
[[block sidebar]]
<!-- Optional sidebar content -->
[[=globals().get('sidebar','')]]
[[end]]
</aside>
</div>
<footer style="margin-top:12px;">
<small>© [[=request.now.year]]</small>
</footer>
</div>
[[block page_scripts]][[end]]
</body>
</html>