Landscape kiosk overhaul: 3-column layout, resilient updates, visual polish

- Add 3-column balanced site distribution using greedy weight algorithm
- Build new DOM off-screen in DocumentFragment, swap atomically (no flash)
- Skip empty API responses and preserve display on transient errors
- Remove news ticker from UI and grid layout
- Add blue-to-red gradient on site header bars
- Bump font sizes: destinations 1.4em, countdowns 1.5em, line numbers 1.6em
- Add breathing pulse animation on daylight bar sun/moon icons
- Fix daylight bar indicator snapping to position on first render
- Make config button visible in landscape with semi-transparent background
- Add weather forecast strip as grid row 4 with compact styling

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-15 23:07:10 +01:00
parent 5f60ed88c8
commit 57cd9809e0
5 changed files with 222 additions and 98 deletions

View File

@@ -101,7 +101,7 @@ body {
body.normal .departure-container {
display: grid;
grid-template-columns: repeat(2, 1fr);
grid-template-columns: repeat(4, 1fr);
gap: 6px;
margin-bottom: 0;
width: 100%;
@@ -128,17 +128,6 @@ body {
max-width: 100%;
}
body.normal .direction-destination {
font-size: 1.1em;
}
body.normal .countdown-large {
font-size: 1.4em;
}
body.normal .next-departures {
font-size: 0.9em;
}
}
/* ========================================
@@ -185,7 +174,7 @@ body.landscape #background-overlay {
body.landscape #content-wrapper {
display: grid;
grid-template-rows: auto auto 1fr auto auto;
gap: var(--kiosk-gap);
gap: 4px;
height: 100vh;
max-height: 100vh;
overflow: hidden;
@@ -196,9 +185,11 @@ body.landscape .clock-container {
margin-bottom: 0;
}
/* Compact weather bar sits in row 2 */
/* Compact weather bar in row 2 */
body.landscape #compact-weather-bar {
grid-row: 2;
font-size: 0.85em;
padding: 2px 16px;
}
body.landscape .main-content-grid {
@@ -208,15 +199,62 @@ body.landscape .main-content-grid {
min-height: 0;
}
/* Hide the full weather widget in landscape */
/* Weather forecast strip at bottom - row 4 */
body.landscape .weather-section {
grid-row: 4;
overflow: hidden;
}
body.landscape .weather-container {
overflow: hidden;
max-height: none;
position: static;
}
body.landscape #custom-weather {
background: var(--color-bar-bg);
border-radius: 4px;
padding: 2px 8px;
}
body.landscape #custom-weather .current-weather {
display: none;
}
body.landscape #custom-weather .forecast {
display: flex;
gap: 0;
overflow-x: auto;
overflow-y: hidden;
justify-content: center;
}
body.landscape #custom-weather .forecast-hour {
flex-shrink: 0;
padding: 2px 8px;
min-width: auto;
}
body.landscape #custom-weather .forecast-hour .time {
font-size: 0.65em;
}
body.landscape #custom-weather .forecast-hour .icon img {
width: 20px;
height: 20px;
}
body.landscape #custom-weather .forecast-hour .temp {
font-size: 0.65em;
}
body.landscape #custom-weather .attribution {
display: none;
}
body.landscape .departure-container {
display: flex;
flex-direction: column;
gap: var(--kiosk-gap);
gap: 12px;
overflow-y: auto;
overflow-x: hidden;
padding-right: 4px;
@@ -224,49 +262,52 @@ body.landscape .departure-container {
height: 100%;
}
body.landscape .weather-container {
overflow-y: auto;
overflow-x: hidden;
max-height: 100%;
position: sticky;
top: 0;
align-self: start;
}
body.landscape .departure-card {
min-height: 80px;
background-color: var(--color-surface-kiosk);
border: 1px solid rgba(255, 255, 255, 0.06);
border-radius: 4px;
width: 100%;
flex-shrink: 0;
}
body.landscape .line-number-box {
min-width: 110px;
width: 110px;
}
body.landscape .line-number-large {
font-size: 3em;
body.landscape .departure-column {
flex: 1;
min-width: 0;
display: flex;
flex-direction: column;
gap: 4px;
}
body.landscape .site-container {
margin-bottom: 6px;
margin-bottom: 0;
}
body.landscape .departure-card {
min-height: 0;
background-color: var(--color-surface-kiosk);
border: 1px solid rgba(255, 255, 255, 0.06);
border-radius: 3px;
margin-bottom: 0;
}
body.landscape .line-number-box {
min-width: 48px;
width: 48px;
padding: 2px;
}
body.landscape .line-number-large {
font-size: 1.6em;
}
body.landscape .transport-mode-icon .transport-icon {
width: 14px;
height: 14px;
}
body.landscape .site-container {
margin-bottom: 2px;
}
body.landscape .site-header {
font-size: 1em;
font-size: 0.8em;
padding: 0;
margin-bottom: 6px;
margin-bottom: 2px;
}
/* News ticker sits in row 4 */
body.landscape #news-ticker {
grid-row: 4;
}
/* Daylight bar sits in row 5 */
/* Daylight bar in row 5 */
body.landscape #daylight-hours-bar {
grid-row: 5;
}
@@ -274,7 +315,6 @@ body.landscape #daylight-hours-bar {
/* Dark card surfaces for landscape */
body.landscape .direction-destination {
color: var(--color-text-light);
font-size: 1.3em;
}
body.landscape .countdown-large {
@@ -285,32 +325,43 @@ body.landscape .next-departures {
color: var(--color-text-secondary);
}
/* Tighter card spacing in landscape */
/* Compact card spacing in landscape */
body.landscape .directions-wrapper {
padding: 4px 8px;
gap: 2px;
padding: 3px 6px;
gap: 1px;
}
body.landscape .direction-row {
min-height: 28px;
gap: 6px;
min-height: 30px;
gap: 4px;
}
/* Hero countdown in landscape */
body.landscape .direction-destination {
font-size: 1.4em;
color: #eee;
}
body.landscape .direction-arrow-box {
width: 22px;
height: 22px;
font-size: 0.85em;
}
/* Countdown in landscape */
body.landscape .countdown-large {
font-size: 2.5em;
font-size: 1.5em;
}
body.landscape .times-container {
min-width: 200px;
max-width: 280px;
min-width: 90px;
max-width: 140px;
}
body.landscape .next-departures {
font-size: 1em;
font-size: 0.75em;
color: var(--color-text-secondary);
white-space: nowrap;
letter-spacing: 1px;
letter-spacing: 0.3px;
}
/* ========================================